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
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 /*************************************************************************
62 **************************************************************************/
64 static lzo_uint
xread(FILE *fp
, lzo_voidp buf
, lzo_uint len
, lzo_bool allow_eof
)
68 l
= (lzo_uint
) lzo_fread(fp
, buf
, len
);
71 fprintf(stderr
, "\n%s: internal error - something is wrong with your C library !!!\n", progname
);
74 if (l
!= len
&& !allow_eof
)
76 fprintf(stderr
, "\n%s: read error - premature end of file\n", progname
);
79 total_in
+= (unsigned long) 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
);
90 total_out
+= (unsigned long) len
;
95 static int xgetc(FILE *fp
)
98 xread(fp
, (lzo_voidp
) &c
, 1, 0);
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
)
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;
123 static void xwrite32(FILE *fp
, lzo_uint v
)
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);
135 /*************************************************************************
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
145 **************************************************************************/
147 static int do_compress(FILE *fi
, FILE *fo
, int compression_level
, lzo_uint block_size
)
151 lzo_bytep out
= NULL
;
152 lzo_voidp wrkmem
= NULL
;
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
));
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
;
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
);
190 * Step 3: process blocks
195 in_len
= xread(fi
, in
, block_size
, 1);
199 /* update checksum */
201 checksum
= lzo_adler32(checksum
, in
, in_len
);
203 /* clear wrkmem (not needed, only for debug/benchmark purposes) */
205 lzo_memset(wrkmem
, 0xff, wrkmem_size
);
208 if (compression_level
== 9)
209 r
= lzo1x_999_compress(in
, in_len
, out
, &out_len
, wrkmem
);
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
);
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
);
231 /* not compressible - write uncompressed block */
232 xwrite32(fo
, in_len
);
233 xwrite(fo
, in
, in_len
);
237 /* write EOF marker */
242 xwrite32(fo
, checksum
);
253 /*************************************************************************
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
)
263 lzo_bytep buf
= NULL
;
265 unsigned char m
[ sizeof(magic
) ];
268 int compression_level
;
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
);
286 compression_level
= xgetc(fi
);
289 printf("%s: header error - invalid method %d (level %d)\n",
290 progname
, method
, compression_level
);
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
);
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
);
311 printf("%s: out of memory\n", progname
);
317 * Step 3: process blocks
326 /* read uncompressed size */
327 out_len
= xread32(fi
);
329 /* exit if last block (EOF marker) */
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
);
345 /* place compressed block at the top of the buffer */
346 in
= buf
+ buf_len
- in_len
;
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
);
365 /* write decompressed block */
366 xwrite(fo
, out
, out_len
);
367 /* update checksum */
369 checksum
= lzo_adler32(checksum
, out
, out_len
);
373 /* write original (incompressible) block */
374 xwrite(fo
, in
, in_len
);
375 /* update checksum */
377 checksum
= lzo_adler32(checksum
, in
, in_len
);
381 /* read and verify checksum */
384 lzo_uint32_t c
= xread32(fi
);
387 printf("%s: checksum error - data corrupted\n", progname
);
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
);
413 /* open input file */
414 static FILE *xopen_fi(const char *name
)
418 fp
= fopen(name
, "rb");
421 printf("%s: cannot open input file %s\n", progname
, name
);
424 #if defined(HAVE_STAT) && defined(S_ISREG)
428 if (stat(name
, &st
) != 0 || !S_ISREG(st
.st_mode
))
432 printf("%s: %s is not a regular file\n", progname
, name
);
433 fclose(fp
); fp
= NULL
;
442 /* open output file */
443 static FILE *xopen_fo(const char *name
)
448 /* this is an example program, so make sure we don't overwrite a file */
449 fp
= fopen(name
, "rb");
452 printf("%s: file %s already exists -- not overwritten\n", progname
, name
);
453 fclose(fp
); fp
= NULL
;
457 fp
= fopen(name
, "wb");
460 printf("%s: cannot open output file %s\n", progname
, name
);
468 static void xclose(FILE *fp
)
478 printf("%s: error while closing file\n", progname
);
485 /*************************************************************************
487 **************************************************************************/
489 int __lzo_cdecl_main
main(int argc
, char *argv
[])
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
;
503 lzo_wildargv(&argc
, &argv
);
506 for (s
= progname
; *s
; s
++)
507 if ((*s
== '/' || *s
== '\\') && 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");
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"
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");
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;
548 * Step 3: get options
551 while (i
< argc
&& argv
[i
][0] == '-')
553 if (strcmp(argv
[i
],"-d") == 0)
555 else if (strcmp(argv
[i
],"-t") == 0)
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
;
566 printf("%s: invalid block_size in option '%s'.\n", progname
, argv
[i
]);
570 else if (strcmp(argv
[i
],"--debug") == 0)
576 if (opt_test
&& i
>= argc
)
578 if (!opt_test
&& i
+ 2 != argc
)
583 * Step 4: process file(s)
588 while (i
< argc
&& r
== 0)
591 fi
= xopen_fi(in_name
);
592 r
= do_decompress(fi
, NULL
);
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
)
602 out_name
= argv
[i
++];
603 fi
= xopen_fi(in_name
);
604 fo
= xopen_fo(out_name
);
605 r
= do_decompress(fi
, fo
);
607 printf("%s: decompressed %lu into %lu bytes\n",
608 progname
, total_in
, total_out
);
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
);
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
;
628 /* vim:set ts=4 sw=4 et: */