/src/upx/src/compress/compress.cpp
Line | Count | Source |
1 | | /* compress.cpp -- |
2 | | |
3 | | This file is part of the UPX executable compressor. |
4 | | |
5 | | Copyright (C) 1996-2025 Markus Franz Xaver Johannes Oberhumer |
6 | | All Rights Reserved. |
7 | | |
8 | | UPX and the UCL library are free software; you can redistribute them |
9 | | and/or modify them under the terms of the GNU General Public License as |
10 | | published by the Free Software Foundation; either version 2 of |
11 | | the License, or (at your option) any later version. |
12 | | |
13 | | This program is distributed in the hope that it will be useful, |
14 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | GNU General Public License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with this program; see the file COPYING. |
20 | | If not, write to the Free Software Foundation, Inc., |
21 | | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
22 | | |
23 | | Markus F.X.J. Oberhumer |
24 | | <markus@oberhumer.com> |
25 | | */ |
26 | | |
27 | | #include "../conf.h" |
28 | | #include "compress.h" |
29 | | #include "../util/membuffer.h" |
30 | | |
31 | | /************************************************************************* |
32 | | // |
33 | | **************************************************************************/ |
34 | | |
35 | 945k | unsigned upx_adler32(const void *buf, unsigned len, unsigned adler) { |
36 | 945k | if (len == 0) |
37 | 773k | return adler; |
38 | 171k | assert(buf != nullptr); |
39 | 0 | #if 1 |
40 | 0 | return upx_ucl_adler32(buf, len, adler); |
41 | | #else |
42 | | return upx_zlib_adler32(buf, len, adler); |
43 | | #endif |
44 | 945k | } |
45 | | |
46 | | #if 0 // UNUSED |
47 | | unsigned upx_crc32(const void *buf, unsigned len, unsigned crc) |
48 | | { |
49 | | if (len == 0) |
50 | | return crc; |
51 | | assert(buf != nullptr); |
52 | | #if 1 |
53 | | return upx_ucl_crc32(buf, len, crc); |
54 | | #else |
55 | | return upx_zlib_crc32(buf, len, crc); |
56 | | #endif |
57 | | } |
58 | | #endif // UNUSED |
59 | | |
60 | | /************************************************************************* |
61 | | // |
62 | | **************************************************************************/ |
63 | | |
64 | | int upx_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len, |
65 | | upx_callback_t *cb, int method, int level, const upx_compress_config_t *cconf, |
66 | 0 | upx_compress_result_t *cresult) { |
67 | 0 | int r = UPX_E_ERROR; |
68 | 0 | upx_compress_result_t cresult_buffer; |
69 | |
|
70 | 0 | assert(method > 0); |
71 | 0 | assert(level > 0); |
72 | | |
73 | 0 | #if 1 |
74 | | // set available bytes in dst |
75 | 0 | if (*dst_len == 0) |
76 | 0 | *dst_len = MemBuffer::getSizeForCompression(src_len); |
77 | | #else |
78 | | // force users to provide *dst_len |
79 | | assert(*dst_len != 0); |
80 | | #endif |
81 | | // for UPX, we always require a reasonably sized output buffer |
82 | 0 | assert(*dst_len >= MemBuffer::getSizeForCompression(src_len)); |
83 | | |
84 | 0 | if (!cresult) |
85 | 0 | cresult = &cresult_buffer; |
86 | 0 | cresult->reset(); |
87 | 0 | #if 1 |
88 | | // debugging aid |
89 | 0 | cresult->debug.method = method; |
90 | 0 | cresult->debug.level = level; |
91 | 0 | cresult->debug.u_len = src_len; |
92 | 0 | cresult->debug.c_len = 0; |
93 | 0 | #endif |
94 | |
|
95 | 0 | const unsigned orig_dst_len = *dst_len; |
96 | 0 | if (__acc_cte(false)) { |
97 | 0 | } |
98 | | #if (WITH_BZIP2) |
99 | | else if (M_IS_BZIP2(method)) |
100 | | r = upx_bzip2_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult); |
101 | | #endif |
102 | 0 | #if (WITH_LZMA) |
103 | 0 | else if (M_IS_LZMA(method)) |
104 | 0 | r = upx_lzma_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult); |
105 | 0 | #endif |
106 | | #if (WITH_NRV) |
107 | | else if ((M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) && !opt->prefer_ucl) |
108 | | r = upx_nrv_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult); |
109 | | #endif |
110 | 0 | #if (WITH_UCL) |
111 | 0 | else if (M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) |
112 | 0 | r = upx_ucl_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult); |
113 | 0 | #endif |
114 | | #if (WITH_ZSTD) |
115 | | else if (M_IS_ZSTD(method)) |
116 | | r = upx_zstd_compress(src, src_len, dst, dst_len, cb, method, level, cconf, cresult); |
117 | | #endif |
118 | 0 | else { |
119 | 0 | throwInternalError("unknown compression method %d", method); |
120 | 0 | } |
121 | | |
122 | 0 | #if 1 |
123 | | // debugging aid |
124 | 0 | cresult->debug.c_len = *dst_len; |
125 | 0 | #endif |
126 | 0 | assert_noexcept(*dst_len <= orig_dst_len); |
127 | 0 | return r; |
128 | 0 | } |
129 | | |
130 | | /************************************************************************* |
131 | | // |
132 | | **************************************************************************/ |
133 | | |
134 | | int upx_decompress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned *dst_len, |
135 | 11.1k | int method, const upx_compress_result_t *cresult) { |
136 | 11.1k | int r = UPX_E_ERROR; |
137 | | |
138 | 11.1k | assert(*dst_len > 0); |
139 | 11.1k | assert(src_len < *dst_len); // must be compressed |
140 | | |
141 | 11.1k | if (cresult && cresult->debug.method == 0) |
142 | 11.0k | cresult = nullptr; |
143 | | |
144 | 11.1k | const unsigned orig_dst_len = *dst_len; |
145 | 11.1k | if (__acc_cte(false)) { |
146 | 0 | } |
147 | | #if (WITH_BZIP2) |
148 | | else if (M_IS_BZIP2(method)) |
149 | | r = upx_bzip2_decompress(src, src_len, dst, dst_len, method, cresult); |
150 | | #endif |
151 | 11.1k | #if (WITH_LZMA) |
152 | 11.1k | else if (M_IS_LZMA(method)) |
153 | 9.12k | r = upx_lzma_decompress(src, src_len, dst, dst_len, method, cresult); |
154 | 2.07k | #endif |
155 | | #if (WITH_NRV) |
156 | | else if ((M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) && !opt->prefer_ucl) |
157 | | r = upx_nrv_decompress(src, src_len, dst, dst_len, method, cresult); |
158 | | #endif |
159 | 2.07k | #if (WITH_UCL) |
160 | 2.07k | else if (M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) |
161 | 1.77k | r = upx_ucl_decompress(src, src_len, dst, dst_len, method, cresult); |
162 | 296 | #endif |
163 | 296 | #if (WITH_ZLIB) |
164 | 296 | else if (M_IS_DEFLATE(method)) |
165 | 289 | r = upx_zlib_decompress(src, src_len, dst, dst_len, method, cresult); |
166 | 7 | #endif |
167 | | #if (WITH_ZSTD) |
168 | | else if (M_IS_ZSTD(method)) |
169 | | r = upx_zstd_decompress(src, src_len, dst, dst_len, method, cresult); |
170 | | #endif |
171 | 7 | else { |
172 | 7 | throwInternalError("unknown compression method %d", method); |
173 | 7 | } |
174 | | |
175 | 11.1k | assert_noexcept(*dst_len <= orig_dst_len); |
176 | 0 | return r; |
177 | 11.1k | } |
178 | | |
179 | | /************************************************************************* |
180 | | // |
181 | | **************************************************************************/ |
182 | | |
183 | | int upx_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src_off, unsigned src_len, |
184 | 0 | unsigned *dst_len, int method, const upx_compress_result_t *cresult) { |
185 | 0 | int r = UPX_E_ERROR; |
186 | |
|
187 | 0 | if (cresult && cresult->debug.method == 0) |
188 | 0 | cresult = nullptr; |
189 | |
|
190 | 0 | assert(*dst_len > 0); |
191 | 0 | assert(src_len < *dst_len); // must be compressed |
192 | 0 | unsigned overlap_overhead = src_off + src_len - *dst_len; |
193 | 0 | assert((int) overlap_overhead > 0); |
194 | | |
195 | 0 | const unsigned orig_dst_len = *dst_len; |
196 | 0 | if (__acc_cte(false)) { |
197 | 0 | } |
198 | | #if (WITH_BZIP2) |
199 | | else if (M_IS_BZIP2(method)) |
200 | | r = upx_bzip2_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult); |
201 | | #endif |
202 | 0 | #if (WITH_LZMA) |
203 | 0 | else if (M_IS_LZMA(method)) |
204 | 0 | r = upx_lzma_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult); |
205 | 0 | #endif |
206 | | #if (WITH_NRV) |
207 | | else if ((M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) && !opt->prefer_ucl) |
208 | | r = upx_nrv_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult); |
209 | | #endif |
210 | 0 | #if (WITH_UCL) |
211 | 0 | else if (M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) |
212 | 0 | r = upx_ucl_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult); |
213 | 0 | #endif |
214 | | #if (WITH_ZSTD) |
215 | | else if (M_IS_ZSTD(method)) |
216 | | r = upx_zstd_test_overlap(buf, tbuf, src_off, src_len, dst_len, method, cresult); |
217 | | #endif |
218 | 0 | else { |
219 | 0 | throwInternalError("unknown compression method %d", method); |
220 | 0 | } |
221 | | |
222 | 0 | assert_noexcept(*dst_len <= orig_dst_len); |
223 | 0 | return r; |
224 | 0 | } |
225 | | |
226 | | /* vim:set ts=4 sw=4 et: */ |