diff --git a/src/qtquick/karchive-rar/CMakeLists.txt b/src/qtquick/karchive-rar/CMakeLists.txt index c4fa920..3928dfd 100644 --- a/src/qtquick/karchive-rar/CMakeLists.txt +++ b/src/qtquick/karchive-rar/CMakeLists.txt @@ -1,17 +1,50 @@ project(karchive-rar) -# For unarr -add_subdirectory(external) +find_package(ZLIB) + +if (UNIX OR MINGW) + add_compile_options(-std=gnu99 -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 -fPIC) +endif (UNIX OR MINGW) + +set(unarr_SRCS + unarr/rar/uncompress-rar.c + unarr/rar/huffman-rar.c + unarr/rar/rar.c + unarr/rar/filter-rar.c + unarr/rar/rarvm.c + unarr/rar/parse-rar.c + unarr/lzmasdk/Ppmd7.c + unarr/lzmasdk/Ppmd8.c + unarr/lzmasdk/CpuArch.c + unarr/lzmasdk/LzmaDec.c + unarr/lzmasdk/Ppmd7Dec.c + unarr/lzmasdk/Ppmd8Dec.c + unarr/common/custalloc.c + unarr/common/unarr.c + unarr/common/stream.c + unarr/common/conv.c + unarr/common/crc32.c +) set(karchive_rar_SRCS KRar.cpp KRarFileEntry.cpp ) -add_library(karchive-rar STATIC ${karchive_rar_SRCS}) +add_library(karchive-rar STATIC ${karchive_rar_SRCS} ${unarr_SRCS}) target_link_libraries(karchive-rar - PRIVATE unarr PUBLIC KF5::Archive ) +target_include_directories(karchive-rar + PRIVATE + unarr/ +) + +if (ZLIB_FOUND) + target_include_directories(karchive-rar PRIVATE ${ZLIB_INCLUDE_DIRS}) + target_link_libraries(karchive-rar PRIVATE ${ZLIB_LIBRARIES}) + add_definitions(-DHAVE_ZLIB) +endif(ZLIB_FOUND) + # A little hack, which makes the karchive_rar library think it's a part of KF5Archive add_definitions(-DKF5Archive_EXPORTS) diff --git a/src/qtquick/karchive-rar/unarr/AUTHORS b/src/qtquick/karchive-rar/unarr/AUTHORS new file mode 100644 index 0000000..b66d935 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/AUTHORS @@ -0,0 +1,12 @@ +unarr contains code by: + +* The Unarchiver project (https://code.google.com/p/theunarchiver/) +* Simon Bünzli (zeniko at gmail.com, http://www.zeniko.ch/#SumatraPDF) + +Most code is licensed under LGPLv3 (see COPYING). Exceptions are in code +included from other projects: + +Files License URL +---------------------------------------------------------------------------------- +common/crc32.c Public Domain https://gnunet.org/svn/gnunet/src/util/crypto_crc.c +lzmasdk/*.* Public Domain http://www.7-zip.org/sdk.html diff --git a/src/qtquick/karchive-rar/unarr/COPYING b/src/qtquick/karchive-rar/unarr/COPYING new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/src/qtquick/karchive-rar/unarr/README b/src/qtquick/karchive-rar/unarr/README new file mode 100644 index 0000000..9aabec6 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/README @@ -0,0 +1,5 @@ +The unarr directory contains code from the unarr project, originally +created for use with SumatraPDF. The code is mostly unmaintained upstream +and generally unpackaged, and as such it has been imported here. +The specific bits of code imported here are only the parts used for +reading and writing rar files. diff --git a/src/qtquick/karchive-rar/unarr/common/allocator.h b/src/qtquick/karchive-rar/unarr/common/allocator.h new file mode 100644 index 0000000..41199c8 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/common/allocator.h @@ -0,0 +1,29 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#ifndef common_allocator_h +#define common_allocator_h + +#ifdef USE_CUSTOM_ALLOCATOR + +#include + +typedef void *(* custom_malloc_fn)(void *opaque, size_t size); +typedef void (* custom_free_fn)(void *opaque, void *ptr); + +void ar_set_custom_allocator(custom_malloc_fn custom_malloc, custom_free_fn custom_free, void *opaque); + +#define malloc(size) ar_malloc(size) +#define calloc(count, size) ar_calloc(count, size) +#define free(ptr) ar_free(ptr) + +#define realloc(ptr, size) _use_malloc_memcpy_free_instead(ptr, size) +#define strdup(str) _use_malloc_memcpy_instead(str) + +#elif !defined(NDEBUG) && defined(_MSC_VER) + +#include + +#endif + +#endif diff --git a/src/qtquick/karchive-rar/unarr/common/conv.c b/src/qtquick/karchive-rar/unarr/common/conv.c new file mode 100644 index 0000000..4398539 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/common/conv.c @@ -0,0 +1,96 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#include "unarr-imp.h" + +#include + +/* data from http://en.wikipedia.org/wiki/Cp437 */ +static const wchar_t gCp437[256] = { + 0, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266C, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x2302, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0, +}; + +size_t ar_conv_rune_to_utf8(wchar_t rune, char *out, size_t size) +{ + if (size < 1) + return 0; + if (rune < 0x0080) { + *out++ = rune & 0x7F; + return 1; + } + if (rune < 0x0800 && size >= 2) { + *out++ = 0xC0 | ((rune >> 6) & 0x1F); + *out++ = 0x80 | (rune & 0x3F); + return 2; + } + if (size >= 3) { + if ((0xD800 <= rune && rune <= 0xDFFF) || rune >= 0x10000) + rune = 0xFFFD; + *out++ = 0xE0 | ((rune >> 12) & 0x0F); + *out++ = 0x80 | ((rune >> 6) & 0x3F); + *out++ = 0x80 | (rune & 0x3F); + return 3; + } + *out++ = '?'; + return 1; +} + +char *ar_conv_dos_to_utf8(const char *astr) +{ + char *str, *out; + const char *in; + size_t size; + + size = 0; + for (in = astr; *in; in++) { + char buf[4]; + size += ar_conv_rune_to_utf8(gCp437[(uint8_t)*in], buf, sizeof(buf)); + } + + if (size == (size_t)-1) + return NULL; + str = malloc(size + 1); + if (!str) + return NULL; + + for (in = astr, out = str; *in; in++) { + out += ar_conv_rune_to_utf8(gCp437[(uint8_t)*in], out, str + size - out); + } + *out = '\0'; + + return str; +} + +time64_t ar_conv_dosdate_to_filetime(uint32_t dosdate) +{ + struct tm tm; + time_t t1, t2; + + tm.tm_sec = (dosdate & 0x1F) * 2; + tm.tm_min = (dosdate >> 5) & 0x3F; + tm.tm_hour = (dosdate >> 11) & 0x1F; + tm.tm_mday = (dosdate >> 16) & 0x1F; + tm.tm_mon = ((dosdate >> 21) & 0x0F) - 1; + tm.tm_year = ((dosdate >> 25) & 0x7F) + 80; + tm.tm_isdst = -1; + + t1 = mktime(&tm); + t2 = mktime(gmtime(&t1)); + + return (time64_t)(2 * t1 - t2 + 11644473600) * 10000000; +} diff --git a/src/qtquick/karchive-rar/unarr/common/crc32.c b/src/qtquick/karchive-rar/unarr/common/crc32.c new file mode 100644 index 0000000..b482e6e --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/common/crc32.c @@ -0,0 +1,51 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#include "unarr-imp.h" + +#ifndef HAVE_ZLIB + +/* code adapted from https://gnunet.org/svn/gnunet/src/util/crypto_crc.c (public domain) */ + +static bool crc_table_ready = false; +static uint32_t crc_table[256]; + +uint32_t ar_crc32(uint32_t crc32, const unsigned char *data, size_t data_len) +{ + if (!crc_table_ready) { + uint32_t i, j; + uint32_t h = 1; + crc_table[0] = 0; + for (i = 128; i; i >>= 1) { + h = (h >> 1) ^ ((h & 1) ? 0xEDB88320 : 0); + for (j = 0; j < 256; j += 2 * i) { + crc_table[i + j] = crc_table[j] ^ h; + } + } + crc_table_ready = true; + } + + crc32 = crc32 ^ 0xFFFFFFFF; + while (data_len-- > 0) { + crc32 = (crc32 >> 8) ^ crc_table[(crc32 ^ *data++) & 0xFF]; + } + return crc32 ^ 0xFFFFFFFF; +} + +#else + +#include + +uint32_t ar_crc32(uint32_t crc, const unsigned char *data, size_t data_len) +{ +#if SIZE_MAX > UINT32_MAX + while (data_len > UINT32_MAX) { + crc = crc32(crc, data, UINT32_MAX); + data += UINT32_MAX; + data_len -= UINT32_MAX; + } +#endif + return crc32(crc, data, (uint32_t)data_len); +} + +#endif diff --git a/src/qtquick/karchive-rar/unarr/common/custalloc.c b/src/qtquick/karchive-rar/unarr/common/custalloc.c new file mode 100644 index 0000000..9bd63b8 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/common/custalloc.c @@ -0,0 +1,49 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#include +#include +#include + +typedef void *(* custom_malloc_fn)(void *opaque, size_t size); +typedef void (* custom_free_fn)(void *opaque, void *ptr); + +static void *default_malloc(void *opaque, size_t size) { (void)opaque; return malloc(size); } +static void default_free(void *opaque, void *ptr) { (void)opaque; free(ptr); } + +static struct { + custom_malloc_fn malloc; + custom_free_fn free; + void *opaque; +} gAllocator = { + default_malloc, + default_free, + NULL, +}; + +void *ar_malloc(size_t size) +{ + return gAllocator.malloc(gAllocator.opaque, size); +} + +void *ar_calloc(size_t count, size_t size) +{ + void *ptr = NULL; + if (size <= SIZE_MAX / count) + ptr = ar_malloc(count * size); + if (ptr) + memset(ptr, 0, count * size); + return ptr; +} + +void ar_free(void *ptr) +{ + gAllocator.free(gAllocator.opaque, ptr); +} + +void ar_set_custom_allocator(custom_malloc_fn custom_malloc, custom_free_fn custom_free, void *opaque) +{ + gAllocator.malloc = custom_malloc ? custom_malloc : default_malloc; + gAllocator.free = custom_free ? custom_free : default_free; + gAllocator.opaque = opaque; +} diff --git a/src/qtquick/karchive-rar/unarr/common/stream.c b/src/qtquick/karchive-rar/unarr/common/stream.c new file mode 100644 index 0000000..d98a1c2 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/common/stream.c @@ -0,0 +1,222 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#include "unarr-imp.h" +#ifdef WIN32 +#define COBJMACROS +#include +#include +#endif + +ar_stream *ar_open_stream(void *data, ar_stream_close_fn close, ar_stream_read_fn read, ar_stream_seek_fn seek, ar_stream_tell_fn tell) +{ + ar_stream *stream = malloc(sizeof(ar_stream)); + if (!stream) { + close(data); + return NULL; + } + stream->data = data; + stream->close = close; + stream->read = read; + stream->seek = seek; + stream->tell = tell; + return stream; +} + +void ar_close(ar_stream *stream) +{ + if (stream) + stream->close(stream->data); + free(stream); +} + +size_t ar_read(ar_stream *stream, void *buffer, size_t count) +{ + return stream->read(stream->data, buffer, count); +} + +bool ar_seek(ar_stream *stream, off64_t offset, int origin) +{ + return stream->seek(stream->data, offset, origin); +} + +bool ar_skip(ar_stream *stream, off64_t count) +{ + return stream->seek(stream->data, count, SEEK_CUR); +} + +off64_t ar_tell(ar_stream *stream) +{ + return stream->tell(stream->data); +} + +/***** stream based on FILE *****/ + +static void file_close(void *data) +{ + fclose(data); +} + +static size_t file_read(void *data, void *buffer, size_t count) +{ + return fread(buffer, 1, count, data); +} + +static bool file_seek(void *data, off64_t offset, int origin) +{ +#ifdef _MSC_VER + return _fseeki64(data, offset, origin) == 0; +#else +#if _POSIX_C_SOURCE >= 200112L + if (sizeof(off_t) == 8) + return fseeko(data, offset, origin) == 0; +#endif + if (offset > INT32_MAX || offset < INT32_MIN) + return false; + return fseek(data, (long)offset, origin) == 0; +#endif +} + +static off64_t file_tell(void *data) +{ +#ifdef _MSC_VER + return _ftelli64(data); +#elif _POSIX_C_SOURCE >= 200112L + return ftello(data); +#else + return ftell(data); +#endif +} + +ar_stream *ar_open_file(const char *path) +{ + FILE *f = path ? fopen(path, "rb") : NULL; + if (!f) + return NULL; + return ar_open_stream(f, file_close, file_read, file_seek, file_tell); +} + +#ifdef _WIN32 +ar_stream *ar_open_file_w(const wchar_t *path) +{ + FILE *f = path ? _wfopen(path, L"rb") : NULL; + if (!f) + return NULL; + return ar_open_stream(f, file_close, file_read, file_seek, file_tell); +} +#endif + +/***** stream based on preallocated memory *****/ + +struct MemoryStream { + const uint8_t *data; + size_t length; + size_t offset; +}; + +static void memory_close(void *data) +{ + struct MemoryStream *stm = data; + free(stm); +} + +static size_t memory_read(void *data, void *buffer, size_t count) +{ + struct MemoryStream *stm = data; + if (count > stm->length - stm->offset) + count = stm->length - stm->offset; + memcpy(buffer, stm->data + stm->offset, count); + stm->offset += count; + return count; +} + +static bool memory_seek(void *data, off64_t offset, int origin) +{ + struct MemoryStream *stm = data; + if (origin == SEEK_CUR) + offset += stm->offset; + else if (origin == SEEK_END) + offset += stm->length; + if (offset < 0 || offset > (off64_t)stm->length || (size_t)offset > stm->length) + return false; + stm->offset = (size_t)offset; + return true; +} + +static off64_t memory_tell(void *data) +{ + struct MemoryStream *stm = data; + return stm->offset; +} + +ar_stream *ar_open_memory(const void *data, size_t datalen) +{ + struct MemoryStream *stm = malloc(sizeof(struct MemoryStream)); + if (!stm) + return NULL; + stm->data = data; + stm->length = datalen; + stm->offset = 0; + return ar_open_stream(stm, memory_close, memory_read, memory_seek, memory_tell); +} + +#ifdef _WIN32 +/***** stream based on IStream *****/ + +#define COBJMACROS +#include + +static void stream_close(void *data) +{ + IUnknown_Release((IStream *)data); +} + +static size_t stream_read(void *data, void *buffer, size_t count) +{ + size_t read = 0; + HRESULT res; + ULONG cbRead; +#ifdef _WIN64 + while (count > ULONG_MAX) { + res = IStream_Read((IStream *)data, buffer, ULONG_MAX, &cbRead); + if (FAILED(res)) + return read; + read += cbRead; + buffer = (BYTE *)buffer + ULONG_MAX; + count -= ULONG_MAX; + } +#endif + res = IStream_Read((IStream *)data, buffer, (ULONG)count, &cbRead); + if (SUCCEEDED(res)) + read += cbRead; + return read; +} + +static bool stream_seek(void *data, off64_t offset, int origin) +{ + LARGE_INTEGER off; + ULARGE_INTEGER n; + HRESULT res; + off.QuadPart = offset; + res = IStream_Seek((IStream *)data, off, origin, &n); + return SUCCEEDED(res); +} + +static off64_t stream_tell(void *data) +{ + LARGE_INTEGER zero = { 0 }; + ULARGE_INTEGER n = { 0 }; + IStream_Seek((IStream *)data, zero, SEEK_CUR, &n); + return (off64_t)n.QuadPart; +} + +ar_stream *ar_open_istream(IStream *stream) +{ + LARGE_INTEGER zero = { 0 }; + HRESULT res = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); + if (FAILED(res)) + return NULL; + IUnknown_AddRef(stream); + return ar_open_stream(stream, stream_close, stream_read, stream_seek, stream_tell); +} +#endif diff --git a/src/qtquick/karchive-rar/unarr/common/unarr-imp.h b/src/qtquick/karchive-rar/unarr/common/unarr-imp.h new file mode 100644 index 0000000..90ad317 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/common/unarr-imp.h @@ -0,0 +1,81 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +/* this is the common private/implementation API of unarr which should only be used by unarr code */ + +#ifndef common_unarr_imp_h +#define common_unarr_imp_h + +#include "../unarr.h" +#include "allocator.h" + +#include +#include +#include +#include +#include + +/***** conv ****/ + +size_t ar_conv_rune_to_utf8(wchar_t rune, char *out, size_t size); +char *ar_conv_dos_to_utf8(const char *astr); +time64_t ar_conv_dosdate_to_filetime(uint32_t dosdate); + +/***** crc32 *****/ + +uint32_t ar_crc32(uint32_t crc32, const unsigned char *data, size_t data_len); + +/***** stream *****/ + +typedef void (* ar_stream_close_fn)(void *data); +typedef size_t (* ar_stream_read_fn)(void *data, void *buffer, size_t count); +typedef bool (* ar_stream_seek_fn)(void *data, off64_t offset, int origin); +typedef off64_t (* ar_stream_tell_fn)(void *data); + +struct ar_stream_s { + ar_stream_close_fn close; + ar_stream_read_fn read; + ar_stream_seek_fn seek; + ar_stream_tell_fn tell; + void *data; +}; + +ar_stream *ar_open_stream(void *data, ar_stream_close_fn close, ar_stream_read_fn read, ar_stream_seek_fn seek, ar_stream_tell_fn tell); + +/***** unarr *****/ + +#define warn(...) ar_log("!", __FILE__, __LINE__, __VA_ARGS__) +#ifndef NDEBUG +#define log(...) ar_log("-", __FILE__, __LINE__, __VA_ARGS__) +#else +#define log(...) ((void)0) +#endif +void ar_log(const char *prefix, const char *file, int line, const char *msg, ...); + +typedef void (* ar_archive_close_fn)(ar_archive *ar); +typedef bool (* ar_parse_entry_fn)(ar_archive *ar, off64_t offset); +typedef const char *(* ar_entry_get_name_fn)(ar_archive *ar); +typedef bool (* ar_entry_uncompress_fn)(ar_archive *ar, void *buffer, size_t count); +typedef size_t (* ar_get_global_comment_fn)(ar_archive *ar, void *buffer, size_t count); + +struct ar_archive_s { + ar_archive_close_fn close; + ar_parse_entry_fn parse_entry; + ar_entry_get_name_fn get_name; + ar_entry_uncompress_fn uncompress; + ar_get_global_comment_fn get_comment; + + ar_stream *stream; + bool at_eof; + off64_t entry_offset; + off64_t entry_offset_first; + off64_t entry_offset_next; + size_t entry_size_uncompressed; + time64_t entry_filetime; +}; + +ar_archive *ar_open_archive(ar_stream *stream, size_t struct_size, ar_archive_close_fn close, ar_parse_entry_fn parse_entry, + ar_entry_get_name_fn get_name, ar_entry_uncompress_fn uncompress, ar_get_global_comment_fn get_comment, + off64_t first_entry_offset); + +#endif diff --git a/src/qtquick/karchive-rar/unarr/common/unarr.c b/src/qtquick/karchive-rar/unarr/common/unarr.c new file mode 100644 index 0000000..97ec92a --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/common/unarr.c @@ -0,0 +1,109 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#include "unarr-imp.h" + +ar_archive *ar_open_archive(ar_stream *stream, size_t struct_size, ar_archive_close_fn close, ar_parse_entry_fn parse_entry, + ar_entry_get_name_fn get_name, ar_entry_uncompress_fn uncompress, ar_get_global_comment_fn get_comment, + off64_t first_entry_offset) +{ + ar_archive *ar = malloc(struct_size); + if (!ar) + return NULL; + memset(ar, 0, struct_size); + ar->close = close; + ar->parse_entry = parse_entry; + ar->get_name = get_name; + ar->uncompress = uncompress; + ar->get_comment = get_comment; + ar->stream = stream; + ar->entry_offset_first = first_entry_offset; + ar->entry_offset_next = first_entry_offset; + return ar; +} + +void ar_close_archive(ar_archive *ar) +{ + if (ar) + ar->close(ar); + free(ar); +} + +bool ar_at_eof(ar_archive *ar) +{ + return ar->at_eof; +} + +bool ar_parse_entry(ar_archive *ar) +{ + return ar->parse_entry(ar, ar->entry_offset_next); +} + +bool ar_parse_entry_at(ar_archive *ar, off64_t offset) +{ + ar->at_eof = false; + return ar->parse_entry(ar, offset ? offset : ar->entry_offset_first); +} + +bool ar_parse_entry_for(ar_archive *ar, const char *entry_name) +{ + ar->at_eof = false; + if (!entry_name) + return false; + if (!ar_parse_entry_at(ar, ar->entry_offset_first)) + return false; + do { + const char *name = ar_entry_get_name(ar); + if (name && strcmp(name, entry_name) == 0) + return true; + } while (ar_parse_entry(ar)); + return false; +} + +const char *ar_entry_get_name(ar_archive *ar) +{ + return ar->get_name(ar); +} + +off64_t ar_entry_get_offset(ar_archive *ar) +{ + return ar->entry_offset; +} + +size_t ar_entry_get_size(ar_archive *ar) +{ + return ar->entry_size_uncompressed; +} + +time64_t ar_entry_get_filetime(ar_archive *ar) +{ + return ar->entry_filetime; +} + +bool ar_entry_uncompress(ar_archive *ar, void *buffer, size_t count) +{ + return ar->uncompress(ar, buffer, count); +} + +size_t ar_get_global_comment(ar_archive *ar, void *buffer, size_t count) +{ + if (!ar->get_comment) + return 0; + return ar->get_comment(ar, buffer, count); +} + +void ar_log(const char *prefix, const char *file, int line, const char *msg, ...) +{ + va_list args; + va_start(args, msg); + if (prefix) + fprintf(stderr, "%s ", prefix); + if (strrchr(file, '/')) + file = strrchr(file, '/') + 1; + if (strrchr(file, '\\')) + file = strrchr(file, '\\') + 1; + fprintf(stderr, "%s:%d: ", file, line); + vfprintf(stderr, msg, args); + fprintf(stderr, "\n"); + va_end(args); +} diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/7zTypes.h b/src/qtquick/karchive-rar/unarr/lzmasdk/7zTypes.h new file mode 100644 index 0000000..778413e --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/7zTypes.h @@ -0,0 +1,256 @@ +/* 7zTypes.h -- Basic types +2013-11-12 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#ifdef _WIN32 +/* #include */ +#endif + +#include + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#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; + +#ifdef _WIN32 +/* typedef DWORD WRes; */ +typedef unsigned WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#define UINT64_CONST(n) n +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#define UINT64_CONST(n) n ## ULL +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#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_FAST_CALL __fastcall + +#else + +#define MY_NO_INLINE +#define MY_CDECL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ +} IByteIn; + +typedef struct +{ + void (*Write)(void *p, Byte b); +} IByteOut; + +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; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +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 enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + +EXTERN_C_END + +#endif diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/CpuArch.c b/src/qtquick/karchive-rar/unarr/lzmasdk/CpuArch.c new file mode 100644 index 0000000..d7f8b1d --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/CpuArch.c @@ -0,0 +1,190 @@ +/* CpuArch.c -- CPU specific code +2012-05-29: Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + +#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) +#define USE_ASM +#endif + +#if !defined(USE_ASM) && _MSC_VER >= 1500 +#include +#endif + +#if defined(USE_ASM) && !defined(MY_CPU_AMD64) +static UInt32 CheckFlag(UInt32 flag) +{ + #ifdef _MSC_VER + __asm pushfd; + __asm pop EAX; + __asm mov EDX, EAX; + __asm xor EAX, flag; + __asm push EAX; + __asm popfd; + __asm pushfd; + __asm pop EAX; + __asm xor EAX, EDX; + __asm push EDX; + __asm popfd; + __asm and flag, EAX; + #else + __asm__ __volatile__ ( + "pushf\n\t" + "pop %%EAX\n\t" + "movl %%EAX,%%EDX\n\t" + "xorl %0,%%EAX\n\t" + "push %%EAX\n\t" + "popf\n\t" + "pushf\n\t" + "pop %%EAX\n\t" + "xorl %%EDX,%%EAX\n\t" + "push %%EDX\n\t" + "popf\n\t" + "andl %%EAX, %0\n\t": + "=c" (flag) : "c" (flag)); + #endif + return flag; +} +#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; +#else +#define CHECK_CPUID_IS_SUPPORTED +#endif + +static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +{ + #ifdef USE_ASM + + #ifdef _MSC_VER + + UInt32 a2, b2, c2, d2; + __asm xor EBX, EBX; + __asm xor ECX, ECX; + __asm xor EDX, EDX; + __asm mov EAX, function; + __asm cpuid; + __asm mov a2, EAX; + __asm mov b2, EBX; + __asm mov c2, ECX; + __asm mov d2, EDX; + + *a = a2; + *b = b2; + *c = c2; + *d = d2; + + #else + + __asm__ __volatile__ ( + #if defined(MY_CPU_X86) && defined(__PIC__) + "mov %%ebx, %%edi;" + "cpuid;" + "xchgl %%ebx, %%edi;" + : "=a" (*a) , + "=D" (*b) , + #else + "cpuid" + : "=a" (*a) , + "=b" (*b) , + #endif + "=c" (*c) , + "=d" (*d) + : "0" (function)) ; + + #endif + + #else + + int CPUInfo[4]; + __cpuid(CPUInfo, function); + *a = CPUInfo[0]; + *b = CPUInfo[1]; + *c = CPUInfo[2]; + *d = CPUInfo[3]; + + #endif +} + +Bool x86cpuid_CheckAndRead(Cx86cpuid *p) +{ + CHECK_CPUID_IS_SUPPORTED + MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); + MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); + return True; +} + +static UInt32 kVendors[][3] = +{ + { 0x756E6547, 0x49656E69, 0x6C65746E}, + { 0x68747541, 0x69746E65, 0x444D4163}, + { 0x746E6543, 0x48727561, 0x736C7561} +}; + +int x86cpuid_GetFirm(const Cx86cpuid *p) +{ + unsigned i; + for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) + { + const UInt32 *v = kVendors[i]; + if (v[0] == p->vendor[0] && + v[1] == p->vendor[1] && + v[2] == p->vendor[2]) + return (int)i; + } + return -1; +} + +Bool CPU_Is_InOrder() +{ + Cx86cpuid p; + int firm; + UInt32 family, model; + if (!x86cpuid_CheckAndRead(&p)) + return True; + family = x86cpuid_GetFamily(&p); + model = x86cpuid_GetModel(&p); + firm = x86cpuid_GetFirm(&p); + switch (firm) + { + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( + /* Atom CPU */ + model == 0x100C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ + || model == 0x2006 /* 45 nm, Z6xx */ + || model == 0x2007 /* 32 nm, Z2460 */ + || model == 0x3005 /* 32 nm, Z2760 */ + || model == 0x3006 /* 32 nm, N2xxx, D2xxx */ + ))); + case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); + case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); + } + return True; +} + +#if !defined(MY_CPU_AMD64) && defined(_WIN32) +#include +static Bool CPU_Sys_Is_SSE_Supported() +{ + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionEx(&vi)) + return False; + return (vi.dwMajorVersion >= 5); +} +#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; +#else +#define CHECK_SYS_SSE_SUPPORT +#endif + +Bool CPU_Is_Aes_Supported() +{ + Cx86cpuid p; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_CheckAndRead(&p)) + return False; + return (p.c >> 25) & 1; +} + +#endif diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/CpuArch.h b/src/qtquick/karchive-rar/unarr/lzmasdk/CpuArch.h new file mode 100644 index 0000000..4fee009 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/CpuArch.h @@ -0,0 +1,157 @@ +/* CpuArch.h -- CPU specific code +2013-11-12: Igor Pavlov : Public domain */ + +#ifndef __CPU_ARCH_H +#define __CPU_ARCH_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* +MY_CPU_LE means that CPU is LITTLE ENDIAN. +If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). + +MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. +If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. +*/ + +#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) +#define MY_CPU_AMD64 +#endif + +#if defined(MY_CPU_AMD64) || defined(_M_IA64) +#define MY_CPU_64BIT +#endif + +#if defined(_M_IX86) || defined(__i386__) +#define MY_CPU_X86 +#endif + +#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) +#define MY_CPU_X86_OR_AMD64 +#endif + +#if defined(MY_CPU_X86) || defined(_M_ARM) +#define MY_CPU_32BIT +#endif + +#if defined(_WIN32) && defined(_M_ARM) +#define MY_CPU_ARM_LE +#endif + +#if defined(_WIN32) && defined(_M_IA64) +#define MY_CPU_IA64_LE +#endif + +#if defined(MY_CPU_X86_OR_AMD64) +#define MY_CPU_LE_UNALIGN +#endif + +#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) +#define MY_CPU_LE +#endif + +#if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__) +#define MY_CPU_BE +#endif + +#if defined(MY_CPU_LE) && defined(MY_CPU_BE) +Stop_Compiling_Bad_Endian +#endif + +#ifdef MY_CPU_LE_UNALIGN + +#define GetUi16(p) (*(const UInt16 *)(const void *)(p)) +#define GetUi32(p) (*(const UInt32 *)(const void *)(p)) +#define GetUi64(p) (*(const UInt64 *)(const void *)(p)) +#define SetUi16(p, d) *(UInt16 *)(p) = (d); +#define SetUi32(p, d) *(UInt32 *)(p) = (d); +#define SetUi64(p, d) *(UInt64 *)(p) = (d); + +#else + +#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) + +#define GetUi32(p) ( \ + ((const Byte *)(p))[0] | \ + ((UInt32)((const Byte *)(p))[1] << 8) | \ + ((UInt32)((const Byte *)(p))[2] << 16) | \ + ((UInt32)((const Byte *)(p))[3] << 24)) + +#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) + +#define SetUi16(p, d) { UInt32 _x_ = (d); \ + ((Byte *)(p))[0] = (Byte)_x_; \ + ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } + +#define SetUi32(p, d) { UInt32 _x_ = (d); \ + ((Byte *)(p))[0] = (Byte)_x_; \ + ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ + ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ + ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } + +#define SetUi64(p, d) { UInt64 _x64_ = (d); \ + SetUi32(p, (UInt32)_x64_); \ + SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } + +#endif + +#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) + +#include + +#pragma intrinsic(_byteswap_ulong) +#pragma intrinsic(_byteswap_uint64) +#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) + +#else + +#define GetBe32(p) ( \ + ((UInt32)((const Byte *)(p))[0] << 24) | \ + ((UInt32)((const Byte *)(p))[1] << 16) | \ + ((UInt32)((const Byte *)(p))[2] << 8) | \ + ((const Byte *)(p))[3] ) + +#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) + +#endif + +#define GetBe16(p) ((UInt16)(((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])) + + +#ifdef MY_CPU_X86_OR_AMD64 + +typedef struct +{ + UInt32 maxFunc; + UInt32 vendor[3]; + UInt32 ver; + UInt32 b; + UInt32 c; + UInt32 d; +} Cx86cpuid; + +enum +{ + CPU_FIRM_INTEL, + CPU_FIRM_AMD, + CPU_FIRM_VIA +}; + +Bool x86cpuid_CheckAndRead(Cx86cpuid *p); +int x86cpuid_GetFirm(const Cx86cpuid *p); + +#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) +#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) +#define x86cpuid_GetStepping(p) ((p)->ver & 0xF) + +Bool CPU_Is_InOrder(); +Bool CPU_Is_Aes_Supported(); + +#endif + +EXTERN_C_END + +#endif diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/LzmaDec.c b/src/qtquick/karchive-rar/unarr/lzmasdk/LzmaDec.c new file mode 100644 index 0000000..bbf650d --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/LzmaDec.c @@ -0,0 +1,1025 @@ +/* LzmaDec.c -- LZMA Decoder +2015-01-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "LzmaDec.h" + +#include + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol) +#define MATCHED_LITER_DEC \ + matchByte <<= 1; \ + bit = (matchByte & offs); \ + probLit = prob + offs + bit + symbol; \ + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + #ifdef _LZMA_SIZE_OPT + do { NORMAL_LITER_DEC } while (symbol < 0x100); + #else + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + #endif + } + else + { + unsigned matchByte = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + #ifdef _LZMA_SIZE_OPT + do + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + } + while (symbol < 0x100); + #else + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + } + #endif + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len != 0) + { + len--; + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + LzmaDec_Construct(&p); + RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); + p.dic = dest; + p.dicBufSize = outSize; + LzmaDec_Init(&p); + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/LzmaDec.h b/src/qtquick/karchive-rar/unarr/lzmasdk/LzmaDec.h new file mode 100644 index 0000000..cc44dae --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/LzmaDec.h @@ -0,0 +1,227 @@ +/* LzmaDec.h -- LZMA Decoder +2013-01-18 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* #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 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *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; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte 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 Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- 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, SizeT dicLimit, + const Byte *src, SizeT *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, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *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(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +EXTERN_C_END + +#endif diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd.h b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd.h new file mode 100644 index 0000000..4356dd1 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd.h @@ -0,0 +1,85 @@ +/* Ppmd.h -- PPMD codec common code +2013-01-18 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#ifndef __PPMD_H +#define __PPMD_H + +#include "CpuArch.h" + +EXTERN_C_BEGIN + +#ifdef MY_CPU_32BIT + #define PPMD_32BIT +#endif + +#define PPMD_INT_BITS 7 +#define PPMD_PERIOD_BITS 7 +#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) + +#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) +#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) +#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) +#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) + +#define PPMD_N1 4 +#define PPMD_N2 4 +#define PPMD_N3 4 +#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) +#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) + +#pragma pack(push, 1) +/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ + +/* SEE-contexts for PPM-contexts with masked symbols */ +typedef struct +{ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ +} CPpmd_See; + +#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } + +typedef struct +{ + Byte Symbol; + Byte Freq; + UInt16 SuccessorLow; + UInt16 SuccessorHigh; +} CPpmd_State; + +#pragma pack(pop) + +typedef + #ifdef PPMD_32BIT + CPpmd_State * + #else + UInt32 + #endif + CPpmd_State_Ref; + +typedef + #ifdef PPMD_32BIT + void * + #else + UInt32 + #endif + CPpmd_Void_Ref; + +typedef + #ifdef PPMD_32BIT + Byte * + #else + UInt32 + #endif + CPpmd_Byte_Ref; + +#define PPMD_SetAllBitsIn256Bytes(p) \ + { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \ + p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }} + +EXTERN_C_END + +#endif diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7.c b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7.c new file mode 100644 index 0000000..bb5d175 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7.c @@ -0,0 +1,710 @@ +/* Ppmd7.c -- PPMdH codec +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd7.h" + +const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define STATS(ctx) Ppmd7_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd7_Context * CTX_PTR; + +struct CPpmd7_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Node_ * + #else + UInt32 + #endif + CPpmd7_Node_Ref; + +typedef struct CPpmd7_Node_ +{ + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; +} CPpmd7_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) +#endif + +void Ppmd7_Construct(CPpmd7 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while(--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } + + memset(p->HB2Flag, 0, 0x40); + memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); +} + +void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) +{ + if (p->Base == 0 || p->Size != size) + { + Ppmd7_Free(p, alloc); + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size + #ifndef PPMD_32BIT + + UNIT_SIZE + #endif + )) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd7 *p, void *node, unsigned indx) +{ + *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + p->FreeList[indx] = REF(node); +} + +static void *RemoveNode(CPpmd7 *p, unsigned indx) +{ + CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + return node; +} + +static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd7 *p) +{ + #ifdef PPMD_32BIT + CPpmd7_Node headItem; + CPpmd7_Node_Ref head = &headItem; + #else + CPpmd7_Node_Ref head = p->AlignOffset + p->Size; + #endif + + CPpmd7_Node_Ref n = head; + unsigned i; + + p->GlueCount = 255; + + /* create doubly-linked list of free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt16 nu = I2U(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd7_Node *node = NODE(next); + node->Next = n; + n = NODE(n)->Prev = next; + next = *(const CPpmd7_Node_Ref *)node; + node->Stamp = 0; + node->NU = (UInt16)nu; + } + } + NODE(head)->Stamp = 1; + NODE(head)->Next = n; + NODE(n)->Prev = head; + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; + + /* Glue free blocks */ + while (n != head) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = (UInt32)node->NU; + for (;;) + { + CPpmd7_Node *node2 = NODE(n) + nu; + nu += node2->NU; + if (node2->Stamp != 0 || nu >= 0x10000) + break; + NODE(node2->Prev)->Next = node2->Next; + NODE(node2->Next)->Prev = node2->Prev; + node->NU = (UInt16)nu; + } + n = node->Next; + } + + /* Fill lists of free blocks */ + for (n = NODE(head)->Next; n != head;) + { + CPpmd7_Node *node = NODE(n); + unsigned nu; + CPpmd7_Node_Ref next = node->Next; + for (nu = node->NU; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + n = next; + } +} + +static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd7 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } + +static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +static void RestartModel(CPpmd7 *p) +{ + unsigned i, k, m; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 256; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = 0; i < 128; i++) + for (k = 0; k < 8; k++) + { + UInt16 *dest = p->BinSumm[i] + k; + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + for (i = 0; i < 25; i++) + for (k = 0; k < 16; k++) + { + CPpmd_See *s = &p->See[i][k]; + s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 4; + } +} + +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +{ + p->MaxOrder = maxOrder; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) +{ + CPpmd_State upState; + CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + CPpmd_State *ps[PPMD7_MAX_ORDER]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (c->NumStats != 1) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + } + else + s = ONE_STATE(c); + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + + if (c->NumStats == 1) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 1; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static void UpdateModel(CPpmd7 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State *s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State *s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + if (p->OrderFall == 0) + { + p->MinContext = p->MaxContext = CreateSuccessors(p, True); + if (p->MinContext == 0) + { + RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RestartModel(p); + return; + } + + if (fSuccessor) + { + if (fSuccessor <= successor) + { + CTX_PTR cs = CreateSuccessors(p, False); + if (cs == NULL) + { + RestartModel(p); + return; + } + fSuccessor = REF(cs); + } + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + SetSuccessor(p->FoundState, successor); + fSuccessor = REF(p->MinContext); + } + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); + + for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + unsigned oldNU = ns1 >> 1; + unsigned i = U2I(oldNU); + if (i != U2I(oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RestartModel(p); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RestartModel(p); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); + } + cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 3; + } + else + { + cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1; + SetSuccessor(s, successor); + s->Symbol = p->FoundState->Symbol; + s->Freq = (Byte)cf; + c->NumStats = (UInt16)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd7 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats - 1; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 1) + { + CPpmd_State tmp = *stats; + do + { + tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); + escFreq >>= 1; + } + while (escFreq > 1); + InsertNode(p, stats, U2I(((numStats + 1) >> 1))); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 1) >> 1; + n1 = (p->MinContext->NumStats + 1) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +{ + CPpmd_See *see; + unsigned nonMasked = p->MinContext->NumStats - numMasked; + if (p->MinContext->NumStats != 256) + { + see = p->See[p->NS2Indx[nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + + 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + + 4 * (numMasked > nonMasked) + + p->HiBitsFlag; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd7 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c > p->Text) + p->MinContext = p->MaxContext = c; + else + UpdateModel(p); +} + +void Ppmd7_Update1(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd7_Update1_0(CPpmd7 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd7_UpdateBin(CPpmd7 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd7_Update2(CPpmd7 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); +} diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7.h b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7.h new file mode 100644 index 0000000..96521c3 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7.h @@ -0,0 +1,140 @@ +/* Ppmd7.h -- PPMdH compression codec +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +/* This code supports virtual RangeDecoder and includes the implementation +of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. +If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ + +#ifndef __PPMD7_H +#define __PPMD7_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD7_MIN_ORDER 2 +#define PPMD7_MAX_ORDER 64 + +#define PPMD7_MIN_MEM_SIZE (1 << 11) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) + +struct CPpmd7_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd7_Context_ * + #else + UInt32 + #endif + CPpmd7_Context_Ref; + +typedef struct CPpmd7_Context_ +{ + UInt16 NumStats; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd7_Context_Ref Suffix; +} CPpmd7_Context; + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +typedef struct +{ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; +} CPpmd7; + +void Ppmd7_Construct(CPpmd7 *p); +Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); +void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc); +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); +#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +extern const Byte PPMD7_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd7_GetPtr(p, ptr) (ptr) + #define Ppmd7_GetContext(p, ptr) (ptr) + #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) + #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd7_Update1(CPpmd7 *p); +void Ppmd7_Update1_0(CPpmd7 *p); +void Ppmd7_Update2(CPpmd7 *p); +void Ppmd7_UpdateBin(CPpmd7 *p); + +#define Ppmd7_GetBinSumm(p) \ + &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ + p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ + (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ + 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +typedef struct +{ + UInt32 (*GetThreshold)(void *p, UInt32 total); + void (*Decode)(void *p, UInt32 start, UInt32 size); + UInt32 (*DecodeBit)(void *p, UInt32 size0); +} IPpmd7_RangeDec; + +typedef struct +{ + IPpmd7_RangeDec p; + UInt32 Range; + UInt32 Code; + IByteIn *Stream; +} CPpmd7z_RangeDec; + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); +#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) + +int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc); + + +/* ---------- Encode ---------- */ + +typedef struct +{ + UInt64 Low; + UInt32 Range; + Byte Cache; + UInt64 CacheSize; + IByteOut *Stream; +} CPpmd7z_RangeEnc; + +void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); +void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); + +void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); + +EXTERN_C_END + +#endif diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7Dec.c b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7Dec.c new file mode 100644 index 0000000..04b4b09 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd7Dec.c @@ -0,0 +1,189 @@ +/* Ppmd7Dec.c -- PPMdH Decoder +2010-03-12 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue (1 << 24) + +Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + if (p->Stream->Read((void *)p->Stream) != 0) + return False; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + return (p->Code < 0xFFFFFFFF); +} + +static UInt32 Range_GetThreshold(void *pp, UInt32 total) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + return (p->Code) / (p->Range /= total); +} + +static void Range_Normalize(CPpmd7z_RangeDec *p) +{ + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + if (p->Range < kTopValue) + { + p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); + p->Range <<= 8; + } + } +} + +static void Range_Decode(void *pp, UInt32 start, UInt32 size) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + p->Code -= start * p->Range; + p->Range *= size; + Range_Normalize(p); +} + +static UInt32 Range_DecodeBit(void *pp, UInt32 size0) +{ + CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; + UInt32 newBound = (p->Range >> 14) * size0; + UInt32 symbol; + if (p->Code < newBound) + { + symbol = 0; + p->Range = newBound; + } + else + { + symbol = 1; + p->Code -= newBound; + p->Range -= newBound; + } + Range_Normalize(p); + return symbol; +} + +void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) +{ + p->p.GetThreshold = Range_GetThreshold; + p->p.Decode = Range_Decode; + p->p.DecodeBit = Range_DecodeBit; +} + + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + rc->Decode(rc, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats - 1; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; + rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats - 1; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + if (rc->DecodeBit(rc, *prob) == 0) + { + Byte symbol; + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + Ppmd7_UpdateBin(p); + return symbol; + } + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd7_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = rc->GetThreshold(rc, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + rc->Decode(rc, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd7_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + rc->Decode(rc, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8.c b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8.c new file mode 100644 index 0000000..8beef23 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8.c @@ -0,0 +1,1122 @@ +/* Ppmd8.c -- PPMdI codec +2010-03-24 : Igor Pavlov : Public domain +This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd8.h" + +const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(nu) - 1]) +#define I2U(indx) (p->Indx2Units[indx]) + +#ifdef PPMD_32BIT + #define REF(ptr) (ptr) +#else + #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) +#endif + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) +#define STATS(ctx) Ppmd8_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd8_Context * CTX_PTR; + +struct CPpmd8_Node_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd8_Node_ * + #else + UInt32 + #endif + CPpmd8_Node_Ref; + +typedef struct CPpmd8_Node_ +{ + UInt32 Stamp; + CPpmd8_Node_Ref Next; + UInt32 NU; +} CPpmd8_Node; + +#ifdef PPMD_32BIT + #define NODE(ptr) (ptr) +#else + #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs))) +#endif + +#define EMPTY_NODE 0xFFFFFFFF + +void Ppmd8_Construct(CPpmd8 *p) +{ + unsigned i, k, m; + + p->Base = 0; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while(--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 5; i++) + p->NS2Indx[i] = (Byte)i; + for (m = i, k = 1; i < 260; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 4; + } +} + +void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->Base); + p->Size = 0; + p->Base = 0; +} + +Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc) +{ + if (p->Base == 0 || p->Size != size) + { + Ppmd8_Free(p, alloc); + p->AlignOffset = + #ifdef PPMD_32BIT + (4 - size) & 3; + #else + 4 - (size & 3); + #endif + if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size)) == 0) + return False; + p->Size = size; + } + return True; +} + +static void InsertNode(CPpmd8 *p, void *node, unsigned indx) +{ + ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; + ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; + ((CPpmd8_Node *)node)->NU = I2U(indx); + p->FreeList[indx] = REF(node); + p->Stamps[indx]++; +} + +static void *RemoveNode(CPpmd8 *p, unsigned indx) +{ + CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); + p->FreeList[indx] = node->Next; + p->Stamps[indx]--; + return node; +} + +static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + InsertNode(p, ptr, i); +} + +static void GlueFreeBlocks(CPpmd8 *p) +{ + CPpmd8_Node_Ref head = 0; + CPpmd8_Node_Ref *prev = &head; + unsigned i; + + p->GlueCount = 1 << 13; + memset(p->Stamps, 0, sizeof(p->Stamps)); + + /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end. + All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */ + if (p->LoUnit != p->HiUnit) + ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; + + /* Glue free blocks */ + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd8_Node *node = NODE(next); + if (node->NU != 0) + { + CPpmd8_Node *node2; + *prev = next; + prev = &(node->Next); + while ((node2 = node + node->NU)->Stamp == EMPTY_NODE) + { + node->NU += node2->NU; + node2->NU = 0; + } + } + next = node->Next; + } + } + *prev = 0; + + /* Fill lists of free blocks */ + while (head != 0) + { + CPpmd8_Node *node = NODE(head); + unsigned nu; + head = node->Next; + nu = node->NU; + if (nu == 0) + continue; + for (; nu > 128; nu -= 128, node += 128) + InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + InsertNode(p, node + k, nu - k - 1); + } + InsertNode(p, node, i); + } +} + +static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) +{ + unsigned i; + void *retVal; + if (p->GlueCount == 0) + { + GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + } + i = indx; + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + p->GlueCount--; + return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + retVal = RemoveNode(p, i); + SplitBlock(p, retVal, i, indx); + return retVal; +} + +static void *AllocUnits(CPpmd8 *p, unsigned indx) +{ + UInt32 numBytes; + if (p->FreeList[indx] != 0) + return RemoveNode(p, indx); + numBytes = U2B(I2U(indx)); + if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) + { + void *retVal = p->LoUnit; + p->LoUnit += numBytes; + return retVal; + } + return AllocUnitsRare(p, indx); +} + +#define MyMem12Cpy(dest, src, num) \ + { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } + +static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = RemoveNode(p, i1); + MyMem12Cpy(ptr, oldPtr, newNU); + InsertNode(p, oldPtr, i0); + return ptr; + } + SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + +static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) +{ + InsertNode(p, ptr, U2I(nu)); +} + +static void SpecialFreeUnit(CPpmd8 *p, void *ptr) +{ + if ((Byte *)ptr != p->UnitsStart) + InsertNode(p, ptr, 0); + else + { + #ifdef PPMD8_FREEZE_SUPPORT + *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */ + #endif + p->UnitsStart += UNIT_SIZE; + } +} + +static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) +{ + unsigned indx = U2I(nu); + void *ptr; + if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx]) + return oldPtr; + ptr = RemoveNode(p, indx); + MyMem12Cpy(ptr, oldPtr, nu); + if ((Byte*)oldPtr != p->UnitsStart) + InsertNode(p, oldPtr, indx); + else + p->UnitsStart += U2B(I2U(indx)); + return ptr; +} + +static void ExpandTextArea(CPpmd8 *p) +{ + UInt32 count[PPMD_NUM_INDEXES]; + unsigned i; + memset(count, 0, sizeof(count)); + if (p->LoUnit != p->HiUnit) + ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; + + { + CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart; + for (; node->Stamp == EMPTY_NODE; node += node->NU) + { + node->Stamp = 0; + count[U2I(node->NU)]++; + } + p->UnitsStart = (Byte *)node; + } + + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i]; + while (count[i] != 0) + { + CPpmd8_Node *node = NODE(*next); + while (node->Stamp == 0) + { + *next = node->Next; + node = NODE(*next); + p->Stamps[i]--; + if (--count[i] == 0) + break; + } + next = &node->Next; + } + } +} + +#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) + +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); + (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); +} + +#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } + +static void RestartModel(CPpmd8 *p) +{ + unsigned i, k, m, r; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + memset(p->Stamps, 0, sizeof(p->Stamps)); + RESET_TEXT(0); + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + p->MinContext->Suffix = 0; + p->MinContext->NumStats = 255; + p->MinContext->Flags = 0; + p->MinContext->SummFreq = 256 + 1; + p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + p->LoUnit += U2B(256 / 2); + p->MinContext->Stats = REF(p->FoundState); + for (i = 0; i < 256; i++) + { + CPpmd_State *s = &p->FoundState[i]; + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + for (i = m = 0; m < 25; m++) + { + while (p->NS2Indx[i] == m) + i++; + for (k = 0; k < 8; k++) + { + UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); + UInt16 *dest = p->BinSumm[m] + k; + for (r = 0; r < 64; r += 8) + dest[r] = val; + } + } + + for (i = m = 0; m < 24; m++) + { + while (p->NS2Indx[i + 3] == m + 3) + i++; + for (k = 0; k < 32; k++) + { + CPpmd_See *s = &p->See[m][k]; + s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4)); + s->Count = 7; + } + } +} + +void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) +{ + p->MaxOrder = maxOrder; + p->RestoreMethod = restoreMethod; + RestartModel(p); + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Count = 64; /* unused */ +} + +static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) +{ + unsigned i = ctx->NumStats, escFreq, sumFreq, flags; + CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); + ctx->Stats = REF(s); + #ifdef PPMD8_FREEZE_SUPPORT + /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */ + scale |= (ctx->SummFreq >= ((UInt32)1 << 15)); + #endif + flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); + escFreq = ctx->SummFreq - s->Freq; + sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); + do + { + escFreq -= (++s)->Freq; + sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale)); + flags |= 0x08 * (s->Symbol >= 0x40); + } + while (--i); + ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); + ctx->Flags = (Byte)flags; +} + +static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + +static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) +{ + int i; + unsigned tmp; + CPpmd_State *s; + + if (!ctx->NumStats) + { + s = ONE_STATE(ctx); + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart) + { + if (order < p->MaxOrder) + SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + if (SUCCESSOR(s) || order <= 9) /* O_BOUND */ + return REF(ctx); + } + SpecialFreeUnit(p, ctx); + return 0; + } + + ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1)); + + for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--) + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart) + { + CPpmd_State *s2 = STATS(ctx) + (i--); + SetSuccessor(s, 0); + SwapStates(s, s2); + } + else if (order < p->MaxOrder) + SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + + if (i != ctx->NumStats && order) + { + ctx->NumStats = (Byte)i; + s = STATS(ctx); + if (i < 0) + { + FreeUnits(p, s, tmp); + SpecialFreeUnit(p, ctx); + return 0; + } + if (i == 0) + { + ctx->Flags = (ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40); + *ONE_STATE(ctx) = *s; + FreeUnits(p, s, tmp); + ONE_STATE(ctx)->Freq = (Byte)((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3; + } + else + Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i); + } + return REF(ctx); +} + +#ifdef PPMD8_FREEZE_SUPPORT +static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order) +{ + CPpmd_State *s; + if (!ctx->NumStats) + { + s = ONE_STATE(ctx); + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) + SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + /* Suffix context can be removed already, since different (high-order) + Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ + if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) + { + FreeUnits(p, ctx, 1); + return 0; + } + else + return REF(ctx); + } + + for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--) + if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) + SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); + else + SetSuccessor(s, 0); + + return REF(ctx); +} +#endif + +static UInt32 GetUsedMemory(const CPpmd8 *p) +{ + UInt32 v = 0; + unsigned i; + for (i = 0; i < PPMD_NUM_INDEXES; i++) + v += p->Stamps[i] * I2U(i); + return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); +} + +#ifdef PPMD8_FREEZE_SUPPORT + #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) +#else + #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) +#endif + +static void RestoreModel(CPpmd8 *p, CTX_PTR c1 + #ifdef PPMD8_FREEZE_SUPPORT + , CTX_PTR fSuccessor + #endif + ) +{ + CTX_PTR c; + CPpmd_State *s; + RESET_TEXT(0); + for (c = p->MaxContext; c != c1; c = SUFFIX(c)) + if (--(c->NumStats) == 0) + { + s = STATS(c); + c->Flags = (c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40); + *ONE_STATE(c) = *s; + SpecialFreeUnit(p, s); + ONE_STATE(c)->Freq = (ONE_STATE(c)->Freq + 11) >> 3; + } + else + Refresh(p, c, (c->NumStats+3) >> 1, 0); + + for (; c != p->MinContext; c = SUFFIX(c)) + if (!c->NumStats) + ONE_STATE(c)->Freq -= ONE_STATE(c)->Freq >> 1; + else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats) + Refresh(p, c, (c->NumStats + 2) >> 1, 1); + + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + p->MaxContext = fSuccessor; + p->GlueCount += !(p->Stamps[1] & 1); + } + else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) + { + while (p->MaxContext->Suffix) + p->MaxContext = SUFFIX(p->MaxContext); + RemoveBinContexts(p, p->MaxContext, 0); + p->RestoreMethod++; + p->GlueCount = 0; + p->OrderFall = p->MaxOrder; + } + else + #endif + if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) + RestartModel(p); + else + { + while (p->MaxContext->Suffix) + p->MaxContext = SUFFIX(p->MaxContext); + do + { + CutOff(p, p->MaxContext, 0); + ExpandTextArea(p); + } + while (GetUsedMemory(p) > 3 * (p->Size >> 2)); + p->GlueCount = 0; + p->OrderFall = p->MaxOrder; + } +} + +static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c) +{ + CPpmd_State upState; + Byte flags; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ + CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; + unsigned numPs = 0; + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + if (s1) + { + s = s1; + s1 = NULL; + } + else if (c->NumStats != 0) + { + for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); + if (s->Freq < MAX_FREQ - 9) + { + s->Freq++; + c->SummFreq++; + } + } + else + { + s = ONE_STATE(c); + s->Freq += (!SUFFIX(c)->NumStats & (s->Freq < 24)); + } + successor = SUCCESSOR(s); + if (successor != upBranch) + { + c = CTX(successor); + if (numPs == 0) + return c; + break; + } + ps[numPs++] = s; + } + + upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch); + SetSuccessor(&upState, upBranch + 1); + flags = 0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40); + + if (c->NumStats == 0) + upState.Freq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != upState.Symbol; s++); + cf = s->Freq - 1; + s0 = c->SummFreq - c->NumStats - cf; + upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); + } + + do + { + /* Create Child */ + CTX_PTR c1; /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (CTX_PTR)RemoveNode(p, 0); + else + { + c1 = (CTX_PTR)AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->NumStats = 0; + c1->Flags = flags; + *ONE_STATE(c1) = upState; + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + +static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) +{ + CPpmd_State *s = NULL; + CTX_PTR c1 = c; + CPpmd_Void_Ref upBranch = REF(p->Text); + + #ifdef PPMD8_FREEZE_SUPPORT + /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ + CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; + unsigned numPs = 0; + ps[numPs++] = p->FoundState; + #endif + + SetSuccessor(p->FoundState, upBranch); + p->OrderFall++; + + for (;;) + { + if (s1) + { + c = SUFFIX(c); + s = s1; + s1 = NULL; + } + else + { + if (!c->Suffix) + { + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); + RESET_TEXT(1); + p->OrderFall = 1; + } + #endif + return c; + } + c = SUFFIX(c); + if (c->NumStats) + { + if ((s = STATS(c))->Symbol != p->FoundState->Symbol) + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + else + { + s = ONE_STATE(c); + s->Freq += (s->Freq < 32); + } + } + if (SUCCESSOR(s)) + break; + #ifdef PPMD8_FREEZE_SUPPORT + ps[numPs++] = s; + #endif + SetSuccessor(s, upBranch); + p->OrderFall++; + } + + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + c = CTX(SUCCESSOR(s)); + do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); + RESET_TEXT(1); + p->OrderFall = 1; + return c; + } + else + #endif + if (SUCCESSOR(s) <= upBranch) + { + CTX_PTR successor; + CPpmd_State *s1 = p->FoundState; + p->FoundState = s; + + successor = CreateSuccessors(p, False, NULL, c); + if (successor == NULL) + SetSuccessor(s, 0); + else + SetSuccessor(s, REF(successor)); + p->FoundState = s1; + } + + if (p->OrderFall == 1 && c1 == p->MaxContext) + { + SetSuccessor(p->FoundState, SUCCESSOR(s)); + p->Text--; + } + if (SUCCESSOR(s) == 0) + return NULL; + return CTX(SUCCESSOR(s)); +} + +static void UpdateModel(CPpmd8 *p) +{ + CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); + CTX_PTR c; + unsigned s0, ns, fFreq = p->FoundState->Freq; + Byte flag, fSymbol = p->FoundState->Symbol; + CPpmd_State *s = NULL; + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + c = SUFFIX(p->MinContext); + + if (c->NumStats == 0) + { + s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + s = STATS(c); + if (s->Symbol != p->FoundState->Symbol) + { + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s[0].Freq >= s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + s--; + } + } + if (s->Freq < MAX_FREQ - 9) + { + s->Freq += 2; + c->SummFreq += 2; + } + } + } + + c = p->MaxContext; + if (p->OrderFall == 0 && fSuccessor) + { + CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); + if (cs == 0) + { + SetSuccessor(p->FoundState, 0); + RESTORE_MODEL(c, CTX(fSuccessor)); + } + else + { + SetSuccessor(p->FoundState, REF(cs)); + p->MaxContext = cs; + } + return; + } + + *p->Text++ = p->FoundState->Symbol; + successor = REF(p->Text); + if (p->Text >= p->UnitsStart) + { + RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */ + return; + } + + if (!fSuccessor) + { + CTX_PTR cs = ReduceOrder(p, s, p->MinContext); + if (cs == NULL) + { + RESTORE_MODEL(c, 0); + return; + } + fSuccessor = REF(cs); + } + else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart) + { + CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); + if (cs == NULL) + { + RESTORE_MODEL(c, 0); + return; + } + fSuccessor = REF(cs); + } + + if (--p->OrderFall == 0) + { + successor = fSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + #ifdef PPMD8_FREEZE_SUPPORT + else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + successor = fSuccessor; + RESET_TEXT(0); + p->OrderFall = 0; + } + #endif + + s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq; + flag = 0x08 * (fSymbol >= 0x40); + + for (; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 cf, sf; + if ((ns1 = c->NumStats) != 0) + { + if ((ns1 & 1) != 0) + { + /* Expand for one UNIT */ + unsigned oldNU = (ns1 + 1) >> 1; + unsigned i = U2I(oldNU); + if (i != U2I(oldNU + 1)) + { + void *ptr = AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RESTORE_MODEL(c, CTX(fSuccessor)); + return; + } + oldPtr = STATS(c); + MyMem12Cpy(ptr, oldPtr, oldNU); + InsertNode(p, oldPtr, i); + c->Stats = STATS_REF(ptr); + } + } + c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns)); + } + else + { + CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); + if (!s) + { + RESTORE_MODEL(c, CTX(fSuccessor)); + return; + } + *s = *ONE_STATE(c); + c->Stats = REF(s); + if (s->Freq < MAX_FREQ / 4 - 1) + s->Freq <<= 1; + else + s->Freq = MAX_FREQ - 4; + c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 2)); + } + cf = 2 * fFreq * (c->SummFreq + 6); + sf = (UInt32)s0 + c->SummFreq; + if (cf < 6 * sf) + { + cf = 1 + (cf > sf) + (cf >= 4 * sf); + c->SummFreq += 4; + } + else + { + cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); + c->SummFreq = (UInt16)(c->SummFreq + cf); + } + { + CPpmd_State *s = STATS(c) + ns1 + 1; + SetSuccessor(s, successor); + s->Symbol = fSymbol; + s->Freq = (Byte)cf; + c->Flags |= flag; + c->NumStats = (Byte)(ns1 + 1); + } + } + p->MaxContext = p->MinContext = CTX(fSuccessor); +} + +static void Rescale(CPpmd8 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + { + CPpmd_State tmp = *s; + for (; s != stats; s--) + s[0] = s[-1]; + *s = tmp; + } + escFreq = p->MinContext->SummFreq - s->Freq; + s->Freq += 4; + adder = (p->OrderFall != 0 + #ifdef PPMD8_FREEZE_SUPPORT + || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE + #endif + ); + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq = s->Freq; + + i = p->MinContext->NumStats; + do + { + escFreq -= (++s)->Freq; + s->Freq = (Byte)((s->Freq + adder) >> 1); + sumFreq += s->Freq; + if (s[0].Freq > s[-1].Freq) + { + CPpmd_State *s1 = s; + CPpmd_State tmp = *s1; + do + s1[0] = s1[-1]; + while (--s1 != stats && tmp.Freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + unsigned numStats = p->MinContext->NumStats; + unsigned n0, n1; + do { i++; } while ((--s)->Freq == 0); + escFreq += i; + p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i); + if (p->MinContext->NumStats == 0) + { + CPpmd_State tmp = *stats; + tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq); + if (tmp.Freq > MAX_FREQ / 3) + tmp.Freq = MAX_FREQ / 3; + InsertNode(p, stats, U2I((numStats + 2) >> 1)); + p->MinContext->Flags = (p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40); + *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; + return; + } + n0 = (numStats + 2) >> 1; + n1 = (p->MinContext->NumStats + 2) >> 1; + if (n0 != n1) + p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + p->MinContext->Flags &= ~0x08; + p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40); + i = p->MinContext->NumStats; + do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i); + } + p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + p->MinContext->Flags |= 0x4; + p->FoundState = STATS(p->MinContext); +} + +CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) +{ + CPpmd_See *see; + if (p->MinContext->NumStats != 0xFF) + { + see = p->See[p->NS2Indx[p->MinContext->NumStats + 2] - 3] + + (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) + + 2 * (2 * (unsigned)p->MinContext->NumStats < + ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) + + p->MinContext->Flags; + { + unsigned r = (see->Summ >> see->Shift); + see->Summ = (UInt16)(see->Summ - r); + *escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + +static void NextContext(CPpmd8 *p) +{ + CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart) + p->MinContext = p->MaxContext = c; + else + { + UpdateModel(p); + p->MinContext = p->MaxContext; + } +} + +void Ppmd8_Update1(CPpmd8 *p) +{ + CPpmd_State *s = p->FoundState; + s->Freq += 4; + p->MinContext->SummFreq += 4; + if (s[0].Freq > s[-1].Freq) + { + SwapStates(&s[0], &s[-1]); + p->FoundState = --s; + if (s->Freq > MAX_FREQ) + Rescale(p); + } + NextContext(p); +} + +void Ppmd8_Update1_0(CPpmd8 *p) +{ + p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq); + p->RunLength += p->PrevSuccess; + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + NextContext(p); +} + +void Ppmd8_UpdateBin(CPpmd8 *p) +{ + p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196)); + p->PrevSuccess = 1; + p->RunLength++; + NextContext(p); +} + +void Ppmd8_Update2(CPpmd8 *p) +{ + p->MinContext->SummFreq += 4; + if ((p->FoundState->Freq += 4) > MAX_FREQ) + Rescale(p); + p->RunLength = p->InitRL; + UpdateModel(p); + p->MinContext = p->MaxContext; +} + +/* H->I changes: + NS2Indx + GlewCount, and Glue method + BinSum + See / EscFreq + CreateSuccessors updates more suffix contexts + UpdateModel consts. + PrevSuccess Update +*/ diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8.h b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8.h new file mode 100644 index 0000000..7dcfc91 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8.h @@ -0,0 +1,137 @@ +/* Ppmd8.h -- PPMdI codec +2011-01-27 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#ifndef __PPMD8_H +#define __PPMD8_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD8_MIN_ORDER 2 +#define PPMD8_MAX_ORDER 16 + +struct CPpmd8_Context_; + +typedef + #ifdef PPMD_32BIT + struct CPpmd8_Context_ * + #else + UInt32 + #endif + CPpmd8_Context_Ref; + +#pragma pack(push, 1) + +typedef struct CPpmd8_Context_ +{ + Byte NumStats; + Byte Flags; + UInt16 SummFreq; + CPpmd_State_Ref Stats; + CPpmd8_Context_Ref Suffix; +} CPpmd8_Context; + +#pragma pack(pop) + +#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) + +/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed + code is not compatible with original code for some files compressed + in FREEZE mode. So we disable FREEZE mode support. */ + +enum +{ + PPMD8_RESTORE_METHOD_RESTART, + PPMD8_RESTORE_METHOD_CUT_OFF + #ifdef PPMD8_FREEZE_SUPPORT + , PPMD8_RESTORE_METHOD_FREEZE + #endif +}; + +typedef struct +{ + CPpmd8_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + UInt32 AlignOffset; + unsigned RestoreMethod; + + /* Range Coder */ + UInt32 Range; + UInt32 Code; + UInt32 Low; + union + { + IByteIn *In; + IByteOut *Out; + } Stream; + + Byte Indx2Units[PPMD_NUM_INDEXES]; + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + UInt32 Stamps[PPMD_NUM_INDEXES]; + + Byte NS2BSIndx[256], NS2Indx[260]; + CPpmd_See DummySee, See[24][32]; + UInt16 BinSumm[25][64]; +} CPpmd8; + +void Ppmd8_Construct(CPpmd8 *p); +Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc); +void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc); +void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod); +#define Ppmd8_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +extern const Byte PPMD8_kExpEscape[16]; + +#ifdef PPMD_32BIT + #define Ppmd8_GetPtr(p, ptr) (ptr) + #define Ppmd8_GetContext(p, ptr) (ptr) + #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats) +#else + #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs))) + #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats))) +#endif + +void Ppmd8_Update1(CPpmd8 *p); +void Ppmd8_Update1_0(CPpmd8 *p); +void Ppmd8_Update2(CPpmd8 *p); +void Ppmd8_UpdateBin(CPpmd8 *p); + +#define Ppmd8_GetBinSumm(p) \ + &p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \ + p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ + p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)] + +CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); + + +/* ---------- Decode ---------- */ + +Bool Ppmd8_RangeDec_Init(CPpmd8 *p); +#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */ + + +/* ---------- Encode ---------- */ + +#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } +void Ppmd8_RangeEnc_FlushData(CPpmd8 *p); +void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */ + +EXTERN_C_END + +#endif diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8Dec.c b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8Dec.c new file mode 100644 index 0000000..317bd65 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/Ppmd8Dec.c @@ -0,0 +1,157 @@ +/* Ppmd8Dec.c -- PPMdI Decoder +2010-04-16 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd8.h" + +#define kTop (1 << 24) +#define kBot (1 << 15) + +Bool Ppmd8_RangeDec_Init(CPpmd8 *p) +{ + unsigned i; + p->Low = 0; + p->Range = 0xFFFFFFFF; + p->Code = 0; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); + return (p->Code < 0xFFFFFFFF); +} + +static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total) +{ + return p->Code / (p->Range /= total); +} + +static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) +{ + start *= p->Range; + p->Low += start; + p->Code -= start; + p->Range *= size; + + while ((p->Low ^ (p->Low + p->Range)) < kTop || + (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) + { + p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); + p->Range <<= 8; + p->Low <<= 8; + } +} + +#define MASK(sym) ((signed char *)charMask)[sym] + +int Ppmd8_DecodeSymbol(CPpmd8 *p) +{ + size_t charMask[256 / sizeof(size_t)]; + if (p->MinContext->NumStats != 0) + { + CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) + { + Byte symbol; + RangeDec_Decode(p, 0, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update1_0(p); + return symbol; + } + p->PrevSuccess = 0; + i = p->MinContext->NumStats; + do + { + if ((hiCnt += (++s)->Freq) > count) + { + Byte symbol; + RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update1(p); + return symbol; + } + } + while (--i); + if (count >= p->MinContext->SummFreq) + return -2; + RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt); + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(s->Symbol) = 0; + i = p->MinContext->NumStats; + do { MASK((--s)->Symbol) = 0; } while (--i); + } + else + { + UInt16 *prob = Ppmd8_GetBinSumm(p); + if (((p->Code / (p->Range >>= 14)) < *prob)) + { + Byte symbol; + RangeDec_Decode(p, 0, *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); + symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; + Ppmd8_UpdateBin(p); + return symbol; + } + RangeDec_Decode(p, *prob, (1 << 14) - *prob); + *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); + p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; + PPMD_SetAllBitsIn256Bytes(charMask); + MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + for (;;) + { + CPpmd_State *ps[256], *s; + UInt32 freqSum, count, hiCnt; + CPpmd_See *see; + unsigned i, num, numMasked = p->MinContext->NumStats; + do + { + p->OrderFall++; + if (!p->MinContext->Suffix) + return -1; + p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); + } + while (p->MinContext->NumStats == numMasked); + hiCnt = 0; + s = Ppmd8_GetStats(p, p->MinContext); + i = 0; + num = p->MinContext->NumStats - numMasked; + do + { + int k = (int)(MASK(s->Symbol)); + hiCnt += (s->Freq & k); + ps[i] = s++; + i -= k; + } + while (i != num); + + see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + count = RangeDec_GetThreshold(p, freqSum); + + if (count < hiCnt) + { + Byte symbol; + CPpmd_State **pps = ps; + for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); + s = *pps; + RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); + Ppmd_See_Update(see); + p->FoundState = s; + symbol = s->Symbol; + Ppmd8_Update2(p); + return symbol; + } + if (count >= freqSum) + return -2; + RangeDec_Decode(p, hiCnt, freqSum - hiCnt); + see->Summ = (UInt16)(see->Summ + freqSum); + do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); + } +} diff --git a/src/qtquick/karchive-rar/unarr/lzmasdk/Precomp.h b/src/qtquick/karchive-rar/unarr/lzmasdk/Precomp.h new file mode 100644 index 0000000..895bc35 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/lzmasdk/Precomp.h @@ -0,0 +1,15 @@ +/* Precomp.h -- StdAfx +2013-11-12 : Igor Pavlov : Public domain */ + +#ifndef __7Z_PRECOMP_H +#define __7Z_PRECOMP_H + +/* #include "Compiler.h" */ +#ifdef _MSC_VER +#pragma warning(disable : 4456) // declaration of * hides previous local declaration +#pragma warning(disable : 4457) // declaration of * hides function parameter +#pragma warning(disable : 4996) // This function or variable may be unsafe +#endif +/* #include "7zTypes.h" */ + +#endif diff --git a/src/qtquick/karchive-rar/unarr/rar/filter-rar.c b/src/qtquick/karchive-rar/unarr/rar/filter-rar.c new file mode 100644 index 0000000..cbb2916 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/filter-rar.c @@ -0,0 +1,704 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#include "rar.h" +#include "rarvm.h" + +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRARVirtualMachine.m */ +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRAR30Filter.m */ + +struct MemBitReader { + const uint8_t *bytes; + size_t length; + size_t offset; + uint64_t bits; + int available; + bool at_eof; +}; + +struct RARProgramCode { + RARProgram *prog; + uint8_t *staticdata; + uint32_t staticdatalen; + uint8_t *globalbackup; + uint32_t globalbackuplen; + uint64_t fingerprint; + uint32_t usagecount; + uint32_t oldfilterlength; + struct RARProgramCode *next; +}; + +struct RARFilter { + struct RARProgramCode *prog; + uint32_t initialregisters[8]; + uint8_t *globaldata; + uint32_t globaldatalen; + size_t blockstartpos; + uint32_t blocklength; + uint32_t filteredblockaddress; + uint32_t filteredblocklength; + struct RARFilter *next; +}; + +static bool br_fill(struct MemBitReader *br, int bits) +{ + while (br->available < bits && br->offset < br->length) { + br->bits = (br->bits << 8) | br->bytes[br->offset++]; + br->available += 8; + } + if (bits > br->available) { + br->at_eof = true; + return false; + } + return true; +} + +static inline uint32_t br_bits(struct MemBitReader *br, int bits) +{ + if (bits > br->available && (br->at_eof || !br_fill(br, bits))) + return 0; + return (uint32_t)((br->bits >> (br->available -= bits)) & (((uint64_t)1 << bits) - 1)); +} + +static inline bool br_available(struct MemBitReader *br, int bits) +{ + return !br->at_eof && (bits <= br->available || br_fill(br, bits)); +} + +static uint32_t br_next_rarvm_number(struct MemBitReader *br) +{ + uint32_t val; + switch (br_bits(br, 2)) { + case 0: + return br_bits(br, 4); + case 1: + val = br_bits(br, 8); + if (val >= 16) + return val; + return 0xFFFFFF00 | (val << 4) | br_bits(br, 4); + case 2: + return br_bits(br, 16); + default: + return br_bits(br, 32); + } +} + +static void bw_write32le(uint8_t *dst, uint32_t value) +{ + dst[0] = value & 0xFF; + dst[1] = (value >> 8) & 0xFF; + dst[2] = (value >> 16) & 0xFF; + dst[3] = (value >> 24) & 0xFF; +} + +static void rar_delete_program(struct RARProgramCode *prog) +{ + while (prog) { + struct RARProgramCode *next = prog->next; + RARDeleteProgram(prog->prog); + free(prog->staticdata); + free(prog->globalbackup); + free(prog); + prog = next; + } +} + +static bool rar_parse_operand(struct MemBitReader *br, uint8_t instruction, bool bytemode, uint32_t instrcount, uint8_t *addressmode, uint32_t *value) +{ + if (br_bits(br, 1)) { + *addressmode = RARRegisterAddressingMode((uint8_t)br_bits(br, 3)); + *value = 0; + } + else if (br_bits(br, 1)) { + if (br_bits(br, 1)) { + if (br_bits(br, 1)) + *addressmode = RARAbsoluteAddressingMode; + else + *addressmode = RARIndexedAbsoluteAddressingMode((uint8_t)br_bits(br, 3)); + *value = br_next_rarvm_number(br); + } + else { + *addressmode = RARRegisterIndirectAddressingMode((uint8_t)br_bits(br, 3)); + *value = 0; + } + } + else { + *addressmode = RARImmediateAddressingMode; + if (!bytemode) + *value = br_next_rarvm_number(br); + else + *value = br_bits(br, 8); + if (instrcount != (uint32_t)-1 && RARInstructionIsRelativeJump(instruction)) { + if (*value >= 256) /* absolute address */ + *value -= 256; + else { /* relative address */ + if (*value >= 136) + *value -= 264; + else if (*value >= 16) + *value -= 8; + else if (*value >= 8) + *value -= 16; + *value += instrcount; + } + } + } + return !br->at_eof; +} + +static struct RARProgramCode *rar_compile_program(const uint8_t *bytes, size_t length) +{ + struct MemBitReader br = { 0 }; + struct RARProgramCode *prog; + uint32_t instrcount = 0; + uint8_t xor; + size_t i; + + xor = 0; + for (i = 1; i < length; i++) + xor ^= bytes[i]; + if (!length || xor != bytes[0]) + return NULL; + + br.bytes = bytes; + br.length = length; + br.offset = 1; + + prog = calloc(1, sizeof(*prog)); + if (!prog) + return NULL; + prog->prog = RARCreateProgram(); + if (!prog->prog) { + rar_delete_program(prog); + return NULL; + } + prog->fingerprint = ar_crc32(0, bytes, length) | ((uint64_t)length << 32); + + if (br_bits(&br, 1)) { + prog->staticdatalen = br_next_rarvm_number(&br) + 1; + prog->staticdata = malloc(prog->staticdatalen); + if (!prog->staticdata) { + rar_delete_program(prog); + return NULL; + } + for (i = 0; i < prog->staticdatalen; i++) + prog->staticdata[i] = (uint8_t)br_bits(&br, 8); + } + + while (br_available(&br, 8)) { + bool ok = true; + uint8_t instruction = (uint8_t)br_bits(&br, 4); + bool bytemode = false; + int numargs = 0; + uint8_t addrmode1 = 0, addrmode2 = 0; + uint32_t value1 = 0, value2 = 0; + + if ((instruction & 0x08)) + instruction = ((instruction << 2) | (uint8_t)br_bits(&br, 2)) - 24; + if (RARInstructionHasByteMode(instruction)) + bytemode = br_bits(&br, 1) != 0; + ok = RARProgramAddInstr(prog->prog, instruction, bytemode); + numargs = NumberOfRARInstructionOperands(instruction); + if (ok && numargs >= 1) + ok = rar_parse_operand(&br, instruction, bytemode, instrcount, &addrmode1, &value1); + if (ok && numargs == 2) + ok = rar_parse_operand(&br, instruction, bytemode, (uint32_t)-1, &addrmode2, &value2); + if (ok) + ok = RARSetLastInstrOperands(prog->prog, addrmode1, value1, addrmode2, value2); + if (!ok) { + warn("Invalid RAR program instruction"); + rar_delete_program(prog); + return NULL; + } + instrcount++; + } + + if (!RARIsProgramTerminated(prog->prog)) { + if (!RARProgramAddInstr(prog->prog, RARRetInstruction, false)) { + rar_delete_program(prog); + return NULL; + } + } + + return prog; +} + +static bool rar_execute_filter_prog(struct RARFilter *filter, RARVirtualMachine *vm) +{ + uint32_t newgloballength; + uint32_t globallength = filter->globaldatalen; + if (globallength > RARProgramSystemGlobalSize) + globallength = RARProgramSystemGlobalSize; + memcpy(&vm->memory[RARProgramSystemGlobalAddress], filter->globaldata, globallength); + if (filter->prog->staticdata) { + uint32_t staticlength = filter->prog->staticdatalen; + if (staticlength > RARProgramUserGlobalSize - globallength) + staticlength = RARProgramUserGlobalSize - globallength; + memcpy(&vm->memory[RARProgramUserGlobalAddress], filter->prog->staticdata, staticlength); + } + RARSetVirtualMachineRegisters(vm, filter->initialregisters); + + if (!RARExecuteProgram(vm, filter->prog->prog)) { + warn("Error while executing program in RAR VM"); + return false; + } + + newgloballength = RARVirtualMachineRead32(vm, RARProgramSystemGlobalAddress + 0x30); + if (newgloballength > RARProgramUserGlobalSize) + newgloballength = RARProgramUserGlobalSize; + if (newgloballength > 0) { + uint32_t newglobaldatalength = RARProgramSystemGlobalSize + newgloballength; + if (newglobaldatalength > filter->globaldatalen) { + uint8_t *newglobaldata = malloc(newglobaldatalength); + if (!newglobaldata) + return false; + free(filter->globaldata); + filter->globaldata = newglobaldata; + } + filter->globaldatalen = newglobaldatalength; + memcpy(filter->globaldata, &vm->memory[RARProgramSystemGlobalAddress], filter->globaldatalen); + } + else + filter->globaldatalen = 0; + + return true; +} + +static struct RARFilter *rar_create_filter(struct RARProgramCode *prog, const uint8_t *globaldata, uint32_t globaldatalen, uint32_t registers[8], size_t startpos, uint32_t length) +{ + struct RARFilter *filter; + + filter = calloc(1, sizeof(*filter)); + if (!filter) + return NULL; + filter->prog = prog; + filter->globaldatalen = globaldatalen > RARProgramSystemGlobalSize ? globaldatalen : RARProgramSystemGlobalSize; + filter->globaldata = calloc(1, filter->globaldatalen); + if (!filter->globaldata) + return NULL; + if (globaldata) + memcpy(filter->globaldata, globaldata, globaldatalen); + if (registers) + memcpy(filter->initialregisters, registers, sizeof(filter->initialregisters)); + filter->blockstartpos = startpos; + filter->blocklength = length; + + return filter; +} + +static void rar_delete_filter(struct RARFilter *filter) +{ + while (filter) { + struct RARFilter *next = filter->next; + free(filter->globaldata); + free(filter); + filter = next; + } +} + +static bool rar_execute_filter_delta(struct RARFilter *filter, RARVirtualMachine *vm) +{ + uint32_t length = filter->initialregisters[4]; + uint32_t numchannels = filter->initialregisters[0]; + uint8_t *src, *dst; + uint32_t i, idx; + + if (length > RARProgramWorkSize / 2) + return false; + + src = &vm->memory[0]; + dst = &vm->memory[length]; + for (i = 0; i < numchannels; i++) { + uint8_t lastbyte = 0; + for (idx = i; idx < length; idx += numchannels) + lastbyte = dst[idx] = lastbyte - *src++; + } + + filter->filteredblockaddress = length; + filter->filteredblocklength = length; + + return true; +} + +static bool rar_execute_filter_e8(struct RARFilter *filter, RARVirtualMachine *vm, size_t pos, bool e9also) +{ + uint32_t length = filter->initialregisters[4]; + uint32_t filesize = 0x1000000; + uint32_t i; + + if (length > RARProgramWorkSize || length < 4) + return false; + + for (i = 0; i <= length - 5; i++) { + if (vm->memory[i] == 0xE8 || (e9also && vm->memory[i] == 0xE9)) { + uint32_t currpos = (uint32_t)pos + i + 1; + int32_t address = (int32_t)RARVirtualMachineRead32(vm, i + 1); + if (address < 0 && currpos >= (uint32_t)-address) + RARVirtualMachineWrite32(vm, i + 1, address + filesize); + else if (address >= 0 && (uint32_t)address < filesize) + RARVirtualMachineWrite32(vm, i + 1, address - currpos); + i += 4; + } + } + + filter->filteredblockaddress = 0; + filter->filteredblocklength = length; + + return true; +} + +static bool rar_execute_filter_rgb(struct RARFilter *filter, RARVirtualMachine *vm) +{ + uint32_t stride = filter->initialregisters[0]; + uint32_t byteoffset = filter->initialregisters[1]; + uint32_t blocklength = filter->initialregisters[4]; + uint8_t *src, *dst; + uint32_t i, j; + + if (blocklength > RARProgramWorkSize / 2 || stride > blocklength) + return false; + + src = &vm->memory[0]; + dst = &vm->memory[blocklength]; + for (i = 0; i < 3; i++) { + uint8_t byte = 0; + uint8_t *prev = dst + i - stride; + for (j = i; j < blocklength; j += 3) { + if (prev >= dst) { + uint32_t delta1 = abs(prev[3] - prev[0]); + uint32_t delta2 = abs(byte - prev[0]); + uint32_t delta3 = abs(prev[3] - prev[0] + byte - prev[0]); + if (delta1 > delta2 || delta1 > delta3) + byte = delta2 <= delta3 ? prev[3] : prev[0]; + } + byte -= *src++; + dst[j] = byte; + prev += 3; + } + } + for (i = byteoffset; i < blocklength - 2; i += 3) { + dst[i] += dst[i + 1]; + dst[i + 2] += dst[i + 1]; + } + + filter->filteredblockaddress = blocklength; + filter->filteredblocklength = blocklength; + + return true; +} + +static bool rar_execute_filter_audio(struct RARFilter *filter, RARVirtualMachine *vm) +{ + uint32_t length = filter->initialregisters[4]; + uint32_t numchannels = filter->initialregisters[0]; + uint8_t *src, *dst; + uint32_t i, j; + + if (length > RARProgramWorkSize / 2) + return false; + + src = &vm->memory[0]; + dst = &vm->memory[length]; + for (i = 0; i < numchannels; i++) { + struct AudioState state; + memset(&state, 0, sizeof(state)); + for (j = i; j < length; j += numchannels) { + int8_t delta = (int8_t)*src++; + uint8_t predbyte, byte; + int prederror; + state.delta[2] = state.delta[1]; + state.delta[1] = state.lastdelta - state.delta[0]; + state.delta[0] = state.lastdelta; + predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF; + byte = (predbyte - delta) & 0xFF; + prederror = delta << 3; + state.error[0] += abs(prederror); + state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]); + state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]); + state.error[5] += abs(prederror - state.delta[2]); state.error[6] += abs(prederror + state.delta[2]); + state.lastdelta = (int8_t)(byte - state.lastbyte); + dst[j] = state.lastbyte = byte; + if (!(state.count++ & 0x1F)) { + uint8_t k, idx = 0; + for (k = 1; k < 7; k++) { + if (state.error[k] < state.error[idx]) + idx = k; + } + memset(state.error, 0, sizeof(state.error)); + switch (idx) { + case 1: if (state.weight[0] >= -16) state.weight[0]--; break; + case 2: if (state.weight[0] < 16) state.weight[0]++; break; + case 3: if (state.weight[1] >= -16) state.weight[1]--; break; + case 4: if (state.weight[1] < 16) state.weight[1]++; break; + case 5: if (state.weight[2] >= -16) state.weight[2]--; break; + case 6: if (state.weight[2] < 16) state.weight[2]++; break; + } + } + } + } + + filter->filteredblockaddress = length; + filter->filteredblocklength = length; + + return true; +} + +static bool rar_execute_filter(struct RARFilter *filter, RARVirtualMachine *vm, size_t pos) +{ + if (filter->prog->fingerprint == 0x1D0E06077D) + return rar_execute_filter_delta(filter, vm); + if (filter->prog->fingerprint == 0x35AD576887) + return rar_execute_filter_e8(filter, vm, pos, false); + if (filter->prog->fingerprint == 0x393CD7E57E) + return rar_execute_filter_e8(filter, vm, pos, true); + if (filter->prog->fingerprint == 0x951C2C5DC8) + return rar_execute_filter_rgb(filter, vm); + if (filter->prog->fingerprint == 0xD8BC85E701) + return rar_execute_filter_audio(filter, vm); + log("Unknown parsing filter 0x%x%08x", (uint32_t)(filter->prog->fingerprint >> 32), (uint32_t)filter->prog->fingerprint); + + /* XADRAR30Filter.m @executeOnVirtualMachine claims that this is required */ + if (filter->prog->globalbackuplen > RARProgramSystemGlobalSize) { + uint8_t *newglobaldata = malloc(filter->prog->globalbackuplen); + if (newglobaldata) { + free(filter->globaldata); + filter->globaldata = newglobaldata; + filter->globaldatalen = filter->prog->globalbackuplen; + memcpy(filter->globaldata, filter->prog->globalbackup, filter->prog->globalbackuplen); + } + } + + filter->initialregisters[6] = (uint32_t)pos; + bw_write32le(&filter->globaldata[0x24], (uint32_t)pos); + bw_write32le(&filter->globaldata[0x28], (uint32_t)((uint64_t)pos >> 32)); + + if (!rar_execute_filter_prog(filter, vm)) + return false; + + filter->filteredblockaddress = RARVirtualMachineRead32(vm, RARProgramSystemGlobalAddress + 0x20) & RARProgramMemoryMask; + filter->filteredblocklength = RARVirtualMachineRead32(vm, RARProgramSystemGlobalAddress + 0x1C) & RARProgramMemoryMask; + if (filter->filteredblockaddress + filter->filteredblocklength >= RARProgramMemorySize) { + filter->filteredblockaddress = filter->filteredblocklength = 0; + return false; + } + + if (filter->globaldatalen > RARProgramSystemGlobalSize) { + uint8_t *newglobalbackup = malloc(filter->globaldatalen); + if (newglobalbackup) { + free(filter->prog->globalbackup); + filter->prog->globalbackup = newglobalbackup; + filter->prog->globalbackuplen = filter->globaldatalen; + memcpy(filter->prog->globalbackup, filter->globaldata, filter->globaldatalen); + } + } + else + filter->prog->globalbackuplen = 0; + + return true; +} + +bool rar_parse_filter(ar_archive_rar *rar, const uint8_t *bytes, uint16_t length, uint8_t flags) +{ + struct ar_archive_rar_uncomp_v3 *uncomp = &rar->uncomp.state.v3; + struct ar_archive_rar_filters *filters = &uncomp->filters; + + struct MemBitReader br = { 0 }; + struct RARProgramCode *prog; + struct RARFilter *filter, **nextfilter; + + uint32_t numprogs, num, blocklength, globaldatalen; + uint8_t *globaldata; + size_t blockstartpos; + uint32_t registers[8] = { 0 }; + uint32_t i; + + br.bytes = bytes; + br.length = length; + + numprogs = 0; + for (prog = filters->progs; prog; prog = prog->next) + numprogs++; + + if ((flags & 0x80)) { + num = br_next_rarvm_number(&br); + if (num == 0) { + rar_delete_filter(filters->stack); + filters->stack = NULL; + rar_delete_program(filters->progs); + filters->progs = NULL; + } + else + num--; + if (num > numprogs) { + warn("Invalid program number"); + return false; + } + filters->lastfilternum = num; + } + else + num = filters->lastfilternum; + + prog = filters->progs; + for (i = 0; i < num; i++) + prog = prog->next; + if (prog) + prog->usagecount++; + + blockstartpos = br_next_rarvm_number(&br) + (size_t)lzss_position(&rar->uncomp.lzss); + if ((flags & 0x40)) + blockstartpos += 258; + if ((flags & 0x20)) + blocklength = br_next_rarvm_number(&br); + else + blocklength = prog ? prog->oldfilterlength : 0; + + registers[3] = RARProgramSystemGlobalAddress; + registers[4] = blocklength; + registers[5] = prog ? prog->usagecount : 0; + registers[7] = RARProgramMemorySize; + + if ((flags & 0x10)) { + uint8_t mask = (uint8_t)br_bits(&br, 7); + for (i = 0; i < 7; i++) { + if ((mask & (1 << i))) + registers[i] = br_next_rarvm_number(&br); + } + } + + if (!prog) { + uint32_t len = br_next_rarvm_number(&br); + uint8_t *bytecode; + struct RARProgramCode **next; + + if (len == 0 || len > 0x10000) { + warn("Invalid RARVM bytecode length"); + return false; + } + bytecode = malloc(len); + if (!bytecode) + return false; + for (i = 0; i < len; i++) + bytecode[i] = (uint8_t)br_bits(&br, 8); + prog = rar_compile_program(bytecode, len); + if (!prog) { + free(bytecode); + return false; + } + free(bytecode); + next = &filters->progs; + while (*next) + next = &(*next)->next; + *next = prog; + } + prog->oldfilterlength = blocklength; + + globaldata = NULL; + globaldatalen = 0; + if ((flags & 0x08)) { + globaldatalen = br_next_rarvm_number(&br); + if (globaldatalen > RARProgramUserGlobalSize) { + warn("Invalid RARVM data length"); + return false; + } + globaldata = malloc(globaldatalen + RARProgramSystemGlobalSize); + if (!globaldata) + return false; + for (i = 0; i < globaldatalen; i++) + globaldata[i + RARProgramSystemGlobalSize] = (uint8_t)br_bits(&br, 8); + } + + if (br.at_eof) { + free(globaldata); + return false; + } + + filter = rar_create_filter(prog, globaldata, globaldatalen, registers, blockstartpos, blocklength); + free(globaldata); + if (!filter) + return false; + + for (i = 0; i < 7; i++) + bw_write32le(&filter->globaldata[i * 4], registers[i]); + bw_write32le(&filter->globaldata[0x1C], blocklength); + bw_write32le(&filter->globaldata[0x20], 0); + bw_write32le(&filter->globaldata[0x2C], prog->usagecount); + + nextfilter = &filters->stack; + while (*nextfilter) + nextfilter = &(*nextfilter)->next; + *nextfilter = filter; + + if (!filters->stack->next) + filters->filterstart = blockstartpos; + + return true; +} + +bool rar_run_filters(ar_archive_rar *rar) +{ + struct ar_archive_rar_filters *filters = &rar->uncomp.state.v3.filters; + struct RARFilter *filter = filters->stack; + size_t start = filters->filterstart; + size_t end = start + filter->blocklength; + uint32_t lastfilteraddress; + uint32_t lastfilterlength; + + filters->filterstart = SIZE_MAX; + end = (size_t)rar_expand(rar, end); + if (end != start + filter->blocklength) { + warn("Failed to expand the expected amout of bytes"); + return false; + } + + if (!filters->vm) { + filters->vm = calloc(1, sizeof(*filters->vm)); + if (!filters->vm) + return false; + } + + lzss_copy_bytes_from_window(&rar->uncomp.lzss, filters->vm->memory, start, filter->blocklength); + if (!rar_execute_filter(filter, filters->vm, rar->progress.bytes_done)) { + warn("Failed to execute parsing filter"); + return false; + } + + lastfilteraddress = filter->filteredblockaddress; + lastfilterlength = filter->filteredblocklength; + filters->stack = filter->next; + filter->next = NULL; + rar_delete_filter(filter); + + while ((filter = filters->stack) != NULL && filter->blockstartpos == filters->filterstart && filter->blocklength == lastfilterlength) { + memmove(&filters->vm->memory[0], &filters->vm->memory[lastfilteraddress], lastfilterlength); + if (!rar_execute_filter(filter, filters->vm, rar->progress.bytes_done)) { + warn("Failed to execute parsing filter"); + return false; + } + + lastfilteraddress = filter->filteredblockaddress; + lastfilterlength = filter->filteredblocklength; + filters->stack = filter->next; + filter->next = NULL; + rar_delete_filter(filter); + } + + if (filters->stack) { + if (filters->stack->blockstartpos < end) { + warn("Bad filter order"); + return false; + } + filters->filterstart = filters->stack->blockstartpos; + } + + filters->lastend = end; + filters->bytes = &filters->vm->memory[lastfilteraddress]; + filters->bytes_ready = lastfilterlength; + + return true; +} + +void rar_clear_filters(struct ar_archive_rar_filters *filters) +{ + rar_delete_filter(filters->stack); + rar_delete_program(filters->progs); + free(filters->vm); +} diff --git a/src/qtquick/karchive-rar/unarr/rar/huffman-rar.c b/src/qtquick/karchive-rar/unarr/rar/huffman-rar.c new file mode 100644 index 0000000..c77eed9 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/huffman-rar.c @@ -0,0 +1,142 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADPrefixCode.m */ + +#include "rar.h" + +bool rar_new_node(struct huffman_code *code) +{ + if (!code->tree) { + code->minlength = INT_MAX; + code->maxlength = INT_MIN; + } + if (code->numentries + 1 >= code->capacity) { + /* in my small file sample, 1024 is the value needed most often */ + int new_capacity = code->capacity ? code->capacity * 2 : 1024; + void *new_tree = calloc(new_capacity, sizeof(*code->tree)); + if (!new_tree) { + warn("OOM during decompression"); + return false; + } + memcpy(new_tree, code->tree, code->capacity * sizeof(*code->tree)); + free(code->tree); + code->tree = new_tree; + code->capacity = new_capacity; + } + code->tree[code->numentries].branches[0] = -1; + code->tree[code->numentries].branches[1] = -2; + code->numentries++; + return true; +} + +bool rar_add_value(struct huffman_code *code, int value, int codebits, int length) +{ + int lastnode, bitpos, bit; + + free(code->table); + code->table = NULL; + + if (length > code->maxlength) + code->maxlength = length; + if (length < code->minlength) + code->minlength = length; + + lastnode = 0; + for (bitpos = length - 1; bitpos >= 0; bitpos--) { + bit = (codebits >> bitpos) & 1; + if (rar_is_leaf_node(code, lastnode)) { + warn("Invalid data in bitstream"); /* prefix found */ + return false; + } + if (code->tree[lastnode].branches[bit] < 0) { + if (!rar_new_node(code)) + return false; + code->tree[lastnode].branches[bit] = code->numentries - 1; + } + lastnode = code->tree[lastnode].branches[bit]; + } + + if (code->tree[lastnode].branches[0] != -1 || code->tree[lastnode].branches[1] != -2) { + warn("Invalid data in bitstream"); /* prefix found */ + return false; + } + code->tree[lastnode].branches[0] = code->tree[lastnode].branches[1] = value; + return true; +} + +bool rar_create_code(struct huffman_code *code, uint8_t *lengths, int numsymbols) +{ + int symbolsleft = numsymbols; + int codebits = 0; + int i, j; + + if (!rar_new_node(code)) + return false; + + for (i = 1; i <= 0x0F; i++) { + for (j = 0; j < numsymbols; j++) { + if (lengths[j] != i) + continue; + if (!rar_add_value(code, j, codebits, i)) + return false; + if (--symbolsleft <= 0) + return true; + codebits++; + } + codebits <<= 1; + } + return true; +} + +static bool rar_make_table_rec(struct huffman_code *code, int node, int offset, int depth, int maxdepth) +{ + int currtablesize = 1 << (maxdepth - depth); + + if (node < 0 || code->numentries <= node) { + warn("Invalid data in bitstream"); /* invalid location to Huffman tree specified */ + return false; + } + + if (rar_is_leaf_node(code, node)) { + int i; + for (i = 0; i < currtablesize; i++) { + code->table[offset + i].length = depth; + code->table[offset + i].value = code->tree[node].branches[0]; + } + } + else if (depth == maxdepth) { + code->table[offset].length = maxdepth + 1; + code->table[offset].value = node; + } + else { + if (!rar_make_table_rec(code, code->tree[node].branches[0], offset, depth + 1, maxdepth)) + return false; + if (!rar_make_table_rec(code, code->tree[node].branches[1], offset + currtablesize / 2, depth + 1, maxdepth)) + return false; + } + return true; +} + +bool rar_make_table(struct huffman_code *code) +{ + if (code->minlength <= code->maxlength && code->maxlength <= 10) + code->tablesize = code->maxlength; + else + code->tablesize = 10; + + code->table = calloc(1ULL << code->tablesize, sizeof(*code->table)); + if (!code->table) { + warn("OOM during decompression"); + return false; + } + + return rar_make_table_rec(code, 0, 0, 0, code->tablesize); +} + +void rar_free_code(struct huffman_code *code) +{ + free(code->tree); + free(code->table); + memset(code, 0, sizeof(*code)); +} diff --git a/src/qtquick/karchive-rar/unarr/rar/lzss.h b/src/qtquick/karchive-rar/unarr/rar/lzss.h new file mode 100644 index 0000000..580fe4c --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/lzss.h @@ -0,0 +1,88 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/LZSS.h */ + +#ifndef rar_lzss_h +#define rar_lzss_h + +#include +#include +#include +#include + +#if defined(_MSC_VER) && !defined(inline) +#define inline __inline +#endif + +typedef struct { + uint8_t *window; + int mask; + int64_t position; +} LZSS; + +static inline int64_t lzss_position(LZSS *self) { return self->position; } + +static inline int lzss_mask(LZSS *self) { return self->mask; } + +static inline int lzss_size(LZSS *self) { return self->mask + 1; } + +static inline uint8_t *lzss_window_pointer(LZSS *self) { return self->window; } + +static inline int lzss_offset_for_position(LZSS *self, int64_t pos) { return (int)(pos & self->mask); } + +static inline uint8_t *lzss_window_pointer_for_position(LZSS *self, int64_t pos) { return &self->window[lzss_offset_for_position(self, pos)]; } + +static inline int lzss_current_window_offset(LZSS *self) { return lzss_offset_for_position(self, self->position); } + +static inline uint8_t *lzss_current_window_pointer(LZSS *self) { return lzss_window_pointer_for_position(self, self->position); } + +static inline int64_t lzss_next_window_edge_after_position(LZSS *self, int64_t pos) { return (pos + lzss_size(self)) & ~(int64_t)lzss_mask(self); } + +static inline int64_t lzss_next_window_edge(LZSS *self) { return lzss_next_window_edge_after_position(self, self->position); } + +static inline uint8_t lzss_get_byte_from_window(LZSS *self, int64_t pos) { return *lzss_window_pointer_for_position(self, pos); } + +static inline void lzss_emit_literal(LZSS *self, uint8_t literal) { + /* self->window[(self->position & self->mask)] = literal; */ + *lzss_current_window_pointer(self) = literal; + self->position++; +} + +static inline void lzss_emit_match(LZSS *self, int offset, int length) { + int windowoffs = lzss_current_window_offset(self); + int i; + for (i = 0; i < length; i++) { + self->window[(windowoffs + i) & lzss_mask(self)] = self->window[(windowoffs + i - offset) & lzss_mask(self)]; + } + self->position += length; +} + +static inline void lzss_copy_bytes_from_window(LZSS *self, uint8_t *buffer, int64_t startpos, int length) { + int windowoffs = lzss_offset_for_position(self, startpos); + int firstpart = lzss_size(self) - windowoffs; + if (length <= firstpart) { + /* Request fits inside window */ + memcpy(buffer, &self->window[windowoffs], length); + } + else { + /* Request wraps around window */ + memcpy(buffer, &self->window[windowoffs], firstpart); + memcpy(buffer + firstpart, &self->window[0], length - firstpart); + } +} + +static inline bool lzss_initialize(LZSS *self, int windowsize) { + self->window = malloc(windowsize); + if (!self->window) + return false; + + self->mask = windowsize - 1; /* Assume windows are power-of-two sized! */ + memset(self->window, 0, lzss_size(self)); + self->position = 0; + return true; +} + +static inline void lzss_cleanup(LZSS *self) { free(self->window); } + +#endif diff --git a/src/qtquick/karchive-rar/unarr/rar/parse-rar.c b/src/qtquick/karchive-rar/unarr/rar/parse-rar.c new file mode 100644 index 0000000..f41534c --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/parse-rar.c @@ -0,0 +1,236 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRARParser.m */ + +#include "rar.h" + +static inline uint8_t uint8le(unsigned char *data) { return data[0]; } +static inline uint16_t uint16le(unsigned char *data) { return data[0] | data[1] << 8; } +static inline uint32_t uint32le(unsigned char *data) { return data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24; } + +bool rar_parse_header(ar_archive *ar, struct rar_header *header) +{ + unsigned char header_data[7]; + size_t read = ar_read(ar->stream, header_data, sizeof(header_data)); + if (read == 0) { + ar->at_eof = true; + return false; + } + if (read < sizeof(header_data)) + return false; + + header->crc = uint16le(header_data + 0); + header->type = uint8le(header_data + 2); + header->flags = uint16le(header_data + 3); + header->size = uint16le(header_data + 5); + + header->datasize = 0; + if ((header->flags & LHD_LONG_BLOCK) || header->type == 0x74) { + unsigned char size_data[4]; + if (!(header->flags & LHD_LONG_BLOCK)) + log("File header without LHD_LONG_BLOCK set"); + read += ar_read(ar->stream, size_data, sizeof(size_data)); + if (read < sizeof(header_data) + sizeof(size_data)) + return false; + header->datasize = uint32le(size_data); + } + + if (header->size < read) { + warn("Invalid header size %d", header->size); + return false; + } + + return true; +} + +bool rar_check_header_crc(ar_archive *ar) +{ + unsigned char buffer[256]; + uint16_t crc16, size; + uint32_t crc32; + + if (!ar_seek(ar->stream, ar->entry_offset, SEEK_SET)) + return false; + if (ar_read(ar->stream, buffer, 7) != 7) + return false; + + crc16 = uint16le(buffer + 0); + size = uint16le(buffer + 5); + if (size < 7) + return false; + size -= 7; + + crc32 = ar_crc32(0, buffer + 2, 5); + while (size > 0) { + if (ar_read(ar->stream, buffer, smin(size, sizeof(buffer))) != smin(size, sizeof(buffer))) + return false; + crc32 = ar_crc32(crc32, buffer, smin(size, sizeof(buffer))); + size -= (uint16_t)smin(size, sizeof(buffer)); + } + return (crc32 & 0xFFFF) == crc16; +} + +bool rar_parse_header_entry(ar_archive_rar *rar, struct rar_header *header, struct rar_entry *entry) +{ + unsigned char data[21]; + if (ar_read(rar->super.stream, data, sizeof(data)) != sizeof(data)) + return false; + + entry->size = uint32le(data + 0); + entry->os = uint8le(data + 4); + entry->crc = uint32le(data + 5); + entry->dosdate = uint32le(data + 9); + entry->version = uint8le(data + 13); + entry->method = uint8le(data + 14); + entry->namelen = uint16le(data + 15); + entry->attrs = uint32le(data + 17); + if ((header->flags & LHD_LARGE)) { + unsigned char more_data[8]; + if (ar_read(rar->super.stream, more_data, sizeof(more_data)) != sizeof(more_data)) + return false; + header->datasize += (uint64_t)uint32le(more_data + 0); + entry->size += (uint64_t)uint32le(more_data + 4); + } + if (!ar_skip(rar->super.stream, entry->namelen)) + return false; + if ((header->flags & LHD_SALT)) { + log("Skipping LHD_SALT"); + ar_skip(rar->super.stream, 8); + } + + rar->entry.version = entry->version; + rar->entry.method = entry->method; + rar->entry.crc = entry->crc; + rar->entry.header_size = header->size; + rar->entry.solid = entry->version < 20 ? (rar->archive_flags & MHD_SOLID) : (header->flags & LHD_SOLID); + free(rar->entry.name); + rar->entry.name = NULL; + + return true; +} + +/* this seems to be what RAR considers "Unicode" */ +static char *rar_conv_unicode_to_utf8(const char *data, uint16_t len) +{ +#define Check(cond) if (!(cond)) { free(str); return NULL; } else ((void)0) + + uint8_t highbyte, flagbyte, flagbits, size, length, i; + const uint8_t *in = (uint8_t *)data + strlen(data) + 1; + const uint8_t *end_in = (uint8_t *)data + len; + char *str = calloc(len + 1, 3); + char *out = str; + char *end_out = str + len * 3; + + if (!str) + return NULL; + if (end_in - in <= 1) { + memcpy(str, data, len); + return str; + } + + highbyte = *in++; + flagbyte = 0; + flagbits = 0; + size = 0; + + while (in < end_in && out < end_out) { + if (flagbits == 0) { + flagbyte = *in++; + flagbits = 8; + } + flagbits -= 2; + switch ((flagbyte >> flagbits) & 3) { + case 0: + Check(in + 1 <= end_in); + out += ar_conv_rune_to_utf8(*in++, out, end_out - out); + size++; + break; + case 1: + Check(in + 1 <= end_in); + out += ar_conv_rune_to_utf8(((uint16_t)highbyte << 8) | *in++, out, end_out - out); + size++; + break; + case 2: + Check(in + 2 <= end_in); + out += ar_conv_rune_to_utf8(((uint16_t)*(in + 1) << 8) | *in, out, end_out - out); + in += 2; + size++; + break; + case 3: + Check(in + 1 <= end_in); + length = *in++; + if ((length & 0x80)) { + uint8_t correction = *in++; + for (i = 0; i < (length & 0x7F) + 2; i++) { + Check(size < len); + out += ar_conv_rune_to_utf8(((uint16_t)highbyte << 8) | (data[size] + (correction & 0xFF)), out, end_out - out); + size++; + } + } + else { + for (i = 0; i < (length & 0x7F) + 2; i++) { + Check(size < len); + out += ar_conv_rune_to_utf8(data[size], out, end_out - out); + size++; + } + } + break; + } + } + + return str; + +#undef Check +} + +const char *rar_get_name(ar_archive *ar) +{ + ar_archive_rar *rar = (ar_archive_rar *)ar; + if (!rar->entry.name) { + unsigned char data[21]; + uint16_t namelen; + char *name; + + struct rar_header header; + if (!ar_seek(ar->stream, ar->entry_offset, SEEK_SET)) + return NULL; + if (!rar_parse_header(ar, &header)) + return NULL; + if (ar_read(ar->stream, data, sizeof(data)) != sizeof(data)) + return NULL; + if ((header.flags & LHD_LARGE) && !ar_skip(ar->stream, 8)) + return NULL; + + namelen = uint16le(data + 15); + name = malloc(namelen + 1); + if (!name || ar_read(ar->stream, name, namelen) != namelen) { + free(name); + return NULL; + } + name[namelen] = '\0'; + + if (!(header.flags & LHD_UNICODE)) { + rar->entry.name = ar_conv_dos_to_utf8(name); + free(name); + } + else if (namelen == strlen(name)) { + rar->entry.name = name; + } + else { + rar->entry.name = rar_conv_unicode_to_utf8(name, namelen); + free(name); + } + /* normalize path separators */ + if (rar->entry.name) { + char *p = rar->entry.name; + while ((p = strchr(p, '\\')) != NULL) { + *p = '/'; + } + } + + if (!ar_seek(ar->stream, ar->entry_offset + rar->entry.header_size, SEEK_SET)) + warn("Couldn't seek back to the end of the entry header"); + } + return rar->entry.name; +} diff --git a/src/qtquick/karchive-rar/unarr/rar/rar.c b/src/qtquick/karchive-rar/unarr/rar/rar.c new file mode 100644 index 0000000..40cafcf --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/rar.c @@ -0,0 +1,223 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#include "rar.h" + +static void rar_close(ar_archive *ar) +{ + ar_archive_rar *rar = (ar_archive_rar *)ar; + free(rar->entry.name); + rar_clear_uncompress(&rar->uncomp); +} + +static bool rar_parse_entry(ar_archive *ar, off64_t offset) +{ + ar_archive_rar *rar = (ar_archive_rar *)ar; + struct rar_header header; + struct rar_entry entry; + bool out_of_order = offset != ar->entry_offset_next; + + if (!ar_seek(ar->stream, offset, SEEK_SET)) { + warn("Couldn't seek to offset %" PRIi64, offset); + return false; + } + + for (;;) { + ar->entry_offset = ar_tell(ar->stream); + ar->entry_size_uncompressed = 0; + + if (!rar_parse_header(ar, &header)) + return false; + + ar->entry_offset_next = ar->entry_offset + header.size + header.datasize; + if (ar->entry_offset_next < ar->entry_offset + header.size) { + warn("Integer overflow due to overly large data size"); + return false; + } + + switch (header.type) { + case TYPE_MAIN_HEADER: + if ((header.flags & MHD_PASSWORD)) { + warn("Encrypted archives aren't supported"); + return false; + } + ar_skip(ar->stream, 6 /* reserved data */); + if ((header.flags & MHD_ENCRYPTVER)) { + log("MHD_ENCRYPTVER is set"); + ar_skip(ar->stream, 1); + } + if ((header.flags & MHD_COMMENT)) + log("MHD_COMMENT is set"); + if (ar_tell(ar->stream) - ar->entry_offset > header.size) { + warn("Invalid RAR header size: %d", header.size); + return false; + } + rar->archive_flags = header.flags; + break; + + case TYPE_FILE_ENTRY: + if (!rar_parse_header_entry(rar, &header, &entry)) + return false; + if ((header.flags & LHD_PASSWORD)) + warn("Encrypted entries will fail to uncompress"); + if ((header.flags & LHD_DIRECTORY) == LHD_DIRECTORY) { + if (header.datasize == 0) { + log("Skipping directory entry \"%s\"", rar_get_name(ar)); + break; + } + warn("Can't skip directory entries containing data"); + } + if ((header.flags & (LHD_SPLIT_BEFORE | LHD_SPLIT_AFTER))) + warn("Splitting files isn't really supported"); + ar->entry_size_uncompressed = (size_t)entry.size; + ar->entry_filetime = ar_conv_dosdate_to_filetime(entry.dosdate); + if (!rar->entry.solid || rar->entry.method == METHOD_STORE || out_of_order) { + rar_clear_uncompress(&rar->uncomp); + memset(&rar->solid, 0, sizeof(rar->solid)); + } + else { + br_clear_leftover_bits(&rar->uncomp); + } + + rar->solid.restart = rar->entry.solid && (out_of_order || !rar->solid.part_done); + rar->solid.part_done = !ar->entry_size_uncompressed; + rar->progress.data_left = (size_t)header.datasize; + rar->progress.bytes_done = 0; + rar->progress.crc = 0; + + /* TODO: CRC checks don't always hold (claim in XADRARParser.m @readBlockHeader) */ + if (!rar_check_header_crc(ar)) + warn("Invalid header checksum @%" PRIi64, ar->entry_offset); + if (ar_tell(ar->stream) != ar->entry_offset + rar->entry.header_size) { + warn("Couldn't seek to offset %" PRIi64, ar->entry_offset + rar->entry.header_size); + return false; + } + return true; + + case TYPE_NEWSUB: + log("Skipping newsub header @%" PRIi64, ar->entry_offset); + break; + + case TYPE_END_OF_ARCHIVE: + ar->at_eof = true; + return false; + + default: + log("Unknown RAR header type %02x", header.type); + break; + } + + /* TODO: CRC checks don't always hold (claim in XADRARParser.m @readBlockHeader) */ + if (!rar_check_header_crc(ar)) + warn("Invalid header checksum @%" PRIi64, ar->entry_offset); + if (!ar_seek(ar->stream, ar->entry_offset_next, SEEK_SET)) { + warn("Couldn't seek to offset %" PRIi64, ar->entry_offset_next); + return false; + } + } +} + +static bool rar_copy_stored(ar_archive_rar *rar, void *buffer, size_t count) +{ + if (count > rar->progress.data_left) { + warn("Unexpected EOS in stored data"); + return false; + } + if (ar_read(rar->super.stream, buffer, count) != count) { + warn("Unexpected EOF in stored data"); + return false; + } + rar->progress.data_left -= count; + rar->progress.bytes_done += count; + return true; +} + +static bool rar_restart_solid(ar_archive *ar) +{ + ar_archive_rar *rar = (ar_archive_rar *)ar; + off64_t current_offset = ar->entry_offset; + log("Restarting decompression for solid entry"); + if (!ar_parse_entry_at(ar, ar->entry_offset_first)) { + ar_parse_entry_at(ar, current_offset); + return false; + } + while (ar->entry_offset < current_offset) { + size_t size = ar->entry_size_uncompressed; + rar->solid.restart = false; + while (size > 0) { + unsigned char buffer[1024]; + size_t count = smin(size, sizeof(buffer)); + if (!ar_entry_uncompress(ar, buffer, count)) { + ar_parse_entry_at(ar, current_offset); + return false; + } + size -= count; + } + if (!ar_parse_entry(ar)) { + ar_parse_entry_at(ar, current_offset); + return false; + } + } + rar->solid.restart = false; + return true; +} + +static bool rar_uncompress(ar_archive *ar, void *buffer, size_t count) +{ + ar_archive_rar *rar = (ar_archive_rar *)ar; + if (count > ar->entry_size_uncompressed - rar->progress.bytes_done) { + warn("Requesting too much data (%" PRIuPTR " < %" PRIuPTR ")", ar->entry_size_uncompressed - rar->progress.bytes_done, count); + return false; + } + if (rar->entry.method == METHOD_STORE) { + if (!rar_copy_stored(rar, buffer, count)) + return false; + } + else if (rar->entry.method == METHOD_FASTEST || rar->entry.method == METHOD_FAST || + rar->entry.method == METHOD_NORMAL || rar->entry.method == METHOD_GOOD || + rar->entry.method == METHOD_BEST) { + if (rar->solid.restart && !rar_restart_solid(ar)) { + warn("Failed to produce the required solid decompression state"); + return false; + } + if (!rar_uncompress_part(rar, buffer, count)) + return false; + } + else { + warn("Unknown compression method %#02x", rar->entry.method); + return false; + } + + rar->progress.crc = ar_crc32(rar->progress.crc, buffer, count); + if (rar->progress.bytes_done < ar->entry_size_uncompressed) + return true; + if (rar->progress.data_left) + log("Compressed block has more data than required"); + rar->solid.part_done = true; + rar->solid.size_total += rar->progress.bytes_done; + if (rar->progress.crc != rar->entry.crc) { + warn("Checksum of extracted data doesn't match"); + return false; + } + return true; +} + +ar_archive *ar_open_rar_archive(ar_stream *stream) +{ + char signature[FILE_SIGNATURE_SIZE]; + if (!ar_seek(stream, 0, SEEK_SET)) + return NULL; + if (ar_read(stream, signature, sizeof(signature)) != sizeof(signature)) + return NULL; + if (memcmp(signature, "Rar!\x1A\x07\x00", sizeof(signature)) != 0) { + if (memcmp(signature, "Rar!\x1A\x07\x01", sizeof(signature)) == 0) + warn("RAR 5 format isn't supported"); + else if (memcmp(signature, "RE~^", 4) == 0) + warn("Ancient RAR format isn't supported"); + else if (memcmp(signature, "MZ", 2) == 0 || memcmp(signature, "\x7F\x45LF", 4) == 0) + warn("SFX archives aren't supported"); + return NULL; + } + + return ar_open_archive(stream, sizeof(ar_archive_rar), rar_close, rar_parse_entry, rar_get_name, rar_uncompress, NULL, FILE_SIGNATURE_SIZE); +} diff --git a/src/qtquick/karchive-rar/unarr/rar/rar.h b/src/qtquick/karchive-rar/unarr/rar/rar.h new file mode 100644 index 0000000..0e11222 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/rar.h @@ -0,0 +1,252 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#ifndef rar_rar_h +#define rar_rar_h + +#include "../common/unarr-imp.h" + +#include "lzss.h" +#include "../lzmasdk/Ppmd7.h" +#include + +static inline size_t smin(size_t a, size_t b) { return a < b ? a : b; } + +typedef struct ar_archive_rar_s ar_archive_rar; + +/***** parse-rar *****/ + +#define FILE_SIGNATURE_SIZE 7 + +enum block_types { + TYPE_FILE_SIGNATURE = 0x72, TYPE_MAIN_HEADER = 0x73, TYPE_FILE_ENTRY = 0x74, + TYPE_NEWSUB = 0x7A, TYPE_END_OF_ARCHIVE = 0x7B, +}; + +enum archive_flags { + MHD_VOLUME = 1 << 0, MHD_COMMENT = 1 << 1, MHD_LOCK = 1 << 2, + MHD_SOLID = 1 << 3, MHD_PACK_COMMENT = 1 << 4, MHD_AV = 1 << 5, + MHD_PROTECT = 1 << 6, MHD_PASSWORD = 1 << 7, MHD_FIRSTVOLUME = 1 << 8, + MHD_ENCRYPTVER = 1 << 9, + MHD_LONG_BLOCK = 1 << 15, +}; + +enum entry_flags { + LHD_SPLIT_BEFORE = 1 << 0, LHD_SPLIT_AFTER = 1 << 1, LHD_PASSWORD = 1 << 2, + LHD_COMMENT = 1 << 3, LHD_SOLID = 1 << 4, + LHD_DIRECTORY = (1 << 5) | (1 << 6) | (1 << 7), + LHD_LARGE = 1 << 8, LHD_UNICODE = 1 << 9, LHD_SALT = 1 << 10, + LHD_VERSION = 1 << 11, LHD_EXTTIME = 1 << 12, LHD_EXTFLAGS = 1 << 13, + LHD_LONG_BLOCK = 1 << 15, +}; + +enum compression_method { + METHOD_STORE = 0x30, + METHOD_FASTEST = 0x31, METHOD_FAST = 0x32, METHOD_NORMAL = 0x33, + METHOD_GOOD = 0x34, METHOD_BEST = 0x35, +}; + +struct rar_header { + uint16_t crc; + uint8_t type; + uint16_t flags; + uint16_t size; + uint64_t datasize; +}; + +struct rar_entry { + uint64_t size; + uint8_t os; + uint32_t crc; + uint32_t dosdate; + uint8_t version; + uint8_t method; + uint16_t namelen; + uint32_t attrs; +}; + +struct ar_archive_rar_entry { + uint8_t version; + uint8_t method; + uint32_t crc; + uint16_t header_size; + bool solid; + char *name; +}; + +bool rar_parse_header(ar_archive *ar, struct rar_header *header); +bool rar_check_header_crc(ar_archive *ar); +bool rar_parse_header_entry(ar_archive_rar *rar, struct rar_header *header, struct rar_entry *entry); +const char *rar_get_name(ar_archive *ar); + +/***** filter-rar *****/ + +struct RARVirtualMachine; +struct RARProgramCode; +struct RARFilter; + +struct ar_archive_rar_filters { + struct RARVirtualMachine *vm; + struct RARProgramCode *progs; + struct RARFilter *stack; + size_t filterstart; + uint32_t lastfilternum; + size_t lastend; + uint8_t *bytes; + size_t bytes_ready; +}; + +bool rar_parse_filter(ar_archive_rar *rar, const uint8_t *bytes, uint16_t length, uint8_t flags); +bool rar_run_filters(ar_archive_rar *rar); +void rar_clear_filters(struct ar_archive_rar_filters *filters); + +/***** huffman-rar *****/ + +struct huffman_code { + struct { + int branches[2]; + } *tree; + int numentries; + int capacity; + int minlength; + int maxlength; + struct { + int length; + int value; + } *table; + int tablesize; +}; + +bool rar_new_node(struct huffman_code *code); +bool rar_add_value(struct huffman_code *code, int value, int codebits, int length); +bool rar_create_code(struct huffman_code *code, uint8_t *lengths, int numsymbols); +bool rar_make_table(struct huffman_code *code); +void rar_free_code(struct huffman_code *code); + +static inline bool rar_is_leaf_node(struct huffman_code *code, int node) { return code->tree[node].branches[0] == code->tree[node].branches[1]; } + +/***** uncompress-rar *****/ + +#define LZSS_WINDOW_SIZE 0x400000 +#define LZSS_OVERFLOW_SIZE 288 + +#define MAINCODE_SIZE 299 +#define OFFSETCODE_SIZE 60 +#define LOWOFFSETCODE_SIZE 17 +#define LENGTHCODE_SIZE 28 +#define HUFFMAN_TABLE_SIZE MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE + LENGTHCODE_SIZE + +struct ByteReader { + IByteIn super; + ar_archive_rar *rar; +}; + +struct CPpmdRAR_RangeDec { + IPpmd7_RangeDec super; + UInt32 Range; + UInt32 Code; + UInt32 Low; + IByteIn *Stream; +}; + +struct ar_archive_rar_uncomp_v3 { + struct huffman_code maincode; + struct huffman_code offsetcode; + struct huffman_code lowoffsetcode; + struct huffman_code lengthcode; + uint8_t lengthtable[HUFFMAN_TABLE_SIZE]; + uint32_t lastlength; + uint32_t lastoffset; + uint32_t oldoffset[4]; + uint32_t lastlowoffset; + uint32_t numlowoffsetrepeats; + + bool is_ppmd_block; + int ppmd_escape; + CPpmd7 ppmd7_context; + struct CPpmdRAR_RangeDec range_dec; + struct ByteReader bytein; + + struct ar_archive_rar_filters filters; +}; + +#define MAINCODE_SIZE_20 298 +#define OFFSETCODE_SIZE_20 48 +#define LENGTHCODE_SIZE_20 28 +#define HUFFMAN_TABLE_SIZE_20 4 * 257 + +struct AudioState { + int8_t weight[5]; + int16_t delta[4]; + int8_t lastdelta; + int error[11]; + int count; + uint8_t lastbyte; +}; + +struct ar_archive_rar_uncomp_v2 { + struct huffman_code maincode; + struct huffman_code offsetcode; + struct huffman_code lengthcode; + struct huffman_code audiocode[4]; + uint8_t lengthtable[HUFFMAN_TABLE_SIZE_20]; + uint32_t lastoffset; + uint32_t lastlength; + uint32_t oldoffset[4]; + uint32_t oldoffsetindex; + + bool audioblock; + uint8_t channel; + uint8_t numchannels; + struct AudioState audiostate[4]; + int8_t channeldelta; +}; + +struct ar_archive_rar_uncomp { + uint8_t version; + + LZSS lzss; + size_t bytes_ready; + bool start_new_table; + + union { + struct ar_archive_rar_uncomp_v3 v3; + struct ar_archive_rar_uncomp_v2 v2; + } state; + + struct StreamBitReader { + uint64_t bits; + int available; + bool at_eof; + } br; +}; + +bool rar_uncompress_part(ar_archive_rar *rar, void *buffer, size_t buffer_size); +int64_t rar_expand(ar_archive_rar *rar, int64_t end); +void rar_clear_uncompress(struct ar_archive_rar_uncomp *uncomp); +static inline void br_clear_leftover_bits(struct ar_archive_rar_uncomp *uncomp) { uncomp->br.available &= ~0x07; } + +/***** rar *****/ + +struct ar_archive_rar_progress { + size_t data_left; + size_t bytes_done; + uint32_t crc; +}; + +struct ar_archive_rar_solid { + size_t size_total; + bool part_done; + bool restart; +}; + +struct ar_archive_rar_s { + ar_archive super; + uint16_t archive_flags; + struct ar_archive_rar_entry entry; + struct ar_archive_rar_uncomp uncomp; + struct ar_archive_rar_progress progress; + struct ar_archive_rar_solid solid; +}; + +#endif diff --git a/src/qtquick/karchive-rar/unarr/rar/rarvm.c b/src/qtquick/karchive-rar/unarr/rar/rarvm.c new file mode 100644 index 0000000..6f738ec --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/rarvm.c @@ -0,0 +1,616 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/RARVirtualMachine.c */ + +#include "rarvm.h" +#include "../common/allocator.h" + +#include +#include + +typedef struct RAROpcode_s RAROpcode; + +struct RAROpcode_s { + uint8_t instruction; + uint8_t bytemode; + uint8_t addressingmode1; + uint8_t addressingmode2; + uint32_t value1; + uint32_t value2; +}; + +struct RARProgram_s { + RAROpcode *opcodes; + uint32_t length; + uint32_t capacity; +}; + +/* Program building */ + +RARProgram *RARCreateProgram() +{ + return calloc(1, sizeof(RARProgram)); +} + +void RARDeleteProgram(RARProgram *prog) +{ + if (prog) + free(prog->opcodes); + free(prog); +} + +bool RARProgramAddInstr(RARProgram *prog, uint8_t instruction, bool bytemode) +{ + if (instruction >= RARNumberOfInstructions) + return false; + if (bytemode && !RARInstructionHasByteMode(instruction)) + return false; + if (prog->length + 1 >= prog->capacity) { + /* in my small file sample, 16 is the value needed most often */ + uint32_t newCapacity = prog->capacity ? prog->capacity * 4 : 32; + RAROpcode *newCodes = calloc(newCapacity, sizeof(*prog->opcodes)); + if (!newCodes) + return false; + memcpy(newCodes, prog->opcodes, prog->capacity * sizeof(*prog->opcodes)); + free(prog->opcodes); + prog->opcodes = newCodes; + prog->capacity = newCapacity; + } + memset(&prog->opcodes[prog->length], 0, sizeof(prog->opcodes[prog->length])); + prog->opcodes[prog->length].instruction = instruction; + if (instruction == RARMovzxInstruction || instruction == RARMovsxInstruction) + prog->opcodes[prog->length].bytemode = 2; /* second argument only */ + else if (bytemode) + prog->opcodes[prog->length].bytemode = (1 | 2); + else + prog->opcodes[prog->length].bytemode = 0; + prog->length++; + return true; +} + +bool RARSetLastInstrOperands(RARProgram *prog, uint8_t addressingmode1, uint32_t value1, uint8_t addressingmode2, uint32_t value2) +{ + RAROpcode *opcode = &prog->opcodes[prog->length - 1]; + int numoperands; + + if (addressingmode1 >= RARNumberOfAddressingModes || addressingmode2 >= RARNumberOfAddressingModes) + return false; + if (!prog->length || opcode->addressingmode1 || opcode->value1 || opcode->addressingmode2 || opcode->value2) + return false; + + numoperands = NumberOfRARInstructionOperands(opcode->instruction); + if (numoperands == 0) + return true; + + if (addressingmode1 == RARImmediateAddressingMode && RARInstructionWritesFirstOperand(opcode->instruction)) + return false; + opcode->addressingmode1 = addressingmode1; + opcode->value1 = value1; + + if (numoperands == 2) { + if (addressingmode2 == RARImmediateAddressingMode && RARInstructionWritesSecondOperand(opcode->instruction)) + return false; + opcode->addressingmode2 = addressingmode2; + opcode->value2 = value2; + } + + return true; +} + +bool RARIsProgramTerminated(RARProgram *prog) +{ + return prog->length > 0 && RARInstructionIsUnconditionalJump(prog->opcodes[prog->length - 1].instruction); +} + +/* Execution */ + +#define EXTMACRO_BEGIN do { +#ifdef _MSC_VER +#define EXTMACRO_END } __pragma(warning(push)) __pragma(warning(disable:4127)) while (0) __pragma(warning(pop)) +#else +#define EXTMACRO_END } while (0) +#endif + +#define CarryFlag 1 +#define ZeroFlag 2 +#define SignFlag 0x80000000 + +#define SignExtend(a) ((uint32_t)((int8_t)(a))) + +static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode); +static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data); + +#define GetOperand1() _RARGetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1) +#define GetOperand2() _RARGetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2) +#define SetOperand1(data) _RARSetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1, data) +#define SetOperand2(data) _RARSetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2, data) + +#define SetFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t result = (res); flags = (result == 0 ? ZeroFlag : (result & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END +#define SetByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t result = (res); flags = (result == 0 ? ZeroFlag : (SignExtend(result) & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END +#define SetFlags(res) SetFlagsWithCarry(res, 0) + +#define SetOperand1AndFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t r = (res); SetFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END +#define SetOperand1AndByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t r = (res); SetByteFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END +#define SetOperand1AndFlags(res) EXTMACRO_BEGIN uint32_t r = (res); SetFlags(r); SetOperand1(r); EXTMACRO_END + +#define NextInstruction() { opcode++; continue; } +#define Jump(offs) { uint32_t o = (offs); if (o >= prog->length) return false; opcode = &prog->opcodes[o]; continue; } + +bool RARExecuteProgram(RARVirtualMachine *vm, RARProgram *prog) +{ + RAROpcode *opcode = prog->opcodes; + uint32_t flags = 0; + uint32_t op1, op2, carry, i; + uint32_t counter = 0; + + if (!RARIsProgramTerminated(prog)) + return false; + + while ((uint32_t)(opcode - prog->opcodes) < prog->length && counter++ < RARRuntimeMaxInstructions) { + switch (opcode->instruction) { + case RARMovInstruction: + SetOperand1(GetOperand2()); + NextInstruction(); + + case RARCmpInstruction: + op1 = GetOperand1(); + SetFlagsWithCarry(op1 - GetOperand2(), result > op1); + NextInstruction(); + + case RARAddInstruction: + op1 = GetOperand1(); + if (opcode->bytemode) + SetOperand1AndByteFlagsWithCarry((op1 + GetOperand2()) & 0xFF, result < op1); + else + SetOperand1AndFlagsWithCarry(op1 + GetOperand2(), result < op1); + NextInstruction(); + + case RARSubInstruction: + op1 = GetOperand1(); +#if 0 /* apparently not correctly implemented in the RAR VM */ + if (opcode->bytemode) + SetOperand1AndByteFlagsWithCarry((op1 - GetOperand2()) & 0xFF, result > op1); + else +#endif + SetOperand1AndFlagsWithCarry(op1 - GetOperand2(), result > op1); + NextInstruction(); + + case RARJzInstruction: + if ((flags & ZeroFlag)) + Jump(GetOperand1()); + NextInstruction(); + + case RARJnzInstruction: + if (!(flags & ZeroFlag)) + Jump(GetOperand1()); + NextInstruction(); + + case RARIncInstruction: + if (opcode->bytemode) + SetOperand1AndFlags((GetOperand1() + 1) & 0xFF); + else + SetOperand1AndFlags(GetOperand1() + 1); + NextInstruction(); + + case RARDecInstruction: + if (opcode->bytemode) + SetOperand1AndFlags((GetOperand1() - 1) & 0xFF); + else + SetOperand1AndFlags(GetOperand1() - 1); + NextInstruction(); + + case RARJmpInstruction: + Jump(GetOperand1()); + + case RARXorInstruction: + SetOperand1AndFlags(GetOperand1() ^ GetOperand2()); + NextInstruction(); + + case RARAndInstruction: + SetOperand1AndFlags(GetOperand1() & GetOperand2()); + NextInstruction(); + + case RAROrInstruction: + SetOperand1AndFlags(GetOperand1() | GetOperand2()); + NextInstruction(); + + case RARTestInstruction: + SetFlags(GetOperand1() & GetOperand2()); + NextInstruction(); + + case RARJsInstruction: + if ((flags & SignFlag)) + Jump(GetOperand1()); + NextInstruction(); + + case RARJnsInstruction: + if (!(flags & SignFlag)) + Jump(GetOperand1()); + NextInstruction(); + + case RARJbInstruction: + if ((flags & CarryFlag)) + Jump(GetOperand1()); + NextInstruction(); + + case RARJbeInstruction: + if ((flags & (CarryFlag | ZeroFlag))) + Jump(GetOperand1()); + NextInstruction(); + + case RARJaInstruction: + if (!(flags & (CarryFlag | ZeroFlag))) + Jump(GetOperand1()); + NextInstruction(); + + case RARJaeInstruction: + if (!(flags & CarryFlag)) + Jump(GetOperand1()); + NextInstruction(); + + case RARPushInstruction: + vm->registers[7] -= 4; + RARVirtualMachineWrite32(vm, vm->registers[7], GetOperand1()); + NextInstruction(); + + case RARPopInstruction: + SetOperand1(RARVirtualMachineRead32(vm, vm->registers[7])); + vm->registers[7] += 4; + NextInstruction(); + + case RARCallInstruction: + vm->registers[7] -= 4; + RARVirtualMachineWrite32(vm, vm->registers[7], (uint32_t)(opcode - prog->opcodes + 1)); + Jump(GetOperand1()); + + case RARRetInstruction: + if (vm->registers[7] >= RARProgramMemorySize) + return true; + i = RARVirtualMachineRead32(vm, vm->registers[7]); + vm->registers[7] += 4; + Jump(i); + + case RARNotInstruction: + SetOperand1(~GetOperand1()); + NextInstruction(); + + case RARShlInstruction: + op1 = GetOperand1(); + op2 = GetOperand2(); + SetOperand1AndFlagsWithCarry(op1 << op2, ((op1 << (op2 - 1)) & 0x80000000) != 0); + NextInstruction(); + + case RARShrInstruction: + op1 = GetOperand1(); + op2 = GetOperand2(); + SetOperand1AndFlagsWithCarry(op1 >> op2, ((op1 >> (op2 - 1)) & 1) != 0); + NextInstruction(); + + case RARSarInstruction: + op1 = GetOperand1(); + op2 = GetOperand2(); + SetOperand1AndFlagsWithCarry(((int32_t)op1) >> op2, ((op1 >> (op2 - 1)) & 1) != 0); + NextInstruction(); + + case RARNegInstruction: + SetOperand1AndFlagsWithCarry(-(int32_t)GetOperand1(), result != 0); + NextInstruction(); + + case RARPushaInstruction: + vm->registers[7] -= 32; + for (i = 0; i < 8; i++) + RARVirtualMachineWrite32(vm, vm->registers[7] + (7 - i) * 4, vm->registers[i]); + NextInstruction(); + + case RARPopaInstruction: + for (i = 0; i < 8; i++) + vm->registers[i] = RARVirtualMachineRead32(vm, vm->registers[7] + (7 - i) * 4); + vm->registers[7] += 32; + NextInstruction(); + + case RARPushfInstruction: + vm->registers[7] -= 4; + RARVirtualMachineWrite32(vm, vm->registers[7], flags); + NextInstruction(); + + case RARPopfInstruction: + flags = RARVirtualMachineRead32(vm, vm->registers[7]); + vm->registers[7] += 4; + NextInstruction(); + + case RARMovzxInstruction: + SetOperand1(GetOperand2()); + NextInstruction(); + + case RARMovsxInstruction: + SetOperand1(SignExtend(GetOperand2())); + NextInstruction(); + + case RARXchgInstruction: + op1 = GetOperand1(); + op2 = GetOperand2(); + SetOperand1(op2); + SetOperand2(op1); + NextInstruction(); + + case RARMulInstruction: + SetOperand1(GetOperand1() * GetOperand2()); + NextInstruction(); + + case RARDivInstruction: + op2 = GetOperand2(); + if (op2 != 0) + SetOperand1(GetOperand1() / op2); + NextInstruction(); + + case RARAdcInstruction: + op1 = GetOperand1(); + carry = (flags & CarryFlag); + if (opcode->bytemode) + SetOperand1AndFlagsWithCarry((op1 + GetOperand2() + carry) & 0xFF, result < op1 || (result == op1 && carry)); /* does not correctly set sign bit */ + else + SetOperand1AndFlagsWithCarry(op1 + GetOperand2() + carry, result < op1 || (result == op1 && carry)); + NextInstruction(); + + case RARSbbInstruction: + op1 = GetOperand1(); + carry = (flags & CarryFlag); + if (opcode->bytemode) + SetOperand1AndFlagsWithCarry((op1 - GetOperand2() - carry) & 0xFF, result > op1 || (result == op1 && carry)); /* does not correctly set sign bit */ + else + SetOperand1AndFlagsWithCarry(op1 - GetOperand2() - carry, result > op1 || (result == op1 && carry)); + NextInstruction(); + + case RARPrintInstruction: + /* TODO: ??? */ + NextInstruction(); + } + } + + return false; +} + +/* Memory and register access */ + +static uint32_t _RARRead32(const uint8_t *b) +{ + return ((uint32_t)b[3] << 24) | ((uint32_t)b[2] << 16) | ((uint32_t)b[1] << 8) | (uint32_t)b[0]; +} + +static void _RARWrite32(uint8_t *b, uint32_t n) +{ + b[3] = (n >> 24) & 0xFF; + b[2] = (n >> 16) & 0xFF; + b[1] = (n >> 8) & 0xFF; + b[0] = n & 0xFF; +} + +void RARSetVirtualMachineRegisters(RARVirtualMachine *vm, uint32_t registers[8]) +{ + if (registers) + memcpy(vm->registers, registers, sizeof(vm->registers)); + else + memset(vm->registers, 0, sizeof(vm->registers)); +} + +uint32_t RARVirtualMachineRead32(RARVirtualMachine *vm, uint32_t address) +{ + return _RARRead32(&vm->memory[address & RARProgramMemoryMask]); +} + +void RARVirtualMachineWrite32(RARVirtualMachine *vm, uint32_t address, uint32_t val) +{ + _RARWrite32(&vm->memory[address & RARProgramMemoryMask], val); +} + +uint8_t RARVirtualMachineRead8(RARVirtualMachine *vm, uint32_t address) +{ + return vm->memory[address & RARProgramMemoryMask]; +} + +void RARVirtualMachineWrite8(RARVirtualMachine *vm, uint32_t address, uint8_t val) +{ + vm->memory[address & RARProgramMemoryMask] = val; +} + +static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode) +{ + if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) { + uint32_t result = vm->registers[addressingmode % 8]; + if (bytemode) + result = result & 0xFF; + return result; + } + if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) { + if (bytemode) + return RARVirtualMachineRead8(vm, vm->registers[addressingmode % 8]); + return RARVirtualMachineRead32(vm, vm->registers[addressingmode % 8]); + } + if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) { + if (bytemode) + return RARVirtualMachineRead8(vm, value + vm->registers[addressingmode % 8]); + return RARVirtualMachineRead32(vm, value + vm->registers[addressingmode % 8]); + } + if (addressingmode == RARAbsoluteAddressingMode) { + if (bytemode) + return RARVirtualMachineRead8(vm, value); + return RARVirtualMachineRead32(vm, value); + } + /* if (addressingmode == RARImmediateAddressingMode) */ + return value; +} + +static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data) +{ + if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) { + if (bytemode) + data = data & 0xFF; + vm->registers[addressingmode % 8] = data; + } + else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) { + if (bytemode) + RARVirtualMachineWrite8(vm, vm->registers[addressingmode % 8], (uint8_t)data); + else + RARVirtualMachineWrite32(vm, vm->registers[addressingmode % 8], data); + } + else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) { + if (bytemode) + RARVirtualMachineWrite8(vm, value + vm->registers[addressingmode % 8], (uint8_t)data); + else + RARVirtualMachineWrite32(vm, value + vm->registers[addressingmode % 8], data); + } + else if (addressingmode == RARAbsoluteAddressingMode) { + if (bytemode) + RARVirtualMachineWrite8(vm, value, (uint8_t)data); + else + RARVirtualMachineWrite32(vm, value, data); + } +} + +/* Instruction properties */ + +#define RAR0OperandsFlag 0 +#define RAR1OperandFlag 1 +#define RAR2OperandsFlag 2 +#define RAROperandsFlag 3 +#define RARHasByteModeFlag 4 +#define RARIsUnconditionalJumpFlag 8 +#define RARIsRelativeJumpFlag 16 +#define RARWritesFirstOperandFlag 32 +#define RARWritesSecondOperandFlag 64 +#define RARReadsStatusFlag 128 +#define RARWritesStatusFlag 256 + +static const int InstructionFlags[RARNumberOfInstructions] = { + /*RARMovInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag, + /*RARCmpInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag, + /*RARAddInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARSubInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARJzInstruction*/ RAR1OperandFlag | RARIsUnconditionalJumpFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, + /*RARJnzInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, + /*RARIncInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARDecInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARJmpInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag, + /*RARXorInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARAndInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RAROrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARTestInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag, + /*RARJsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, + /*RARJnsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, + /*RARJbInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, + /*RARJbeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, + /*RARJaInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, + /*RARJaeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, + /*RARPushInstruction*/ RAR1OperandFlag, + /*RARPopInstruction*/ RAR1OperandFlag, + /*RARCallInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag, + /*RARRetInstruction*/ RAR0OperandsFlag | RARIsUnconditionalJumpFlag, + /*RARNotInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag, + /*RARShlInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARShrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARSarInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARNegInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, + /*RARPushaInstruction*/ RAR0OperandsFlag, + /*RARPopaInstruction*/ RAR0OperandsFlag, + /*RARPushfInstruction*/ RAR0OperandsFlag | RARReadsStatusFlag, + /*RARPopfInstruction*/ RAR0OperandsFlag | RARWritesStatusFlag, + /*RARMovzxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag, + /*RARMovsxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag, + /*RARXchgInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag | RARWritesSecondOperandFlag | RARHasByteModeFlag, + /*RARMulInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag, + /*RARDivInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag, + /*RARAdcInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag, + /*RARSbbInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag, + /*RARPrintInstruction*/ RAR0OperandsFlag +}; + +int NumberOfRARInstructionOperands(uint8_t instruction) +{ + if (instruction >= RARNumberOfInstructions) + return 0; + return InstructionFlags[instruction] & RAROperandsFlag; +} + +bool RARInstructionHasByteMode(uint8_t instruction) +{ + if (instruction >= RARNumberOfInstructions) + return false; + return (InstructionFlags[instruction] & RARHasByteModeFlag)!=0; +} + +bool RARInstructionIsUnconditionalJump(uint8_t instruction) +{ + if (instruction >= RARNumberOfInstructions) + return false; + return (InstructionFlags[instruction] & RARIsUnconditionalJumpFlag) != 0; +} + +bool RARInstructionIsRelativeJump(uint8_t instruction) +{ + if (instruction >= RARNumberOfInstructions) + return false; + return (InstructionFlags[instruction] & RARIsRelativeJumpFlag) != 0; +} + +bool RARInstructionWritesFirstOperand(uint8_t instruction) +{ + if (instruction >= RARNumberOfInstructions) + return false; + return (InstructionFlags[instruction] & RARWritesFirstOperandFlag) != 0; +} + +bool RARInstructionWritesSecondOperand(uint8_t instruction) +{ + if (instruction >= RARNumberOfInstructions) + return false; + return (InstructionFlags[instruction] & RARWritesSecondOperandFlag) != 0; +} + +/* Program debugging */ + +#ifndef NDEBUG +#include + +static void RARPrintOperand(uint8_t addressingmode, uint32_t value) +{ + if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) + printf("r%d", addressingmode % 8); + else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) + printf("@(r%d)", addressingmode % 8); + else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) + printf("@(r%d+$%02x)", addressingmode % 8, value); + else if (addressingmode == RARAbsoluteAddressingMode) + printf("@($%02x)", value); + else if (addressingmode == RARImmediateAddressingMode) + printf("$%02x", value); +} + +void RARPrintProgram(RARProgram *prog) +{ + static const char *instructionNames[RARNumberOfInstructions] = { + "Mov", "Cmp", "Add", "Sub", "Jz", "Jnz", "Inc", "Dec", "Jmp", "Xor", + "And", "Or", "Test", "Js", "Jns", "Jb", "Jbe", "Ja", "Jae", "Push", + "Pop", "Call", "Ret", "Not", "Shl", "Shr", "Sar", "Neg", "Pusha", "Popa", + "Pushf", "Popf", "Movzx", "Movsx", "Xchg", "Mul", "Div", "Adc", "Sbb", "Print", + }; + + uint32_t i; + for (i = 0; i < prog->length; i++) { + RAROpcode *opcode = &prog->opcodes[i]; + int numoperands = NumberOfRARInstructionOperands(opcode->instruction); + printf(" %02x: %s", i, instructionNames[opcode->instruction]); + if (opcode->bytemode) + printf("B"); + if (numoperands >= 1) { + printf(" "); + RARPrintOperand(opcode->addressingmode1, opcode->value1); + } + if (numoperands == 2) { + printf(", "); + RARPrintOperand(opcode->addressingmode2, opcode->value2); + } + printf("\n"); + } +} +#endif diff --git a/src/qtquick/karchive-rar/unarr/rar/rarvm.h b/src/qtquick/karchive-rar/unarr/rar/rarvm.h new file mode 100644 index 0000000..4fb0b47 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/rarvm.h @@ -0,0 +1,117 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/RARVirtualMachine.h */ + +#ifndef rar_vm_h +#define rar_vm_h + +#include +#include + +#define RARProgramMemorySize 0x40000 +#define RARProgramMemoryMask (RARProgramMemorySize - 1) +#define RARProgramWorkSize 0x3c000 +#define RARProgramGlobalSize 0x2000 +#define RARProgramSystemGlobalAddress RARProgramWorkSize +#define RARProgramSystemGlobalSize 64 +#define RARProgramUserGlobalAddress (RARProgramSystemGlobalAddress + RARProgramSystemGlobalSize) +#define RARProgramUserGlobalSize (RARProgramGlobalSize - RARProgramSystemGlobalSize) +#define RARRuntimeMaxInstructions 250000000 + +#define RARRegisterAddressingMode(n) (0 + (n)) +#define RARRegisterIndirectAddressingMode(n) (8 + (n)) +#define RARIndexedAbsoluteAddressingMode(n) (16 + (n)) +#define RARAbsoluteAddressingMode 24 +#define RARImmediateAddressingMode 25 +#define RARNumberOfAddressingModes 26 + +typedef struct RARVirtualMachine RARVirtualMachine; + +struct RARVirtualMachine { + uint32_t registers[8]; + uint8_t memory[RARProgramMemorySize + sizeof(uint32_t) /* overflow sentinel */]; +}; + +typedef struct RARProgram_s RARProgram; + +/* Program building */ + +enum { + RARMovInstruction = 0, + RARCmpInstruction = 1, + RARAddInstruction = 2, + RARSubInstruction = 3, + RARJzInstruction = 4, + RARJnzInstruction = 5, + RARIncInstruction = 6, + RARDecInstruction = 7, + RARJmpInstruction = 8, + RARXorInstruction = 9, + RARAndInstruction = 10, + RAROrInstruction = 11, + RARTestInstruction = 12, + RARJsInstruction = 13, + RARJnsInstruction = 14, + RARJbInstruction = 15, + RARJbeInstruction = 16, + RARJaInstruction = 17, + RARJaeInstruction = 18, + RARPushInstruction = 19, + RARPopInstruction = 20, + RARCallInstruction = 21, + RARRetInstruction = 22, + RARNotInstruction = 23, + RARShlInstruction = 24, + RARShrInstruction = 25, + RARSarInstruction = 26, + RARNegInstruction = 27, + RARPushaInstruction = 28, + RARPopaInstruction = 29, + RARPushfInstruction = 30, + RARPopfInstruction = 31, + RARMovzxInstruction = 32, + RARMovsxInstruction = 33, + RARXchgInstruction = 34, + RARMulInstruction = 35, + RARDivInstruction = 36, + RARAdcInstruction = 37, + RARSbbInstruction = 38, + RARPrintInstruction = 39, + RARNumberOfInstructions = 40, +}; + +RARProgram *RARCreateProgram(); +void RARDeleteProgram(RARProgram *prog); +bool RARProgramAddInstr(RARProgram *prog, uint8_t instruction, bool bytemode); +bool RARSetLastInstrOperands(RARProgram *prog, uint8_t addressingmode1, uint32_t value1, uint8_t addressingmode2, uint32_t value2); +bool RARIsProgramTerminated(RARProgram *prog); + +/* Execution */ + +bool RARExecuteProgram(RARVirtualMachine *vm, RARProgram *prog); + +/* Memory and register access (convenience) */ + +void RARSetVirtualMachineRegisters(RARVirtualMachine *vm, uint32_t registers[8]); +uint32_t RARVirtualMachineRead32(RARVirtualMachine *vm, uint32_t address); +void RARVirtualMachineWrite32(RARVirtualMachine *vm, uint32_t address, uint32_t val); +uint8_t RARVirtualMachineRead8(RARVirtualMachine *vm, uint32_t address); +void RARVirtualMachineWrite8(RARVirtualMachine *vm, uint32_t address, uint8_t val); + +/* Instruction properties */ + +int NumberOfRARInstructionOperands(uint8_t instruction); +bool RARInstructionHasByteMode(uint8_t instruction); +bool RARInstructionIsUnconditionalJump(uint8_t instruction); +bool RARInstructionIsRelativeJump(uint8_t instruction); +bool RARInstructionWritesFirstOperand(uint8_t instruction); +bool RARInstructionWritesSecondOperand(uint8_t instruction); + +/* Program debugging */ + +#ifndef NDEBUG +void RARPrintProgram(RARProgram *prog); +#endif + +#endif diff --git a/src/qtquick/karchive-rar/unarr/rar/uncompress-rar.c b/src/qtquick/karchive-rar/unarr/rar/uncompress-rar.c new file mode 100644 index 0000000..74c2ea6 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/rar/uncompress-rar.c @@ -0,0 +1,1038 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRAR30Handle.m */ +/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRAR20Handle.m */ + +#include "rar.h" + +static void *gSzAlloc_Alloc(void *self, size_t size) { (void)self; return malloc(size); } +static void gSzAlloc_Free(void *self, void *ptr) { (void)self; free(ptr); } +static ISzAlloc gSzAlloc = { gSzAlloc_Alloc, gSzAlloc_Free }; + +static bool br_fill(ar_archive_rar *rar, int bits) +{ + uint8_t bytes[8]; + int count, i; + /* read as many bits as possible */ + count = (64 - rar->uncomp.br.available) / 8; + if (rar->progress.data_left < (size_t)count) + count = (int)rar->progress.data_left; + + if (bits > rar->uncomp.br.available + 8 * count || ar_read(rar->super.stream, bytes, count) != (size_t)count) { + if (!rar->uncomp.br.at_eof) { + warn("Unexpected EOF during decompression (truncated file?)"); + rar->uncomp.br.at_eof = true; + } + return false; + } + rar->progress.data_left -= count; + for (i = 0; i < count; i++) { + rar->uncomp.br.bits = (rar->uncomp.br.bits << 8) | bytes[i]; + } + rar->uncomp.br.available += 8 * count; + return true; +} + +static inline bool br_check(ar_archive_rar *rar, int bits) +{ + return bits <= rar->uncomp.br.available || br_fill(rar, bits); +} + +static inline uint64_t br_bits(ar_archive_rar *rar, int bits) +{ + return (rar->uncomp.br.bits >> (rar->uncomp.br.available -= bits)) & (((uint64_t)1 << bits) - 1); +} + +static Byte ByteIn_Read(void *p) +{ + struct ByteReader *self = p; + return br_check(self->rar, 8) ? (Byte)br_bits(self->rar, 8) : 0xFF; +} + +static void ByteIn_CreateVTable(struct ByteReader *br, ar_archive_rar *rar) +{ + br->super.Read = ByteIn_Read; + br->rar = rar; +} + +/* Ppmd7 range decoder differs between 7z and RAR */ +static void PpmdRAR_RangeDec_Init(struct CPpmdRAR_RangeDec *p) +{ + int i; + p->Code = 0; + p->Low = 0; + p->Range = 0xFFFFFFFF; + for (i = 0; i < 4; i++) { + p->Code = (p->Code << 8) | p->Stream->Read(p->Stream); + } +} + +static UInt32 Range_GetThreshold(void *p, UInt32 total) +{ + struct CPpmdRAR_RangeDec *self = p; + return self->Code / (self->Range /= total); +} + +static void Range_Decode_RAR(void *p, UInt32 start, UInt32 size) +{ + struct CPpmdRAR_RangeDec *self = p; + self->Low += start * self->Range; + self->Code -= start * self->Range; + self->Range *= size; + for (;;) { + if ((self->Low ^ (self->Low + self->Range)) >= (1 << 24)) { + if (self->Range >= (1 << 15)) + break; + self->Range = ((uint32_t)(-(int32_t)self->Low)) & ((1 << 15) - 1); + } + self->Code = (self->Code << 8) | self->Stream->Read(self->Stream); + self->Range <<= 8; + self->Low <<= 8; + } +} + +static UInt32 Range_DecodeBit_RAR(void *p, UInt32 size0) +{ + UInt32 value = Range_GetThreshold(p, PPMD_BIN_SCALE); + UInt32 bit = value < size0 ? 0 : 1; + if (!bit) + Range_Decode_RAR(p, 0, size0); + else + Range_Decode_RAR(p, size0, PPMD_BIN_SCALE - size0); + return bit; +} + +static void PpmdRAR_RangeDec_CreateVTable(struct CPpmdRAR_RangeDec *p, IByteIn *stream) +{ + p->super.GetThreshold = Range_GetThreshold; + p->super.Decode = Range_Decode_RAR; + p->super.DecodeBit = Range_DecodeBit_RAR; + p->Stream = stream; +} + +static bool rar_init_uncompress(struct ar_archive_rar_uncomp *uncomp, uint8_t version) +{ + /* per XADRARParser.m @handleForSolidStreamWithObject these versions are identical */ + if (version == 29 || version == 36) + version = 3; + else if (version == 20 || version == 26) + version = 2; + else { + warn("Unsupported compression version: %d", version); + return false; + } + if (uncomp->version) { + if (uncomp->version != version) { + warn("Compression version mismatch: %d != %d", version, uncomp->version); + return false; + } + return true; + } + memset(uncomp, 0, sizeof(*uncomp)); + uncomp->start_new_table = true; + if (!lzss_initialize(&uncomp->lzss, LZSS_WINDOW_SIZE)) { + warn("OOM during decompression"); + return false; + } + if (version == 3) { + uncomp->state.v3.ppmd_escape = 2; + uncomp->state.v3.filters.filterstart = SIZE_MAX; + } + uncomp->version = version; + return true; +} + +static void rar_free_codes(struct ar_archive_rar_uncomp *uncomp); + +void rar_clear_uncompress(struct ar_archive_rar_uncomp *uncomp) +{ + if (!uncomp->version) + return; + rar_free_codes(uncomp); + lzss_cleanup(&uncomp->lzss); + if (uncomp->version == 3) { + Ppmd7_Free(&uncomp->state.v3.ppmd7_context, &gSzAlloc); + rar_clear_filters(&uncomp->state.v3.filters); + } + uncomp->version = 0; +} + +static int rar_read_next_symbol(ar_archive_rar *rar, struct huffman_code *code) +{ + int node = 0; + + if (!code->table && !rar_make_table(code)) + return -1; + + /* performance optimization */ + if (code->tablesize <= rar->uncomp.br.available) { + uint16_t bits = (uint16_t)br_bits(rar, code->tablesize); + int length = code->table[bits].length; + int value = code->table[bits].value; + + if (length < 0) { + warn("Invalid data in bitstream"); /* invalid prefix code in bitstream */ + return -1; + } + if (length <= code->tablesize) { + /* Skip only length bits */ + rar->uncomp.br.available += code->tablesize - length; + return value; + } + + node = value; + } + + while (!rar_is_leaf_node(code, node)) { + uint8_t bit; + if (!br_check(rar, 1)) + return -1; + bit = (uint8_t)br_bits(rar, 1); + if (code->tree[node].branches[bit] < 0) { + warn("Invalid data in bitstream"); /* invalid prefix code in bitstream */ + return -1; + } + node = code->tree[node].branches[bit]; + } + + return code->tree[node].branches[0]; +} + +/***** RAR version 2 decompression *****/ + +static void rar_free_codes_v2(struct ar_archive_rar_uncomp_v2 *uncomp_v2) +{ + int i; + rar_free_code(&uncomp_v2->maincode); + rar_free_code(&uncomp_v2->offsetcode); + rar_free_code(&uncomp_v2->lengthcode); + for (i = 0; i < 4; i++) + rar_free_code(&uncomp_v2->audiocode[i]); +} + +static bool rar_parse_codes_v2(ar_archive_rar *rar) +{ + struct ar_archive_rar_uncomp_v2 *uncomp_v2 = &rar->uncomp.state.v2; + struct huffman_code precode; + uint8_t prelengths[19]; + uint16_t i, count; + int j, val, n; + bool ok = false; + + rar_free_codes_v2(uncomp_v2); + + if (!br_check(rar, 2)) + return false; + uncomp_v2->audioblock = br_bits(rar, 1) != 0; + if (!br_bits(rar, 1)) + memset(uncomp_v2->lengthtable, 0, sizeof(uncomp_v2->lengthtable)); + + if (uncomp_v2->audioblock) { + if (!br_check(rar, 2)) + return false; + uncomp_v2->numchannels = (uint8_t)br_bits(rar, 2) + 1; + count = uncomp_v2->numchannels * 257; + if (uncomp_v2->channel > uncomp_v2->numchannels) + uncomp_v2->channel = 0; + } + else + count = MAINCODE_SIZE_20 + OFFSETCODE_SIZE_20 + LENGTHCODE_SIZE_20; + + for (i = 0; i < 19; i++) { + if (!br_check(rar, 4)) + return false; + prelengths[i] = (uint8_t)br_bits(rar, 4); + } + + memset(&precode, 0, sizeof(precode)); + if (!rar_create_code(&precode, prelengths, 19)) + goto PrecodeError; + for (i = 0; i < count; ) { + val = rar_read_next_symbol(rar, &precode); + if (val < 0) + goto PrecodeError; + if (val < 16) { + uncomp_v2->lengthtable[i] = (uncomp_v2->lengthtable[i] + val) & 0x0F; + i++; + } + else if (val == 16) { + if (i == 0) { + warn("Invalid data in bitstream"); + goto PrecodeError; + } + if (!br_check(rar, 2)) + goto PrecodeError; + n = (uint8_t)br_bits(rar, 2) + 3; + for (j = 0; j < n && i < count; i++, j++) { + uncomp_v2->lengthtable[i] = uncomp_v2->lengthtable[i - 1]; + } + } + else { + if (val == 17) { + if (!br_check(rar, 3)) + goto PrecodeError; + n = (uint8_t)br_bits(rar, 3) + 3; + } + else { + if (!br_check(rar, 7)) + goto PrecodeError; + n = (uint8_t)br_bits(rar, 7) + 11; + } + for (j = 0; j < n && i < count; i++, j++) { + uncomp_v2->lengthtable[i] = 0; + } + } + } + ok = true; +PrecodeError: + rar_free_code(&precode); + if (!ok) + return false; + + if (uncomp_v2->audioblock) { + for (i = 0; i < uncomp_v2->numchannels; i++) { + if (!rar_create_code(&uncomp_v2->audiocode[i], uncomp_v2->lengthtable + i * 257, 257)) + return false; + } + } + else { + if (!rar_create_code(&uncomp_v2->maincode, uncomp_v2->lengthtable, MAINCODE_SIZE_20)) + return false; + if (!rar_create_code(&uncomp_v2->offsetcode, uncomp_v2->lengthtable + MAINCODE_SIZE_20, OFFSETCODE_SIZE_20)) + return false; + if (!rar_create_code(&uncomp_v2->lengthcode, uncomp_v2->lengthtable + MAINCODE_SIZE_20 + OFFSETCODE_SIZE_20, LENGTHCODE_SIZE_20)) + return false; + } + + rar->uncomp.start_new_table = false; + return true; +} + +static uint8_t rar_decode_audio(struct AudioState *state, int8_t *channeldelta, int8_t delta) +{ + uint8_t predbyte, byte; + int prederror; + + state->delta[3] = state->delta[2]; + state->delta[2] = state->delta[1]; + state->delta[1] = state->lastdelta - state->delta[0]; + state->delta[0] = state->lastdelta; + + predbyte = ((8 * state->lastbyte + state->weight[0] * state->delta[0] + state->weight[1] * state->delta[1] + state->weight[2] * state->delta[2] + state->weight[3] * state->delta[3] + state->weight[4] * *channeldelta) >> 3) & 0xFF; + byte = (predbyte - delta) & 0xFF; + + prederror = delta << 3; + state->error[0] += abs(prederror); + state->error[1] += abs(prederror - state->delta[0]); state->error[2] += abs(prederror + state->delta[0]); + state->error[3] += abs(prederror - state->delta[1]); state->error[4] += abs(prederror + state->delta[1]); + state->error[5] += abs(prederror - state->delta[2]); state->error[6] += abs(prederror + state->delta[2]); + state->error[7] += abs(prederror - state->delta[3]); state->error[8] += abs(prederror + state->delta[3]); + state->error[9] += abs(prederror - *channeldelta); state->error[10] += abs(prederror + *channeldelta); + + *channeldelta = state->lastdelta = (int8_t)(byte - state->lastbyte); + state->lastbyte = byte; + + if (!(++state->count & 0x1F)) { + uint8_t i, idx = 0; + for (i = 1; i < 11; i++) { + if (state->error[i] < state->error[idx]) + idx = i; + } + memset(state->error, 0, sizeof(state->error)); + + switch (idx) { + case 1: if (state->weight[0] >= -16) state->weight[0]--; break; + case 2: if (state->weight[0] < 16) state->weight[0]++; break; + case 3: if (state->weight[1] >= -16) state->weight[1]--; break; + case 4: if (state->weight[1] < 16) state->weight[1]++; break; + case 5: if (state->weight[2] >= -16) state->weight[2]--; break; + case 6: if (state->weight[2] < 16) state->weight[2]++; break; + case 7: if (state->weight[3] >= -16) state->weight[3]--; break; + case 8: if (state->weight[3] < 16) state->weight[3]++; break; + case 9: if (state->weight[4] >= -16) state->weight[4]--; break; + case 10: if (state->weight[4] < 16) state->weight[4]++; break; + } + } + + return byte; +} + +int64_t rar_expand_v2(ar_archive_rar *rar, int64_t end) +{ + static const uint8_t lengthbases[] = + { 0, 1, 2, 3, 4, 5, 6, + 7, 8, 10, 12, 14, 16, 20, + 24, 28, 32, 40, 48, 56, 64, + 80, 96, 112, 128, 160, 192, 224 }; + static const uint8_t lengthbits[] = + { 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 2, 2, + 2, 2, 3, 3, 3, 3, 4, + 4, 4, 4, 5, 5, 5, 5 }; + static const int32_t offsetbases[] = + { 0, 1, 2, 3, 4, 6, + 8, 12, 16, 24, 32, 48, + 64, 96, 128, 192, 256, 384, + 512, 768, 1024, 1536, 2048, 3072, + 4096, 6144, 8192, 12288, 16384, 24576, + 32768, 49152, 65536, 98304, 131072, 196608, + 262144, 327680, 393216, 458752, 524288, 589824, + 655360, 720896, 786432, 851968, 917504, 983040 }; + static const uint8_t offsetbits[] = + { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; + static const uint8_t shortbases[] = + { 0, 4, 8, 16, 32, 64, 128, 192 }; + static const uint8_t shortbits[] = + { 2, 2, 3, 4, 5, 6, 6, 6 }; + + struct ar_archive_rar_uncomp_v2 *uncomp_v2 = &rar->uncomp.state.v2; + LZSS *lzss = &rar->uncomp.lzss; + int symbol, offs, len; + + if ((uint64_t)end > rar->super.entry_size_uncompressed + rar->solid.size_total) + end = rar->super.entry_size_uncompressed + rar->solid.size_total; + + for (;;) { + if (lzss_position(lzss) >= end) + return end; + + if (uncomp_v2->audioblock) { + uint8_t byte; + symbol = rar_read_next_symbol(rar, &uncomp_v2->audiocode[uncomp_v2->channel]); + if (symbol < 0) + return -1; + if (symbol == 256) { + rar->uncomp.start_new_table = true; + return lzss_position(lzss); + } + byte = rar_decode_audio(&uncomp_v2->audiostate[uncomp_v2->channel], &uncomp_v2->channeldelta, (int8_t)(uint8_t)symbol); + uncomp_v2->channel++; + if (uncomp_v2->channel == uncomp_v2->numchannels) + uncomp_v2->channel = 0; + lzss_emit_literal(lzss, byte); + continue; + } + + symbol = rar_read_next_symbol(rar, &uncomp_v2->maincode); + if (symbol < 0) + return -1; + if (symbol < 256) { + lzss_emit_literal(lzss, (uint8_t)symbol); + continue; + } + if (symbol == 256) { + offs = uncomp_v2->lastoffset; + len = uncomp_v2->lastlength; + } + else if (symbol <= 260) { + int idx = symbol - 256; + int lensymbol = rar_read_next_symbol(rar, &uncomp_v2->lengthcode); + offs = uncomp_v2->oldoffset[(uncomp_v2->oldoffsetindex - idx) & 0x03]; + if (lensymbol < 0 || lensymbol > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || lensymbol > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) { + warn("Invalid data in bitstream"); + return -1; + } + len = lengthbases[lensymbol] + 2; + if (lengthbits[lensymbol] > 0) { + if (!br_check(rar, lengthbits[lensymbol])) + return -1; + len += (uint8_t)br_bits(rar, lengthbits[lensymbol]); + } + if (offs >= 0x40000) + len++; + if (offs >= 0x2000) + len++; + if (offs >= 0x101) + len++; + } + else if (symbol <= 268) { + int idx = symbol - 261; + offs = shortbases[idx] + 1; + if (shortbits[idx] > 0) { + if (!br_check(rar, shortbits[idx])) + return -1; + offs += (uint8_t)br_bits(rar, shortbits[idx]); + } + len = 2; + } + else if (symbol == 269) { + rar->uncomp.start_new_table = true; + return lzss_position(lzss); + } + else { + int idx = symbol - 270; + int offssymbol; + if (idx > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || idx > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) { + warn("Invalid data in bitstream"); + return -1; + } + len = lengthbases[idx] + 3; + if (lengthbits[idx] > 0) { + if (!br_check(rar, lengthbits[idx])) + return -1; + len += (uint8_t)br_bits(rar, lengthbits[idx]); + } + offssymbol = rar_read_next_symbol(rar, &uncomp_v2->offsetcode); + if (offssymbol < 0 || offssymbol > (int)(sizeof(offsetbases) / sizeof(offsetbases[0])) || offssymbol > (int)(sizeof(offsetbits) / sizeof(offsetbits[0]))) { + warn("Invalid data in bitstream"); + return -1; + } + offs = offsetbases[offssymbol] + 1; + if (offsetbits[offssymbol] > 0) { + if (!br_check(rar, offsetbits[offssymbol])) + return -1; + offs += (int)br_bits(rar, offsetbits[offssymbol]); + } + if (offs >= 0x40000) + len++; + if (offs >= 0x2000) + len++; + } + + uncomp_v2->lastoffset = uncomp_v2->oldoffset[uncomp_v2->oldoffsetindex++ & 0x03] = offs; + uncomp_v2->lastlength = len; + + lzss_emit_match(lzss, offs, len); + } +} + +/***** RAR version 3 decompression *****/ + +static void rar_free_codes(struct ar_archive_rar_uncomp *uncomp) +{ + struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &uncomp->state.v3; + + if (uncomp->version == 2) { + rar_free_codes_v2(&uncomp->state.v2); + return; + } + + rar_free_code(&uncomp_v3->maincode); + rar_free_code(&uncomp_v3->offsetcode); + rar_free_code(&uncomp_v3->lowoffsetcode); + rar_free_code(&uncomp_v3->lengthcode); +} + +static bool rar_parse_codes(ar_archive_rar *rar) +{ + struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3; + + if (rar->uncomp.version == 2) + return rar_parse_codes_v2(rar); + + rar_free_codes(&rar->uncomp); + + br_clear_leftover_bits(&rar->uncomp); + + if (!br_check(rar, 1)) + return false; + uncomp_v3->is_ppmd_block = br_bits(rar, 1) != 0; + if (uncomp_v3->is_ppmd_block) { + uint8_t ppmd_flags; + uint32_t max_alloc = 0; + + if (!br_check(rar, 7)) + return false; + ppmd_flags = (uint8_t)br_bits(rar, 7); + if ((ppmd_flags & 0x20)) { + if (!br_check(rar, 8)) + return false; + max_alloc = ((uint8_t)br_bits(rar, 8) + 1) << 20; + } + if ((ppmd_flags & 0x40)) { + if (!br_check(rar, 8)) + return false; + uncomp_v3->ppmd_escape = (uint8_t)br_bits(rar, 8); + } + if ((ppmd_flags & 0x20)) { + uint32_t maxorder = (ppmd_flags & 0x1F) + 1; + if (maxorder == 1) + return false; + if (maxorder > 16) + maxorder = 16 + (maxorder - 16) * 3; + + Ppmd7_Free(&uncomp_v3->ppmd7_context, &gSzAlloc); + Ppmd7_Construct(&uncomp_v3->ppmd7_context); + if (!Ppmd7_Alloc(&uncomp_v3->ppmd7_context, max_alloc, &gSzAlloc)) { + warn("OOM during decompression"); + return false; + } + ByteIn_CreateVTable(&uncomp_v3->bytein, rar); + PpmdRAR_RangeDec_CreateVTable(&uncomp_v3->range_dec, &uncomp_v3->bytein.super); + PpmdRAR_RangeDec_Init(&uncomp_v3->range_dec); + Ppmd7_Init(&uncomp_v3->ppmd7_context, maxorder); + } + else { + if (!Ppmd7_WasAllocated(&uncomp_v3->ppmd7_context)) { + warn("Invalid data in bitstream"); /* invalid PPMd sequence */ + return false; + } + PpmdRAR_RangeDec_Init(&uncomp_v3->range_dec); + } + } + else { + struct huffman_code precode; + uint8_t bitlengths[20]; + uint8_t zerocount; + int i, j, val, n; + bool ok = false; + + if (!br_check(rar, 1)) + return false; + if (!br_bits(rar, 1)) + memset(uncomp_v3->lengthtable, 0, sizeof(uncomp_v3->lengthtable)); + memset(&bitlengths, 0, sizeof(bitlengths)); + for (i = 0; i < sizeof(bitlengths); i++) { + if (!br_check(rar, 4)) + return false; + bitlengths[i] = (uint8_t)br_bits(rar, 4); + if (bitlengths[i] == 0x0F) { + if (!br_check(rar, 4)) + return false; + zerocount = (uint8_t)br_bits(rar, 4); + if (zerocount) { + for (j = 0; j < zerocount + 2 && i < sizeof(bitlengths); j++) { + bitlengths[i++] = 0; + } + i--; + } + } + } + + memset(&precode, 0, sizeof(precode)); + if (!rar_create_code(&precode, bitlengths, sizeof(bitlengths))) + goto PrecodeError; + for (i = 0; i < HUFFMAN_TABLE_SIZE; ) { + val = rar_read_next_symbol(rar, &precode); + if (val < 0) + goto PrecodeError; + if (val < 16) { + uncomp_v3->lengthtable[i] = (uncomp_v3->lengthtable[i] + val) & 0x0F; + i++; + } + else if (val < 18) { + if (i == 0) { + warn("Invalid data in bitstream"); + goto PrecodeError; + } + if (val == 16) { + if (!br_check(rar, 3)) + goto PrecodeError; + n = (uint8_t)br_bits(rar, 3) + 3; + } + else { + if (!br_check(rar, 7)) + goto PrecodeError; + n = (uint8_t)br_bits(rar, 7) + 11; + } + for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; i++, j++) { + uncomp_v3->lengthtable[i] = uncomp_v3->lengthtable[i - 1]; + } + } + else { + if (val == 18) { + if (!br_check(rar, 3)) + goto PrecodeError; + n = (uint8_t)br_bits(rar, 3) + 3; + } + else { + if (!br_check(rar, 7)) + goto PrecodeError; + n = (uint8_t)br_bits(rar, 7) + 11; + } + for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; i++, j++) { + uncomp_v3->lengthtable[i] = 0; + } + } + } + ok = true; +PrecodeError: + rar_free_code(&precode); + if (!ok) + return false; + + if (!rar_create_code(&uncomp_v3->maincode, uncomp_v3->lengthtable, MAINCODE_SIZE)) + return false; + if (!rar_create_code(&uncomp_v3->offsetcode, uncomp_v3->lengthtable + MAINCODE_SIZE, OFFSETCODE_SIZE)) + return false; + if (!rar_create_code(&uncomp_v3->lowoffsetcode, uncomp_v3->lengthtable + MAINCODE_SIZE + OFFSETCODE_SIZE, LOWOFFSETCODE_SIZE)) + return false; + if (!rar_create_code(&uncomp_v3->lengthcode, uncomp_v3->lengthtable + MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE, LENGTHCODE_SIZE)) + return false; + } + + rar->uncomp.start_new_table = false; + return true; +} + +static bool rar_read_filter(ar_archive_rar *rar, bool (* decode_byte)(ar_archive_rar *rar, uint8_t *byte), int64_t *end) +{ + uint8_t flags, val, *code; + uint16_t length, i; + + if (!decode_byte(rar, &flags)) + return false; + length = (flags & 0x07) + 1; + if (length == 7) { + if (!decode_byte(rar, &val)) + return false; + length = val + 7; + } + else if (length == 8) { + if (!decode_byte(rar, &val)) + return false; + length = val << 8; + if (!decode_byte(rar, &val)) + return false; + length |= val; + } + + code = malloc(length); + if (!code) { + warn("OOM during decompression"); + return false; + } + for (i = 0; i < length; i++) { + if (!decode_byte(rar, &code[i])) { + free(code); + return false; + } + } + if (!rar_parse_filter(rar, code, length, flags)) { + free(code); + return false; + } + free(code); + + if (rar->uncomp.state.v3.filters.filterstart < (size_t)*end) + *end = rar->uncomp.state.v3.filters.filterstart; + + return true; +} + +static inline bool rar_decode_ppmd7_symbol(struct ar_archive_rar_uncomp_v3 *uncomp_v3, Byte *symbol) +{ + int value = Ppmd7_DecodeSymbol(&uncomp_v3->ppmd7_context, &uncomp_v3->range_dec.super); + if (value < 0) { + warn("Invalid data in bitstream"); /* invalid PPMd symbol */ + return false; + } + *symbol = (Byte)value; + return true; +} + +static bool rar_decode_byte(ar_archive_rar *rar, uint8_t *byte) +{ + if (!br_check(rar, 8)) + return false; + *byte = (uint8_t)br_bits(rar, 8); + return true; +} + +static bool rar_decode_ppmd7_byte(ar_archive_rar *rar, uint8_t *byte) +{ + return rar_decode_ppmd7_symbol(&rar->uncomp.state.v3, byte); +} + +static bool rar_handle_ppmd_sequence(ar_archive_rar *rar, int64_t *end) +{ + struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3; + LZSS *lzss = &rar->uncomp.lzss; + Byte sym, code, length; + int lzss_offset; + + if (!rar_decode_ppmd7_symbol(uncomp_v3, &sym)) + return false; + if (sym != uncomp_v3->ppmd_escape) { + lzss_emit_literal(lzss, sym); + return true; + } + + if (!rar_decode_ppmd7_symbol(uncomp_v3, &code)) + return false; + switch (code) { + case 0: + return rar_parse_codes(rar); + + case 2: + rar->uncomp.start_new_table = true; + return true; + + case 3: + return rar_read_filter(rar, rar_decode_ppmd7_byte, end); + + case 4: + if (!rar_decode_ppmd7_symbol(uncomp_v3, &code)) + return false; + lzss_offset = code << 16; + if (!rar_decode_ppmd7_symbol(uncomp_v3, &code)) + return false; + lzss_offset |= code << 8; + if (!rar_decode_ppmd7_symbol(uncomp_v3, &code)) + return false; + lzss_offset |= code; + if (!rar_decode_ppmd7_symbol(uncomp_v3, &length)) + return false; + lzss_emit_match(lzss, lzss_offset + 2, length + 32); + return true; + + case 5: + if (!rar_decode_ppmd7_symbol(uncomp_v3, &length)) + return false; + lzss_emit_match(lzss, 1, length + 4); + return true; + + default: + lzss_emit_literal(lzss, sym); + return true; + } +} + +int64_t rar_expand(ar_archive_rar *rar, int64_t end) +{ + static const uint8_t lengthbases[] = + { 0, 1, 2, 3, 4, 5, 6, + 7, 8, 10, 12, 14, 16, 20, + 24, 28, 32, 40, 48, 56, 64, + 80, 96, 112, 128, 160, 192, 224 }; + static const uint8_t lengthbits[] = + { 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 2, 2, + 2, 2, 3, 3, 3, 3, 4, + 4, 4, 4, 5, 5, 5, 5 }; + static const int32_t offsetbases[] = + { 0, 1, 2, 3, 4, 6, + 8, 12, 16, 24, 32, 48, + 64, 96, 128, 192, 256, 384, + 512, 768, 1024, 1536, 2048, 3072, + 4096, 6144, 8192, 12288, 16384, 24576, + 32768, 49152, 65536, 98304, 131072, 196608, + 262144, 327680, 393216, 458752, 524288, 589824, + 655360, 720896, 786432, 851968, 917504, 983040, + 1048576, 1310720, 1572864, 1835008, 2097152, 2359296, + 2621440, 2883584, 3145728, 3407872, 3670016, 3932160 }; + static const uint8_t offsetbits[] = + { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 }; + static const uint8_t shortbases[] = + { 0, 4, 8, 16, 32, 64, 128, 192 }; + static const uint8_t shortbits[] = + { 2, 2, 3, 4, 5, 6, 6, 6 }; + + struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3; + LZSS *lzss = &rar->uncomp.lzss; + int symbol, offs, len, i; + + if (rar->uncomp.version == 2) + return rar_expand_v2(rar, end); + + for (;;) { + if (lzss_position(lzss) >= end) + return end; + + if (uncomp_v3->is_ppmd_block) { + if (!rar_handle_ppmd_sequence(rar, &end)) + return -1; + if (rar->uncomp.start_new_table) + return lzss_position(lzss); + continue; + } + + symbol = rar_read_next_symbol(rar, &uncomp_v3->maincode); + if (symbol < 0) + return -1; + if (symbol < 256) { + lzss_emit_literal(lzss, (uint8_t)symbol); + continue; + } + if (symbol == 256) { + if (!br_check(rar, 1)) + return -1; + if (!br_bits(rar, 1)) { + if (!br_check(rar, 1)) + return -1; + rar->uncomp.start_new_table = br_bits(rar, 1) != 0; + return lzss_position(lzss); + } + if (!rar_parse_codes(rar)) + return -1; + continue; + } + if (symbol == 257) { + if (!rar_read_filter(rar, rar_decode_byte, &end)) + return -1; + continue; + } + if (symbol == 258) { + if (uncomp_v3->lastlength == 0) + continue; + offs = uncomp_v3->lastoffset; + len = uncomp_v3->lastlength; + } + else if (symbol <= 262) { + int idx = symbol - 259; + int lensymbol = rar_read_next_symbol(rar, &uncomp_v3->lengthcode); + offs = uncomp_v3->oldoffset[idx]; + if (lensymbol < 0 || lensymbol > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || lensymbol > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) { + warn("Invalid data in bitstream"); + return -1; + } + len = lengthbases[lensymbol] + 2; + if (lengthbits[lensymbol] > 0) { + if (!br_check(rar, lengthbits[lensymbol])) + return -1; + len += (uint8_t)br_bits(rar, lengthbits[lensymbol]); + } + for (i = idx; i > 0; i--) + uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1]; + uncomp_v3->oldoffset[0] = offs; + } + else if (symbol <= 270) { + int idx = symbol - 263; + offs = shortbases[idx] + 1; + if (shortbits[idx] > 0) { + if (!br_check(rar, shortbits[idx])) + return -1; + offs += (uint8_t)br_bits(rar, shortbits[idx]); + } + len = 2; + for (i = 3; i > 0; i--) + uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1]; + uncomp_v3->oldoffset[0] = offs; + } + else { + int idx = symbol - 271; + int offssymbol; + if (idx > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || idx > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) { + warn("Invalid data in bitstream"); + return -1; + } + len = lengthbases[idx] + 3; + if (lengthbits[idx] > 0) { + if (!br_check(rar, lengthbits[idx])) + return -1; + len += (uint8_t)br_bits(rar, lengthbits[idx]); + } + offssymbol = rar_read_next_symbol(rar, &uncomp_v3->offsetcode); + if (offssymbol < 0 || offssymbol > (int)(sizeof(offsetbases) / sizeof(offsetbases[0])) || offssymbol > (int)(sizeof(offsetbits) / sizeof(offsetbits[0]))) { + warn("Invalid data in bitstream"); + return -1; + } + offs = offsetbases[offssymbol] + 1; + if (offsetbits[offssymbol] > 0) { + if (offssymbol > 9) { + if (offsetbits[offssymbol] > 4) { + if (!br_check(rar, offsetbits[offssymbol] - 4)) + return -1; + offs += (int)br_bits(rar, offsetbits[offssymbol] - 4) << 4; + } + if (uncomp_v3->numlowoffsetrepeats > 0) { + uncomp_v3->numlowoffsetrepeats--; + offs += uncomp_v3->lastlowoffset; + } + else { + int lowoffsetsymbol = rar_read_next_symbol(rar, &uncomp_v3->lowoffsetcode); + if (lowoffsetsymbol < 0) + return -1; + if (lowoffsetsymbol == 16) { + uncomp_v3->numlowoffsetrepeats = 15; + offs += uncomp_v3->lastlowoffset; + } + else { + offs += lowoffsetsymbol; + uncomp_v3->lastlowoffset = lowoffsetsymbol; + } + } + } + else { + if (!br_check(rar, offsetbits[offssymbol])) + return -1; + offs += (int)br_bits(rar, offsetbits[offssymbol]); + } + } + + if (offs >= 0x40000) + len++; + if (offs >= 0x2000) + len++; + + for (i = 3; i > 0; i--) + uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1]; + uncomp_v3->oldoffset[0] = offs; + } + + uncomp_v3->lastoffset = offs; + uncomp_v3->lastlength = len; + + lzss_emit_match(lzss, offs, len); + } +} + +bool rar_uncompress_part(ar_archive_rar *rar, void *buffer, size_t buffer_size) +{ + struct ar_archive_rar_uncomp *uncomp = &rar->uncomp; + struct ar_archive_rar_uncomp_v3 *uncomp_v3 = NULL; + size_t end; + + if (!rar_init_uncompress(uncomp, rar->entry.version)) + return false; + if (uncomp->version == 3) + uncomp_v3 = &uncomp->state.v3; + + for (;;) { + if (uncomp_v3 && uncomp_v3->filters.bytes_ready > 0) { + size_t count = smin(uncomp_v3->filters.bytes_ready, buffer_size); + memcpy(buffer, uncomp_v3->filters.bytes, count); + uncomp_v3->filters.bytes_ready -= count; + uncomp_v3->filters.bytes += count; + rar->progress.bytes_done += count; + buffer_size -= count; + buffer = (uint8_t *)buffer + count; + if (rar->progress.bytes_done == rar->super.entry_size_uncompressed) + goto FinishBlock; + } + else if (uncomp->bytes_ready > 0) { + int count = (int)smin(uncomp->bytes_ready, buffer_size); + lzss_copy_bytes_from_window(&uncomp->lzss, buffer, rar->progress.bytes_done + rar->solid.size_total, count); + uncomp->bytes_ready -= count; + rar->progress.bytes_done += count; + buffer_size -= count; + buffer = (uint8_t *)buffer + count; + } + if (buffer_size == 0) + return true; + + if (uncomp->br.at_eof) + return false; + + if (uncomp_v3 && uncomp_v3->filters.lastend == uncomp_v3->filters.filterstart) { + if (!rar_run_filters(rar)) + return false; + continue; + } + +FinishBlock: + if (uncomp->start_new_table && !rar_parse_codes(rar)) + return false; + + end = rar->progress.bytes_done + rar->solid.size_total + LZSS_WINDOW_SIZE - LZSS_OVERFLOW_SIZE; + if (uncomp_v3 && uncomp_v3->filters.filterstart < end) + end = uncomp_v3->filters.filterstart; + end = (size_t)rar_expand(rar, end); + if (end == (size_t)-1 || end < rar->progress.bytes_done + rar->solid.size_total) + return false; + uncomp->bytes_ready = end - rar->progress.bytes_done - rar->solid.size_total; + if (uncomp_v3) + uncomp_v3->filters.lastend = end; + + if (uncomp_v3 && uncomp_v3->is_ppmd_block && uncomp->start_new_table) + goto FinishBlock; + } +} diff --git a/src/qtquick/karchive-rar/unarr/unarr.h b/src/qtquick/karchive-rar/unarr/unarr.h new file mode 100644 index 0000000..5ef7447 --- /dev/null +++ b/src/qtquick/karchive-rar/unarr/unarr.h @@ -0,0 +1,94 @@ +/* Copyright 2015 the unarr project authors (see AUTHORS file). + License: LGPLv3 */ + +#ifndef unarr_h +#define unarr_h + +#include +#include +#include +typedef int64_t off64_t; +typedef int64_t time64_t; + +#define UNARR_API_VERSION 100 + +/***** common/stream *****/ + +typedef struct ar_stream_s ar_stream; + +/* opens a read-only stream for the given file path; returns NULL on error */ +ar_stream *ar_open_file(const char *path); +#ifdef _WIN32 +ar_stream *ar_open_file_w(const wchar_t *path); +#endif +/* opens a read-only stream for the given chunk of memory; the pointer must be valid until ar_close is called */ +ar_stream *ar_open_memory(const void *data, size_t datalen); +#ifdef _WIN32 +typedef struct IStream IStream; +/* opens a read-only stream based on the given IStream */ +ar_stream *ar_open_istream(IStream *stream); +#endif + +/* closes the stream and releases underlying resources */ +void ar_close(ar_stream *stream); +/* tries to read 'count' bytes into buffer, advancing the read offset pointer; returns the actual number of bytes read */ +size_t ar_read(ar_stream *stream, void *buffer, size_t count); +/* moves the read offset pointer (same as fseek); returns false on failure */ +bool ar_seek(ar_stream *stream, off64_t offset, int origin); +/* shortcut for ar_seek(stream, count, SEEK_CUR); returns false on failure */ +bool ar_skip(ar_stream *stream, off64_t count); +/* returns the current read offset (or 0 on error) */ +off64_t ar_tell(ar_stream *stream); + +/***** common/unarr *****/ + +typedef struct ar_archive_s ar_archive; + +/* frees all data stored for the given archive; does not close the underlying stream */ +void ar_close_archive(ar_archive *ar); +/* reads the next archive entry; returns false on error or at the end of the file (use ar_at_eof to distinguish the two cases) */ +bool ar_parse_entry(ar_archive *ar); +/* reads the archive entry at the given offset as returned by ar_entry_get_offset (offset 0 always restarts at the first entry); should always succeed */ +bool ar_parse_entry_at(ar_archive *ar, off64_t offset); +/* reads the (first) archive entry associated with the given name; returns false if the entry couldn't be found */ +bool ar_parse_entry_for(ar_archive *ar, const char *entry_name); +/* returns whether the last ar_parse_entry call has reached the file's expected end */ +bool ar_at_eof(ar_archive *ar); + +/* returns the name of the current entry as UTF-8 string; this pointer is only valid until the next call to ar_parse_entry; returns NULL on failure */ +const char *ar_entry_get_name(ar_archive *ar); +/* returns the stream offset of the current entry for use with ar_parse_entry_at */ +off64_t ar_entry_get_offset(ar_archive *ar); +/* returns the total size of uncompressed data of the current entry; read exactly that many bytes using ar_entry_uncompress */ +size_t ar_entry_get_size(ar_archive *ar); +/* returns the stored modification date of the current entry in 100ns since 1601/01/01 */ +time64_t ar_entry_get_filetime(ar_archive *ar); +/* WARNING: don't manually seek in the stream between ar_parse_entry and the last corresponding ar_entry_uncompress call! */ +/* uncompresses the next 'count' bytes of the current entry into buffer; returns false on error */ +bool ar_entry_uncompress(ar_archive *ar, void *buffer, size_t count); + +/* copies at most 'count' bytes of the archive's global comment (if any) into buffer; returns the actual amout of bytes copied (or, if 'buffer' is NULL, the required buffer size) */ +size_t ar_get_global_comment(ar_archive *ar, void *buffer, size_t count); + +/***** rar/rar *****/ + +/* checks whether 'stream' could contain RAR data and prepares for archive listing/extraction; returns NULL on failure */ +ar_archive *ar_open_rar_archive(ar_stream *stream); + +/***** tar/tar *****/ + +/* checks whether 'stream' could contain TAR data and prepares for archive listing/extraction; returns NULL on failure */ +ar_archive *ar_open_tar_archive(ar_stream *stream); + +/***** zip/zip *****/ + +/* checks whether 'stream' could contain ZIP data and prepares for archive listing/extraction; returns NULL on failure */ +/* set deflatedonly for extracting XPS, EPUB, etc. documents where non-Deflate compression methods are not supported by specification */ +ar_archive *ar_open_zip_archive(ar_stream *stream, bool deflatedonly); + +/***** _7z/_7z *****/ + +/* checks whether 'stream' could contain 7Z data and prepares for archive listing/extraction; returns NULL on failure */ +ar_archive *ar_open_7z_archive(ar_stream *stream); + +#endif