1 /* compress_ucl.cpp --
2
3 This file is part of the UPX executable compressor.
4
5 Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer
6 Copyright (C) 1996-2020 Laszlo Molnar
7 All Rights Reserved.
8
9 UPX and the UCL library are free software; you can redistribute them
10 and/or modify them under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of
12 the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING.
21 If not, write to the Free Software Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 Markus F.X.J. Oberhumer Laszlo Molnar
25 <markus@oberhumer.com> <ezerotven+github@gmail.com>
26 */
27
28
29 #include "conf.h"
30 #include "compress.h"
31 #if !(WITH_UCL)
32 extern int compress_ucl_dummy;
33 int compress_ucl_dummy = 0;
34 #else
35
36 #if 1 && !(UCL_USE_ASM) && (ACC_ARCH_I386)
37 # if (ACC_CC_CLANG || ACC_CC_GNUC || ACC_CC_INTELC || ACC_CC_MSC || ACC_CC_WATCOMC)
38 # define UCL_USE_ASM 1
39 # endif
40 #endif
41 #if (UCL_NO_ASM)
42 # undef UCL_USE_ASM
43 #endif
44 #if (ACC_CFG_NO_UNALIGNED)
45 # undef UCL_USE_ASM
46 #endif
47 #if 1 && (UCL_USE_ASM)
48 # include <ucl/ucl_asm.h>
49 # define ucl_nrv2b_decompress_safe_8 ucl_nrv2b_decompress_asm_safe_8
50 # define ucl_nrv2b_decompress_safe_le16 ucl_nrv2b_decompress_asm_safe_le16
51 # define ucl_nrv2b_decompress_safe_le32 ucl_nrv2b_decompress_asm_safe_le32
52 # define ucl_nrv2d_decompress_safe_8 ucl_nrv2d_decompress_asm_safe_8
53 # define ucl_nrv2d_decompress_safe_le16 ucl_nrv2d_decompress_asm_safe_le16
54 # define ucl_nrv2d_decompress_safe_le32 ucl_nrv2d_decompress_asm_safe_le32
55 # define ucl_nrv2e_decompress_safe_8 ucl_nrv2e_decompress_asm_safe_8
56 # define ucl_nrv2e_decompress_safe_le16 ucl_nrv2e_decompress_asm_safe_le16
57 # define ucl_nrv2e_decompress_safe_le32 ucl_nrv2e_decompress_asm_safe_le32
58 #endif
59
60
61 /*************************************************************************
62 //
63 **************************************************************************/
64
convert_errno_from_ucl(int r)65 static int convert_errno_from_ucl(int r)
66 {
67 switch (r)
68 {
69 case UCL_E_OK: return UPX_E_OK;
70 case UCL_E_ERROR: return UPX_E_ERROR;
71 case UCL_E_OUT_OF_MEMORY: return UPX_E_OUT_OF_MEMORY;
72 case UCL_E_NOT_COMPRESSIBLE: return UPX_E_NOT_COMPRESSIBLE;
73 case UCL_E_INPUT_OVERRUN: return UPX_E_INPUT_OVERRUN;
74 case UCL_E_OUTPUT_OVERRUN: return UPX_E_OUTPUT_OVERRUN;
75 case UCL_E_LOOKBEHIND_OVERRUN: return UPX_E_LOOKBEHIND_OVERRUN;
76 case UCL_E_EOF_NOT_FOUND: return UPX_E_EOF_NOT_FOUND;
77 case UCL_E_INPUT_NOT_CONSUMED: return UPX_E_INPUT_NOT_CONSUMED;
78 // case UCL_E_NOT_YET_IMPLEMENTED: return UPX_E_NOT_YET_IMPLEMENTED;
79 case UCL_E_INVALID_ARGUMENT: return UPX_E_INVALID_ARGUMENT;
80 // UCL extra:
81 case UCL_E_OVERLAP_OVERRUN: return UPX_E_ERROR;
82 }
83 return UPX_E_ERROR;
84 }
85
86
87 extern "C" {
wrap_nprogress_ucl(ucl_uint a,ucl_uint b,int state,ucl_voidp user)88 static void __UCL_CDECL wrap_nprogress_ucl(ucl_uint a, ucl_uint b, int state, ucl_voidp user)
89 {
90 if (state != -1 && state != 3) return;
91 upx_callback_p cb = (upx_callback_p) user;
92 if (cb && cb->nprogress)
93 cb->nprogress(cb, a, b);
94 }}
95
96
97 /*************************************************************************
98 //
99 **************************************************************************/
100
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)101 int upx_ucl_compress ( const upx_bytep src, unsigned src_len,
102 upx_bytep dst, unsigned* dst_len,
103 upx_callback_p cb_parm,
104 int method, int level,
105 const upx_compress_config_t *cconf_parm,
106 upx_compress_result_t *cresult )
107 {
108 int r;
109 assert(level > 0); assert(cresult != NULL);
110
111 COMPILE_TIME_ASSERT(sizeof(ucl_compress_config_t) == sizeof(REAL_ucl_compress_config_t))
112
113 ucl_progress_callback_t cb;
114 cb.callback = 0;
115 cb.user = NULL;
116 if (cb_parm && cb_parm->nprogress) {
117 cb.callback = wrap_nprogress_ucl;
118 cb.user = cb_parm;
119 }
120
121 ucl_compress_config_t cconf; cconf.reset();
122 if (cconf_parm)
123 memcpy(&cconf, &cconf_parm->conf_ucl, sizeof(cconf)); // cconf = cconf_parm->conf_ucl; // struct copy
124
125 ucl_uint *res = cresult->result_ucl.result;
126 // assume no info available - fill in worst case results
127 //res[0] = 1; // min_offset_found - NOT USED
128 res[1] = src_len - 1; // max_offset_found
129 //res[2] = 2; // min_match_found - NOT USED
130 res[3] = src_len - 1; // max_match_found
131 //res[4] = 1; // min_run_found - NOT USED
132 res[5] = src_len; // max_run_found
133 res[6] = 1; // first_offset_found
134 //res[7] = 999999; // same_match_offsets_found - NOT USED
135
136 // prepare bit-buffer settings
137 cconf.bb_endian = 0;
138 cconf.bb_size = 0;
139 if (method >= M_NRV2B_LE32 && method <= M_NRV2E_LE16)
140 {
141 static const unsigned char sizes[3] = {32, 8, 16};
142 cconf.bb_size = sizes[(method - M_NRV2B_LE32) % 3];
143 }
144 else {
145 throwInternalError("unknown compression method");
146 return UPX_E_ERROR;
147 }
148
149 // optimize compression parms
150 if (level <= 3 && cconf.max_offset == UCL_UINT_MAX)
151 cconf.max_offset = 8*1024-1;
152 else if (level == 4 && cconf.max_offset == UCL_UINT_MAX)
153 cconf.max_offset = 32*1024-1;
154
155 if M_IS_NRV2B(method)
156 r = ucl_nrv2b_99_compress(src, src_len, dst, dst_len,
157 &cb, level, &cconf, res);
158 else if M_IS_NRV2D(method)
159 r = ucl_nrv2d_99_compress(src, src_len, dst, dst_len,
160 &cb, level, &cconf, res);
161 else if M_IS_NRV2E(method)
162 r = ucl_nrv2e_99_compress(src, src_len, dst, dst_len,
163 &cb, level, &cconf, res);
164 else {
165 throwInternalError("unknown compression method");
166 return UPX_E_ERROR;
167 }
168
169 // make sure first_offset_found is set
170 if (res[6] == 0)
171 res[6] = 1;
172
173 return convert_errno_from_ucl(r);
174 }
175
176
177 /*************************************************************************
178 //
179 **************************************************************************/
180
upx_ucl_decompress(const upx_bytep src,unsigned src_len,upx_bytep dst,unsigned * dst_len,int method,const upx_compress_result_t * cresult)181 int upx_ucl_decompress ( const upx_bytep src, unsigned src_len,
182 upx_bytep dst, unsigned* dst_len,
183 int method,
184 const upx_compress_result_t *cresult )
185 {
186 int r;
187
188 switch (method)
189 {
190 case M_NRV2B_8:
191 r = ucl_nrv2b_decompress_safe_8(src,src_len,dst,dst_len,NULL);
192 break;
193 case M_NRV2B_LE16:
194 r = ucl_nrv2b_decompress_safe_le16(src,src_len,dst,dst_len,NULL);
195 break;
196 case M_NRV2B_LE32:
197 r = ucl_nrv2b_decompress_safe_le32(src,src_len,dst,dst_len,NULL);
198 break;
199 case M_NRV2D_8:
200 r = ucl_nrv2d_decompress_safe_8(src,src_len,dst,dst_len,NULL);
201 break;
202 case M_NRV2D_LE16:
203 r = ucl_nrv2d_decompress_safe_le16(src,src_len,dst,dst_len,NULL);
204 break;
205 case M_NRV2D_LE32:
206 r = ucl_nrv2d_decompress_safe_le32(src,src_len,dst,dst_len,NULL);
207 break;
208 case M_NRV2E_8:
209 r = ucl_nrv2e_decompress_safe_8(src,src_len,dst,dst_len,NULL);
210 break;
211 case M_NRV2E_LE16:
212 r = ucl_nrv2e_decompress_safe_le16(src,src_len,dst,dst_len,NULL);
213 break;
214 case M_NRV2E_LE32:
215 r = ucl_nrv2e_decompress_safe_le32(src,src_len,dst,dst_len,NULL);
216 break;
217 default:
218 throwInternalError("unknown decompression method");
219 return UPX_E_ERROR;
220 }
221
222 UNUSED(cresult);
223 return convert_errno_from_ucl(r);
224 }
225
226
227 /*************************************************************************
228 //
229 **************************************************************************/
230
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)231 int upx_ucl_test_overlap ( const upx_bytep buf,
232 const upx_bytep tbuf,
233 unsigned src_off, unsigned src_len,
234 unsigned* dst_len,
235 int method,
236 const upx_compress_result_t *cresult )
237 {
238 int r;
239 UNUSED(tbuf); // not needed for UCL
240
241 switch (method)
242 {
243 case M_NRV2B_8:
244 r = ucl_nrv2b_test_overlap_8(buf,src_off,src_len,dst_len,NULL);
245 break;
246 case M_NRV2B_LE16:
247 r = ucl_nrv2b_test_overlap_le16(buf,src_off,src_len,dst_len,NULL);
248 break;
249 case M_NRV2B_LE32:
250 r = ucl_nrv2b_test_overlap_le32(buf,src_off,src_len,dst_len,NULL);
251 break;
252 case M_NRV2D_8:
253 r = ucl_nrv2d_test_overlap_8(buf,src_off,src_len,dst_len,NULL);
254 break;
255 case M_NRV2D_LE16:
256 r = ucl_nrv2d_test_overlap_le16(buf,src_off,src_len,dst_len,NULL);
257 break;
258 case M_NRV2D_LE32:
259 r = ucl_nrv2d_test_overlap_le32(buf,src_off,src_len,dst_len,NULL);
260 break;
261 case M_NRV2E_8:
262 r = ucl_nrv2e_test_overlap_8(buf,src_off,src_len,dst_len,NULL);
263 break;
264 case M_NRV2E_LE16:
265 r = ucl_nrv2e_test_overlap_le16(buf,src_off,src_len,dst_len,NULL);
266 break;
267 case M_NRV2E_LE32:
268 r = ucl_nrv2e_test_overlap_le32(buf,src_off,src_len,dst_len,NULL);
269 break;
270 default:
271 throwInternalError("unknown decompression method");
272 return UPX_E_ERROR;
273 }
274
275 UNUSED(cresult);
276 return convert_errno_from_ucl(r);
277 }
278
279
280 /*************************************************************************
281 // misc
282 **************************************************************************/
283
284 extern "C" {
my_malloc(ucl_uint n)285 static ucl_voidp __UCL_CDECL my_malloc(ucl_uint n) { return calloc(1, n); }
my_free(ucl_voidp p)286 static void __UCL_CDECL my_free(ucl_voidp p) { free(p); }
287 }
288
upx_ucl_init(void)289 int upx_ucl_init(void)
290 {
291 if (ucl_init() != UCL_E_OK)
292 return -1;
293 #if defined(UPX_OFFICIAL_BUILD)
294 if (UCL_VERSION != ucl_version())
295 return -2;
296 #endif
297 ucl_set_malloc_hooks(my_malloc, my_free);
298 return 0;
299 }
300
upx_ucl_version_string(void)301 const char *upx_ucl_version_string(void)
302 {
303 return ucl_version_string();
304 }
305
upx_ucl_adler32(const void * buf,unsigned len,unsigned adler)306 unsigned upx_ucl_adler32(const void *buf, unsigned len, unsigned adler)
307 {
308 return ucl_adler32(adler, (const ucl_bytep) buf, len);
309 }
310
311 #if 0 /* UNUSED */
312 unsigned upx_ucl_crc32(const void *buf, unsigned len, unsigned crc)
313 {
314 return ucl_crc32(crc, (const ucl_bytep) buf, len);
315 }
316 #endif
317
318 #endif /* WITH_UCL */
319
320 /* vim:set ts=4 sw=4 et: */
321