1
0
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:
Bastien Nocera 2022-01-12 16:18:29 +01:00 committed by Germán Poo-Caamaño
parent e25912b3a2
commit d97fdcda6e
30 changed files with 0 additions and 7522 deletions

View File

@ -3,7 +3,6 @@ cut_n_paste_inc = include_directories('.')
subdir('gimpcellrenderertoggle')
subdir('libdazzle')
subdir('libgd')
subdir('unarr')
if not external_synctex
subdir('synctex')

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
*/

View File

@ -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

View File

@ -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.

View File

@ -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,
)

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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