prepcore: error out if the compressed image is too large to load
[profile/ivi/syslinux.git] / lzo / prepcore.c
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8  *   Boston MA 02110-1301, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12
13 /* 
14    This file is based in part on:
15
16    precomp2.c -- example program: how to generate pre-compressed data
17
18    This file is part of the LZO real-time data compression library.
19
20    Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
21    Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
22    Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
23    Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
24    Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
25    Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
26    Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
27    Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
28    Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
29    Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
30    Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
31    Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
32    Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
33    All Rights Reserved.
34
35    The LZO library is free software; you can redistribute it and/or
36    modify it under the terms of the GNU General Public License as
37    published by the Free Software Foundation; either version 2 of
38    the License, or (at your option) any later version.
39
40    The LZO library is distributed in the hope that it will be useful,
41    but WITHOUT ANY WARRANTY; without even the implied warranty of
42    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43    GNU General Public License for more details.
44
45    You should have received a copy of the GNU General Public License
46    along with the LZO library; see the file COPYING.
47    If not, write to the Free Software Foundation, Inc.,
48    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
49
50    Markus F.X.J. Oberhumer
51    <markus@oberhumer.com>
52    http://www.oberhumer.com/opensource/lzo/
53  */
54
55 #include "lzo/lzoconf.h"
56 #include "lzo/lzo1x.h"
57
58 LZO_EXTERN(int)
59 lzo1x_999_compress_internal(const lzo_bytep in, lzo_uint in_len,
60                             lzo_bytep out, lzo_uintp out_len,
61                             lzo_voidp wrkmem,
62                             const lzo_bytep dict, lzo_uint dict_len,
63                             lzo_callback_p cb,
64                             int try_lazy,
65                             lzo_uint good_length,
66                             lzo_uint max_lazy,
67                             lzo_uint nice_length,
68                             lzo_uint max_chain, lzo_uint32 flags);
69
70 LZO_EXTERN(int)
71 lzo1y_999_compress_internal(const lzo_bytep in, lzo_uint in_len,
72                             lzo_bytep out, lzo_uintp out_len,
73                             lzo_voidp wrkmem,
74                             const lzo_bytep dict, lzo_uint dict_len,
75                             lzo_callback_p cb,
76                             int try_lazy,
77                             lzo_uint good_length,
78                             lzo_uint max_lazy,
79                             lzo_uint nice_length,
80                             lzo_uint max_chain, lzo_uint32 flags);
81
82 #define PARANOID 1
83
84 #include <assert.h>
85 #include <inttypes.h>
86 #include <stddef.h>
87 #include <stdlib.h>
88 #include <stdio.h>
89 #include <string.h>
90 #include <ctype.h>
91 #include <time.h>
92
93 struct prefix {
94     uint32_t pfx_start;
95     uint32_t pfx_compressed;
96     uint32_t pfx_cdatalen;
97     uint32_t pfx_checksum;
98     uint32_t pfx_maxlma;
99 };
100
101 static inline uint32_t get_32(const uint32_t * p)
102 {
103 #if defined(__i386__) || defined(__x86_64__)
104     /* Littleendian and unaligned-capable */
105     return *p;
106 #else
107     const uint8_t *pp = (const uint8_t *)p;
108     return (uint32_t) pp[0] + ((uint32_t) pp[1] << 8) +
109         ((uint32_t) pp[2] << 16) + ((uint32_t) pp[3] << 24);
110 #endif
111 }
112
113 static inline void set_32(uint32_t * p, uint32_t v)
114 {
115 #if defined(__i386__) || defined(__x86_64__)
116     /* Littleendian and unaligned-capable */
117     *p = v;
118 #else
119     uint8_t *pp = (uint8_t *) p;
120     pp[0] = (v & 0xff);
121     pp[1] = ((v >> 8) & 0xff);
122     pp[2] = ((v >> 16) & 0xff);
123     pp[3] = ((v >> 24) & 0xff);
124 #endif
125 }
126
127 /*************************************************************************
128 //
129 **************************************************************************/
130
131 int __lzo_cdecl_main main(int argc, char *argv[])
132 {
133     int r;
134     int lazy;
135     const int max_try_lazy = 5;
136     const lzo_uint big = 65536L;        /* can result in very slow compression */
137     const lzo_uint32 flags = 0x1;
138
139     lzo_bytep in;
140     lzo_bytep infile;
141     lzo_uint in_len, infile_len, start, offset, soff;
142
143     lzo_bytep out;
144     lzo_uint out_bufsize;
145     lzo_uint out_len = 0;
146     lzo_uint outfile_len;
147
148     lzo_bytep test;
149
150     lzo_byte wrkmem[LZO1X_999_MEM_COMPRESS];
151
152     lzo_uint best_len;
153     int best_lazy = -1;
154
155     lzo_uint orig_len;
156     lzo_uint32 uncompressed_checksum;
157     lzo_uint32 compressed_checksum;
158
159     FILE *f;
160     const char *progname = NULL;
161     const char *in_name = NULL;
162     const char *out_name = NULL;
163     long l;
164
165     struct prefix *prefix;
166
167     progname = argv[0];
168     if (argc != 3) {
169         printf("usage: %s file output-file\n", progname);
170         exit(1);
171     }
172     in_name = argv[1];
173     if (argc > 2)
174         out_name = argv[2];
175
176 /*
177  * Step 1: initialize the LZO library
178  */
179     if (lzo_init() != LZO_E_OK) {
180         printf("internal error - lzo_init() failed !!!\n");
181         printf
182             ("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable `-DLZO_DEBUG' for diagnostics)\n");
183         exit(1);
184     }
185
186 /*
187  * Step 3: open the input file
188  */
189     f = fopen(in_name, "rb");
190     if (f == NULL) {
191         printf("%s: cannot open file %s\n", progname, in_name);
192         exit(1);
193     }
194     fseek(f, 0, SEEK_END);
195     l = ftell(f);
196     fseek(f, 0, SEEK_SET);
197     if (l <= 0) {
198         printf("%s: %s: empty file\n", progname, in_name);
199         fclose(f);
200         exit(1);
201     }
202     infile_len = (lzo_uint) l;
203     out_bufsize = infile_len + infile_len / 16 + 64 + 3 + 2048;
204
205 /*
206  * Step 4: allocate compression buffers and read the file
207  */
208     infile = (lzo_bytep) malloc(infile_len);
209     out = (lzo_bytep) malloc(out_bufsize);
210     if (infile == NULL || out == NULL) {
211         printf("%s: out of memory\n", progname);
212         exit(1);
213     }
214     infile_len = (lzo_uint) fread(infile, 1, infile_len, f);
215     fclose(f);
216
217 /*
218  * Select the portion which is for compression...
219  */
220     prefix = (struct prefix *)infile;
221     start = get_32(&prefix->pfx_start);
222     offset = get_32(&prefix->pfx_compressed);
223     in = infile + offset;
224     in_len = infile_len - offset;
225     best_len = in_len;
226
227 /*
228  * Step 5: compute a checksum of the uncompressed data
229  */
230     uncompressed_checksum = lzo_adler32(0, NULL, 0);
231     uncompressed_checksum = lzo_adler32(uncompressed_checksum, in, in_len);
232
233 /*
234  * Step 6a: compress from `in' to `out' with LZO1X-999
235  */
236     for (lazy = 0; lazy <= max_try_lazy; lazy++) {
237         out_len = out_bufsize;
238         r = lzo1x_999_compress_internal(in, in_len, out, &out_len, wrkmem,
239                                         NULL, 0, 0,
240                                         lazy, big, big, big, big, flags);
241         if (r != LZO_E_OK) {
242             /* this should NEVER happen */
243             printf("internal error - compression failed: %d\n", r);
244             exit(1);
245         }
246         if (out_len < best_len) {
247             best_len = out_len;
248             best_lazy = lazy;
249         }
250     }
251
252 /*
253  * Step 7: check if compressible
254  */
255     if (best_len >= in_len) {
256         printf("This file contains incompressible data.\n");
257         /* return 0;  -- Sucks to be us -hpa ... */
258     }
259
260 /*
261  * Step 8: compress data again using the best compressor found
262  */
263     out_len = out_bufsize;
264     r = lzo1x_999_compress_internal(in, in_len, out, &out_len, wrkmem,
265                                     NULL, 0, 0,
266                                     best_lazy, big, big, big, big, flags);
267     assert(r == LZO_E_OK);
268     assert(out_len == best_len);
269
270 /*
271  * Step 9: optimize compressed data (compressed data is in `out' buffer)
272  */
273 #if 1
274     /* Optimization does not require any data in the buffer that will
275      * hold the uncompressed data. To prove this, we clear the buffer.
276      */
277     memset(in, 0, in_len);
278 #endif
279
280     orig_len = in_len;
281     r = lzo1x_optimize(out, out_len, in, &orig_len, NULL);
282     if (r != LZO_E_OK || orig_len != in_len) {
283         /* this should NEVER happen */
284         printf("internal error - optimization failed: %d\n", r);
285         exit(1);
286     }
287
288 /*
289  * Step 10: compute a checksum of the compressed data
290  */
291     compressed_checksum = lzo_adler32(0, NULL, 0);
292     compressed_checksum = lzo_adler32(compressed_checksum, out, out_len);
293
294 /*
295  * Step 11: write compressed data to a file
296  */
297     /* Make sure we have up to 2048 bytes of zero after the output */
298     memset(out + out_len, 0, 2048);
299
300     outfile_len = out_len;
301
302     soff = get_32(&prefix->pfx_cdatalen);
303     set_32((uint32_t *) (infile + soff), out_len);
304
305     soff = get_32(&prefix->pfx_checksum);
306     if (soff) {
307         /* ISOLINUX padding and checksumming */
308         uint32_t csum = 0;
309         unsigned int ptr;
310         outfile_len =
311             ((offset - start + out_len + 2047) & ~2047) - (offset - start);
312         for (ptr = 64; ptr < offset; ptr += 4)
313             csum += get_32((uint32_t *) (infile + ptr));
314         for (ptr = 0; ptr < outfile_len; ptr += 4)
315             csum += get_32((uint32_t *) (out + ptr));
316
317         set_32((uint32_t *) (infile + soff), offset - start + outfile_len);
318         set_32((uint32_t *) (infile + soff + 4), csum);
319     }
320
321     if (offset+outfile_len > get_32(&prefix->pfx_maxlma)) {
322         printf("%s: output too big (%lu, max %lu)\n",
323                (unsigned long)offset+outfile_len,
324                (unsigned long)get_32(&prefix->pfx_maxlma));
325         exit(1);
326     }
327
328     f = fopen(out_name, "wb");
329     if (f == NULL) {
330         printf("%s: cannot open output file %s\n", progname, out_name);
331         exit(1);
332     }
333     if (fwrite(infile + start, 1, offset - start, f) != offset - start ||
334         fwrite(out, 1, outfile_len, f) != outfile_len || fclose(f)) {
335         printf("%s: write error !!\n", progname);
336         exit(1);
337     }
338
339 /*
340  * Step 12: verify decompression
341  */
342 #ifdef PARANOID
343     test = calloc(in_len,2);
344     orig_len = in_len*2;
345     r = lzo1x_decompress_safe(out, out_len, test, &orig_len, NULL);
346
347     if (r != LZO_E_OK || orig_len != in_len) {
348         /* this should NEVER happen */
349         printf("internal error - decompression failed: %d\n", r);
350         exit(1);
351     }
352     if (memcmp(test, in, in_len)) {
353         /* this should NEVER happen */
354         printf("internal error - decompression data error\n");
355         exit(1);
356     }
357     /* Now you could also verify decompression under similar conditions as in
358      * your application, e.g. overlapping assembler decompression etc.
359      */
360
361     free(test);
362 #endif
363
364     free(infile);
365     free(out);
366
367     return 0;
368 }