lzo: update to 2.09
[tomato.git] / release / src / router / lzo / examples / lzopack.c
blobc01b47dc883846039502390a010436a0aae19b07
1 /* lzopack.c -- LZO example program: a simple file packer
3 This file is part of the LZO real-time data compression library.
5 Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer
6 All Rights Reserved.
8 The LZO library is free software; you can redistribute it and/or
9 modify it 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.
13 The LZO library 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.
18 You should have received a copy of the GNU General Public License
19 along with the LZO library; see the file COPYING.
20 If not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 http://www.oberhumer.com/opensource/lzo/
29 /*************************************************************************
30 // NOTE: this is an example program, so do not use to backup your data.
32 // This program lacks things like sophisticated file handling but is
33 // pretty complete regarding compression - it should provide a good
34 // starting point for adaption for your applications.
36 // Please study LZO.FAQ and simple.c first.
37 **************************************************************************/
39 #include <lzo/lzoconf.h>
40 #include <lzo/lzo1x.h>
42 /* portability layer */
43 static const char *progname = NULL;
44 #define WANT_LZO_MALLOC 1
45 #define WANT_LZO_FREAD 1
46 #define WANT_LZO_WILDARGV 1
47 #define WANT_XMALLOC 1
48 #include "examples/portab.h"
51 static unsigned long total_in = 0;
52 static unsigned long total_out = 0;
53 static lzo_bool opt_debug = 0;
55 /* magic file header for lzopack-compressed files */
56 static const unsigned char magic[7] =
57 { 0x00, 0xe9, 0x4c, 0x5a, 0x4f, 0xff, 0x1a };
60 /*************************************************************************
61 // file IO
62 **************************************************************************/
64 static lzo_uint xread(FILE *fp, lzo_voidp buf, lzo_uint len, lzo_bool allow_eof)
66 lzo_uint l;
68 l = (lzo_uint) lzo_fread(fp, buf, len);
69 if (l > len)
71 fprintf(stderr, "\n%s: internal error - something is wrong with your C library !!!\n", progname);
72 exit(1);
74 if (l != len && !allow_eof)
76 fprintf(stderr, "\n%s: read error - premature end of file\n", progname);
77 exit(1);
79 total_in += (unsigned long) l;
80 return l;
83 static lzo_uint xwrite(FILE *fp, const lzo_voidp buf, lzo_uint len)
85 if (fp != NULL && lzo_fwrite(fp, buf, len) != len)
87 fprintf(stderr, "\n%s: write error (disk full ?)\n", progname);
88 exit(1);
90 total_out += (unsigned long) len;
91 return len;
95 static int xgetc(FILE *fp)
97 unsigned char c;
98 xread(fp, (lzo_voidp) &c, 1, 0);
99 return c;
102 static void xputc(FILE *fp, int c)
104 unsigned char cc = (unsigned char) (c & 0xff);
105 xwrite(fp, (const lzo_voidp) &cc, 1);
108 /* read and write portable 32-bit integers */
110 static lzo_uint32_t xread32(FILE *fp)
112 unsigned char b[4];
113 lzo_uint32_t v;
115 xread(fp, b, 4, 0);
116 v = (lzo_uint32_t) b[3] << 0;
117 v |= (lzo_uint32_t) b[2] << 8;
118 v |= (lzo_uint32_t) b[1] << 16;
119 v |= (lzo_uint32_t) b[0] << 24;
120 return v;
123 static void xwrite32(FILE *fp, lzo_uint v)
125 unsigned char b[4];
127 b[3] = (unsigned char) ((v >> 0) & 0xff);
128 b[2] = (unsigned char) ((v >> 8) & 0xff);
129 b[1] = (unsigned char) ((v >> 16) & 0xff);
130 b[0] = (unsigned char) ((v >> 24) & 0xff);
131 xwrite(fp, b, 4);
135 /*************************************************************************
136 // compress
138 // possible improvement: we could use overlapping compression to
139 // save some memory - see overlap.c. This would require some minor
140 // changes in the decompression code as well, because if a block
141 // turns out to be incompressible we would still have to store it in its
142 // "compressed" (i.e. then slightly enlarged) form because the original
143 // (uncompressed) data would have been lost during the overlapping
144 // compression.
145 **************************************************************************/
147 static int do_compress(FILE *fi, FILE *fo, int compression_level, lzo_uint block_size)
149 int r = 0;
150 lzo_bytep in = NULL;
151 lzo_bytep out = NULL;
152 lzo_voidp wrkmem = NULL;
153 lzo_uint in_len;
154 lzo_uint out_len;
155 lzo_uint wrkmem_size;
156 lzo_uint32_t flags = 1; /* do compute a checksum */
157 int method = 1; /* compression method: LZO1X */
158 lzo_uint32_t checksum;
160 total_in = total_out = 0;
163 * Step 1: write magic header, flags & block size, init checksum
165 xwrite(fo, magic, sizeof(magic));
166 xwrite32(fo, flags);
167 xputc(fo, method); /* compression method */
168 xputc(fo, compression_level); /* compression level */
169 xwrite32(fo, block_size);
170 checksum = lzo_adler32(0, NULL, 0);
173 * Step 2: allocate compression buffers and work-memory
175 in = (lzo_bytep) xmalloc(block_size);
176 out = (lzo_bytep) xmalloc(block_size + block_size / 16 + 64 + 3);
177 if (compression_level == 9)
178 wrkmem_size = LZO1X_999_MEM_COMPRESS;
179 else
180 wrkmem_size = LZO1X_1_MEM_COMPRESS;
181 wrkmem = (lzo_voidp) xmalloc(wrkmem_size);
182 if (in == NULL || out == NULL || wrkmem == NULL)
184 printf("%s: out of memory\n", progname);
185 r = 1;
186 goto err;
190 * Step 3: process blocks
192 for (;;)
194 /* read block */
195 in_len = xread(fi, in, block_size, 1);
196 if (in_len == 0)
197 break;
199 /* update checksum */
200 if (flags & 1)
201 checksum = lzo_adler32(checksum, in, in_len);
203 /* clear wrkmem (not needed, only for debug/benchmark purposes) */
204 if (opt_debug)
205 lzo_memset(wrkmem, 0xff, wrkmem_size);
207 /* compress block */
208 if (compression_level == 9)
209 r = lzo1x_999_compress(in, in_len, out, &out_len, wrkmem);
210 else
211 r = lzo1x_1_compress(in, in_len, out, &out_len, wrkmem);
212 if (r != LZO_E_OK || out_len > in_len + in_len / 16 + 64 + 3)
214 /* this should NEVER happen */
215 printf("internal error - compression failed: %d\n", r);
216 r = 2;
217 goto err;
220 /* write uncompressed block size */
221 xwrite32(fo, in_len);
223 if (out_len < in_len)
225 /* write compressed block */
226 xwrite32(fo, out_len);
227 xwrite(fo, out, out_len);
229 else
231 /* not compressible - write uncompressed block */
232 xwrite32(fo, in_len);
233 xwrite(fo, in, in_len);
237 /* write EOF marker */
238 xwrite32(fo, 0);
240 /* write checksum */
241 if (flags & 1)
242 xwrite32(fo, checksum);
244 r = 0;
245 err:
246 lzo_free(wrkmem);
247 lzo_free(out);
248 lzo_free(in);
249 return r;
253 /*************************************************************************
254 // decompress / test
256 // We are using overlapping (in-place) decompression to save some
257 // memory - see overlap.c.
258 **************************************************************************/
260 static int do_decompress(FILE *fi, FILE *fo)
262 int r = 0;
263 lzo_bytep buf = NULL;
264 lzo_uint buf_len;
265 unsigned char m [ sizeof(magic) ];
266 lzo_uint32_t flags;
267 int method;
268 int compression_level;
269 lzo_uint block_size;
270 lzo_uint32_t checksum;
272 total_in = total_out = 0;
275 * Step 1: check magic header, read flags & block size, init checksum
277 if (xread(fi, m, sizeof(magic), 1) != sizeof(magic) ||
278 memcmp(m, magic, sizeof(magic)) != 0)
280 printf("%s: header error - this file is not compressed by lzopack\n", progname);
281 r = 1;
282 goto err;
284 flags = xread32(fi);
285 method = xgetc(fi);
286 compression_level = xgetc(fi);
287 if (method != 1)
289 printf("%s: header error - invalid method %d (level %d)\n",
290 progname, method, compression_level);
291 r = 2;
292 goto err;
294 block_size = xread32(fi);
295 if (block_size < 1024 || block_size > 8L * 1024L * 1024L)
297 printf("%s: header error - invalid block size %ld\n",
298 progname, (long) block_size);
299 r = 3;
300 goto err;
302 checksum = lzo_adler32(0, NULL, 0);
305 * Step 2: allocate buffer for in-place decompression
307 buf_len = block_size + block_size / 16 + 64 + 3;
308 buf = (lzo_bytep) xmalloc(buf_len);
309 if (buf == NULL)
311 printf("%s: out of memory\n", progname);
312 r = 4;
313 goto err;
317 * Step 3: process blocks
319 for (;;)
321 lzo_bytep in;
322 lzo_bytep out;
323 lzo_uint in_len;
324 lzo_uint out_len;
326 /* read uncompressed size */
327 out_len = xread32(fi);
329 /* exit if last block (EOF marker) */
330 if (out_len == 0)
331 break;
333 /* read compressed size */
334 in_len = xread32(fi);
336 /* sanity check of the size values */
337 if (in_len > block_size || out_len > block_size ||
338 in_len == 0 || in_len > out_len)
340 printf("%s: block size error - data corrupted\n", progname);
341 r = 5;
342 goto err;
345 /* place compressed block at the top of the buffer */
346 in = buf + buf_len - in_len;
347 out = buf;
349 /* read compressed block data */
350 xread(fi, in, in_len, 0);
352 if (in_len < out_len)
354 /* decompress - use safe decompressor as data might be corrupted
355 * during a file transfer */
356 lzo_uint new_len = out_len;
358 r = lzo1x_decompress_safe(in, in_len, out, &new_len, NULL);
359 if (r != LZO_E_OK || new_len != out_len)
361 printf("%s: compressed data violation\n", progname);
362 r = 6;
363 goto err;
365 /* write decompressed block */
366 xwrite(fo, out, out_len);
367 /* update checksum */
368 if (flags & 1)
369 checksum = lzo_adler32(checksum, out, out_len);
371 else
373 /* write original (incompressible) block */
374 xwrite(fo, in, in_len);
375 /* update checksum */
376 if (flags & 1)
377 checksum = lzo_adler32(checksum, in, in_len);
381 /* read and verify checksum */
382 if (flags & 1)
384 lzo_uint32_t c = xread32(fi);
385 if (c != checksum)
387 printf("%s: checksum error - data corrupted\n", progname);
388 r = 7;
389 goto err;
393 r = 0;
394 err:
395 lzo_free(buf);
396 return r;
400 /*************************************************************************
402 **************************************************************************/
404 static void usage(void)
406 printf("usage: %s [-9] input-file output-file (compress)\n", progname);
407 printf("usage: %s -d input-file output-file (decompress)\n", progname);
408 printf("usage: %s -t input-file... (test)\n", progname);
409 exit(1);
413 /* open input file */
414 static FILE *xopen_fi(const char *name)
416 FILE *fp;
418 fp = fopen(name, "rb");
419 if (fp == NULL)
421 printf("%s: cannot open input file %s\n", progname, name);
422 exit(1);
424 #if defined(HAVE_STAT) && defined(S_ISREG)
426 struct stat st;
427 int is_regular = 1;
428 if (stat(name, &st) != 0 || !S_ISREG(st.st_mode))
429 is_regular = 0;
430 if (!is_regular)
432 printf("%s: %s is not a regular file\n", progname, name);
433 fclose(fp); fp = NULL;
434 exit(1);
437 #endif
438 return fp;
442 /* open output file */
443 static FILE *xopen_fo(const char *name)
445 FILE *fp;
447 #if 0
448 /* this is an example program, so make sure we don't overwrite a file */
449 fp = fopen(name, "rb");
450 if (fp != NULL)
452 printf("%s: file %s already exists -- not overwritten\n", progname, name);
453 fclose(fp); fp = NULL;
454 exit(1);
456 #endif
457 fp = fopen(name, "wb");
458 if (fp == NULL)
460 printf("%s: cannot open output file %s\n", progname, name);
461 exit(1);
463 return fp;
467 /* close file */
468 static void xclose(FILE *fp)
470 if (fp)
472 int err;
473 err = ferror(fp);
474 if (fclose(fp) != 0)
475 err = 1;
476 if (err)
478 printf("%s: error while closing file\n", progname);
479 exit(1);
485 /*************************************************************************
487 **************************************************************************/
489 int __lzo_cdecl_main main(int argc, char *argv[])
491 int i = 1;
492 int r = 0;
493 FILE *fi = NULL;
494 FILE *fo = NULL;
495 const char *in_name = NULL;
496 const char *out_name = NULL;
497 unsigned opt_decompress = 0;
498 unsigned opt_test = 0;
499 int opt_compression_level = 1;
500 lzo_uint opt_block_size;
501 const char *s;
503 lzo_wildargv(&argc, &argv);
505 progname = argv[0];
506 for (s = progname; *s; s++)
507 if ((*s == '/' || *s == '\\') && s[1])
508 progname = s + 1;
510 printf("\nLZO real-time data compression library (v%s, %s).\n",
511 lzo_version_string(), lzo_version_date());
512 printf("Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer\nAll Rights Reserved.\n\n");
514 #if 0
515 printf(
516 "*** DISCLAIMER ***\n"
517 " This is an example program, do not use to backup your data !\n"
518 " Get LZOP if you're interested into a full-featured packer.\n"
519 " See http://www.oberhumer.com/opensource/lzop/\n"
520 "\n");
521 #endif
525 * Step 1: initialize the LZO library
527 if (lzo_init() != LZO_E_OK)
529 printf("internal error - lzo_init() failed !!!\n");
530 printf("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable '-DLZO_DEBUG' for diagnostics)\n");
531 exit(1);
536 * Step 2: setup memory
538 opt_block_size = 256 * 1024L;
540 #if defined(LZO_MM_AHSHIFT)
541 /* reduce memory requirements for ancient 16-bit DOS 640kB real-mode */
542 if (LZO_MM_AHSHIFT != 3)
543 opt_block_size = 16 * 1024L;
544 #endif
548 * Step 3: get options
551 while (i < argc && argv[i][0] == '-')
553 if (strcmp(argv[i],"-d") == 0)
554 opt_decompress = 1;
555 else if (strcmp(argv[i],"-t") == 0)
556 opt_test = 1;
557 else if (strcmp(argv[i],"-9") == 0)
558 opt_compression_level = 9;
559 else if (argv[i][1] == 'b' && argv[i][2])
561 long b = atol(&argv[i][2]);
562 if (b >= 1024L && b <= 8*1024*1024L)
563 opt_block_size = (lzo_uint) b;
564 else
566 printf("%s: invalid block_size in option '%s'.\n", progname, argv[i]);
567 usage();
570 else if (strcmp(argv[i],"--debug") == 0)
571 opt_debug += 1;
572 else
573 usage();
574 i++;
576 if (opt_test && i >= argc)
577 usage();
578 if (!opt_test && i + 2 != argc)
579 usage();
583 * Step 4: process file(s)
586 if (opt_test)
588 while (i < argc && r == 0)
590 in_name = argv[i++];
591 fi = xopen_fi(in_name);
592 r = do_decompress(fi, NULL);
593 if (r == 0)
594 printf("%s: %s tested ok (%lu -> %lu bytes)\n",
595 progname, in_name, total_in, total_out);
596 xclose(fi); fi = NULL;
599 else if (opt_decompress)
601 in_name = argv[i++];
602 out_name = argv[i++];
603 fi = xopen_fi(in_name);
604 fo = xopen_fo(out_name);
605 r = do_decompress(fi, fo);
606 if (r == 0)
607 printf("%s: decompressed %lu into %lu bytes\n",
608 progname, total_in, total_out);
610 else /* compress */
612 in_name = argv[i++];
613 out_name = argv[i++];
614 fi = xopen_fi(in_name);
615 fo = xopen_fo(out_name);
616 r = do_compress(fi, fo, opt_compression_level, opt_block_size);
617 if (r == 0)
618 printf("%s: compressed %lu into %lu bytes\n",
619 progname, total_in, total_out);
622 xclose(fi); fi = NULL;
623 xclose(fo); fo = NULL;
624 return r;
628 /* vim:set ts=4 sw=4 et: */