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