ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/liblzf/lzf.c
(Generate patch)

Comparing liblzf/lzf.c (file contents):
Revision 1.2 by root, Sun Nov 17 11:39:26 2002 UTC vs.
Revision 1.13 by root, Mon Nov 5 23:28:40 2007 UTC

1/* 1/*
2 * Copyright (c) 2000-2002 Marc Alexander Lehmann <pcg@goof.com> 2 * Copyright (c) 2006 Stefan Traby <stefan@hello-penguin.com>
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without modifica- 4 * Redistribution and use in source and binary forms, with or without modifica-
5 * tion, are permitted provided that the following conditions are met: 5 * tion, are permitted provided that the following conditions are met:
6 * 6 *
7 * 1. Redistributions of source code must retain the above copyright notice, 7 * 1. Redistributions of source code must retain the above copyright notice,
9 * 9 *
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution.
13 * 13 *
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19 * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 16 * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 17 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21 * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 18 * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25 * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 22 * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26 * OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * the GNU General Public License ("GPL") version 2 or any later version,
27 * in which case the provisions of the GPL are applicable instead of
28 * the above. If you wish to allow the use of your version of this file
29 * only under the terms of the GPL and not to allow others to use your
30 * version of this file under the BSD license, indicate your decision
31 * by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL. If you do not delete the
33 * provisions above, a recipient may use your version of this file under
34 * either the BSD or the GPL.
27 */ 35 */
28 36
29#include "config.h" 37#include "config.h"
30
31#include <stdio.h> 38#include <stdio.h>
39#include <string.h>
32#include <stdlib.h> 40#include <stdlib.h>
33#include <assert.h>
34
35#include <unistd.h> 41#include <unistd.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <fcntl.h>
36#include <getopt.h> 45#include <errno.h>
37 46#include <limits.h>
38#include "lzf.h" 47#include "lzf.h"
39 48
49#ifdef HAVE_GETOPT_H
50# include <getopt.h>
51#endif
52
53#define BLOCKSIZE (1024 * 64 - 1)
54#define MAX_BLOCKSIZE BLOCKSIZE
55
56typedef unsigned char u8;
57
58static off_t nr_read, nr_written;
59
60static const char *imagename;
61static enum { compress, uncompress, lzcat } mode = compress;
62static int verbose = 0;
63static int force = 0;
64static long blocksize = BLOCKSIZE;
65
66#ifdef HAVE_GETOPT_LONG
67
68 struct option longopts[] = {
69 {"compress", 0, 0, 'c'},
70 {"decompress", 0, 0, 'd'},
71 {"uncompress", 0, 0, 'd'},
72 {"force", 0, 0, 'f'},
73 {"help", 0, 0, 'h'},
74 {"verbose", 0, 0, 'v'},
75 {"blocksize", 1, 0, 'b'},
76 {0, 0, 0, 0}
77 };
78
79 static const char *opt =
80 "-c --compress compress\n"
81 "-d --decompress decompress\n"
82 "-f --force force overwrite of output file\n"
83 "-h --help give this help\n" "-v --verbose verbose mode\n" "-b # --blocksize # set blocksize\n" "\n";
84
85#else
86
87 static const char *opt =
88 "-c compress\n"
89 "-d decompress\n"
90 "-f force overwrite of output file\n"
91 "-h give this help\n"
92 "-v verbose mode\n"
93 "-b # set blocksize\n"
94 "\n";
95
96#endif
97
40static void 98static void
41usage (int ec) 99usage (int rc)
42{ 100{
43 fprintf (stderr, "\n" 101 fprintf (stderr, "\n"
44 "lzf, a very leightweight compression/decompression filter\n" 102 "lzf, a very lightweight compression/decompression utility written by Stefan Traby.\n"
45 "written by Marc Lehmann <pcg@goof.com> You can find more info at\n" 103 "uses liblzf written by Marc Lehmann <schmorp@schmorp.de> You can find more info at\n"
46 "http://liblzv.plan9.de/\n" 104 "http://liblzf.plan9.de/\n"
47 "\n" 105 "\n"
48 "USAGE: lzf -c [-b blocksize] | -d\n" 106 "usage: lzf [-dufhvb] [file ...]\n"
49 " -c compress\n" 107 " unlzf [file ...]\n"
50 " -d decompress\n" 108 " lzcat [file ...]\n"
51 " -b specify the blocksize (default 64k-1)\n"
52 "\n" 109 "\n%s",
53 ); 110 opt);
54 111
55 exit (ec); 112 exit (rc);
113}
114
115static inline ssize_t
116rread (int fd, void *buf, size_t len)
117{
118 ssize_t rc = 0, offset = 0;
119 char *p = buf;
120
121 while (len && (rc = read (fd, &p[offset], len)) > 0)
122 {
123 offset += rc;
124 len -= rc;
125 }
126
127 nr_read += offset;
128
129 if (rc < 0)
130 return rc;
131
132 return offset;
133}
134
135/* returns 0 if all written else -1 */
136static inline ssize_t
137wwrite (int fd, void *buf, size_t len)
138{
139 ssize_t rc;
140 char *b = buf;
141 size_t l = len;
142
143 while (l)
144 {
145 rc = write (fd, b, l);
146 if (rc < 0)
147 {
148 fprintf (stderr, "%s: write error: ", imagename);
149 perror ("");
150 return -1;
151 }
152
153 l -= rc;
154 b += rc;
155 }
156
157 nr_written += len;
158 return 0;
56} 159}
57 160
58/* 161/*
59 * Anatomy: an lzf file consists of any number of blocks in the following format: 162 * Anatomy: an lzf file consists of any number of blocks in the following format:
60 * 163 *
164 * \x00 EOF (optional)
61 * "ZV\0" 2-byte-usize <uncompressed data> 165 * "ZV\0" 2-byte-usize <uncompressed data>
62 * "ZV\1" 2-byte-csize 2-byte-usize <compressed data> 166 * "ZV\1" 2-byte-csize 2-byte-usize <compressed data>
63 * "ZV\2" 4-byte-crc32-0xdebb20e3 (NYI) 167 * "ZV\2" 4-byte-crc32-0xdebb20e3 (NYI)
64 *
65 */ 168 */
66 169
67static void compress (unsigned int blocksize) 170
171#define TYPE0_HDR_SIZE 5
172#define TYPE1_HDR_SIZE 7
173#define MAX_HDR_SIZE 7
174#define MIN_HDR_SIZE 5
175
176static int
177compress_fd (int from, int to)
68{ 178{
69 ssize_t us; 179 ssize_t us, cs, len;
70 unsigned int cs; 180 u8 buf1[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16];
71 u8 buff1[64*1024]; 181 u8 buf2[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16];
72 u8 buff2[64*1024];
73 u8 header[3+2+2]; 182 u8 *header;
74 183
75 header[0] = 'Z'; 184 nr_read = nr_written = 0;
76 header[1] = 'V'; 185 while ((us = rread (from, &buf1[MAX_HDR_SIZE], blocksize)) > 0)
77
78 for(;;) {
79 us = fread (buff1, 1, blocksize, stdin);
80
81 if (us < blocksize)
82 { 186 {
83 if (us == 0) 187 cs = lzf_compress (&buf1[MAX_HDR_SIZE], us, &buf2[MAX_HDR_SIZE], us > 4 ? us - 4 : us);
84 break;
85 else if (!feof (stdin))
86 {
87 perror ("compress");
88 exit (1);
89 }
90 }
91
92 cs = lzf_compress (buff1, us, buff2, us - 4);
93
94 if (cs) 188 if (cs)
95 { 189 {
190 header = &buf2[MAX_HDR_SIZE - TYPE1_HDR_SIZE];
191 header[0] = 'Z';
192 header[1] = 'V';
96 header[2] = 1; 193 header[2] = 1;
97 header[3] = cs >> 8; 194 header[3] = cs >> 8;
98 header[4] = cs & 0xff; 195 header[4] = cs & 0xff;
99 header[5] = us >> 8; 196 header[5] = us >> 8;
100 header[6] = us & 0xff; 197 header[6] = us & 0xff;
101 198 len = cs + TYPE1_HDR_SIZE;
102 fwrite (header, 3+2+2, 1, stdout);
103 fwrite (buff2, cs, 1, stdout);
104 } 199 }
105 else 200 else
106 { 201 { // write uncompressed
202 header = &buf1[MAX_HDR_SIZE - TYPE0_HDR_SIZE];
203 header[0] = 'Z';
204 header[1] = 'V';
107 header[2] = 0; 205 header[2] = 0;
108 header[3] = us >> 8; 206 header[3] = us >> 8;
109 header[4] = us & 0xff; 207 header[4] = us & 0xff;
110 208 len = us + TYPE0_HDR_SIZE;
111 fwrite (header, 3+2, 1, stdout);
112 fwrite (buff1, us, 1, stdout);
113 } 209 }
114 } while (!feof (stdin));
115}
116 210
117static void decompress (void) 211 if (wwrite (to, header, len) == -1)
118{ 212 return -1;
119 ssize_t us; 213 }
120 unsigned int cs;
121 u8 buff1[64*1024];
122 u8 buff2[64*1024];
123 u8 header[3+2+2];
124 214
125 for(;;) { 215 return 0;
126 if (fread (header, 3+2, 1, stdin) != 1) 216}
217
218static int
219uncompress_fd (int from, int to)
220{
221 u8 header[MAX_HDR_SIZE];
222 u8 buf1[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16];
223 u8 buf2[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16];
224 u8 *p;
225 int l, rd;
226 ssize_t rc, cs, us, bytes, over = 0;
227
228 nr_read = nr_written = 0;
229 while (1)
230 {
231 rc = rread (from, header + over, MAX_HDR_SIZE - over);
232 if (rc < 0)
127 { 233 {
128 if (feof (stdin)) 234 fprintf (stderr, "%s: read error: ", imagename);
235 perror ("");
236 return -1;
237 }
238
239 rc += over;
240 over = 0;
241 if (!rc || header[0] == 0)
242 return 0;
243
244 if (rc < MIN_HDR_SIZE || header[0] != 'Z' || header[1] != 'V')
245 {
246 fprintf (stderr, "%s: invalid data stream - magic not found or short header\n", imagename);
247 return -1;
248 }
249
250 switch (header[2])
251 {
252 case 0:
253 cs = -1;
254 us = (header[3] << 8) | header[4];
255 p = &header[TYPE0_HDR_SIZE];
129 break; 256 break;
130 else 257 case 1:
258 if (rc < TYPE1_HDR_SIZE)
131 { 259 {
132 perror ("decompress"); 260 goto short_read;
133 exit (1);
134 } 261 }
135 }
136
137 if (header[0] != 'Z' || header[1] != 'V')
138 {
139 fprintf (stderr, "decompress: invalid stream - no magic number found\n");
140 exit (1);
141 }
142
143 cs = (header[3] << 8) | header[4]; 262 cs = (header[3] << 8) | header[4];
144
145 if (header[2] == 1)
146 {
147 if (fread (header+3+2, 2, 1, stdin) != 1)
148 {
149 perror ("decompress");
150 exit (1);
151 }
152
153 us = (header[5] << 8) | header[6]; 263 us = (header[5] << 8) | header[6];
154 264 p = &header[TYPE1_HDR_SIZE];
155 if (fread (buff1, cs, 1, stdin) != 1) 265 break;
156 { 266 default:
157 perror ("decompress"); 267 fprintf (stderr, "%s: unknown blocktype\n", imagename);
158 exit (1); 268 return -1;
159 } 269 }
160 270
271 bytes = cs == -1 ? us : cs;
272 l = &header[rc] - p;
273
274 if (l > 0)
275 memcpy (buf1, p, l);
276
277 if (l > bytes)
278 {
279 over = l - bytes;
280 memmove (header, &p[bytes], over);
281 }
282
283 p = &buf1[l];
284 rd = bytes - l;
285 if (rd > 0)
286 if ((rc = rread (from, p, rd)) != rd)
287 goto short_read;
288
289 if (cs == -1)
290 {
291 if (wwrite (to, buf1, us))
292 return -1;
293 }
294 else
295 {
161 if (lzf_decompress (buff1, cs, buff2, us) != us) 296 if (lzf_decompress (buf1, cs, buf2, us) != us)
162 { 297 {
163 fprintf (stderr, "decompress: invalid stream - data corrupted\n"); 298 fprintf (stderr, "%s: decompress: invalid stream - data corrupted\n", imagename);
164 exit (1); 299 return -1;
165 } 300 }
166 301
167 fwrite (buff2, us, 1, stdout); 302 if (wwrite (to, buf2, us))
168 } 303 return -1;
169 else if (header[2] == 0)
170 {
171 if (fread (buff2, cs, 1, stdin) != 1)
172 {
173 perror ("decompress");
174 exit (1);
175 } 304 }
176
177 fwrite (buff2, cs, 1, stdout);
178 } 305 }
179 else 306
307 return 0;
308
309short_read:
310 fprintf (stderr, "%s: short data\n", imagename);
311 return -1;
312}
313
314static int
315open_out (const char *name)
316{
317 int fd;
318 int m = O_EXCL;
319
320 if (force)
321 m = 0;
322
323 fd = open (name, O_CREAT | O_WRONLY | O_TRUNC | m, 600);
324#if defined(__MINGW32__)
325 _setmode(fd, _O_BINARY);
326#endif
327 return fd;
328}
329
330static int
331compose_name (const char *fname, char *oname)
332{
333 char *p;
334
335 if (mode == compress)
336 {
337 if (strlen (fname) > PATH_MAX - 4)
180 { 338 {
181 fprintf (stderr, "decompress: invalid stream - unknown block type\n"); 339 fprintf (stderr, "%s: %s.lzf: name too long", imagename, fname);
182 exit (1); 340 return -1;
183 } 341 }
342
343 strcpy (oname, fname);
344 strcat (oname, ".lzf");
184 } 345 }
346 else
347 {
348 if (strlen (fname) > PATH_MAX)
349 {
350 fprintf (stderr, "%s: %s: name too long\n", imagename, fname);
351 return -1;
352 }
353
354 strcpy (oname, fname);
355 p = &oname[strlen (oname)] - 4;
356 if (p < oname || strcmp (p, ".lzf"))
357 {
358 fprintf (stderr, "%s: %s: unknown suffix\n", imagename, fname);
359 return -1;
360 }
361
362 *p = 0;
363 }
364
365 return 0;
366}
367
368static int
369run_file (const char *fname)
370{
371 int fd, fd2;
372 int rc;
373 struct stat mystat;
374 char oname[PATH_MAX + 1];
375
376 if (mode != lzcat)
377 if (compose_name (fname, oname))
378 return -1;
379
380#if !defined(__MINGW32__)
381 rc = lstat (fname, &mystat);
382#else
383 rc = stat (fname, &mystat);
384#endif
385 fd = open (fname, O_RDONLY);
386#if defined(__MINGW32__)
387 _setmode(fd, _O_BINARY);
388#endif
389 if (rc || fd == -1)
390 {
391 fprintf (stderr, "%s: %s: ", imagename, fname);
392 perror ("");
393 return -1;
394 }
395
396 if (!S_ISREG (mystat.st_mode))
397 {
398 fprintf (stderr, "%s: %s: not a regular file.\n", imagename, fname);
399 close (fd);
400 return -1;
401 }
402
403 if (mode == lzcat)
404 {
405 rc = uncompress_fd (fd, 1);
406 close (fd);
407 return rc;
408 }
409
410 fd2 = open_out (oname);
411 if (fd2 == -1)
412 {
413 fprintf (stderr, "%s: %s: ", imagename, oname);
414 perror ("");
415 close (fd);
416 return -1;
417 }
418
419 if (mode == compress)
420 {
421 rc = compress_fd (fd, fd2);
422 if (!rc && verbose)
423 fprintf (stderr, "%s: %5.1f%% -- replaced with %s\n",
424 fname, nr_read == 0 ? 0 : 100.0 - nr_written / ((double) nr_read / 100.0), oname);
425 }
426 else
427 {
428 rc = uncompress_fd (fd, fd2);
429 if (!rc && verbose)
430 fprintf (stderr, "%s: %5.1f%% -- replaced with %s\n",
431 fname, nr_written == 0 ? 0 : 100.0 - nr_read / ((double) nr_written / 100.0), oname);
432 }
433
434#if !defined(__MINGW32__)
435 fchmod (fd2, mystat.st_mode);
436#else
437 chmod (oname, mystat.st_mode);
438#endif
439 close (fd);
440 close (fd2);
441
442 if (!rc)
443 unlink (fname);
444
445 return rc;
185} 446}
186 447
187int 448int
188main (int argc, char *argv[]) 449main (int argc, char *argv[])
189{ 450{
451 char *p = argv[0];
190 int c; 452 int optc;
191 unsigned int blocksize = 64*1024-1; 453 int rc = 0;
192 enum { m_compress, m_decompress } mode = m_compress;
193 454
455 errno = 0;
456 p = getenv ("LZF_BLOCKSIZE");
457 if (p)
458 {
459 blocksize = strtoul (p, 0, 0);
460 if (errno || !blocksize || blocksize > MAX_BLOCKSIZE)
461 blocksize = BLOCKSIZE;
462 }
463
464 p = strrchr (argv[0], '/');
465 imagename = p ? ++p : argv[0];
466
467 if (!strncmp (imagename, "un", 2) || !strncmp (imagename, "de", 2))
468 mode = uncompress;
469
470 if (strstr (imagename, "cat"))
471 mode = lzcat;
472
473#ifdef HAVE_GETOPT_LONG
474 while ((optc = getopt_long (argc, argv, "cdfhvb:", longopts, 0)) != -1)
475#else
194 while ((c = getopt (argc, argv, "cdb:h")) != -1) 476 while ((optc = getopt (argc, argv, "cdfhvb:")) != -1)
477#endif
478 {
195 switch (c) 479 switch (optc)
196 { 480 {
197 case 'c': 481 case 'c':
198 mode = m_compress; 482 mode = compress;
199 break; 483 break;
200
201 case 'd': 484 case 'd':
202 mode = m_decompress; 485 mode = uncompress;
203 break; 486 break;
204
205 case 'b': 487 case 'f':
206 blocksize = atol (optarg); 488 force = 1;
207 break; 489 break;
208
209 case 'h': 490 case 'h':
210 usage (0); 491 usage (0);
211 492 break;
212 case ':':
213 fprintf (stderr, "required argument missing, use -h\n");
214 exit (1);
215
216 case '?': 493 case 'v':
217 fprintf (stderr, "unknown option, use -h\n"); 494 verbose = 1;
218 exit (1); 495 break;
219 496 case 'b':
497 errno = 0;
498 blocksize = strtoul (optarg, 0, 0);
499 if (errno || !blocksize || blocksize > MAX_BLOCKSIZE)
500 blocksize = BLOCKSIZE;
501 break;
220 default: 502 default:
221 usage (1); 503 usage (1);
504 break;
222 } 505 }
506 }
223 507
508 if (optind == argc)
509 { // stdin stdout
510 if (!force)
511 {
512 if ((mode == uncompress || mode == lzcat) && isatty (0))
513 {
514 fprintf (stderr, "%s: compressed data not read from a terminal. Use -f to force decompression.\n", imagename);
515 exit (1);
516 }
517 if (mode == compress && isatty (1))
518 {
519 fprintf (stderr, "%s: compressed data not written to a terminal. Use -f to force compression.\n", imagename);
520 exit (1);
521 }
522 }
523
224 if (mode == m_compress) 524 if (mode == compress)
225 compress (blocksize); 525 rc = compress_fd (0, 1);
226 else if (mode == m_decompress)
227 decompress ();
228 else 526 else
229 abort (); 527 rc = uncompress_fd (0, 1);
230 528
231 return 0; 529 exit (rc ? 1 : 0);
530 }
531
532 while (optind < argc)
533 rc |= run_file (argv[optind++]);
534
535 exit (rc ? 1 : 0);
232} 536}
537

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines