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) 2011 Markus Franz Xaver Johannes Oberhumer
6 Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
7 Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
8 Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
9 Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
10 Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
11 Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
12 Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
13 Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
14 Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
15 Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
16 Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
17 Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
18 Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
19 Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
20 Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
23 The LZO library is free software; you can redistribute it and/or
24 modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation; either version 2 of
26 the License, or (at your option) any later version.
28 The LZO library is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with the LZO library; see the file COPYING.
35 If not, write to the Free Software Foundation, Inc.,
36 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
38 Markus F.X.J. Oberhumer
39 <markus@oberhumer.com>
40 http://www.oberhumer.com/opensource/lzo/
44 /*************************************************************************
45 // NOTE: this is an example program, so do not use to backup your data.
47 // This program lacks things like sophisticated file handling but is
48 // pretty complete regarding compression - it should provide a good
49 // starting point for adaption for your applications.
51 // Please study LZO.FAQ and simple.c first.
52 **************************************************************************/
54 #include "lzo/lzoconf.h"
55 #include "lzo/lzo1x.h"
57 /* portability layer */
58 static const char *progname
= NULL
;
59 #define WANT_LZO_MALLOC 1
60 #define WANT_LZO_FREAD 1
61 #define WANT_LZO_WILDARGV 1
62 #define WANT_XMALLOC 1
63 #include "examples/portab.h"
66 static unsigned long total_in
= 0;
67 static unsigned long total_out
= 0;
68 static lzo_bool opt_debug
= 0;
70 /* magic file header for lzopack-compressed files */
71 static const unsigned char magic
[7] =
72 { 0x00, 0xe9, 0x4c, 0x5a, 0x4f, 0xff, 0x1a };
75 /*************************************************************************
77 **************************************************************************/
79 lzo_uint
xread(FILE *fp
, lzo_voidp buf
, lzo_uint len
, lzo_bool allow_eof
)
83 l
= (lzo_uint
) lzo_fread(fp
, buf
, len
);
86 fprintf(stderr
, "\nsomething's wrong with your C library !!!\n");
89 if (l
!= len
&& !allow_eof
)
91 fprintf(stderr
, "\nread error - premature end of file\n");
94 total_in
+= (unsigned long) l
;
98 lzo_uint
xwrite(FILE *fp
, const lzo_voidp buf
, lzo_uint len
)
100 if (fp
!= NULL
&& lzo_fwrite(fp
, buf
, len
) != len
)
102 fprintf(stderr
, "\nwrite error (disk full ?)\n");
105 total_out
+= (unsigned long) len
;
113 xread(fp
, (lzo_voidp
) &c
, 1, 0);
117 void xputc(FILE *fp
, int c
)
119 unsigned char cc
= (unsigned char) (c
& 0xff);
120 xwrite(fp
, (const lzo_voidp
) &cc
, 1);
123 /* read and write portable 32-bit integers */
125 lzo_uint32
xread32(FILE *fp
)
131 v
= (lzo_uint32
) b
[3] << 0;
132 v
|= (lzo_uint32
) b
[2] << 8;
133 v
|= (lzo_uint32
) b
[1] << 16;
134 v
|= (lzo_uint32
) b
[0] << 24;
138 void xwrite32(FILE *fp
, lzo_xint v
)
142 b
[3] = (unsigned char) ((v
>> 0) & 0xff);
143 b
[2] = (unsigned char) ((v
>> 8) & 0xff);
144 b
[1] = (unsigned char) ((v
>> 16) & 0xff);
145 b
[0] = (unsigned char) ((v
>> 24) & 0xff);
150 /*************************************************************************
153 // possible improvement: we could use overlapping compression to
154 // save some memory - see overlap.c. This would require some minor
155 // changes in the decompression code as well, because if a block
156 // turns out to be incompressible we would still have to store it in its
157 // "compressed" (i.e. then slightly enlarged) form because the original
158 // (uncompressed) data would have been lost during the overlapping
160 **************************************************************************/
162 int do_compress(FILE *fi
, FILE *fo
, int compression_level
, lzo_uint block_size
)
166 lzo_bytep out
= NULL
;
167 lzo_voidp wrkmem
= NULL
;
170 lzo_uint32 wrk_len
= 0;
171 lzo_uint32 flags
= 1; /* do compute a checksum */
172 int method
= 1; /* compression method: LZO1X */
175 total_in
= total_out
= 0;
178 * Step 1: write magic header, flags & block size, init checksum
180 xwrite(fo
, magic
, sizeof(magic
));
182 xputc(fo
, method
); /* compression method */
183 xputc(fo
, compression_level
); /* compression level */
184 xwrite32(fo
, block_size
);
185 checksum
= lzo_adler32(0, NULL
, 0);
188 * Step 2: allocate compression buffers and work-memory
190 in
= (lzo_bytep
) xmalloc(block_size
);
191 out
= (lzo_bytep
) xmalloc(block_size
+ block_size
/ 16 + 64 + 3);
192 if (compression_level
== 9)
193 wrk_len
= LZO1X_999_MEM_COMPRESS
;
195 wrk_len
= LZO1X_1_MEM_COMPRESS
;
196 wrkmem
= (lzo_voidp
) xmalloc(wrk_len
);
197 if (in
== NULL
|| out
== NULL
|| wrkmem
== NULL
)
199 printf("%s: out of memory\n", progname
);
205 * Step 3: process blocks
210 in_len
= xread(fi
, in
, block_size
, 1);
214 /* update checksum */
216 checksum
= lzo_adler32(checksum
, in
, in_len
);
218 /* clear wrkmem (not needed, only for debug/benchmark purposes) */
220 lzo_memset(wrkmem
, 0xff, wrk_len
);
223 if (compression_level
== 9)
224 r
= lzo1x_999_compress(in
, in_len
, out
, &out_len
, wrkmem
);
226 r
= lzo1x_1_compress(in
, in_len
, out
, &out_len
, wrkmem
);
227 if (r
!= LZO_E_OK
|| out_len
> in_len
+ in_len
/ 16 + 64 + 3)
229 /* this should NEVER happen */
230 printf("internal error - compression failed: %d\n", r
);
235 /* write uncompressed block size */
236 xwrite32(fo
, in_len
);
238 if (out_len
< in_len
)
240 /* write compressed block */
241 xwrite32(fo
, out_len
);
242 xwrite(fo
, out
, out_len
);
246 /* not compressible - write uncompressed block */
247 xwrite32(fo
, in_len
);
248 xwrite(fo
, in
, in_len
);
252 /* write EOF marker */
257 xwrite32(fo
, checksum
);
268 /*************************************************************************
271 // We are using overlapping (in-place) decompression to save some
272 // memory - see overlap.c.
273 **************************************************************************/
275 int do_decompress(FILE *fi
, FILE *fo
)
278 lzo_bytep buf
= NULL
;
280 unsigned char m
[ sizeof(magic
) ];
283 int compression_level
;
287 total_in
= total_out
= 0;
290 * Step 1: check magic header, read flags & block size, init checksum
292 if (xread(fi
, m
, sizeof(magic
),1) != sizeof(magic
) ||
293 memcmp(m
, magic
, sizeof(magic
)) != 0)
295 printf("%s: header error - this file is not compressed by lzopack\n", progname
);
301 compression_level
= xgetc(fi
);
304 printf("%s: header error - invalid method %d (level %d)\n",
305 progname
, method
, compression_level
);
309 block_size
= xread32(fi
);
310 if (block_size
< 1024 || block_size
> 8*1024*1024L)
312 printf("%s: header error - invalid block size %ld\n",
313 progname
, (long) block_size
);
317 checksum
= lzo_adler32(0,NULL
,0);
320 * Step 2: allocate buffer for in-place decompression
322 buf_len
= block_size
+ block_size
/ 16 + 64 + 3;
323 buf
= (lzo_bytep
) xmalloc(buf_len
);
326 printf("%s: out of memory\n", progname
);
332 * Step 3: process blocks
341 /* read uncompressed size */
342 out_len
= xread32(fi
);
344 /* exit if last block (EOF marker) */
348 /* read compressed size */
349 in_len
= xread32(fi
);
351 /* sanity check of the size values */
352 if (in_len
> block_size
|| out_len
> block_size
||
353 in_len
== 0 || in_len
> out_len
)
355 printf("%s: block size error - data corrupted\n", progname
);
360 /* place compressed block at the top of the buffer */
361 in
= buf
+ buf_len
- in_len
;
364 /* read compressed block data */
365 xread(fi
, in
, in_len
, 0);
367 if (in_len
< out_len
)
369 /* decompress - use safe decompressor as data might be corrupted
370 * during a file transfer */
371 lzo_uint new_len
= out_len
;
373 r
= lzo1x_decompress_safe(in
, in_len
, out
, &new_len
, NULL
);
374 if (r
!= LZO_E_OK
|| new_len
!= out_len
)
376 printf("%s: compressed data violation\n", progname
);
380 /* write decompressed block */
381 xwrite(fo
, out
, out_len
);
382 /* update checksum */
384 checksum
= lzo_adler32(checksum
, out
, out_len
);
388 /* write original (incompressible) block */
389 xwrite(fo
, in
, in_len
);
390 /* update checksum */
392 checksum
= lzo_adler32(checksum
, in
, in_len
);
396 /* read and verify checksum */
399 lzo_uint32 c
= xread32(fi
);
402 printf("%s: checksum error - data corrupted\n", progname
);
415 /*************************************************************************
417 **************************************************************************/
419 static void usage(void)
421 printf("usage: %s [-9] input-file output-file (compress)\n", progname
);
422 printf("usage: %s -d input-file output-file (decompress)\n", progname
);
423 printf("usage: %s -t input-file... (test)\n", progname
);
428 /* open input file */
429 static FILE *xopen_fi(const char *name
)
433 fp
= fopen(name
, "rb");
436 printf("%s: cannot open input file %s\n", progname
, name
);
439 #if defined(HAVE_STAT) && defined(S_ISREG)
443 if (stat(name
, &st
) != 0 || !S_ISREG(st
.st_mode
))
447 printf("%s: %s is not a regular file\n", progname
, name
);
448 fclose(fp
); fp
= NULL
;
457 /* open output file */
458 static FILE *xopen_fo(const char *name
)
463 /* this is an example program, so make sure we don't overwrite a file */
464 fp
= fopen(name
, "rb");
467 printf("%s: file %s already exists -- not overwritten\n", progname
, name
);
468 fclose(fp
); fp
= NULL
;
472 fp
= fopen(name
, "wb");
475 printf("%s: cannot open output file %s\n", progname
, name
);
483 static void xclose(FILE *fp
)
493 printf("%s: error while closing file\n", progname
);
500 /*************************************************************************
502 **************************************************************************/
504 int __lzo_cdecl_main
main(int argc
, char *argv
[])
510 const char *in_name
= NULL
;
511 const char *out_name
= NULL
;
512 unsigned opt_decompress
= 0;
513 unsigned opt_test
= 0;
514 int opt_compression_level
= 1;
515 lzo_uint opt_block_size
;
518 lzo_wildargv(&argc
, &argv
);
521 for (s
= progname
; *s
; s
++)
522 if ((*s
== '/' || *s
== '\\') && s
[1])
525 printf("\nLZO real-time data compression library (v%s, %s).\n",
526 lzo_version_string(), lzo_version_date());
527 printf("Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\nAll Rights Reserved.\n\n");
531 "*** DISCLAIMER ***\n"
532 " This is an example program, do not use to backup your data !\n"
533 " Get LZOP if you're interested into a full-featured packer.\n"
534 " See http://www.oberhumer.com/opensource/lzop/\n"
540 * Step 1: initialize the LZO library
542 if (lzo_init() != LZO_E_OK
)
544 printf("internal error - lzo_init() failed !!!\n");
545 printf("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable '-DLZO_DEBUG' for diagnostics)\n");
551 * Step 2: setup memory
553 opt_block_size
= 256 * 1024L;
555 #if defined(ACC_MM_AHSHIFT)
556 /* reduce memory requirements for ancient 16-bit DOS 640kB real-mode */
557 if (ACC_MM_AHSHIFT
!= 3)
558 opt_block_size
= 16 * 1024L;
563 * Step 3: get options
566 while (i
< argc
&& argv
[i
][0] == '-')
568 if (strcmp(argv
[i
],"-d") == 0)
570 else if (strcmp(argv
[i
],"-t") == 0)
572 else if (strcmp(argv
[i
],"-9") == 0)
573 opt_compression_level
= 9;
574 else if (argv
[i
][1] == 'b' && argv
[i
][2])
576 long b
= atol(&argv
[i
][2]);
577 if (b
>= 1024L && b
<= 8*1024*1024L)
578 opt_block_size
= (lzo_uint
) b
;
581 printf("%s: invalid block_size in option '%s'.\n", progname
, argv
[i
]);
585 else if (strcmp(argv
[i
],"--debug") == 0)
591 if (opt_test
&& i
>= argc
)
593 if (!opt_test
&& i
+ 2 != argc
)
598 * Step 4: process file(s)
603 while (i
< argc
&& r
== 0)
606 fi
= xopen_fi(in_name
);
607 r
= do_decompress(fi
, NULL
);
609 printf("%s: %s tested ok (%lu -> %lu bytes)\n",
610 progname
, in_name
, total_in
, total_out
);
611 xclose(fi
); fi
= NULL
;
614 else if (opt_decompress
)
617 out_name
= argv
[i
++];
618 fi
= xopen_fi(in_name
);
619 fo
= xopen_fo(out_name
);
620 r
= do_decompress(fi
, fo
);
622 printf("%s: decompressed %lu into %lu bytes\n",
623 progname
, total_in
, total_out
);
628 out_name
= argv
[i
++];
629 fi
= xopen_fi(in_name
);
630 fo
= xopen_fo(out_name
);
631 r
= do_compress(fi
, fo
, opt_compression_level
, opt_block_size
);
633 printf("%s: compressed %lu into %lu bytes\n",
634 progname
, total_in
, total_out
);
637 xclose(fi
); fi
= NULL
;
638 xclose(fo
); fo
= NULL
;