3c197c37f7c23e467d43231032cc7506e0600917
[dragonfly.git] / lib / libz / minigzip.c
1 /* minigzip.c -- simulate gzip using the zlib compression library
2  * Copyright (C) 1995-2002 Jean-loup Gailly.
3  * For conditions of distribution and use, see copyright notice in zlib.h 
4  */
5
6 /*
7  * minigzip is a minimal implementation of the gzip utility. This is
8  * only an example of using zlib and isn't meant to replace the
9  * full-featured gzip. No attempt is made to deal with file systems
10  * limiting names to 14 or 8+3 characters, etc... Error checking is
11  * very limited. So use minigzip only for testing; use gzip for the
12  * real thing. On MSDOS, use only on file names without extension
13  * or in pipe mode.
14  *
15  * $FreeBSD: src/lib/libz/minigzip.c,v 1.6.2.4 2003/02/01 13:33:12 sobomax Exp $
16  * $DragonFly: src/lib/libz/Attic/minigzip.c,v 1.2 2003/06/17 04:26:52 dillon Exp $
17  */
18
19 #include <stdio.h>
20 #include "zlib.h"
21
22 #ifdef STDC
23 #  include <string.h>
24 #  include <stdlib.h>
25 #else
26    extern void exit  OF((int));
27 #endif
28
29 #ifdef USE_MMAP
30 #  include <sys/types.h>
31 #  include <sys/mman.h>
32 #  include <sys/stat.h>
33 #endif
34
35 #if defined(MSDOS) || defined(OS2) || defined(WIN32)
36 #  include <fcntl.h>
37 #  include <io.h>
38 #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
39 #else
40 #  define SET_BINARY_MODE(file)
41 #endif
42
43 #ifdef VMS
44 #  define unlink delete
45 #  define GZ_SUFFIX "-gz"
46 #endif
47 #ifdef RISCOS
48 #  define unlink remove
49 #  define GZ_SUFFIX "-gz"
50 #  define fileno(file) file->__file
51 #endif
52 #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
53 #  include <unix.h> /* for fileno */
54 #endif
55
56 #ifndef WIN32 /* unlink already in stdio.h for WIN32 */
57   extern int unlink OF((const char *));
58 #endif
59
60 #ifndef GZ_SUFFIX
61 #  define GZ_SUFFIX ".gz"
62 #endif
63 #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
64
65 #define BUFLEN      16384
66 #define MAX_NAME_LEN 1024
67
68 #ifdef MAXSEG_64K
69 #  define local static
70    /* Needed for systems with limitation on stack size. */
71 #else
72 #  define local
73 #endif
74
75 char *prog;
76
77 void error            OF((const char *msg));
78 void gz_compress      OF((FILE   *in, gzFile out));
79 #ifdef USE_MMAP
80 int  gz_compress_mmap OF((FILE   *in, gzFile out));
81 #endif
82 void gz_uncompress    OF((gzFile in, FILE   *out));
83 void file_compress    OF((char  *file, char *mode));
84 void file_uncompress  OF((char  *file));
85 int  main             OF((int argc, char *argv[]));
86
87 /* ===========================================================================
88  * Display error message and exit
89  */
90 void error(msg)
91     const char *msg;
92 {
93     fprintf(stderr, "%s: %s\n", prog, msg);
94     exit(1);
95 }
96
97 /* ===========================================================================
98  * Compress input to output then close both files.
99  */
100
101 void gz_compress(in, out)
102     FILE   *in;
103     gzFile out;
104 {
105     local char buf[BUFLEN];
106     int len;
107     int err;
108
109 #ifdef USE_MMAP
110     /* Try first compressing with mmap. If mmap fails (minigzip used in a
111      * pipe), use the normal fread loop.
112      */
113     if (gz_compress_mmap(in, out) == Z_OK) return;
114 #endif
115     for (;;) {
116         len = fread(buf, 1, sizeof(buf), in);
117         if (ferror(in)) {
118             perror("fread");
119             exit(1);
120         }
121         if (len == 0) break;
122
123         if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
124     }
125     fclose(in);
126     if (gzclose(out) != Z_OK) error("failed gzclose");
127 }
128
129 #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
130
131 /* Try compressing the input file at once using mmap. Return Z_OK if
132  * if success, Z_ERRNO otherwise.
133  */
134 int gz_compress_mmap(in, out)
135     FILE   *in;
136     gzFile out;
137 {
138     int len;
139     int err;
140     int ifd = fileno(in);
141     caddr_t buf;    /* mmap'ed buffer for the entire input file */
142     off_t buf_len;  /* length of the input file */
143     struct stat sb;
144
145     /* Determine the size of the file, needed for mmap: */
146     if (fstat(ifd, &sb) < 0) return Z_ERRNO;
147     buf_len = sb.st_size;
148     if (buf_len <= 0) return Z_ERRNO;
149
150     /* Now do the actual mmap: */
151     buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); 
152     if (buf == (caddr_t)(-1)) return Z_ERRNO;
153
154     /* Compress the whole file at once: */
155     len = gzwrite(out, (char *)buf, (unsigned)buf_len);
156
157     if (len != (int)buf_len) error(gzerror(out, &err));
158
159     munmap(buf, buf_len);
160     fclose(in);
161     if (gzclose(out) != Z_OK) error("failed gzclose");
162     return Z_OK;
163 }
164 #endif /* USE_MMAP */
165
166 /* ===========================================================================
167  * Uncompress input to output then close both files.
168  */
169 void gz_uncompress(in, out)
170     gzFile in;
171     FILE   *out;
172 {
173     local char buf[BUFLEN];
174     int len;
175     int err;
176
177     for (;;) {
178         len = gzread(in, buf, sizeof(buf));
179         if (len < 0) error (gzerror(in, &err));
180         if (len == 0) break;
181
182         if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
183             error("failed fwrite");
184         }
185     }
186     if (fclose(out)) error("failed fclose");
187
188     if (gzclose(in) != Z_OK) error("failed gzclose");
189 }
190
191
192 /* ===========================================================================
193  * Compress the given file: create a corresponding .gz file and remove the
194  * original.
195  */
196 void file_compress(file, mode)
197     char  *file;
198     char  *mode;
199 {
200     local char outfile[MAX_NAME_LEN];
201     FILE  *in;
202     gzFile out;
203
204     if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
205         fprintf(stderr, "%s: filename too long\n", prog);
206         exit(1);            
207     }
208     
209     strcpy(outfile, file);
210     strcat(outfile, GZ_SUFFIX);
211
212     in = fopen(file, "rb");
213     if (in == NULL) {
214         perror(file);
215         exit(1);
216     }
217     out = gzopen(outfile, mode);
218     if (out == NULL) {
219         fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
220         exit(1);
221     }
222     gz_compress(in, out);
223
224     unlink(file);
225 }
226
227
228 /* ===========================================================================
229  * Uncompress the given file and remove the original.
230  */
231 void file_uncompress(file)
232     char  *file;
233 {
234     local char buf[MAX_NAME_LEN];
235     char *infile, *outfile;
236     FILE  *out;
237     gzFile in;
238     size_t len = strlen(file);
239
240     if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
241         fprintf(stderr, "%s: filename too long\n", prog);
242         exit(1);            
243     }
244
245     strcpy(buf, file);
246
247     if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
248         infile = file;
249         outfile = buf;
250         outfile[len-3] = '\0';
251     } else {
252         outfile = file;
253         infile = buf;
254         strcat(infile, GZ_SUFFIX);
255     }
256     in = gzopen(infile, "rb");
257     if (in == NULL) {
258         fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
259         exit(1);
260     }
261     out = fopen(outfile, "wb");
262     if (out == NULL) {
263         perror(file);
264         exit(1);
265     }
266
267     gz_uncompress(in, out);
268
269     unlink(infile);
270 }
271
272
273 /* ===========================================================================
274  * Usage:  minigzip [-c ] [-d] [-f] [-h] [-1 to -9] [files...]
275  *   -c : write to standard output
276  *   -d : decompress
277  *   -f : compress with Z_FILTERED
278  *   -h : compress with Z_HUFFMAN_ONLY
279  *   -1 to -9 : compression level
280  */
281
282 int main(argc, argv)
283     int argc;
284     char *argv[];
285 {
286     int copyout = 0;
287     int uncompr = 0;
288     gzFile file;
289     char *bname, outmode[20];
290
291     strcpy(outmode, "wb6 ");
292
293     prog = argv[0];
294     bname = strrchr(argv[0], '/');
295     if (bname)
296       bname++;
297     else
298       bname = argv[0];
299     argc--, argv++;
300
301     if (!strcmp(bname, "gunzip"))
302       uncompr = 1;
303     else if (!strcmp(bname, "zcat"))
304       copyout = uncompr = 1;
305
306     while (argc > 0) {
307       if (strcmp(*argv, "-c") == 0)
308         copyout = 1;
309       else if (strcmp(*argv, "-d") == 0)
310         uncompr = 1;
311       else if (strcmp(*argv, "-f") == 0)
312         outmode[3] = 'f';
313       else if (strcmp(*argv, "-h") == 0)
314         outmode[3] = 'h';
315       else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
316                (*argv)[2] == 0)
317         outmode[2] = (*argv)[1];
318       else
319         break;
320       argc--, argv++;
321     }
322     if (argc == 0) {
323         SET_BINARY_MODE(stdin);
324         SET_BINARY_MODE(stdout);
325         if (uncompr) {
326             file = gzdopen(fileno(stdin), "rb");
327             if (file == NULL) error("can't gzdopen stdin");
328             gz_uncompress(file, stdout);
329         } else {
330             file = gzdopen(fileno(stdout), outmode);
331             if (file == NULL) error("can't gzdopen stdout");
332             gz_compress(stdin, file);
333         }
334     } else {
335         if (copyout) {
336             SET_BINARY_MODE(stdout);
337         }
338         do {
339             if (uncompr) {
340                 if (copyout) {
341                     file = gzopen(*argv, "rb");
342                     if (file == NULL)
343                         fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
344                     else
345                         gz_uncompress(file, stdout);
346                 } else {
347                     file_uncompress(*argv);
348                 }
349             } else {
350                 if (copyout) {
351                     FILE * in = fopen(*argv, "rb");
352
353                     if (in == NULL) {
354                         perror(*argv);
355                     } else {
356                         file = gzdopen(fileno(stdout), outmode);
357                         if (file == NULL) error("can't gzdopen stdout");
358
359                         gz_compress(in, file);
360                     }
361                 
362                 } else {
363                     file_compress(*argv, outmode);
364                 }
365             }
366         } while (argv++, --argc);
367     }
368     exit(0);
369     return 0; /* to avoid warning */
370 }