src: move compress files into a subdir; clang-format some more files; NFC

This commit is contained in:
Markus F.X.J. Oberhumer
2023-01-18 09:28:12 +01:00
parent 334be287fc
commit 6c41a4c9c8
17 changed files with 183 additions and 212 deletions
+208
View File
@@ -0,0 +1,208 @@
/* compress.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
*/
#include "../conf.h"
#include "compress.h"
#include "../util/membuffer.h"
/*************************************************************************
//
**************************************************************************/
unsigned upx_adler32(const void *buf, unsigned len, unsigned adler) {
if (len == 0)
return adler;
assert(buf != nullptr);
#if 1
return upx_ucl_adler32(buf, len, adler);
#else
return upx_zlib_adler32(buf, len, adler);
#endif
}
#if 0 // UNUSED
unsigned upx_crc32(const void *buf, unsigned len, unsigned crc)
{
if (len == 0)
return crc;
assert(buf != nullptr);
#if 1
return upx_ucl_crc32(buf, len, crc);
#else
return upx_zlib_crc32(buf, len, crc);
#endif
}
#endif // UNUSED
/*************************************************************************
//
**************************************************************************/
int upx_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
upx_callback_p cb, int method, int level, const upx_compress_config_t *cconf,
upx_compress_result_t *cresult) {
int r = UPX_E_ERROR;
upx_compress_result_t cresult_buffer;
assert(method > 0);
assert(level > 0);
#if 1
// set available bytes in dst
if (*dst_len == 0)
*dst_len = MemBuffer::getSizeForCompression(src_len);
#else
// force users to provide *dst_len
assert(*dst_len != 0);
#endif
// for UPX, we always require a reasonably sized outbut buffer
assert(*dst_len >= MemBuffer::getSizeForCompression(src_len));
if (!cresult)
cresult = &cresult_buffer;
memset(cresult, 0, sizeof(*cresult));
#if 1
// debugging aid
cresult->debug.method = method;
cresult->debug.level = level;
cresult->debug.u_len = src_len;
cresult->debug.c_len = 0;
#endif
if (__acc_cte(false)) {
}
#if (WITH_LZMA)
else if (M_IS_LZMA(method))
r = upx_lzma_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult);
#endif
#if (WITH_NRV)
else if ((M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) && !opt->prefer_ucl)
r = upx_nrv_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult);
#endif
#if (WITH_UCL)
else if (M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method))
r = upx_ucl_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult);
#endif
#if (WITH_ZSTD)
else if (M_IS_ZSTD(method))
r = upx_zstd_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult);
#endif
else {
throwInternalError("unknown compression method");
}
#if 1
// debugging aid
cresult->debug.c_len = *dst_len;
#endif
return r;
}
/*************************************************************************
//
**************************************************************************/
int upx_decompress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
int method, const upx_compress_result_t *cresult) {
int r = UPX_E_ERROR;
assert(*dst_len > 0);
assert(src_len < *dst_len); // must be compressed
if (cresult && cresult->debug.method == 0)
cresult = nullptr;
if (__acc_cte(false)) {
}
#if (WITH_LZMA)
else if (M_IS_LZMA(method))
r = upx_lzma_decompress(src, src_len, dst, dst_len, method, cresult);
#endif
#if (WITH_NRV)
else if ((M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) && !opt->prefer_ucl)
r = upx_nrv_decompress(src, src_len, dst, dst_len, method, cresult);
#endif
#if (WITH_UCL)
else if (M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method))
r = upx_ucl_decompress(src, src_len, dst, dst_len, method, cresult);
#endif
#if (WITH_ZLIB)
else if (M_IS_DEFLATE(method))
r = upx_zlib_decompress(src, src_len, dst, dst_len, method, cresult);
#endif
#if (WITH_ZSTD)
else if (M_IS_ZSTD(method))
r = upx_zstd_decompress(src, src_len, dst, dst_len, method, cresult);
#endif
else {
throwInternalError("unknown decompression method");
}
return r;
}
/*************************************************************************
//
**************************************************************************/
int upx_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src_off, unsigned src_len,
unsigned *dst_len, int method, const upx_compress_result_t *cresult) {
int r = UPX_E_ERROR;
if (cresult && cresult->debug.method == 0)
cresult = nullptr;
assert(*dst_len > 0);
assert(src_len < *dst_len); // must be compressed
unsigned overlap_overhead = src_off + src_len - *dst_len;
assert((int) overlap_overhead > 0);
if (__acc_cte(false)) {
}
#if (WITH_LZMA)
else if (M_IS_LZMA(method))
r = upx_lzma_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult);
#endif
#if (WITH_NRV)
else if ((M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) && !opt->prefer_ucl)
r = upx_nrv_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult);
#endif
#if (WITH_UCL)
else if (M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method))
r = upx_ucl_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult);
#endif
#if (WITH_ZSTD)
else if (M_IS_ZSTD(method))
r = upx_zstd_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult);
#endif
else {
throwInternalError("unknown decompression method");
}
return r;
}
/* vim:set ts=4 sw=4 et: */
+173
View File
@@ -0,0 +1,173 @@
/* compress.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
*/
#pragma once
#ifndef UPX_COMPRESS_H__
#define UPX_COMPRESS_H__ 1
/*************************************************************************
//
**************************************************************************/
#if (WITH_BZIP2)
int upx_bzip2_init(void);
const char *upx_bzip2_version_string(void);
int upx_bzip2_compress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
upx_callback_p cb,
int method, int level,
const upx_compress_config_t *cconf,
upx_compress_result_t *cresult );
int upx_bzip2_decompress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
int upx_bzip2_test_overlap ( const upx_bytep buf,
const upx_bytep tbuf,
unsigned src_off, unsigned src_len,
unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
#endif
#if (WITH_LZMA)
int upx_lzma_init(void);
const char *upx_lzma_version_string(void);
int upx_lzma_compress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
upx_callback_p cb,
int method, int level,
const upx_compress_config_t *cconf,
upx_compress_result_t *cresult );
int upx_lzma_decompress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
int upx_lzma_test_overlap ( const upx_bytep buf,
const upx_bytep tbuf,
unsigned src_off, unsigned src_len,
unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
#endif
#if (WITH_NRV)
int upx_nrv_init(void);
const char *upx_nrv_version_string(void);
int upx_nrv_compress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
upx_callback_p cb,
int method, int level,
const upx_compress_config_t *cconf,
upx_compress_result_t *cresult );
int upx_nrv_decompress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
int upx_nrv_test_overlap ( const upx_bytep buf,
const upx_bytep tbuf,
unsigned src_off, unsigned src_len,
unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
#endif
#if (WITH_UCL)
int upx_ucl_init(void);
const char *upx_ucl_version_string(void);
int upx_ucl_compress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
upx_callback_p cb,
int method, int level,
const upx_compress_config_t *cconf,
upx_compress_result_t *cresult );
int upx_ucl_decompress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
int upx_ucl_test_overlap ( const upx_bytep buf,
const upx_bytep tbuf,
unsigned src_off, unsigned src_len,
unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
unsigned upx_ucl_adler32(const void *buf, unsigned len, unsigned adler);
unsigned upx_ucl_crc32 (const void *buf, unsigned len, unsigned crc);
#endif
#if (WITH_ZLIB)
int upx_zlib_init(void);
const char *upx_zlib_version_string(void);
int upx_zlib_compress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
upx_callback_p cb,
int method, int level,
const upx_compress_config_t *cconf,
upx_compress_result_t *cresult );
int upx_zlib_decompress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
int upx_zlib_test_overlap ( const upx_bytep buf,
const upx_bytep tbuf,
unsigned src_off, unsigned src_len,
unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
unsigned upx_zlib_adler32(const void *buf, unsigned len, unsigned adler);
unsigned upx_zlib_crc32 (const void *buf, unsigned len, unsigned crc);
#endif
#if (WITH_ZSTD)
int upx_zstd_init(void);
const char *upx_zstd_version_string(void);
int upx_zstd_compress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
upx_callback_p cb,
int method, int level,
const upx_compress_config_t *cconf,
upx_compress_result_t *cresult );
int upx_zstd_decompress ( const upx_bytep src, unsigned src_len,
upx_bytep dst, unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
int upx_zstd_test_overlap ( const upx_bytep buf,
const upx_bytep tbuf,
unsigned src_off, unsigned src_len,
unsigned* dst_len,
int method,
const upx_compress_result_t *cresult );
#endif
#endif /* already included */
/* vim:set ts=4 sw=4 et: */
+544
View File
@@ -0,0 +1,544 @@
/* compress_lzma.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
*/
#include "../conf.h"
#include "compress.h"
#include "../util/membuffer.h"
#if (ACC_CC_CLANG)
#pragma clang diagnostic ignored "-Wshadow"
#endif
#if (ACC_CC_GNUC >= 0x040200)
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#if (ACC_CC_MSC)
#pragma warning(disable : 4456) // -Wno-shadow
#endif
#if (ACC_CC_MSC && (_MSC_VER < 1900))
#pragma warning(disable : 4127) // warning C4127: conditional expression is constant
#endif
void lzma_compress_config_t::reset() {
pos_bits.reset();
lit_pos_bits.reset();
lit_context_bits.reset();
dict_size.reset();
fast_mode = 2;
num_fast_bytes.reset();
match_finder_cycles = 0;
max_num_probs = 0;
}
// INFO: the LZMA SDK is covered by a permissive license which allows
// using unmodified LZMA source code in UPX and the UPX stubs.
// See SPECIAL EXCEPTION below.
//
// Quoting from lzma-4.43/lzma.txt:
//
// LICENSE
// -------
//
// LZMA SDK is available under any of the following licenses:
//
// 1) GNU Lesser General Public License (GNU LGPL)
// 2) Common Public License (CPL)
// 3) Simplified license for unmodified code (read SPECIAL EXCEPTION)
// 4) Proprietary license
//
// It means that you can select one of these four options and follow rules
// of that license.
//
// 1,2) GNU LGPL and CPL licenses are pretty similar and both these
// licenses are classified as
// - "Free software licenses" at http://www.gnu.org/
// - "OSI-approved" at http://www.opensource.org/
//
// 3) SPECIAL EXCEPTION
//
// Igor Pavlov, as the author of this code, expressly permits you
// to statically or dynamically link your code (or bind by name)
// to the files from LZMA SDK without subjecting your linked
// code to the terms of the CPL or GNU LGPL.
// Any modifications or additions to files from LZMA SDK, however,
// are subject to the GNU LGPL or CPL terms.
//
// SPECIAL EXCEPTION allows you to use LZMA SDK in applications with closed code,
// while you keep LZMA SDK code unmodified.
/*************************************************************************
// compress defaults
**************************************************************************/
static bool prepare_result(lzma_compress_result_t *res, unsigned src_len, int method, int level,
const lzma_compress_config_t *lcconf) {
// setup defaults
res->pos_bits = 2; // 0 .. 4
res->lit_pos_bits = 0; // 0 .. 4
res->lit_context_bits = 3; // 0 .. 8
res->dict_size = 4 * 1024 * 1024; // 1 .. 2**30
res->fast_mode = 2; // 0 .. 2
res->num_fast_bytes = 64; // 5 .. 273
res->match_finder_cycles = 0;
// UPX overrides
res->pos_bits = lzma_compress_config_t::pos_bits_t::default_value;
res->lit_pos_bits = lzma_compress_config_t::lit_pos_bits_t::default_value;
res->lit_context_bits = lzma_compress_config_t::lit_context_bits_t::default_value;
res->dict_size = lzma_compress_config_t::dict_size_t::default_value;
res->num_fast_bytes = lzma_compress_config_t::num_fast_bytes_t::default_value;
// method overrides
if (method >= 0x100) {
res->pos_bits = (method >> 16) & 15;
res->lit_pos_bits = (method >> 12) & 15;
res->lit_context_bits = (method >> 8) & 15;
}
#if 0
// DEBUG - set sizes so that we use a maxmimum amount of stack.
// These settings cause res->num_probs == 3147574, i.e. we will
// need about 6 MiB of stack during runtime decompression.
res->lit_pos_bits = 4;
res->lit_context_bits = 8;
#endif
// TODO: tune these settings according to level
switch (level) {
case 1:
res->dict_size = 256 * 1024;
res->fast_mode = 0;
res->num_fast_bytes = 8;
break;
case 2:
res->dict_size = 256 * 1024;
res->fast_mode = 0;
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
res->dict_size = 8 * 1024 * 1024;
break;
case 10:
res->dict_size = src_len;
break;
default:
goto error;
}
// cconf overrides
if (lcconf) {
oassign(res->pos_bits, lcconf->pos_bits);
oassign(res->lit_pos_bits, lcconf->lit_pos_bits);
oassign(res->lit_context_bits, lcconf->lit_context_bits);
oassign(res->dict_size, lcconf->dict_size);
oassign(res->num_fast_bytes, lcconf->num_fast_bytes);
}
// limit dictionary size
if (res->dict_size > src_len)
res->dict_size = src_len;
// limit num_probs
if (lcconf && lcconf->max_num_probs) {
for (;;) {
unsigned n = 1846 + (768u << (res->lit_context_bits + res->lit_pos_bits));
if (n <= lcconf->max_num_probs)
break;
if (res->lit_pos_bits > res->lit_context_bits) {
if (res->lit_pos_bits == 0)
goto error;
res->lit_pos_bits -= 1;
} else {
if (res->lit_context_bits == 0)
goto error;
res->lit_context_bits -= 1;
}
}
}
lzma_compress_config_t::pos_bits_t::assertValue(res->pos_bits);
lzma_compress_config_t::lit_pos_bits_t::assertValue(res->lit_pos_bits);
lzma_compress_config_t::lit_context_bits_t::assertValue(res->lit_context_bits);
lzma_compress_config_t::dict_size_t::assertValue(res->dict_size);
lzma_compress_config_t::num_fast_bytes_t::assertValue(res->num_fast_bytes);
res->num_probs = 1846 + (768u << (res->lit_context_bits + res->lit_pos_bits));
// printf("\nlzma_compress config: %u %u %u %u %u\n", res->pos_bits, res->lit_pos_bits,
// res->lit_context_bits, res->dict_size, res->num_probs);
return true;
error:
return false;
}
/*************************************************************************
// compress - cruft because of pseudo-COM layer
**************************************************************************/
#undef MSDOS
#undef OS2
#undef _WIN32
#undef _WIN32_WCE
#undef COMPRESS_MF_MT
#undef _NO_EXCEPTIONS
#undef NULL
#define NULL nullptr
#include <lzma-sdk/C/Common/MyInitGuid.h>
// #include <lzma-sdk/C/7zip/Compress/LZMA/LZMADecoder.h>
#include <lzma-sdk/C/7zip/Compress/LZMA/LZMAEncoder.h>
namespace MyLzma {
struct InStream final : public ISequentialInStream, public CMyUnknownImp {
virtual ~InStream() {}
MY_UNKNOWN_IMP
const Byte *b_buf = nullptr;
size_t b_size;
size_t b_pos;
void Init(const Byte *data, size_t size) {
b_buf = data;
b_size = size;
b_pos = 0;
}
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) override;
};
STDMETHODIMP InStream::Read(void *data, UInt32 size, UInt32 *processedSize) {
size_t remain = b_size - b_pos;
if (size > remain)
size = (UInt32) remain;
memmove(data, b_buf + b_pos, size);
b_pos += size;
if (processedSize != nullptr)
*processedSize = size;
return S_OK;
}
struct OutStream final : public ISequentialOutStream, public CMyUnknownImp {
virtual ~OutStream() {}
MY_UNKNOWN_IMP
Byte *b_buf = nullptr;
size_t b_size;
size_t b_pos;
bool overflow;
void Init(Byte *data, size_t size) {
b_buf = data;
b_size = size;
b_pos = 0;
overflow = false;
}
HRESULT WriteByte(Byte c) {
if (b_pos >= b_size) {
overflow = true;
return E_FAIL;
}
b_buf[b_pos++] = c;
return S_OK;
}
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) override;
};
STDMETHODIMP OutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) {
size_t remain = b_size - b_pos;
if (size > remain)
size = (UInt32) remain, overflow = true;
memmove(b_buf + b_pos, data, size);
b_pos += size;
if (processedSize != nullptr)
*processedSize = size;
return overflow ? E_FAIL : S_OK;
}
struct ProgressInfo final : public ICompressProgressInfo, public CMyUnknownImp {
virtual ~ProgressInfo() {}
MY_UNKNOWN_IMP
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) override;
upx_callback_p cb = nullptr;
};
STDMETHODIMP ProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) {
if (cb && cb->nprogress)
cb->nprogress(cb, (unsigned) *inSize, (unsigned) *outSize);
return S_OK;
}
} // namespace MyLzma
#include <lzma-sdk/C/Common/Alloc.cpp>
#include <lzma-sdk/C/Common/CRC.cpp>
// #include <lzma-sdk/C/7zip/Common/InBuffer.cpp>
#include <lzma-sdk/C/7zip/Common/OutBuffer.cpp>
#include <lzma-sdk/C/7zip/Common/StreamUtils.cpp>
#include <lzma-sdk/C/7zip/Compress/LZ/LZInWindow.cpp>
// #include <lzma-sdk/C/7zip/Compress/LZ/LZOutWindow.cpp>
// #include <lzma-sdk/C/7zip/Compress/LZMA/LZMADecoder.cpp>
#include <lzma-sdk/C/7zip/Compress/LZMA/LZMAEncoder.cpp>
#include <lzma-sdk/C/7zip/Compress/RangeCoder/RangeCoderBit.cpp>
#undef RC_NORMALIZE
int upx_lzma_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
upx_callback_p cb, int method, int level,
const upx_compress_config_t *cconf_parm, upx_compress_result_t *cresult) {
assert(M_IS_LZMA(method));
assert(level > 0);
assert(cresult != nullptr);
int r = UPX_E_ERROR;
HRESULT rh;
const lzma_compress_config_t *const lcconf = cconf_parm ? &cconf_parm->conf_lzma : nullptr;
lzma_compress_result_t *const res = &cresult->result_lzma;
MyLzma::InStream is;
is.AddRef();
is.Init(src, src_len);
MyLzma::OutStream os;
os.AddRef();
os.Init(dst, *dst_len);
MyLzma::ProgressInfo progress;
progress.AddRef();
progress.cb = cb; // progress.Init()
NCompress::NLZMA::CEncoder enc;
const PROPID propIDs[8] = {
NCoderPropID::kPosStateBits, // 0 pb _posStateBits(2)
NCoderPropID::kLitPosBits, // 1 lp _numLiteralPosStateBits(0)
NCoderPropID::kLitContextBits, // 2 lc _numLiteralContextBits(3)
NCoderPropID::kDictionarySize, // 3 ds
NCoderPropID::kAlgorithm, // 4 fm _fastmode
NCoderPropID::kNumFastBytes, // 5 fb
NCoderPropID::kMatchFinderCycles, // 6 mfc _matchFinderCycles, _cutValue
NCoderPropID::kMatchFinder // 7 mf
};
PROPVARIANT pr[8];
const unsigned nprops = 8;
if (!prepare_result(res, src_len, method, level, lcconf))
goto error;
pr[0].vt = pr[1].vt = pr[2].vt = pr[3].vt = pr[4].vt = pr[5].vt = pr[6].vt = VT_UI4;
pr[7].vt = VT_BSTR;
pr[0].uintVal = res->pos_bits;
pr[1].uintVal = res->lit_pos_bits;
pr[2].uintVal = res->lit_context_bits;
pr[3].uintVal = res->dict_size;
pr[4].uintVal = res->fast_mode;
pr[5].uintVal = res->num_fast_bytes;
pr[6].uintVal = res->match_finder_cycles;
static const wchar_t matchfinder[] = L"BT4";
assert(NCompress::NLZMA::FindMatchFinder(matchfinder) >= 0);
pr[7].bstrVal = ACC_PCAST(BSTR, ACC_UNCONST_CAST(wchar_t *, matchfinder));
try {
if (enc.SetCoderProperties(propIDs, pr, nprops) != S_OK)
goto error;
// encode properties in LZMA-style (5 bytes)
if (enc.WriteCoderProperties(&os) != S_OK)
goto error;
if (os.overflow) {
// r = UPX_E_OUTPUT_OVERRUN;
r = UPX_E_NOT_COMPRESSIBLE;
goto error;
}
assert(os.b_pos == 5);
// reset and encode properties in UPX-style (2 bytes)
os.b_pos = 0;
// UPX extra stuff in first byte: 5 high bits convenience for stub decompressor
unsigned t = res->lit_context_bits + res->lit_pos_bits;
os.WriteByte(Byte((t << 3) | res->pos_bits));
os.WriteByte(Byte((res->lit_pos_bits << 4) | (res->lit_context_bits)));
// compress
rh = enc.Code(&is, &os, nullptr, nullptr, &progress);
} catch (...) {
rh = E_OUTOFMEMORY;
}
assert(is.b_pos <= src_len);
assert(os.b_pos <= *dst_len);
if (rh == E_OUTOFMEMORY)
r = UPX_E_OUT_OF_MEMORY;
else if (os.overflow) {
assert(os.b_pos == *dst_len);
// r = UPX_E_OUTPUT_OVERRUN;
r = UPX_E_NOT_COMPRESSIBLE;
} else if (rh == S_OK) {
assert(is.b_pos == src_len);
r = UPX_E_OK;
}
error:
*dst_len = (unsigned) os.b_pos;
// printf("\nlzma_compress: %d: %u %u %u %u %u, %u - > %u\n", r, res->pos_bits,
// res->lit_pos_bits,
// res->lit_context_bits, res->dict_size, res->num_probs, src_len, *dst_len);
// printf("%u %u %u\n", is.__m_RefCount, os.__m_RefCount, progress.__m_RefCount);
return r;
}
/*************************************************************************
// decompress
**************************************************************************/
#undef _LZMA_IN_CB
#undef _LZMA_OUT_READ
#undef _LZMA_PROB32
#undef _LZMA_LOC_OPT
#include <lzma-sdk/C/7zip/Compress/LZMA_C/LzmaDecode.h>
#include <lzma-sdk/C/7zip/Compress/LZMA_C/LzmaDecode.c>
int upx_lzma_decompress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
int method, const upx_compress_result_t *cresult) {
assert(M_IS_LZMA(method));
// see res->num_probs above
COMPILE_TIME_ASSERT(sizeof(CProb) == 2)
COMPILE_TIME_ASSERT(LZMA_BASE_SIZE == 1846)
COMPILE_TIME_ASSERT(LZMA_LIT_SIZE == 768)
CLzmaDecoderState s;
memset(&s, 0, sizeof(s));
SizeT src_out = 0, dst_out = 0;
int r = UPX_E_ERROR;
int rh;
// decode UPX-style properties (2 bytes)
if (src_len < 3) {
r = UPX_E_INPUT_OVERRUN;
goto error;
}
s.Properties.pb = src[0] & 7;
s.Properties.lp = (src[1] >> 4);
s.Properties.lc = src[1] & 15;
if (s.Properties.pb >= 5)
goto error;
if (s.Properties.lp >= 5)
goto error;
if (s.Properties.lc >= 9)
goto error;
// UPX extra stuff in first byte: 5 high bits convenience for stub decompressor
if ((src[0] >> 3) != s.Properties.lc + s.Properties.lp)
goto error;
src += 2;
src_len -= 2;
if (cresult) {
assert(cresult->debug.method == method);
assert(cresult->result_lzma.pos_bits == (unsigned) s.Properties.pb);
assert(cresult->result_lzma.lit_pos_bits == (unsigned) s.Properties.lp);
assert(cresult->result_lzma.lit_context_bits == (unsigned) s.Properties.lc);
assert(cresult->result_lzma.num_probs == (unsigned) LzmaGetNumProbs(&s.Properties));
const lzma_compress_result_t *res = &cresult->result_lzma;
// printf("\nlzma_decompress config: %u %u %u %u %u\n", res->pos_bits, res->lit_pos_bits,
// res->lit_context_bits, res->dict_size, res->num_probs);
UNUSED(res);
}
s.Probs = (CProb *) malloc(sizeof(CProb) * LzmaGetNumProbs(&s.Properties));
if (!s.Probs) {
r = UPX_E_OUT_OF_MEMORY;
goto error;
}
rh = LzmaDecode(&s, src, src_len, &src_out, dst, *dst_len, &dst_out);
assert(src_out <= src_len);
assert(dst_out <= *dst_len);
if (rh == 0) {
r = UPX_E_OK;
if (src_out != src_len)
r = UPX_E_INPUT_NOT_CONSUMED;
} else if (rh == LZMA_RESULT_INPUT_OVERRUN)
r = UPX_E_INPUT_OVERRUN;
else if (rh == LZMA_RESULT_OUTPUT_OVERRUN)
r = UPX_E_OUTPUT_OVERRUN;
error:
*dst_len = dst_out;
free(s.Probs);
return r;
}
/*************************************************************************
// test_overlap - see <ucl/ucl.h> for semantics
**************************************************************************/
int upx_lzma_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src_off,
unsigned src_len, unsigned *dst_len, int method,
const upx_compress_result_t *cresult) {
assert(M_IS_LZMA(method));
MemBuffer b(src_off + src_len);
memcpy(b + src_off, buf + src_off, src_len);
unsigned saved_dst_len = *dst_len;
int r = upx_lzma_decompress(raw_index_bytes(b, src_off, src_len), src_len,
raw_bytes(b, *dst_len), dst_len, method, cresult);
if (r != UPX_E_OK)
return r;
if (*dst_len != saved_dst_len)
return UPX_E_ERROR;
// NOTE: there is a very tiny possibility that decompression has
// succeeded but the data is not restored correctly because of
// in-place buffer overlapping, so we use an extra memcmp().
if (tbuf != nullptr && memcmp(tbuf, b, *dst_len) != 0)
return UPX_E_ERROR;
return UPX_E_OK;
}
/*************************************************************************
// misc
**************************************************************************/
int upx_lzma_init(void) { return 0; }
const char *upx_lzma_version_string(void) { return "4.43"; }
/*************************************************************************
// doctest checks
**************************************************************************/
TEST_CASE("upx_lzma_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[16];
unsigned d_len;
int r;
c_data = (C *) "\x1a\x03\x00\x7f\xed\x3c\x00\x00\x00";
d_len = 16;
r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr);
CHECK((r == 0 && d_len == 16));
r = upx_lzma_decompress(c_data, 8, d_buf, &d_len, M_LZMA, nullptr);
CHECK(r == UPX_E_INPUT_OVERRUN);
d_len = 15;
r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN);
}
/* vim:set ts=4 sw=4 et: */
+367
View File
@@ -0,0 +1,367 @@
/* compress_ucl.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
*/
#include "../conf.h"
#include "compress.h"
/*************************************************************************
//
**************************************************************************/
static int convert_errno_from_ucl(int r) {
switch (r) {
case UCL_E_OK:
return UPX_E_OK;
case UCL_E_ERROR:
return UPX_E_ERROR;
case UCL_E_OUT_OF_MEMORY:
return UPX_E_OUT_OF_MEMORY;
case UCL_E_NOT_COMPRESSIBLE:
return UPX_E_NOT_COMPRESSIBLE;
case UCL_E_INPUT_OVERRUN:
return UPX_E_INPUT_OVERRUN;
case UCL_E_OUTPUT_OVERRUN:
return UPX_E_OUTPUT_OVERRUN;
case UCL_E_LOOKBEHIND_OVERRUN:
return UPX_E_LOOKBEHIND_OVERRUN;
case UCL_E_EOF_NOT_FOUND:
return UPX_E_EOF_NOT_FOUND;
case UCL_E_INPUT_NOT_CONSUMED:
return UPX_E_INPUT_NOT_CONSUMED;
case UCL_E_INVALID_ARGUMENT:
return UPX_E_INVALID_ARGUMENT;
// UCL extra:
case UCL_E_OVERLAP_OVERRUN:
return UPX_E_ERROR;
}
return UPX_E_ERROR;
}
extern "C" {
static void __UCL_CDECL wrap_nprogress_ucl(ucl_uint a, ucl_uint b, int state, ucl_voidp user) {
if (state != -1 && state != 3)
return;
upx_callback_p cb = (upx_callback_p) user;
if (cb && cb->nprogress)
cb->nprogress(cb, a, b);
}
}
/*************************************************************************
//
**************************************************************************/
int upx_ucl_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
upx_callback_p cb_parm, int method, int level,
const upx_compress_config_t *cconf_parm, upx_compress_result_t *cresult) {
int r;
assert(level > 0);
assert(cresult != nullptr);
COMPILE_TIME_ASSERT(sizeof(ucl_compress_config_t) == sizeof(REAL_ucl_compress_config_t))
ucl_progress_callback_t cb;
cb.callback = nullptr;
cb.user = nullptr;
if (cb_parm && cb_parm->nprogress) {
cb.callback = wrap_nprogress_ucl;
cb.user = cb_parm;
}
ucl_compress_config_t cconf;
cconf.reset();
if (cconf_parm) {
// cconf = cconf_parm->conf_ucl; // struct copy
memcpy(&cconf, &cconf_parm->conf_ucl, sizeof(cconf));
}
ucl_uint *const res = cresult->result_ucl.result;
// assume no info available - fill in worst case results
// res[0] = 1; // min_offset_found - NOT USED
res[1] = src_len - 1; // max_offset_found
// res[2] = 2; // min_match_found - NOT USED
res[3] = src_len - 1; // max_match_found
// res[4] = 1; // min_run_found - NOT USED
res[5] = src_len; // max_run_found
res[6] = 1; // first_offset_found
// res[7] = 999999; // same_match_offsets_found - NOT USED
// prepare bit-buffer settings
cconf.bb_endian = 0;
cconf.bb_size = 0;
if (method >= M_NRV2B_LE32 && method <= M_NRV2E_LE16) {
static const unsigned char sizes[3] = {32, 8, 16};
cconf.bb_size = sizes[(method - M_NRV2B_LE32) % 3];
} else {
throwInternalError("unknown compression method");
return UPX_E_ERROR;
}
// optimize compression parms
if (level <= 3 && cconf.max_offset == UCL_UINT_MAX)
cconf.max_offset = 8 * 1024 - 1;
else if (level == 4 && cconf.max_offset == UCL_UINT_MAX)
cconf.max_offset = 32 * 1024 - 1;
if M_IS_NRV2B (method)
r = ucl_nrv2b_99_compress(src, src_len, dst, dst_len, &cb, level, &cconf, res);
else if M_IS_NRV2D (method)
r = ucl_nrv2d_99_compress(src, src_len, dst, dst_len, &cb, level, &cconf, res);
else if M_IS_NRV2E (method)
r = ucl_nrv2e_99_compress(src, src_len, dst, dst_len, &cb, level, &cconf, res);
else {
throwInternalError("unknown compression method");
return UPX_E_ERROR;
}
// make sure first_offset_found is set
if (res[6] == 0)
res[6] = 1;
return convert_errno_from_ucl(r);
}
/*************************************************************************
//
**************************************************************************/
int upx_ucl_decompress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
int method, const upx_compress_result_t *cresult) {
int r;
switch (method) {
case M_NRV2B_8:
r = ucl_nrv2b_decompress_safe_8(src, src_len, dst, dst_len, nullptr);
break;
case M_NRV2B_LE16:
r = ucl_nrv2b_decompress_safe_le16(src, src_len, dst, dst_len, nullptr);
break;
case M_NRV2B_LE32:
r = ucl_nrv2b_decompress_safe_le32(src, src_len, dst, dst_len, nullptr);
break;
case M_NRV2D_8:
r = ucl_nrv2d_decompress_safe_8(src, src_len, dst, dst_len, nullptr);
break;
case M_NRV2D_LE16:
r = ucl_nrv2d_decompress_safe_le16(src, src_len, dst, dst_len, nullptr);
break;
case M_NRV2D_LE32:
r = ucl_nrv2d_decompress_safe_le32(src, src_len, dst, dst_len, nullptr);
break;
case M_NRV2E_8:
r = ucl_nrv2e_decompress_safe_8(src, src_len, dst, dst_len, nullptr);
break;
case M_NRV2E_LE16:
r = ucl_nrv2e_decompress_safe_le16(src, src_len, dst, dst_len, nullptr);
break;
case M_NRV2E_LE32:
r = ucl_nrv2e_decompress_safe_le32(src, src_len, dst, dst_len, nullptr);
break;
default:
throwInternalError("unknown decompression method");
return UPX_E_ERROR;
}
UNUSED(cresult);
return convert_errno_from_ucl(r);
}
/*************************************************************************
//
**************************************************************************/
int upx_ucl_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src_off,
unsigned src_len, unsigned *dst_len, int method,
const upx_compress_result_t *cresult) {
int r;
UNUSED(tbuf); // not needed for UCL
switch (method) {
case M_NRV2B_8:
r = ucl_nrv2b_test_overlap_8(buf, src_off, src_len, dst_len, nullptr);
break;
case M_NRV2B_LE16:
r = ucl_nrv2b_test_overlap_le16(buf, src_off, src_len, dst_len, nullptr);
break;
case M_NRV2B_LE32:
r = ucl_nrv2b_test_overlap_le32(buf, src_off, src_len, dst_len, nullptr);
break;
case M_NRV2D_8:
r = ucl_nrv2d_test_overlap_8(buf, src_off, src_len, dst_len, nullptr);
break;
case M_NRV2D_LE16:
r = ucl_nrv2d_test_overlap_le16(buf, src_off, src_len, dst_len, nullptr);
break;
case M_NRV2D_LE32:
r = ucl_nrv2d_test_overlap_le32(buf, src_off, src_len, dst_len, nullptr);
break;
case M_NRV2E_8:
r = ucl_nrv2e_test_overlap_8(buf, src_off, src_len, dst_len, nullptr);
break;
case M_NRV2E_LE16:
r = ucl_nrv2e_test_overlap_le16(buf, src_off, src_len, dst_len, nullptr);
break;
case M_NRV2E_LE32:
r = ucl_nrv2e_test_overlap_le32(buf, src_off, src_len, dst_len, nullptr);
break;
default:
throwInternalError("unknown decompression method");
return UPX_E_ERROR;
}
UNUSED(cresult);
return convert_errno_from_ucl(r);
}
/*************************************************************************
// misc
**************************************************************************/
extern "C" {
static ucl_voidp __UCL_CDECL my_malloc(ucl_uint n) { return calloc(1, n); }
static void __UCL_CDECL my_free(ucl_voidp p) { free(p); }
}
int upx_ucl_init(void) {
if (ucl_init() != UCL_E_OK)
return -1;
if (UCL_VERSION != ucl_version() || strcmp(UCL_VERSION_STRING, ucl_version_string()) != 0)
return -2;
ucl_set_malloc_hooks(my_malloc, my_free);
return 0;
}
const char *upx_ucl_version_string(void) { return ucl_version_string(); }
unsigned upx_ucl_adler32(const void *buf, unsigned len, unsigned adler) {
return ucl_adler32(adler, (const ucl_bytep) buf, len);
}
#if 0 // UNUSED
unsigned upx_ucl_crc32(const void *buf, unsigned len, unsigned crc) {
return ucl_crc32(crc, (const ucl_bytep) buf, len);
}
#endif
/*************************************************************************
// doctest checks
**************************************************************************/
#if DEBUG && !defined(DOCTEST_CONFIG_DISABLE) && 1
#include "../util/membuffer.h"
static bool check_ucl(const int method, const unsigned expected_c_len) {
const unsigned u_len = 16384;
const unsigned c_extra = 4096;
MemBuffer u_buf, c_buf, d_buf;
unsigned c_len, d_len;
upx_compress_result_t cresult;
int r;
const int level = 3; // don't waste time
u_buf.alloc(u_len);
memset(u_buf, 0, u_len);
c_buf.allocForCompression(u_len, c_extra);
d_buf.allocForDecompression(u_len);
c_len = c_buf.getSize() - c_extra;
r = upx_ucl_compress(raw_bytes(u_buf, u_len), u_len, raw_index_bytes(c_buf, c_extra, c_len),
&c_len, nullptr, method, level, NULL_cconf, &cresult);
if (r != 0 || c_len != expected_c_len)
return false;
d_len = d_buf.getSize();
r = upx_ucl_decompress(raw_index_bytes(c_buf, c_extra, c_len), c_len, raw_bytes(d_buf, d_len),
&d_len, method, nullptr);
if (r != 0 || d_len != u_len || memcmp(u_buf, d_buf, u_len) != 0)
return false;
d_len = u_len - 1;
r = upx_ucl_decompress(raw_index_bytes(c_buf, c_extra, c_len), c_len, raw_bytes(d_buf, d_len),
&d_len, method, nullptr);
if (r == 0)
return false;
// TODO: rewrite Packer::findOverlapOverhead() so that we can test it here
// unsigned x_len = d_len;
// r = upx_ucl_test_overlap(c_buf, u_buf, c_extra, c_len, &x_len, method, nullptr);
return true;
}
TEST_CASE("compress_ucl") {
CHECK(check_ucl(M_NRV2B_8, 34));
CHECK(check_ucl(M_NRV2B_LE16, 34));
CHECK(check_ucl(M_NRV2B_LE32, 34));
CHECK(check_ucl(M_NRV2D_8, 32));
CHECK(check_ucl(M_NRV2D_LE16, 32));
CHECK(check_ucl(M_NRV2D_LE32, 34));
CHECK(check_ucl(M_NRV2E_8, 32));
CHECK(check_ucl(M_NRV2E_LE16, 32));
CHECK(check_ucl(M_NRV2E_LE32, 34));
}
#endif // DEBUG
TEST_CASE("upx_ucl_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[16];
unsigned d_len;
int r;
c_data = (C *) "\x92\xff\x10\x00\x00\x00\x00\x00\x48\xff";
d_len = 16;
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
CHECK((r == 0 && d_len == 16));
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2B_8, nullptr);
CHECK(r == UPX_E_INPUT_OVERRUN);
d_len = 15;
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN);
c_data = (C *) "\x92\xff\x10\x92\x49\x24\x92\xa0\xff";
d_len = 16;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
CHECK((r == 0 && d_len == 16));
r = upx_ucl_decompress(c_data, 8, d_buf, &d_len, M_NRV2D_8, nullptr);
CHECK(r == UPX_E_INPUT_OVERRUN);
d_len = 15;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN);
c_data = (C *) "\x90\xff\xb0\x92\x49\x24\x92\xa0\xff";
d_len = 16;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr);
CHECK((r == 0 && d_len == 16));
r = upx_ucl_decompress(c_data, 8, d_buf, &d_len, M_NRV2E_8, nullptr);
CHECK(r == UPX_E_INPUT_OVERRUN);
d_len = 15;
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN);
}
/* vim:set ts=4 sw=4 et: */
+307
View File
@@ -0,0 +1,307 @@
/* compress_zlib.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
*/
#include "../conf.h"
#include "compress.h"
#include "../util/membuffer.h"
#include <zlib/zlib.h>
#include <zlib/deflate.h>
void zlib_compress_config_t::reset() {
mem_clear(this, sizeof(*this));
mem_level.reset();
window_bits.reset();
strategy.reset();
}
static int convert_errno_from_zlib(int zr) {
switch (zr) {
case Z_OK:
return UPX_E_OK;
// positive values
case Z_STREAM_END:
return UPX_E_ERROR;
case Z_NEED_DICT:
return UPX_E_ERROR;
// negative values
case Z_ERRNO:
return UPX_E_ERROR;
case Z_STREAM_ERROR:
return UPX_E_ERROR;
case Z_DATA_ERROR:
return UPX_E_ERROR;
case Z_MEM_ERROR:
return UPX_E_OUT_OF_MEMORY;
case Z_BUF_ERROR:
return UPX_E_OUTPUT_OVERRUN;
case Z_VERSION_ERROR:
return UPX_E_ERROR;
case -7: // UPX extra
return UPX_E_INPUT_OVERRUN;
}
return UPX_E_ERROR;
}
/*************************************************************************
//
**************************************************************************/
int upx_zlib_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
upx_callback_p cb_parm, int method, int level,
const upx_compress_config_t *cconf_parm, upx_compress_result_t *cresult) {
assert(method == M_DEFLATE);
assert(level > 0);
assert(cresult != nullptr);
UNUSED(cb_parm);
int r = UPX_E_ERROR;
int zr;
const zlib_compress_config_t *const lcconf = cconf_parm ? &cconf_parm->conf_zlib : nullptr;
zlib_compress_result_t *const res = &cresult->result_zlib;
if (level == 10)
level = 9;
zlib_compress_config_t::mem_level_t mem_level;
zlib_compress_config_t::window_bits_t window_bits;
zlib_compress_config_t::strategy_t strategy;
// cconf overrides
if (lcconf) {
oassign(mem_level, lcconf->mem_level);
oassign(window_bits, lcconf->window_bits);
oassign(strategy, lcconf->strategy);
}
res->dummy = 0;
z_stream s;
s.zalloc = (alloc_func) nullptr;
s.zfree = (free_func) nullptr;
s.next_in = ACC_UNCONST_CAST(upx_bytep, src);
s.avail_in = src_len;
s.next_out = dst;
s.avail_out = *dst_len;
s.total_in = s.total_out = 0;
zr = (int) deflateInit2(&s, level, Z_DEFLATED, 0 - (int) window_bits, mem_level, strategy);
if (zr != Z_OK)
goto error;
assert(s.state->level == level);
zr = deflate(&s, Z_FINISH);
if (zr != Z_STREAM_END)
goto error;
zr = deflateEnd(&s);
if (zr != Z_OK)
goto error;
r = UPX_E_OK;
goto done;
error:
(void) deflateEnd(&s);
r = convert_errno_from_zlib(zr);
if (r == UPX_E_OK)
r = UPX_E_ERROR;
done:
if (r == UPX_E_OK) {
if (s.avail_in != 0 || s.total_in != src_len)
r = UPX_E_ERROR;
}
assert(s.total_in <= src_len);
assert(s.total_out <= *dst_len);
*dst_len = s.total_out;
return r;
}
/*************************************************************************
//
**************************************************************************/
int upx_zlib_decompress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
int method, const upx_compress_result_t *cresult) {
assert(method == M_DEFLATE);
UNUSED(method);
UNUSED(cresult);
int r = UPX_E_ERROR;
int zr;
z_stream s;
s.zalloc = (alloc_func) nullptr;
s.zfree = (free_func) nullptr;
s.next_in = ACC_UNCONST_CAST(upx_bytep, src);
s.avail_in = src_len;
s.next_out = dst;
s.avail_out = *dst_len;
s.total_in = s.total_out = 0;
zr = inflateInit2(&s, -15);
if (zr != Z_OK)
goto error;
zr = inflate(&s, Z_FINISH);
if (zr != Z_STREAM_END) {
if (zr == Z_BUF_ERROR && s.avail_in == 0)
zr = -7; // UPX extra
goto error;
}
zr = inflateEnd(&s);
if (zr != Z_OK)
goto error;
r = UPX_E_OK;
goto done;
error:
(void) inflateEnd(&s);
r = convert_errno_from_zlib(zr);
if (r == UPX_E_OK)
r = UPX_E_ERROR;
done:
if (r == UPX_E_OK) {
if (s.avail_in != 0 || s.total_in != src_len)
r = UPX_E_INPUT_NOT_CONSUMED;
}
assert(s.total_in <= src_len);
assert(s.total_out <= *dst_len);
*dst_len = s.total_out;
return r;
}
/*************************************************************************
// test_overlap - see <ucl/ucl.h> for semantics
**************************************************************************/
int upx_zlib_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src_off,
unsigned src_len, unsigned *dst_len, int method,
const upx_compress_result_t *cresult) {
assert(method == M_DEFLATE);
MemBuffer b(src_off + src_len);
memcpy(b + src_off, buf + src_off, src_len);
unsigned saved_dst_len = *dst_len;
int r = upx_zlib_decompress(raw_index_bytes(b, src_off, src_len), src_len,
raw_bytes(b, *dst_len), dst_len, method, cresult);
if (r != UPX_E_OK)
return r;
if (*dst_len != saved_dst_len)
return UPX_E_ERROR;
// NOTE: there is a very tiny possibility that decompression has
// succeeded but the data is not restored correctly because of
// in-place buffer overlapping, so we use an extra memcmp().
if (tbuf != nullptr && memcmp(tbuf, b, *dst_len) != 0)
return UPX_E_ERROR;
return UPX_E_OK;
}
/*************************************************************************
// misc
**************************************************************************/
int upx_zlib_init(void) {
if (strcmp(ZLIB_VERSION, zlibVersion()) != 0)
return -2;
return 0;
}
const char *upx_zlib_version_string(void) { return zlibVersion(); }
#if 0 // UNUSED
unsigned upx_zlib_adler32(const void *buf, unsigned len, unsigned adler) {
return adler32(adler, (const Bytef *) buf, len);
}
#endif
#if 0 // UNUSED
unsigned upx_zlib_crc32(const void *buf, unsigned len, unsigned crc) {
return crc32(crc, (const Bytef *) buf, len);
}
#endif
/*************************************************************************
// doctest checks
**************************************************************************/
#if DEBUG && !defined(DOCTEST_CONFIG_DISABLE) && 1
static bool check_zlib(const int method, const int level, const unsigned expected_c_len) {
const unsigned u_len = 16384;
const unsigned c_extra = 4096;
MemBuffer u_buf, c_buf, d_buf;
unsigned c_len, d_len;
upx_compress_result_t cresult;
int r;
u_buf.alloc(u_len);
memset(u_buf, 0, u_len);
c_buf.allocForCompression(u_len, c_extra);
d_buf.allocForDecompression(u_len);
c_len = c_buf.getSize() - c_extra;
r = upx_zlib_compress(raw_bytes(u_buf, u_len), u_len, raw_index_bytes(c_buf, c_extra, c_len),
&c_len, nullptr, method, level, NULL_cconf, &cresult);
if (r != 0 || c_len != expected_c_len)
return false;
d_len = d_buf.getSize();
r = upx_zlib_decompress(raw_index_bytes(c_buf, c_extra, c_len), c_len, raw_bytes(d_buf, d_len),
&d_len, method, nullptr);
if (r != 0 || d_len != u_len || memcmp(u_buf, d_buf, u_len) != 0)
return false;
d_len = u_len - 1;
r = upx_zlib_decompress(raw_index_bytes(c_buf, c_extra, c_len), c_len, raw_bytes(d_buf, d_len),
&d_len, method, nullptr);
if (r == 0)
return false;
// TODO: rewrite Packer::findOverlapOverhead() so that we can test it here
// unsigned x_len = d_len;
// r = upx_zlib_test_overlap(c_buf, u_buf, c_extra, c_len, &x_len, method, nullptr);
return true;
}
TEST_CASE("compress_zlib") {
CHECK(check_zlib(M_DEFLATE, 1, 89));
CHECK(check_zlib(M_DEFLATE, 3, 89));
CHECK(check_zlib(M_DEFLATE, 5, 33));
}
#endif // DEBUG
TEST_CASE("upx_zlib_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[16];
unsigned d_len;
int r;
c_data = (C *) "\xfb\xff\x1f\x15\x00\x00";
d_len = 16;
r = upx_zlib_decompress(c_data, 6, d_buf, &d_len, M_DEFLATE, nullptr);
CHECK((r == 0 && d_len == 16));
r = upx_zlib_decompress(c_data, 5, d_buf, &d_len, M_DEFLATE, nullptr);
CHECK(r == UPX_E_INPUT_OVERRUN);
d_len = 15;
r = upx_zlib_decompress(c_data, 6, d_buf, &d_len, M_DEFLATE, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN);
}
/* vim:set ts=4 sw=4 et: */
+229
View File
@@ -0,0 +1,229 @@
/* compress_zstd.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
*/
#include "../conf.h"
void zstd_compress_config_t::reset() { mem_clear(this, sizeof(*this)); }
#if WITH_ZSTD
#include "compress.h"
#include "../util/membuffer.h"
#include <zstd/lib/zstd.h>
#include <zstd/lib/zstd_errors.h>
#include <zstd/lib/compress/hist.h>
static int convert_errno_from_zstd(size_t zr) {
const ZSTD_ErrorCode ze = ZSTD_getErrorCode(zr);
switch (ze) {
case ZSTD_error_memory_allocation:
return UPX_E_OUT_OF_MEMORY;
case ZSTD_error_srcSize_wrong:
return UPX_E_INPUT_OVERRUN;
case ZSTD_error_dstSize_tooSmall:
return UPX_E_OUTPUT_OVERRUN;
default:
break;
}
return UPX_E_ERROR;
}
/*************************************************************************
// TODO later: use advanced compression API for compression finetuning
**************************************************************************/
int upx_zstd_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
upx_callback_p cb_parm, int method, int level,
const upx_compress_config_t *cconf_parm, upx_compress_result_t *cresult) {
assert(method == M_ZSTD);
assert(level > 0);
assert(cresult != nullptr);
UNUSED(cb_parm);
int r = UPX_E_ERROR;
size_t zr;
const zstd_compress_config_t *const lcconf = cconf_parm ? &cconf_parm->conf_zstd : nullptr;
zstd_compress_result_t *const res = &cresult->result_zstd;
// TODO later: map level 1..10 to zstd-level 1..22
if (level == 10)
level = 22;
// cconf overrides
if (lcconf) {
UNUSED(lcconf);
}
res->dummy = 0;
zr = ZSTD_compress(dst, *dst_len, src, src_len, level);
if (ZSTD_isError(zr)) {
*dst_len = 0; // TODO ???
r = convert_errno_from_zstd(zr);
assert(r != UPX_E_OK);
} else {
assert(zr <= *dst_len);
*dst_len = (unsigned) zr;
r = UPX_E_OK;
}
return r;
}
/*************************************************************************
//
**************************************************************************/
int upx_zstd_decompress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len,
int method, const upx_compress_result_t *cresult) {
assert(method == M_ZSTD);
UNUSED(method);
UNUSED(cresult);
int r = UPX_E_ERROR;
size_t zr;
zr = ZSTD_decompress(dst, *dst_len, src, src_len);
if (ZSTD_isError(zr)) {
*dst_len = 0; // TODO ???
r = convert_errno_from_zstd(zr);
assert(r != UPX_E_OK);
} else {
assert(zr <= *dst_len);
*dst_len = (unsigned) zr;
r = UPX_E_OK;
}
return r;
}
/*************************************************************************
// test_overlap - see <ucl/ucl.h> for semantics
**************************************************************************/
int upx_zstd_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src_off,
unsigned src_len, unsigned *dst_len, int method,
const upx_compress_result_t *cresult) {
assert(method == M_ZSTD);
MemBuffer b(src_off + src_len);
memcpy(b + src_off, buf + src_off, src_len);
unsigned saved_dst_len = *dst_len;
int r = upx_zstd_decompress(raw_index_bytes(b, src_off, src_len), src_len,
raw_bytes(b, *dst_len), dst_len, method, cresult);
if (r != UPX_E_OK)
return r;
if (*dst_len != saved_dst_len)
return UPX_E_ERROR;
// NOTE: there is a very tiny possibility that decompression has
// succeeded but the data is not restored correctly because of
// in-place buffer overlapping, so we use an extra memcmp().
if (tbuf != nullptr && memcmp(tbuf, b, *dst_len) != 0)
return UPX_E_ERROR;
return UPX_E_OK;
}
/*************************************************************************
// misc
**************************************************************************/
int upx_zstd_init(void) {
if (strcmp(ZSTD_VERSION_STRING, ZSTD_versionString()) != 0)
return -2;
return 0;
}
const char *upx_zstd_version_string(void) { return ZSTD_VERSION_STRING; }
/*************************************************************************
// doctest checks
**************************************************************************/
#if DEBUG && !defined(DOCTEST_CONFIG_DISABLE) && 1
static bool check_zstd(const int method, const int level, const unsigned expected_c_len) {
const unsigned u_len = 16384;
const unsigned c_extra = 4096;
MemBuffer u_buf, c_buf, d_buf;
unsigned c_len, d_len;
upx_compress_result_t cresult;
int r;
u_buf.alloc(u_len);
memset(u_buf, 0, u_len);
c_buf.allocForCompression(u_len, c_extra);
d_buf.allocForDecompression(u_len);
c_len = c_buf.getSize() - c_extra;
r = upx_zstd_compress(raw_bytes(u_buf, u_len), u_len, raw_index_bytes(c_buf, c_extra, c_len),
&c_len, nullptr, method, level, NULL_cconf, &cresult);
if (r != 0 || c_len != expected_c_len)
return false;
d_len = d_buf.getSize();
r = upx_zstd_decompress(raw_index_bytes(c_buf, c_extra, c_len), c_len, raw_bytes(d_buf, d_len),
&d_len, method, nullptr);
if (r != 0 || d_len != u_len || memcmp(u_buf, d_buf, u_len) != 0)
return false;
d_len = u_len - 1;
r = upx_zstd_decompress(raw_index_bytes(c_buf, c_extra, c_len), c_len, raw_bytes(d_buf, d_len),
&d_len, method, nullptr);
if (r == 0)
return false;
// TODO: rewrite Packer::findOverlapOverhead() so that we can test it here
// unsigned x_len = d_len;
// r = upx_zstd_test_overlap(c_buf, u_buf, c_extra, c_len, &x_len, method, nullptr);
return true;
}
TEST_CASE("compress_zstd") {
CHECK(check_zstd(M_ZSTD, 1, 19));
CHECK(check_zstd(M_ZSTD, 3, 19));
CHECK(check_zstd(M_ZSTD, 5, 19));
}
#endif // DEBUG
TEST_CASE("upx_zstd_decompress") {
typedef const upx_byte C;
C *c_data;
upx_byte d_buf[32];
unsigned d_len;
int r;
c_data = (C *) "\x28\xb5\x2f\xfd\x20\x20\x3d\x00\x00\x08\xff\x01\x00\x34\x4e\x08";
d_len = 32;
r = upx_zstd_decompress(c_data, 16, d_buf, &d_len, M_ZSTD, nullptr);
CHECK((r == 0 && d_len == 32));
r = upx_zstd_decompress(c_data, 15, d_buf, &d_len, M_ZSTD, nullptr);
CHECK(r == UPX_E_INPUT_OVERRUN);
d_len = 31;
r = upx_zstd_decompress(c_data, 16, d_buf, &d_len, M_ZSTD, nullptr);
CHECK(r == UPX_E_OUTPUT_OVERRUN);
}
#endif // WITH_ZSTD
/* vim:set ts=4 sw=4 et: */