From 34ae4136072ed526f9a675a98da63cffe5e5bfcd Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Wed, 7 Jun 2006 04:42:15 +0200 Subject: [PATCH] Initial lzma support. --- .hgignore | 1 + src/compress.ch | 195 +++++++++++++++++++++++++++++++++++++++++++++++ src/compress.cpp | 5 +- src/conf.h | 5 ++ src/main.cpp | 5 ++ src/p_lx_elf.cpp | 3 + src/packer.cpp | 14 +++- 7 files changed, 226 insertions(+), 2 deletions(-) diff --git a/.hgignore b/.hgignore index 3606a036..7d4cbcb1 100644 --- a/.hgignore +++ b/.hgignore @@ -1,5 +1,6 @@ syntax: regexp +^\.bzr ^ChangeLog ^build ^maint diff --git a/src/compress.ch b/src/compress.ch index 66cf0131..922d0fe8 100644 --- a/src/compress.ch +++ b/src/compress.ch @@ -66,6 +66,184 @@ unsigned upx_crc32(const void *buf, unsigned len, unsigned crc) #endif +/************************************************************************* +// +**************************************************************************/ + +#if defined(ALG_LZMA) + +#undef MSDOS +#undef OS2 +#undef _WIN32 +#undef _WIN32_WCE +#include "lzma/MyInitGuid.h" +//#include "lzma/LZMADecoder.h" +#include "lzma/LZMAEncoder.h" +#undef RC_NORMALIZE + + +struct CInStreamRam: public ISequentialInStream, public CMyUnknownImp +{ + MY_UNKNOWN_IMP + const Byte *Data; size_t Size; size_t Pos; + void Init(const Byte *data, size_t size) { + Data = data; Size = size; Pos = 0; + } + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CInStreamRam::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 remain = Size - Pos; + if (size > remain) size = remain; + memmove(data, Data + Pos, size); + Pos += size; + if (processedSize != NULL) *processedSize = size; + return S_OK; +} + +struct COutStreamRam : public ISequentialOutStream, public CMyUnknownImp +{ + MY_UNKNOWN_IMP + Byte *Data; size_t Size; size_t Pos; bool Overflow; + void Init(Byte *data, size_t size) { + Data = data; Size = size; Pos = 0; Overflow = false; + } + HRESULT WriteByte(Byte b) { + if (Pos >= Size) { Overflow = true; return E_FAIL; } + Data[Pos++] = b; + return S_OK; + } + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP COutStreamRam::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 i; + for (i = 0; i < size && Pos < Size; i++) + Data[Pos++] = ((const Byte *)data)[i]; + if (processedSize != NULL) *processedSize = i; + if (i != size) { Overflow = true; return E_FAIL; } + return S_OK; +} + + +static +int upx_lzma_compress ( const upx_bytep src, upx_uint src_len, + upx_bytep dst, upx_uintp dst_len, + upx_progress_callback_t *cb, + int level, + const struct upx_compress_config_t *conf_parm, + upx_uintp result ) +{ + UNUSED(cb); UNUSED(level); + UNUSED(conf_parm); UNUSED(result); + + int r = UPX_E_ERROR; + HRESULT rh; + + CInStreamRam* isp = new CInStreamRam; + CInStreamRam& is = *isp; + COutStreamRam* osp = new COutStreamRam; + COutStreamRam& os = *osp; + is.Init(src, src_len); +// os.Init(dst, *dst_len); + os.Init(dst, src_len); + +#ifndef _NO_EXCEPTIONS + try { +#endif + + NCompress::NLZMA::CEncoder enc; + PROPID propIDs[] = { + NCoderPropID::kAlgorithm, + NCoderPropID::kDictionarySize, + NCoderPropID::kNumFastBytes, + }; + const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]); + PROPVARIANT properties[kNumProps]; + properties[0].vt = VT_UI4; + properties[1].vt = VT_UI4; + properties[2].vt = VT_UI4; + properties[0].ulVal = (UInt32)2; +// properties[1].ulVal = (UInt32)dictionarySize; + properties[1].ulVal = (UInt32)1024 * 1024; // FIXME + properties[2].ulVal = (UInt32)64; + + if (enc.SetCoderProperties(propIDs, properties, kNumProps) != S_OK) + goto error; + if (enc.WriteCoderProperties(&os) != S_OK) + goto error; + if (os.Pos != 5) + goto error; + + rh = enc.Code(&is, &os, 0, 0, 0); + if (rh == E_OUTOFMEMORY) + r = UPX_E_OUT_OF_MEMORY; +#if 0 + else if (os.Overflow) + r = UPX_E_OUPUT_OVERRUN; // FIXME - not compressible +#endif + else if (rh == S_OK) + r = UPX_E_OK; +error: + *dst_len = os.Pos; + return r; + +#ifndef _NO_EXCEPTIONS + } catch(...) { return UPX_E_OUT_OF_MEMORY; } +#endif +} + + +#include "lzma/Alloc.cpp" +#include "lzma/CRC.cpp" +//#include "lzma/LZMADecoder.cpp" +#include "lzma/LZMAEncoder.cpp" +#include "lzma/LZInWindow.cpp" +#include "lzma/OutBuffer.cpp" +#include "lzma/RangeCoderBit.cpp" +#include "lzma/StreamUtils.cpp" + + + +#undef _LZMA_IN_CB +#undef _LZMA_OUT_READ +#undef _LZMA_PROB32 +#undef _LZMA_LOC_OPT +#include "lzma/LzmaDecode.cpp" + +static +int upx_lzma_decompress ( const upx_bytep src, upx_uint src_len, + upx_bytep dst, upx_uintp dst_len ) +{ + CLzmaDecoderState s; + SizeT src_out = 0, dst_out = 0; + int r; + + s.Probs = NULL; +#if defined(LzmaDecoderInit) + LzmaDecoderInit(&s); +#endif + r = LzmaDecodeProperties(&s.Properties, src, src_len); + if (r != 0) + goto error; + src += LZMA_PROPERTIES_SIZE; src_len -= LZMA_PROPERTIES_SIZE; + s.Probs = (CProb *) malloc(sizeof(CProb) * LzmaGetNumProbs(&s.Properties)); + if (!s.Probs) + r = UPX_E_OUT_OF_MEMORY; + else + r = LzmaDecode(&s, src, src_len, &src_out, dst, *dst_len, &dst_out); +error: + *dst_len = dst_out; + free(s.Probs); + return r; +} + + +#endif + + /************************************************************************* // **************************************************************************/ @@ -133,6 +311,11 @@ int upx_compress ( const upx_bytep src, upx_uint src_len, r = cl1b_compress(src, src_len, dst, dst_len, cb, level, &conf, result); #endif /*}*/ +#if defined(ALG_LZMA) + else if M_IS_LZMA(method) + r = upx_lzma_compress(src, src_len, dst, dst_len, + cb, level, &conf, result); +#endif else throwInternalError("unknown compression method"); @@ -196,6 +379,11 @@ int upx_decompress ( const upx_bytep src, upx_uint src_len, r = cl1b_decompress_safe_le32(src,src_len,dst,dst_len,NULL); break; #endif /*}*/ +#if defined(ALG_LZMA) + case M_LZMA: + r = upx_lzma_decompress(src,src_len,dst,dst_len); + break; +#endif default: throwInternalError("unknown decompression method"); break; @@ -261,6 +449,13 @@ int upx_test_overlap ( const upx_bytep buf, upx_uint src_off, r = cl1b_test_overlap_le32(buf,src_off,src_len,dst_len,NULL); break; #endif /*}*/ +#if defined(ALG_LZMA) + case M_LZMA: + /* FIXME */ + if (src_off >= 256) + r = UPX_E_OK; + break; +#endif default: throwInternalError("unknown decompression method"); break; diff --git a/src/compress.cpp b/src/compress.cpp index 93c1c423..c751fc30 100644 --- a/src/compress.cpp +++ b/src/compress.cpp @@ -29,10 +29,13 @@ #include "conf.h" +#if defined(WITH_LZMA) +# define ALG_LZMA 1 +#endif #if defined(WITH_NRV) # include "compress_nrv.ch" #elif defined(WITH_UCL) -# define ALG_NRV2E +# define ALG_NRV2E 1 # define upx_adler32 upx_adler32 //# define upx_crc32 upx_crc32 # define upx_compress upx_compress diff --git a/src/conf.h b/src/conf.h index e3f6023a..af38261f 100644 --- a/src/conf.h +++ b/src/conf.h @@ -173,6 +173,9 @@ #if defined(WITH_NRV) # include #endif +#if 1 && !defined(WITH_LZMA) +# define WITH_LZMA 1 +#endif #if !defined(__UPX_CHECKER) # if defined(__UCL_CHECKER) || defined(__NRV_CHECKER) # define __UPX_CHECKER @@ -429,11 +432,13 @@ inline void operator delete[](void *p) #define M_CL1B_LE32 11 #define M_CL1B_8 12 #define M_CL1B_LE16 13 +#define M_LZMA 14 #define M_IS_NRV2B(x) ((x) >= M_NRV2B_LE32 && (x) <= M_NRV2B_LE16) #define M_IS_NRV2D(x) ((x) >= M_NRV2D_LE32 && (x) <= M_NRV2D_LE16) #define M_IS_NRV2E(x) ((x) >= M_NRV2E_LE32 && (x) <= M_NRV2E_LE16) #define M_IS_CL1B(x) ((x) >= M_CL1B_LE32 && (x) <= M_CL1B_LE16) +#define M_IS_LZMA(x) ((x) == M_LZMA) // Executable formats. Note: big endian types are >= 128. diff --git a/src/main.cpp b/src/main.cpp index 58f18ddf..3014efb3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -511,6 +511,10 @@ static int do_option(int optc, const char *arg) if (!set_method(M_NRV2E_LE32, -1)) e_method(M_NRV2E_LE32, opt->level); break; + case 721: + if (!set_method(M_LZMA, -1)) + e_method(M_LZMA, opt->level); + break; // compression level case '1': @@ -824,6 +828,7 @@ static const struct mfx_option longopts[] = {"nrv2b", 0x10, 0, 702}, // --nrv2b {"nrv2d", 0x10, 0, 704}, // --nrv2d {"nrv2e", 0x10, 0, 705}, // --nrv2e + {"lzma", 0x10, 0, 721}, // --lzma // compression settings {"all-filters", 0x10, 0, 523}, {"all-methods", 0x10, 0, 524}, diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index d284f165..84e91731 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -197,11 +197,14 @@ PackLinuxElf64amd::getCompressionMethods(int method, int level) const // No real dependency on LE32. static const int m_nrv2b[] = { M_NRV2B_LE32, M_NRV2E_LE32, -1 }; static const int m_nrv2e[] = { M_NRV2E_LE32, M_NRV2B_LE32, -1 }; + static const int m_lzma[] = { M_LZMA,-1 }; if (M_IS_NRV2B(method)) return m_nrv2b; if (M_IS_NRV2E(method)) return m_nrv2e; + if (M_IS_LZMA(method)) + return m_lzma; if (1==level) return m_nrv2b; return m_nrv2e; diff --git a/src/packer.cpp b/src/packer.cpp index 1dfdefab..05638edf 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -942,7 +942,7 @@ unsigned Packer::unoptimizeReloc32(upx_byte **in, upx_byte *image, bool Packer::isValidCompressionMethod(int method) { - return (method >= M_NRV2B_LE32 && method <= M_CL1B_LE16); + return (method >= M_NRV2B_LE32 && method <= M_LZMA); } @@ -952,6 +952,7 @@ const int *Packer::getDefaultCompressionMethods_8(int method, int level, int sma static const int m_nrv2d[] = { M_NRV2D_8, M_NRV2B_8, M_NRV2E_8, -1 }; static const int m_nrv2e[] = { M_NRV2E_8, M_NRV2B_8, M_NRV2D_8, -1 }; static const int m_cl1b[] = { M_CL1B_8, -1 }; + static const int m_lzma[] = { M_LZMA, -1 }; if (small < 0) small = file_size <= 512*1024; @@ -963,6 +964,8 @@ const int *Packer::getDefaultCompressionMethods_8(int method, int level, int sma return m_nrv2e; if (M_IS_CL1B(method)) return m_cl1b; + if (M_IS_LZMA(method)) + return m_lzma; if (level == 1 || small) return m_nrv2b; return m_nrv2e; @@ -975,6 +978,7 @@ const int *Packer::getDefaultCompressionMethods_le32(int method, int level, int static const int m_nrv2d[] = { M_NRV2D_LE32, M_NRV2B_LE32, M_NRV2E_LE32, -1 }; static const int m_nrv2e[] = { M_NRV2E_LE32, M_NRV2B_LE32, M_NRV2D_LE32, -1 }; static const int m_cl1b[] = { M_CL1B_LE32, -1 }; + static const int m_lzma[] = { M_LZMA, -1 }; if (small < 0) small = file_size <= 512*1024; @@ -986,6 +990,8 @@ const int *Packer::getDefaultCompressionMethods_le32(int method, int level, int return m_nrv2e; if (M_IS_CL1B(method)) return m_cl1b; + if (M_IS_LZMA(method)) + return m_lzma; if (level == 1 || small) return m_nrv2b; return m_nrv2e; @@ -1224,6 +1230,10 @@ const char *Packer::getDecompressor() const "CL1LEN01,CL1FAS1B," "CL1LEN02," "CL1COPY0"; + static const char lzma_fast[] = + "LZMA_SMALL"; // FIXME + static const char lzma_small[] = + "LZMA_SMALL"; if (ph.method == M_NRV2B_LE32) return opt->small ? nrv2b_le32_small : nrv2b_le32_fast; @@ -1233,6 +1243,8 @@ const char *Packer::getDecompressor() const return opt->small ? nrv2e_le32_small : nrv2e_le32_fast; if (ph.method == M_CL1B_LE32) return opt->small ? cl1b_le32_small : cl1b_le32_fast; + if (ph.method == M_LZMA) + return opt->small ? lzma_small : lzma_fast; throwInternalError("bad decompressor"); return NULL; }