Replace lzma with xz. Tweaks to fix debug builds.

This commit is contained in:
Petr Mrázek 2013-09-28 18:43:30 +02:00
parent d903b0f0ea
commit d267d86f6e
44 changed files with 3739 additions and 7261 deletions

View File

@ -47,13 +47,15 @@ include_directories(${Qt5Widgets_INCLUDE_DIRS})
add_subdirectory(depends/quazip) add_subdirectory(depends/quazip)
include_directories(depends/quazip) include_directories(depends/quazip)
# Add lzma
#add_subdirectory(depends/lzma)
#include_directories(depends/lzma/include)
# Add the java launcher # Add the java launcher
add_subdirectory(depends/launcher) add_subdirectory(depends/launcher)
# Add xz decompression
add_subdirectory(depends/xz-embedded)
# Add pack200 decompression
add_subdirectory(depends/pack200)
######## MultiMC Libs ######## ######## MultiMC Libs ########
# Add the util library. # Add the util library.
@ -68,9 +70,6 @@ include_directories(${LIBSETTINGS_INCLUDE_DIR})
add_subdirectory(depends/groupview) add_subdirectory(depends/groupview)
include_directories(${LIBGROUPVIEW_INCLUDE_DIR}) include_directories(${LIBGROUPVIEW_INCLUDE_DIR})
#pack 200
#add_subdirectory(depends/pack200)
################################ SET UP BUILD OPTIONS ################################ ################################ SET UP BUILD OPTIONS ################################
######## Check endianness ######## ######## Check endianness ########
@ -355,9 +354,8 @@ ADD_EXECUTABLE(MultiMC MACOSX_BUNDLE WIN32
# Link # Link
QT5_USE_MODULES(MultiMC Widgets Network Xml) QT5_USE_MODULES(MultiMC Widgets Network Xml)
TARGET_LINK_LIBRARIES(MultiMC quazip lzma libUtil libSettings libGroupView TARGET_LINK_LIBRARIES(MultiMC quazip libUtil libSettings libGroupView ${MultiMC_LINK_ADDITIONAL_LIBS})
${MultiMC_LINK_ADDITIONAL_LIBS}) ADD_DEPENDENCIES(MultiMC MultiMCLauncher)
#ADD_DEPENDENCIES(MultiMC MultiMCLauncher libUtil libSettings libGroupView)
option(BUILD_KEYRING_TEST "Build the simple keyring test binary" OFF) option(BUILD_KEYRING_TEST "Build the simple keyring test binary" OFF)

View File

@ -1,54 +0,0 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(lzma)
IF (WIN32)
ADD_DEFINITIONS(-DWIN32)
ENDIF (WIN32)
SET(SRCS
# original code by Igor Pavlov
# Lzma version 4.63
# Minified ~_~
pavlov/7zCrc.c
pavlov/7zCrc.h
pavlov/LzFind.c
pavlov/LzFind.h
pavlov/LzHash.h
pavlov/LzmaDec.c
pavlov/LzmaDec.h
pavlov/LzmaEnc.c
pavlov/LzmaEnc.h
pavlov/LzmaLib.c
pavlov/LzmaLib.h
pavlov/Types.h
# Public headers
include/common.h
include/compress.h
include/decompress.h
include/simple.h
# Wrapper by Lloyd Hilaiel (lloyd@hilaiel.com)
wrapper/common_internal.c
wrapper/common_internal.h
wrapper/compress.c
wrapper/decompress.c
wrapper/simple.c
wrapper/lzip_header.c
wrapper/lzip_header.h
wrapper/lzma_header.c
wrapper/lzma_header.h
)
# an include directory to allow easylzma implementation to find public
# headers
INCLUDE_DIRECTORIES(include)
ADD_LIBRARY(lzma STATIC ${SRCS})
# lzma compress/decompress tool
ADD_EXECUTABLE(elzma elzma.c)
TARGET_LINK_LIBRARIES(elzma lzma)
# a simple test...
ADD_EXECUTABLE(easylzma_test easylzma_test.c)
TARGET_LINK_LIBRARIES(easylzma_test lzma)

View File

@ -1,9 +0,0 @@
# Written in 2009 by Lloyd Hilaiel
# Butchered in 2013 by Petr Mrazek
#
# License
#
# All the cruft you find here is public domain. You don't have to credit
# anyone to use this code, but my personal request is that you mention
# Igor Pavlov for his hard, high quality work.
#

View File

@ -1,282 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*
* Various compiled-in tests for the easylzma library which excercise
* API correctness and handling of corrupt data.
*/
#include "simple.h"
#include <stdio.h>
#include <string.h>
static const char *sampleData =
"Overview\n"
"\n"
"Easylzma is a C library and command line tools for LZMA compression and \n"
"decompression. It uses a Igor Pavlov's reference implementation and SDK\n"
"written in C.\n"
"\n"
"License\n"
"\n"
"All the cruft you find here is public domain. You don't have to credit\n"
"anyone to use this code, but my personal request is that you mention\n"
"Igor Pavlov for his hard, high quality work.\n"
"\n"
"Project Goals\n"
"\n"
"1. A tiny C wrapper and portable build system around a subset of\n"
" Igor Pavlov's public domain LZMA compression and decompression\n"
" implementation.\n"
"2. A tiny and straighforward API\n"
"3. Support for multiple different prominent LZMA file formats (see section on\n"
" file formats below)\n"
"4. easy to build and use everywhere (doze and nix alike)\n"
"5. public domain licensing through and through. (hats off to Igor)\n"
"\n"
"Current State:\n"
"\n"
"THIS IS A WORK IN PROGRESS. The code here should be considered pre-alpha,\n"
"and this should only be used by tinkerers or hackers at this point. Once\n"
"feature completion is attained this message will be updated. See the\n"
"TODO file distributed with the source for remaining work to be done.\n"
"\n"
"Platforms Supported\n"
"\n"
"0.0.2 has been successfully compiled and run basic round trip testing\n"
"on the following platforms & compilers:\n"
"\n"
" * win32 - visual studio 2005\n"
" * osx - 10.4 & 10.5 (intel)\n"
" * netbsd ppc - 4.0.1 with gcc 4.1.2\n"
" (NOTE: memory allocation errors when dict size is default)\n"
" * freebsd 6.1 - amd64 gcc 3.4.4\n"
"\n"
"Features\n"
"\n"
"XXX: write me (and the code)\n"
"\n"
"Usage\n"
"\n"
"XXX: write me (and the code)\n"
"\n"
"The Saga of LZMA File Formats, and a couple cents.\n"
"\n"
"As far as I can tell, there are at least four different ways to put LZMA\n"
"compressed data in a stream:\n"
"\n"
"1. The LZMA-Alone format, which consists of a 13 byte header including\n"
" compression properties, dictionary size, and the uncompressed size of\n"
" the file, followed by compressed data. This format has some support\n"
" in Igor Pavlov's reference implementation and is in widespread use, as\n"
" it's supported by lzmautils: http://tukaani.org/lzma/\n"
"\n"
" The canonical (afaict) implementation of this format (lzmautis) is\n"
" BSD licensed.\n"
"\n"
"2. The lzip format (http://www.nongnu.org/lzip/lzip.html) - which\n"
" includes a CRC footer and leading \"magic number\". The former\n"
" affords data integrity gaurantees, while the latter simplifies\n"
" heuristic determination of file format. This format looks to have\n"
" reasonably widespread usage, though not quite as significant as\n"
" LZMA-Alone.\n"
"\n"
" The only implementation of this format I can find (lzip) is GPL licensed.\n"
"\n"
"3. the xz format ( http://tukaani.org/xz/xz-file-format.txt ) which is\n"
" a more complex representation that includes CRC support and a magic\n"
" number. This format is to be supported by the next iteration of\n"
" XZ Utils which is currently in beta. The source may be obtained\n"
" here: git://ctrl.tukaani.org/xz.git\n"
"\n"
" This format will address some criticisms to the LZMA-Alone format and\n"
" was developed collaboratively by Lasse Collin (the current maintainer\n"
" of XZ utils) and Igor Pavlov (the author of 7zip and the refrence\n"
" implementation of LZMA).\n"
"\n"
" The xz format will employ LZMA2 which consists of extensions on top\n"
" of LZMA, in the xz utils maintainer's words:\n"
"\n"
" \"The primary compression algorithm in .xz is currently LZMA2, which\n"
" is an extension on top of the orignal LZMA to fix a few practical\n"
" issues, like adding support for flushing the encoder (equivalent\n"
" to zlib's Z_SYNC_FLUSH), which isn't possible with the original\n"
" LZMA.\"\n"
"\n"
" Again, maintainers words, regarding licensing:\n"
"\n"
" \"XZ Utils currently contains a zlib-like compression library and a \n"
" gzip-like command line tool. It's currently under LGPLv2.1+ but I will \n"
" put it into the public domain before the first stable release.\"\n"
"\n"
"4. The 7zip disk format which can contain multiple files possibly stored in\n"
" LZMA compressed format.\n"
"\n"
"Given the state of things, the goal of this project is to develop something\n"
"based on the existing formats, and quickly leverage code generated by the XZ\n"
"Utils project, or simply kill this thing if that project produces something\n"
"that's easy to embed and has a clean API at a similar level of abstraction\n"
"as easylzma.\n"
"\n"
"lloyd - sometime in oh nine.\n";
/* a test that we can round trip compress/decompress data using LZMA or LZIP
* formats */
static int roundTripTest(elzma_file_format format)
{
int rc;
unsigned char *compressed;
unsigned char *decompressed;
size_t sz;
rc = simpleCompress(format, (unsigned char *)sampleData, strlen(sampleData), &compressed,
&sz);
if (rc != ELZMA_E_OK)
return rc;
/* gross assurance that compression is actually compressing */
if (sz > strlen(sampleData))
{
free(compressed);
return 1;
}
rc = simpleDecompress(format, compressed, sz, &decompressed, &sz);
free(compressed);
if (rc != ELZMA_E_OK)
return rc;
if (sz != strlen(sampleData) || 0 != memcmp(decompressed, sampleData, sz))
{
free(decompressed);
return 1;
}
return ELZMA_E_OK;
}
/* "correct" lzip generated from the lzip program */
/*|LZIP...3.?..????|*/
/*|....?e2~........|*/
static unsigned char correctLzip[] = {
0x4c, 0x5a, 0x49, 0x50, 0x01, 0x0c, 0x00, 0x33, 0x1b, 0xec, 0x15, 0x07, 0xff, 0xff,
0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* "correct" lzip generated from lzma utils */
static unsigned char correctLzma[] = {0x5d, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x1b, 0xec, 0x14, 0x00, 0x00, 0x00};
/* lzip with a bad CRC */
static unsigned char corruptCRC[] = {
0x4c, 0x5a, 0x49, 0x50, 0x01, 0x0c, 0x00, 0x33, 0x1b, 0xec, 0x15, 0x07, 0xff, 0xff,
0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xa8, 0x65, 0x31, 0x7e, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* lzip with a bad uncompressed size */
static unsigned char corruptSize[] = {
0x4c, 0x5a, 0x49, 0x50, 0x01, 0x0c, 0x00, 0x33, 0x1b, 0xec, 0x15, 0x07, 0xff, 0xff,
0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* lzma with a bad uncompressed size */
static unsigned char corruptSizeLzma[] = {0x5d, 0x00, 0x00, 0x80, 0x00, 0x04, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x1b, 0xec, 0x14, 0x00, 0x00, 0x00};
/* lzma with a bad uncompressed size */
static unsigned char corruptSizeLzma2[] = {0x5d, 0x00, 0x00, 0x80, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x1b, 0xec, 0x14, 0x00, 0x00, 0x00};
/* tests */
static struct
{
const char *testName; /* the name of the test */
int expectedCode; /* the expected output of the test */
elzma_file_format format;
unsigned char *data; /* input data */
unsigned int dataSize;
} tests[] = {
{"correct lzip", ELZMA_E_OK, ELZMA_lzip, correctLzip, sizeof(correctLzip)},
{"lzip as lzma", ELZMA_E_DECOMPRESS_ERROR, ELZMA_lzma, correctLzip, sizeof(correctLzip)},
{"correct lzma", ELZMA_E_OK, ELZMA_lzma, correctLzma, sizeof(correctLzma)},
{"lzma as lzip", ELZMA_E_CORRUPT_HEADER, ELZMA_lzip, correctLzma, sizeof(correctLzma)},
{"corrupt crc", ELZMA_E_CRC32_MISMATCH, ELZMA_lzip, corruptCRC, sizeof(corruptCRC)},
{"bad lzip size", ELZMA_E_SIZE_MISMATCH, ELZMA_lzip, corruptSize, sizeof(corruptSize)},
{"bad lzma size", ELZMA_E_INSUFFICIENT_INPUT, ELZMA_lzma,
corruptSizeLzma, sizeof(corruptSizeLzma)},
{"bad lzma size 2", ELZMA_E_SIZE_MISMATCH, ELZMA_lzma,
corruptSizeLzma2, sizeof(corruptSizeLzma2)}};
int main(void)
{
unsigned int i;
unsigned int testsPassed = 0;
unsigned int testsRun = 0;
int rc = 0;
printf("round trip lzma test: ");
fflush(stdout);
testsRun++;
if (ELZMA_E_OK != (rc = roundTripTest(ELZMA_lzma)))
{
printf("fail! (%d)\n", rc);
}
else
{
testsPassed++;
printf("ok\n");
}
printf("round trip lzip test: ");
fflush(stdout);
testsRun++;
if (ELZMA_E_OK != (rc = roundTripTest(ELZMA_lzip)))
{
printf("fail (%d)!\n", rc);
}
else
{
testsPassed++;
printf("ok\n");
}
/* now run through the tests table */
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
{
unsigned char *decompressed = NULL;
size_t sz = 0;
printf("%s test: ", tests[i].testName);
rc = simpleDecompress(tests[i].format, tests[i].data, tests[i].dataSize, &decompressed,
&sz);
testsRun++;
if (rc != tests[i].expectedCode)
{
printf("fail - got %d - expected %d\n", rc, tests[i].expectedCode);
}
else
{
testsPassed++;
printf("ok\n");
free(decompressed);
}
}
printf("\n%d/%d tests passed\n", testsPassed, testsRun);
return (testsPassed == testsRun) ? 0 : 1;
}

View File

@ -1,557 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*
* command line elzma tool for lzma compression
*
* At time of writing, the primary purpose of this tool is to test the
* easylzma library.
*
* TODO:
* - stdin/stdout support
* - multiple file support
* - much more
*/
#include "include/compress.h"
#include "include/decompress.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#ifdef WIN32
#include <stdio.h>
#define unlink _unlink
#else
#include <unistd.h>
#endif
int deleteFile(const char *path)
{
return unlink(path);
}
/* a utility to open a pair of files */
/* XXX: respect overwrite flag */
static int openFiles(const char *ifname, FILE **inFile, const char *ofname, FILE **outFile,
int overwrite)
{
*inFile = fopen(ifname, "rb");
if (*inFile == NULL)
{
fprintf(stderr, "couldn't open '%s' for reading\n", ifname);
return 1;
}
*outFile = fopen(ofname, "wb");
if (*outFile == NULL)
{
fprintf(stderr, "couldn't open '%s' for writing\n", ofname);
return 1;
}
return 0;
}
#define ELZMA_COMPRESS_USAGE \
"Compress files using the LZMA algorithm (in place by default).\n" \
"\n" \
"Usage: elzma [options] [file]\n" \
" -1 .. -9 compression level, -1 is fast, -9 is best (default 5)\n" \
" -f, --force overwrite output files if they exist\n" \
" -h, --help output this message and exit\n" \
" -k, --keep don't delete input files\n" \
" --lzip compress to lzip disk format (.lz extension)\n" \
" --lzma compress to LZMA-Alone disk format (.lzma extension)\n" \
" -v, --verbose output verbose status information while compressing\n" \
" -z, --compress compress files (default when invoking elzma program)\n" \
" -d, --decompress decompress files (default when invoking unelzma program)\n" \
"\n" \
"Advanced Options:\n" \
" -s --set-max-dict (advanced) specify maximum dictionary size in bytes\n"
/* parse arguments populating output parameters, return nonzero on failure */
static int parseCompressArgs(int argc, char **argv, unsigned char *level, char **fname,
unsigned int *maxDictSize, unsigned int *verbose,
unsigned int *keep, unsigned int *overwrite,
elzma_file_format *format)
{
int i;
if (argc < 2)
return 1;
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
char *val = NULL;
char *arg = &(argv[i][1]);
if (arg[0] == '-')
arg++;
/* now see what argument this is */
if (!strcmp(arg, "h") || !strcmp(arg, "help"))
{
return 1;
}
else if (!strcmp(arg, "s") || !strcmp(arg, "set-max-dict"))
{
unsigned int j = 0;
val = argv[++i];
/* validate argument is numeric */
for (j = 0; j < strlen(val); j++)
{
if (val[j] < '0' || val[j] > '9')
return 1;
}
*maxDictSize = strtoul(val, (char **)NULL, 10);
/* don't allow dictionary sizes less than 8k */
if (*maxDictSize < (1 < 13))
*maxDictSize = 1 < 13;
else
{
/* make sure dict size is compatible with lzip,
* this will effectively collapse it to a close power
* of 2 */
*maxDictSize = elzma_get_dict_size(*maxDictSize);
}
}
else if (!strcmp(arg, "v") || !strcmp(arg, "verbose"))
{
*verbose = 1;
}
else if (!strcmp(arg, "f") || !strcmp(arg, "force"))
{
*overwrite = 1;
}
else if (!strcmp(arg, "k") || !strcmp(arg, "keep"))
{
*keep = 1;
}
else if (strlen(arg) == 1 && arg[0] >= '1' && arg[0] <= '9')
{
*level = arg[0] - '0';
}
else if (!strcmp(arg, "lzma"))
{
*format = ELZMA_lzma;
}
else if (!strcmp(arg, "lzip"))
{
*format = ELZMA_lzip;
}
else if (!strcmp(arg, "z") || !strcmp(arg, "d") || !strcmp(arg, "compress") ||
!strcmp(arg, "decompress"))
{
/* noop */
}
else
{
return 1;
}
}
else
{
*fname = argv[i];
break;
}
}
/* proper number of arguments? */
if (i != argc - 1 || *fname == NULL)
return 1;
return 0;
}
/* callbacks for streamed input and output */
static size_t elzmaWriteFunc(void *ctx, const void *buf, size_t size)
{
size_t wt;
FILE *f = (FILE *)ctx;
assert(f != NULL);
wt = fwrite(buf, 1, size, f);
return wt;
}
static int elzmaReadFunc(void *ctx, void *buf, size_t *size)
{
FILE *f = (FILE *)ctx;
assert(f != NULL);
*size = fread(buf, 1, *size, f);
return 0;
}
static void printProgressHeader(void)
{
printf("|0%% 50%% 100%%|\n");
}
static void endProgress(int pCtx)
{
while (pCtx++ < 64)
{
printf(".");
}
printf("|\n");
}
static void elzmaProgressFunc(void *ctx, size_t complete, size_t total)
{
int *dots = (int *)ctx;
int wantDots = (int)(64 * (double)complete / (double)total);
if (*dots == 0)
{
printf("|");
(*dots)++;
}
while (wantDots > *dots)
{
printf(".");
(*dots)++;
}
fflush(stdout);
}
static int doCompress(int argc, char **argv)
{
/* default compression parameters, some of which may be overridded by
* command line arguments */
unsigned char level = 5;
unsigned char lc = ELZMA_LC_DEFAULT;
unsigned char lp = ELZMA_LP_DEFAULT;
unsigned char pb = ELZMA_PB_DEFAULT;
unsigned int maxDictSize = ELZMA_DICT_SIZE_DEFAULT_MAX;
unsigned int dictSize = 0;
elzma_file_format format = ELZMA_lzma;
char *ext = ".lzma";
char *ifname = NULL;
char *ofname = NULL;
unsigned int verbose = 0;
FILE *inFile = NULL;
FILE *outFile = NULL;
elzma_compress_handle hand = NULL;
/* XXX: large file support */
unsigned int uncompressedSize = 0;
unsigned int keep = 0;
unsigned int overwrite = 0;
if (0 != parseCompressArgs(argc, argv, &level, &ifname, &maxDictSize, &verbose, &keep,
&overwrite, &format))
{
fprintf(stderr, ELZMA_COMPRESS_USAGE);
return 1;
}
/* extension switching based on compression type*/
if (format == ELZMA_lzip)
ext = ".lz";
/* generate output file name */
{
ofname = malloc(strlen(ifname) + strlen(ext) + 1);
ofname[0] = 0;
strcat(ofname, ifname);
strcat(ofname, ext);
}
/* now attempt to open input and ouput files */
/* XXX: stdin/stdout support */
if (0 != openFiles(ifname, &inFile, ofname, &outFile, overwrite))
{
return 1;
}
/* set uncompressed size */
if (0 != fseek(inFile, 0, SEEK_END) || 0 == (uncompressedSize = ftell(inFile)) ||
0 != fseek(inFile, 0, SEEK_SET))
{
fprintf(stderr, "error seeking input file (%s) - zero length?\n", ifname);
deleteFile(ofname);
return 1;
}
/* determine a reasonable dictionary size given input size */
dictSize = elzma_get_dict_size(uncompressedSize);
if (dictSize > maxDictSize)
dictSize = maxDictSize;
if (verbose)
{
printf("compressing '%s' to '%s'\n", ifname, ofname);
printf("lc/lp/pb = %u/%u/%u | dictionary size = %u bytes\n", lc, lp, pb, dictSize);
printf("input file is %u bytes\n", uncompressedSize);
}
/* allocate a compression handle */
hand = elzma_compress_alloc();
if (hand == NULL)
{
fprintf(stderr, "couldn't allocate compression object\n");
deleteFile(ofname);
return 1;
}
if (ELZMA_E_OK !=
elzma_compress_config(hand, lc, lp, pb, level, dictSize, format, uncompressedSize))
{
fprintf(stderr, "couldn't configure compression with "
"provided parameters\n");
deleteFile(ofname);
return 1;
}
{
int rv;
int pCtx = 0;
if (verbose)
printProgressHeader();
rv = elzma_compress_run(hand, elzmaReadFunc, (void *)inFile, elzmaWriteFunc,
(void *)outFile, (verbose ? elzmaProgressFunc : NULL), &pCtx);
if (verbose)
endProgress(pCtx);
if (ELZMA_E_OK != rv)
{
fprintf(stderr, "error compressing\n");
deleteFile(ofname);
return 1;
}
}
/* clean up */
elzma_compress_free(&hand);
fclose(inFile);
fclose(outFile);
free(ofname);
if (!keep)
deleteFile(ifname);
return 0;
}
#define ELZMA_DECOMPRESS_USAGE \
"Decompress files compressed using the LZMA algorithm (in place by default).\n" \
"\n" \
"Usage: unelzma [options] [file]\n" \
" -f, --force overwrite output files if they exist\n" \
" -h, --help output this message and exit\n" \
" -k, --keep don't delete input files\n" \
" -v, --verbose output verbose status information while decompressing\n" \
" -z, --compress compress files (default when invoking elzma program)\n" \
" -d, --decompress decompress files (default when invoking unelzma program)\n" \
"\n"
/* parse arguments populating output parameters, return nonzero on failure */
static int parseDecompressArgs(int argc, char **argv, char **fname, unsigned int *verbose,
unsigned int *keep, unsigned int *overwrite)
{
int i;
if (argc < 2)
return 1;
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
char *arg = &(argv[i][1]);
if (arg[0] == '-')
arg++;
/* now see what argument this is */
if (!strcmp(arg, "h") || !strcmp(arg, "help"))
{
return 1;
}
else if (!strcmp(arg, "v") || !strcmp(arg, "verbose"))
{
*verbose = 1;
}
else if (!strcmp(arg, "k") || !strcmp(arg, "keep"))
{
*keep = 1;
}
else if (!strcmp(arg, "f") || !strcmp(arg, "force"))
{
*overwrite = 1;
}
else if (!strcmp(arg, "z") || !strcmp(arg, "d") || !strcmp(arg, "compress") ||
!strcmp(arg, "decompress"))
{
/* noop */
}
else
{
return 1;
}
}
else
{
*fname = argv[i];
break;
}
}
/* proper number of arguments? */
if (i != argc - 1 || *fname == NULL)
return 1;
return 0;
}
static int doDecompress(int argc, char **argv)
{
char *ifname = NULL;
char *ofname = NULL;
unsigned int verbose = 0;
FILE *inFile = NULL;
FILE *outFile = NULL;
elzma_decompress_handle hand = NULL;
unsigned int overwrite = 0;
unsigned int keep = 0;
elzma_file_format format;
const char *lzmaExt = ".lzma";
const char *lzipExt = ".lz";
const char *ext = ".lz";
if (0 != parseDecompressArgs(argc, argv, &ifname, &verbose, &keep, &overwrite))
{
fprintf(stderr, ELZMA_DECOMPRESS_USAGE);
return 1;
}
/* generate output file name */
if (strlen(ifname) > strlen(lzmaExt) &&
0 == strcmp(lzmaExt, ifname + strlen(ifname) - strlen(lzmaExt)))
{
format = ELZMA_lzma;
ext = lzmaExt;
}
else if (strlen(ifname) > strlen(lzipExt) &&
0 == strcmp(lzipExt, ifname + strlen(ifname) - strlen(lzipExt)))
{
format = ELZMA_lzip;
ext = lzipExt;
}
else
{
fprintf(stderr, "input file extension not recognized (expected either "
"%s or %s)",
lzmaExt, lzipExt);
return 1;
}
ofname = malloc(strlen(ifname) - strlen(ext));
ofname[0] = 0;
strncat(ofname, ifname, strlen(ifname) - strlen(ext));
/* now attempt to open input and ouput files */
/* XXX: stdin/stdout support */
if (0 != openFiles(ifname, &inFile, ofname, &outFile, overwrite))
{
return 1;
}
hand = elzma_decompress_alloc();
if (hand == NULL)
{
fprintf(stderr, "couldn't allocate decompression object\n");
deleteFile(ofname);
return 1;
}
if (ELZMA_E_OK != elzma_decompress_run(hand, elzmaReadFunc, (void *)inFile, elzmaWriteFunc,
(void *)outFile, format))
{
fprintf(stderr, "error decompressing\n");
deleteFile(ofname);
return 1;
}
elzma_decompress_free(&hand);
if (!keep)
deleteFile(ifname);
return 0;
}
int main(int argc, char **argv)
{
const char *unelzma = "unelzma";
const char *unelzmaLose = "unelzma.exe";
const char *elzma = "elzma";
const char *elzmaLose = "elzma.exe";
enum
{
RM_NONE,
RM_COMPRESS,
RM_DECOMPRESS
} runmode = RM_NONE;
/* first we'll determine the mode we're running in, indicated by
* the binary name (argv[0]) or by the presence of a flag:
* one of -z, -d, -compress, --decompress */
if ((strlen(argv[0]) >= strlen(unelzma) &&
!strcmp((argv[0] + strlen(argv[0]) - strlen(unelzma)), unelzma)) ||
(strlen(argv[0]) >= strlen(unelzmaLose) &&
!strcmp((argv[0] + strlen(argv[0]) - strlen(unelzmaLose)), unelzmaLose)))
{
runmode = RM_DECOMPRESS;
}
else if ((strlen(argv[0]) >= strlen(elzma) &&
!strcmp((argv[0] + strlen(argv[0]) - strlen(elzma)), elzma)) ||
(strlen(argv[0]) >= strlen(elzmaLose) &&
!strcmp((argv[0] + strlen(argv[0]) - strlen(elzmaLose)), elzmaLose)))
{
runmode = RM_COMPRESS;
}
/* allow runmode to be overridded by a command line flag, first flag
* wins */
{
int i;
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--decompress"))
{
runmode = RM_DECOMPRESS;
break;
}
else if (!strcmp(argv[i], "-z") || !strcmp(argv[i], "--compress"))
{
runmode = RM_COMPRESS;
break;
}
}
}
if (runmode != RM_COMPRESS && runmode != RM_DECOMPRESS)
{
fprintf(stderr, "couldn't determine whether "
"you want to compress or decompress\n");
return 1;
}
if (runmode == RM_COMPRESS)
return doCompress(argc, argv);
return doDecompress(argc, argv);
}

View File

@ -1,118 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*
* easylzma/common.h - definitions common to both compression and
* decompression
*/
#pragma once
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/* msft dll export gunk. To build a DLL on windows, you
* must define WIN32, EASYLZMA_SHARED, and EASYLZMA_BUILD. To use a
* DLL, you must define EASYLZMA_SHARED and WIN32 */
#if defined(WIN32) && defined(EASYLZMA_SHARED)
#ifdef EASYLZMA_BUILD
#define EASYLZMA_API __declspec(dllexport)
#else
#define EASYLZMA_API __declspec(dllimport)
#endif
#else
#define EASYLZMA_API
#endif
/** error codes */
/** no error */
#define ELZMA_E_OK 0
/** bad parameters passed to an ELZMA function */
#define ELZMA_E_BAD_PARAMS 10
/** could not initialize the encode with configured parameters. */
#define ELZMA_E_ENCODING_PROPERTIES_ERROR 11
/** an error occured during compression (XXX: be more specific) */
#define ELZMA_E_COMPRESS_ERROR 12
/** currently unsupported lzma file format was specified*/
#define ELZMA_E_UNSUPPORTED_FORMAT 13
/** an error occured when reading input */
#define ELZMA_E_INPUT_ERROR 14
/** an error occured when writing output */
#define ELZMA_E_OUTPUT_ERROR 15
/** LZMA header couldn't be parsed */
#define ELZMA_E_CORRUPT_HEADER 16
/** an error occured during decompression (XXX: be more specific) */
#define ELZMA_E_DECOMPRESS_ERROR 17
/** the input stream returns EOF before the decompression could complete */
#define ELZMA_E_INSUFFICIENT_INPUT 18
/** for formats which have an emebedded crc, this error would indicated that
* what came out was not what went in, i.e. data corruption */
#define ELZMA_E_CRC32_MISMATCH 19
/** for formats which have an emebedded uncompressed content length,
* this error indicates that the amount we read was not what we expected */
#define ELZMA_E_SIZE_MISMATCH 20
/** Supported file formats */
typedef enum
{
ELZMA_lzip, /**< the lzip format which includes a magic number and
* CRC check */
ELZMA_lzma /**< the LZMA-Alone format, originally designed by
* Igor Pavlov and in widespread use due to lzmautils,
* lacking both aforementioned features of lzip */
/* XXX: future, potentially ,
ELZMA_xz
*/
} elzma_file_format;
/**
* A callback invoked during elzma_[de]compress_run when the [de]compression
* process has generated [de]compressed output.
*
* the size parameter indicates how much data is in buf to be written.
* it is required that the write callback consume all data, and a return
* value not equal to input size indicates and error.
*/
typedef size_t (*elzma_write_callback)(void *ctx, const void *buf, size_t size);
/**
* A callback invoked during elzma_[de]compress_run when the [de]compression
* process requires more [un]compressed input.
*
* the size parameter is an in/out argument. on input it indicates
* the buffer size. on output it indicates the amount of data read into
* buf. when *size is zero on output it indicates EOF.
*
* \returns the read callback should return nonzero on failure.
*/
typedef int (*elzma_read_callback)(void *ctx, void *buf, size_t *size);
/**
* A callback invoked during elzma_[de]compress_run to report progress
* on the [de]compression.
*
* \returns the read callback should return nonzero on failure.
*/
typedef void (*elzma_progress_callback)(void *ctx, size_t complete, size_t total);
/** pointer to a malloc function, supporting client overriding memory
* allocation routines */
typedef void *(*elzma_malloc)(void *ctx, unsigned int sz);
/** pointer to a free function, supporting client overriding memory
* allocation routines */
typedef void (*elzma_free)(void *ctx, void *ptr);
#ifdef __cplusplus
}
;
#endif

View File

@ -1,77 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*
* compress.h - the API for LZMA compression using easylzma
*/
#pragma once
#include "common.h"
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/** suggested default values */
#define ELZMA_LC_DEFAULT 3
#define ELZMA_LP_DEFAULT 0
#define ELZMA_PB_DEFAULT 2
#define ELZMA_DICT_SIZE_DEFAULT_MAX (1 << 24)
/** an opaque handle to an lzma compressor */
typedef struct _elzma_compress_handle *elzma_compress_handle;
/**
* Allocate a handle to an LZMA compressor object.
*/
elzma_compress_handle EASYLZMA_API elzma_compress_alloc();
/**
* set allocation routines (optional, if not called malloc & free will
* be used)
*/
void EASYLZMA_API
elzma_compress_set_allocation_callbacks(elzma_compress_handle hand, elzma_malloc mallocFunc,
void *mallocFuncContext, elzma_free freeFunc,
void *freeFuncContext);
/**
* Free all data associated with an LZMA compressor object.
*/
void EASYLZMA_API elzma_compress_free(elzma_compress_handle *hand);
/**
* Set configuration paramters for a compression run. If not called,
* reasonable defaults will be used.
*/
int EASYLZMA_API elzma_compress_config(elzma_compress_handle hand, unsigned char lc,
unsigned char lp, unsigned char pb, unsigned char level,
unsigned int dictionarySize, elzma_file_format format,
unsigned long long uncompressedSize);
/**
* Run compression
*/
int EASYLZMA_API
elzma_compress_run(elzma_compress_handle hand, elzma_read_callback inputStream,
void *inputContext, elzma_write_callback outputStream, void *outputContext,
elzma_progress_callback progressCallback, void *progressContext);
/**
* a heuristic utility routine to guess a dictionary size that gets near
* optimal compression while reducing memory usage.
* accepts a size in bytes, returns a proposed dictionary size
*/
unsigned int EASYLZMA_API elzma_get_dict_size(unsigned long long size);
#ifdef __cplusplus
}
;
#endif

View File

@ -1,58 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*
* easylzma/decompress.h - The API for LZMA decompression using easylzma
*/
#pragma once
#include "include/common.h"
#ifdef __cplusplus
extern "C" {
#endif
/** an opaque handle to an lzma decompressor */
typedef struct _elzma_decompress_handle *elzma_decompress_handle;
/**
* Allocate a handle to an LZMA decompressor object.
*/
elzma_decompress_handle EASYLZMA_API elzma_decompress_alloc();
/**
* set allocation routines (optional, if not called malloc & free will
* be used)
*/
void EASYLZMA_API
elzma_decompress_set_allocation_callbacks(elzma_decompress_handle hand, elzma_malloc mallocFunc,
void *mallocFuncContext, elzma_free freeFunc,
void *freeFuncContext);
/**
* Free all data associated with an LZMA decompressor object.
*/
void EASYLZMA_API elzma_decompress_free(elzma_decompress_handle *hand);
/**
* Perform decompression
*
* XXX: should the library automatically detect format by reading stream?
* currently it's based on data external to stream (such as extension
* or convention)
*/
int EASYLZMA_API elzma_decompress_run(elzma_decompress_handle hand,
elzma_read_callback inputStream, void *inputContext,
elzma_write_callback outputStream, void *outputContext,
elzma_file_format format);
#ifdef __cplusplus
}
;
#endif

View File

@ -1,37 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*
* simple.h - a wrapper around easylzma to compress/decompress to memory
*/
#pragma once
#include "include/common.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "include/compress.h"
#include "include/decompress.h"
/* compress a chunk of memory and return a dynamically allocated buffer
* if successful. return value is an easylzma error code */
int EASYLZMA_API simpleCompress(elzma_file_format format, const unsigned char *inData,
size_t inLen, unsigned char **outData, size_t *outLen);
/* decompress a chunk of memory and return a dynamically allocated buffer
* if successful. return value is an easylzma error code */
int EASYLZMA_API simpleDecompress(elzma_file_format format, const unsigned char *inData,
size_t inLen, unsigned char **outData, size_t *outLen);
#ifdef __cplusplus
}
;
#endif

View File

@ -1,35 +0,0 @@
/* 7zCrc.c -- CRC32 calculation
2008-08-05
Igor Pavlov
Public domain */
#include "7zCrc.h"
#define kCrcPoly 0xEDB88320
uint32_t g_CrcTable[256];
void MY_FAST_CALL CrcGenerateTable(void)
{
uint32_t i;
for (i = 0; i < 256; i++)
{
uint32_t r = i;
int j;
for (j = 0; j < 8; j++)
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
g_CrcTable[i] = r;
}
}
uint32_t MY_FAST_CALL CrcUpdate(uint32_t v, const void *data, size_t size)
{
const uint8_t *p = (const uint8_t *)data;
for (; size > 0; size--, p++)
v = CRC_UPDATE_BYTE(v, *p);
return v;
}
uint32_t MY_FAST_CALL CrcCalc(const void *data, size_t size)
{
return CrcUpdate(CRC_INIT_VAL, data, size) ^ 0xFFFFFFFF;
}

View File

@ -1,24 +0,0 @@
/* 7zCrc.h -- CRC32 calculation
2008-03-13
Igor Pavlov
Public domain */
#ifndef __7Z_CRC_H
#define __7Z_CRC_H
#include <stddef.h>
#include "Types.h"
extern uint32_t g_CrcTable[];
void MY_FAST_CALL CrcGenerateTable(void);
#define CRC_INIT_VAL 0xFFFFFFFF
#define CRC_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFF)
#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
uint32_t MY_FAST_CALL CrcUpdate(uint32_t crc, const void *data, size_t size);
uint32_t MY_FAST_CALL CrcCalc(const void *data, size_t size);
#endif

View File

@ -1,779 +0,0 @@
/* LzFind.c -- Match finder for LZ algorithms
2008-10-04 : Igor Pavlov : Public domain */
#include <string.h>
#include <stdlib.h>
#include "LzFind.h"
#include "LzHash.h"
#define kEmptyHashValue 0
#define kMaxValForNormalize ((uint32_t)0xFFFFFFFF)
#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
#define kNormalizeMask (~(kNormalizeStepMin - 1))
#define kMaxHistorySize ((uint32_t)3 << 30)
#define kStartMaxLen 3
static void LzInWindow_Free(CMatchFinder *p)
{
if (!p->directInput)
{
free(p->bufferBase);
p->bufferBase = 0;
}
}
/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
static int LzInWindow_Create(CMatchFinder *p, uint32_t keepSizeReserv)
{
uint32_t blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
if (p->directInput)
{
p->blockSize = blockSize;
return 1;
}
if (p->bufferBase == 0 || p->blockSize != blockSize)
{
LzInWindow_Free(p);
p->blockSize = blockSize;
p->bufferBase = (uint8_t *)malloc((size_t)blockSize);
}
return (p->bufferBase != 0);
}
uint8_t *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p)
{
return p->buffer;
}
uint8_t MatchFinder_GetIndexByte(CMatchFinder *p, int32_t index)
{
return p->buffer[index];
}
uint32_t MatchFinder_GetNumAvailableBytes(CMatchFinder *p)
{
return p->streamPos - p->pos;
}
void MatchFinder_ReduceOffsets(CMatchFinder *p, uint32_t subValue)
{
p->posLimit -= subValue;
p->pos -= subValue;
p->streamPos -= subValue;
}
static void MatchFinder_ReadBlock(CMatchFinder *p)
{
if (p->streamEndWasReached || p->result != SZ_OK)
return;
for (;;)
{
uint8_t *dest = p->buffer + (p->streamPos - p->pos);
size_t size = (p->bufferBase + p->blockSize - dest);
if (size == 0)
return;
p->result = p->stream->Read(p->stream, dest, &size);
if (p->result != SZ_OK)
return;
if (size == 0)
{
p->streamEndWasReached = 1;
return;
}
p->streamPos += (uint32_t)size;
if (p->streamPos - p->pos > p->keepSizeAfter)
return;
}
}
void MatchFinder_MoveBlock(CMatchFinder *p)
{
memmove(p->bufferBase, p->buffer - p->keepSizeBefore,
(size_t)(p->streamPos - p->pos + p->keepSizeBefore));
p->buffer = p->bufferBase + p->keepSizeBefore;
}
int MatchFinder_NeedMove(CMatchFinder *p)
{
/* if (p->streamEndWasReached) return 0; */
return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
}
void MatchFinder_ReadIfRequired(CMatchFinder *p)
{
if (p->streamEndWasReached)
return;
if (p->keepSizeAfter >= p->streamPos - p->pos)
MatchFinder_ReadBlock(p);
}
static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
{
if (MatchFinder_NeedMove(p))
MatchFinder_MoveBlock(p);
MatchFinder_ReadBlock(p);
}
static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
{
p->cutValue = 32;
p->btMode = 1;
p->numHashBytes = 4;
/* p->skipModeBits = 0; */
p->directInput = 0;
p->bigHash = 0;
}
#define kCrcPoly 0xEDB88320
void MatchFinder_Construct(CMatchFinder *p)
{
uint32_t i;
p->bufferBase = 0;
p->directInput = 0;
p->hash = 0;
MatchFinder_SetDefaultSettings(p);
for (i = 0; i < 256; i++)
{
uint32_t r = i;
int j;
for (j = 0; j < 8; j++)
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
p->crc[i] = r;
}
}
static void MatchFinder_FreeThisClassMemory(CMatchFinder *p)
{
free(p->hash);
p->hash = 0;
}
void MatchFinder_Free(CMatchFinder *p)
{
MatchFinder_FreeThisClassMemory(p);
LzInWindow_Free(p);
}
static CLzRef *AllocRefs(uint32_t num)
{
size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
if (sizeInBytes / sizeof(CLzRef) != num)
return 0;
return (CLzRef *)malloc(sizeInBytes);
}
int MatchFinder_Create(CMatchFinder *p, uint32_t historySize, uint32_t keepAddBufferBefore,
uint32_t matchMaxLen, uint32_t keepAddBufferAfter)
{
uint32_t sizeReserv;
if (historySize > kMaxHistorySize)
{
MatchFinder_Free(p);
return 0;
}
sizeReserv = historySize >> 1;
if (historySize > ((uint32_t)2 << 30))
sizeReserv = historySize >> 2;
sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
/* we need one additional byte, since we use MoveBlock after pos++ and before dictionary
* using */
if (LzInWindow_Create(p, sizeReserv))
{
uint32_t newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
uint32_t hs;
p->matchMaxLen = matchMaxLen;
{
p->fixedHashSize = 0;
if (p->numHashBytes == 2)
hs = (1 << 16) - 1;
else
{
hs = historySize - 1;
hs |= (hs >> 1);
hs |= (hs >> 2);
hs |= (hs >> 4);
hs |= (hs >> 8);
hs >>= 1;
/* hs >>= p->skipModeBits; */
hs |= 0xFFFF; /* don't change it! It's required for Deflate */
if (hs > (1 << 24))
{
if (p->numHashBytes == 3)
hs = (1 << 24) - 1;
else
hs >>= 1;
}
}
p->hashMask = hs;
hs++;
if (p->numHashBytes > 2)
p->fixedHashSize += kHash2Size;
if (p->numHashBytes > 3)
p->fixedHashSize += kHash3Size;
if (p->numHashBytes > 4)
p->fixedHashSize += kHash4Size;
hs += p->fixedHashSize;
}
{
uint32_t prevSize = p->hashSizeSum + p->numSons;
uint32_t newSize;
p->historySize = historySize;
p->hashSizeSum = hs;
p->cyclicBufferSize = newCyclicBufferSize;
p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
newSize = p->hashSizeSum + p->numSons;
if (p->hash != 0 && prevSize == newSize)
return 1;
MatchFinder_FreeThisClassMemory(p);
p->hash = AllocRefs(newSize);
if (p->hash != 0)
{
p->son = p->hash + p->hashSizeSum;
return 1;
}
}
}
MatchFinder_Free(p);
return 0;
}
static void MatchFinder_SetLimits(CMatchFinder *p)
{
uint32_t limit = kMaxValForNormalize - p->pos;
uint32_t limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
if (limit2 < limit)
limit = limit2;
limit2 = p->streamPos - p->pos;
if (limit2 <= p->keepSizeAfter)
{
if (limit2 > 0)
limit2 = 1;
}
else
limit2 -= p->keepSizeAfter;
if (limit2 < limit)
limit = limit2;
{
uint32_t lenLimit = p->streamPos - p->pos;
if (lenLimit > p->matchMaxLen)
lenLimit = p->matchMaxLen;
p->lenLimit = lenLimit;
}
p->posLimit = p->pos + limit;
}
void MatchFinder_Init(CMatchFinder *p)
{
uint32_t i;
for (i = 0; i < p->hashSizeSum; i++)
p->hash[i] = kEmptyHashValue;
p->cyclicBufferPos = 0;
p->buffer = p->bufferBase;
p->pos = p->streamPos = p->cyclicBufferSize;
p->result = SZ_OK;
p->streamEndWasReached = 0;
MatchFinder_ReadBlock(p);
MatchFinder_SetLimits(p);
}
static uint32_t MatchFinder_GetSubValue(CMatchFinder *p)
{
return (p->pos - p->historySize - 1) & kNormalizeMask;
}
void MatchFinder_Normalize3(uint32_t subValue, CLzRef *items, uint32_t numItems)
{
uint32_t i;
for (i = 0; i < numItems; i++)
{
uint32_t value = items[i];
if (value <= subValue)
value = kEmptyHashValue;
else
value -= subValue;
items[i] = value;
}
}
static void MatchFinder_Normalize(CMatchFinder *p)
{
uint32_t subValue = MatchFinder_GetSubValue(p);
MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
MatchFinder_ReduceOffsets(p, subValue);
}
static void MatchFinder_CheckLimits(CMatchFinder *p)
{
if (p->pos == kMaxValForNormalize)
MatchFinder_Normalize(p);
if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
MatchFinder_CheckAndMoveAndRead(p);
if (p->cyclicBufferPos == p->cyclicBufferSize)
p->cyclicBufferPos = 0;
MatchFinder_SetLimits(p);
}
static uint32_t *Hc_GetMatchesSpec(uint32_t lenLimit, uint32_t curMatch, uint32_t pos,
const uint8_t *cur, CLzRef *son, uint32_t _cyclicBufferPos,
uint32_t _cyclicBufferSize, uint32_t cutValue,
uint32_t *distances, uint32_t maxLen)
{
son[_cyclicBufferPos] = curMatch;
for (;;)
{
uint32_t delta = pos - curMatch;
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
return distances;
{
const uint8_t *pb = cur - delta;
curMatch = son[_cyclicBufferPos - delta +
((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
if (pb[maxLen] == cur[maxLen] && *pb == *cur)
{
uint32_t len = 0;
while (++len != lenLimit)
if (pb[len] != cur[len])
break;
if (maxLen < len)
{
*distances++ = maxLen = len;
*distances++ = delta - 1;
if (len == lenLimit)
return distances;
}
}
}
}
}
uint32_t *GetMatchesSpec1(uint32_t lenLimit, uint32_t curMatch, uint32_t pos,
const uint8_t *cur, CLzRef *son, uint32_t _cyclicBufferPos,
uint32_t _cyclicBufferSize, uint32_t cutValue, uint32_t *distances,
uint32_t maxLen)
{
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
uint32_t len0 = 0, len1 = 0;
for (;;)
{
uint32_t delta = pos - curMatch;
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
{
*ptr0 = *ptr1 = kEmptyHashValue;
return distances;
}
{
CLzRef *pair = son + ((_cyclicBufferPos - delta +
((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0))
<< 1);
const uint8_t *pb = cur - delta;
uint32_t len = (len0 < len1 ? len0 : len1);
if (pb[len] == cur[len])
{
if (++len != lenLimit && pb[len] == cur[len])
while (++len != lenLimit)
if (pb[len] != cur[len])
break;
if (maxLen < len)
{
*distances++ = maxLen = len;
*distances++ = delta - 1;
if (len == lenLimit)
{
*ptr1 = pair[0];
*ptr0 = pair[1];
return distances;
}
}
}
if (pb[len] < cur[len])
{
*ptr1 = curMatch;
ptr1 = pair + 1;
curMatch = *ptr1;
len1 = len;
}
else
{
*ptr0 = curMatch;
ptr0 = pair;
curMatch = *ptr0;
len0 = len;
}
}
}
}
static void SkipMatchesSpec(uint32_t lenLimit, uint32_t curMatch, uint32_t pos,
const uint8_t *cur, CLzRef *son, uint32_t _cyclicBufferPos,
uint32_t _cyclicBufferSize, uint32_t cutValue)
{
CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
uint32_t len0 = 0, len1 = 0;
for (;;)
{
uint32_t delta = pos - curMatch;
if (cutValue-- == 0 || delta >= _cyclicBufferSize)
{
*ptr0 = *ptr1 = kEmptyHashValue;
return;
}
{
CLzRef *pair = son + ((_cyclicBufferPos - delta +
((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0))
<< 1);
const uint8_t *pb = cur - delta;
uint32_t len = (len0 < len1 ? len0 : len1);
if (pb[len] == cur[len])
{
while (++len != lenLimit)
if (pb[len] != cur[len])
break;
{
if (len == lenLimit)
{
*ptr1 = pair[0];
*ptr0 = pair[1];
return;
}
}
}
if (pb[len] < cur[len])
{
*ptr1 = curMatch;
ptr1 = pair + 1;
curMatch = *ptr1;
len1 = len;
}
else
{
*ptr0 = curMatch;
ptr0 = pair;
curMatch = *ptr0;
len0 = len;
}
}
}
}
#define MOVE_POS \
++p->cyclicBufferPos; \
p->buffer++; \
if (++p->pos == p->posLimit) \
MatchFinder_CheckLimits(p);
#define MOVE_POS_RET MOVE_POS return offset;
static void MatchFinder_MovePos(CMatchFinder *p)
{
MOVE_POS;
}
#define GET_MATCHES_HEADER2(minLen, ret_op) \
uint32_t lenLimit; \
uint32_t hashValue; \
const uint8_t *cur; \
uint32_t curMatch; \
lenLimit = p->lenLimit; \
{ \
if (lenLimit < minLen) \
{ \
MatchFinder_MovePos(p); \
ret_op; \
} \
} \
cur = p->buffer;
#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
#define MF_PARAMS(p) \
p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
#define GET_MATCHES_FOOTER(offset, maxLen) \
offset = (uint32_t)( \
GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), distances + offset, maxLen) - \
distances); \
MOVE_POS_RET;
#define SKIP_FOOTER \
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); \
MOVE_POS;
static uint32_t Bt2_MatchFinder_GetMatches(CMatchFinder *p, uint32_t *distances)
{
uint32_t offset;
GET_MATCHES_HEADER(2)
HASH2_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
offset = 0;
GET_MATCHES_FOOTER(offset, 1)
}
uint32_t Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint32_t *distances)
{
uint32_t offset;
GET_MATCHES_HEADER(3)
HASH_ZIP_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
offset = 0;
GET_MATCHES_FOOTER(offset, 2)
}
static uint32_t Bt3_MatchFinder_GetMatches(CMatchFinder *p, uint32_t *distances)
{
uint32_t hash2Value, delta2, maxLen, offset;
GET_MATCHES_HEADER(3)
HASH3_CALC;
delta2 = p->pos - p->hash[hash2Value];
curMatch = p->hash[kFix3HashSize + hashValue];
p->hash[hash2Value] = p->hash[kFix3HashSize + hashValue] = p->pos;
maxLen = 2;
offset = 0;
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
{
for (; maxLen != lenLimit; maxLen++)
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
break;
distances[0] = maxLen;
distances[1] = delta2 - 1;
offset = 2;
if (maxLen == lenLimit)
{
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
MOVE_POS_RET;
}
}
GET_MATCHES_FOOTER(offset, maxLen)
}
static uint32_t Bt4_MatchFinder_GetMatches(CMatchFinder *p, uint32_t *distances)
{
uint32_t hash2Value, hash3Value, delta2, delta3, maxLen, offset;
GET_MATCHES_HEADER(4)
HASH4_CALC;
delta2 = p->pos - p->hash[hash2Value];
delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
curMatch = p->hash[kFix4HashSize + hashValue];
p->hash[hash2Value] = p->hash[kFix3HashSize + hash3Value] =
p->hash[kFix4HashSize + hashValue] = p->pos;
maxLen = 1;
offset = 0;
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
{
distances[0] = maxLen = 2;
distances[1] = delta2 - 1;
offset = 2;
}
if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
{
maxLen = 3;
distances[offset + 1] = delta3 - 1;
offset += 2;
delta2 = delta3;
}
if (offset != 0)
{
for (; maxLen != lenLimit; maxLen++)
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
break;
distances[offset - 2] = maxLen;
if (maxLen == lenLimit)
{
SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
MOVE_POS_RET;
}
}
if (maxLen < 3)
maxLen = 3;
GET_MATCHES_FOOTER(offset, maxLen)
}
static uint32_t Hc4_MatchFinder_GetMatches(CMatchFinder *p, uint32_t *distances)
{
uint32_t hash2Value, hash3Value, delta2, delta3, maxLen, offset;
GET_MATCHES_HEADER(4)
HASH4_CALC;
delta2 = p->pos - p->hash[hash2Value];
delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
curMatch = p->hash[kFix4HashSize + hashValue];
p->hash[hash2Value] = p->hash[kFix3HashSize + hash3Value] =
p->hash[kFix4HashSize + hashValue] = p->pos;
maxLen = 1;
offset = 0;
if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
{
distances[0] = maxLen = 2;
distances[1] = delta2 - 1;
offset = 2;
}
if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
{
maxLen = 3;
distances[offset + 1] = delta3 - 1;
offset += 2;
delta2 = delta3;
}
if (offset != 0)
{
for (; maxLen != lenLimit; maxLen++)
if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
break;
distances[offset - 2] = maxLen;
if (maxLen == lenLimit)
{
p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS_RET;
}
}
if (maxLen < 3)
maxLen = 3;
offset = (uint32_t)(
Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), distances + offset, maxLen) -
(distances));
MOVE_POS_RET
}
uint32_t Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint32_t *distances)
{
uint32_t offset;
GET_MATCHES_HEADER(3)
HASH_ZIP_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
offset = (uint32_t)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), distances, 2) -
(distances));
MOVE_POS_RET
}
static void Bt2_MatchFinder_Skip(CMatchFinder *p, uint32_t num)
{
do
{
SKIP_HEADER(2)
HASH2_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
SKIP_FOOTER
} while (--num != 0);
}
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, uint32_t num)
{
do
{
SKIP_HEADER(3)
HASH_ZIP_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
SKIP_FOOTER
} while (--num != 0);
}
static void Bt3_MatchFinder_Skip(CMatchFinder *p, uint32_t num)
{
do
{
uint32_t hash2Value;
SKIP_HEADER(3)
HASH3_CALC;
curMatch = p->hash[kFix3HashSize + hashValue];
p->hash[hash2Value] = p->hash[kFix3HashSize + hashValue] = p->pos;
SKIP_FOOTER
} while (--num != 0);
}
static void Bt4_MatchFinder_Skip(CMatchFinder *p, uint32_t num)
{
do
{
uint32_t hash2Value, hash3Value;
SKIP_HEADER(4)
HASH4_CALC;
curMatch = p->hash[kFix4HashSize + hashValue];
p->hash[hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->pos;
p->hash[kFix4HashSize + hashValue] = p->pos;
SKIP_FOOTER
} while (--num != 0);
}
static void Hc4_MatchFinder_Skip(CMatchFinder *p, uint32_t num)
{
do
{
uint32_t hash2Value, hash3Value;
SKIP_HEADER(4)
HASH4_CALC;
curMatch = p->hash[kFix4HashSize + hashValue];
p->hash[hash2Value] = p->hash[kFix3HashSize + hash3Value] =
p->hash[kFix4HashSize + hashValue] = p->pos;
p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS
} while (--num != 0);
}
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, uint32_t num)
{
do
{
SKIP_HEADER(3)
HASH_ZIP_CALC;
curMatch = p->hash[hashValue];
p->hash[hashValue] = p->pos;
p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS
} while (--num != 0);
}
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
{
vTable->Init = (Mf_Init_Func)MatchFinder_Init;
vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
vTable->GetNumAvailableBytes =
(Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
vTable->GetPointerToCurrentPos =
(Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
if (!p->btMode)
{
vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
}
else if (p->numHashBytes == 2)
{
vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
}
else if (p->numHashBytes == 3)
{
vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
}
else
{
vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
}
}

View File

@ -1,107 +0,0 @@
/* LzFind.h -- Match finder for LZ algorithms
2008-10-04 : Igor Pavlov : Public domain */
#ifndef __LZFIND_H
#define __LZFIND_H
#include "Types.h"
typedef uint32_t CLzRef;
typedef struct _CMatchFinder
{
uint8_t *buffer;
uint32_t pos;
uint32_t posLimit;
uint32_t streamPos;
uint32_t lenLimit;
uint32_t cyclicBufferPos;
uint32_t cyclicBufferSize; /* it must be = (historySize + 1) */
uint32_t matchMaxLen;
CLzRef *hash;
CLzRef *son;
uint32_t hashMask;
uint32_t cutValue;
uint8_t *bufferBase;
ISeqInStream *stream;
int streamEndWasReached;
uint32_t blockSize;
uint32_t keepSizeBefore;
uint32_t keepSizeAfter;
uint32_t numHashBytes;
int directInput;
int btMode;
/* int skipModeBits; */
int bigHash;
uint32_t historySize;
uint32_t fixedHashSize;
uint32_t hashSizeSum;
uint32_t numSons;
SRes result;
uint32_t crc[256];
} CMatchFinder;
#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
int MatchFinder_NeedMove(CMatchFinder *p);
uint8_t *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
void MatchFinder_MoveBlock(CMatchFinder *p);
void MatchFinder_ReadIfRequired(CMatchFinder *p);
void MatchFinder_Construct(CMatchFinder *p);
/* Conditions:
historySize <= 3 GB
keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
*/
int MatchFinder_Create(CMatchFinder *p, uint32_t historySize, uint32_t keepAddBufferBefore,
uint32_t matchMaxLen, uint32_t keepAddBufferAfter);
void MatchFinder_Free(CMatchFinder *p);
void MatchFinder_Normalize3(uint32_t subValue, CLzRef *items, uint32_t numItems);
void MatchFinder_ReduceOffsets(CMatchFinder *p, uint32_t subValue);
uint32_t *GetMatchesSpec1(uint32_t lenLimit, uint32_t curMatch, uint32_t pos,
const uint8_t *buffer, CLzRef *son, uint32_t _cyclicBufferPos,
uint32_t _cyclicBufferSize, uint32_t _cutValue, uint32_t *distances,
uint32_t maxLen);
/*
Conditions:
Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
*/
typedef void (*Mf_Init_Func)(void *object);
typedef uint8_t (*Mf_GetIndexByte_Func)(void *object, int32_t index);
typedef uint32_t (*Mf_GetNumAvailableBytes_Func)(void *object);
typedef const uint8_t *(*Mf_GetPointerToCurrentPos_Func)(void *object);
typedef uint32_t (*Mf_GetMatches_Func)(void *object, uint32_t *distances);
typedef void (*Mf_Skip_Func)(void *object, uint32_t);
typedef struct _IMatchFinder
{
Mf_Init_Func Init;
Mf_GetIndexByte_Func GetIndexByte;
Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
Mf_GetMatches_Func GetMatches;
Mf_Skip_Func Skip;
} IMatchFinder;
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
void MatchFinder_Init(CMatchFinder *p);
uint32_t Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint32_t *distances);
uint32_t Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint32_t *distances);
void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, uint32_t num);
void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, uint32_t num);
#endif

View File

@ -1,62 +0,0 @@
/* LzHash.h -- HASH functions for LZ algorithms
2008-10-04 : Igor Pavlov : Public domain */
#pragma once
#define kHash2Size (1 << 10)
#define kHash3Size (1 << 16)
#define kHash4Size (1 << 20)
#define kFix3HashSize (kHash2Size)
#define kFix4HashSize (kHash2Size + kHash3Size)
#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
#define HASH2_CALC hashValue = cur[0] | ((uint32_t)cur[1] << 8);
#define HASH3_CALC \
{ \
uint32_t temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hashValue = (temp ^ ((uint32_t)cur[2] << 8)) & p->hashMask; \
}
#define HASH4_CALC \
{ \
uint32_t temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hash3Value = (temp ^ ((uint32_t)cur[2] << 8)) & (kHash3Size - 1); \
hashValue = (temp ^ ((uint32_t)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; \
}
#define HASH5_CALC \
{ \
uint32_t temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hash3Value = (temp ^ ((uint32_t)cur[2] << 8)) & (kHash3Size - 1); \
hash4Value = (temp ^ ((uint32_t)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
hash4Value &= (kHash4Size - 1); \
}
/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((uint32_t)cur[1] << 8)) ^ p->crc[cur[2]]) &
* 0xFFFF; */
#define HASH_ZIP_CALC \
hashValue = ((cur[2] | ((uint32_t)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
#define MT_HASH2_CALC hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
#define MT_HASH3_CALC \
{ \
uint32_t temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hash3Value = (temp ^ ((uint32_t)cur[2] << 8)) & (kHash3Size - 1); \
}
#define MT_HASH4_CALC \
{ \
uint32_t temp = p->crc[cur[0]] ^ cur[1]; \
hash2Value = temp & (kHash2Size - 1); \
hash3Value = (temp ^ ((uint32_t)cur[2] << 8)) & (kHash3Size - 1); \
hash4Value = \
(temp ^ ((uint32_t)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); \
}

File diff suppressed because it is too large Load Diff

View File

@ -1,220 +0,0 @@
/* LzmaDec.h -- LZMA Decoder
2008-10-04 : Igor Pavlov : Public domain */
#pragma once
#include "Types.h"
/* #define _LZMA_PROB32 */
/* _LZMA_PROB32 can increase the speed on some CPUs,
but memory usage for CLzmaDec::probs will be doubled in that case */
#ifdef _LZMA_PROB32
#define CLzmaProb UInt32
#else
#define CLzmaProb uint16_t
#endif
/* ---------- LZMA Properties ---------- */
#define LZMA_PROPS_SIZE 5
typedef struct _CLzmaProps
{
unsigned lc, lp, pb;
uint32_t dicSize;
} CLzmaProps;
/* LzmaProps_Decode - decodes properties
Returns:
SZ_OK
SZ_ERROR_UNSUPPORTED - Unsupported properties
*/
SRes LzmaProps_Decode(CLzmaProps *p, const uint8_t *data, unsigned size);
/* ---------- LZMA Decoder state ---------- */
/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
#define LZMA_REQUIRED_INPUT_MAX 20
typedef struct
{
CLzmaProps prop;
CLzmaProb *probs;
uint8_t *dic;
const uint8_t *buf;
uint32_t range, code;
size_t dicPos;
size_t dicBufSize;
uint32_t processedPos;
uint32_t checkDicSize;
unsigned state;
uint32_t reps[4];
unsigned remainLen;
int needFlush;
int needInitState;
uint32_t numProbs;
unsigned tempBufSize;
uint8_t tempBuf[LZMA_REQUIRED_INPUT_MAX];
} CLzmaDec;
#define LzmaDec_Construct(p) \
{ \
(p)->dic = 0; \
(p)->probs = 0; \
}
void LzmaDec_Init(CLzmaDec *p);
/* There are two types of LZMA streams:
0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
1) Stream without end mark. You must know exact uncompressed size to decompress such
stream. */
typedef enum
{
LZMA_FINISH_ANY, /* finish at any point */
LZMA_FINISH_END /* block must be finished at the end */
} ELzmaFinishMode;
/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
You must use LZMA_FINISH_END, when you know that current output buffer
covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
and output value of destLen will be less than output buffer size limit.
You can check status result also.
You can use multiple checks to test data integrity after full decompression:
1) Check Result and "status" variable.
2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
You must use correct finish mode in that case. */
typedef enum
{
LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished
without end mark */
} ELzmaStatus;
/* ELzmaStatus is used only as output value for function call */
/* ---------- Interfaces ---------- */
/* There are 3 levels of interfaces:
1) Dictionary Interface
2) Buffer Interface
3) One Call Interface
You can select any of these interfaces, but don't mix functions from different
groups for same object. */
/* There are two variants to allocate state for Dictionary Interface:
1) LzmaDec_Allocate / LzmaDec_Free
2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
You can use variant 2, if you set dictionary buffer manually.
For Buffer Interface you must always use variant 1.
LzmaDec_Allocate* can return:
SZ_OK
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_UNSUPPORTED - Unsupported properties
*/
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const uint8_t *props, unsigned propsSize);
void LzmaDec_FreeProbs(CLzmaDec *p);
SRes LzmaDec_Allocate(CLzmaDec *state, const uint8_t *prop, unsigned propsSize);
void LzmaDec_Free(CLzmaDec *state);
/* ---------- Dictionary Interface ---------- */
/* You can use it, if you want to eliminate the overhead for data copying from
dictionary to some other external buffer.
You must work with CLzmaDec variables directly in this interface.
STEPS:
LzmaDec_Constr()
LzmaDec_Allocate()
for (each new stream)
{
LzmaDec_Init()
while (it needs more decompression)
{
LzmaDec_DecodeToDic()
use data from CLzmaDec::dic and update CLzmaDec::dicPos
}
}
LzmaDec_Free()
*/
/* LzmaDec_DecodeToDic
The decoding to internal dictionary buffer (CLzmaDec::dic).
You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
finishMode:
It has meaning only if the decoding reaches output limit (dicLimit).
LZMA_FINISH_ANY - Decode just dicLimit bytes.
LZMA_FINISH_END - Stream must be finished after dicLimit.
Returns:
SZ_OK
status:
LZMA_STATUS_FINISHED_WITH_MARK
LZMA_STATUS_NOT_FINISHED
LZMA_STATUS_NEEDS_MORE_INPUT
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
SZ_ERROR_DATA - Data error
*/
SRes LzmaDec_DecodeToDic(CLzmaDec *p, size_t dicLimit, const uint8_t *src, size_t *srcLen,
ELzmaFinishMode finishMode, ELzmaStatus *status);
/* ---------- Buffer Interface ---------- */
/* It's zlib-like interface.
See LzmaDec_DecodeToDic description for information about STEPS and return results,
but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
to work with CLzmaDec variables manually.
finishMode:
It has meaning only if the decoding reaches output limit (*destLen).
LZMA_FINISH_ANY - Decode just destLen bytes.
LZMA_FINISH_END - Stream must be finished after (*destLen).
*/
SRes LzmaDec_DecodeToBuf(CLzmaDec *p, uint8_t *dest, size_t *destLen, const uint8_t *src,
size_t *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
/* ---------- One Call Interface ---------- */
/* LzmaDecode
finishMode:
It has meaning only if the decoding reaches output limit (*destLen).
LZMA_FINISH_ANY - Decode just destLen bytes.
LZMA_FINISH_END - Stream must be finished after (*destLen).
Returns:
SZ_OK
status:
LZMA_STATUS_FINISHED_WITH_MARK
LZMA_STATUS_NOT_FINISHED
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
SZ_ERROR_DATA - Data error
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_UNSUPPORTED - Unsupported properties
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
*/
SRes LzmaDecode(uint8_t *dest, size_t *destLen, const uint8_t *src, size_t *srcLen,
const uint8_t *propData, unsigned propSize, ELzmaFinishMode finishMode,
ELzmaStatus *status);

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
/* LzmaEnc.h -- LZMA Encoder
2008-10-04 : Igor Pavlov : Public domain */
#ifndef __LZMAENC_H
#define __LZMAENC_H
#include "Types.h"
#define LZMA_PROPS_SIZE 5
typedef struct _CLzmaEncProps
{
int level; /* 0 <= level <= 9 */
uint32_t dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
(1 << 12) <= dictSize <= (1 << 30) for 64-bit version
default = (1 << 24) */
int lc; /* 0 <= lc <= 8, default = 3 */
int lp; /* 0 <= lp <= 4, default = 0 */
int pb; /* 0 <= pb <= 4, default = 2 */
int algo; /* 0 - fast, 1 - normal, default = 1 */
int fb; /* 5 <= fb <= 273, default = 32 */
int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
int numHashBytes; /* 2, 3 or 4, default = 4 */
uint32_t mc; /* 1 <= mc <= (1 << 30), default = 32 */
unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
int numThreads; /* 1 or 2, default = 2 */
} CLzmaEncProps;
void LzmaEncProps_Init(CLzmaEncProps *p);
void LzmaEncProps_Normalize(CLzmaEncProps *p);
uint32_t LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
/* ---------- CLzmaEncHandle Interface ---------- */
/* LzmaEnc_* functions can return the following exit codes:
Returns:
SZ_OK - OK
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_PARAM - Incorrect paramater in props
SZ_ERROR_WRITE - Write callback error.
SZ_ERROR_PROGRESS - some break from progress callback
SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
*/
typedef void *CLzmaEncHandle;
CLzmaEncHandle LzmaEnc_Create();
void LzmaEnc_Destroy(CLzmaEncHandle p);
SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, uint8_t *properties, size_t *size);
SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
ICompressProgress *progress);
SRes LzmaEnc_MemEncode(CLzmaEncHandle p, uint8_t *dest, size_t *destLen, const uint8_t *src,
size_t srcLen, int writeEndMark, ICompressProgress *progress);
/* ---------- One Call Interface ---------- */
/* LzmaEncode
Return code:
SZ_OK - OK
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_PARAM - Incorrect paramater
SZ_ERROR_OUTPUT_EOF - output buffer overflow
SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
*/
SRes LzmaEncode(uint8_t *dest, size_t *destLen, const uint8_t *src, size_t srcLen,
const CLzmaEncProps *props, uint8_t *propsEncoded, size_t *propsSize,
int writeEndMark, ICompressProgress *progress);
#endif

View File

@ -1,41 +0,0 @@
/* LzmaLib.c -- LZMA library wrapper
2008-08-05
Igor Pavlov
Public domain */
#include "LzmaEnc.h"
#include "LzmaDec.h"
#include "LzmaLib.h"
MY_STDAPI
LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
unsigned char *outProps, size_t *outPropsSize,
int level, /* 0 <= level <= 9, default = 5 */
unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */
int lc, /* 0 <= lc <= 8, default = 3 */
int lp, /* 0 <= lp <= 4, default = 0 */
int pb, /* 0 <= pb <= 4, default = 2 */
int fb, /* 5 <= fb <= 273, default = 32 */
int numThreads /* 1 or 2, default = 2 */
)
{
CLzmaEncProps props;
LzmaEncProps_Init(&props);
props.level = level;
props.dictSize = dictSize;
props.lc = lc;
props.lp = lp;
props.pb = pb;
props.fb = fb;
props.numThreads = numThreads;
return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, NULL);
}
MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src,
size_t *srcLen, const unsigned char *props, size_t propsSize)
{
ELzmaStatus status;
return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY,
&status);
}

View File

@ -1,137 +0,0 @@
/* LzmaLib.h -- LZMA library interface
2008-08-05
Igor Pavlov
Public domain */
#ifndef __LZMALIB_H
#define __LZMALIB_H
#include "Types.h"
#ifdef __cplusplus
#define MY_EXTERN_C extern "C"
#else
#define MY_EXTERN_C extern
#endif
#define MY_STDAPI MY_EXTERN_C int MY_STD_CALL
#define LZMA_PROPS_SIZE 5
/*
RAM requirements for LZMA:
for compression: (dictSize * 11.5 + 6 MB) + state_size
for decompression: dictSize + state_size
state_size = (4 + (1.5 << (lc + lp))) KB
by default (lc=3, lp=0), state_size = 16 KB.
LZMA properties (5 bytes) format
Offset Size Description
0 1 lc, lp and pb in encoded form.
1 4 dictSize (little endian).
*/
/*
LzmaCompress
------------
outPropsSize -
In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
Out: the pointer to the size of written properties in outProps buffer; *outPropsSize =
LZMA_PROPS_SIZE = 5.
LZMA Encoder will use defult values for any parameter, if it is
-1 for any from: level, loc, lp, pb, fb, numThreads
0 for dictSize
level - compression level: 0 <= level <= 9;
level dictSize algo fb
0: 16 KB 0 32
1: 64 KB 0 32
2: 256 KB 0 32
3: 1 MB 0 32
4: 4 MB 0 32
5: 16 MB 1 32
6: 32 MB 1 32
7+: 64 MB 1 64
The default value for "level" is 5.
algo = 0 means fast method
algo = 1 means normal method
dictSize - The dictionary size in bytes. The maximum value is
128 MB = (1 << 27) bytes for 32-bit version
1 GB = (1 << 30) bytes for 64-bit version
The default value is 16 MB = (1 << 24) bytes.
It's recommended to use the dictionary that is larger than 4 KB and
that can be calculated as (1 << N) or (3 << N) sizes.
lc - The number of literal context bits (high bits of previous literal).
It can be in the range from 0 to 8. The default value is 3.
Sometimes lc=4 gives the gain for big files.
lp - The number of literal pos bits (low bits of current position for literals).
It can be in the range from 0 to 4. The default value is 0.
The lp switch is intended for periodical data when the period is equal to 2^lp.
For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's
better to set lc=0, if you change lp switch.
pb - The number of pos bits (low bits of current position).
It can be in the range from 0 to 4. The default value is 2.
The pb switch is intended for periodical data when the period is equal 2^pb.
fb - Word size (the number of fast bytes).
It can be in the range from 5 to 273. The default value is 32.
Usually, a big number gives a little bit better compression ratio and
slower compression process.
numThreads - The number of thereads. 1 or 2. The default value is 2.
Fast mode (algo = 0) can use only 1 thread.
Out:
destLen - processed output size
Returns:
SZ_OK - OK
SZ_ERROR_MEM - Memory allocation error
SZ_ERROR_PARAM - Incorrect paramater
SZ_ERROR_OUTPUT_EOF - output buffer overflow
SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
*/
MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src,
size_t srcLen, unsigned char *outProps,
size_t *outPropsSize, /* *outPropsSize must be = 5 */
int level, /* 0 <= level <= 9, default = 5 */
unsigned dictSize, /* default = (1 << 24) */
int lc, /* 0 <= lc <= 8, default = 3 */
int lp, /* 0 <= lp <= 4, default = 0 */
int pb, /* 0 <= pb <= 4, default = 2 */
int fb, /* 5 <= fb <= 273, default = 32 */
int numThreads /* 1 or 2, default = 2 */
);
/*
LzmaUncompress
--------------
In:
dest - output data
destLen - output data size
src - input data
srcLen - input data size
Out:
destLen - processed output size
srcLen - processed input size
Returns:
SZ_OK - OK
SZ_ERROR_DATA - Data error
SZ_ERROR_MEM - Memory allocation arror
SZ_ERROR_UNSUPPORTED - Unsupported properties
SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src)
*/
MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src,
size_t *srcLen, const unsigned char *props, size_t propsSize);
#endif

View File

@ -1,87 +0,0 @@
/* Types.h -- Basic types
2008-11-23 : Igor Pavlov : Public domain */
#pragma once
#include <stddef.h>
#include <stdint.h>
#ifdef _WIN32
#include <windows.h>
#endif
#define SZ_OK 0
#define SZ_ERROR_DATA 1
#define SZ_ERROR_MEM 2
#define SZ_ERROR_CRC 3
#define SZ_ERROR_UNSUPPORTED 4
#define SZ_ERROR_PARAM 5
#define SZ_ERROR_INPUT_EOF 6
#define SZ_ERROR_OUTPUT_EOF 7
#define SZ_ERROR_READ 8
#define SZ_ERROR_WRITE 9
#define SZ_ERROR_PROGRESS 10
#define SZ_ERROR_FAIL 11
#define SZ_ERROR_THREAD 12
#define SZ_ERROR_ARCHIVE 16
#define SZ_ERROR_NO_ARCHIVE 17
typedef int SRes;
#ifndef RINOK
#define RINOK(x) \
{ \
int __result__ = (x); \
if (__result__ != 0) \
return __result__; \
}
#endif
typedef int Bool;
#define True 1
#define False 0
#ifdef _MSC_VER
#if _MSC_VER >= 1300
#define MY_NO_INLINE __declspec(noinline)
#else
#define MY_NO_INLINE
#endif
#define MY_CDECL __cdecl
#define MY_STD_CALL __stdcall
#define MY_FAST_CALL MY_NO_INLINE __fastcall
#else
#define MY_CDECL
#define MY_STD_CALL
#define MY_FAST_CALL
#endif
/* The following interfaces use first parameter as pointer to structure */
typedef struct
{
SRes (*Read)(void *p, void *buf, size_t *size);
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
(output(*size) < input(*size)) is allowed */
} ISeqInStream;
typedef struct
{
size_t (*Write)(void *p, const void *buf, size_t size);
/* Returns: result - the number of actually written bytes.
(result < size) means error */
} ISeqOutStream;
typedef struct
{
SRes (*Progress)(void *p, uint64_t inSize, uint64_t outSize);
/* Returns: result. (result != SZ_OK) means break.
Value (uint64_t)(int64_t)-1 for size means unknown value. */
} ICompressProgress;

View File

@ -1,46 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*/
#include "common_internal.h"
static void *elzmaAlloc(void *p, size_t size)
{
struct elzma_alloc_struct *as = (struct elzma_alloc_struct *)p;
if (as->clientMallocFunc)
{
return as->clientMallocFunc(as->clientMallocContext, size);
}
return malloc(size);
}
static void elzmaFree(void *p, void *address)
{
struct elzma_alloc_struct *as = (struct elzma_alloc_struct *)p;
if (as->clientFreeFunc)
{
as->clientFreeFunc(as->clientMallocContext, address);
}
else
{
free(address);
}
}
void init_alloc_struct(struct elzma_alloc_struct *as, elzma_malloc clientMallocFunc,
void *clientMallocContext, elzma_free clientFreeFunc,
void *clientFreeContext)
{
as->Alloc = elzmaAlloc;
as->Free = elzmaFree;
as->clientMallocFunc = clientMallocFunc;
as->clientMallocContext = clientMallocContext;
as->clientFreeFunc = clientFreeFunc;
as->clientFreeContext = clientFreeContext;
}

View File

@ -1,60 +0,0 @@
#ifndef __ELZMA_COMMON_INTERNAL_H__
#define __ELZMA_COMMON_INTERNAL_H__
#include "common.h"
/** a structure which may be cast and passed into Igor's allocate
* routines */
struct elzma_alloc_struct
{
void *(*Alloc)(void *p, size_t size);
void (*Free)(void *p, void *address); /* address can be 0 */
elzma_malloc clientMallocFunc;
void *clientMallocContext;
elzma_free clientFreeFunc;
void *clientFreeContext;
};
/* initialize an allocation structure, may be called safely multiple
* times */
void init_alloc_struct(struct elzma_alloc_struct *allocStruct, elzma_malloc clientMallocFunc,
void *clientMallocContext, elzma_free clientFreeFunc,
void *clientFreeContext);
/** superset representation of a compressed file header */
struct elzma_file_header
{
unsigned char pb;
unsigned char lp;
unsigned char lc;
unsigned char isStreamed;
long long unsigned int uncompressedSize;
unsigned int dictSize;
};
/** superset representation of a compressed file footer */
struct elzma_file_footer
{
unsigned int crc32;
long long unsigned int uncompressedSize;
};
/** a structure which encapsulates information about the particular
* file header and footer in use (lzip vs lzma vs (eventually) xz.
* The intention of this structure is to simplify compression and
* decompression logic by abstracting the file format details a bit. */
struct elzma_format_handler
{
unsigned int header_size;
void (*init_header)(struct elzma_file_header *hdr);
int (*parse_header)(const unsigned char *hdrBuf, struct elzma_file_header *hdr);
int (*serialize_header)(unsigned char *hdrBuf, const struct elzma_file_header *hdr);
unsigned int footer_size;
int (*serialize_footer)(struct elzma_file_footer *ftr, unsigned char *ftrBuf);
int (*parse_footer)(const unsigned char *ftrBuf, struct elzma_file_footer *ftr);
};
#endif

View File

@ -1,297 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*/
#include "compress.h"
#include "lzma_header.h"
#include "lzip_header.h"
#include "common_internal.h"
#include "pavlov/Types.h"
#include "pavlov/LzmaEnc.h"
#include "pavlov/7zCrc.h"
#include <string.h>
struct _elzma_compress_handle
{
CLzmaEncProps props;
CLzmaEncHandle encHand;
unsigned long long uncompressedSize;
elzma_file_format format;
struct elzma_alloc_struct allocStruct;
struct elzma_format_handler formatHandler;
};
elzma_compress_handle elzma_compress_alloc()
{
elzma_compress_handle hand = malloc(sizeof(struct _elzma_compress_handle));
memset((void *)hand, 0, sizeof(struct _elzma_compress_handle));
/* "reasonable" defaults for props */
LzmaEncProps_Init(&(hand->props));
hand->props.lc = 3;
hand->props.lp = 0;
hand->props.pb = 2;
hand->props.level = 5;
hand->props.algo = 1;
hand->props.fb = 32;
hand->props.dictSize = 1 << 24;
hand->props.btMode = 1;
hand->props.numHashBytes = 4;
hand->props.mc = 32;
hand->props.numThreads = 1;
hand->props.writeEndMark = 1;
init_alloc_struct(&(hand->allocStruct), NULL, NULL, NULL, NULL);
/* default format is LZMA-Alone */
initializeLZMAFormatHandler(&(hand->formatHandler));
return hand;
}
void elzma_compress_free(elzma_compress_handle *hand)
{
if (hand && *hand)
{
if ((*hand)->encHand)
{
LzmaEnc_Destroy((*hand)->encHand);
}
}
*hand = NULL;
}
int elzma_compress_config(elzma_compress_handle hand, unsigned char lc, unsigned char lp,
unsigned char pb, unsigned char level, unsigned int dictionarySize,
elzma_file_format format, unsigned long long uncompressedSize)
{
/* XXX: validate arguments are in valid ranges */
hand->props.lc = lc;
hand->props.lp = lp;
hand->props.pb = pb;
hand->props.level = level;
hand->props.dictSize = dictionarySize;
hand->uncompressedSize = uncompressedSize;
hand->format = format;
/* default of LZMA-Alone is set at alloc time, and there are only
* two possible formats */
if (format == ELZMA_lzip)
{
initializeLZIPFormatHandler(&(hand->formatHandler));
}
return ELZMA_E_OK;
}
/* use Igor's stream hooks for compression. */
struct elzmaInStream
{
SRes (*ReadPtr)(void *p, void *buf, size_t *size);
elzma_read_callback inputStream;
void *inputContext;
unsigned int crc32;
unsigned int crc32a;
unsigned int crc32b;
unsigned int crc32c;
int calculateCRC;
};
static SRes elzmaReadFunc(void *p, void *buf, size_t *size)
{
int rv;
struct elzmaInStream *is = (struct elzmaInStream *)p;
rv = is->inputStream(is->inputContext, buf, size);
if (rv == 0 && *size > 0 && is->calculateCRC)
{
is->crc32 = CrcUpdate(is->crc32, buf, *size);
}
return rv;
}
struct elzmaOutStream
{
size_t (*WritePtr)(void *p, const void *buf, size_t size);
elzma_write_callback outputStream;
void *outputContext;
};
static size_t elzmaWriteFunc(void *p, const void *buf, size_t size)
{
struct elzmaOutStream *os = (struct elzmaOutStream *)p;
return os->outputStream(os->outputContext, buf, size);
}
/* use Igor's stream hooks for compression. */
struct elzmaProgressStruct
{
SRes (*Progress)(void *p, uint64_t inSize, uint64_t outSize);
long long unsigned int uncompressedSize;
elzma_progress_callback progressCallback;
void *progressContext;
};
#include <stdio.h>
static SRes elzmaProgress(void *p, uint64_t inSize, uint64_t outSize)
{
struct elzmaProgressStruct *ps = (struct elzmaProgressStruct *)p;
if (ps->progressCallback)
{
ps->progressCallback(ps->progressContext, inSize, ps->uncompressedSize);
}
return SZ_OK;
}
void elzma_compress_set_allocation_callbacks(elzma_compress_handle hand,
elzma_malloc mallocFunc, void *mallocFuncContext,
elzma_free freeFunc, void *freeFuncContext)
{
if (hand)
{
init_alloc_struct(&(hand->allocStruct), mallocFunc, mallocFuncContext, freeFunc,
freeFuncContext);
}
}
int elzma_compress_run(elzma_compress_handle hand, elzma_read_callback inputStream,
void *inputContext, elzma_write_callback outputStream,
void *outputContext, elzma_progress_callback progressCallback,
void *progressContext)
{
struct elzmaInStream inStreamStruct;
struct elzmaOutStream outStreamStruct;
struct elzmaProgressStruct progressStruct;
SRes r;
CrcGenerateTable();
if (hand == NULL || inputStream == NULL)
return ELZMA_E_BAD_PARAMS;
/* initialize stream structrures */
inStreamStruct.ReadPtr = elzmaReadFunc;
inStreamStruct.inputStream = inputStream;
inStreamStruct.inputContext = inputContext;
inStreamStruct.crc32 = CRC_INIT_VAL;
inStreamStruct.calculateCRC = (hand->formatHandler.serialize_footer != NULL);
outStreamStruct.WritePtr = elzmaWriteFunc;
outStreamStruct.outputStream = outputStream;
outStreamStruct.outputContext = outputContext;
progressStruct.Progress = elzmaProgress;
progressStruct.uncompressedSize = hand->uncompressedSize;
progressStruct.progressCallback = progressCallback;
progressStruct.progressContext = progressContext;
/* create an encoding object */
hand->encHand = LzmaEnc_Create();
if (hand->encHand == NULL)
{
return ELZMA_E_COMPRESS_ERROR;
}
/* inintialize with compression parameters */
if (SZ_OK != LzmaEnc_SetProps(hand->encHand, &(hand->props)))
{
return ELZMA_E_BAD_PARAMS;
}
/* verify format is sane */
if (ELZMA_lzma != hand->format && ELZMA_lzip != hand->format)
{
return ELZMA_E_UNSUPPORTED_FORMAT;
}
/* now write the compression header header */
{
unsigned char *hdr =
hand->allocStruct.Alloc(&(hand->allocStruct), hand->formatHandler.header_size);
struct elzma_file_header h;
size_t wt;
hand->formatHandler.init_header(&h);
h.pb = (unsigned char)hand->props.pb;
h.lp = (unsigned char)hand->props.lp;
h.lc = (unsigned char)hand->props.lc;
h.dictSize = hand->props.dictSize;
h.isStreamed = (unsigned char)(hand->uncompressedSize == 0);
h.uncompressedSize = hand->uncompressedSize;
hand->formatHandler.serialize_header(hdr, &h);
wt = outputStream(outputContext, (void *)hdr, hand->formatHandler.header_size);
hand->allocStruct.Free(&(hand->allocStruct), hdr);
if (wt != hand->formatHandler.header_size)
{
return ELZMA_E_OUTPUT_ERROR;
}
}
/* begin LZMA encoding */
/* XXX: expose encoding progress */
r = LzmaEnc_Encode(hand->encHand, (ISeqOutStream *)&outStreamStruct,
(ISeqInStream *)&inStreamStruct, (ICompressProgress *)&progressStruct);
if (r != SZ_OK)
return ELZMA_E_COMPRESS_ERROR;
/* support a footer! (lzip) */
if (hand->formatHandler.serialize_footer != NULL && hand->formatHandler.footer_size > 0)
{
size_t wt;
unsigned char *ftrBuf =
hand->allocStruct.Alloc(&(hand->allocStruct), hand->formatHandler.footer_size);
struct elzma_file_footer ftr;
ftr.crc32 = inStreamStruct.crc32 ^ 0xFFFFFFFF;
ftr.uncompressedSize = hand->uncompressedSize;
hand->formatHandler.serialize_footer(&ftr, ftrBuf);
wt = outputStream(outputContext, (void *)ftrBuf, hand->formatHandler.footer_size);
hand->allocStruct.Free(&(hand->allocStruct), ftrBuf);
if (wt != hand->formatHandler.footer_size)
{
return ELZMA_E_OUTPUT_ERROR;
}
}
return ELZMA_E_OK;
}
unsigned int elzma_get_dict_size(unsigned long long size)
{
int i = 13; /* 16k dict is minimum */
/* now we'll find the closes power of two with a max at 16< *
* if the size is greater than 8m, we'll divide by two, all of this
* is based on a quick set of emperical tests on hopefully
* representative sample data */
if (size > (1 << 23))
size >>= 1;
while (size >> i)
i++;
if (i > 23)
return 1 << 23;
/* now 1 << i is greater than size, let's return either 1<<i or 1<<(i-1),
* whichever is closer to size */
return 1 << ((((1 << i) - size) > (size - (1 << (i - 1)))) ? i - 1 : i);
}

View File

@ -1,263 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*/
#include "include/decompress.h"
#include "pavlov/LzmaDec.h"
#include "pavlov/7zCrc.h"
#include "common_internal.h"
#include "lzma_header.h"
#include "lzip_header.h"
#include <string.h>
#include <assert.h>
#define ELZMA_DECOMPRESS_INPUT_BUFSIZE (1024 * 64)
#define ELZMA_DECOMPRESS_OUTPUT_BUFSIZE (1024 * 256)
/** an opaque handle to an lzma decompressor */
struct _elzma_decompress_handle
{
char inbuf[ELZMA_DECOMPRESS_INPUT_BUFSIZE];
char outbuf[ELZMA_DECOMPRESS_OUTPUT_BUFSIZE];
struct elzma_alloc_struct allocStruct;
};
elzma_decompress_handle elzma_decompress_alloc()
{
elzma_decompress_handle hand = malloc(sizeof(struct _elzma_decompress_handle));
memset((void *)hand, 0, sizeof(struct _elzma_decompress_handle));
init_alloc_struct(&(hand->allocStruct), NULL, NULL, NULL, NULL);
return hand;
}
void elzma_decompress_set_allocation_callbacks(elzma_decompress_handle hand,
elzma_malloc mallocFunc, void *mallocFuncContext,
elzma_free freeFunc, void *freeFuncContext)
{
if (hand)
{
init_alloc_struct(&(hand->allocStruct), mallocFunc, mallocFuncContext, freeFunc,
freeFuncContext);
}
}
void elzma_decompress_free(elzma_decompress_handle *hand)
{
if (*hand)
free(*hand);
*hand = NULL;
}
int elzma_decompress_run(elzma_decompress_handle hand, elzma_read_callback inputStream,
void *inputContext, elzma_write_callback outputStream,
void *outputContext, elzma_file_format format)
{
unsigned long long int totalRead = 0; /* total amount read from stream */
unsigned int crc32 = CRC_INIT_VAL; /* running crc32 (lzip case) */
CLzmaDec dec;
unsigned int errorCode = ELZMA_E_OK;
struct elzma_format_handler formatHandler;
struct elzma_file_header h;
struct elzma_file_footer f;
/* switch between supported formats */
if (format == ELZMA_lzma)
{
initializeLZMAFormatHandler(&formatHandler);
}
else if (format == ELZMA_lzip)
{
CrcGenerateTable();
initializeLZIPFormatHandler(&formatHandler);
}
else
{
return ELZMA_E_BAD_PARAMS;
}
/* initialize footer */
f.crc32 = 0;
f.uncompressedSize = 0;
/* initialize decoder memory */
memset((void *)&dec, 0, sizeof(dec));
LzmaDec_Init(&dec);
/* decode the header. */
{
unsigned char *hdr =
hand->allocStruct.Alloc(&(hand->allocStruct), formatHandler.header_size);
size_t sz = formatHandler.header_size;
formatHandler.init_header(&h);
if (inputStream(inputContext, hdr, &sz) != 0 || sz != formatHandler.header_size)
{
hand->allocStruct.Free(&(hand->allocStruct), hdr);
return ELZMA_E_INPUT_ERROR;
}
if (0 != formatHandler.parse_header(hdr, &h))
{
hand->allocStruct.Free(&(hand->allocStruct), hdr);
return ELZMA_E_CORRUPT_HEADER;
}
/* the LzmaDec_Allocate call requires 5 bytes which have
* compression properties encoded in them. In the case of
* lzip, the header format does not already contain what
* LzmaDec_Allocate expects, so we must craft it, silly */
{
unsigned char propsBuf[13];
const unsigned char *propsPtr = hdr;
if (format == ELZMA_lzip)
{
struct elzma_format_handler lzmaHand;
initializeLZMAFormatHandler(&lzmaHand);
lzmaHand.serialize_header(propsBuf, &h);
propsPtr = propsBuf;
}
/* now we're ready to allocate the decoder */
LzmaDec_Allocate(&dec, propsPtr, 5);
}
hand->allocStruct.Free(&(hand->allocStruct), hdr);
}
/* perform the decoding */
for (;;)
{
size_t dstLen = ELZMA_DECOMPRESS_OUTPUT_BUFSIZE;
size_t srcLen = ELZMA_DECOMPRESS_INPUT_BUFSIZE;
size_t amt = 0;
size_t bufOff = 0;
ELzmaStatus stat;
if (0 != inputStream(inputContext, hand->inbuf, &srcLen))
{
errorCode = ELZMA_E_INPUT_ERROR;
goto decompressEnd;
}
/* handle the case where the input prematurely finishes */
if (srcLen == 0)
{
errorCode = ELZMA_E_INSUFFICIENT_INPUT;
goto decompressEnd;
}
amt = srcLen;
/* handle the case where a single read buffer of compressed bytes
* will translate into multiple buffers of uncompressed bytes,
* with this inner loop */
stat = LZMA_STATUS_NOT_SPECIFIED;
while (bufOff < srcLen)
{
SRes r = LzmaDec_DecodeToBuf(&dec, (uint8_t *)hand->outbuf, &dstLen,
((uint8_t *)hand->inbuf + bufOff), &amt,
LZMA_FINISH_ANY, &stat);
/* XXX deal with result code more granularly*/
if (r != SZ_OK)
{
errorCode = ELZMA_E_DECOMPRESS_ERROR;
goto decompressEnd;
}
/* write what we've read */
{
size_t wt;
/* if decoding lzip, update our crc32 value */
if (format == ELZMA_lzip && dstLen > 0)
{
crc32 = CrcUpdate(crc32, hand->outbuf, dstLen);
}
totalRead += dstLen;
wt = outputStream(outputContext, hand->outbuf, dstLen);
if (wt != dstLen)
{
errorCode = ELZMA_E_OUTPUT_ERROR;
goto decompressEnd;
}
}
/* do we have more data on the input buffer? */
bufOff += amt;
assert(bufOff <= srcLen);
if (bufOff >= srcLen)
break;
amt = srcLen - bufOff;
/* with lzip, we will have the footer left on the buffer! */
if (stat == LZMA_STATUS_FINISHED_WITH_MARK)
{
break;
}
}
/* now check status */
if (stat == LZMA_STATUS_FINISHED_WITH_MARK)
{
/* read a footer if one is expected and
* present */
if (formatHandler.footer_size > 0 && amt >= formatHandler.footer_size &&
formatHandler.parse_footer != NULL)
{
formatHandler.parse_footer((unsigned char *)hand->inbuf + bufOff, &f);
}
break;
}
/* for LZMA utils, we don't always have a finished mark */
if (!h.isStreamed && totalRead >= h.uncompressedSize)
{
break;
}
}
/* finish the calculated crc32 */
crc32 ^= 0xFFFFFFFF;
/* if we have a footer, check that the calculated crc32 matches
* the encoded crc32, and that the sizes match */
if (formatHandler.footer_size)
{
if (f.crc32 != crc32)
{
errorCode = ELZMA_E_CRC32_MISMATCH;
}
else if (f.uncompressedSize != totalRead)
{
errorCode = ELZMA_E_SIZE_MISMATCH;
}
}
else if (!h.isStreamed)
{
/* if the format does not support a footer and has an uncompressed
* size in the header, let's compare that with how much we actually
* read */
if (h.uncompressedSize != totalRead)
{
errorCode = ELZMA_E_SIZE_MISMATCH;
}
}
decompressEnd:
LzmaDec_Free(&dec);
return errorCode;
}

View File

@ -1,96 +0,0 @@
#include "lzip_header.h"
#include <string.h>
#define ELZMA_LZIP_HEADER_SIZE 6
#define ELZMA_LZIP_FOOTER_SIZE 12
static void initLzipHeader(struct elzma_file_header *hdr)
{
memset((void *)hdr, 0, sizeof(struct elzma_file_header));
}
static int parseLzipHeader(const unsigned char *hdrBuf, struct elzma_file_header *hdr)
{
if (0 != strncmp("LZIP", (char *)hdrBuf, 4))
return 1;
/* XXX: ignore version for now */
hdr->pb = 2;
hdr->lp = 0;
hdr->lc = 3;
/* unknown at this point */
hdr->isStreamed = 1;
hdr->uncompressedSize = 0;
hdr->dictSize = 1 << (hdrBuf[5] & 0x1F);
return 0;
}
static int serializeLzipHeader(unsigned char *hdrBuf, const struct elzma_file_header *hdr)
{
hdrBuf[0] = 'L';
hdrBuf[1] = 'Z';
hdrBuf[2] = 'I';
hdrBuf[3] = 'P';
hdrBuf[4] = 0;
{
int r = 0;
while ((hdr->dictSize >> r) != 0)
r++;
hdrBuf[5] = (unsigned char)(r - 1) & 0x1F;
}
return 0;
}
static int serializeLzipFooter(struct elzma_file_footer *ftr, unsigned char *ftrBuf)
{
unsigned int i = 0;
/* first crc32 */
for (i = 0; i < 4; i++)
{
*(ftrBuf++) = (unsigned char)(ftr->crc32 >> (i * 8));
}
/* next data size */
for (i = 0; i < 8; i++)
{
*(ftrBuf++) = (unsigned char)(ftr->uncompressedSize >> (i * 8));
}
/* write version 0 files, omit member length for now*/
return 0;
}
static int parseLzipFooter(const unsigned char *ftrBuf, struct elzma_file_footer *ftr)
{
unsigned int i = 0;
ftr->crc32 = 0;
ftr->uncompressedSize = 0;
/* first crc32 */
for (i = 0; i < 4; i++)
{
ftr->crc32 += ((unsigned int)*(ftrBuf++) << (i * 8));
}
/* next data size */
for (i = 0; i < 8; i++)
{
ftr->uncompressedSize += (unsigned long long)*(ftrBuf++) << (i * 8);
}
/* read version 0 files, omit member length for now*/
return 0;
}
void initializeLZIPFormatHandler(struct elzma_format_handler *hand)
{
hand->header_size = ELZMA_LZIP_HEADER_SIZE;
hand->init_header = initLzipHeader;
hand->parse_header = parseLzipHeader;
hand->serialize_header = serializeLzipHeader;
hand->footer_size = ELZMA_LZIP_FOOTER_SIZE;
hand->serialize_footer = serializeLzipFooter;
hand->parse_footer = parseLzipFooter;
}

View File

@ -1,11 +0,0 @@
#ifndef __EASYLZMA_LZIP_HEADER__
#define __EASYLZMA_LZIP_HEADER__
#include "common_internal.h"
/* lzip file format documented here:
* http://download.savannah.gnu.org/releases-noredirect/lzip/manual/ */
void initializeLZIPFormatHandler(struct elzma_format_handler *hand);
#endif

View File

@ -1,134 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*/
/* XXX: clean this up, it's mostly lifted from pavel */
#include "lzma_header.h"
#include <string.h>
#include <assert.h>
#define ELZMA_LZMA_HEADER_SIZE 13
#define ELZMA_LZMA_PROPSBUF_SIZE 5
/****************
Header parsing
****************/
#ifndef UINT64_MAX
#define UINT64_MAX ((unsigned long long)-1)
#endif
/* Parse the properties byte */
static char lzmadec_header_properties(unsigned char *pb, unsigned char *lp, unsigned char *lc,
const unsigned char c)
{
/* pb, lp and lc are encoded into a single byte. */
if (c > (9 * 5 * 5))
return -1;
*pb = c / (9 * 5); /* 0 <= pb <= 4 */
*lp = (c % (9 * 5)) / 9; /* 0 <= lp <= 4 */
*lc = c % 9; /* 0 <= lc <= 8 */
assert(*pb < 5 && *lp < 5 && *lc < 9);
return 0;
}
/* Parse the dictionary size (4 bytes, little endian) */
static char lzmadec_header_dictionary(unsigned int *size, const unsigned char *buffer)
{
unsigned int i;
*size = 0;
for (i = 0; i < 4; i++)
*size += (unsigned int)(*buffer++) << (i * 8);
/* The dictionary size is limited to 256 MiB (checked from
* LZMA SDK 4.30) */
if (*size > (1 << 28))
return -1;
return 0;
}
/* Parse the uncompressed size field (8 bytes, little endian) */
static void lzmadec_header_uncompressed(unsigned long long *size, unsigned char *is_streamed,
const unsigned char *buffer)
{
unsigned int i;
/* Streamed files have all 64 bits set in the size field.
* We don't know the uncompressed size beforehand. */
*is_streamed = 1; /* Assume streamed. */
*size = 0;
for (i = 0; i < 8; i++)
{
*size += (unsigned long long)buffer[i] << (i * 8);
if (buffer[i] != 255)
*is_streamed = 0;
}
assert((*is_streamed == 1 && *size == UINT64_MAX) ||
(*is_streamed == 0 && *size < UINT64_MAX));
}
static void initLzmaHeader(struct elzma_file_header *hdr)
{
memset((void *)hdr, 0, sizeof(struct elzma_file_header));
}
static int parseLzmaHeader(const unsigned char *hdrBuf, struct elzma_file_header *hdr)
{
if (lzmadec_header_properties(&(hdr->pb), &(hdr->lp), &(hdr->lc), *hdrBuf) ||
lzmadec_header_dictionary(&(hdr->dictSize), hdrBuf + 1))
{
return 1;
}
lzmadec_header_uncompressed(&(hdr->uncompressedSize), &(hdr->isStreamed), hdrBuf + 5);
return 0;
}
static int serializeLzmaHeader(unsigned char *hdrBuf, const struct elzma_file_header *hdr)
{
unsigned int i;
memset((void *)hdrBuf, 0, ELZMA_LZMA_HEADER_SIZE);
/* encode lc, pb, and lp */
*hdrBuf++ = hdr->lc + (hdr->pb * 45) + (hdr->lp * 45 * 9);
/* encode dictionary size */
for (i = 0; i < 4; i++)
{
*(hdrBuf++) = (unsigned char)(hdr->dictSize >> (i * 8));
}
/* encode uncompressed size */
for (i = 0; i < 8; i++)
{
if (hdr->isStreamed)
{
*(hdrBuf++) = 0xff;
}
else
{
*(hdrBuf++) = (unsigned char)(hdr->uncompressedSize >> (i * 8));
}
}
return 0;
}
void initializeLZMAFormatHandler(struct elzma_format_handler *hand)
{
hand->header_size = ELZMA_LZMA_HEADER_SIZE;
hand->init_header = initLzmaHeader;
hand->parse_header = parseLzmaHeader;
hand->serialize_header = serializeLzmaHeader;
hand->footer_size = 0;
hand->serialize_footer = NULL;
}

View File

@ -1,10 +0,0 @@
#ifndef __EASYLZMA_LZMA_HEADER__
#define __EASYLZMA_LZMA_HEADER__
#include "common_internal.h"
/* LZMA-Alone header format gleaned from reading Igor's code */
void initializeLZMAFormatHandler(struct elzma_format_handler *hand);
#endif

View File

@ -1,139 +0,0 @@
/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*
* simple.c - a wrapper around easylzma to compress/decompress to memory
*/
#include "simple.h"
#include <string.h>
#include <assert.h>
struct dataStream
{
const unsigned char *inData;
size_t inLen;
unsigned char *outData;
size_t outLen;
};
static int inputCallback(void *ctx, void *buf, size_t *size)
{
size_t rd = 0;
struct dataStream *ds = (struct dataStream *)ctx;
assert(ds != NULL);
rd = (ds->inLen < *size) ? ds->inLen : *size;
if (rd > 0)
{
memcpy(buf, (void *)ds->inData, rd);
ds->inData += rd;
ds->inLen -= rd;
}
*size = rd;
return 0;
}
static size_t outputCallback(void *ctx, const void *buf, size_t size)
{
struct dataStream *ds = (struct dataStream *)ctx;
assert(ds != NULL);
if (size > 0)
{
ds->outData = realloc(ds->outData, ds->outLen + size);
memcpy((void *)(ds->outData + ds->outLen), buf, size);
ds->outLen += size;
}
return size;
}
int simpleCompress(elzma_file_format format, const unsigned char *inData, size_t inLen,
unsigned char **outData, size_t *outLen)
{
int rc;
elzma_compress_handle hand;
/* allocate compression handle */
hand = elzma_compress_alloc();
assert(hand != NULL);
rc = elzma_compress_config(hand, ELZMA_LC_DEFAULT, ELZMA_LP_DEFAULT, ELZMA_PB_DEFAULT, 5,
(1 << 20) /* 1mb */, format, inLen);
if (rc != ELZMA_E_OK)
{
elzma_compress_free(&hand);
return rc;
}
/* now run the compression */
{
struct dataStream ds;
ds.inData = inData;
ds.inLen = inLen;
ds.outData = NULL;
ds.outLen = 0;
rc = elzma_compress_run(hand, inputCallback, (void *)&ds, outputCallback, (void *)&ds,
NULL, NULL);
if (rc != ELZMA_E_OK)
{
if (ds.outData != NULL)
free(ds.outData);
elzma_compress_free(&hand);
return rc;
}
*outData = ds.outData;
*outLen = ds.outLen;
}
return rc;
}
int simpleDecompress(elzma_file_format format, const unsigned char *inData, size_t inLen,
unsigned char **outData, size_t *outLen)
{
int rc;
elzma_decompress_handle hand;
hand = elzma_decompress_alloc();
/* now run the compression */
{
struct dataStream ds;
ds.inData = inData;
ds.inLen = inLen;
ds.outData = NULL;
ds.outLen = 0;
rc = elzma_decompress_run(hand, inputCallback, (void *)&ds, outputCallback, (void *)&ds,
format);
if (rc != ELZMA_E_OK)
{
if (ds.outData != NULL)
free(ds.outData);
elzma_decompress_free(&hand);
return rc;
}
*outData = ds.outData;
*outLen = ds.outLen;
}
return rc;
}

View File

@ -93,13 +93,6 @@ void band::readData(int expectedLength)
{ {
// must be a variable-length coding // must be a variable-length coding
assert(defc->B() > 1 && defc->L() > 0); assert(defc->B() > 1 && defc->L() > 0);
// must have already read from previous band:
assert(bn >= BAND_LIMIT || bn <= 0 || bn == e_cp_Utf8_big_chars ||
endsWith(name, "_lo") // preceded by _hi conditional band
||
bn == e_file_options // preceded by conditional band
||
u->rp == u->all_bands[bn - 1].maxRP() || u->all_bands[bn - 1].defc == nullptr);
value_stream xvs; value_stream xvs;
coding *valc = defc; coding *valc = defc;
@ -425,7 +418,6 @@ band *band::makeBands(unpacker *u)
coding *defc = coding::findBySpec(bi.defc); coding *defc = coding::findBySpec(bi.defc);
assert((defc == nullptr) == (bi.defc == -1)); // no garbage, please assert((defc == nullptr) == (bi.defc == -1)); // no garbage, please
assert(defc == nullptr || !defc->isMalloc); assert(defc == nullptr || !defc->isMalloc);
assert(bi.bn == i); // band array consistent w/ band enum
b.init(u, i, defc); b.init(u, i, defc);
if (bi.index > 0) if (bi.index > 0)
{ {

View File

@ -2369,13 +2369,11 @@ void unpacker::read_attrs(int attrc, int obj_count)
bool haveLongFlags = ad.haveLongFlags(); bool haveLongFlags = ad.haveLongFlags();
band &xxx_flags_hi = ad.xxx_flags_hi(); band &xxx_flags_hi = ad.xxx_flags_hi();
assert(endsWith(xxx_flags_hi.name, "_flags_hi"));
if (haveLongFlags) if (haveLongFlags)
xxx_flags_hi.readData(obj_count); xxx_flags_hi.readData(obj_count);
CHECK; CHECK;
band &xxx_flags_lo = ad.xxx_flags_lo(); band &xxx_flags_lo = ad.xxx_flags_lo();
assert(endsWith(xxx_flags_lo.name, "_flags_lo"));
xxx_flags_lo.readData(obj_count); xxx_flags_lo.readData(obj_count);
CHECK; CHECK;
@ -2400,13 +2398,11 @@ void unpacker::read_attrs(int attrc, int obj_count)
xxx_flags_hi.rewind(); xxx_flags_hi.rewind();
band &xxx_attr_count = ad.xxx_attr_count(); band &xxx_attr_count = ad.xxx_attr_count();
assert(endsWith(xxx_attr_count.name, "_attr_count"));
// There is one count element for each 1<<16 bit set in flags: // There is one count element for each 1<<16 bit set in flags:
xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW)); xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW));
CHECK; CHECK;
band &xxx_attr_indexes = ad.xxx_attr_indexes(); band &xxx_attr_indexes = ad.xxx_attr_indexes();
assert(endsWith(xxx_attr_indexes.name, "_attr_indexes"));
int overflowIndexCount = xxx_attr_count.getIntTotal(); int overflowIndexCount = xxx_attr_count.getIntTotal();
xxx_attr_indexes.readData(overflowIndexCount); xxx_attr_indexes.readData(overflowIndexCount);
CHECK; CHECK;
@ -4637,9 +4633,6 @@ void unpacker::write_members(int num, int attrc)
band &member_flags_hi = ad.xxx_flags_hi(); band &member_flags_hi = ad.xxx_flags_hi();
band &member_flags_lo = ad.xxx_flags_lo(); band &member_flags_lo = ad.xxx_flags_lo();
band &member_descr = (&member_flags_hi)[e_field_descr - e_field_flags_hi]; band &member_descr = (&member_flags_hi)[e_field_descr - e_field_flags_hi];
assert(endsWith(member_descr.name, "_descr"));
assert(endsWith(member_flags_lo.name, "_flags_lo"));
assert(endsWith(member_flags_lo.name, "_flags_lo"));
bool haveLongFlags = ad.haveLongFlags(); bool haveLongFlags = ad.haveLongFlags();
putu2(num); putu2(num);

View File

@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 2.6)
project(xz-embedded)
option(XZ_BUILD_BCJ "Build xz-embedded with BCJ support (native binary optimization)" OFF)
option(XZ_BUILD_CRC64 "Build xz-embedded with CRC64 checksum support" ON)
option(XZ_BUILD_MINIDEC "Build a tiny utility that decompresses xz streams" ON)
set(CMAKE_C_FLAGS "-std=c99")
include_directories(include)
set(XZ_SOURCES
include/xz.h
src/xz_config.h
src/xz_crc32.c
src/xz_dec_lzma2.c
src/xz_dec_stream.c
src/xz_lzma2.h
src/xz_private.h
src/xz_stream.h
)
# checksum checks
add_definitions(-DXZ_DEC_ANY_CHECK)
if(XZ_BUILD_CRC64)
add_definitions(-DXZ_USE_CRC64)
LIST(APPEND XZ_SOURCES src/xz_crc64.c)
endif()
# TODO: add SHA256
# uncomment these, if required.
if(XZ_BUILD_BCJ)
add_definitions(-DXZ_DEC_X86 -DXZ_DEC_POWERPC -DXZ_DEC_IA64)
add_definitions(-DXZ_DEC_ARM -DXZ_DEC_ARMTHUMB -DXZ_DEC_SPARC)
LIST(APPEND XZ_SOURCES src/xz_dec_bcj.c)
endif()
# Static link!
ADD_DEFINITIONS(-DXZ_STATIC)
add_definitions(-DXZ_LIBRARY)
add_library(xz-embedded SHARED ${XZ_SOURCES})
add_executable(xzminidec xzminidec.c)
target_link_libraries(xzminidec xz-embedded)

View File

@ -0,0 +1,304 @@
/*
* XZ decompressor
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_H
#define XZ_H
#ifdef __KERNEL__
# include <linux/stddef.h>
# include <linux/types.h>
#else
# include <stddef.h>
# include <stdint.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* In Linux, this is used to make extern functions static when needed. */
#ifndef XZ_EXTERN
# define XZ_EXTERN extern
#endif
/**
* enum xz_mode - Operation mode
*
* @XZ_SINGLE: Single-call mode. This uses less RAM than
* than multi-call modes, because the LZMA2
* dictionary doesn't need to be allocated as
* part of the decoder state. All required data
* structures are allocated at initialization,
* so xz_dec_run() cannot return XZ_MEM_ERROR.
* @XZ_PREALLOC: Multi-call mode with preallocated LZMA2
* dictionary buffer. All data structures are
* allocated at initialization, so xz_dec_run()
* cannot return XZ_MEM_ERROR.
* @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is
* allocated once the required size has been
* parsed from the stream headers. If the
* allocation fails, xz_dec_run() will return
* XZ_MEM_ERROR.
*
* It is possible to enable support only for a subset of the above
* modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
* or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
* with support for all operation modes, but the preboot code may
* be built with fewer features to minimize code size.
*/
enum xz_mode {
XZ_SINGLE,
XZ_PREALLOC,
XZ_DYNALLOC
};
/**
* enum xz_ret - Return codes
* @XZ_OK: Everything is OK so far. More input or more
* output space is required to continue. This
* return code is possible only in multi-call mode
* (XZ_PREALLOC or XZ_DYNALLOC).
* @XZ_STREAM_END: Operation finished successfully.
* @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
* is still possible in multi-call mode by simply
* calling xz_dec_run() again.
* Note that this return value is used only if
* XZ_DEC_ANY_CHECK was defined at build time,
* which is not used in the kernel. Unsupported
* check types return XZ_OPTIONS_ERROR if
* XZ_DEC_ANY_CHECK was not defined at build time.
* @XZ_MEM_ERROR: Allocating memory failed. This return code is
* possible only if the decoder was initialized
* with XZ_DYNALLOC. The amount of memory that was
* tried to be allocated was no more than the
* dict_max argument given to xz_dec_init().
* @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than
* allowed by the dict_max argument given to
* xz_dec_init(). This return value is possible
* only in multi-call mode (XZ_PREALLOC or
* XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
* ignores the dict_max argument.
* @XZ_FORMAT_ERROR: File format was not recognized (wrong magic
* bytes).
* @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
* compression options. In the decoder this means
* that the header CRC32 matches, but the header
* itself specifies something that we don't support.
* @XZ_DATA_ERROR: Compressed data is corrupt.
* @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
* different between multi-call and single-call
* mode; more information below.
*
* In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
* to XZ code cannot consume any input and cannot produce any new output.
* This happens when there is no new input available, or the output buffer
* is full while at least one output byte is still pending. Assuming your
* code is not buggy, you can get this error only when decoding a compressed
* stream that is truncated or otherwise corrupt.
*
* In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
* is too small or the compressed input is corrupt in a way that makes the
* decoder produce more output than the caller expected. When it is
* (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
* is used instead of XZ_BUF_ERROR.
*/
enum xz_ret {
XZ_OK,
XZ_STREAM_END,
XZ_UNSUPPORTED_CHECK,
XZ_MEM_ERROR,
XZ_MEMLIMIT_ERROR,
XZ_FORMAT_ERROR,
XZ_OPTIONS_ERROR,
XZ_DATA_ERROR,
XZ_BUF_ERROR
};
/**
* struct xz_buf - Passing input and output buffers to XZ code
* @in: Beginning of the input buffer. This may be NULL if and only
* if in_pos is equal to in_size.
* @in_pos: Current position in the input buffer. This must not exceed
* in_size.
* @in_size: Size of the input buffer
* @out: Beginning of the output buffer. This may be NULL if and only
* if out_pos is equal to out_size.
* @out_pos: Current position in the output buffer. This must not exceed
* out_size.
* @out_size: Size of the output buffer
*
* Only the contents of the output buffer from out[out_pos] onward, and
* the variables in_pos and out_pos are modified by the XZ code.
*/
struct xz_buf {
const uint8_t *in;
size_t in_pos;
size_t in_size;
uint8_t *out;
size_t out_pos;
size_t out_size;
};
/**
* struct xz_dec - Opaque type to hold the XZ decoder state
*/
struct xz_dec;
/**
* xz_dec_init() - Allocate and initialize a XZ decoder state
* @mode: Operation mode
* @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
* multi-call decoding. This is ignored in single-call mode
* (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
* or 2^n + 2^(n-1) bytes (the latter sizes are less common
* in practice), so other values for dict_max don't make sense.
* In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
* 512 KiB, and 1 MiB are probably the only reasonable values,
* except for kernel and initramfs images where a bigger
* dictionary can be fine and useful.
*
* Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
* once. The caller must provide enough output space or the decoding will
* fail. The output space is used as the dictionary buffer, which is why
* there is no need to allocate the dictionary as part of the decoder's
* internal state.
*
* Because the output buffer is used as the workspace, streams encoded using
* a big dictionary are not a problem in single-call mode. It is enough that
* the output buffer is big enough to hold the actual uncompressed data; it
* can be smaller than the dictionary size stored in the stream headers.
*
* Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
* of memory is preallocated for the LZMA2 dictionary. This way there is no
* risk that xz_dec_run() could run out of memory, since xz_dec_run() will
* never allocate any memory. Instead, if the preallocated dictionary is too
* small for decoding the given input stream, xz_dec_run() will return
* XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
* decoded to avoid allocating excessive amount of memory for the dictionary.
*
* Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
* dict_max specifies the maximum allowed dictionary size that xz_dec_run()
* may allocate once it has parsed the dictionary size from the stream
* headers. This way excessive allocations can be avoided while still
* limiting the maximum memory usage to a sane value to prevent running the
* system out of memory when decompressing streams from untrusted sources.
*
* On success, xz_dec_init() returns a pointer to struct xz_dec, which is
* ready to be used with xz_dec_run(). If memory allocation fails,
* xz_dec_init() returns NULL.
*/
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max);
/**
* xz_dec_run() - Run the XZ decoder
* @s: Decoder state allocated using xz_dec_init()
* @b: Input and output buffers
*
* The possible return values depend on build options and operation mode.
* See enum xz_ret for details.
*
* Note that if an error occurs in single-call mode (return value is not
* XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
* contents of the output buffer from b->out[b->out_pos] onward are
* undefined. This is true even after XZ_BUF_ERROR, because with some filter
* chains, there may be a second pass over the output buffer, and this pass
* cannot be properly done if the output buffer is truncated. Thus, you
* cannot give the single-call decoder a too small buffer and then expect to
* get that amount valid data from the beginning of the stream. You must use
* the multi-call decoder if you don't want to uncompress the whole stream.
*/
XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
/**
* xz_dec_reset() - Reset an already allocated decoder state
* @s: Decoder state allocated using xz_dec_init()
*
* This function can be used to reset the multi-call decoder state without
* freeing and reallocating memory with xz_dec_end() and xz_dec_init().
*
* In single-call mode, xz_dec_reset() is always called in the beginning of
* xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
* multi-call mode.
*/
XZ_EXTERN void xz_dec_reset(struct xz_dec *s);
/**
* xz_dec_end() - Free the memory allocated for the decoder state
* @s: Decoder state allocated using xz_dec_init(). If s is NULL,
* this function does nothing.
*/
XZ_EXTERN void xz_dec_end(struct xz_dec *s);
/*
* Standalone build (userspace build or in-kernel build for boot time use)
* needs a CRC32 implementation. For normal in-kernel use, kernel's own
* CRC32 module is used instead, and users of this module don't need to
* care about the functions below.
*/
#ifndef XZ_INTERNAL_CRC32
# ifdef __KERNEL__
# define XZ_INTERNAL_CRC32 0
# else
# define XZ_INTERNAL_CRC32 1
# endif
#endif
/*
* If CRC64 support has been enabled with XZ_USE_CRC64, a CRC64
* implementation is needed too.
*/
#ifndef XZ_USE_CRC64
# undef XZ_INTERNAL_CRC64
# define XZ_INTERNAL_CRC64 0
#endif
#ifndef XZ_INTERNAL_CRC64
# ifdef __KERNEL__
# error Using CRC64 in the kernel has not been implemented.
# else
# define XZ_INTERNAL_CRC64 1
# endif
#endif
#if XZ_INTERNAL_CRC32
/*
* This must be called before any other xz_* function to initialize
* the CRC32 lookup table.
*/
XZ_EXTERN void xz_crc32_init(void);
/*
* Update CRC32 value using the polynomial from IEEE-802.3. To start a new
* calculation, the third argument must be zero. To continue the calculation,
* the previously returned value is passed as the third argument.
*/
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc);
#endif
#if XZ_INTERNAL_CRC64
/*
* This must be called before any other xz_* function (except xz_crc32_init())
* to initialize the CRC64 lookup table.
*/
XZ_EXTERN void xz_crc64_init(void);
/*
* Update CRC64 value using the polynomial from ECMA-182. To start a new
* calculation, the third argument must be zero. To continue the calculation,
* the previously returned value is passed as the third argument.
*/
XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,124 @@
/*
* Private includes and definitions for userspace use of XZ Embedded
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_CONFIG_H
#define XZ_CONFIG_H
/* Uncomment to enable CRC64 support. */
/* #define XZ_USE_CRC64 */
/* Uncomment as needed to enable BCJ filter decoders. */
/* #define XZ_DEC_X86 */
/* #define XZ_DEC_POWERPC */
/* #define XZ_DEC_IA64 */
/* #define XZ_DEC_ARM */
/* #define XZ_DEC_ARMTHUMB */
/* #define XZ_DEC_SPARC */
/*
* MSVC doesn't support modern C but XZ Embedded is mostly C89
* so these are enough.
*/
#ifdef _MSC_VER
typedef unsigned char bool;
# define true 1
# define false 0
# define inline __inline
#else
# include <stdbool.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "xz.h"
#define kmalloc(size, flags) malloc(size)
#define kfree(ptr) free(ptr)
#define vmalloc(size) malloc(size)
#define vfree(ptr) free(ptr)
#define memeq(a, b, size) (memcmp(a, b, size) == 0)
#define memzero(buf, size) memset(buf, 0, size)
#ifndef min
# define min(x, y) ((x) < (y) ? (x) : (y))
#endif
#define min_t(type, x, y) min(x, y)
/*
* Some functions have been marked with __always_inline to keep the
* performance reasonable even when the compiler is optimizing for
* small code size. You may be able to save a few bytes by #defining
* __always_inline to plain inline, but don't complain if the code
* becomes slow.
*
* NOTE: System headers on GNU/Linux may #define this macro already,
* so if you want to change it, you need to #undef it first.
*/
#ifndef __always_inline
# ifdef __GNUC__
# define __always_inline \
inline __attribute__((__always_inline__))
# else
# define __always_inline inline
# endif
#endif
/* Inline functions to access unaligned unsigned 32-bit integers */
#ifndef get_unaligned_le32
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
{
return (uint32_t)buf[0]
| ((uint32_t)buf[1] << 8)
| ((uint32_t)buf[2] << 16)
| ((uint32_t)buf[3] << 24);
}
#endif
#ifndef get_unaligned_be32
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
{
return (uint32_t)(buf[0] << 24)
| ((uint32_t)buf[1] << 16)
| ((uint32_t)buf[2] << 8)
| (uint32_t)buf[3];
}
#endif
#ifndef put_unaligned_le32
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
{
buf[0] = (uint8_t)val;
buf[1] = (uint8_t)(val >> 8);
buf[2] = (uint8_t)(val >> 16);
buf[3] = (uint8_t)(val >> 24);
}
#endif
#ifndef put_unaligned_be32
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
{
buf[0] = (uint8_t)(val >> 24);
buf[1] = (uint8_t)(val >> 16);
buf[2] = (uint8_t)(val >> 8);
buf[3] = (uint8_t)val;
}
#endif
/*
* Use get_unaligned_le32() also for aligned access for simplicity. On
* little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
* could save a few bytes in code size.
*/
#ifndef get_le32
# define get_le32 get_unaligned_le32
#endif
#endif

View File

@ -0,0 +1,59 @@
/*
* CRC32 using the polynomial from IEEE-802.3
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
/*
* This is not the fastest implementation, but it is pretty compact.
* The fastest versions of xz_crc32() on modern CPUs without hardware
* accelerated CRC instruction are 3-5 times as fast as this version,
* but they are bigger and use more memory for the lookup table.
*/
#include "xz_private.h"
/*
* STATIC_RW_DATA is used in the pre-boot environment on some architectures.
* See <linux/decompress/mm.h> for details.
*/
#ifndef STATIC_RW_DATA
# define STATIC_RW_DATA static
#endif
STATIC_RW_DATA uint32_t xz_crc32_table[256];
XZ_EXTERN void xz_crc32_init(void)
{
const uint32_t poly = 0xEDB88320;
uint32_t i;
uint32_t j;
uint32_t r;
for (i = 0; i < 256; ++i) {
r = i;
for (j = 0; j < 8; ++j)
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
xz_crc32_table[i] = r;
}
return;
}
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
{
crc = ~crc;
while (size != 0) {
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
--size;
}
return ~crc;
}

View File

@ -0,0 +1,50 @@
/*
* CRC64 using the polynomial from ECMA-182
*
* This file is similar to xz_crc32.c. See the comments there.
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#include "xz_private.h"
#ifndef STATIC_RW_DATA
# define STATIC_RW_DATA static
#endif
STATIC_RW_DATA uint64_t xz_crc64_table[256];
XZ_EXTERN void xz_crc64_init(void)
{
const uint64_t poly = 0xC96C5795D7870F42;
uint32_t i;
uint32_t j;
uint64_t r;
for (i = 0; i < 256; ++i) {
r = i;
for (j = 0; j < 8; ++j)
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
xz_crc64_table[i] = r;
}
return;
}
XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc)
{
crc = ~crc;
while (size != 0) {
crc = xz_crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
--size;
}
return ~crc;
}

View File

@ -0,0 +1,574 @@
/*
* Branch/Call/Jump (BCJ) filter decoders
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#include "xz_private.h"
/*
* The rest of the file is inside this ifdef. It makes things a little more
* convenient when building without support for any BCJ filters.
*/
#ifdef XZ_DEC_BCJ
struct xz_dec_bcj {
/* Type of the BCJ filter being used */
enum {
BCJ_X86 = 4, /* x86 or x86-64 */
BCJ_POWERPC = 5, /* Big endian only */
BCJ_IA64 = 6, /* Big or little endian */
BCJ_ARM = 7, /* Little endian only */
BCJ_ARMTHUMB = 8, /* Little endian only */
BCJ_SPARC = 9 /* Big or little endian */
} type;
/*
* Return value of the next filter in the chain. We need to preserve
* this information across calls, because we must not call the next
* filter anymore once it has returned XZ_STREAM_END.
*/
enum xz_ret ret;
/* True if we are operating in single-call mode. */
bool single_call;
/*
* Absolute position relative to the beginning of the uncompressed
* data (in a single .xz Block). We care only about the lowest 32
* bits so this doesn't need to be uint64_t even with big files.
*/
uint32_t pos;
/* x86 filter state */
uint32_t x86_prev_mask;
/* Temporary space to hold the variables from struct xz_buf */
uint8_t *out;
size_t out_pos;
size_t out_size;
struct {
/* Amount of already filtered data in the beginning of buf */
size_t filtered;
/* Total amount of data currently stored in buf */
size_t size;
/*
* Buffer to hold a mix of filtered and unfiltered data. This
* needs to be big enough to hold Alignment + 2 * Look-ahead:
*
* Type Alignment Look-ahead
* x86 1 4
* PowerPC 4 0
* IA-64 16 0
* ARM 4 0
* ARM-Thumb 2 2
* SPARC 4 0
*/
uint8_t buf[16];
} temp;
};
#ifdef XZ_DEC_X86
/*
* This is used to test the most significant byte of a memory address
* in an x86 instruction.
*/
static inline int bcj_x86_test_msbyte(uint8_t b)
{
return b == 0x00 || b == 0xFF;
}
static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
static const bool mask_to_allowed_status[8]
= { true, true, true, false, true, false, false, false };
static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
size_t i;
size_t prev_pos = (size_t)-1;
uint32_t prev_mask = s->x86_prev_mask;
uint32_t src;
uint32_t dest;
uint32_t j;
uint8_t b;
if (size <= 4)
return 0;
size -= 4;
for (i = 0; i < size; ++i) {
if ((buf[i] & 0xFE) != 0xE8)
continue;
prev_pos = i - prev_pos;
if (prev_pos > 3) {
prev_mask = 0;
} else {
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
if (prev_mask != 0) {
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
if (!mask_to_allowed_status[prev_mask]
|| bcj_x86_test_msbyte(b)) {
prev_pos = i;
prev_mask = (prev_mask << 1) | 1;
continue;
}
}
}
prev_pos = i;
if (bcj_x86_test_msbyte(buf[i + 4])) {
src = get_unaligned_le32(buf + i + 1);
while (true) {
dest = src - (s->pos + (uint32_t)i + 5);
if (prev_mask == 0)
break;
j = mask_to_bit_num[prev_mask] * 8;
b = (uint8_t)(dest >> (24 - j));
if (!bcj_x86_test_msbyte(b))
break;
src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
}
dest &= 0x01FFFFFF;
dest |= (uint32_t)0 - (dest & 0x01000000);
put_unaligned_le32(dest, buf + i + 1);
i += 4;
} else {
prev_mask = (prev_mask << 1) | 1;
}
}
prev_pos = i - prev_pos;
s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
return i;
}
#endif
#ifdef XZ_DEC_POWERPC
static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t instr;
for (i = 0; i + 4 <= size; i += 4) {
instr = get_unaligned_be32(buf + i);
if ((instr & 0xFC000003) == 0x48000001) {
instr &= 0x03FFFFFC;
instr -= s->pos + (uint32_t)i;
instr &= 0x03FFFFFC;
instr |= 0x48000001;
put_unaligned_be32(instr, buf + i);
}
}
return i;
}
#endif
#ifdef XZ_DEC_IA64
static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
static const uint8_t branch_table[32] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 6, 6, 0, 0, 7, 7,
4, 4, 0, 0, 4, 4, 0, 0
};
/*
* The local variables take a little bit stack space, but it's less
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
* stack usage here without doing that for the LZMA2 decoder too.
*/
/* Loop counters */
size_t i;
size_t j;
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
uint32_t slot;
/* Bitwise offset of the instruction indicated by slot */
uint32_t bit_pos;
/* bit_pos split into byte and bit parts */
uint32_t byte_pos;
uint32_t bit_res;
/* Address part of an instruction */
uint32_t addr;
/* Mask used to detect which instructions to convert */
uint32_t mask;
/* 41-bit instruction stored somewhere in the lowest 48 bits */
uint64_t instr;
/* Instruction normalized with bit_res for easier manipulation */
uint64_t norm;
for (i = 0; i + 16 <= size; i += 16) {
mask = branch_table[buf[i] & 0x1F];
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
if (((mask >> slot) & 1) == 0)
continue;
byte_pos = bit_pos >> 3;
bit_res = bit_pos & 7;
instr = 0;
for (j = 0; j < 6; ++j)
instr |= (uint64_t)(buf[i + j + byte_pos])
<< (8 * j);
norm = instr >> bit_res;
if (((norm >> 37) & 0x0F) == 0x05
&& ((norm >> 9) & 0x07) == 0) {
addr = (norm >> 13) & 0x0FFFFF;
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
addr <<= 4;
addr -= s->pos + (uint32_t)i;
addr >>= 4;
norm &= ~((uint64_t)0x8FFFFF << 13);
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
norm |= (uint64_t)(addr & 0x100000)
<< (36 - 20);
instr &= (1 << bit_res) - 1;
instr |= norm << bit_res;
for (j = 0; j < 6; j++)
buf[i + j + byte_pos]
= (uint8_t)(instr >> (8 * j));
}
}
}
return i;
}
#endif
#ifdef XZ_DEC_ARM
static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t addr;
for (i = 0; i + 4 <= size; i += 4) {
if (buf[i + 3] == 0xEB) {
addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
| ((uint32_t)buf[i + 2] << 16);
addr <<= 2;
addr -= s->pos + (uint32_t)i + 8;
addr >>= 2;
buf[i] = (uint8_t)addr;
buf[i + 1] = (uint8_t)(addr >> 8);
buf[i + 2] = (uint8_t)(addr >> 16);
}
}
return i;
}
#endif
#ifdef XZ_DEC_ARMTHUMB
static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t addr;
for (i = 0; i + 4 <= size; i += 2) {
if ((buf[i + 1] & 0xF8) == 0xF0
&& (buf[i + 3] & 0xF8) == 0xF8) {
addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
| ((uint32_t)buf[i] << 11)
| (((uint32_t)buf[i + 3] & 0x07) << 8)
| (uint32_t)buf[i + 2];
addr <<= 1;
addr -= s->pos + (uint32_t)i + 4;
addr >>= 1;
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
buf[i] = (uint8_t)(addr >> 11);
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
buf[i + 2] = (uint8_t)addr;
i += 2;
}
}
return i;
}
#endif
#ifdef XZ_DEC_SPARC
static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t instr;
for (i = 0; i + 4 <= size; i += 4) {
instr = get_unaligned_be32(buf + i);
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
instr <<= 2;
instr -= s->pos + (uint32_t)i;
instr >>= 2;
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
| 0x40000000 | (instr & 0x3FFFFF);
put_unaligned_be32(instr, buf + i);
}
}
return i;
}
#endif
/*
* Apply the selected BCJ filter. Update *pos and s->pos to match the amount
* of data that got filtered.
*
* NOTE: This is implemented as a switch statement to avoid using function
* pointers, which could be problematic in the kernel boot code, which must
* avoid pointers to static data (at least on x86).
*/
static void bcj_apply(struct xz_dec_bcj *s,
uint8_t *buf, size_t *pos, size_t size)
{
size_t filtered;
buf += *pos;
size -= *pos;
switch (s->type) {
#ifdef XZ_DEC_X86
case BCJ_X86:
filtered = bcj_x86(s, buf, size);
break;
#endif
#ifdef XZ_DEC_POWERPC
case BCJ_POWERPC:
filtered = bcj_powerpc(s, buf, size);
break;
#endif
#ifdef XZ_DEC_IA64
case BCJ_IA64:
filtered = bcj_ia64(s, buf, size);
break;
#endif
#ifdef XZ_DEC_ARM
case BCJ_ARM:
filtered = bcj_arm(s, buf, size);
break;
#endif
#ifdef XZ_DEC_ARMTHUMB
case BCJ_ARMTHUMB:
filtered = bcj_armthumb(s, buf, size);
break;
#endif
#ifdef XZ_DEC_SPARC
case BCJ_SPARC:
filtered = bcj_sparc(s, buf, size);
break;
#endif
default:
/* Never reached but silence compiler warnings. */
filtered = 0;
break;
}
*pos += filtered;
s->pos += filtered;
}
/*
* Flush pending filtered data from temp to the output buffer.
* Move the remaining mixture of possibly filtered and unfiltered
* data to the beginning of temp.
*/
static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
{
size_t copy_size;
copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
b->out_pos += copy_size;
s->temp.filtered -= copy_size;
s->temp.size -= copy_size;
memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
}
/*
* The BCJ filter functions are primitive in sense that they process the
* data in chunks of 1-16 bytes. To hide this issue, this function does
* some buffering.
*/
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
struct xz_dec_lzma2 *lzma2,
struct xz_buf *b)
{
size_t out_start;
/*
* Flush pending already filtered data to the output buffer. Return
* immediatelly if we couldn't flush everything, or if the next
* filter in the chain had already returned XZ_STREAM_END.
*/
if (s->temp.filtered > 0) {
bcj_flush(s, b);
if (s->temp.filtered > 0)
return XZ_OK;
if (s->ret == XZ_STREAM_END)
return XZ_STREAM_END;
}
/*
* If we have more output space than what is currently pending in
* temp, copy the unfiltered data from temp to the output buffer
* and try to fill the output buffer by decoding more data from the
* next filter in the chain. Apply the BCJ filter on the new data
* in the output buffer. If everything cannot be filtered, copy it
* to temp and rewind the output buffer position accordingly.
*
* This needs to be always run when temp.size == 0 to handle a special
* case where the output buffer is full and the next filter has no
* more output coming but hasn't returned XZ_STREAM_END yet.
*/
if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
out_start = b->out_pos;
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
b->out_pos += s->temp.size;
s->ret = xz_dec_lzma2_run(lzma2, b);
if (s->ret != XZ_STREAM_END
&& (s->ret != XZ_OK || s->single_call))
return s->ret;
bcj_apply(s, b->out, &out_start, b->out_pos);
/*
* As an exception, if the next filter returned XZ_STREAM_END,
* we can do that too, since the last few bytes that remain
* unfiltered are meant to remain unfiltered.
*/
if (s->ret == XZ_STREAM_END)
return XZ_STREAM_END;
s->temp.size = b->out_pos - out_start;
b->out_pos -= s->temp.size;
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
/*
* If there wasn't enough input to the next filter to fill
* the output buffer with unfiltered data, there's no point
* to try decoding more data to temp.
*/
if (b->out_pos + s->temp.size < b->out_size)
return XZ_OK;
}
/*
* We have unfiltered data in temp. If the output buffer isn't full
* yet, try to fill the temp buffer by decoding more data from the
* next filter. Apply the BCJ filter on temp. Then we hopefully can
* fill the actual output buffer by copying filtered data from temp.
* A mix of filtered and unfiltered data may be left in temp; it will
* be taken care on the next call to this function.
*/
if (b->out_pos < b->out_size) {
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
s->out = b->out;
s->out_pos = b->out_pos;
s->out_size = b->out_size;
b->out = s->temp.buf;
b->out_pos = s->temp.size;
b->out_size = sizeof(s->temp.buf);
s->ret = xz_dec_lzma2_run(lzma2, b);
s->temp.size = b->out_pos;
b->out = s->out;
b->out_pos = s->out_pos;
b->out_size = s->out_size;
if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
return s->ret;
bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
/*
* If the next filter returned XZ_STREAM_END, we mark that
* everything is filtered, since the last unfiltered bytes
* of the stream are meant to be left as is.
*/
if (s->ret == XZ_STREAM_END)
s->temp.filtered = s->temp.size;
bcj_flush(s, b);
if (s->temp.filtered > 0)
return XZ_OK;
}
return s->ret;
}
XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call)
{
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (s != NULL)
s->single_call = single_call;
return s;
}
XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id)
{
switch (id) {
#ifdef XZ_DEC_X86
case BCJ_X86:
#endif
#ifdef XZ_DEC_POWERPC
case BCJ_POWERPC:
#endif
#ifdef XZ_DEC_IA64
case BCJ_IA64:
#endif
#ifdef XZ_DEC_ARM
case BCJ_ARM:
#endif
#ifdef XZ_DEC_ARMTHUMB
case BCJ_ARMTHUMB:
#endif
#ifdef XZ_DEC_SPARC
case BCJ_SPARC:
#endif
break;
default:
/* Unsupported Filter ID */
return XZ_OPTIONS_ERROR;
}
s->type = id;
s->ret = XZ_OK;
s->pos = 0;
s->x86_prev_mask = 0;
s->temp.filtered = 0;
s->temp.size = 0;
return XZ_OK;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,847 @@
/*
* .xz Stream decoder
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#include "xz_private.h"
#include "xz_stream.h"
#ifdef XZ_USE_CRC64
# define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64)
#else
# define IS_CRC64(check_type) false
#endif
/* Hash used to validate the Index field */
struct xz_dec_hash {
vli_type unpadded;
vli_type uncompressed;
uint32_t crc32;
};
struct xz_dec {
/* Position in dec_main() */
enum {
SEQ_STREAM_HEADER,
SEQ_BLOCK_START,
SEQ_BLOCK_HEADER,
SEQ_BLOCK_UNCOMPRESS,
SEQ_BLOCK_PADDING,
SEQ_BLOCK_CHECK,
SEQ_INDEX,
SEQ_INDEX_PADDING,
SEQ_INDEX_CRC32,
SEQ_STREAM_FOOTER
} sequence;
/* Position in variable-length integers and Check fields */
uint32_t pos;
/* Variable-length integer decoded by dec_vli() */
vli_type vli;
/* Saved in_pos and out_pos */
size_t in_start;
size_t out_start;
#ifdef XZ_USE_CRC64
/* CRC32 or CRC64 value in Block or CRC32 value in Index */
uint64_t crc;
#else
/* CRC32 value in Block or Index */
uint32_t crc;
#endif
/* Type of the integrity check calculated from uncompressed data */
enum xz_check check_type;
/* Operation mode */
enum xz_mode mode;
/*
* True if the next call to xz_dec_run() is allowed to return
* XZ_BUF_ERROR.
*/
bool allow_buf_error;
/* Information stored in Block Header */
struct {
/*
* Value stored in the Compressed Size field, or
* VLI_UNKNOWN if Compressed Size is not present.
*/
vli_type compressed;
/*
* Value stored in the Uncompressed Size field, or
* VLI_UNKNOWN if Uncompressed Size is not present.
*/
vli_type uncompressed;
/* Size of the Block Header field */
uint32_t size;
} block_header;
/* Information collected when decoding Blocks */
struct {
/* Observed compressed size of the current Block */
vli_type compressed;
/* Observed uncompressed size of the current Block */
vli_type uncompressed;
/* Number of Blocks decoded so far */
vli_type count;
/*
* Hash calculated from the Block sizes. This is used to
* validate the Index field.
*/
struct xz_dec_hash hash;
} block;
/* Variables needed when verifying the Index field */
struct {
/* Position in dec_index() */
enum {
SEQ_INDEX_COUNT,
SEQ_INDEX_UNPADDED,
SEQ_INDEX_UNCOMPRESSED
} sequence;
/* Size of the Index in bytes */
vli_type size;
/* Number of Records (matches block.count in valid files) */
vli_type count;
/*
* Hash calculated from the Records (matches block.hash in
* valid files).
*/
struct xz_dec_hash hash;
} index;
/*
* Temporary buffer needed to hold Stream Header, Block Header,
* and Stream Footer. The Block Header is the biggest (1 KiB)
* so we reserve space according to that. buf[] has to be aligned
* to a multiple of four bytes; the size_t variables before it
* should guarantee this.
*/
struct {
size_t pos;
size_t size;
uint8_t buf[1024];
} temp;
struct xz_dec_lzma2 *lzma2;
#ifdef XZ_DEC_BCJ
struct xz_dec_bcj *bcj;
bool bcj_active;
#endif
};
#ifdef XZ_DEC_ANY_CHECK
/* Sizes of the Check field with different Check IDs */
static const uint8_t check_sizes[16] = {
0,
4, 4, 4,
8, 8, 8,
16, 16, 16,
32, 32, 32,
64, 64, 64
};
#endif
/*
* Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
* must have set s->temp.pos to indicate how much data we are supposed
* to copy into s->temp.buf. Return true once s->temp.pos has reached
* s->temp.size.
*/
static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
{
size_t copy_size = min_t(size_t,
b->in_size - b->in_pos, s->temp.size - s->temp.pos);
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
b->in_pos += copy_size;
s->temp.pos += copy_size;
if (s->temp.pos == s->temp.size) {
s->temp.pos = 0;
return true;
}
return false;
}
/* Decode a variable-length integer (little-endian base-128 encoding) */
static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
size_t *in_pos, size_t in_size)
{
uint8_t byte;
if (s->pos == 0)
s->vli = 0;
while (*in_pos < in_size) {
byte = in[*in_pos];
++*in_pos;
s->vli |= (vli_type)(byte & 0x7F) << s->pos;
if ((byte & 0x80) == 0) {
/* Don't allow non-minimal encodings. */
if (byte == 0 && s->pos != 0)
return XZ_DATA_ERROR;
s->pos = 0;
return XZ_STREAM_END;
}
s->pos += 7;
if (s->pos == 7 * VLI_BYTES_MAX)
return XZ_DATA_ERROR;
}
return XZ_OK;
}
/*
* Decode the Compressed Data field from a Block. Update and validate
* the observed compressed and uncompressed sizes of the Block so that
* they don't exceed the values possibly stored in the Block Header
* (validation assumes that no integer overflow occurs, since vli_type
* is normally uint64_t). Update the CRC32 or CRC64 value if presence of
* the CRC32 or CRC64 field was indicated in Stream Header.
*
* Once the decoding is finished, validate that the observed sizes match
* the sizes possibly stored in the Block Header. Update the hash and
* Block count, which are later used to validate the Index field.
*/
static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
s->in_start = b->in_pos;
s->out_start = b->out_pos;
#ifdef XZ_DEC_BCJ
if (s->bcj_active)
ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
else
#endif
ret = xz_dec_lzma2_run(s->lzma2, b);
s->block.compressed += b->in_pos - s->in_start;
s->block.uncompressed += b->out_pos - s->out_start;
/*
* There is no need to separately check for VLI_UNKNOWN, since
* the observed sizes are always smaller than VLI_UNKNOWN.
*/
if (s->block.compressed > s->block_header.compressed
|| s->block.uncompressed
> s->block_header.uncompressed)
return XZ_DATA_ERROR;
if (s->check_type == XZ_CHECK_CRC32)
s->crc = xz_crc32(b->out + s->out_start,
b->out_pos - s->out_start, s->crc);
#ifdef XZ_USE_CRC64
else if (s->check_type == XZ_CHECK_CRC64)
s->crc = xz_crc64(b->out + s->out_start,
b->out_pos - s->out_start, s->crc);
#endif
if (ret == XZ_STREAM_END) {
if (s->block_header.compressed != VLI_UNKNOWN
&& s->block_header.compressed
!= s->block.compressed)
return XZ_DATA_ERROR;
if (s->block_header.uncompressed != VLI_UNKNOWN
&& s->block_header.uncompressed
!= s->block.uncompressed)
return XZ_DATA_ERROR;
s->block.hash.unpadded += s->block_header.size
+ s->block.compressed;
#ifdef XZ_DEC_ANY_CHECK
s->block.hash.unpadded += check_sizes[s->check_type];
#else
if (s->check_type == XZ_CHECK_CRC32)
s->block.hash.unpadded += 4;
else if (IS_CRC64(s->check_type))
s->block.hash.unpadded += 8;
#endif
s->block.hash.uncompressed += s->block.uncompressed;
s->block.hash.crc32 = xz_crc32(
(const uint8_t *)&s->block.hash,
sizeof(s->block.hash), s->block.hash.crc32);
++s->block.count;
}
return ret;
}
/* Update the Index size and the CRC32 value. */
static void index_update(struct xz_dec *s, const struct xz_buf *b)
{
size_t in_used = b->in_pos - s->in_start;
s->index.size += in_used;
s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc);
}
/*
* Decode the Number of Records, Unpadded Size, and Uncompressed Size
* fields from the Index field. That is, Index Padding and CRC32 are not
* decoded by this function.
*
* This can return XZ_OK (more input needed), XZ_STREAM_END (everything
* successfully decoded), or XZ_DATA_ERROR (input is corrupt).
*/
static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
do {
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
if (ret != XZ_STREAM_END) {
index_update(s, b);
return ret;
}
switch (s->index.sequence) {
case SEQ_INDEX_COUNT:
s->index.count = s->vli;
/*
* Validate that the Number of Records field
* indicates the same number of Records as
* there were Blocks in the Stream.
*/
if (s->index.count != s->block.count)
return XZ_DATA_ERROR;
s->index.sequence = SEQ_INDEX_UNPADDED;
break;
case SEQ_INDEX_UNPADDED:
s->index.hash.unpadded += s->vli;
s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
break;
case SEQ_INDEX_UNCOMPRESSED:
s->index.hash.uncompressed += s->vli;
s->index.hash.crc32 = xz_crc32(
(const uint8_t *)&s->index.hash,
sizeof(s->index.hash),
s->index.hash.crc32);
--s->index.count;
s->index.sequence = SEQ_INDEX_UNPADDED;
break;
}
} while (s->index.count > 0);
return XZ_STREAM_END;
}
/*
* Validate that the next four or eight input bytes match the value
* of s->crc. s->pos must be zero when starting to validate the first byte.
* The "bits" argument allows using the same code for both CRC32 and CRC64.
*/
static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
uint32_t bits)
{
do {
if (b->in_pos == b->in_size)
return XZ_OK;
if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++])
return XZ_DATA_ERROR;
s->pos += 8;
} while (s->pos < bits);
s->crc = 0;
s->pos = 0;
return XZ_STREAM_END;
}
#ifdef XZ_DEC_ANY_CHECK
/*
* Skip over the Check field when the Check ID is not supported.
* Returns true once the whole Check field has been skipped over.
*/
static bool check_skip(struct xz_dec *s, struct xz_buf *b)
{
while (s->pos < check_sizes[s->check_type]) {
if (b->in_pos == b->in_size)
return false;
++b->in_pos;
++s->pos;
}
s->pos = 0;
return true;
}
#endif
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
static enum xz_ret dec_stream_header(struct xz_dec *s)
{
if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
return XZ_FORMAT_ERROR;
if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
return XZ_DATA_ERROR;
if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
return XZ_OPTIONS_ERROR;
/*
* Of integrity checks, we support none (Check ID = 0),
* CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4).
* However, if XZ_DEC_ANY_CHECK is defined, we will accept other
* check types too, but then the check won't be verified and
* a warning (XZ_UNSUPPORTED_CHECK) will be given.
*/
s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
#ifdef XZ_DEC_ANY_CHECK
if (s->check_type > XZ_CHECK_MAX)
return XZ_OPTIONS_ERROR;
if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
return XZ_UNSUPPORTED_CHECK;
#else
if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
return XZ_OPTIONS_ERROR;
#endif
return XZ_OK;
}
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
static enum xz_ret dec_stream_footer(struct xz_dec *s)
{
if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
return XZ_DATA_ERROR;
if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
return XZ_DATA_ERROR;
/*
* Validate Backward Size. Note that we never added the size of the
* Index CRC32 field to s->index.size, thus we use s->index.size / 4
* instead of s->index.size / 4 - 1.
*/
if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
return XZ_DATA_ERROR;
if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
return XZ_DATA_ERROR;
/*
* Use XZ_STREAM_END instead of XZ_OK to be more convenient
* for the caller.
*/
return XZ_STREAM_END;
}
/* Decode the Block Header and initialize the filter chain. */
static enum xz_ret dec_block_header(struct xz_dec *s)
{
enum xz_ret ret;
/*
* Validate the CRC32. We know that the temp buffer is at least
* eight bytes so this is safe.
*/
s->temp.size -= 4;
if (xz_crc32(s->temp.buf, s->temp.size, 0)
!= get_le32(s->temp.buf + s->temp.size))
return XZ_DATA_ERROR;
s->temp.pos = 2;
/*
* Catch unsupported Block Flags. We support only one or two filters
* in the chain, so we catch that with the same test.
*/
#ifdef XZ_DEC_BCJ
if (s->temp.buf[1] & 0x3E)
#else
if (s->temp.buf[1] & 0x3F)
#endif
return XZ_OPTIONS_ERROR;
/* Compressed Size */
if (s->temp.buf[1] & 0x40) {
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
!= XZ_STREAM_END)
return XZ_DATA_ERROR;
s->block_header.compressed = s->vli;
} else {
s->block_header.compressed = VLI_UNKNOWN;
}
/* Uncompressed Size */
if (s->temp.buf[1] & 0x80) {
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
!= XZ_STREAM_END)
return XZ_DATA_ERROR;
s->block_header.uncompressed = s->vli;
} else {
s->block_header.uncompressed = VLI_UNKNOWN;
}
#ifdef XZ_DEC_BCJ
/* If there are two filters, the first one must be a BCJ filter. */
s->bcj_active = s->temp.buf[1] & 0x01;
if (s->bcj_active) {
if (s->temp.size - s->temp.pos < 2)
return XZ_OPTIONS_ERROR;
ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
if (ret != XZ_OK)
return ret;
/*
* We don't support custom start offset,
* so Size of Properties must be zero.
*/
if (s->temp.buf[s->temp.pos++] != 0x00)
return XZ_OPTIONS_ERROR;
}
#endif
/* Valid Filter Flags always take at least two bytes. */
if (s->temp.size - s->temp.pos < 2)
return XZ_DATA_ERROR;
/* Filter ID = LZMA2 */
if (s->temp.buf[s->temp.pos++] != 0x21)
return XZ_OPTIONS_ERROR;
/* Size of Properties = 1-byte Filter Properties */
if (s->temp.buf[s->temp.pos++] != 0x01)
return XZ_OPTIONS_ERROR;
/* Filter Properties contains LZMA2 dictionary size. */
if (s->temp.size - s->temp.pos < 1)
return XZ_DATA_ERROR;
ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
if (ret != XZ_OK)
return ret;
/* The rest must be Header Padding. */
while (s->temp.pos < s->temp.size)
if (s->temp.buf[s->temp.pos++] != 0x00)
return XZ_OPTIONS_ERROR;
s->temp.pos = 0;
s->block.compressed = 0;
s->block.uncompressed = 0;
return XZ_OK;
}
static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
/*
* Store the start position for the case when we are in the middle
* of the Index field.
*/
s->in_start = b->in_pos;
while (true) {
switch (s->sequence) {
case SEQ_STREAM_HEADER:
/*
* Stream Header is copied to s->temp, and then
* decoded from there. This way if the caller
* gives us only little input at a time, we can
* still keep the Stream Header decoding code
* simple. Similar approach is used in many places
* in this file.
*/
if (!fill_temp(s, b))
return XZ_OK;
/*
* If dec_stream_header() returns
* XZ_UNSUPPORTED_CHECK, it is still possible
* to continue decoding if working in multi-call
* mode. Thus, update s->sequence before calling
* dec_stream_header().
*/
s->sequence = SEQ_BLOCK_START;
ret = dec_stream_header(s);
if (ret != XZ_OK)
return ret;
case SEQ_BLOCK_START:
/* We need one byte of input to continue. */
if (b->in_pos == b->in_size)
return XZ_OK;
/* See if this is the beginning of the Index field. */
if (b->in[b->in_pos] == 0) {
s->in_start = b->in_pos++;
s->sequence = SEQ_INDEX;
break;
}
/*
* Calculate the size of the Block Header and
* prepare to decode it.
*/
s->block_header.size
= ((uint32_t)b->in[b->in_pos] + 1) * 4;
s->temp.size = s->block_header.size;
s->temp.pos = 0;
s->sequence = SEQ_BLOCK_HEADER;
case SEQ_BLOCK_HEADER:
if (!fill_temp(s, b))
return XZ_OK;
ret = dec_block_header(s);
if (ret != XZ_OK)
return ret;
s->sequence = SEQ_BLOCK_UNCOMPRESS;
case SEQ_BLOCK_UNCOMPRESS:
ret = dec_block(s, b);
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_BLOCK_PADDING;
case SEQ_BLOCK_PADDING:
/*
* Size of Compressed Data + Block Padding
* must be a multiple of four. We don't need
* s->block.compressed for anything else
* anymore, so we use it here to test the size
* of the Block Padding field.
*/
while (s->block.compressed & 3) {
if (b->in_pos == b->in_size)
return XZ_OK;
if (b->in[b->in_pos++] != 0)
return XZ_DATA_ERROR;
++s->block.compressed;
}
s->sequence = SEQ_BLOCK_CHECK;
case SEQ_BLOCK_CHECK:
if (s->check_type == XZ_CHECK_CRC32) {
ret = crc_validate(s, b, 32);
if (ret != XZ_STREAM_END)
return ret;
}
else if (IS_CRC64(s->check_type)) {
ret = crc_validate(s, b, 64);
if (ret != XZ_STREAM_END)
return ret;
}
#ifdef XZ_DEC_ANY_CHECK
else if (!check_skip(s, b)) {
return XZ_OK;
}
#endif
s->sequence = SEQ_BLOCK_START;
break;
case SEQ_INDEX:
ret = dec_index(s, b);
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_INDEX_PADDING;
case SEQ_INDEX_PADDING:
while ((s->index.size + (b->in_pos - s->in_start))
& 3) {
if (b->in_pos == b->in_size) {
index_update(s, b);
return XZ_OK;
}
if (b->in[b->in_pos++] != 0)
return XZ_DATA_ERROR;
}
/* Finish the CRC32 value and Index size. */
index_update(s, b);
/* Compare the hashes to validate the Index field. */
if (!memeq(&s->block.hash, &s->index.hash,
sizeof(s->block.hash)))
return XZ_DATA_ERROR;
s->sequence = SEQ_INDEX_CRC32;
case SEQ_INDEX_CRC32:
ret = crc_validate(s, b, 32);
if (ret != XZ_STREAM_END)
return ret;
s->temp.size = STREAM_HEADER_SIZE;
s->sequence = SEQ_STREAM_FOOTER;
case SEQ_STREAM_FOOTER:
if (!fill_temp(s, b))
return XZ_OK;
return dec_stream_footer(s);
}
}
/* Never reached */
}
/*
* xz_dec_run() is a wrapper for dec_main() to handle some special cases in
* multi-call and single-call decoding.
*
* In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
* are not going to make any progress anymore. This is to prevent the caller
* from calling us infinitely when the input file is truncated or otherwise
* corrupt. Since zlib-style API allows that the caller fills the input buffer
* only when the decoder doesn't produce any new output, we have to be careful
* to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
* after the second consecutive call to xz_dec_run() that makes no progress.
*
* In single-call mode, if we couldn't decode everything and no error
* occurred, either the input is truncated or the output buffer is too small.
* Since we know that the last input byte never produces any output, we know
* that if all the input was consumed and decoding wasn't finished, the file
* must be corrupt. Otherwise the output buffer has to be too small or the
* file is corrupt in a way that decoding it produces too big output.
*
* If single-call decoding fails, we reset b->in_pos and b->out_pos back to
* their original values. This is because with some filter chains there won't
* be any valid uncompressed data in the output buffer unless the decoding
* actually succeeds (that's the price to pay of using the output buffer as
* the workspace).
*/
XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
{
size_t in_start;
size_t out_start;
enum xz_ret ret;
if (DEC_IS_SINGLE(s->mode))
xz_dec_reset(s);
in_start = b->in_pos;
out_start = b->out_pos;
ret = dec_main(s, b);
if (DEC_IS_SINGLE(s->mode)) {
if (ret == XZ_OK)
ret = b->in_pos == b->in_size
? XZ_DATA_ERROR : XZ_BUF_ERROR;
if (ret != XZ_STREAM_END) {
b->in_pos = in_start;
b->out_pos = out_start;
}
} else if (ret == XZ_OK && in_start == b->in_pos
&& out_start == b->out_pos) {
if (s->allow_buf_error)
ret = XZ_BUF_ERROR;
s->allow_buf_error = true;
} else {
s->allow_buf_error = false;
}
return ret;
}
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
{
struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (s == NULL)
return NULL;
s->mode = mode;
#ifdef XZ_DEC_BCJ
s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
if (s->bcj == NULL)
goto error_bcj;
#endif
s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
if (s->lzma2 == NULL)
goto error_lzma2;
xz_dec_reset(s);
return s;
error_lzma2:
#ifdef XZ_DEC_BCJ
xz_dec_bcj_end(s->bcj);
error_bcj:
#endif
kfree(s);
return NULL;
}
XZ_EXTERN void xz_dec_reset(struct xz_dec *s)
{
s->sequence = SEQ_STREAM_HEADER;
s->allow_buf_error = false;
s->pos = 0;
s->crc = 0;
memzero(&s->block, sizeof(s->block));
memzero(&s->index, sizeof(s->index));
s->temp.pos = 0;
s->temp.size = STREAM_HEADER_SIZE;
}
XZ_EXTERN void xz_dec_end(struct xz_dec *s)
{
if (s != NULL) {
xz_dec_lzma2_end(s->lzma2);
#ifdef XZ_DEC_BCJ
xz_dec_bcj_end(s->bcj);
#endif
kfree(s);
}
}

View File

@ -0,0 +1,204 @@
/*
* LZMA2 definitions
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_LZMA2_H
#define XZ_LZMA2_H
/* Range coder constants */
#define RC_SHIFT_BITS 8
#define RC_TOP_BITS 24
#define RC_TOP_VALUE (1 << RC_TOP_BITS)
#define RC_BIT_MODEL_TOTAL_BITS 11
#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
#define RC_MOVE_BITS 5
/*
* Maximum number of position states. A position state is the lowest pb
* number of bits of the current uncompressed offset. In some places there
* are different sets of probabilities for different position states.
*/
#define POS_STATES_MAX (1 << 4)
/*
* This enum is used to track which LZMA symbols have occurred most recently
* and in which order. This information is used to predict the next symbol.
*
* Symbols:
* - Literal: One 8-bit byte
* - Match: Repeat a chunk of data at some distance
* - Long repeat: Multi-byte match at a recently seen distance
* - Short repeat: One-byte repeat at a recently seen distance
*
* The symbol names are in from STATE_oldest_older_previous. REP means
* either short or long repeated match, and NONLIT means any non-literal.
*/
enum lzma_state {
STATE_LIT_LIT,
STATE_MATCH_LIT_LIT,
STATE_REP_LIT_LIT,
STATE_SHORTREP_LIT_LIT,
STATE_MATCH_LIT,
STATE_REP_LIT,
STATE_SHORTREP_LIT,
STATE_LIT_MATCH,
STATE_LIT_LONGREP,
STATE_LIT_SHORTREP,
STATE_NONLIT_MATCH,
STATE_NONLIT_REP
};
/* Total number of states */
#define STATES 12
/* The lowest 7 states indicate that the previous state was a literal. */
#define LIT_STATES 7
/* Indicate that the latest symbol was a literal. */
static inline void lzma_state_literal(enum lzma_state *state)
{
if (*state <= STATE_SHORTREP_LIT_LIT)
*state = STATE_LIT_LIT;
else if (*state <= STATE_LIT_SHORTREP)
*state -= 3;
else
*state -= 6;
}
/* Indicate that the latest symbol was a match. */
static inline void lzma_state_match(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
}
/* Indicate that the latest state was a long repeated match. */
static inline void lzma_state_long_rep(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
}
/* Indicate that the latest symbol was a short match. */
static inline void lzma_state_short_rep(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
}
/* Test if the previous symbol was a literal. */
static inline bool lzma_state_is_literal(enum lzma_state state)
{
return state < LIT_STATES;
}
/* Each literal coder is divided in three sections:
* - 0x001-0x0FF: Without match byte
* - 0x101-0x1FF: With match byte; match bit is 0
* - 0x201-0x2FF: With match byte; match bit is 1
*
* Match byte is used when the previous LZMA symbol was something else than
* a literal (that is, it was some kind of match).
*/
#define LITERAL_CODER_SIZE 0x300
/* Maximum number of literal coders */
#define LITERAL_CODERS_MAX (1 << 4)
/* Minimum length of a match is two bytes. */
#define MATCH_LEN_MIN 2
/* Match length is encoded with 4, 5, or 10 bits.
*
* Length Bits
* 2-9 4 = Choice=0 + 3 bits
* 10-17 5 = Choice=1 + Choice2=0 + 3 bits
* 18-273 10 = Choice=1 + Choice2=1 + 8 bits
*/
#define LEN_LOW_BITS 3
#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
#define LEN_MID_BITS 3
#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
#define LEN_HIGH_BITS 8
#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
/*
* Maximum length of a match is 273 which is a result of the encoding
* described above.
*/
#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
/*
* Different sets of probabilities are used for match distances that have
* very short match length: Lengths of 2, 3, and 4 bytes have a separate
* set of probabilities for each length. The matches with longer length
* use a shared set of probabilities.
*/
#define DIST_STATES 4
/*
* Get the index of the appropriate probability array for decoding
* the distance slot.
*/
static inline uint32_t lzma_get_dist_state(uint32_t len)
{
return len < DIST_STATES + MATCH_LEN_MIN
? len - MATCH_LEN_MIN : DIST_STATES - 1;
}
/*
* The highest two bits of a 32-bit match distance are encoded using six bits.
* This six-bit value is called a distance slot. This way encoding a 32-bit
* value takes 6-36 bits, larger values taking more bits.
*/
#define DIST_SLOT_BITS 6
#define DIST_SLOTS (1 << DIST_SLOT_BITS)
/* Match distances up to 127 are fully encoded using probabilities. Since
* the highest two bits (distance slot) are always encoded using six bits,
* the distances 0-3 don't need any additional bits to encode, since the
* distance slot itself is the same as the actual distance. DIST_MODEL_START
* indicates the first distance slot where at least one additional bit is
* needed.
*/
#define DIST_MODEL_START 4
/*
* Match distances greater than 127 are encoded in three pieces:
* - distance slot: the highest two bits
* - direct bits: 2-26 bits below the highest two bits
* - alignment bits: four lowest bits
*
* Direct bits don't use any probabilities.
*
* The distance slot value of 14 is for distances 128-191.
*/
#define DIST_MODEL_END 14
/* Distance slots that indicate a distance <= 127. */
#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
/*
* For match distances greater than 127, only the highest two bits and the
* lowest four bits (alignment) is encoded using probabilities.
*/
#define ALIGN_BITS 4
#define ALIGN_SIZE (1 << ALIGN_BITS)
#define ALIGN_MASK (ALIGN_SIZE - 1)
/* Total number of all probability variables */
#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
/*
* LZMA remembers the four most recent match distances. Reusing these
* distances tends to take less space than re-encoding the actual
* distance value.
*/
#define REPS 4
#endif

View File

@ -0,0 +1,156 @@
/*
* Private includes and definitions
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_PRIVATE_H
#define XZ_PRIVATE_H
#ifdef __KERNEL__
# include <linux/xz.h>
# include <linux/kernel.h>
# include <asm/unaligned.h>
/* XZ_PREBOOT may be defined only via decompress_unxz.c. */
# ifndef XZ_PREBOOT
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/string.h>
# ifdef CONFIG_XZ_DEC_X86
# define XZ_DEC_X86
# endif
# ifdef CONFIG_XZ_DEC_POWERPC
# define XZ_DEC_POWERPC
# endif
# ifdef CONFIG_XZ_DEC_IA64
# define XZ_DEC_IA64
# endif
# ifdef CONFIG_XZ_DEC_ARM
# define XZ_DEC_ARM
# endif
# ifdef CONFIG_XZ_DEC_ARMTHUMB
# define XZ_DEC_ARMTHUMB
# endif
# ifdef CONFIG_XZ_DEC_SPARC
# define XZ_DEC_SPARC
# endif
# define memeq(a, b, size) (memcmp(a, b, size) == 0)
# define memzero(buf, size) memset(buf, 0, size)
# endif
# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
#else
/*
* For userspace builds, use a separate header to define the required
* macros and functions. This makes it easier to adapt the code into
* different environments and avoids clutter in the Linux kernel tree.
*/
# include "xz_config.h"
#endif
/* If no specific decoding mode is requested, enable support for all modes. */
#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
&& !defined(XZ_DEC_DYNALLOC)
# define XZ_DEC_SINGLE
# define XZ_DEC_PREALLOC
# define XZ_DEC_DYNALLOC
#endif
/*
* The DEC_IS_foo(mode) macros are used in "if" statements. If only some
* of the supported modes are enabled, these macros will evaluate to true or
* false at compile time and thus allow the compiler to omit unneeded code.
*/
#ifdef XZ_DEC_SINGLE
# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE)
#else
# define DEC_IS_SINGLE(mode) (false)
#endif
#ifdef XZ_DEC_PREALLOC
# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC)
#else
# define DEC_IS_PREALLOC(mode) (false)
#endif
#ifdef XZ_DEC_DYNALLOC
# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC)
#else
# define DEC_IS_DYNALLOC(mode) (false)
#endif
#if !defined(XZ_DEC_SINGLE)
# define DEC_IS_MULTI(mode) (true)
#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC)
# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE)
#else
# define DEC_IS_MULTI(mode) (false)
#endif
/*
* If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
* XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
*/
#ifndef XZ_DEC_BCJ
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|| defined(XZ_DEC_SPARC)
# define XZ_DEC_BCJ
# endif
#endif
/*
* Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
* before calling xz_dec_lzma2_run().
*/
XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
uint32_t dict_max);
/*
* Decode the LZMA2 properties (one byte) and reset the decoder. Return
* XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
* big enough, and XZ_OPTIONS_ERROR if props indicates something that this
* decoder doesn't support.
*/
XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s,
uint8_t props);
/* Decode raw LZMA2 stream from b->in to b->out. */
XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
struct xz_buf *b);
/* Free the memory allocated for the LZMA2 decoder. */
XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
#ifdef XZ_DEC_BCJ
/*
* Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
* calling xz_dec_bcj_run().
*/
XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call);
/*
* Decode the Filter ID of a BCJ filter. This implementation doesn't
* support custom start offsets, so no decoding of Filter Properties
* is needed. Returns XZ_OK if the given Filter ID is supported.
* Otherwise XZ_OPTIONS_ERROR is returned.
*/
XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id);
/*
* Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
* a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
* must be called directly.
*/
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
struct xz_dec_lzma2 *lzma2,
struct xz_buf *b);
/* Free the memory allocated for the BCJ filters. */
#define xz_dec_bcj_end(s) kfree(s)
#endif
#endif

View File

@ -0,0 +1,62 @@
/*
* Definitions for handling the .xz file format
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
#ifndef XZ_STREAM_H
#define XZ_STREAM_H
#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32
# include <linux/crc32.h>
# undef crc32
# define xz_crc32(buf, size, crc) \
(~crc32_le(~(uint32_t)(crc), buf, size))
#endif
/*
* See the .xz file format specification at
* http://tukaani.org/xz/xz-file-format.txt
* to understand the container format.
*/
#define STREAM_HEADER_SIZE 12
#define HEADER_MAGIC "\3757zXZ"
#define HEADER_MAGIC_SIZE 6
#define FOOTER_MAGIC "YZ"
#define FOOTER_MAGIC_SIZE 2
/*
* Variable-length integer can hold a 63-bit unsigned integer or a special
* value indicating that the value is unknown.
*
* Experimental: vli_type can be defined to uint32_t to save a few bytes
* in code size (no effect on speed). Doing so limits the uncompressed and
* compressed size of the file to less than 256 MiB and may also weaken
* error detection slightly.
*/
typedef uint64_t vli_type;
#define VLI_MAX ((vli_type)-1 / 2)
#define VLI_UNKNOWN ((vli_type)-1)
/* Maximum encoded size of a VLI */
#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
/* Integrity Check types */
enum xz_check {
XZ_CHECK_NONE = 0,
XZ_CHECK_CRC32 = 1,
XZ_CHECK_CRC64 = 4,
XZ_CHECK_SHA256 = 10
};
/* Maximum possible Check ID */
#define XZ_CHECK_MAX 15
#endif

View File

@ -0,0 +1,135 @@
/*
* Simple XZ decoder command line tool
*
* Author: Lasse Collin <lasse.collin@tukaani.org>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
/*
* This is really limited: Not all filters from .xz format are supported,
* only CRC32 is supported as the integrity check, and decoding of
* concatenated .xz streams is not supported. Thus, you may want to look
* at xzdec from XZ Utils if a few KiB bigger tool is not a problem.
*/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "xz.h"
static uint8_t in[BUFSIZ];
static uint8_t out[BUFSIZ];
int main(int argc, char **argv)
{
struct xz_buf b;
struct xz_dec *s;
enum xz_ret ret;
const char *msg;
if (argc >= 2 && strcmp(argv[1], "--help") == 0) {
fputs("Uncompress a .xz file from stdin to stdout.\n"
"Arguments other than `--help' are ignored.\n",
stdout);
return 0;
}
xz_crc32_init();
#ifdef XZ_USE_CRC64
xz_crc64_init();
#endif
/*
* Support up to 64 MiB dictionary. The actually needed memory
* is allocated once the headers have been parsed.
*/
s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
if (s == NULL) {
msg = "Memory allocation failed\n";
goto error;
}
b.in = in;
b.in_pos = 0;
b.in_size = 0;
b.out = out;
b.out_pos = 0;
b.out_size = BUFSIZ;
while (true) {
if (b.in_pos == b.in_size) {
b.in_size = fread(in, 1, sizeof(in), stdin);
b.in_pos = 0;
}
ret = xz_dec_run(s, &b);
if (b.out_pos == sizeof(out)) {
if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
msg = "Write error\n";
goto error;
}
b.out_pos = 0;
}
if (ret == XZ_OK)
continue;
#ifdef XZ_DEC_ANY_CHECK
if (ret == XZ_UNSUPPORTED_CHECK) {
fputs(argv[0], stderr);
fputs(": ", stderr);
fputs("Unsupported check; not verifying "
"file integrity\n", stderr);
continue;
}
#endif
if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos
|| fclose(stdout)) {
msg = "Write error\n";
goto error;
}
switch (ret) {
case XZ_STREAM_END:
xz_dec_end(s);
return 0;
case XZ_MEM_ERROR:
msg = "Memory allocation failed\n";
goto error;
case XZ_MEMLIMIT_ERROR:
msg = "Memory usage limit reached\n";
goto error;
case XZ_FORMAT_ERROR:
msg = "Not a .xz file\n";
goto error;
case XZ_OPTIONS_ERROR:
msg = "Unsupported options in the .xz headers\n";
goto error;
case XZ_DATA_ERROR:
case XZ_BUF_ERROR:
msg = "File is corrupt\n";
goto error;
default:
msg = "Bug!\n";
goto error;
}
}
error:
xz_dec_end(s);
fputs(argv[0], stderr);
fputs(": ", stderr);
fputs(msg, stderr);
return 1;
}