From: Mostyn Bramley-Moore Date: Sun, 11 Jun 2023 16:52:40 +0000 (+0200) Subject: 7zip reader: add 7z ARM filter support for copy/bzip2/deflate/zstd X-Git-Tag: v3.7.0~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0443198a9279a69b396aff70b2273ddb36f3769e;p=thirdparty%2Flibarchive.git 7zip reader: add 7z ARM filter support for copy/bzip2/deflate/zstd This makes the new test_read_format_7zip_zstd_arm test pass. I expect that the other compression algorithms in this group should also work now. --- diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index a0553c7ee..df6f035ed 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -407,6 +407,8 @@ static int setup_decode_folder(struct archive_read *, struct _7z_folder *, int); static void x86_Init(struct _7zip *); static size_t x86_Convert(struct _7zip *, uint8_t *, size_t); +static void arm_Init(struct _7zip *); +static size_t arm_Convert(struct _7zip *, uint8_t *, size_t); static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t); @@ -1041,7 +1043,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip, case _7Z_PPMD: if (coder2 != NULL) { if (coder2->codec != _7Z_X86 && - coder2->codec != _7Z_X86_BCJ2) { + coder2->codec != _7Z_X86_BCJ2 && + coder2->codec != _7Z_ARM) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unsupported filter %lx for %lx", @@ -1052,6 +1055,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip, zip->bcj_state = 0; if (coder2->codec == _7Z_X86) x86_Init(zip); + else if (coder2->codec == _7Z_ARM) + arm_Init(zip); } break; default: @@ -1615,16 +1620,21 @@ decompress(struct archive_read *a, struct _7zip *zip, /* * Decord BCJ. */ - if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) { - size_t l = x86_Convert(zip, buff, *outbytes); - zip->odd_bcj_size = *outbytes - l; - if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 && - o_avail_in && ret != ARCHIVE_EOF) { - memcpy(zip->odd_bcj, ((unsigned char *)buff) + l, - zip->odd_bcj_size); - *outbytes = l; - } else - zip->odd_bcj_size = 0; + if (zip->codec != _7Z_LZMA2 && (zip->codec2 == _7Z_X86 || zip->codec2 == _7Z_ARM)) { + if (zip->codec2 == _7Z_X86) { + size_t l = x86_Convert(zip, buff, *outbytes); + + zip->odd_bcj_size = *outbytes - l; + if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 && + o_avail_in && ret != ARCHIVE_EOF) { + memcpy(zip->odd_bcj, ((unsigned char *)buff) + l, + zip->odd_bcj_size); + *outbytes = l; + } else + zip->odd_bcj_size = 0; + } else { // zip->codec2 == _7Z_ARM + *outbytes = arm_Convert(zip, buff, *outbytes); + } } /* @@ -3770,6 +3780,53 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size) return (bufferPos); } +static void +arm_Init(struct _7zip *zip) +{ + zip->bcj_ip = 8; +} + +static size_t +arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size) +{ + // This function was adapted from + // static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size) + // in https://git.tukaani.org/xz-embedded.git + + /* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) { + if (buf[i + 3] == 0xEB) { + // Calculate the transformed addr. + addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) + | ((uint32_t)buf[i + 2] << 16); + addr <<= 2; + addr -= zip->bcj_ip + (uint32_t)i; + addr >>= 2; + + // Store the transformed addr in buf. + buf[i] = (uint8_t)addr; + buf[i + 1] = (uint8_t)(addr >> 8); + buf[i + 2] = (uint8_t)(addr >> 16); + } + } + + zip->bcj_ip += i; + + return i; +} + /* * Brought from LZMA SDK. *