Merge commit 'ee861bc6cf7ccec4a056443488e7b0860b8b0606' as 'external/unarr'
This commit is contained in:
205
external/unarr/_7z/_7z.c
vendored
Normal file
205
external/unarr/_7z/_7z.c
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
/* Copyright 2018 the unarr project authors (see AUTHORS file).
|
||||
License: LGPLv3 */
|
||||
|
||||
#include "_7z.h"
|
||||
|
||||
#ifdef HAVE_7Z
|
||||
|
||||
static void *gSzAlloc_Alloc(ISzAllocPtr self, size_t size) { (void)self; return malloc(size); }
|
||||
static void gSzAlloc_Free(ISzAllocPtr self, void *ptr) { (void)self; free(ptr); }
|
||||
static ISzAlloc gSzAlloc = { gSzAlloc_Alloc, gSzAlloc_Free };
|
||||
|
||||
static SRes CSeekStream_Read(const ISeekInStream *p, void *data, size_t *size)
|
||||
{
|
||||
struct CSeekStream *stm = (struct CSeekStream *) p;
|
||||
*size = ar_read(stm->stream, data, *size);
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes CSeekStream_Seek(const ISeekInStream *p, Int64 *pos, ESzSeek origin)
|
||||
{
|
||||
struct CSeekStream *stm = (struct CSeekStream *) p;
|
||||
if (!ar_seek(stm->stream, *pos, (int)origin))
|
||||
return SZ_ERROR_FAIL;
|
||||
*pos = ar_tell(stm->stream);
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static void CSeekStream_CreateVTable(struct CSeekStream *in_stream, ar_stream *stream)
|
||||
{
|
||||
in_stream->super.Read = CSeekStream_Read;
|
||||
in_stream->super.Seek = CSeekStream_Seek;
|
||||
in_stream->stream = stream;
|
||||
}
|
||||
|
||||
#ifndef USE_7Z_CRC32
|
||||
UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return ar_crc32(0, data, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _7z_close(ar_archive *ar)
|
||||
{
|
||||
ar_archive_7z *_7z = (ar_archive_7z *)ar;
|
||||
free(_7z->entry_name);
|
||||
SzArEx_Free(&_7z->data, &gSzAlloc);
|
||||
IAlloc_Free(&gSzAlloc, _7z->uncomp.buffer);
|
||||
IAlloc_Free(&gSzAlloc, _7z->look_stream.buf);
|
||||
}
|
||||
|
||||
static const char *_7z_get_name(ar_archive *ar, bool raw);
|
||||
|
||||
static bool _7z_parse_entry(ar_archive *ar, off64_t offset)
|
||||
{
|
||||
ar_archive_7z *_7z = (ar_archive_7z *)ar;
|
||||
//const CSzFileItem *item = _7z->data.db.PackPositions + offset;
|
||||
|
||||
if (offset < 0 || offset > _7z->data.NumFiles) {
|
||||
warn("Offsets must be between 0 and %u", _7z->data.NumFiles);
|
||||
return false;
|
||||
}
|
||||
if (offset == _7z->data.NumFiles) {
|
||||
ar->at_eof = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
ar->entry_offset = offset;
|
||||
ar->entry_offset_next = offset + 1;
|
||||
ar->entry_size_uncompressed = (size_t)SzArEx_GetFileSize(&_7z->data, offset);
|
||||
ar->entry_filetime = SzBitWithVals_Check(&_7z->data.MTime, offset) ?
|
||||
(time64_t)(_7z->data.MTime.Vals[offset].Low |
|
||||
((time64_t)_7z->data.MTime.Vals[offset].High << 32))
|
||||
: 0;
|
||||
free(_7z->entry_name);
|
||||
_7z->entry_name = NULL;
|
||||
_7z->uncomp.initialized = false;
|
||||
|
||||
if (SzArEx_IsDir(&_7z->data, offset)) {
|
||||
log("Skipping directory entry \"%s\"", _7z_get_name(ar, false));
|
||||
return _7z_parse_entry(ar, offset + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *SzArEx_GetFileNameUtf8(const CSzArEx *p, UInt32 fileIndex)
|
||||
{
|
||||
size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
|
||||
const Byte *src = p->FileNames + p->FileNameOffsets[fileIndex] * 2;
|
||||
const Byte *srcEnd = src + len * 2;
|
||||
size_t size = len * 3;
|
||||
char *str, *out;
|
||||
|
||||
if (size == (size_t)-1)
|
||||
return NULL;
|
||||
str = malloc(size + 1);
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
for (out = str; src < srcEnd - 1; src += 2) {
|
||||
out += ar_conv_rune_to_utf8(src[0] | src[1] << 8, out, str + size - out);
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static const char *_7z_get_name(ar_archive *ar, bool raw)
|
||||
{
|
||||
if (raw)
|
||||
return NULL;
|
||||
|
||||
ar_archive_7z *_7z = (ar_archive_7z *)ar;
|
||||
if (!_7z->entry_name && ar->entry_offset_next && !ar->at_eof) {
|
||||
_7z->entry_name = SzArEx_GetFileNameUtf8(&_7z->data, (UInt32)ar->entry_offset);
|
||||
/* normalize path separators */
|
||||
if (_7z->entry_name) {
|
||||
char *p = _7z->entry_name;
|
||||
while ((p = strchr(p, '\\')) != NULL) {
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
return _7z->entry_name;
|
||||
}
|
||||
|
||||
static bool _7z_uncompress(ar_archive *ar, void *buffer, size_t buffer_size)
|
||||
{
|
||||
ar_archive_7z *_7z = (ar_archive_7z *)ar;
|
||||
struct ar_archive_7z_uncomp *uncomp = &_7z->uncomp;
|
||||
|
||||
if (!uncomp->initialized) {
|
||||
/* TODO: this uncompresses all data for solid compressions */
|
||||
SRes res = SzArEx_Extract(&_7z->data, &_7z->look_stream.vt, (UInt32)ar->entry_offset, &uncomp->folder_index, &uncomp->buffer, &uncomp->buffer_size, &uncomp->offset, &uncomp->bytes_left, &gSzAlloc, &gSzAlloc);
|
||||
if (res != SZ_OK) {
|
||||
warn("Failed to extract file at index %" PRIi64 " (failed with error %d)", ar->entry_offset, res);
|
||||
return false;
|
||||
}
|
||||
if (uncomp->bytes_left != ar->entry_size_uncompressed) {
|
||||
warn("Uncompressed sizes don't match (%" PRIuPTR " != %" PRIuPTR ")", uncomp->bytes_left, ar->entry_size_uncompressed);
|
||||
return false;
|
||||
}
|
||||
uncomp->initialized = true;
|
||||
}
|
||||
|
||||
if (buffer_size > uncomp->bytes_left) {
|
||||
warn("Requesting too much data (%" PRIuPTR " < %" PRIuPTR ")", uncomp->bytes_left, buffer_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(buffer, uncomp->buffer + uncomp->offset + ar->entry_size_uncompressed - uncomp->bytes_left, buffer_size);
|
||||
uncomp->bytes_left -= buffer_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ar_archive *ar_open_7z_archive(ar_stream *stream)
|
||||
{
|
||||
ar_archive *ar;
|
||||
ar_archive_7z *_7z;
|
||||
SRes res;
|
||||
|
||||
if (!ar_seek(stream, 0, SEEK_SET))
|
||||
return NULL;
|
||||
|
||||
ar = ar_open_archive(stream, sizeof(ar_archive_7z), _7z_close, _7z_parse_entry, _7z_get_name, _7z_uncompress, NULL, 0);
|
||||
if (!ar)
|
||||
return NULL;
|
||||
|
||||
_7z = (ar_archive_7z *)ar;
|
||||
CSeekStream_CreateVTable(&_7z->in_stream, stream);
|
||||
LookToRead2_CreateVTable(&_7z->look_stream, False);
|
||||
_7z->look_stream.realStream = &_7z->in_stream.super;
|
||||
_7z->look_stream.buf = ISzAlloc_Alloc(&gSzAlloc, 1 << 18);
|
||||
_7z->look_stream.bufSize = 1 << 18;
|
||||
LookToRead2_INIT(&_7z->look_stream);
|
||||
|
||||
|
||||
#ifdef USE_7Z_CRC32
|
||||
CrcGenerateTable();
|
||||
#endif
|
||||
|
||||
SzArEx_Init(&_7z->data);
|
||||
res = SzArEx_Open(&_7z->data, &_7z->look_stream.vt, &gSzAlloc, &gSzAlloc);
|
||||
if (res != SZ_OK) {
|
||||
if (res != SZ_ERROR_NO_ARCHIVE)
|
||||
warn("Invalid 7z archive (failed with error %d)", res);
|
||||
ISzAlloc_Free(&gSzAlloc, _7z->look_stream.buf);
|
||||
free(ar);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ar_archive *ar_open_7z_archive(ar_stream *stream)
|
||||
{
|
||||
(void)stream;
|
||||
warn("7z support requires 7z SDK (define HAVE_7Z)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
47
external/unarr/_7z/_7z.h
vendored
Normal file
47
external/unarr/_7z/_7z.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/* Copyright 2018 the unarr project authors (see AUTHORS file).
|
||||
License: LGPLv3 */
|
||||
|
||||
#ifndef _7z_7z_h
|
||||
#define _7z_7z_h
|
||||
|
||||
#include "../common/unarr-imp.h"
|
||||
|
||||
#include "../lzmasdk/7zTypes.h"
|
||||
#ifdef HAVE_7Z
|
||||
#include "../lzmasdk/7z.h"
|
||||
#endif
|
||||
|
||||
typedef struct ar_archive_7z_s ar_archive_7z;
|
||||
|
||||
struct CSeekStream {
|
||||
ISeekInStream super;
|
||||
ar_stream *stream;
|
||||
};
|
||||
|
||||
struct ar_archive_7z_uncomp {
|
||||
bool initialized;
|
||||
|
||||
UInt32 folder_index;
|
||||
Byte *buffer;
|
||||
size_t buffer_size;
|
||||
|
||||
size_t offset;
|
||||
size_t bytes_left;
|
||||
};
|
||||
|
||||
struct ar_archive_7z_s {
|
||||
ar_archive super;
|
||||
struct CSeekStream in_stream;
|
||||
#ifdef HAVE_7Z
|
||||
CLookToRead2 look_stream;
|
||||
CSzArEx data;
|
||||
#endif
|
||||
char *entry_name;
|
||||
struct ar_archive_7z_uncomp uncomp;
|
||||
};
|
||||
|
||||
#ifndef USE_7Z_CRC32
|
||||
UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user