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

Comparing liblzf/lzf.c (file contents):
Revision 1.8 by root, Wed Sep 27 13:51:51 2006 UTC vs.
Revision 1.13 by root, Mon Nov 5 23:28:40 2007 UTC

1/* 1/*
2 * Copyright (c) 2000-2005 Marc Alexander Lehmann <schmorp@schmorp.de> 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,
8 * this list of conditions and the following disclaimer. 8 * this list of conditions and the following disclaimer.
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 *
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 * 13 *
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-
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.
27 * 24 *
28 * Alternatively, the contents of this file may be used under the terms of 25 * Alternatively, the contents of this file may be used under the terms of
29 * the GNU General Public License version 2 (the "GPL"), in which case the 26 * the GNU General Public License ("GPL") version 2 or any later version,
30 * provisions of the GPL are applicable instead of the above. If you wish to 27 * in which case the provisions of the GPL are applicable instead of
31 * allow the use of your version of this file only under the terms of the 28 * the above. If you wish to allow the use of your version of this file
32 * GPL and not to allow others to use your version of this file under the 29 * only under the terms of the GPL and not to allow others to use your
33 * BSD license, indicate your decision by deleting the provisions above and 30 * version of this file under the BSD license, indicate your decision
34 * replace them with the notice and other provisions required by the GPL. If 31 * by deleting the provisions above and replace them with the notice
35 * you do not delete the provisions above, a recipient may use your version 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
36 * of this file under either the BSD or the GPL. 34 * either the BSD or the GPL.
37 */ 35 */
38 36
39#include "config.h" 37#include "config.h"
40
41#include <stdio.h> 38#include <stdio.h>
39#include <string.h>
42#include <stdlib.h> 40#include <stdlib.h>
43#include <string.h>
44#include <assert.h>
45
46#include <unistd.h> 41#include <unistd.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <fcntl.h>
47#include <getopt.h> 45#include <errno.h>
48 46#include <limits.h>
49#include "lzf.h" 47#include "lzf.h"
50 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
51typedef unsigned char u8; 56typedef unsigned char u8;
52 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
53static void 98static void
54usage (int ec) 99usage (int rc)
55{ 100{
56 fprintf (stderr, "\n" 101 fprintf (stderr, "\n"
57 "lzf, a very lightweight compression/decompression filter\n" 102 "lzf, a very lightweight compression/decompression utility written by Stefan Traby.\n"
58 "written by Marc Lehmann <schmorp@schmorp.de> You can find more info at\n" 103 "uses liblzf written by Marc Lehmann <schmorp@schmorp.de> You can find more info at\n"
59 "http://liblzf.plan9.de/\n" 104 "http://liblzf.plan9.de/\n"
60 "\n" 105 "\n"
61 "USAGE: lzf -c [-b blocksize] | -d\n" 106 "usage: lzf [-dufhvb] [file ...]\n"
62 " -c compress\n" 107 " unlzf [file ...]\n"
63 " -d decompress\n" 108 " lzcat [file ...]\n"
64 " -b specify the blocksize (default 64k-1)\n"
65 "\n" 109 "\n%s",
66 ); 110 opt);
67 111
68 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;
69} 159}
70 160
71/* 161/*
72 * 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:
73 * 163 *
74 * \x00 EOF (optional) 164 * \x00 EOF (optional)
75 * "ZV\0" 2-byte-usize <uncompressed data> 165 * "ZV\0" 2-byte-usize <uncompressed data>
76 * "ZV\1" 2-byte-csize 2-byte-usize <compressed data> 166 * "ZV\1" 2-byte-csize 2-byte-usize <compressed data>
77 * "ZV\2" 4-byte-crc32-0xdebb20e3 (NYI) 167 * "ZV\2" 4-byte-crc32-0xdebb20e3 (NYI)
78 *
79 */ 168 */
80 169
81static 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)
82{ 178{
83 ssize_t us; 179 ssize_t us, cs, len;
84 unsigned int cs; 180 u8 buf1[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16];
85 u8 buff1[64*1024]; 181 u8 buf2[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16];
86 u8 buff2[64*1024];
87 u8 header[3+2+2]; 182 u8 *header;
88 183
89 header[0] = 'Z'; 184 nr_read = nr_written = 0;
90 header[1] = 'V'; 185 while ((us = rread (from, &buf1[MAX_HDR_SIZE], blocksize)) > 0)
91
92 for(;;) {
93 us = fread (buff1, 1, blocksize, stdin);
94
95 if (us < blocksize)
96 { 186 {
97 if (us == 0) 187 cs = lzf_compress (&buf1[MAX_HDR_SIZE], us, &buf2[MAX_HDR_SIZE], us > 4 ? us - 4 : us);
98 break;
99 else if (!feof (stdin))
100 {
101 perror ("compress");
102 exit (1);
103 }
104 }
105
106 cs = lzf_compress (buff1, us, buff2, us - 4);
107
108 if (cs) 188 if (cs)
109 { 189 {
190 header = &buf2[MAX_HDR_SIZE - TYPE1_HDR_SIZE];
191 header[0] = 'Z';
192 header[1] = 'V';
110 header[2] = 1; 193 header[2] = 1;
111 header[3] = cs >> 8; 194 header[3] = cs >> 8;
112 header[4] = cs & 0xff; 195 header[4] = cs & 0xff;
113 header[5] = us >> 8; 196 header[5] = us >> 8;
114 header[6] = us & 0xff; 197 header[6] = us & 0xff;
115 198 len = cs + TYPE1_HDR_SIZE;
116 fwrite (header, 3+2+2, 1, stdout);
117 fwrite (buff2, cs, 1, stdout);
118 } 199 }
119 else 200 else
120 { 201 { // write uncompressed
202 header = &buf1[MAX_HDR_SIZE - TYPE0_HDR_SIZE];
203 header[0] = 'Z';
204 header[1] = 'V';
121 header[2] = 0; 205 header[2] = 0;
122 header[3] = us >> 8; 206 header[3] = us >> 8;
123 header[4] = us & 0xff; 207 header[4] = us & 0xff;
124 208 len = us + TYPE0_HDR_SIZE;
125 fwrite (header, 3+2, 1, stdout);
126 fwrite (buff1, us, 1, stdout);
127 } 209 }
128 } while (!feof (stdin));
129}
130 210
131static void decompress (void) 211 if (wwrite (to, header, len) == -1)
132{ 212 return -1;
133 ssize_t us; 213 }
134 unsigned int cs;
135 u8 buff1[64*1024];
136 u8 buff2[64*1024];
137 u8 header[3+2+2];
138 214
139 for(;;) { 215 return 0;
140 int hdrsize = fread (header, 1, 3+2, stdin); 216}
141 217
142 /* check for \0 record */ 218static int
143 if (hdrsize) 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)
144 { 233 {
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
145 if (!header[0]) 250 switch (header[2])
251 {
252 case 0:
253 cs = -1;
254 us = (header[3] << 8) | header[4];
255 p = &header[TYPE0_HDR_SIZE];
146 break; 256 break;
147 else if (hdrsize != 3+2) 257 case 1:
258 if (rc < TYPE1_HDR_SIZE)
148 { 259 {
149 if (feof (stdin)) 260 goto short_read;
150 fprintf (stderr, "decompress: invalid stream - short header\n");
151 else
152 perror ("decompress");
153
154 exit (1);
155 } 261 }
156 }
157 else
158 {
159 if (feof (stdin))
160 break;
161 else
162 {
163 perror ("decompress");
164 exit (1);
165 }
166 }
167
168 if (header[0] != 'Z' || header[1] != 'V')
169 {
170 fprintf (stderr, "decompress: invalid stream - no magic number found\n");
171 exit (1);
172 }
173
174 cs = (header[3] << 8) | header[4]; 262 cs = (header[3] << 8) | header[4];
175
176 if (header[2] == 1)
177 {
178 if (fread (header+3+2, 2, 1, stdin) != 1)
179 {
180 perror ("decompress");
181 exit (1);
182 }
183
184 us = (header[5] << 8) | header[6]; 263 us = (header[5] << 8) | header[6];
185 264 p = &header[TYPE1_HDR_SIZE];
186 if (fread (buff1, cs, 1, stdin) != 1) 265 break;
187 { 266 default:
188 perror ("decompress"); 267 fprintf (stderr, "%s: unknown blocktype\n", imagename);
189 exit (1); 268 return -1;
190 } 269 }
191 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 {
192 if (lzf_decompress (buff1, cs, buff2, us) != us) 296 if (lzf_decompress (buf1, cs, buf2, us) != us)
193 { 297 {
194 fprintf (stderr, "decompress: invalid stream - data corrupted\n"); 298 fprintf (stderr, "%s: decompress: invalid stream - data corrupted\n", imagename);
195 exit (1); 299 return -1;
196 } 300 }
197 301
198 fwrite (buff2, us, 1, stdout); 302 if (wwrite (to, buf2, us))
199 } 303 return -1;
200 else if (header[2] == 0)
201 {
202 if (fread (buff2, cs, 1, stdin) != 1)
203 {
204 perror ("decompress");
205 exit (1);
206 } 304 }
207
208 fwrite (buff2, cs, 1, stdout);
209 } 305 }
210 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)
211 { 338 {
212 fprintf (stderr, "decompress: invalid stream - unknown block type\n"); 339 fprintf (stderr, "%s: %s.lzf: name too long", imagename, fname);
213 exit (1); 340 return -1;
214 } 341 }
342
343 strcpy (oname, fname);
344 strcat (oname, ".lzf");
215 } 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;
216} 446}
217 447
218int 448int
219main (int argc, char *argv[]) 449main (int argc, char *argv[])
220{ 450{
451 char *p = argv[0];
221 int c; 452 int optc;
222 unsigned int blocksize = 64*1024-1; 453 int rc = 0;
223 enum { m_compress, m_decompress } mode = m_compress;
224 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
225 while ((c = getopt (argc, argv, "cdb:h")) != -1) 476 while ((optc = getopt (argc, argv, "cdfhvb:")) != -1)
477#endif
478 {
226 switch (c) 479 switch (optc)
227 { 480 {
228 case 'c': 481 case 'c':
229 mode = m_compress; 482 mode = compress;
230 break; 483 break;
231
232 case 'd': 484 case 'd':
233 mode = m_decompress; 485 mode = uncompress;
234 break; 486 break;
235
236 case 'b': 487 case 'f':
237 blocksize = atol (optarg); 488 force = 1;
238 break; 489 break;
239
240 case 'h': 490 case 'h':
241 usage (0); 491 usage (0);
242 492 break;
243 case ':':
244 fprintf (stderr, "required argument missing, use -h\n");
245 exit (1);
246
247 case '?': 493 case 'v':
248 fprintf (stderr, "unknown option, use -h\n"); 494 verbose = 1;
249 exit (1); 495 break;
250 496 case 'b':
497 errno = 0;
498 blocksize = strtoul (optarg, 0, 0);
499 if (errno || !blocksize || blocksize > MAX_BLOCKSIZE)
500 blocksize = BLOCKSIZE;
501 break;
251 default: 502 default:
252 usage (1); 503 usage (1);
504 break;
253 } 505 }
506 }
254 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
255 if (mode == m_compress) 524 if (mode == compress)
256 compress (blocksize); 525 rc = compress_fd (0, 1);
257 else if (mode == m_decompress)
258 decompress ();
259 else 526 else
260 abort (); 527 rc = uncompress_fd (0, 1);
261 528
262 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);
263} 536}
537

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines