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