summaryrefslogtreecommitdiff
path: root/tools/ucl/uclpack.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ucl/uclpack.c')
-rw-r--r--tools/ucl/uclpack.c660
1 files changed, 660 insertions, 0 deletions
diff --git a/tools/ucl/uclpack.c b/tools/ucl/uclpack.c
new file mode 100644
index 0000000000..08b33af48d
--- /dev/null
+++ b/tools/ucl/uclpack.c
@@ -0,0 +1,660 @@
1/* uclpack.c -- example program: a simple file packer
2
3 This file is part of the UCL data compression library.
4
5 Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
6 All Rights Reserved.
7
8 The UCL 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.
12
13 The UCL 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.
17
18 You should have received a copy of the GNU General Public License
19 along with the UCL library; see the file COPYING.
20 If not, write to the Free Software Foundation, Inc.,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 */
26
27
28/*************************************************************************
29// NOTE: this is an example program, so do not use to backup your data
30//
31// This program lacks things like sophisticated file handling but is
32// pretty complete regarding compression - it should provide a good
33// starting point for adaption for you applications.
34**************************************************************************/
35
36#include <ucl/ucl.h>
37#include "lutil.h"
38
39static const char *progname = NULL;
40
41static unsigned long total_in = 0;
42static unsigned long total_out = 0;
43static ucl_bool opt_debug = 0;
44
45/* don't compute or verify checksum, always use fast decompressor */
46static ucl_bool opt_fast = 0;
47
48/* magic file header for compressed files */
49static const unsigned char magic[8] =
50 { 0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a };
51
52
53/*************************************************************************
54// file IO
55**************************************************************************/
56
57ucl_uint xread(FILE *f, ucl_voidp buf, ucl_uint len, ucl_bool allow_eof)
58{
59 ucl_uint l;
60
61 l = ucl_fread(f,buf,len);
62 if (l > len)
63 {
64 fprintf(stderr,"\nsomething's wrong with your C library !!!\n");
65 exit(1);
66 }
67 if (l != len && !allow_eof)
68 {
69 fprintf(stderr,"\nread error - premature end of file\n");
70 exit(1);
71 }
72 total_in += l;
73 return l;
74}
75
76ucl_uint xwrite(FILE *f, const ucl_voidp buf, ucl_uint len)
77{
78 ucl_uint l;
79
80 if (f != NULL)
81 {
82 l = ucl_fwrite(f,buf,len);
83 if (l != len)
84 {
85 fprintf(stderr,"\nwrite error [%ld %ld] (disk full ?)\n",
86 (long)len, (long)l);
87 exit(1);
88 }
89 }
90 total_out += len;
91 return len;
92}
93
94
95int xgetc(FILE *f)
96{
97 unsigned char c;
98 xread(f,(ucl_voidp) &c,1,0);
99 return c;
100}
101
102void xputc(FILE *f, int c)
103{
104 unsigned char cc = (unsigned char) c;
105 xwrite(f,(const ucl_voidp) &cc,1);
106}
107
108/* read and write portable 32-bit integers */
109
110ucl_uint32 xread32(FILE *f)
111{
112 unsigned char b[4];
113 ucl_uint32 v;
114
115 xread(f,b,4,0);
116 v = (ucl_uint32) b[3] << 0;
117 v |= (ucl_uint32) b[2] << 8;
118 v |= (ucl_uint32) b[1] << 16;
119 v |= (ucl_uint32) b[0] << 24;
120 return v;
121}
122
123void xwrite32(FILE *f, ucl_uint32 v)
124{
125 unsigned char b[4];
126
127 b[3] = (unsigned char) (v >> 0);
128 b[2] = (unsigned char) (v >> 8);
129 b[1] = (unsigned char) (v >> 16);
130 b[0] = (unsigned char) (v >> 24);
131 xwrite(f,b,4);
132}
133
134
135/*************************************************************************
136// util
137**************************************************************************/
138
139static ucl_uint get_overhead(int method, ucl_uint size)
140{
141 if (method == 0x2b || method == 0x2d || method == 0x2e)
142 return size / 8 + 256;
143 return 0;
144}
145
146
147static char method_name[64];
148
149static ucl_bool set_method_name(int method, int level)
150{
151 method_name[0] = 0;
152 if (level < 1 || level > 10)
153 return 0;
154 if (method == 0x2b)
155 sprintf(method_name,"NRV2B-99/%d", level);
156 else if (method == 0x2d)
157 sprintf(method_name,"NRV2D-99/%d", level);
158 else if (method == 0x2e)
159 sprintf(method_name,"NRV2E-99/%d", level);
160 else
161 return 0;
162 return 1;
163}
164
165
166/*************************************************************************
167// compress
168**************************************************************************/
169
170int do_compress(FILE *fi, FILE *fo, int method, int level, ucl_uint block_size)
171{
172 int r = 0;
173 ucl_byte *in = NULL;
174 ucl_byte *out = NULL;
175 ucl_uint in_len;
176 ucl_uint out_len;
177 ucl_uint32 flags = opt_fast ? 0 : 1;
178 ucl_uint32 checksum;
179 ucl_uint overhead = 0;
180
181 total_in = total_out = 0;
182
183/*
184 * Step 1: write magic header, flags & block size, init checksum
185 */
186 xwrite(fo,magic,sizeof(magic));
187 xwrite32(fo,flags);
188 xputc(fo,method); /* compression method */
189 xputc(fo,level); /* compression level */
190 xwrite32(fo,block_size);
191 checksum = ucl_adler32(0,NULL,0);
192
193/*
194 * Step 2: allocate compression buffers and work-memory
195 */
196 overhead = get_overhead(method,block_size);
197 in = (ucl_byte *) ucl_malloc(block_size);
198 out = (ucl_byte *) ucl_malloc(block_size + overhead);
199 if (in == NULL || out == NULL)
200 {
201 printf("%s: out of memory\n", progname);
202 r = 1;
203 goto err;
204 }
205
206/*
207 * Step 3: process blocks
208 */
209 for (;;)
210 {
211 /* read block */
212 in_len = xread(fi,in,block_size,1);
213 if (in_len <= 0)
214 break;
215
216 /* update checksum */
217 if (flags & 1)
218 checksum = ucl_adler32(checksum,in,in_len);
219
220 /* compress block */
221 r = UCL_E_ERROR;
222 if (method == 0x2b)
223 r = ucl_nrv2b_99_compress(in,in_len,out,&out_len,0,level,NULL,NULL);
224 else if (method == 0x2d)
225 r = ucl_nrv2d_99_compress(in,in_len,out,&out_len,0,level,NULL,NULL);
226 else if (method == 0x2e)
227 r = ucl_nrv2e_99_compress(in,in_len,out,&out_len,0,level,NULL,NULL);
228 if (r != UCL_E_OK || out_len > in_len + get_overhead(method,in_len))
229 {
230 /* this should NEVER happen */
231 printf("internal error - compression failed: %d\n", r);
232 r = 2;
233 goto err;
234 }
235
236 /* write uncompressed block size */
237 xwrite32(fo,in_len);
238
239 if (out_len < in_len)
240 {
241 /* write compressed block */
242 xwrite32(fo,out_len);
243 xwrite(fo,out,out_len);
244 }
245 else
246 {
247 /* not compressible - write uncompressed block */
248 xwrite32(fo,in_len);
249 xwrite(fo,in,in_len);
250 }
251 }
252
253 /* write EOF marker */
254 xwrite32(fo,0);
255
256 /* write checksum */
257 if (flags & 1)
258 xwrite32(fo,checksum);
259
260 r = 0;
261err:
262 ucl_free(out);
263 ucl_free(in);
264 return r;
265}
266
267
268/*************************************************************************
269// decompress / test
270//
271// We are using overlapping (in-place) decompression to save some
272// memory - see overlap.c.
273**************************************************************************/
274
275int do_decompress(FILE *fi, FILE *fo)
276{
277 int r = 0;
278 ucl_byte *buf = NULL;
279 ucl_uint buf_len;
280 unsigned char m [ sizeof(magic) ];
281 ucl_uint32 flags;
282 int method;
283 int level;
284 ucl_uint block_size;
285 ucl_uint32 checksum;
286 ucl_uint overhead = 0;
287
288 total_in = total_out = 0;
289
290/*
291 * Step 1: check magic header, read flags & block size, init checksum
292 */
293 if (xread(fi,m,sizeof(magic),1) != sizeof(magic) ||
294 memcmp(m,magic,sizeof(magic)) != 0)
295 {
296 printf("%s: header error - this file is not compressed by uclpack\n", progname);
297 r = 1;
298 goto err;
299 }
300 flags = xread32(fi);
301 method = xgetc(fi);
302 level = xgetc(fi);
303 block_size = xread32(fi);
304 overhead = get_overhead(method,block_size);
305 if (overhead == 0 || !set_method_name(method, level))
306 {
307 printf("%s: header error - invalid method %d (level %d)\n",
308 progname, method, level);
309 r = 2;
310 goto err;
311 }
312 if (block_size < 1024 || block_size > 8*1024*1024L)
313 {
314 printf("%s: header error - invalid block size %ld\n",
315 progname, (long) block_size);
316 r = 3;
317 goto err;
318 }
319 checksum = ucl_adler32(0,NULL,0);
320
321/*
322 * Step 2: allocate buffer for in-place decompression
323 */
324 buf_len = block_size + overhead;
325 buf = (ucl_byte *) ucl_malloc(buf_len);
326 if (buf == NULL)
327 {
328 printf("%s: out of memory\n", progname);
329 r = 4;
330 goto err;
331 }
332
333/*
334 * Step 3: process blocks
335 */
336 for (;;)
337 {
338 ucl_byte *in;
339 ucl_byte *out;
340 ucl_uint in_len;
341 ucl_uint out_len;
342
343 /* read uncompressed size */
344 out_len = xread32(fi);
345
346 /* exit if last block (EOF marker) */
347 if (out_len == 0)
348 break;
349
350 /* read compressed size */
351 in_len = xread32(fi);
352
353 /* sanity check of the size values */
354 if (in_len > block_size || out_len > block_size ||
355 in_len == 0 || in_len > out_len)
356 {
357 printf("%s: block size error - data corrupted\n", progname);
358 r = 5;
359 goto err;
360 }
361
362 /* place compressed block at the top of the buffer */
363 in = buf + buf_len - in_len;
364 out = buf;
365
366 /* read compressed block data */
367 xread(fi,in,in_len,0);
368
369 if (in_len < out_len)
370 {
371 /* decompress - use safe decompressor as data might be corrupted */
372 ucl_uint new_len = out_len;
373
374 if (method == 0x2b)
375 {
376 if (opt_fast)
377 r = ucl_nrv2b_decompress_8(in,in_len,out,&new_len,NULL);
378 else
379 r = ucl_nrv2b_decompress_safe_8(in,in_len,out,&new_len,NULL);
380 }
381 else if (method == 0x2d)
382 {
383 if (opt_fast)
384 r = ucl_nrv2d_decompress_8(in,in_len,out,&new_len,NULL);
385 else
386 r = ucl_nrv2d_decompress_safe_8(in,in_len,out,&new_len,NULL);
387 }
388 else if (method == 0x2e)
389 {
390 if (opt_fast)
391 r = ucl_nrv2e_decompress_8(in,in_len,out,&new_len,NULL);
392 else
393 r = ucl_nrv2e_decompress_safe_8(in,in_len,out,&new_len,NULL);
394 }
395 if (r != UCL_E_OK || new_len != out_len)
396 {
397 printf("%s: compressed data violation: error %d (0x%x: %ld/%ld/%ld)\n", progname, r, method, (long) in_len, (long) out_len, (long) new_len);
398 r = 6;
399 goto err;
400 }
401 /* write decompressed block */
402 xwrite(fo,out,out_len);
403 /* update checksum */
404 if ((flags & 1) && !opt_fast)
405 checksum = ucl_adler32(checksum,out,out_len);
406 }
407 else
408 {
409 /* write original (incompressible) block */
410 xwrite(fo,in,in_len);
411 /* update checksum */
412 if ((flags & 1) && !opt_fast)
413 checksum = ucl_adler32(checksum,in,in_len);
414 }
415 }
416
417 /* read and verify checksum */
418 if (flags & 1)
419 {
420 ucl_uint32 c = xread32(fi);
421 if (!opt_fast && c != checksum)
422 {
423 printf("%s: checksum error - data corrupted\n", progname);
424 r = 7;
425 goto err;
426 }
427 }
428
429 r = 0;
430err:
431 ucl_free(buf);
432 return r;
433}
434
435
436/*************************************************************************
437//
438**************************************************************************/
439
440static void usage(void)
441{
442 printf("usage: %s [-123456789] input-file output-file (compress)\n", progname);
443 printf("usage: %s -d input-file output-file (decompress)\n", progname);
444 printf("usage: %s -t input-file... (test)\n", progname);
445 exit(1);
446}
447
448
449/* open input file */
450static FILE *xopen_fi(const char *name)
451{
452 FILE *f;
453
454 f = fopen(name,"rb");
455 if (f == NULL)
456 {
457 printf("%s: cannot open input file %s\n", progname, name);
458 exit(1);
459 }
460#if defined(HAVE_STAT) && defined(S_ISREG)
461 {
462 struct stat st;
463#if defined(HAVE_LSTAT)
464 if (lstat(name,&st) != 0 || !S_ISREG(st.st_mode))
465#else
466 if (stat(name,&st) != 0 || !S_ISREG(st.st_mode))
467#endif
468 {
469 printf("%s: %s is not a regular file\n", progname, name);
470 fclose(f);
471 exit(1);
472 }
473 }
474#endif
475 return f;
476}
477
478
479/* open output file */
480static FILE *xopen_fo(const char *name)
481{
482 FILE *f;
483
484#if 0
485 /* this is an example program, so make sure we don't overwrite a file */
486 f = fopen(name,"rb");
487 if (f != NULL)
488 {
489 printf("%s: file %s already exists -- not overwritten\n", progname, name);
490 fclose(f);
491 exit(1);
492 }
493#endif
494 f = fopen(name,"wb");
495 if (f == NULL)
496 {
497 printf("%s: cannot open output file %s\n", progname, name);
498 exit(1);
499 }
500 return f;
501}
502
503
504/*************************************************************************
505//
506**************************************************************************/
507
508int main(int argc, char *argv[])
509{
510 int i = 1;
511 int r = 0;
512 FILE *fi = NULL;
513 FILE *fo = NULL;
514 const char *in_name = NULL;
515 const char *out_name = NULL;
516 ucl_bool opt_decompress = 0;
517 ucl_bool opt_test = 0;
518 int opt_method = 0x2b;
519 int opt_level = 7;
520#if defined(MAINT)
521 ucl_uint opt_block_size = (2*1024*1024L);
522#else
523 ucl_uint opt_block_size = (256*1024L);
524#endif
525 const char *s;
526
527#if defined(__EMX__)
528 _response(&argc,&argv);
529 _wildcard(&argc,&argv);
530#endif
531 progname = argv[0];
532 for (s = progname; *s; s++)
533 if (*s == '/' || *s == '\\')
534 progname = s + 1;
535
536 printf("\nUCL real-time data compression library (v%s, %s).\n",
537 ucl_version_string(), ucl_version_date());
538 printf("Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer\n\n");
539
540 printf(
541"*** WARNING ***\n"
542" This is an example program, do not use to backup your data !\n"
543"\n");
544
545/*
546 * Step 1: initialize the UCL library
547 */
548 if (ucl_init() != UCL_E_OK)
549 {
550 printf("ucl_init() failed !!!\n");
551 exit(1);
552 }
553
554/*
555 * Step 2: get options
556 */
557
558 while (i < argc && argv[i][0] == '-')
559 {
560 if (strcmp(argv[i],"-d") == 0)
561 opt_decompress = 1;
562 else if (strcmp(argv[i],"-t") == 0)
563 opt_test = 1;
564 else if (strcmp(argv[i],"-F") == 0)
565 opt_fast = 1;
566 else if (strcmp(argv[i],"--2b") == 0)
567 opt_method = 0x2b;
568 else if (strcmp(argv[i],"--nrv2b") == 0)
569 opt_method = 0x2b;
570 else if (strcmp(argv[i],"--2d") == 0)
571 opt_method = 0x2d;
572 else if (strcmp(argv[i],"--nrv2d") == 0)
573 opt_method = 0x2d;
574 else if (strcmp(argv[i],"--2e") == 0)
575 opt_method = 0x2e;
576 else if (strcmp(argv[i],"--nrv2e") == 0)
577 opt_method = 0x2e;
578 else if ((argv[i][1] >= '1' && argv[i][1] <= '9') && !argv[i][2])
579 opt_level = argv[i][1] - '0';
580 else if (strcmp(argv[i],"--10") == 0)
581 opt_level = 10;
582 else if (strcmp(argv[i],"--best") == 0)
583 opt_level = 10;
584 else if (argv[i][1] == 'b' && argv[i][2])
585 {
586#if (UCL_UINT_MAX > UINT_MAX) && defined(HAVE_ATOL)
587 ucl_int b = (ucl_int) atol(&argv[i][2]);
588#else
589 ucl_int b = (ucl_int) atoi(&argv[i][2]);
590#endif
591 if (b >= 1024L && b <= 8*1024*1024L)
592 opt_block_size = b;
593 }
594 else if (strcmp(argv[i],"--debug") == 0)
595 opt_debug = 1;
596 else
597 usage();
598 i++;
599 }
600 if (opt_test && i >= argc)
601 usage();
602 if (!opt_test && i + 2 != argc)
603 usage();
604
605/*
606 * Step 3: process file(s)
607 */
608 if (opt_test)
609 {
610 while (i < argc && r == 0)
611 {
612 in_name = argv[i++];
613 fi = xopen_fi(in_name);
614 r = do_decompress(fi,NULL);
615 if (r == 0)
616 printf("%s: tested ok: %-10s %-11s: %6ld -> %6ld bytes\n",
617 progname, in_name, method_name, total_in, total_out);
618 fclose(fi);
619 fi = NULL;
620 }
621 }
622 else if (opt_decompress)
623 {
624 in_name = argv[i++];
625 out_name = argv[i++];
626 fi = xopen_fi(in_name);
627 fo = xopen_fo(out_name);
628 r = do_decompress(fi,fo);
629 if (r == 0)
630 printf("%s: decompressed %ld into %ld bytes\n",
631 progname, total_in, total_out);
632 }
633 else /* compress */
634 {
635 if (!set_method_name(opt_method, opt_level))
636 {
637 printf("%s: internal error - invalid method %d (level %d)\n",
638 progname, opt_method, opt_level);
639 goto quit;
640 }
641 in_name = argv[i++];
642 out_name = argv[i++];
643 fi = xopen_fi(in_name);
644 fo = xopen_fo(out_name);
645 r = do_compress(fi,fo,opt_method,opt_level,opt_block_size);
646 if (r == 0)
647 printf("%s: algorithm %s, compressed %ld into %ld bytes\n",
648 progname, method_name, total_in, total_out);
649 }
650
651quit:
652 if (fi) fclose(fi);
653 if (fo) fclose(fo);
654 return r;
655}
656
657/*
658vi:ts=4:et
659*/
660