Implemented xz and pack200 unpackers required for proper forge installation.

Merge branch 'feature_forge_unpackers' into develop

Conflicts:
	CMakeLists.txt
This commit is contained in:
Petr Mrázek 2013-09-30 03:29:12 +02:00
commit c05a39147a
77 changed files with 4720 additions and 8621 deletions

View File

@ -50,6 +50,14 @@ include_directories(depends/quazip)
# Add the java launcher
add_subdirectory(depends/launcher)
# Add xz decompression
add_subdirectory(depends/xz-embedded)
include_directories(${XZ_INCLUDE_DIR})
# Add pack200 decompression
add_subdirectory(depends/pack200)
include_directories(${PACK200_INCLUDE_DIR})
######## MultiMC Libs ########
# Add the util library.
@ -225,6 +233,8 @@ logic/net/ByteArrayDownload.h
logic/net/ByteArrayDownload.cpp
logic/net/CacheDownload.h
logic/net/CacheDownload.cpp
logic/net/ForgeXzDownload.h
logic/net/ForgeXzDownload.cpp
logic/net/DownloadJob.h
logic/net/DownloadJob.cpp
logic/net/HttpMetaCache.h
@ -347,8 +357,8 @@ ADD_EXECUTABLE(MultiMC MACOSX_BUNDLE WIN32
${MULTIMC_SOURCES} ${MULTIMC_UI} ${MULTIMC_QRC} ${MULTIMC_RCS})
# Link
QT5_USE_MODULES(MultiMC Widgets Network Xml)
TARGET_LINK_LIBRARIES(MultiMC quazip libUtil libSettings libGroupView ${MultiMC_LINK_ADDITIONAL_LIBS})
TARGET_LINK_LIBRARIES(MultiMC xz-embedded unpack200 quazip libUtil libSettings libGroupView ${MultiMC_LINK_ADDITIONAL_LIBS})
QT5_USE_MODULES(MultiMC Core Widgets Network Xml)
ADD_DEPENDENCIES(MultiMC MultiMCLauncher)
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

@ -19,6 +19,7 @@ ELSE(UNIX)
ENDIF(UNIX)
SET(PACK200_SRC
include/unpack200.h
src/bands.cpp
src/bands.h
src/bytes.cpp
@ -27,7 +28,7 @@ src/coding.cpp
src/coding.h
src/constants.h
src/defines.h
src/main.cpp
src/unpack200.cpp
src/unpack.cpp
src/unpack.h
src/utils.cpp
@ -36,7 +37,14 @@ src/zip.cpp
src/zip.h
)
add_executable(unpack200 ${PACK200_SRC})
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
SET(PACK200_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
include_directories(
include
${ZLIB_INCLUDE_DIRS}
)
add_library(unpack200 STATIC ${PACK200_SRC})
IF(UNIX)
target_link_libraries(unpack200 ${ZLIB_LIBRARIES})
@ -44,3 +52,6 @@ ELSE()
# zlib is part of Qt on windows. use it.
QT5_USE_MODULES(unpack200 Core)
ENDIF()
add_executable(anti200 anti200.cpp)
target_link_libraries(anti200 unpack200)

View File

@ -0,0 +1,28 @@
/*
* This is trivial. Do what thou wilt with it. Public domain.
*/
#include <stdexcept>
#include <iostream>
#include "unpack200.h"
int main(int argc, char **argv)
{
if (argc == 3)
{
try
{
unpack_200(argv[1], argv[2]);
}
catch (std::runtime_error &e)
{
std::cerr << "Bad things happened: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
else
std::cerr << "Simple pack200 unpacker!" << std::endl << "Run like this:" << std::endl
<< " " << argv[0] << " input.jar.lzma output.jar" << std::endl;
return EXIT_FAILURE;
}

View File

@ -1 +1,37 @@
/*
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#pragma once
#include <string>
/**
* @brief Unpack a PACK200 file
*
* @param input_path Path to the input file in PACK200 format. System native string encoding.
* @param output_path Path to the output file in PACK200 format. System native string encoding.
* @return void
* @throw std::runtime_error for any error encountered
*/
void unpack_200(std::string input_path, std::string output_path);

View File

@ -34,6 +34,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <stdint.h>
#include "defines.h"
#include "bytes.h"
@ -44,18 +45,8 @@
#include "constants.h"
#include "unpack.h"
inline void band::abort(const char *msg)
{
u->abort(msg);
}
inline bool band::aborting()
{
return u->aborting();
}
void band::readData(int expectedLength)
{
CHECK;
assert(expectedLength >= 0);
assert(vs[0].cmk == cmk_ERROR);
if (expectedLength != 0)
@ -82,7 +73,7 @@ void band::readData(int expectedLength)
// Make a conservatively generous estimate of band size in bytes.
// Assume B == 5 everywhere.
// Assume awkward pop with all {U} values (2*5 per value)
jlong generous = (jlong)length * (B_MAX * 3 + 1) + C_SLOP;
int64_t generous = (int64_t)length * (B_MAX * 3 + 1) + C_SLOP;
u->ensure_input(generous);
}
@ -93,13 +84,6 @@ void band::readData(int expectedLength)
{
// must be a variable-length coding
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;
coding *valc = defc;
@ -109,7 +93,6 @@ void band::readData(int expectedLength)
assert(!valc->isMalloc);
}
xvs.init(u->rp, u->rplimit, valc);
CHECK;
int X = xvs.getInt();
if (valc->S() != 0)
{
@ -140,7 +123,6 @@ void band::readData(int expectedLength)
byte XB_byte = (byte)XB;
byte *XB_ptr = &XB_byte;
cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, nullptr);
CHECK;
}
else
{
@ -169,7 +151,6 @@ void band::setIndexByTag(byte tag)
entry *band::getRefCommon(cpindex *ix_, bool nullOKwithCaller)
{
CHECK_0;
assert(ix_->ixTag == ixTag ||
(ixTag == CONSTANT_Literal && ix_->ixTag >= CONSTANT_Integer &&
ix_->ixTag <= CONSTANT_String));
@ -178,27 +159,26 @@ entry *band::getRefCommon(cpindex *ix_, bool nullOKwithCaller)
// But nullOKwithCaller means caller is willing to tolerate a nullptr.
entry *ref = ix_->get(n);
if (ref == nullptr && !(nullOKwithCaller && n == -1))
abort(n == -1 ? "nullptr ref" : "bad ref");
unpack_abort(n == -1 ? "nullptr ref" : "bad ref");
return ref;
}
jlong band::getLong(band &lo_band, bool have_hi)
int64_t band::getLong(band &lo_band, bool have_hi)
{
band &hi_band = (*this);
assert(lo_band.bn == hi_band.bn + 1);
uint lo = lo_band.getInt();
uint32_t lo = lo_band.getInt();
if (!have_hi)
{
assert(hi_band.length == 0);
return makeLong(0, lo);
}
uint hi = hi_band.getInt();
uint32_t hi = hi_band.getInt();
return makeLong(hi, lo);
}
int band::getIntTotal()
{
CHECK_0;
if (length == 0)
return 0;
if (total_memo > 0)
@ -208,8 +188,7 @@ int band::getIntTotal()
// and that the partial sums never overflow (wrap negative)
if (total < 0)
{
abort("overflow detected");
return 0;
unpack_abort("overflow detected");
}
for (int k = length - 1; k > 0; k--)
{
@ -217,8 +196,7 @@ int band::getIntTotal()
total += vs[0].getInt();
if (total < prev_total)
{
abort("overflow detected");
return 0;
unpack_abort("overflow detected");
}
}
rewind();
@ -228,7 +206,6 @@ int band::getIntTotal()
int band::getIntCount(int tag)
{
CHECK_0;
if (length == 0)
return 0;
if (tag >= HIST0_MIN && tag <= HIST0_MAX)
@ -237,7 +214,6 @@ int band::getIntCount(int tag)
{
// Lazily calculate an approximate histogram.
hist0 = U_NEW(int, (HIST0_MAX - HIST0_MIN) + 1);
CHECK_0;
for (int k = length; k > 0; k--)
{
int x = vs[0].getInt();
@ -411,7 +387,6 @@ const band_init all_band_inits[] =
BAND_INIT(file_modtime, DELTA5_spec, 0), BAND_INIT(file_options, UNSIGNED5_spec, 0),
// BAND_INIT(file_bits, BYTE1_spec, 0),
{0, 0}};
#define NUM_BAND_INITS (sizeof(all_band_inits) / sizeof(all_band_inits[0]))
band *band::makeBands(unpacker *u)
{
@ -425,7 +400,6 @@ band *band::makeBands(unpacker *u)
coding *defc = coding::findBySpec(bi.defc);
assert((defc == nullptr) == (bi.defc == -1)); // no garbage, please
assert(defc == nullptr || !defc->isMalloc);
assert(bi.bn == i); // band array consistent w/ band enum
b.init(u, i, defc);
if (bi.index > 0)
{
@ -442,7 +416,7 @@ void band::initIndexes(unpacker *u)
for (int i = 0; i < BAND_LIMIT; i++)
{
band *scan = &tmp_all_bands[i];
uint tag = scan->ixTag; // Cf. #define INDEX(tag) above
uint32_t tag = scan->ixTag; // Cf. #define INDEX(tag) above
if (tag != 0 && tag != CONSTANT_Literal && (tag & SUBINDEX_BIT) == 0)
{
scan->setIndex(u->cp.getIndex(tag));

View File

@ -150,11 +150,11 @@ struct band
return getRefCommon(ix2, true);
}
entry *getRefCommon(cpindex *ix, bool nullOK);
jlong getLong(band &lo_band, bool have_hi);
int64_t getLong(band &lo_band, bool have_hi);
static jlong makeLong(uint hi, uint lo)
static int64_t makeLong(uint32_t hi, uint32_t lo)
{
return ((julong)hi << 32) + (((julong)lo << 32) >> 32);
return ((uint64_t)hi << 32) + (((uint64_t)lo << 32) >> 32);
}
int getIntTotal();
@ -162,9 +162,6 @@ struct band
static band *makeBands(unpacker *u);
static void initIndexes(unpacker *u);
void abort(const char *msg = nullptr); //{ u->abort(msg); }
bool aborting(); //{ return u->aborting(); }
};
extern band all_bands[];

View File

@ -27,6 +27,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include "defines.h"
#include "bytes.h"
#include "utils.h"
@ -114,7 +115,7 @@ int bytes::compareTo(bytes &other)
void bytes::saveFrom(const void *ptr_, size_t len_)
{
malloc(len_);
// Save as much as possible. (Helps unpacker::abort.)
// Save as much as possible.
if (len_ > len)
{
assert(ptr == dummy); // error recovery
@ -161,7 +162,6 @@ byte *fillbytes::grow(size_t s)
allocated = b.len;
if (allocated != maxlen)
{
assert(unpack_aborting());
b.len = nlen - s; // back up
return dummy; // scribble during error recov.
}

View File

@ -161,7 +161,7 @@ struct fillbytes
b.len = 0;
}
int8_t *grow(size_t s); // grow so that limit() += s
int getByte(uint i)
int getByte(uint32_t i)
{
return *loc(i) & 0xFF;
}

View File

@ -32,6 +32,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <stdint.h>
#include "defines.h"
#include "bytes.h"
@ -53,12 +54,12 @@ extern coding basic_codings[];
#define IS_NEG_CODE(S, codeVal) ((((int)(codeVal) + 1) & ((1 << S) - 1)) == 0)
#define DECODE_SIGN_S1(ux) (((uint)(ux) >> 1) ^ -((int)(ux) & 1))
#define DECODE_SIGN_S1(ux) (((uint32_t)(ux) >> 1) ^ -((int)(ux) & 1))
static int decode_sign(int S, uint ux)
static int decode_sign(int S, uint32_t ux)
{ // == Coding.decodeSign32
assert(S > 0);
uint sigbits = (ux >> S);
uint32_t sigbits = (ux >> S);
if (IS_NEG_CODE(S, ux))
return (int)(~sigbits);
else
@ -90,9 +91,9 @@ coding *coding::init()
return nullptr; // no 5-byte fixed-size coding
// first compute the range of the coding, in 64 bits
jlong range = 0;
int64_t range = 0;
{
jlong H_i = 1;
int64_t H_i = 1;
for (int i = 0; i < B; i++)
{
range += H_i;
@ -106,7 +107,7 @@ coding *coding::init()
int this_umax;
// now, compute min and max
if (range >= ((jlong)1 << 32))
if (range >= ((int64_t)1 << 32))
{
this_umax = INT_MAX_VALUE;
this->umin = INT_MIN_VALUE;
@ -121,13 +122,13 @@ coding *coding::init()
if (S != 0 && range != 0)
{
int Smask = (1 << S) - 1;
jlong maxPosCode = range - 1;
jlong maxNegCode = range - 1;
int64_t maxPosCode = range - 1;
int64_t maxNegCode = range - 1;
while (IS_NEG_CODE(S, maxPosCode))
--maxPosCode;
while (!IS_NEG_CODE(S, maxNegCode))
--maxNegCode;
int maxPos = decode_sign(S, (uint)maxPosCode);
int maxPos = decode_sign(S, (uint32_t)maxPosCode);
if (maxPos < 0)
this->max = INT_MAX_VALUE; // 32-bit wraparound
else
@ -135,7 +136,7 @@ coding *coding::init()
if (maxNegCode < 0)
this->min = 0; // No negative codings at all.
else
this->min = decode_sign(S, (uint)maxNegCode);
this->min = decode_sign(S, (uint32_t)maxNegCode);
}
}
@ -163,7 +164,8 @@ coding *coding::findBySpec(int spec)
break;
}
coding *ptr = NEW(coding, 1);
CHECK_NULL_0(ptr);
if (!ptr)
return nullptr;
coding *c = ptr->initFrom(spec);
if (c == nullptr)
{
@ -207,25 +209,25 @@ void coding_method::reset(value_stream *state)
}
}
uint coding::parse(byte *&rp, int B, int H)
uint32_t coding::parse(byte *&rp, int B, int H)
{
int L = 256 - H;
byte *ptr = rp;
// hand peel the i==0 part of the loop:
uint b_i = *ptr++ & 0xFF;
if (B == 1 || b_i < (uint)L)
uint32_t b_i = *ptr++ & 0xFF;
if (B == 1 || b_i < (uint32_t)L)
{
rp = ptr;
return b_i;
}
uint sum = b_i;
uint H_i = H;
uint32_t sum = b_i;
uint32_t H_i = H;
assert(B <= B_MAX);
for (int i = 2; i <= B_MAX; i++)
{ // easy for compilers to unroll if desired
b_i = *ptr++ & 0xFF;
sum += b_i * H_i;
if (i == B || b_i < (uint)L)
if (i == B || b_i < (uint32_t)L)
{
rp = ptr;
return sum;
@ -236,26 +238,26 @@ uint coding::parse(byte *&rp, int B, int H)
return 0;
}
uint coding::parse_lgH(byte *&rp, int B, int H, int lgH)
uint32_t coding::parse_lgH(byte *&rp, int B, int H, int lgH)
{
assert(H == (1 << lgH));
int L = 256 - (1 << lgH);
byte *ptr = rp;
// hand peel the i==0 part of the loop:
uint b_i = *ptr++ & 0xFF;
if (B == 1 || b_i < (uint)L)
uint32_t b_i = *ptr++ & 0xFF;
if (B == 1 || b_i < (uint32_t)L)
{
rp = ptr;
return b_i;
}
uint sum = b_i;
uint lg_H_i = lgH;
uint32_t sum = b_i;
uint32_t lg_H_i = lgH;
assert(B <= B_MAX);
for (int i = 2; i <= B_MAX; i++)
{ // easy for compilers to unroll if desired
b_i = *ptr++ & 0xFF;
sum += b_i << lg_H_i;
if (i == B || b_i < (uint)L)
if (i == B || b_i < (uint32_t)L)
{
rp = ptr;
return sum;
@ -272,7 +274,7 @@ void coding::parseMultiple(byte *&rp, int N, byte *limit, int B, int H)
{
if (N < 0)
{
abort("bad value count");
unpack_abort("bad value count");
return;
}
byte *ptr = rp;
@ -281,7 +283,7 @@ void coding::parseMultiple(byte *&rp, int N, byte *limit, int B, int H)
size_t len = (size_t)N * B;
if (len / B != (size_t)N || ptr + len > limit)
{
abort(ERB);
unpack_abort(ERB);
return;
}
rp = ptr + len;
@ -312,7 +314,7 @@ void coding::parseMultiple(byte *&rp, int N, byte *limit, int B, int H)
// do an error check here
if (ptr > limit)
{
abort(ERB);
unpack_abort(ERB);
return;
}
}
@ -401,12 +403,12 @@ void value_stream::setCoding(coding *defc)
}
}
static int getPopValue(value_stream *self, uint uval)
static int getPopValue(value_stream *self, uint32_t uval)
{
if (uval > 0)
{
// note that the initial parse performed a range check
assert(uval <= (uint)self->cm->fVlength);
assert(uval <= (uint32_t)self->cm->fVlength);
return self->cm->fValues[uval - 1];
}
else
@ -422,7 +424,7 @@ int coding::sumInUnsignedRange(int x, int y)
int range = (int)(umax + 1);
assert(range > 0);
x += y;
if (x != (int)((jlong)(x - y) + (jlong)y))
if (x != (int)((int64_t)(x - y) + (int64_t)y))
{
// 32-bit overflow interferes with range reduction.
// Back off from the overflow by adding a multiple of range:
@ -461,9 +463,9 @@ int coding::sumInUnsignedRange(int x, int y)
return x;
}
static int getDeltaValue(value_stream *self, uint uval, bool isSubrange)
static int getDeltaValue(value_stream *self, uint32_t uval, bool isSubrange)
{
assert((uint)(self->c.isSubrange) == (uint)isSubrange);
assert((uint32_t)(self->c.isSubrange) == (uint32_t)isSubrange);
assert(self->c.isSubrange | self->c.isFullRange);
if (isSubrange)
return self->sum = self->c.sumInUnsignedRange(self->sum, (int)uval);
@ -499,7 +501,7 @@ int value_stream::getInt()
}
CODING_PRIVATE(c.spec);
uint uval;
uint32_t uval;
enum
{
B5 = 5,
@ -546,19 +548,19 @@ int value_stream::getInt()
assert(D == 1);
uval = coding::parse(rp, B, H);
if (S != 0)
uval = (uint)decode_sign(S, uval);
uval = (uint32_t)decode_sign(S, uval);
return getDeltaValue(this, uval, (bool)c.isSubrange);
case cmk_BHS1D1full:
assert(S == 1 && D == 1 && c.isFullRange);
uval = coding::parse(rp, B, H);
uval = (uint)DECODE_SIGN_S1(uval);
uval = (uint32_t)DECODE_SIGN_S1(uval);
return getDeltaValue(this, uval, false);
case cmk_BHS1D1sub:
assert(S == 1 && D == 1 && c.isSubrange);
uval = coding::parse(rp, B, H);
uval = (uint)DECODE_SIGN_S1(uval);
uval = (uint32_t)DECODE_SIGN_S1(uval);
return getDeltaValue(this, uval, true);
case cmk_DELTA5:
@ -583,7 +585,7 @@ int value_stream::getInt()
uval = coding::parse(rp, B, H);
if (S != 0)
{
uval = (uint)decode_sign(S, uval);
uval = (uint32_t)decode_sign(S, uval);
}
if (D != 0)
{
@ -592,7 +594,7 @@ int value_stream::getInt()
sum = c.sumInUnsignedRange(sum, (int)uval);
else
sum += (int)uval;
uval = (uint)sum;
uval = (uint32_t)sum;
}
return getPopValue(this, uval);
@ -616,8 +618,8 @@ int value_stream::getInt()
static int moreCentral(int x, int y)
{ // used to find end of Pop.{F}
// Suggested implementation from the Pack200 specification:
uint kx = (x >> 31) ^ (x << 1);
uint ky = (y >> 31) ^ (y << 1);
uint32_t kx = (x >> 31) ^ (x << 1);
uint32_t ky = (y >> 31) ^ (y << 1);
return (kx < ky ? x : y);
}
// static maybe_inline
@ -680,7 +682,7 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
to_free = foundc; // findBySpec may dynamically allocate
if (foundc == nullptr)
{
abort("illegal arb. coding");
unpack_abort("illegal arbitrary coding");
return;
}
// and fall through
@ -699,13 +701,11 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
int N2 = (N >= 0) ? N - K : N;
if (N == 0 || (N2 <= 0 && N2 != N))
{
abort("illegal run encoding");
return;
unpack_abort("illegal run encoding");
}
if ((mode & DISABLE_RUN) != 0)
{
abort("illegal nested run encoding");
return;
unpack_abort("illegal nested run encoding");
}
// & Enc{ ACode } if ADef=0 (ABDef != 1)
@ -719,11 +719,11 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
{
this->init(band_rp, band_limit, meta_rp, disRun, defc, K, valueSink);
}
CHECK;
// & Enc{ BCode } if BDef=0 (ABDef != 2)
coding_method *tail = U_NEW(coding_method, 1);
CHECK_NULL(tail);
if (!tail)
return;
tail->u = u;
// The 'run' codings may be nested indirectly via 'pop' codings.
@ -764,13 +764,11 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
int TH = (256 - TL);
if (N <= 0)
{
abort("illegal pop encoding");
return;
unpack_abort("illegal pop encoding");
}
if ((mode & DISABLE_POP) != 0)
{
abort("illegal nested pop encoding");
return;
unpack_abort("illegal nested pop encoding");
}
// No indirect nesting of 'pop', but 'run' is OK.
@ -796,7 +794,6 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
fValues = (u->saveTo(fvbuf, fValueSink.b), (int *)fvbuf.ptr);
fVlength = fValueSink.length(); // i.e., the parameter K
fValueSink.free();
CHECK;
// Skip the first {F} run in all subsequent passes.
// The next call to this->init(...) will set vs0.rp to point after the {F}.
@ -812,12 +809,12 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
break; // found it
tcode->free();
tcode = coding::findBySpec(B, TH);
CHECK_NULL(tcode);
if (!tcode)
return;
}
if (!(fVlength <= tcode->umax))
{
abort("pop.L value too small");
return;
unpack_abort("pop.L value too small");
}
this->init(band_rp, band_limit, NO_META, disPop, tcode, N, nullptr);
tcode->free();
@ -826,7 +823,6 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
{
this->init(band_rp, band_limit, meta_rp, disPop, defc, N, nullptr);
}
CHECK;
// Count the number of zero tokens right now.
// Also verify that they are in bounds.
@ -834,13 +830,12 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
value_stream vs = vs0;
for (int i = 0; i < N; i++)
{
uint val = vs.getInt();
uint32_t val = vs.getInt();
if (val == 0)
UN += 1;
if (!(val <= (uint)fVlength))
if (!(val <= (uint32_t)fVlength))
{
abort("pop token out of range");
return;
unpack_abort("pop token out of range");
}
}
vs.done();
@ -849,7 +844,8 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
if (UN != 0)
{
uValues = U_NEW(coding_method, 1);
CHECK_NULL(uValues);
if (uValues == nullptr)
return;
uValues->u = u;
if (UDef != 0)
{
@ -867,7 +863,7 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
int uop = (*meta_rp++ & 0xFF);
if (uop > _meta_canon_max)
// %%% Spec. requires the more strict (uop != _meta_default).
abort("bad meta-coding for empty pop/U");
unpack_abort("bad meta-coding for empty pop/U");
}
}
@ -901,8 +897,7 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
}
else
{
abort("bad meta-coding");
return;
unpack_abort("bad meta-coding");
}
// Common code here skips a series of values with one coding.
@ -926,7 +921,7 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
coding &c = vs0.c;
CODING_PRIVATE(c.spec);
// assert sane N
assert((uint)N < INT_MAX_VALUE || N == POP_FAVORED_N);
assert((uint32_t)N < INT_MAX_VALUE || N == POP_FAVORED_N);
// Look at the values, or at least skip over them quickly.
if (valueSink == nullptr)
@ -970,14 +965,12 @@ void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int m
if (valueSink->length() > 0 && (val == last || val == min)) //|| val == min2
break;
valueSink->add(val);
CHECK;
last = val;
min = moreCentral(min, last);
// min2 = moreCentral2(min2, last, min);
}
band_rp = vs.rp;
}
CHECK;
// Get an accurate upper limit now.
vs0.rplimit = band_rp;

View File

@ -84,11 +84,11 @@ struct coding
static coding *findBySpec(int B, int H, int S = 0, int D = 0);
static coding *findByIndex(int irregularCodingIndex);
static uint parse(byte *&rp, int B, int H);
static uint parse_lgH(byte *&rp, int B, int H, int lgH);
static uint32_t parse(byte *&rp, int B, int H);
static uint32_t parse_lgH(byte *&rp, int B, int H, int lgH);
static void parseMultiple(byte *&rp, int N, byte *limit, int B, int H);
uint parse(byte *&rp)
uint32_t parse(byte *&rp)
{
return parse(rp, CODING_B(spec), CODING_H(spec));
}
@ -116,12 +116,6 @@ struct coding
}
void free(); // free self if isMalloc
// error handling
static void abort(const char *msg = nullptr)
{
unpack_abort(msg);
}
};
enum coding_method_kind
@ -224,10 +218,6 @@ struct value_stream
return this + 1;
}
bool hasHelper();
// error handling
// inline void abort(const char* msg);
// inline void aborting();
};
struct coding_method
@ -254,17 +244,4 @@ struct coding_method
// The value sink is used to collect output values, when desired.
void init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int mode, coding *defc, int N,
intlist *valueSink);
// error handling
void abort(const char *msg)
{
unpack_abort(msg, u);
}
bool aborting()
{
return unpack_aborting(u);
}
};
// inline void value_stream::abort(const char* msg) { cm->abort(msg); }
// inline void value_stream::aborting() { cm->aborting(); }

View File

@ -51,7 +51,7 @@
// magic number for gzip streams (for processing pack200-gzip data)
#define GZIP_MAGIC 0x1F8B0800
#define GZIP_MAGIC_MASK 0xFFFFFF00 // last byte is variable "flg" field
#define GZIP_MAGIC_MASK 0xFFFFFF00 // last \bchar\b is variable "flg" field
enum
{

View File

@ -32,39 +32,22 @@
#include <unistd.h>
#endif
#ifndef FULL
#define FULL 1 /* Adds <500 bytes to the zipped final product. */
#endif
#if FULL // define this if you want debugging and/or compile-time attributes
#define IF_FULL(x) x
#else
#define IF_FULL(x) /*x*/
#endif
// Error messages that we have
#define ERROR_ENOMEM "Native allocation failed"
#define ERROR_ENOMEM "Memory allocation failed"
#define ERROR_FORMAT "Corrupted pack file"
#define ERROR_RESOURCE "Cannot extract resource file"
#define ERROR_OVERFLOW "Internal buffer overflow"
#define ERROR_INTERNAL "Internal error"
#define LOGFILE_STDOUT "-"
#define LOGFILE_STDERR ""
#define lengthof(array) (sizeof(array) / sizeof(array[0]))
#define NEW(T, n) (T *) must_malloc((int)(scale_size(n, sizeof(T))))
#define U_NEW(T, n) (T *) u->alloc(scale_size(n, sizeof(T)))
#define T_NEW(T, n) (T *) u->temp_alloc(scale_size(n, sizeof(T)))
// bytes and byte arrays
typedef unsigned int uint;
typedef signed char byte;
#ifdef _MSC_VER
typedef LONGLONG jlong;
typedef DWORDLONG julong;
#define MKDIR(dir) mkdir(dir)
#define getpid() _getpid()
#define PATH_MAX MAX_PATH
@ -73,64 +56,10 @@ typedef DWORDLONG julong;
#define tempname _tempname
#define sleep Sleep
#else
typedef signed char byte;
#ifdef _LP64
typedef long jlong;
typedef long unsigned julong;
#else
typedef long long jlong;
typedef long long unsigned julong;
#endif
#define MKDIR(dir) mkdir(dir, 0777);
#endif
/* Must cast to void *, then size_t, then int. */
#define ptrlowbits(x) ((int)(size_t)(void *)(x))
/* Back and forth from jlong to pointer */
#define ptr2jlong(x) ((jlong)(size_t)(void *)(x))
#define jlong2ptr(x) ((void *)(size_t)(x))
// Keys used by Java:
#define UNPACK_DEFLATE_HINT "unpack.deflate.hint"
#define COM_PREFIX "com.sun.java.util.jar.pack."
#define UNPACK_MODIFICATION_TIME COM_PREFIX "unpack.modification.time"
#define DEBUG_VERBOSE COM_PREFIX "verbose"
#define ZIP_ARCHIVE_MARKER_COMMENT "PACK200"
// The following are not known to the Java classes:
#define UNPACK_REMOVE_PACKFILE COM_PREFIX "unpack.remove.packfile"
// Called from unpacker layers
#define _CHECK_DO(t, x) \
{ \
if (t) \
{ \
x; \
} \
}
#define CHECK _CHECK_DO(aborting(), return)
#define CHECK_(y) _CHECK_DO(aborting(), return y)
#define CHECK_0 _CHECK_DO(aborting(), return 0)
#define CHECK_NULL(p) _CHECK_DO((p) == nullptr, return)
#define CHECK_NULL_(y, p) _CHECK_DO((p) == nullptr, return y)
#define CHECK_NULL_0(p) _CHECK_DO((p) == nullptr, return 0)
#define CHECK_COUNT(t) \
if (t < 0) \
{ \
abort("bad value count"); \
} \
CHECK
#define STR_TRUE "true"
#define STR_FALSE "false"
#define STR_TF(x) ((x) ? STR_TRUE : STR_FALSE)
#define BOOL_TF(x) (((x) != nullptr &&strcmp((x), STR_TRUE) == 0) ? true : false)
#define DEFAULT_ARCHIVE_MODTIME 1060000000 // Aug 04, 2003 5:26 PM PDT

View File

@ -1,489 +0,0 @@
/*
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <assert.h>
#include <limits.h>
#include <time.h>
#include "defines.h"
#include "bytes.h"
#include "utils.h"
#include "coding.h"
#include "bands.h"
#include "constants.h"
#include "zip.h"
#include "unpack.h"
int main(int argc, char **argv)
{
return unpacker::run(argc, argv);
}
unpacker *unpacker::non_mt_current = nullptr;
unpacker *unpacker::current()
{
return non_mt_current;
}
static void set_current_unpacker(unpacker *u)
{
unpacker::non_mt_current = u;
}
// Callback for fetching data, Unix style.
static jlong read_input_via_stdio(unpacker *u, void *buf, jlong minlen, jlong maxlen)
{
assert(minlen <= maxlen); // don't talk nonsense
jlong numread = 0;
char *bufptr = (char *)buf;
while (numread < minlen)
{
// read available input, up to buf.length or maxlen
int readlen = (1 << 16);
if (readlen > (maxlen - numread))
readlen = (int)(maxlen - numread);
int nr = 0;
if (u->infileptr != nullptr)
{
nr = (int)fread(bufptr, 1, readlen, u->infileptr);
}
else
{
#ifndef WIN32
// we prefer unbuffered inputs
nr = (int)read(u->infileno, bufptr, readlen);
#else
nr = (int)fread(bufptr, 1, readlen, stdin);
#endif
}
if (nr <= 0)
{
if (errno != EINTR)
break;
nr = 0;
}
numread += nr;
bufptr += nr;
assert(numread <= maxlen);
}
// fprintf(u->errstrm, "readInputFn(%d,%d) => %d\n",
// (int)minlen, (int)maxlen, (int)numread);
return numread;
}
enum
{
EOF_MAGIC = 0,
BAD_MAGIC = -1
};
static int read_magic(unpacker *u, char peek[], int peeklen)
{
assert(peeklen == 4); // magic numbers are always 4 bytes
jlong nr = (u->read_input_fn)(u, peek, peeklen, peeklen);
if (nr != peeklen)
{
return (nr == 0) ? EOF_MAGIC : BAD_MAGIC;
}
int magic = 0;
for (int i = 0; i < peeklen; i++)
{
magic <<= 8;
magic += peek[i] & 0xFF;
}
return magic;
}
static void setup_gzin(unpacker *u)
{
gunzip *gzin = NEW(gunzip, 1);
gzin->init(u);
}
static const char *nbasename(const char *progname)
{
const char *slash = strrchr(progname, '/');
if (slash != nullptr)
progname = ++slash;
return progname;
}
static const char *usage_lines[] = {
"Usage: %s [-opt... | --option=value]... x.pack[.gz] y.jar\n", "\n", "Unpacking Options\n",
" -H{h}, --deflate-hint={h} override transmitted deflate hint: true, false, or keep "
"(default)\n",
" -r, --remove-pack-file remove input file after unpacking\n",
" -v, --verbose increase program verbosity\n",
" -q, --quiet set verbosity to lowest level\n",
" -l{F}, --log-file={F} output to the given log file, or '-' for standard output "
"(default)\n",
" -?, -h, --help print this message\n",
" -J{X} Java VM argument (ignored)\n", nullptr};
static void usage(unpacker *u, const char *progname, bool full = false)
{
// WinMain does not set argv[0] to the progrname
progname = (progname != nullptr) ? nbasename(progname) : "unpack200";
for (int i = 0; usage_lines[i] != nullptr; i++)
{
fprintf(stderr, usage_lines[i], progname);
if (!full)
{
fprintf(stderr, "(For more information, run %s --help .)\n", progname);
break;
}
}
}
// argument parsing
static char **init_args(int argc, char **argv, int &envargc)
{
const char *env = getenv("UNPACK200_FLAGS");
ptrlist envargs;
envargs.init();
if (env != nullptr)
{
char *buf = (char *)strdup(env);
const char *delim = "\n\t ";
for (char *p = strtok(buf, delim); p != nullptr; p = strtok(nullptr, delim))
{
envargs.add(p);
}
}
// allocate extra margin at both head and tail
char **argp = NEW(char *, envargs.length() + argc + 1);
char **argp0 = argp;
int i;
for (i = 0; i < envargs.length(); i++)
{
*argp++ = (char *)envargs.get(i);
}
for (i = 1; i < argc; i++)
{
// note: skip argv[0] (program name)
*argp++ = (char *)strdup(argv[i]); // make a scratch copy
}
*argp = nullptr; // sentinel
envargc = envargs.length(); // report this count to next_arg
envargs.free();
return argp0;
}
static int strpcmp(const char *str, const char *pfx)
{
return strncmp(str, pfx, strlen(pfx));
}
static const char flag_opts[] = "vqrVh?";
static const char string_opts[] = "HlJ";
static int next_arg(char **&argp)
{
char *arg = *argp;
if (arg == nullptr || arg[0] != '-')
{ // end of option list
return 0;
}
// printf("opt: %s\n", arg);
char ach = arg[1];
if (ach == '\0')
{
// ++argp; // do not pop this arg
return 0; // bare "-" is stdin/stdout
}
else if (arg[1] == '-')
{ // --foo option
static const char *keys[] = {"Hdeflate-hint=", "vverbose", "qquiet",
"rremove-pack-file", "llog-file=", "Vversion",
"hhelp", nullptr};
if (arg[2] == '\0')
{ // end of option list
++argp; // pop the "--"
return 0;
}
for (int i = 0; keys[i] != nullptr; i++)
{
const char *key = keys[i];
char kch = *key++;
if (strchr(key, '=') == nullptr)
{
if (!strcmp(arg + 2, key))
{
++argp; // pop option arg
return kch;
}
}
else
{
if (!strpcmp(arg + 2, key))
{
*argp += 2 + strlen(key); // remove "--"+key from arg
return kch;
}
}
}
}
else if (strchr(flag_opts, ach) != nullptr)
{ // plain option
if (arg[2] == '\0')
{
++argp;
}
else
{
// in-place edit of "-vxyz" to "-xyz"
arg += 1; // skip original '-'
arg[0] = '-';
*argp = arg;
}
// printf(" key => %c\n", ach);
return ach;
}
else if (strchr(string_opts, ach) != nullptr)
{ // argument-bearing option
if (arg[2] == '\0')
{
if (argp[1] == nullptr)
return -1; // no next arg
++argp; // leave the argument in place
}
else
{
// in-place edit of "-Hxyz" to "xyz"
arg += 2; // skip original '-H'
*argp = arg;
}
// printf(" key => %c\n", ach);
return ach;
}
return -1; // bad argument
}
static const char sccsver[] = "1.30, 07/05/05";
// Usage: unpackage input.pack output.jar
int unpacker::run(int argc, char **argv)
{
unpacker u;
u.init(read_input_via_stdio);
set_current_unpacker(&u);
jar jarout;
jarout.init(&u);
int envargc = 0;
char **argbuf = init_args(argc, argv, envargc);
char **arg0 = argbuf + envargc;
char **argp = argbuf;
int verbose = 0;
char *logfile = nullptr;
for (;;)
{
const char *arg = (*argp == nullptr) ? "" : u.saveStr(*argp);
bool isenvarg = (argp < arg0);
int ach = next_arg(argp);
bool hasoptarg = (ach != 0 && strchr(string_opts, ach) != nullptr);
if (ach == 0 && argp >= arg0)
break;
if (isenvarg && argp == arg0 && hasoptarg)
ach = 0; // don't pull from cmdline
switch (ach)
{
case 'H':
u.set_option(UNPACK_DEFLATE_HINT, *argp++);
break;
case 'v':
++verbose;
break;
case 'q':
verbose = 0;
break;
case 'r':
u.set_option(UNPACK_REMOVE_PACKFILE, "1");
break;
case 'l':
logfile = *argp++;
break;
case 'J':
argp += 1;
break; // skip ignored -Jxxx parameter
case 'h':
case '?':
usage(&u, argv[0], true);
exit(1);
default:
const char *inenv = isenvarg ? " in ${UNPACK200_FLAGS}" : "";
if (hasoptarg)
fprintf(stderr, "Missing option string%s: %s\n", inenv, arg);
else
fprintf(stderr, "Unrecognized argument%s: %s\n", inenv, arg);
usage(&u, argv[0]);
exit(2);
}
}
if (verbose != 0)
{
u.set_option(DEBUG_VERBOSE, u.saveIntStr(verbose));
}
const char *source_file = *argp++;
const char *destination_file = *argp++;
if (source_file == nullptr || destination_file == nullptr || *argp != nullptr)
{
usage(&u, argv[0]);
exit(2);
}
if (verbose != 0)
{
fprintf(stderr, "Unpacking from %s to %s\n", source_file, destination_file);
}
bool &remove_source = u.remove_packfile;
if (strcmp(source_file, "-") == 0)
{
remove_source = false;
u.infileno = fileno(stdin);
}
else
{
u.infileptr = fopen(source_file, "rb");
if (u.infileptr == nullptr)
{
fprintf(stderr, "Error: Could not open input file: %s\n", source_file);
exit(3); // Called only from the native standalone unpacker
}
}
if (strcmp(destination_file, "-") == 0)
{
jarout.jarfp = stdout;
}
else
{
jarout.openJarFile(destination_file);
assert(jarout.jarfp != nullptr);
}
if (verbose != 0)
u.dump_options();
char peek[4];
int magic;
// check for GZIP input
magic = read_magic(&u, peek, (int)sizeof(peek));
if ((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC)
{
// Oops; must slap an input filter on this data.
setup_gzin(&u);
u.gzin->start(magic);
if (!u.aborting())
{
u.start();
}
}
else
{
u.start(peek, sizeof(peek));
}
// Note: The checks to u.aborting() are necessary to gracefully
// terminate processing when the first segment throws an error.
for (;;)
{
if (u.aborting())
break;
// Each trip through this loop unpacks one segment
// and then resets the unpacker.
for (unpacker::file *filep; (filep = u.get_next_file()) != nullptr;)
{
if (u.aborting())
break;
u.write_file_to_jar(filep);
}
if (u.aborting())
break;
// Peek ahead for more data.
magic = read_magic(&u, peek, (int)sizeof(peek));
if (magic != (int)JAVA_PACKAGE_MAGIC)
{
if (magic != EOF_MAGIC)
u.abort("garbage after end of pack archive");
break; // all done
}
// Release all storage from parsing the old segment.
u.reset();
// Restart, beginning with the peek-ahead.
u.start(peek, sizeof(peek));
}
int status = 0;
if (u.aborting())
{
fprintf(stderr, "Error: %s\n", u.get_abort_message());
status = 1;
}
if (u.infileptr != nullptr)
{
fclose(u.infileptr);
u.infileptr = nullptr;
}
if (!u.aborting() && remove_source)
remove(source_file);
if (verbose != 0)
{
fprintf(stderr, "unpacker completed with status=%d\n", status);
}
u.finish();
u.free(); // tidy up malloc blocks
set_current_unpacker(nullptr); // clean up global pointer
return status;
}

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@
struct jar;
struct gunzip;
struct band;
struct cpool;
struct constant_pool;
struct entry;
struct cpindex;
struct inner_class;
@ -35,7 +35,7 @@ struct value_stream;
struct cpindex
{
uint len;
uint32_t len;
entry *base1; // base of primary index
entry **base2; // base of secondary index
byte ixTag; // type of entries (!= CONSTANT_None), plus 64 if sub-index
@ -44,7 +44,7 @@ struct cpindex
SUB_TAG = 64
};
entry *get(uint i);
entry *get(uint32_t i);
void init(int len_, entry *base1_, int ixTag_)
{
@ -62,12 +62,12 @@ struct cpindex
}
};
struct cpool
struct constant_pool
{
uint nentries;
uint32_t nentries;
entry *entries;
entry *first_extra_entry;
uint maxentries; // total allocated size of entries
uint32_t maxentries; // total allocated size of entries
// Position and size of each homogeneous subrange:
int tag_count[CONSTANT_Limit];
@ -89,7 +89,7 @@ struct cpool
ptrlist outputEntries; // list of entry* needing output idx assigned
entry **hashTab;
uint hashTabLength;
uint32_t hashTabLength;
entry *&hashTabRef(byte tag, bytes &b);
entry *ensureUtf8(bytes &b);
entry *ensureClass(bytes &b);
@ -117,12 +117,12 @@ struct cpool
int getCount(byte tag)
{
assert((uint)tag < CONSTANT_Limit);
assert((uint32_t)tag < CONSTANT_Limit);
return tag_count[tag];
}
cpindex *getIndex(byte tag)
{
assert((uint)tag < CONSTANT_Limit);
assert((uint32_t)tag < CONSTANT_Limit);
return &tag_index[tag];
}
cpindex *getKQIndex(); // uses cur_descr
@ -133,10 +133,6 @@ struct cpool
void computeOutputOrder();
void computeOutputIndexes();
void resetOutputIndexes();
// error handling
inline void abort(const char *msg);
inline bool aborting();
};
/*
@ -149,7 +145,7 @@ struct unpacker
struct file
{
const char *name;
julong size;
uint64_t size;
int modtime;
int options;
bytes data[2];
@ -161,12 +157,8 @@ struct unpacker
}
};
// global pointer to self, if not running under JNI (not multi-thread safe)
static unpacker *non_mt_current;
// if running Unix-style, here are the inputs and outputs
FILE *infileptr; // buffered
int infileno; // unbuffered
bytes inbytes; // direct
gunzip *gzin; // gunzip filter, if any
jar *jarout; // output JAR file
@ -174,8 +166,6 @@ struct unpacker
// pointer to self, for U_NEW macro
unpacker *u;
// private abort message string, allocated to PATH_MAX*2
const char *abort_message;
ptrlist mallocs; // list of guys to free when we are all done
ptrlist tmallocs; // list of guys to free on next client request
fillbytes smallbuf; // supplies small alloc requests
@ -183,10 +173,6 @@ struct unpacker
// option management members
int verbose; // verbose level, 0 means no output
bool strip_compile;
bool strip_debug;
bool strip_jcov;
bool remove_packfile;
int deflate_hint_or_zero; // ==0 means not set, otherwise -1 or 1
int modification_time_or_zero;
@ -196,11 +182,12 @@ struct unpacker
bool free_input; // must the input buffer be freed?
byte *rp; // read pointer (< rplimit <= input.limit())
byte *rplimit; // how much of the input block has been read?
julong bytes_read;
uint64_t bytes_read;
int unsized_bytes_read;
// callback to read at least one byte, up to available input
typedef jlong (*read_input_fn_t)(unpacker *self, void *buf, jlong minlen, jlong maxlen);
typedef int64_t (*read_input_fn_t)(unpacker *self, void *buf, int64_t minlen,
int64_t maxlen);
read_input_fn_t read_input_fn;
// archive header fields
@ -218,7 +205,7 @@ struct unpacker
// engine state
band *all_bands; // indexed by band_number
byte *meta_rp; // read-pointer into (copy of) band_headers
cpool cp; // all constant pool information
constant_pool cp; // all constant pool information
inner_class *ics; // InnerClasses
// output stream
@ -239,7 +226,7 @@ struct unpacker
fillbytes cur_classfile_tail;
int files_written; // also tells which file we're working on
int classes_written; // also tells which class we're working on
julong bytes_written;
uint64_t bytes_written;
intlist bcimap;
fillbytes class_fixup_type;
intlist class_fixup_offset;
@ -250,8 +237,8 @@ struct unpacker
ptrlist requested_ics; // which ics need output?
// stats pertaining to multiple segments (updated on reset)
julong bytes_read_before_reset;
julong bytes_written_before_reset;
uint64_t bytes_read_before_reset;
uint64_t bytes_written_before_reset;
int files_written_before_reset;
int classes_written_before_reset;
int segments_read_before_reset;
@ -259,7 +246,7 @@ struct unpacker
// attribute state
struct layout_definition
{
uint idx; // index (0..31...) which identifies this layout
uint32_t idx; // index (0..31...) which identifies this layout
const char *name; // name of layout
entry *nameEntry;
const char *layout; // string of layout (not yet parsed)
@ -280,9 +267,9 @@ struct unpacker
unpacker *u; // pointer to self, for U_NEW macro
int xxx_flags_hi_bn; // locator for flags, count, indexes, calls bands
int attrc; // ATTR_CONTEXT_CLASS, etc.
uint flag_limit; // 32 or 63, depending on archive_options bit
julong predef; // mask of built-in definitions
julong redef; // mask of local flag definitions or redefinitions
uint32_t flag_limit; // 32 or 63, depending on archive_options bit
uint64_t predef; // mask of built-in definitions
uint64_t redef; // mask of local flag definitions or redefinitions
ptrlist layouts; // local (compressor-defined) defs, in index order
int flag_count[X_ATTR_LIMIT_FLAGS_HI];
intlist overflow_count;
@ -322,11 +309,11 @@ struct unpacker
// Read data into the bands of the idx-th layout.
void readBandData(int idx); // parse layout, make bands, read data
void readBandData(band **body, uint count); // recursive helper
void readBandData(band **body, uint32_t count); // recursive helper
layout_definition *getLayout(uint idx)
layout_definition *getLayout(uint32_t idx)
{
if (idx >= (uint)layouts.length())
if (idx >= (uint32_t)layouts.length())
return nullptr;
return (layout_definition *)layouts.get(idx);
}
@ -344,33 +331,33 @@ struct unpacker
}
// Return flag_count if idx is predef and not redef, else zero.
int predefCount(uint idx);
int predefCount(uint32_t idx);
bool isRedefined(uint idx)
bool isRedefined(uint32_t idx)
{
if (idx >= flag_limit)
return false;
return (bool)((redef >> idx) & 1);
}
bool isPredefined(uint idx)
bool isPredefined(uint32_t idx)
{
if (idx >= flag_limit)
return false;
return (bool)(((predef & ~redef) >> idx) & 1);
}
julong flagIndexMask()
uint64_t flagIndexMask()
{
return (predef | redef);
}
bool isIndex(uint idx)
bool isIndex(uint32_t idx)
{
assert(flag_limit != 0); // must be set up already
if (idx < flag_limit)
return (bool)(((predef | redef) >> idx) & 1);
else
return (idx - flag_limit < (uint)overflow_count.length());
return (idx - flag_limit < (uint32_t)overflow_count.length());
}
int &getCount(uint idx)
int &getCount(uint32_t idx)
{
assert(isIndex(idx));
if (idx < flag_limit)
@ -378,14 +365,6 @@ struct unpacker
else
return overflow_count.get(idx - flag_limit);
}
bool aborting()
{
return u->aborting();
}
void abort(const char *msg)
{
u->abort(msg);
}
};
attr_definitions attr_defs[ATTR_CONTEXT_LIMIT];
@ -407,10 +386,8 @@ struct unpacker
bool set_option(const char *option, const char *value);
const char *get_option(const char *option);
void dump_options();
// Fetching input.
bool ensure_input(jlong more);
bool ensure_input(int64_t more);
byte *input_scan()
{
return rp;
@ -473,12 +450,6 @@ struct unpacker
sprintf(buf, "%d", num);
return saveStr(buf);
}
const char *get_abort_message();
void abort(const char *s = nullptr);
bool aborting()
{
return abort_message != nullptr;
}
static unpacker *current(); // find current instance
// Output management
@ -514,7 +485,7 @@ struct unpacker
}
void putu2(int n); // { putu2_at(put_space(2), n); }
void putu4(int n); // { putu4_at(put_space(4), n); }
void putu8(jlong n); // { putu8_at(put_space(8), n); }
void putu8(int64_t n); // { putu8_at(put_space(8), n); }
void putref(entry *e); // { putu2_at(put_space(2), putref_index(e, 2)); }
void putu1ref(entry *e); // { putu1_at(put_space(1), putref_index(e, 1)); }
int putref_index(entry *e, int size); // size in [1..2]
@ -530,7 +501,7 @@ struct unpacker
{
return wpbase + offset;
}
uint to_bci(uint bii);
uint32_t to_bci(uint32_t bii);
void get_code_header(int &max_stack, int &max_na_locals, int &handler_count, int &cflags);
band *ref_band_for_self_op(int bc, bool &isAloadVar, int &origBCVar);
band *ref_band_for_op(int bc);
@ -543,7 +514,7 @@ struct unpacker
}
static void putu2_at(byte *wp, int n);
static void putu4_at(byte *wp, int n);
static void putu8_at(byte *wp, jlong n);
static void putu8_at(byte *wp, int64_t n);
// Private stuff
void reset_cur_classfile();
@ -552,7 +523,7 @@ struct unpacker
void write_code();
void write_bc_ops();
void write_members(int num, int attrc); // attrc=ATTR_CONTEXT_FIELD/METHOD
int write_attrs(int attrc, julong indexBits);
int write_attrs(int attrc, uint64_t indexBits);
// The readers
void read_bands();
@ -574,12 +545,3 @@ struct unpacker
void read_double_refs(band &cp_band, byte ref1Tag, byte ref2Tag, entry *cpMap, int len);
void read_signature_values(entry *cpMap, int len);
};
inline void cpool::abort(const char *msg)
{
u->abort(msg);
}
inline bool cpool::aborting()
{
return u->aborting();
}

View File

@ -0,0 +1,175 @@
/*
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <assert.h>
#include <limits.h>
#include <time.h>
#include <stdint.h>
#include "constants.h"
#include "utils.h"
#include "defines.h"
#include "bytes.h"
#include "coding.h"
#include "unpack200.h"
#include "unpack.h"
#include "zip.h"
// Callback for fetching data, Unix style.
static int64_t read_input_via_stdio(unpacker *u, void *buf, int64_t minlen, int64_t maxlen)
{
assert(u->infileptr != nullptr);
assert(minlen <= maxlen); // don't talk nonsense
int64_t numread = 0;
char *bufptr = (char *)buf;
while (numread < minlen)
{
// read available input, up to buf.length or maxlen
int readlen = (1 << 16);
if (readlen > (maxlen - numread))
readlen = (int)(maxlen - numread);
int nr = 0;
nr = (int)fread(bufptr, 1, readlen, u->infileptr);
if (nr <= 0)
{
if (errno != EINTR)
break;
nr = 0;
}
numread += nr;
bufptr += nr;
assert(numread <= maxlen);
}
return numread;
}
enum
{
EOF_MAGIC = 0,
BAD_MAGIC = -1
};
static int read_magic(unpacker *u, char peek[], int peeklen)
{
assert(peeklen == 4); // magic numbers are always 4 bytes
int64_t nr = (u->read_input_fn)(u, peek, peeklen, peeklen);
if (nr != peeklen)
{
return (nr == 0) ? EOF_MAGIC : BAD_MAGIC;
}
int magic = 0;
for (int i = 0; i < peeklen; i++)
{
magic <<= 8;
magic += peek[i] & 0xFF;
}
return magic;
}
void unpack_200(std::string input_path, std::string output_path)
{
unpacker u;
int status = 0;
FILE *input = fopen(input_path.c_str(), "rb");
if (!input)
{
throw std::runtime_error("Can't open input file" + input_path);
}
FILE *output = fopen(output_path.c_str(), "wb");
if (!output)
{
fclose(output);
throw std::runtime_error("Can't open output file" + output_path);
}
u.init(read_input_via_stdio);
// initialize jar output
// the output takes ownership of the file handle
jar jarout;
jarout.init(&u);
jarout.jarfp = output;
// the input doesn't
u.infileptr = input;
// read the magic!
char peek[4];
int magic;
magic = read_magic(&u, peek, (int)sizeof(peek));
// if it is a gzip encoded file, we need an extra gzip input filter
if ((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC)
{
gunzip *gzin = NEW(gunzip, 1);
gzin->init(&u);
// FIXME: why the side effects? WHY?
u.gzin->start(magic);
u.start();
}
else
{
// otherwise, feed the bytes to the unpacker directly
u.start(peek, sizeof(peek));
}
// Note: The checks to u.aborting() are necessary to gracefully
// terminate processing when the first segment throws an error.
for (;;)
{
// Each trip through this loop unpacks one segment
// and then resets the unpacker.
for (unpacker::file *filep; (filep = u.get_next_file()) != nullptr;)
{
u.write_file_to_jar(filep);
}
// Peek ahead for more data.
magic = read_magic(&u, peek, (int)sizeof(peek));
if (magic != (int)JAVA_PACKAGE_MAGIC)
{
// we do not feel strongly about this kind of thing...
/*
if (magic != EOF_MAGIC)
unpack_abort("garbage after end of pack archive");
*/
break; // all done
}
// Release all storage from parsing the old segment.
u.reset();
// Restart, beginning with the peek-ahead.
u.start(peek, sizeof(peek));
}
u.finish();
u.free(); // tidy up malloc blocks
fclose(input);
}

View File

@ -29,6 +29,7 @@
#include <string.h>
#include <limits.h>
#include <assert.h>
#include <stdint.h>
#include <sys/stat.h>
@ -57,35 +58,14 @@ void *must_malloc(size_t size)
}
else
{
unpack_abort(ERROR_ENOMEM);
throw std::runtime_error(ERROR_ENOMEM);
}
return ptr;
}
void unpack_abort(const char *msg, unpacker *u)
void unpack_abort(const char *msg)
{
if (msg == nullptr)
msg = "corrupt pack file or internal error";
if (u == nullptr)
u = unpacker::current();
if (u == nullptr)
{
fprintf(stderr, "Error: unpacker: %s\n", msg);
::abort();
return;
}
u->abort(msg);
}
bool unpack_aborting(unpacker *u)
{
if (u == nullptr)
u = unpacker::current();
if (u == nullptr)
{
fprintf(stderr, "Error: unpacker: no current instance\n");
::abort();
return true;
}
return u->aborting();
throw std::runtime_error(msg);
}

View File

@ -25,6 +25,8 @@
// Definitions of our util functions
#include <stdexcept>
void *must_malloc(size_t size);
// overflow management
@ -46,9 +48,6 @@ inline size_t add_size(size_t size1, size_t size2, int size3)
return add_size(add_size(size1, size2), size3);
}
// These may be expensive, because they have to go via Java TSD,
// if the optional u argument is missing.
struct unpacker;
extern void unpack_abort(const char *msg, unpacker *u = nullptr);
extern bool unpack_aborting(unpacker *u = nullptr);
/// This throws an exception!
extern void unpack_abort(const char *msg = nullptr);

View File

@ -30,6 +30,7 @@
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
@ -47,29 +48,14 @@
#include "zip.h"
#ifdef NO_ZLIB
#include "zlib.h"
inline bool jar::deflate_bytes(bytes &head, bytes &tail)
{
return false;
}
inline uint jar::get_crc32(uint c, uchar *ptr, uint len)
{
return 0;
}
#define Z_NULL NULL
#else // Have ZLIB
#include <zlib.h>
inline uint jar::get_crc32(uint c, uchar *ptr, uint len)
inline uint32_t jar::get_crc32(uint32_t c, uchar *ptr, uint32_t len)
{
return crc32(c, ptr, len);
}
#endif // End of ZLIB
// FIXME: this is bullshit. Do real endianness detection.
#ifdef sparc
#define SWAP_BYTES(a) ((((a) << 8) & 0xff00) | 0x00ff) & (((a) >> 8) | 0xff00)
#else
@ -107,7 +93,7 @@ void jar::write_data(void *buff, int len)
void jar::add_to_jar_directory(const char *fname, bool store, int modtime, int len, int clen,
uint32_t crc)
{
uint fname_length = (uint)strlen(fname);
uint32_t fname_length = (uint32_t)strlen(fname);
ushort header[23];
if (modtime == 0)
modtime = default_modtime;
@ -169,9 +155,9 @@ void jar::add_to_jar_directory(const char *fname, bool store, int modtime, int l
}
void jar::write_jar_header(const char *fname, bool store, int modtime, int len, int clen,
uint crc)
uint32_t crc)
{
uint fname_length = (uint)strlen(fname);
uint32_t fname_length = (uint32_t)strlen(fname);
ushort header[15];
if (modtime == 0)
modtime = default_modtime;
@ -218,12 +204,10 @@ void jar::write_jar_header(const char *fname, bool store, int modtime, int len,
write_data((char *)fname, (int)fname_length);
}
static const char marker_comment[] = ZIP_ARCHIVE_MARKER_COMMENT;
void jar::write_central_directory()
{
bytes mc;
mc.set(marker_comment);
mc.set("PACK200");
ushort header[11];
@ -278,11 +262,11 @@ void jar::addJarEntry(const char *fname, bool deflate_hint, int modtime, bytes &
int len = (int)(head.len + tail.len);
int clen = 0;
uint crc = get_crc32(0, Z_NULL, 0);
uint32_t crc = get_crc32(0, Z_NULL, 0);
if (head.len != 0)
crc = get_crc32(crc, (uchar *)head.ptr, (uint)head.len);
crc = get_crc32(crc, (uchar *)head.ptr, (uint32_t)head.len);
if (tail.len != 0)
crc = get_crc32(crc, (uchar *)tail.ptr, (uint)tail.len);
crc = get_crc32(crc, (uchar *)tail.ptr, (uint32_t)tail.len);
bool deflate = (deflate_hint && len > 0);
@ -340,12 +324,13 @@ inline uint32_t jar::dostime(int y, int n, int d, int h, int m, int s)
: (((uint32_t)y - 1980) << 25) | ((uint32_t)n << 21) | ((uint32_t)d << 16) |
((uint32_t)h << 11) | ((uint32_t)m << 5) | ((uint32_t)s >> 1);
}
/*
#ifdef _REENTRANT // solaris
extern "C" struct tm *gmtime_r(const time_t *, struct tm *);
#else
#define gmtime_r(t, s) gmtime(t)
#endif
*/
/*
* Return the Unix time in DOS format
*/
@ -452,10 +437,10 @@ bool jar::deflate_bytes(bytes &head, bytes &tail)
}
// Callback for fetching data from a GZIP input stream
static jlong read_input_via_gzip(unpacker *u, void *buf, jlong minlen, jlong maxlen)
static int64_t read_input_via_gzip(unpacker *u, void *buf, int64_t minlen, int64_t maxlen)
{
assert(minlen <= maxlen); // don't talk nonsense
jlong numread = 0;
int64_t numread = 0;
char *bufptr = (char *)buf;
char *inbuf = u->gzin->inbuf;
size_t inbuflen = sizeof(u->gzin->inbuf);
@ -476,7 +461,7 @@ static jlong read_input_via_gzip(unpacker *u, void *buf, jlong minlen, jlong max
int error = inflate(&zs, Z_NO_FLUSH);
if (error != Z_OK && error != Z_STREAM_END)
{
u->abort("error inflating input");
unpack_abort("error inflating input");
break;
}
int nr = readlen - zs.avail_out;
@ -505,7 +490,7 @@ static jlong read_input_via_gzip(unpacker *u, void *buf, jlong minlen, jlong max
// %%% should check final CRC and length here
// %%% should check for concatenated *.gz files here
if (zs.avail_in > 0)
u->abort("garbage after end of deflated input stream");
unpack_abort("garbage after end of deflated input stream");
// pop this filter off:
u->gzin->free();
break;
@ -577,15 +562,11 @@ void gunzip::start(int magic)
if (gz_flg & FHCRC)
read_fixed_field(gz_hcrc, sizeof(gz_hcrc));
if (aborting())
return;
// now the input stream is ready to read into the inflater
int error = inflateInit2((z_stream *)zstream, -MAX_WBITS);
if (error != Z_OK)
{
abort("cannot create input");
return;
unpack_abort("cannot create input");
}
}
@ -602,9 +583,7 @@ void gunzip::free()
void gunzip::read_fixed_field(char *buf, size_t buflen)
{
if (aborting())
return;
jlong nr = ((unpacker::read_input_fn_t)read_input_fn)(u, buf, buflen, buflen);
int64_t nr = ((unpacker::read_input_fn_t)read_input_fn)(u, buf, buflen, buflen);
if ((size_t)nr != buflen)
u->abort("short stream header");
unpack_abort("short stream header");
}

View File

@ -24,7 +24,7 @@
*/
#include <stdint.h>
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned int uint32_t;
typedef unsigned char uchar;
struct unpacker;
@ -42,7 +42,7 @@ struct jar
// Private members
fillbytes central_directory;
ushort central_directory_count;
uint output_file_offset;
uint32_t output_file_offset;
fillbytes deflated; // temporary buffer
// pointer to outer unpacker, for error checks etc.
@ -85,17 +85,7 @@ struct jar
// The definitions of these depend on the NO_ZLIB option:
bool deflate_bytes(bytes &head, bytes &tail);
static uint get_crc32(uint c, unsigned char *ptr, uint len);
// error handling
void abort(const char *msg)
{
unpack_abort(msg, u);
}
bool aborting()
{
return unpack_aborting(u);
}
static uint32_t get_crc32(uint32_t c, unsigned char *ptr, uint32_t len);
};
struct gunzip
@ -105,7 +95,7 @@ struct gunzip
// pointer to outer unpacker, for error checks etc.
unpacker *u;
void *read_input_fn; // underlying byte stream
void *read_input_fn; // underlying \bchar\b stream
void *zstream; // inflater state
char inbuf[1 << 14]; // input buffer
@ -117,14 +107,4 @@ struct gunzip
// private stuff
void read_fixed_field(char *buf, size_t buflen);
// error handling
void abort(const char *msg)
{
unpack_abort(msg, u);
}
bool aborting()
{
return unpack_aborting(u);
}
};

View File

@ -32,7 +32,7 @@ ADD_DEFINITIONS(-DQUAZIP_STATIC)
#qt5_wrap_cpp(MOC_SRCS ${PUBLIC_HEADERS})
#set(SRCS ${SRCS} ${MOC_SRCS})
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
#set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_library(quazip STATIC ${SRCS})
QT5_USE_MODULES(quazip Core)

View File

@ -0,0 +1,32 @@
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" OFF)
set(CMAKE_C_FLAGS "-std=c99")
include_directories(include)
SET(XZ_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
# See include/xz.h for manual feature configuration
# tweak this list and xz.h to fit your needs
set(XZ_SOURCES
include/xz.h
src/xz_config.h
src/xz_crc32.c
src/xz_crc64.c
src/xz_dec_lzma2.c
src/xz_dec_stream.c
src/xz_lzma2.h
src/xz_private.h
src/xz_stream.h
# src/xz_dec_bcj.c
)
# TODO: look into what would be needed for plain old lzma
add_library(xz-embedded STATIC ${XZ_SOURCES})
add_executable(xzminidec xzminidec.c)
target_link_libraries(xzminidec xz-embedded)

View File

@ -0,0 +1,319 @@
/*
* 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
/* Definitions that determine available features */
#define XZ_DEC_ANY_CHECK 1
#define XZ_USE_CRC64 1
// native machine code compression stuff
/*
#define XZ_DEC_X86
#define XZ_DEC_POWERPC
#define XZ_DEC_IA64
#define XZ_DEC_ARM
#define XZ_DEC_ARMTHUMB
#define XZ_DEC_SPARC
*/
/* 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;
}

View File

@ -210,7 +210,7 @@ void LegacyModEditDialog::on_addForgeBtn_clicked()
if(entry->stale)
{
DownloadJob * fjob = new DownloadJob("Forge download");
fjob->add(forge->universal_url, entry);
fjob->addCacheDownload(forge->universal_url, entry);
ProgressDialog dlg(this);
dlg.exec(fjob);
if(dlg.result() == QDialog::Accepted)

View File

@ -160,7 +160,7 @@ void OneSixModEditDialog::on_forgeBtn_clicked()
if (entry->stale)
{
DownloadJob *fjob = new DownloadJob("Forge download");
fjob->add(forgeVersion->installer_url, entry);
fjob->addCacheDownload(forgeVersion->installer_url, entry);
ProgressDialog dlg(this);
dlg.exec(fjob);
if (dlg.result() == QDialog::Accepted)

View File

@ -100,11 +100,16 @@ bool ForgeInstaller::apply(QSharedPointer<OneSixVersion> to)
for (auto lib : m_forge_version->libraries)
{
QString libName = lib->name();
// WARNING: This could actually break.
// if this is the actual forge lib, set an absolute url for the download
if (libName.contains("minecraftforge"))
{
lib->setAbsoluteUrl(m_universal_url);
}
else if (libName.contains("scala"))
{
lib->setHint("forge-pack-xz");
}
if (blacklist.contains(libName))
continue;

View File

@ -228,7 +228,7 @@ void LegacyUpdate::jarStart()
urlstr += intended_version_id + "/" + intended_version_id + ".jar";
auto dljob = new DownloadJob("Minecraft.jar for version " + intended_version_id);
dljob->add(QUrl(urlstr), inst->defaultBaseJar());
dljob->addFileDownload(QUrl(urlstr), inst->defaultBaseJar());
legacyDownloadJob.reset(dljob);
connect(dljob, SIGNAL(succeeded()), SLOT(jarFinished()));
connect(dljob, SIGNAL(failed()), SLOT(jarFailed()));

View File

@ -113,7 +113,7 @@ void OneSixAssets::fetchXMLFinished()
auto entry = metacache->resolveEntry("assets", keyStr, etagStr);
if(entry->stale)
{
job->add(QUrl(prefix + keyStr), entry);
job->addCacheDownload(QUrl(prefix + keyStr), entry);
}
}
if(job->size())
@ -130,7 +130,7 @@ void OneSixAssets::fetchXMLFinished()
void OneSixAssets::start()
{
auto job = new DownloadJob("Assets index");
job->add(QUrl ( "http://s3.amazonaws.com/Minecraft.Resources/" ));
job->addByteArrayDownload(QUrl ( "http://s3.amazonaws.com/Minecraft.Resources/" ));
connect ( job, SIGNAL(succeeded()), SLOT ( fetchXMLFinished() ) );
index_job.reset ( job );
job->start();

View File

@ -105,12 +105,24 @@ QString OneSixLibrary::absoluteUrl()
return m_absolute_url;
}
void OneSixLibrary::setHint(QString hint)
{
m_hint = hint;
}
QString OneSixLibrary::hint()
{
return m_hint;
}
QJsonObject OneSixLibrary::toJson()
{
QJsonObject libRoot;
libRoot.insert("name", m_name);
if(m_absolute_url.size())
libRoot.insert("MMC-absulute_url", m_absolute_url);
libRoot.insert("MMC-absoluteUrl", m_absolute_url);
if(m_hint.size())
libRoot.insert("MMC-hint", m_hint);
if(m_base_url != "https://s3.amazonaws.com/Minecraft.Download/libraries/")
libRoot.insert("url", m_base_url);
if (isNative() && m_native_suffixes.size())

View File

@ -19,6 +19,8 @@ private:
// custom values
/// absolute URL. takes precedence over m_download_path, if defined
QString m_absolute_url;
/// download hint - how to actually get the library
QString m_hint;
// derived values used for real things
/// a decent name fit for display
@ -95,4 +97,8 @@ public:
/// set an absolute URL for the library. This is an MMC extension.
void setAbsoluteUrl(QString absolute_url);
QString absoluteUrl();
/// set a hint about how to treat the library. This is an MMC extension.
void setHint(QString hint);
QString hint();
};

View File

@ -75,7 +75,7 @@ void OneSixUpdate::versionFileStart()
QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".json";
auto job = new DownloadJob("Version index");
job->add(QUrl(urlstr));
job->addByteArrayDownload(QUrl(urlstr));
specificVersionDownloadJob.reset(job);
connect(specificVersionDownloadJob.data(), SIGNAL(succeeded()),
SLOT(versionFileFinished()));
@ -158,7 +158,7 @@ void OneSixUpdate::jarlibStart()
targetstr += version->id + "/" + version->id + ".jar";
auto job = new DownloadJob("Libraries for instance " + inst->name());
job->add(QUrl(urlstr), targetstr);
job->addFileDownload(QUrl(urlstr), targetstr);
jarlibDownloadJob.reset(job);
auto libs = version->getActiveNativeLibs();
@ -171,7 +171,10 @@ void OneSixUpdate::jarlibStart()
auto entry = metacache->resolveEntry("libraries", lib->storagePath());
if (entry->stale)
{
jarlibDownloadJob->add(download_path, entry);
if(lib->hint() == "forge-pack-xz")
jarlibDownloadJob->addForgeXzDownload(download_path, entry);
else
jarlibDownloadJob->addCacheDownload(download_path, entry);
}
}
connect(jarlibDownloadJob.data(), SIGNAL(succeeded()), SLOT(jarlibFinished()));

View File

@ -71,11 +71,21 @@ QSharedPointer<OneSixVersion> fromJsonV4(QJsonObject root,
{
library->setBaseUrl(urlVal.toString());
}
auto urlAbsVal = libObj.value("MMC-absulute_url");
auto hintVal = libObj.value("MMC-hint");
if (hintVal.isString())
{
library->setHint(hintVal.toString());
}
auto urlAbsVal = libObj.value("MMC-absoluteUrl");
auto urlAbsuVal = libObj.value("MMC-absulute_url"); // compatibility
if (urlAbsVal.isString())
{
library->setAbsoluteUrl(urlAbsVal.toString());
}
else if(urlAbsuVal.isString())
{
library->setAbsoluteUrl(urlAbsuVal.toString());
}
// Extract excludes (if any)
auto extractVal = libObj.value("extract");
if (extractVal.isObject())

View File

@ -162,7 +162,7 @@ void ForgeListLoadTask::executeTask()
auto job = new DownloadJob("Version index");
// we do not care if the version is stale or not.
auto forgeListEntry = MMC->metacache()->resolveEntry("minecraftforge", "list.json");
job->add(QUrl(JSON_URL), forgeListEntry);
job->addCacheDownload(QUrl(JSON_URL), forgeListEntry);
listJob.reset(job);
connect(listJob.data(), SIGNAL(succeeded()), SLOT(list_downloaded()));
connect(listJob.data(), SIGNAL(failed()), SLOT(versionFileFailed()));

View File

@ -46,7 +46,7 @@ public:
protected:
QList<BaseVersionPtr> m_vlist;
bool m_loaded;
bool m_loaded = false;
protected slots:
virtual void updateListData(QList<BaseVersionPtr> versions);

View File

@ -7,7 +7,7 @@
#include <QDebug>
ByteArrayDownloadPtr DownloadJob::add(QUrl url)
ByteArrayDownloadPtr DownloadJob::addByteArrayDownload(QUrl url)
{
ByteArrayDownloadPtr ptr(new ByteArrayDownload(url));
ptr->index_within_job = downloads.size();
@ -17,7 +17,7 @@ ByteArrayDownloadPtr DownloadJob::add(QUrl url)
return ptr;
}
FileDownloadPtr DownloadJob::add(QUrl url, QString rel_target_path)
FileDownloadPtr DownloadJob::addFileDownload(QUrl url, QString rel_target_path)
{
FileDownloadPtr ptr(new FileDownload(url, rel_target_path));
ptr->index_within_job = downloads.size();
@ -27,7 +27,7 @@ FileDownloadPtr DownloadJob::add(QUrl url, QString rel_target_path)
return ptr;
}
CacheDownloadPtr DownloadJob::add(QUrl url, MetaEntryPtr entry)
CacheDownloadPtr DownloadJob::addCacheDownload(QUrl url, MetaEntryPtr entry)
{
CacheDownloadPtr ptr(new CacheDownload(url, entry));
ptr->index_within_job = downloads.size();
@ -37,6 +37,16 @@ CacheDownloadPtr DownloadJob::add(QUrl url, MetaEntryPtr entry)
return ptr;
}
ForgeXzDownloadPtr DownloadJob::addForgeXzDownload(QUrl url, MetaEntryPtr entry)
{
ForgeXzDownloadPtr ptr(new ForgeXzDownload(url, entry));
ptr->index_within_job = downloads.size();
downloads.append(ptr);
parts_progress.append(part_info());
total_progress++;
return ptr;
}
void DownloadJob::partSucceeded(int index)
{
// do progress. all slots are 1 in size at least

View File

@ -5,6 +5,7 @@
#include "FileDownload.h"
#include "CacheDownload.h"
#include "HttpMetaCache.h"
#include "ForgeXzDownload.h"
#include "logic/tasks/ProgressProvider.h"
class DownloadJob;
@ -20,9 +21,10 @@ public:
explicit DownloadJob(QString job_name)
:ProgressProvider(), m_job_name(job_name){};
ByteArrayDownloadPtr add(QUrl url);
FileDownloadPtr add(QUrl url, QString rel_target_path);
CacheDownloadPtr add(QUrl url, MetaEntryPtr entry);
ByteArrayDownloadPtr addByteArrayDownload(QUrl url);
FileDownloadPtr addFileDownload(QUrl url, QString rel_target_path);
CacheDownloadPtr addCacheDownload(QUrl url, MetaEntryPtr entry);
ForgeXzDownloadPtr addForgeXzDownload(QUrl url, MetaEntryPtr entry);
DownloadPtr operator[](int index)
{

View File

@ -0,0 +1,277 @@
#include "MultiMC.h"
#include "ForgeXzDownload.h"
#include <pathutils.h>
#include <QCryptographicHash>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>
ForgeXzDownload::ForgeXzDownload(QUrl url, MetaEntryPtr entry)
: Download()
{
QString urlstr = url.toString();
urlstr.append(".pack.xz");
m_url = QUrl(urlstr);
m_entry = entry;
m_target_path = entry->getFullPath();
m_status = Job_NotStarted;
m_opened_for_saving = false;
}
void ForgeXzDownload::start()
{
if (!m_entry->stale)
{
emit succeeded(index_within_job);
return;
}
// can we actually create the real, final file?
if (!ensureFilePathExists(m_target_path))
{
emit failed(index_within_job);
return;
}
qDebug() << "Downloading " << m_url.toString();
QNetworkRequest request(m_url);
request.setRawHeader(QString("If-None-Match").toLatin1(), m_entry->etag.toLatin1());
auto worker = MMC->qnam();
QNetworkReply *rep = worker->get(request);
m_reply = QSharedPointer<QNetworkReply>(rep, &QObject::deleteLater);
connect(rep, SIGNAL(downloadProgress(qint64, qint64)),
SLOT(downloadProgress(qint64, qint64)));
connect(rep, SIGNAL(finished()), SLOT(downloadFinished()));
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)),
SLOT(downloadError(QNetworkReply::NetworkError)));
connect(rep, SIGNAL(readyRead()), SLOT(downloadReadyRead()));
}
void ForgeXzDownload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
emit progress(index_within_job, bytesReceived, bytesTotal);
}
void ForgeXzDownload::downloadError(QNetworkReply::NetworkError error)
{
// error happened during download.
// TODO: log the reason why
m_status = Job_Failed;
}
void ForgeXzDownload::downloadFinished()
{
// if the download succeeded
if (m_status != Job_Failed)
{
// nothing went wrong...
m_status = Job_Finished;
if (m_opened_for_saving)
{
// we actually downloaded something! process and isntall it
decompressAndInstall();
return;
}
else
{
// something bad happened
m_pack200_xz_file.remove();
m_reply.clear();
emit failed(index_within_job);
return;
}
}
// else the download failed
else
{
m_pack200_xz_file.close();
m_pack200_xz_file.remove();
m_reply.clear();
emit failed(index_within_job);
return;
}
}
void ForgeXzDownload::downloadReadyRead()
{
if (!m_opened_for_saving)
{
if (!m_pack200_xz_file.open())
{
/*
* Can't open the file... the job failed
*/
m_reply->abort();
emit failed(index_within_job);
return;
}
m_opened_for_saving = true;
}
m_pack200_xz_file.write(m_reply->readAll());
}
#include "xz.h"
#include "unpack200.h"
const size_t buffer_size = 8196;
void ForgeXzDownload::decompressAndInstall()
{
// rewind the downloaded temp file
m_pack200_xz_file.seek(0);
// de-xz'd file
QTemporaryFile pack200_file;
pack200_file.open();
bool xz_success = false;
// first, de-xz
{
uint8_t in[buffer_size];
uint8_t out[buffer_size];
struct xz_buf b;
struct xz_dec *s;
enum xz_ret ret;
xz_crc32_init();
xz_crc64_init();
s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
if (s == nullptr)
{
xz_dec_end(s);
emit failed(index_within_job);
return;
}
b.in = in;
b.in_pos = 0;
b.in_size = 0;
b.out = out;
b.out_pos = 0;
b.out_size = buffer_size;
while (!xz_success)
{
if (b.in_pos == b.in_size)
{
b.in_size = m_pack200_xz_file.read((char*)in, sizeof(in));
b.in_pos = 0;
}
ret = xz_dec_run(s, &b);
if (b.out_pos == sizeof(out))
{
if (pack200_file.write((char*)out, b.out_pos) != b.out_pos)
{
// msg = "Write error\n";
xz_dec_end(s);
emit failed(index_within_job);
return;
}
b.out_pos = 0;
}
if (ret == XZ_OK)
continue;
if (ret == XZ_UNSUPPORTED_CHECK)
{
// unsupported check. this is OK, but we should log this
continue;
}
if (pack200_file.write((char*)out, b.out_pos) != b.out_pos )
{
// write error
pack200_file.close();
xz_dec_end(s);
return;
}
switch (ret)
{
case XZ_STREAM_END:
xz_dec_end(s);
xz_success = true;
break;
case XZ_MEM_ERROR:
qDebug() << "Memory allocation failed\n";
xz_dec_end(s);
emit failed(index_within_job);
return;
case XZ_MEMLIMIT_ERROR:
qDebug() << "Memory usage limit reached\n";
xz_dec_end(s);
emit failed(index_within_job);
return;
case XZ_FORMAT_ERROR:
qDebug() << "Not a .xz file\n";
xz_dec_end(s);
emit failed(index_within_job);
return;
case XZ_OPTIONS_ERROR:
qDebug() << "Unsupported options in the .xz headers\n";
xz_dec_end(s);
emit failed(index_within_job);
return;
case XZ_DATA_ERROR:
case XZ_BUF_ERROR:
qDebug() << "File is corrupt\n";
xz_dec_end(s);
emit failed(index_within_job);
return;
default:
qDebug() << "Bug!\n";
xz_dec_end(s);
emit failed(index_within_job);
return;
}
}
}
// revert pack200
pack200_file.close();
QString pack_name = pack200_file.fileName();
try
{
unpack_200(pack_name.toStdString(), m_target_path.toStdString());
}
catch(std::runtime_error & err)
{
qDebug() << "Error unpacking " << pack_name.toUtf8() << " : " << err.what();
QFile f(m_target_path);
if(f.exists())
f.remove();
emit failed(index_within_job);
return;
}
QFile jar_file(m_target_path);
if (!jar_file.open(QIODevice::ReadOnly))
{
jar_file.remove();
emit failed(index_within_job);
return;
}
m_entry->md5sum = QCryptographicHash::hash(jar_file.readAll(), QCryptographicHash::Md5)
.toHex()
.constData();
jar_file.close();
QFileInfo output_file_info(m_target_path);
m_entry->etag = m_reply->rawHeader("ETag").constData();
m_entry->last_changed_timestamp =
output_file_info.lastModified().toUTC().toMSecsSinceEpoch();
m_entry->stale = false;
MMC->metacache()->updateEntry(m_entry);
m_reply.clear();
emit succeeded(index_within_job);
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "Download.h"
#include "HttpMetaCache.h"
#include <QFile>
#include <QTemporaryFile>
class ForgeXzDownload : public Download
{
Q_OBJECT
public:
MetaEntryPtr m_entry;
/// is the saving file already open?
bool m_opened_for_saving;
/// if saving to file, use the one specified in this string
QString m_target_path;
/// this is the output file, if any
QTemporaryFile m_pack200_xz_file;
public:
explicit ForgeXzDownload(QUrl url, MetaEntryPtr entry);
protected slots:
virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
virtual void downloadError(QNetworkReply::NetworkError error);
virtual void downloadFinished();
virtual void downloadReadyRead();
public slots:
virtual void start();
private:
void decompressAndInstall();
};
typedef QSharedPointer<ForgeXzDownload> ForgeXzDownloadPtr;