mirror of
https://gitlab.gnome.org/GNOME/evince
synced 2024-06-30 22:54:23 +00:00
unarr: Remove obsolete unarr copy/paste
RAR support is now in libarchive. Closes: #848, #1396
This commit is contained in:
parent
e25912b3a2
commit
d97fdcda6e
|
@ -3,7 +3,6 @@ cut_n_paste_inc = include_directories('.')
|
|||
subdir('gimpcellrenderertoggle')
|
||||
subdir('libdazzle')
|
||||
subdir('libgd')
|
||||
subdir('unarr')
|
||||
|
||||
if not external_synctex
|
||||
subdir('synctex')
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
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
|
|
@ -1,165 +0,0 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
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.
|
|
@ -1,29 +0,0 @@
|
|||
/* Copyright 2015 the unarr project authors (see AUTHORS file).
|
||||
License: LGPLv3 */
|
||||
|
||||
#ifndef common_allocator_h
|
||||
#define common_allocator_h
|
||||
|
||||
#ifdef USE_CUSTOM_ALLOCATOR
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
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 <crtdbg.h>
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,96 +0,0 @@
|
|||
/* Copyright 2015 the unarr project authors (see AUTHORS file).
|
||||
License: LGPLv3 */
|
||||
|
||||
#include "unarr-imp.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/* 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 <zlib.h>
|
||||
|
||||
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
|
|
@ -1,217 +0,0 @@
|
|||
/* Copyright 2015 the unarr project authors (see AUTHORS file).
|
||||
License: LGPLv3 */
|
||||
|
||||
#include "unarr-imp.h"
|
||||
|
||||
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 <windows.h>
|
||||
|
||||
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
|
|
@ -1,81 +0,0 @@
|
|||
/* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/***** 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
|
|
@ -1,110 +0,0 @@
|
|||
/* 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);
|
||||
}
|
||||
|
||||
__attribute__((__format__ (__printf__, 4, 0)))
|
||||
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);
|
||||
}
|
|
@ -1,525 +0,0 @@
|
|||
/* 7zTypes.h -- Basic types
|
||||
2021-12-25 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_TYPES_H
|
||||
#define __7Z_TYPES_H
|
||||
|
||||
#ifdef _WIN32
|
||||
/* #include <windows.h> */
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#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 _MSC_VER
|
||||
#if _MSC_VER > 1200
|
||||
#define MY_ALIGN(n) __declspec(align(n))
|
||||
#else
|
||||
#define MY_ALIGN(n)
|
||||
#endif
|
||||
#else
|
||||
#define MY_ALIGN(n) __attribute__ ((aligned(n)))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* typedef DWORD WRes; */
|
||||
typedef unsigned WRes;
|
||||
#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x)
|
||||
|
||||
// #define MY_HRES_ERROR__INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR)
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
// #define ENV_HAVE_LSTAT
|
||||
typedef int WRes;
|
||||
|
||||
// (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT
|
||||
#define MY__FACILITY_ERRNO 0x800
|
||||
#define MY__FACILITY_WIN32 7
|
||||
#define MY__FACILITY__WRes MY__FACILITY_ERRNO
|
||||
|
||||
#define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \
|
||||
( (HRESULT)(x) & 0x0000FFFF) \
|
||||
| (MY__FACILITY__WRes << 16) \
|
||||
| (HRESULT)0x80000000 ))
|
||||
|
||||
#define MY_SRes_HRESULT_FROM_WRes(x) \
|
||||
((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x))
|
||||
|
||||
// we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno)
|
||||
#define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x)
|
||||
|
||||
/*
|
||||
#define ERROR_FILE_NOT_FOUND 2L
|
||||
#define ERROR_ACCESS_DENIED 5L
|
||||
#define ERROR_NO_MORE_FILES 18L
|
||||
#define ERROR_LOCK_VIOLATION 33L
|
||||
#define ERROR_FILE_EXISTS 80L
|
||||
#define ERROR_DISK_FULL 112L
|
||||
#define ERROR_NEGATIVE_SEEK 131L
|
||||
#define ERROR_ALREADY_EXISTS 183L
|
||||
#define ERROR_DIRECTORY 267L
|
||||
#define ERROR_TOO_MANY_POSTS 298L
|
||||
|
||||
#define ERROR_INTERNAL_ERROR 1359L
|
||||
#define ERROR_INVALID_REPARSE_DATA 4392L
|
||||
#define ERROR_REPARSE_TAG_INVALID 4393L
|
||||
#define ERROR_REPARSE_TAG_MISMATCH 4394L
|
||||
*/
|
||||
|
||||
// we use errno equivalents for some WIN32 errors:
|
||||
|
||||
#define ERROR_INVALID_PARAMETER EINVAL
|
||||
#define ERROR_INVALID_FUNCTION EINVAL
|
||||
#define ERROR_ALREADY_EXISTS EEXIST
|
||||
#define ERROR_FILE_EXISTS EEXIST
|
||||
#define ERROR_PATH_NOT_FOUND ENOENT
|
||||
#define ERROR_FILE_NOT_FOUND ENOENT
|
||||
#define ERROR_DISK_FULL ENOSPC
|
||||
// #define ERROR_INVALID_HANDLE EBADF
|
||||
|
||||
// we use FACILITY_WIN32 for errors that has no errno equivalent
|
||||
// Too many posts were made to a semaphore.
|
||||
#define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL)
|
||||
#define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L)
|
||||
#define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L)
|
||||
|
||||
// if (MY__FACILITY__WRes != FACILITY_WIN32),
|
||||
// we use FACILITY_WIN32 for COM errors:
|
||||
#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
|
||||
#define E_INVALIDARG ((HRESULT)0x80070057L)
|
||||
#define MY__E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L)
|
||||
|
||||
/*
|
||||
// we can use FACILITY_ERRNO for some COM errors, that have errno equivalents:
|
||||
#define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM)
|
||||
#define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
|
||||
#define MY__E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
|
||||
*/
|
||||
|
||||
// gcc / clang : (sizeof(long) == sizeof(void*)) in 32/64 bits
|
||||
typedef long INT_PTR;
|
||||
typedef unsigned long UINT_PTR;
|
||||
|
||||
#define TEXT(quote) quote
|
||||
|
||||
#define FILE_ATTRIBUTE_READONLY 0x0001
|
||||
#define FILE_ATTRIBUTE_HIDDEN 0x0002
|
||||
#define FILE_ATTRIBUTE_SYSTEM 0x0004
|
||||
#define FILE_ATTRIBUTE_DIRECTORY 0x0010
|
||||
#define FILE_ATTRIBUTE_ARCHIVE 0x0020
|
||||
#define FILE_ATTRIBUTE_DEVICE 0x0040
|
||||
#define FILE_ATTRIBUTE_NORMAL 0x0080
|
||||
#define FILE_ATTRIBUTE_TEMPORARY 0x0100
|
||||
#define FILE_ATTRIBUTE_SPARSE_FILE 0x0200
|
||||
#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400
|
||||
#define FILE_ATTRIBUTE_COMPRESSED 0x0800
|
||||
#define FILE_ATTRIBUTE_OFFLINE 0x1000
|
||||
#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000
|
||||
#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
|
||||
|
||||
#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef RINOK
|
||||
#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
|
||||
#endif
|
||||
|
||||
#ifndef RINOK_WRes
|
||||
#define RINOK_WRes(x) { WRes __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
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef int INT;
|
||||
typedef Int32 INT32;
|
||||
typedef unsigned int UINT;
|
||||
typedef UInt32 UINT32;
|
||||
typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility
|
||||
typedef UINT32 ULONG;
|
||||
|
||||
#undef DWORD
|
||||
typedef UINT32 DWORD;
|
||||
|
||||
#define VOID void
|
||||
|
||||
#define HRESULT LONG
|
||||
|
||||
typedef void *LPVOID;
|
||||
// typedef void VOID;
|
||||
// typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
|
||||
// gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits)
|
||||
typedef long INT_PTR;
|
||||
typedef unsigned long UINT_PTR;
|
||||
typedef long LONG_PTR;
|
||||
typedef unsigned long DWORD_PTR;
|
||||
|
||||
typedef size_t SIZE_T;
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
#define MY_HRES_ERROR__INTERNAL_ERROR ((HRESULT)0x8007054FL)
|
||||
|
||||
|
||||
#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 BoolInt;
|
||||
/* typedef BoolInt 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_FORCE_INLINE __forceinline
|
||||
|
||||
#define MY_CDECL __cdecl
|
||||
#define MY_FAST_CALL __fastcall
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 4)) \
|
||||
|| (defined(__clang__) && (__clang_major__ >= 4)) \
|
||||
|| defined(__INTEL_COMPILER) \
|
||||
|| defined(__xlC__)
|
||||
#define MY_NO_INLINE __attribute__((noinline))
|
||||
// #define MY_FORCE_INLINE __attribute__((always_inline)) inline
|
||||
#else
|
||||
#define MY_NO_INLINE
|
||||
#endif
|
||||
|
||||
#define MY_FORCE_INLINE
|
||||
|
||||
|
||||
#define MY_CDECL
|
||||
|
||||
#if defined(_M_IX86) \
|
||||
|| defined(__i386__)
|
||||
// #define MY_FAST_CALL __attribute__((fastcall))
|
||||
// #define MY_FAST_CALL __attribute__((cdecl))
|
||||
#define MY_FAST_CALL
|
||||
#elif defined(MY_CPU_AMD64)
|
||||
// #define MY_FAST_CALL __attribute__((ms_abi))
|
||||
#define MY_FAST_CALL
|
||||
#else
|
||||
#define MY_FAST_CALL
|
||||
#endif
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
|
||||
/* The following interfaces use first parameter as pointer to structure */
|
||||
|
||||
typedef struct IByteIn IByteIn;
|
||||
struct IByteIn
|
||||
{
|
||||
Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */
|
||||
};
|
||||
#define IByteIn_Read(p) (p)->Read(p)
|
||||
|
||||
|
||||
typedef struct IByteOut IByteOut;
|
||||
struct IByteOut
|
||||
{
|
||||
void (*Write)(const IByteOut *p, Byte b);
|
||||
};
|
||||
#define IByteOut_Write(p, b) (p)->Write(p, b)
|
||||
|
||||
|
||||
typedef struct ISeqInStream ISeqInStream;
|
||||
struct ISeqInStream
|
||||
{
|
||||
SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
};
|
||||
#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size)
|
||||
|
||||
/* it can return SZ_ERROR_INPUT_EOF */
|
||||
SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size);
|
||||
SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf);
|
||||
|
||||
|
||||
typedef struct ISeqOutStream ISeqOutStream;
|
||||
struct ISeqOutStream
|
||||
{
|
||||
size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size);
|
||||
/* Returns: result - the number of actually written bytes.
|
||||
(result < size) means error */
|
||||
};
|
||||
#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SZ_SEEK_SET = 0,
|
||||
SZ_SEEK_CUR = 1,
|
||||
SZ_SEEK_END = 2
|
||||
} ESzSeek;
|
||||
|
||||
|
||||
typedef struct ISeekInStream ISeekInStream;
|
||||
struct ISeekInStream
|
||||
{
|
||||
SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
|
||||
SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin);
|
||||
};
|
||||
#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size)
|
||||
#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
|
||||
|
||||
|
||||
typedef struct ILookInStream ILookInStream;
|
||||
struct ILookInStream
|
||||
{
|
||||
SRes (*Look)(const ILookInStream *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)(const ILookInStream *p, size_t offset);
|
||||
/* offset must be <= output(*size) of Look */
|
||||
|
||||
SRes (*Read)(const ILookInStream *p, void *buf, size_t *size);
|
||||
/* reads directly (without buffer). It's same as ISeqInStream::Read */
|
||||
SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin);
|
||||
};
|
||||
|
||||
#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size)
|
||||
#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset)
|
||||
#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size)
|
||||
#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
|
||||
|
||||
|
||||
SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size);
|
||||
SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset);
|
||||
|
||||
/* reads via ILookInStream::Read */
|
||||
SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size);
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ILookInStream vt;
|
||||
const ISeekInStream *realStream;
|
||||
|
||||
size_t pos;
|
||||
size_t size; /* it's data size */
|
||||
|
||||
/* the following variables must be set outside */
|
||||
Byte *buf;
|
||||
size_t bufSize;
|
||||
} CLookToRead2;
|
||||
|
||||
void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead);
|
||||
|
||||
#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; }
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream vt;
|
||||
const ILookInStream *realStream;
|
||||
} CSecToLook;
|
||||
|
||||
void SecToLook_CreateVTable(CSecToLook *p);
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream vt;
|
||||
const ILookInStream *realStream;
|
||||
} CSecToRead;
|
||||
|
||||
void SecToRead_CreateVTable(CSecToRead *p);
|
||||
|
||||
|
||||
typedef struct ICompressProgress ICompressProgress;
|
||||
|
||||
struct ICompressProgress
|
||||
{
|
||||
SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize);
|
||||
/* Returns: result. (result != SZ_OK) means break.
|
||||
Value (UInt64)(Int64)-1 for size means unknown value. */
|
||||
};
|
||||
#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize)
|
||||
|
||||
|
||||
|
||||
typedef struct ISzAlloc ISzAlloc;
|
||||
typedef const ISzAlloc * ISzAllocPtr;
|
||||
|
||||
struct ISzAlloc
|
||||
{
|
||||
void *(*Alloc)(ISzAllocPtr p, size_t size);
|
||||
void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
|
||||
};
|
||||
|
||||
#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size)
|
||||
#define ISzAlloc_Free(p, a) (p)->Free(p, a)
|
||||
|
||||
/* deprecated */
|
||||
#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size)
|
||||
#define IAlloc_Free(p, a) ISzAlloc_Free(p, a)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef MY_offsetof
|
||||
#ifdef offsetof
|
||||
#define MY_offsetof(type, m) offsetof(type, m)
|
||||
/*
|
||||
#define MY_offsetof(type, m) FIELD_OFFSET(type, m)
|
||||
*/
|
||||
#else
|
||||
#define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef MY_container_of
|
||||
|
||||
/*
|
||||
#define MY_container_of(ptr, type, m) container_of(ptr, type, m)
|
||||
#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m)
|
||||
#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m)))
|
||||
#define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m))))
|
||||
*/
|
||||
|
||||
/*
|
||||
GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly"
|
||||
GCC 3.4.4 : classes with constructor
|
||||
GCC 4.8.1 : classes with non-public variable members"
|
||||
*/
|
||||
|
||||
#define MY_container_of(ptr, type, m) ((type *)(void *)((char *)(void *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
|
||||
|
||||
#endif
|
||||
|
||||
#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr))
|
||||
|
||||
/*
|
||||
#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
|
||||
*/
|
||||
#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
|
||||
|
||||
#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
|
||||
/*
|
||||
#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m)
|
||||
*/
|
||||
|
||||
|
||||
#define MY_memset_0_ARRAY(a) memset((a), 0, sizeof(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
|
|
@ -1,478 +0,0 @@
|
|||
/* CpuArch.c -- CPU specific code
|
||||
2021-07-13 : 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 <intrin.h>
|
||||
#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) :
|
||||
"%eax", "%edx");
|
||||
#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
|
||||
|
||||
#ifndef USE_ASM
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1600
|
||||
#define MY__cpuidex __cpuidex
|
||||
#else
|
||||
|
||||
/*
|
||||
__cpuid (function == 4) requires subfunction number in ECX.
|
||||
MSDN: The __cpuid intrinsic clears the ECX register before calling the cpuid instruction.
|
||||
__cpuid() in new MSVC clears ECX.
|
||||
__cpuid() in old MSVC (14.00) doesn't clear ECX
|
||||
We still can use __cpuid for low (function) values that don't require ECX,
|
||||
but __cpuid() in old MSVC will be incorrect for some function values: (function == 4).
|
||||
So here we use the hack for old MSVC to send (subFunction) in ECX register to cpuid instruction,
|
||||
where ECX value is first parameter for FAST_CALL / NO_INLINE function,
|
||||
So the caller of MY__cpuidex_HACK() sets ECX as subFunction, and
|
||||
old MSVC for __cpuid() doesn't change ECX and cpuid instruction gets (subFunction) value.
|
||||
|
||||
DON'T remove MY_NO_INLINE and MY_FAST_CALL for MY__cpuidex_HACK() !!!
|
||||
*/
|
||||
|
||||
static
|
||||
MY_NO_INLINE
|
||||
void MY_FAST_CALL MY__cpuidex_HACK(UInt32 subFunction, int *CPUInfo, UInt32 function)
|
||||
{
|
||||
UNUSED_VAR(subFunction);
|
||||
__cpuid(CPUInfo, function);
|
||||
}
|
||||
|
||||
#define MY__cpuidex(info, func, func2) MY__cpuidex_HACK(func2, info, func)
|
||||
#pragma message("======== MY__cpuidex_HACK WAS USED ========")
|
||||
#endif
|
||||
#else
|
||||
#define MY__cpuidex(info, func, func2) __cpuid(info, func)
|
||||
#pragma message("======== (INCORRECT ?) cpuid WAS USED ========")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
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_AMD64) && defined(__PIC__)
|
||||
"mov %%rbx, %%rdi;"
|
||||
"cpuid;"
|
||||
"xchg %%rbx, %%rdi;"
|
||||
: "=a" (*a) ,
|
||||
"=D" (*b) ,
|
||||
#elif 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), "c"(0) ) ;
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
int CPUInfo[4];
|
||||
|
||||
MY__cpuidex(CPUInfo, (int)function, 0);
|
||||
|
||||
*a = (UInt32)CPUInfo[0];
|
||||
*b = (UInt32)CPUInfo[1];
|
||||
*c = (UInt32)CPUInfo[2];
|
||||
*d = (UInt32)CPUInfo[3];
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
BoolInt 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 const 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;
|
||||
}
|
||||
|
||||
BoolInt CPU_Is_InOrder(void)
|
||||
{
|
||||
Cx86cpuid p;
|
||||
int firm;
|
||||
UInt32 family, model;
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return True;
|
||||
|
||||
family = x86cpuid_GetFamily(p.ver);
|
||||
model = x86cpuid_GetModel(p.ver);
|
||||
|
||||
firm = x86cpuid_GetFirm(&p);
|
||||
|
||||
switch (firm)
|
||||
{
|
||||
case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
|
||||
/* In-Order Atom CPU */
|
||||
model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
|
||||
|| model == 0x26 /* 45 nm, Z6xx */
|
||||
|| model == 0x27 /* 32 nm, Z2460 */
|
||||
|| model == 0x35 /* 32 nm, Z2760 */
|
||||
|| model == 0x36 /* 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 <Windows.h>
|
||||
static BoolInt CPU_Sys_Is_SSE_Supported(void)
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
static UInt32 X86_CPUID_ECX_Get_Flags(void)
|
||||
{
|
||||
Cx86cpuid p;
|
||||
CHECK_SYS_SSE_SUPPORT
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return 0;
|
||||
return p.c;
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_AES(void)
|
||||
{
|
||||
return (X86_CPUID_ECX_Get_Flags() >> 25) & 1;
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_SSSE3(void)
|
||||
{
|
||||
return (X86_CPUID_ECX_Get_Flags() >> 9) & 1;
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_SSE41(void)
|
||||
{
|
||||
return (X86_CPUID_ECX_Get_Flags() >> 19) & 1;
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_SHA(void)
|
||||
{
|
||||
Cx86cpuid p;
|
||||
CHECK_SYS_SSE_SUPPORT
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return False;
|
||||
|
||||
if (p.maxFunc < 7)
|
||||
return False;
|
||||
{
|
||||
UInt32 d[4] = { 0 };
|
||||
MyCPUID(7, &d[0], &d[1], &d[2], &d[3]);
|
||||
return (d[1] >> 29) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
BoolInt CPU_IsSupported_AVX2(void)
|
||||
{
|
||||
Cx86cpuid p;
|
||||
CHECK_SYS_SSE_SUPPORT
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MY__PF_XSAVE_ENABLED 17
|
||||
if (!IsProcessorFeaturePresent(MY__PF_XSAVE_ENABLED))
|
||||
return False;
|
||||
#endif
|
||||
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return False;
|
||||
if (p.maxFunc < 7)
|
||||
return False;
|
||||
{
|
||||
UInt32 d[4] = { 0 };
|
||||
MyCPUID(7, &d[0], &d[1], &d[2], &d[3]);
|
||||
// printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
|
||||
return 1
|
||||
& (d[1] >> 5); // avx2
|
||||
}
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_VAES_AVX2(void)
|
||||
{
|
||||
Cx86cpuid p;
|
||||
CHECK_SYS_SSE_SUPPORT
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MY__PF_XSAVE_ENABLED 17
|
||||
if (!IsProcessorFeaturePresent(MY__PF_XSAVE_ENABLED))
|
||||
return False;
|
||||
#endif
|
||||
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return False;
|
||||
if (p.maxFunc < 7)
|
||||
return False;
|
||||
{
|
||||
UInt32 d[4] = { 0 };
|
||||
MyCPUID(7, &d[0], &d[1], &d[2], &d[3]);
|
||||
// printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
|
||||
return 1
|
||||
& (d[1] >> 5) // avx2
|
||||
// & (d[1] >> 31) // avx512vl
|
||||
& (d[2] >> 9); // vaes // VEX-256/EVEX
|
||||
}
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_PageGB(void)
|
||||
{
|
||||
Cx86cpuid cpuid;
|
||||
if (!x86cpuid_CheckAndRead(&cpuid))
|
||||
return False;
|
||||
{
|
||||
UInt32 d[4] = { 0 };
|
||||
MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]);
|
||||
if (d[0] < 0x80000001)
|
||||
return False;
|
||||
}
|
||||
{
|
||||
UInt32 d[4] = { 0 };
|
||||
MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]);
|
||||
return (d[3] >> 26) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#elif defined(MY_CPU_ARM_OR_ARM64)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
BoolInt CPU_IsSupported_CRC32(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
|
||||
BoolInt CPU_IsSupported_CRYPTO(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
|
||||
BoolInt CPU_IsSupported_NEON(void) { return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
|
||||
|
||||
#else
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
/*
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
static void Print_sysctlbyname(const char *name)
|
||||
{
|
||||
size_t bufSize = 256;
|
||||
char buf[256];
|
||||
int res = sysctlbyname(name, &buf, &bufSize, NULL, 0);
|
||||
{
|
||||
int i;
|
||||
printf("\nres = %d : %s : '%s' : bufSize = %d, numeric", res, name, buf, (unsigned)bufSize);
|
||||
for (i = 0; i < 20; i++)
|
||||
printf(" %2x", (unsigned)(Byte)buf[i]);
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static BoolInt My_sysctlbyname_Get_BoolInt(const char *name)
|
||||
{
|
||||
UInt32 val = 0;
|
||||
if (My_sysctlbyname_Get_UInt32(name, &val) == 0 && val == 1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Print_sysctlbyname("hw.pagesize");
|
||||
Print_sysctlbyname("machdep.cpu.brand_string");
|
||||
*/
|
||||
|
||||
BoolInt CPU_IsSupported_CRC32(void)
|
||||
{
|
||||
return My_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32");
|
||||
}
|
||||
|
||||
BoolInt CPU_IsSupported_NEON(void)
|
||||
{
|
||||
return My_sysctlbyname_Get_BoolInt("hw.optional.neon");
|
||||
}
|
||||
|
||||
#ifdef MY_CPU_ARM64
|
||||
#define APPLE_CRYPTO_SUPPORT_VAL 1
|
||||
#else
|
||||
#define APPLE_CRYPTO_SUPPORT_VAL 0
|
||||
#endif
|
||||
|
||||
BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
|
||||
BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
|
||||
BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
|
||||
|
||||
|
||||
#else // __APPLE__
|
||||
|
||||
#include <sys/auxv.h>
|
||||
|
||||
#define USE_HWCAP
|
||||
|
||||
#ifdef USE_HWCAP
|
||||
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
#define MY_HWCAP_CHECK_FUNC_2(name1, name2) \
|
||||
BoolInt CPU_IsSupported_ ## name1() { return (getauxval(AT_HWCAP) & (HWCAP_ ## name2)) ? 1 : 0; }
|
||||
|
||||
#ifdef MY_CPU_ARM64
|
||||
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||
MY_HWCAP_CHECK_FUNC_2(name, name)
|
||||
MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD)
|
||||
// MY_HWCAP_CHECK_FUNC (ASIMD)
|
||||
#elif defined(MY_CPU_ARM)
|
||||
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||
BoolInt CPU_IsSupported_ ## name() { return (getauxval(AT_HWCAP2) & (HWCAP2_ ## name)) ? 1 : 0; }
|
||||
MY_HWCAP_CHECK_FUNC_2(NEON, NEON)
|
||||
#endif
|
||||
|
||||
#else // USE_HWCAP
|
||||
|
||||
#define MY_HWCAP_CHECK_FUNC(name) \
|
||||
BoolInt CPU_IsSupported_ ## name() { return 0; }
|
||||
MY_HWCAP_CHECK_FUNC(NEON)
|
||||
|
||||
#endif // USE_HWCAP
|
||||
|
||||
MY_HWCAP_CHECK_FUNC (CRC32)
|
||||
MY_HWCAP_CHECK_FUNC (SHA1)
|
||||
MY_HWCAP_CHECK_FUNC (SHA2)
|
||||
MY_HWCAP_CHECK_FUNC (AES)
|
||||
|
||||
#endif // __APPLE__
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // MY_CPU_ARM_OR_ARM64
|
||||
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize)
|
||||
{
|
||||
return sysctlbyname(name, buf, bufSize, NULL, 0);
|
||||
}
|
||||
|
||||
int My_sysctlbyname_Get_UInt32(const char *name, UInt32 *val)
|
||||
{
|
||||
size_t bufSize = sizeof(*val);
|
||||
int res = My_sysctlbyname_Get(name, val, &bufSize);
|
||||
if (res == 0 && bufSize != sizeof(*val))
|
||||
return EFAULT;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,442 +0,0 @@
|
|||
/* CpuArch.h -- CPU specific code
|
||||
2021-07-13 : 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.
|
||||
MY_CPU_BE means that CPU is BIG ENDIAN.
|
||||
If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
|
||||
|
||||
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
|
||||
|
||||
MY_CPU_64BIT means that processor can work with 64-bit registers.
|
||||
MY_CPU_64BIT can be used to select fast code branch
|
||||
MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8)
|
||||
*/
|
||||
|
||||
#if defined(_M_X64) \
|
||||
|| defined(_M_AMD64) \
|
||||
|| defined(__x86_64__) \
|
||||
|| defined(__AMD64__) \
|
||||
|| defined(__amd64__)
|
||||
#define MY_CPU_AMD64
|
||||
#ifdef __ILP32__
|
||||
#define MY_CPU_NAME "x32"
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#else
|
||||
#define MY_CPU_NAME "x64"
|
||||
#define MY_CPU_SIZEOF_POINTER 8
|
||||
#endif
|
||||
#define MY_CPU_64BIT
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_M_IX86) \
|
||||
|| defined(__i386__)
|
||||
#define MY_CPU_X86
|
||||
#define MY_CPU_NAME "x86"
|
||||
/* #define MY_CPU_32BIT */
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_M_ARM64) \
|
||||
|| defined(__AARCH64EL__) \
|
||||
|| defined(__AARCH64EB__) \
|
||||
|| defined(__aarch64__)
|
||||
#define MY_CPU_ARM64
|
||||
#define MY_CPU_NAME "arm64"
|
||||
#define MY_CPU_64BIT
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_M_ARM) \
|
||||
|| defined(_M_ARM_NT) \
|
||||
|| defined(_M_ARMT) \
|
||||
|| defined(__arm__) \
|
||||
|| defined(__thumb__) \
|
||||
|| defined(__ARMEL__) \
|
||||
|| defined(__ARMEB__) \
|
||||
|| defined(__THUMBEL__) \
|
||||
|| defined(__THUMBEB__)
|
||||
#define MY_CPU_ARM
|
||||
|
||||
#if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT)
|
||||
#define MY_CPU_NAME "armt"
|
||||
#else
|
||||
#define MY_CPU_NAME "arm"
|
||||
#endif
|
||||
/* #define MY_CPU_32BIT */
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_M_IA64) \
|
||||
|| defined(__ia64__)
|
||||
#define MY_CPU_IA64
|
||||
#define MY_CPU_NAME "ia64"
|
||||
#define MY_CPU_64BIT
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__mips64) \
|
||||
|| defined(__mips64__) \
|
||||
|| (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
|
||||
#define MY_CPU_NAME "mips64"
|
||||
#define MY_CPU_64BIT
|
||||
#elif defined(__mips__)
|
||||
#define MY_CPU_NAME "mips"
|
||||
/* #define MY_CPU_32BIT */
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__ppc64__) \
|
||||
|| defined(__powerpc64__) \
|
||||
|| defined(__ppc__) \
|
||||
|| defined(__powerpc__) \
|
||||
|| defined(__PPC__) \
|
||||
|| defined(_POWER)
|
||||
|
||||
#if defined(__ppc64__) \
|
||||
|| defined(__powerpc64__) \
|
||||
|| defined(_LP64) \
|
||||
|| defined(__64BIT__)
|
||||
#ifdef __ILP32__
|
||||
#define MY_CPU_NAME "ppc64-32"
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
#else
|
||||
#define MY_CPU_NAME "ppc64"
|
||||
#define MY_CPU_SIZEOF_POINTER 8
|
||||
#endif
|
||||
#define MY_CPU_64BIT
|
||||
#else
|
||||
#define MY_CPU_NAME "ppc"
|
||||
#define MY_CPU_SIZEOF_POINTER 4
|
||||
/* #define MY_CPU_32BIT */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__sparc64__)
|
||||
#define MY_CPU_NAME "sparc64"
|
||||
#define MY_CPU_64BIT
|
||||
#elif defined(__sparc__)
|
||||
#define MY_CPU_NAME "sparc"
|
||||
/* #define MY_CPU_32BIT */
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
|
||||
#define MY_CPU_X86_OR_AMD64
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64)
|
||||
#define MY_CPU_ARM_OR_ARM64
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifdef MY_CPU_ARM
|
||||
#define MY_CPU_ARM_LE
|
||||
#endif
|
||||
|
||||
#ifdef MY_CPU_ARM64
|
||||
#define MY_CPU_ARM64_LE
|
||||
#endif
|
||||
|
||||
#ifdef _M_IA64
|
||||
#define MY_CPU_IA64_LE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64) \
|
||||
|| defined(MY_CPU_ARM_LE) \
|
||||
|| defined(MY_CPU_ARM64_LE) \
|
||||
|| defined(MY_CPU_IA64_LE) \
|
||||
|| defined(__LITTLE_ENDIAN__) \
|
||||
|| defined(__ARMEL__) \
|
||||
|| defined(__THUMBEL__) \
|
||||
|| defined(__AARCH64EL__) \
|
||||
|| defined(__MIPSEL__) \
|
||||
|| defined(__MIPSEL) \
|
||||
|| defined(_MIPSEL) \
|
||||
|| defined(__BFIN__) \
|
||||
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
#define MY_CPU_LE
|
||||
#endif
|
||||
|
||||
#if defined(__BIG_ENDIAN__) \
|
||||
|| defined(__ARMEB__) \
|
||||
|| defined(__THUMBEB__) \
|
||||
|| defined(__AARCH64EB__) \
|
||||
|| defined(__MIPSEB__) \
|
||||
|| defined(__MIPSEB) \
|
||||
|| defined(_MIPSEB) \
|
||||
|| defined(__m68k__) \
|
||||
|| defined(__s390__) \
|
||||
|| defined(__s390x__) \
|
||||
|| defined(__zarch__) \
|
||||
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
#define MY_CPU_BE
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
|
||||
#error Stop_Compiling_Bad_Endian
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
|
||||
#error Stop_Compiling_Bad_32_64_BIT
|
||||
#endif
|
||||
|
||||
#ifdef __SIZEOF_POINTER__
|
||||
#ifdef MY_CPU_SIZEOF_POINTER
|
||||
#if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__
|
||||
#error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
|
||||
#endif
|
||||
#else
|
||||
#define MY_CPU_SIZEOF_POINTER __SIZEOF_POINTER__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
|
||||
#if defined (_LP64)
|
||||
#error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1300
|
||||
#define MY_CPU_pragma_pack_push_1 __pragma(pack(push, 1))
|
||||
#define MY_CPU_pragma_pop __pragma(pack(pop))
|
||||
#else
|
||||
#define MY_CPU_pragma_pack_push_1
|
||||
#define MY_CPU_pragma_pop
|
||||
#endif
|
||||
#else
|
||||
#ifdef __xlC__
|
||||
#define MY_CPU_pragma_pack_push_1 _Pragma("pack(1)")
|
||||
#define MY_CPU_pragma_pop _Pragma("pack()")
|
||||
#else
|
||||
#define MY_CPU_pragma_pack_push_1 _Pragma("pack(push, 1)")
|
||||
#define MY_CPU_pragma_pop _Pragma("pack(pop)")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MY_CPU_NAME
|
||||
#ifdef MY_CPU_LE
|
||||
#define MY_CPU_NAME "LE"
|
||||
#elif defined(MY_CPU_BE)
|
||||
#define MY_CPU_NAME "BE"
|
||||
#else
|
||||
/*
|
||||
#define MY_CPU_NAME ""
|
||||
*/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
#if defined(MY_CPU_X86_OR_AMD64) \
|
||||
|| defined(MY_CPU_ARM64)
|
||||
#define MY_CPU_LE_UNALIGN
|
||||
#define MY_CPU_LE_UNALIGN_64
|
||||
#elif defined(__ARM_FEATURE_UNALIGNED)
|
||||
/* gcc9 for 32-bit arm can use LDRD instruction that requires 32-bit alignment.
|
||||
So we can't use unaligned 64-bit operations. */
|
||||
#define MY_CPU_LE_UNALIGN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MY_CPU_LE_UNALIGN
|
||||
|
||||
#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
|
||||
#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
|
||||
#ifdef MY_CPU_LE_UNALIGN_64
|
||||
#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
|
||||
#endif
|
||||
|
||||
#define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); }
|
||||
#define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); }
|
||||
#ifdef MY_CPU_LE_UNALIGN_64
|
||||
#define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); }
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define GetUi16(p) ( (UInt16) ( \
|
||||
((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 SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||
_ppp_[0] = (Byte)_vvv_; \
|
||||
_ppp_[1] = (Byte)(_vvv_ >> 8); }
|
||||
|
||||
#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||
_ppp_[0] = (Byte)_vvv_; \
|
||||
_ppp_[1] = (Byte)(_vvv_ >> 8); \
|
||||
_ppp_[2] = (Byte)(_vvv_ >> 16); \
|
||||
_ppp_[3] = (Byte)(_vvv_ >> 24); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MY_CPU_LE_UNALIGN_64
|
||||
|
||||
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
|
||||
|
||||
#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
|
||||
SetUi32(_ppp2_ , (UInt32)_vvv2_); \
|
||||
SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __has_builtin
|
||||
#define MY__has_builtin(x) __has_builtin(x)
|
||||
#else
|
||||
#define MY__has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
|
||||
/* Note: we use bswap instruction, that is unsupported in 386 cpu */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#pragma intrinsic(_byteswap_ushort)
|
||||
#pragma intrinsic(_byteswap_ulong)
|
||||
#pragma intrinsic(_byteswap_uint64)
|
||||
|
||||
/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */
|
||||
#define GetBe32(p) _byteswap_ulong (*(const UInt32 *)(const void *)(p))
|
||||
#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const void *)(p))
|
||||
|
||||
#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
|
||||
|
||||
#elif defined(MY_CPU_LE_UNALIGN) && ( \
|
||||
(defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
|
||||
|| (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) )
|
||||
|
||||
/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const void *)(p)) */
|
||||
#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const void *)(p))
|
||||
#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const void *)(p))
|
||||
|
||||
#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
|
||||
|
||||
#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))
|
||||
|
||||
#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
|
||||
_ppp_[0] = (Byte)(_vvv_ >> 24); \
|
||||
_ppp_[1] = (Byte)(_vvv_ >> 16); \
|
||||
_ppp_[2] = (Byte)(_vvv_ >> 8); \
|
||||
_ppp_[3] = (Byte)_vvv_; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef GetBe16
|
||||
|
||||
#define GetBe16(p) ( (UInt16) ( \
|
||||
((UInt16)((const Byte *)(p))[0] << 8) | \
|
||||
((const Byte *)(p))[1] ))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
|
||||
|
||||
BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p);
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p);
|
||||
|
||||
#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
|
||||
#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF))
|
||||
#define x86cpuid_GetStepping(ver) (ver & 0xF)
|
||||
|
||||
BoolInt CPU_Is_InOrder(void);
|
||||
|
||||
BoolInt CPU_IsSupported_AES(void);
|
||||
BoolInt CPU_IsSupported_AVX2(void);
|
||||
BoolInt CPU_IsSupported_VAES_AVX2(void);
|
||||
BoolInt CPU_IsSupported_SSSE3(void);
|
||||
BoolInt CPU_IsSupported_SSE41(void);
|
||||
BoolInt CPU_IsSupported_SHA(void);
|
||||
BoolInt CPU_IsSupported_PageGB(void);
|
||||
|
||||
#elif defined(MY_CPU_ARM_OR_ARM64)
|
||||
|
||||
BoolInt CPU_IsSupported_CRC32(void);
|
||||
BoolInt CPU_IsSupported_NEON(void);
|
||||
|
||||
#if defined(_WIN32)
|
||||
BoolInt CPU_IsSupported_CRYPTO(void);
|
||||
#define CPU_IsSupported_SHA1 CPU_IsSupported_CRYPTO
|
||||
#define CPU_IsSupported_SHA2 CPU_IsSupported_CRYPTO
|
||||
#define CPU_IsSupported_AES CPU_IsSupported_CRYPTO
|
||||
#else
|
||||
BoolInt CPU_IsSupported_SHA1(void);
|
||||
BoolInt CPU_IsSupported_SHA2(void);
|
||||
BoolInt CPU_IsSupported_AES(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize);
|
||||
int My_sysctlbyname_Get_UInt32(const char *name, UInt32 *val);
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
|
@ -1,167 +0,0 @@
|
|||
/* Ppmd.h -- PPMD codec common code
|
||||
2021-04-13 : 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
|
||||
|
||||
#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
|
||||
/*
|
||||
PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block.
|
||||
if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields.
|
||||
if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields.
|
||||
if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed,
|
||||
if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional,
|
||||
and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit.
|
||||
PPMD code works slightly faster in (PPMD_32BIT) mode.
|
||||
*/
|
||||
#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)
|
||||
|
||||
MY_CPU_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 = (UInt16)((p)->Summ << 1); (p)->Count = (Byte)(3 << (p)->Shift++); }
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte Symbol;
|
||||
Byte Freq;
|
||||
UInt16 Successor_0;
|
||||
UInt16 Successor_1;
|
||||
} CPpmd_State;
|
||||
|
||||
typedef struct CPpmd_State2_
|
||||
{
|
||||
Byte Symbol;
|
||||
Byte Freq;
|
||||
} CPpmd_State2;
|
||||
|
||||
typedef struct CPpmd_State4_
|
||||
{
|
||||
UInt16 Successor_0;
|
||||
UInt16 Successor_1;
|
||||
} CPpmd_State4;
|
||||
|
||||
MY_CPU_pragma_pop
|
||||
|
||||
/*
|
||||
PPMD code can write full CPpmd_State structure data to CPpmd*_Context
|
||||
at (byte offset = 2) instead of some fields of original CPpmd*_Context structure.
|
||||
|
||||
If we use pointers to different types, but that point to shared
|
||||
memory space, we can have aliasing problem (strict aliasing).
|
||||
|
||||
XLC compiler in -O2 mode can change the order of memory write instructions
|
||||
in relation to read instructions, if we have use pointers to different types.
|
||||
|
||||
To solve that aliasing problem we use combined CPpmd*_Context structure
|
||||
with unions that contain the fields from both structures:
|
||||
the original CPpmd*_Context and CPpmd_State.
|
||||
So we can access the fields from both structures via one pointer,
|
||||
and the compiler doesn't change the order of write instructions
|
||||
in relation to read instructions.
|
||||
|
||||
If we don't use memory write instructions to shared memory in
|
||||
some local code, and we use only reading instructions (read only),
|
||||
then probably it's safe to use pointers to different types for reading.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef PPMD_32BIT
|
||||
|
||||
#define Ppmd_Ref_Type(type) type *
|
||||
#define Ppmd_GetRef(p, ptr) (ptr)
|
||||
#define Ppmd_GetPtr(p, ptr) (ptr)
|
||||
#define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr)
|
||||
|
||||
#else
|
||||
|
||||
#define Ppmd_Ref_Type(type) UInt32
|
||||
#define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
|
||||
#define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
|
||||
#define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs))
|
||||
|
||||
#endif // PPMD_32BIT
|
||||
|
||||
|
||||
typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref;
|
||||
typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref;
|
||||
typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref;
|
||||
|
||||
|
||||
/*
|
||||
#ifdef MY_CPU_LE_UNALIGN
|
||||
// the unaligned 32-bit access latency can be too large, if the data is not in L1 cache.
|
||||
#define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0)
|
||||
#define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v)
|
||||
|
||||
#else
|
||||
*/
|
||||
|
||||
/*
|
||||
We can write 16-bit halves to 32-bit (Successor) field in any selected order.
|
||||
But the native order is more consistent way.
|
||||
So we use the native order, if LE/BE order can be detected here at compile time.
|
||||
*/
|
||||
|
||||
#ifdef MY_CPU_BE
|
||||
|
||||
#define Ppmd_GET_SUCCESSOR(p) \
|
||||
( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) )
|
||||
|
||||
#define Ppmd_SET_SUCCESSOR(p, v) { \
|
||||
(p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \
|
||||
(p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); }
|
||||
|
||||
#else
|
||||
|
||||
#define Ppmd_GET_SUCCESSOR(p) \
|
||||
( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) )
|
||||
|
||||
#define Ppmd_SET_SUCCESSOR(p, v) { \
|
||||
(p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \
|
||||
(p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); }
|
||||
|
||||
#endif
|
||||
|
||||
// #endif
|
||||
|
||||
|
||||
#define PPMD_SetAllBitsIn256Bytes(p) \
|
||||
{ size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \
|
||||
p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }}
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,181 +0,0 @@
|
|||
/* Ppmd7.h -- Ppmd7 (PPMdH) compression codec
|
||||
2021-04-13 : Igor Pavlov : Public domain
|
||||
This code is based on:
|
||||
PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||
|
||||
|
||||
#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 Ppmd_Ref_Type(struct CPpmd7_Context_) CPpmd7_Context_Ref;
|
||||
|
||||
// MY_CPU_pragma_pack_push_1
|
||||
|
||||
typedef struct CPpmd7_Context_
|
||||
{
|
||||
UInt16 NumStats;
|
||||
|
||||
|
||||
union
|
||||
{
|
||||
UInt16 SummFreq;
|
||||
CPpmd_State2 State2;
|
||||
} Union2;
|
||||
|
||||
union
|
||||
{
|
||||
CPpmd_State_Ref Stats;
|
||||
CPpmd_State4 State4;
|
||||
} Union4;
|
||||
|
||||
CPpmd7_Context_Ref Suffix;
|
||||
} CPpmd7_Context;
|
||||
|
||||
// MY_CPU_pragma_pop
|
||||
|
||||
#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->Union2)
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 Range;
|
||||
UInt32 Code;
|
||||
UInt32 Low;
|
||||
IByteIn *Stream;
|
||||
} CPpmd7_RangeDec;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 Range;
|
||||
Byte Cache;
|
||||
// Byte _dummy_[3];
|
||||
UInt64 Low;
|
||||
UInt64 CacheSize;
|
||||
IByteOut *Stream;
|
||||
} CPpmd7z_RangeEnc;
|
||||
|
||||
|
||||
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;
|
||||
UInt32 AlignOffset;
|
||||
Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
|
||||
|
||||
|
||||
|
||||
|
||||
union
|
||||
{
|
||||
CPpmd7_RangeDec dec;
|
||||
CPpmd7z_RangeEnc enc;
|
||||
} rc;
|
||||
|
||||
Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment
|
||||
Byte Units2Indx[128];
|
||||
CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
|
||||
|
||||
Byte NS2BSIndx[256], NS2Indx[256];
|
||||
Byte ExpEscape[16];
|
||||
CPpmd_See DummySee, See[25][16];
|
||||
UInt16 BinSumm[128][64];
|
||||
// int LastSymbol;
|
||||
} CPpmd7;
|
||||
|
||||
|
||||
void Ppmd7_Construct(CPpmd7 *p);
|
||||
BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc);
|
||||
void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc);
|
||||
void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
|
||||
#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
|
||||
|
||||
|
||||
/* ---------- Internal Functions ---------- */
|
||||
|
||||
#define Ppmd7_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr)
|
||||
#define Ppmd7_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd7_Context)
|
||||
#define Ppmd7_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State)
|
||||
|
||||
void Ppmd7_Update1(CPpmd7 *p);
|
||||
void Ppmd7_Update1_0(CPpmd7 *p);
|
||||
void Ppmd7_Update2(CPpmd7 *p);
|
||||
|
||||
#define PPMD7_HiBitsFlag_3(sym) ((((unsigned)sym + 0xC0) >> (8 - 3)) & (1 << 3))
|
||||
#define PPMD7_HiBitsFlag_4(sym) ((((unsigned)sym + 0xC0) >> (8 - 4)) & (1 << 4))
|
||||
// #define PPMD7_HiBitsFlag_3(sym) ((sym) < 0x40 ? 0 : (1 << 3))
|
||||
// #define PPMD7_HiBitsFlag_4(sym) ((sym) < 0x40 ? 0 : (1 << 4))
|
||||
|
||||
#define Ppmd7_GetBinSumm(p) \
|
||||
&p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1] \
|
||||
[ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \
|
||||
+ p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] \
|
||||
+ PPMD7_HiBitsFlag_4(Ppmd7Context_OneState(p->MinContext)->Symbol) \
|
||||
+ (p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol)) ]
|
||||
|
||||
CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
|
||||
|
||||
|
||||
/*
|
||||
We support two versions of Ppmd7 (PPMdH) methods that use same CPpmd7 structure:
|
||||
1) Ppmd7a_*: original PPMdH
|
||||
2) Ppmd7z_*: modified PPMdH with 7z Range Coder
|
||||
Ppmd7_*: the structures and functions that are common for both versions of PPMd7 (PPMdH)
|
||||
*/
|
||||
|
||||
/* ---------- Decode ---------- */
|
||||
|
||||
#define PPMD7_SYM_END (-1)
|
||||
#define PPMD7_SYM_ERROR (-2)
|
||||
|
||||
/*
|
||||
You must set (CPpmd7::rc.dec.Stream) before Ppmd7*_RangeDec_Init()
|
||||
|
||||
Ppmd7*_DecodeSymbol()
|
||||
out:
|
||||
>= 0 : decoded byte
|
||||
-1 : PPMD7_SYM_END : End of payload marker
|
||||
-2 : PPMD7_SYM_ERROR : Data error
|
||||
*/
|
||||
|
||||
/* Ppmd7a_* : original PPMdH */
|
||||
BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p);
|
||||
#define Ppmd7a_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
|
||||
int Ppmd7a_DecodeSymbol(CPpmd7 *p);
|
||||
|
||||
/* Ppmd7z_* : modified PPMdH with 7z Range Coder */
|
||||
BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p);
|
||||
#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
|
||||
int Ppmd7z_DecodeSymbol(CPpmd7 *p);
|
||||
// Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim);
|
||||
|
||||
|
||||
/* ---------- Encode ---------- */
|
||||
|
||||
void Ppmd7z_Init_RangeEnc(CPpmd7 *p);
|
||||
void Ppmd7z_Flush_RangeEnc(CPpmd7 *p);
|
||||
// void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol);
|
||||
void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
|
@ -1,297 +0,0 @@
|
|||
/* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder
|
||||
2021-04-13 : 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)
|
||||
|
||||
|
||||
#define READ_BYTE(p) IByteIn_Read((p)->Stream)
|
||||
|
||||
BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p)
|
||||
{
|
||||
unsigned i;
|
||||
p->Code = 0;
|
||||
p->Range = 0xFFFFFFFF;
|
||||
if (READ_BYTE(p) != 0)
|
||||
return False;
|
||||
for (i = 0; i < 4; i++)
|
||||
p->Code = (p->Code << 8) | READ_BYTE(p);
|
||||
return (p->Code < 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
#define RC_NORM_BASE(p) if ((p)->Range < kTopValue) \
|
||||
{ (p)->Code = ((p)->Code << 8) | READ_BYTE(p); (p)->Range <<= 8;
|
||||
|
||||
#define RC_NORM_1(p) RC_NORM_BASE(p) }
|
||||
#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }}
|
||||
|
||||
// we must use only one type of Normalization from two: LOCAL or REMOTE
|
||||
#define RC_NORM_LOCAL(p) // RC_NORM(p)
|
||||
#define RC_NORM_REMOTE(p) RC_NORM(p)
|
||||
|
||||
#define R (&p->rc.dec)
|
||||
|
||||
MY_FORCE_INLINE
|
||||
// MY_NO_INLINE
|
||||
static void RangeDec_Decode(CPpmd7 *p, UInt32 start, UInt32 size)
|
||||
{
|
||||
|
||||
|
||||
R->Code -= start * R->Range;
|
||||
R->Range *= size;
|
||||
RC_NORM_LOCAL(R)
|
||||
}
|
||||
|
||||
#define RC_Decode(start, size) RangeDec_Decode(p, start, size);
|
||||
#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R)
|
||||
#define RC_GetThreshold(total) (R->Code / (R->Range /= (total)))
|
||||
|
||||
|
||||
#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
|
||||
typedef CPpmd7_Context * CTX_PTR;
|
||||
#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
|
||||
void Ppmd7_UpdateModel(CPpmd7 *p);
|
||||
|
||||
#define MASK(sym) ((unsigned char *)charMask)[sym]
|
||||
// MY_FORCE_INLINE
|
||||
// static
|
||||
int Ppmd7z_DecodeSymbol(CPpmd7 *p)
|
||||
{
|
||||
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;
|
||||
UInt32 summFreq = p->MinContext->Union2.SummFreq;
|
||||
|
||||
|
||||
|
||||
|
||||
count = RC_GetThreshold(summFreq);
|
||||
hiCnt = count;
|
||||
|
||||
if ((Int32)(count -= s->Freq) < 0)
|
||||
{
|
||||
Byte sym;
|
||||
RC_DecodeFinal(0, s->Freq);
|
||||
p->FoundState = s;
|
||||
sym = s->Symbol;
|
||||
Ppmd7_Update1_0(p);
|
||||
return sym;
|
||||
}
|
||||
|
||||
p->PrevSuccess = 0;
|
||||
i = (unsigned)p->MinContext->NumStats - 1;
|
||||
|
||||
do
|
||||
{
|
||||
if ((Int32)(count -= (++s)->Freq) < 0)
|
||||
{
|
||||
Byte sym;
|
||||
RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq);
|
||||
p->FoundState = s;
|
||||
sym = s->Symbol;
|
||||
Ppmd7_Update1(p);
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
while (--i);
|
||||
|
||||
if (hiCnt >= summFreq)
|
||||
return PPMD7_SYM_ERROR;
|
||||
|
||||
hiCnt -= count;
|
||||
RC_Decode(hiCnt, summFreq - hiCnt);
|
||||
|
||||
p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol);
|
||||
PPMD_SetAllBitsIn256Bytes(charMask);
|
||||
// i = p->MinContext->NumStats - 1;
|
||||
// do { MASK((--s)->Symbol) = 0; } while (--i);
|
||||
{
|
||||
CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
|
||||
MASK(s->Symbol) = 0;
|
||||
do
|
||||
{
|
||||
unsigned sym0 = s2[0].Symbol;
|
||||
unsigned sym1 = s2[1].Symbol;
|
||||
s2 += 2;
|
||||
MASK(sym0) = 0;
|
||||
MASK(sym1) = 0;
|
||||
}
|
||||
while (s2 < s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
|
||||
UInt16 *prob = Ppmd7_GetBinSumm(p);
|
||||
UInt32 pr = *prob;
|
||||
UInt32 size0 = (R->Range >> 14) * pr;
|
||||
pr = PPMD_UPDATE_PROB_1(pr);
|
||||
|
||||
if (R->Code < size0)
|
||||
{
|
||||
Byte sym;
|
||||
*prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
|
||||
|
||||
// RangeDec_DecodeBit0(size0);
|
||||
R->Range = size0;
|
||||
RC_NORM_1(R)
|
||||
/* we can use single byte normalization here because of
|
||||
(min(BinSumm[][]) = 95) > (1 << (14 - 8)) */
|
||||
|
||||
// sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
|
||||
// Ppmd7_UpdateBin(p);
|
||||
{
|
||||
unsigned freq = s->Freq;
|
||||
CTX_PTR c = CTX(SUCCESSOR(s));
|
||||
sym = s->Symbol;
|
||||
p->FoundState = s;
|
||||
p->PrevSuccess = 1;
|
||||
p->RunLength++;
|
||||
s->Freq = (Byte)(freq + (freq < 128));
|
||||
// NextContext(p);
|
||||
if (p->OrderFall == 0 && (const Byte *)c > p->Text)
|
||||
p->MaxContext = p->MinContext = c;
|
||||
else
|
||||
Ppmd7_UpdateModel(p);
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
*prob = (UInt16)pr;
|
||||
p->InitEsc = p->ExpEscape[pr >> 10];
|
||||
|
||||
// RangeDec_DecodeBit1(size0);
|
||||
|
||||
R->Code -= size0;
|
||||
R->Range -= size0;
|
||||
RC_NORM_LOCAL(R)
|
||||
|
||||
PPMD_SetAllBitsIn256Bytes(charMask);
|
||||
MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
|
||||
p->PrevSuccess = 0;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CPpmd_State *s, *s2;
|
||||
UInt32 freqSum, count, hiCnt;
|
||||
|
||||
CPpmd_See *see;
|
||||
CPpmd7_Context *mc;
|
||||
unsigned numMasked;
|
||||
RC_NORM_REMOTE(R)
|
||||
mc = p->MinContext;
|
||||
numMasked = mc->NumStats;
|
||||
|
||||
do
|
||||
{
|
||||
p->OrderFall++;
|
||||
if (!mc->Suffix)
|
||||
return PPMD7_SYM_END;
|
||||
mc = Ppmd7_GetContext(p, mc->Suffix);
|
||||
}
|
||||
while (mc->NumStats == numMasked);
|
||||
|
||||
s = Ppmd7_GetStats(p, mc);
|
||||
|
||||
{
|
||||
unsigned num = mc->NumStats;
|
||||
unsigned num2 = num / 2;
|
||||
|
||||
num &= 1;
|
||||
hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
|
||||
s += num;
|
||||
p->MinContext = mc;
|
||||
|
||||
do
|
||||
{
|
||||
unsigned sym0 = s[0].Symbol;
|
||||
unsigned sym1 = s[1].Symbol;
|
||||
s += 2;
|
||||
hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
|
||||
hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1)));
|
||||
}
|
||||
while (--num2);
|
||||
}
|
||||
|
||||
see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
|
||||
freqSum += hiCnt;
|
||||
|
||||
|
||||
|
||||
|
||||
count = RC_GetThreshold(freqSum);
|
||||
|
||||
if (count < hiCnt)
|
||||
{
|
||||
Byte sym;
|
||||
|
||||
s = Ppmd7_GetStats(p, p->MinContext);
|
||||
hiCnt = count;
|
||||
// count -= s->Freq & (unsigned)(MASK(s->Symbol));
|
||||
// if ((Int32)count >= 0)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
|
||||
// count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
|
||||
};
|
||||
}
|
||||
s--;
|
||||
RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq);
|
||||
|
||||
// new (see->Summ) value can overflow over 16-bits in some rare cases
|
||||
Ppmd_See_Update(see);
|
||||
p->FoundState = s;
|
||||
sym = s->Symbol;
|
||||
Ppmd7_Update2(p);
|
||||
return sym;
|
||||
}
|
||||
|
||||
if (count >= freqSum)
|
||||
return PPMD7_SYM_ERROR;
|
||||
|
||||
RC_Decode(hiCnt, freqSum - hiCnt);
|
||||
|
||||
// We increase (see->Summ) for sum of Freqs of all non_Masked symbols.
|
||||
// new (see->Summ) value can overflow over 16-bits in some rare cases
|
||||
see->Summ = (UInt16)(see->Summ + freqSum);
|
||||
|
||||
s = Ppmd7_GetStats(p, p->MinContext);
|
||||
s2 = s + p->MinContext->NumStats;
|
||||
do
|
||||
{
|
||||
MASK(s->Symbol) = 0;
|
||||
s++;
|
||||
}
|
||||
while (s != s2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim)
|
||||
{
|
||||
int sym = 0;
|
||||
if (buf != lim)
|
||||
do
|
||||
{
|
||||
sym = Ppmd7z_DecodeSymbol(p);
|
||||
if (sym < 0)
|
||||
break;
|
||||
*buf = (Byte)sym;
|
||||
}
|
||||
while (++buf < lim);
|
||||
p->LastSymbol = sym;
|
||||
return buf;
|
||||
}
|
||||
*/
|
|
@ -1,10 +0,0 @@
|
|||
/* Precomp.h -- StdAfx
|
||||
2013-11-12 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_PRECOMP_H
|
||||
#define __7Z_PRECOMP_H
|
||||
|
||||
/* #include "Compiler.h" */
|
||||
/* #include "7zTypes.h" */
|
||||
|
||||
#endif
|
|
@ -1,15 +0,0 @@
|
|||
To update to the latest version of the LZMA SDK:
|
||||
1. Grab the latest version from:
|
||||
https://sourceforge.net/projects/sevenzip/files/LZMA%20SDK/
|
||||
and unpack it
|
||||
2. For the files in evince's copy/paste, copy the originals from the
|
||||
C/ sub-directory of the SDK:
|
||||
for i in *.[ch] ; do cp /tmp/lzma1803/C/$i . ; done
|
||||
3. Convert the copied files to Unix format:
|
||||
dos2unix *.[ch]
|
||||
4. Use "git add -p" to apply only the sections that are of interest
|
||||
and do not regress warning fixes (see commits a2aa919 and 5e1a0ef
|
||||
for example)
|
||||
|
||||
Note that you might end up with an empty commit (for example 79b5fe5)
|
||||
which is fine, as long as the change is documented.
|
|
@ -1,28 +0,0 @@
|
|||
sources = files(
|
||||
'common/conv.c',
|
||||
'common/crc32.c',
|
||||
'common/stream.c',
|
||||
'common/unarr.c',
|
||||
'lzmasdk/CpuArch.c',
|
||||
'lzmasdk/Ppmd7.c',
|
||||
'lzmasdk/Ppmd7Dec.c',
|
||||
'rar/filter-rar.c',
|
||||
'rar/huffman-rar.c',
|
||||
'rar/parse-rar.c',
|
||||
'rar/rar.c',
|
||||
'rar/rarvm.c',
|
||||
'rar/uncompress-rar.c',
|
||||
)
|
||||
|
||||
libunarr = static_library(
|
||||
'unarr',
|
||||
sources: sources,
|
||||
dependencies: zlib_dep,
|
||||
c_args: [ '-DHAVE_ZLIB', '-DNDEBUG' ],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
)
|
||||
|
||||
libunarr_dep = declare_dependency(
|
||||
include_directories: include_directories('.'),
|
||||
link_with: libunarr,
|
||||
)
|
|
@ -1,704 +0,0 @@
|
|||
/* 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);
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/* 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));
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/* 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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#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
|
|
@ -1,236 +0,0 @@
|
|||
/* 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;
|
||||
}
|
|
@ -1,254 +0,0 @@
|
|||
/* 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);
|
||||
}
|
||||
|
||||
ar_archive *ar_open_rar_archive_with_error(ar_stream *stream,
|
||||
ArArchiveError *error_code)
|
||||
{
|
||||
char signature[FILE_SIGNATURE_SIZE];
|
||||
ar_archive *ret;
|
||||
|
||||
if (!ar_seek(stream, 0, SEEK_SET)) {
|
||||
*error_code = AR_ARCHIVE_ERROR_UNKNOWN;
|
||||
return NULL;
|
||||
}
|
||||
if (ar_read(stream, signature, sizeof(signature)) != sizeof(signature)) {
|
||||
*error_code = AR_ARCHIVE_ERROR_UNKNOWN;
|
||||
return NULL;
|
||||
}
|
||||
if (memcmp(signature, "Rar!\x1A\x07\x00", sizeof(signature)) != 0) {
|
||||
if (memcmp(signature, "Rar!\x1A\x07\x01", sizeof(signature)) == 0)
|
||||
*error_code = AR_ARCHIVE_ERROR_RAR5;
|
||||
else if (memcmp(signature, "RE~^", 4) == 0)
|
||||
*error_code = AR_ARCHIVE_ERROR_OLDRAR;
|
||||
else if (memcmp(signature, "MZ", 2) == 0 || memcmp(signature, "\x7F\x45LF", 4) == 0)
|
||||
*error_code = AR_ARCHIVE_ERROR_SFX;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ret = ar_open_archive(stream, sizeof(ar_archive_rar), rar_close, rar_parse_entry, rar_get_name, rar_uncompress, NULL, FILE_SIGNATURE_SIZE);
|
||||
if (!ret)
|
||||
*error_code = AR_ARCHIVE_ERROR_UNKNOWN;
|
||||
return ret;
|
||||
}
|
|
@ -1,252 +0,0 @@
|
|||
/* 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 <limits.h>
|
||||
|
||||
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 {
|
||||
CPpmd7_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
|
|
@ -1,616 +0,0 @@
|
|||
/* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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 <stdio.h>
|
||||
|
||||
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
|
|
@ -1,117 +0,0 @@
|
|||
/* 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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);
|
||||
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
|
File diff suppressed because it is too large
Load Diff
|
@ -1,103 +0,0 @@
|
|||
/* Copyright 2015 the unarr project authors (see AUTHORS file).
|
||||
License: LGPLv3 */
|
||||
|
||||
#ifndef unarr_h
|
||||
#define unarr_h
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
typedef int64_t off64_t;
|
||||
typedef int64_t time64_t;
|
||||
|
||||
#define UNARR_API_VERSION 100
|
||||
|
||||
typedef enum {
|
||||
AR_ARCHIVE_ERROR_NONE,
|
||||
AR_ARCHIVE_ERROR_UNKNOWN,
|
||||
AR_ARCHIVE_ERROR_RAR5,
|
||||
AR_ARCHIVE_ERROR_OLDRAR,
|
||||
AR_ARCHIVE_ERROR_SFX
|
||||
} ArArchiveError;
|
||||
|
||||
/***** 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);
|
||||
ar_archive *ar_open_rar_archive_with_error(ar_stream *stream, ArArchiveError *error_code);
|
||||
|
||||
/***** 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
|
|
@ -30,7 +30,6 @@ backend/tiff/tiffdocument.evince-backend.desktop.in
|
|||
backend/xps/evince-xpsdocument.metainfo.xml.in
|
||||
backend/xps/xpsdocument.evince-backend.desktop.in
|
||||
cut-n-paste/libdazzle/dzl-file-manager.c
|
||||
cut-n-paste/unarr/common/conv.c
|
||||
data/org.gnome.Evince.desktop.in
|
||||
data/org.gnome.Evince-previewer.desktop.in
|
||||
data/org.gnome.evince.Daemon.service.in
|
||||
|
|
Loading…
Reference in New Issue
Block a user