xref: /aosp_15_r20/external/zstd/zlibWrapper/examples/minigzip.c (revision 01826a4963a0d8a59bc3812d29bdf0fb76416722)
1*01826a49SYabin Cui /* minigzip.c contains minimal changes required to be compiled with zlibWrapper:
2*01826a49SYabin Cui  * - #include "zlib.h" was changed to #include "zstd_zlibwrapper.h"        */
3*01826a49SYabin Cui 
4*01826a49SYabin Cui /* minigzip.c -- simulate gzip using the zlib compression library
5*01826a49SYabin Cui  * Copyright (C) 1995-2006, 2010, 2011 Jean-loup Gailly.
6*01826a49SYabin Cui  * For conditions of distribution and use, see https://www.zlib.net/zlib_license.html
7*01826a49SYabin Cui  */
8*01826a49SYabin Cui 
9*01826a49SYabin Cui /*
10*01826a49SYabin Cui  * minigzip is a minimal implementation of the gzip utility. This is
11*01826a49SYabin Cui  * only an example of using zlib and isn't meant to replace the
12*01826a49SYabin Cui  * full-featured gzip. No attempt is made to deal with file systems
13*01826a49SYabin Cui  * limiting names to 14 or 8+3 characters, etc... Error checking is
14*01826a49SYabin Cui  * very limited. So use minigzip only for testing; use gzip for the
15*01826a49SYabin Cui  * real thing. On MSDOS, use only on file names without extension
16*01826a49SYabin Cui  * or in pipe mode.
17*01826a49SYabin Cui  */
18*01826a49SYabin Cui 
19*01826a49SYabin Cui /* @(#) $Id$ */
20*01826a49SYabin Cui 
21*01826a49SYabin Cui #define _POSIX_SOURCE /* fileno */
22*01826a49SYabin Cui 
23*01826a49SYabin Cui #include "zstd_zlibwrapper.h"
24*01826a49SYabin Cui #include <stdio.h>
25*01826a49SYabin Cui 
26*01826a49SYabin Cui #ifdef STDC
27*01826a49SYabin Cui #  include <string.h>
28*01826a49SYabin Cui #  include <stdlib.h>
29*01826a49SYabin Cui #endif
30*01826a49SYabin Cui 
31*01826a49SYabin Cui #ifdef USE_MMAP
32*01826a49SYabin Cui #  include <sys/types.h>
33*01826a49SYabin Cui #  include <sys/mman.h>
34*01826a49SYabin Cui #  include <sys/stat.h>
35*01826a49SYabin Cui #endif
36*01826a49SYabin Cui 
37*01826a49SYabin Cui #if defined(MSDOS) || defined(OS2) || defined(_WIN32) || defined(__CYGWIN__)
38*01826a49SYabin Cui #  include <fcntl.h>
39*01826a49SYabin Cui #  include <io.h>
40*01826a49SYabin Cui #  ifdef UNDER_CE
41*01826a49SYabin Cui #    include <stdlib.h>
42*01826a49SYabin Cui #  endif
43*01826a49SYabin Cui #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
44*01826a49SYabin Cui #else
45*01826a49SYabin Cui #  define SET_BINARY_MODE(file)
46*01826a49SYabin Cui #endif
47*01826a49SYabin Cui 
48*01826a49SYabin Cui #ifdef _MSC_VER
49*01826a49SYabin Cui #  define snprintf _snprintf
50*01826a49SYabin Cui #endif
51*01826a49SYabin Cui 
52*01826a49SYabin Cui #ifdef VMS
53*01826a49SYabin Cui #  define unlink delete
54*01826a49SYabin Cui #  define GZ_SUFFIX "-gz"
55*01826a49SYabin Cui #endif
56*01826a49SYabin Cui #ifdef RISCOS
57*01826a49SYabin Cui #  define unlink remove
58*01826a49SYabin Cui #  define GZ_SUFFIX "-gz"
59*01826a49SYabin Cui #  define fileno(file) file->__file
60*01826a49SYabin Cui #endif
61*01826a49SYabin Cui #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
62*01826a49SYabin Cui #  include <unix.h> /* for fileno */
63*01826a49SYabin Cui #endif
64*01826a49SYabin Cui 
65*01826a49SYabin Cui #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE)
66*01826a49SYabin Cui #ifndef _WIN32 /* unlink already in stdio.h for WIN32 */
67*01826a49SYabin Cui   extern int unlink _Z_OF((const char *));
68*01826a49SYabin Cui #endif
69*01826a49SYabin Cui #endif
70*01826a49SYabin Cui 
71*01826a49SYabin Cui #if defined(UNDER_CE)
72*01826a49SYabin Cui #  include <windows.h>
73*01826a49SYabin Cui #  define perror(s) pwinerror(s)
74*01826a49SYabin Cui 
75*01826a49SYabin Cui /* Map the Windows error number in ERROR to a locale-dependent error
76*01826a49SYabin Cui    message string and return a pointer to it.  Typically, the values
77*01826a49SYabin Cui    for ERROR come from GetLastError.
78*01826a49SYabin Cui 
79*01826a49SYabin Cui    The string pointed to shall not be modified by the application,
80*01826a49SYabin Cui    but may be overwritten by a subsequent call to strwinerror
81*01826a49SYabin Cui 
82*01826a49SYabin Cui    The strwinerror function does not change the current setting
83*01826a49SYabin Cui    of GetLastError.  */
84*01826a49SYabin Cui 
strwinerror(DWORD error)85*01826a49SYabin Cui static char *strwinerror(DWORD error)
86*01826a49SYabin Cui {
87*01826a49SYabin Cui     static char buf[1024];
88*01826a49SYabin Cui 
89*01826a49SYabin Cui     wchar_t *msgbuf;
90*01826a49SYabin Cui     DWORD lasterr = GetLastError();
91*01826a49SYabin Cui     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
92*01826a49SYabin Cui         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
93*01826a49SYabin Cui         NULL,
94*01826a49SYabin Cui         error,
95*01826a49SYabin Cui         0, /* Default language */
96*01826a49SYabin Cui         (LPVOID)&msgbuf,
97*01826a49SYabin Cui         0,
98*01826a49SYabin Cui         NULL);
99*01826a49SYabin Cui     if (chars != 0) {
100*01826a49SYabin Cui         /* If there is an \r\n appended, zap it.  */
101*01826a49SYabin Cui         if (chars >= 2
102*01826a49SYabin Cui             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
103*01826a49SYabin Cui             chars -= 2;
104*01826a49SYabin Cui             msgbuf[chars] = 0;
105*01826a49SYabin Cui         }
106*01826a49SYabin Cui 
107*01826a49SYabin Cui         if (chars > sizeof (buf) - 1) {
108*01826a49SYabin Cui             chars = sizeof (buf) - 1;
109*01826a49SYabin Cui             msgbuf[chars] = 0;
110*01826a49SYabin Cui         }
111*01826a49SYabin Cui 
112*01826a49SYabin Cui         wcstombs(buf, msgbuf, chars + 1);
113*01826a49SYabin Cui         LocalFree(msgbuf);
114*01826a49SYabin Cui     }
115*01826a49SYabin Cui     else {
116*01826a49SYabin Cui         sprintf(buf, "unknown win32 error (%ld)", error);
117*01826a49SYabin Cui     }
118*01826a49SYabin Cui 
119*01826a49SYabin Cui     SetLastError(lasterr);
120*01826a49SYabin Cui     return buf;
121*01826a49SYabin Cui }
122*01826a49SYabin Cui 
pwinerror(const char * s)123*01826a49SYabin Cui static void pwinerror (const char *s)
124*01826a49SYabin Cui {
125*01826a49SYabin Cui     if (s && *s)
126*01826a49SYabin Cui         fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
127*01826a49SYabin Cui     else
128*01826a49SYabin Cui         fprintf(stderr, "%s\n", strwinerror(GetLastError ()));
129*01826a49SYabin Cui }
130*01826a49SYabin Cui 
131*01826a49SYabin Cui #endif /* UNDER_CE */
132*01826a49SYabin Cui 
133*01826a49SYabin Cui #ifndef GZ_SUFFIX
134*01826a49SYabin Cui #  define GZ_SUFFIX ".gz"
135*01826a49SYabin Cui #endif
136*01826a49SYabin Cui #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
137*01826a49SYabin Cui 
138*01826a49SYabin Cui #define BUFLEN      16384
139*01826a49SYabin Cui #define MAX_NAME_LEN 1024
140*01826a49SYabin Cui 
141*01826a49SYabin Cui #ifdef MAXSEG_64K
142*01826a49SYabin Cui #  define local static
143*01826a49SYabin Cui    /* Needed for systems with limitation on stack size. */
144*01826a49SYabin Cui #else
145*01826a49SYabin Cui #  define local
146*01826a49SYabin Cui #endif
147*01826a49SYabin Cui 
148*01826a49SYabin Cui #ifdef Z_SOLO
149*01826a49SYabin Cui /* for Z_SOLO, create simplified gz* functions using deflate and inflate */
150*01826a49SYabin Cui 
151*01826a49SYabin Cui #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE)
152*01826a49SYabin Cui #  include <unistd.h>       /* for unlink() */
153*01826a49SYabin Cui #endif
154*01826a49SYabin Cui 
155*01826a49SYabin Cui void *myalloc _Z_OF((void *, unsigned, unsigned));
156*01826a49SYabin Cui void myfree _Z_OF((void *, void *));
157*01826a49SYabin Cui 
myalloc(q,n,m)158*01826a49SYabin Cui void *myalloc(q, n, m)
159*01826a49SYabin Cui     void *q;
160*01826a49SYabin Cui     unsigned n, m;
161*01826a49SYabin Cui {
162*01826a49SYabin Cui     q = Z_NULL;
163*01826a49SYabin Cui     return calloc(n, m);
164*01826a49SYabin Cui }
165*01826a49SYabin Cui 
myfree(q,p)166*01826a49SYabin Cui void myfree(q, p)
167*01826a49SYabin Cui     void *q, *p;
168*01826a49SYabin Cui {
169*01826a49SYabin Cui     q = Z_NULL;
170*01826a49SYabin Cui     free(p);
171*01826a49SYabin Cui }
172*01826a49SYabin Cui 
173*01826a49SYabin Cui typedef struct gzFile_s {
174*01826a49SYabin Cui     FILE *file;
175*01826a49SYabin Cui     int write;
176*01826a49SYabin Cui     int err;
177*01826a49SYabin Cui     char *msg;
178*01826a49SYabin Cui     z_stream strm;
179*01826a49SYabin Cui } *gzFile;
180*01826a49SYabin Cui 
181*01826a49SYabin Cui gzFile gzopen _Z_OF((const char *, const char *));
182*01826a49SYabin Cui gzFile gzdopen _Z_OF((int, const char *));
183*01826a49SYabin Cui gzFile gz_open _Z_OF((const char *, int, const char *));
184*01826a49SYabin Cui 
gzopen(path,mode)185*01826a49SYabin Cui gzFile gzopen(path, mode)
186*01826a49SYabin Cui const char *path;
187*01826a49SYabin Cui const char *mode;
188*01826a49SYabin Cui {
189*01826a49SYabin Cui     return gz_open(path, -1, mode);
190*01826a49SYabin Cui }
191*01826a49SYabin Cui 
gzdopen(fd,mode)192*01826a49SYabin Cui gzFile gzdopen(fd, mode)
193*01826a49SYabin Cui int fd;
194*01826a49SYabin Cui const char *mode;
195*01826a49SYabin Cui {
196*01826a49SYabin Cui     return gz_open(NULL, fd, mode);
197*01826a49SYabin Cui }
198*01826a49SYabin Cui 
gz_open(const char * path,int fd,const char * mode)199*01826a49SYabin Cui gzFile gz_open(const char *path, int fd, const char *mode) {
200*01826a49SYabin Cui     gzFile gz;
201*01826a49SYabin Cui     int ret;
202*01826a49SYabin Cui 
203*01826a49SYabin Cui     gz = malloc(sizeof(struct gzFile_s));
204*01826a49SYabin Cui     if (gz == NULL)
205*01826a49SYabin Cui         return NULL;
206*01826a49SYabin Cui     gz->write = strchr(mode, 'w') != NULL;
207*01826a49SYabin Cui     gz->strm.zalloc = myalloc;
208*01826a49SYabin Cui     gz->strm.zfree = myfree;
209*01826a49SYabin Cui     gz->strm.opaque = Z_NULL;
210*01826a49SYabin Cui     if (gz->write)
211*01826a49SYabin Cui         ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0);
212*01826a49SYabin Cui     else {
213*01826a49SYabin Cui         gz->strm.next_in = 0;
214*01826a49SYabin Cui         gz->strm.avail_in = Z_NULL;
215*01826a49SYabin Cui         ret = inflateInit2(&(gz->strm), 15 + 16);
216*01826a49SYabin Cui     }
217*01826a49SYabin Cui     if (ret != Z_OK) {
218*01826a49SYabin Cui         free(gz);
219*01826a49SYabin Cui         return NULL;
220*01826a49SYabin Cui     }
221*01826a49SYabin Cui     gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") :
222*01826a49SYabin Cui                               fopen(path, gz->write ? "wb" : "rb");
223*01826a49SYabin Cui     if (gz->file == NULL) {
224*01826a49SYabin Cui         gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm));
225*01826a49SYabin Cui         free(gz);
226*01826a49SYabin Cui         return NULL;
227*01826a49SYabin Cui     }
228*01826a49SYabin Cui     gz->err = 0;
229*01826a49SYabin Cui     gz->msg = "";
230*01826a49SYabin Cui     return gz;
231*01826a49SYabin Cui }
232*01826a49SYabin Cui 
233*01826a49SYabin Cui int gzwrite _Z_OF((gzFile, const void *, unsigned));
234*01826a49SYabin Cui 
gzwrite(gzFile gz,const void * buf,unsigned len)235*01826a49SYabin Cui int gzwrite(gzFile gz, const void *buf, unsigned len) {
236*01826a49SYabin Cui     z_stream *strm;
237*01826a49SYabin Cui     unsigned char out[BUFLEN];
238*01826a49SYabin Cui 
239*01826a49SYabin Cui     if (gz == NULL || !gz->write)
240*01826a49SYabin Cui         return 0;
241*01826a49SYabin Cui     strm = &(gz->strm);
242*01826a49SYabin Cui     strm->next_in = (void *)buf;
243*01826a49SYabin Cui     strm->avail_in = len;
244*01826a49SYabin Cui     do {
245*01826a49SYabin Cui         strm->next_out = out;
246*01826a49SYabin Cui         strm->avail_out = BUFLEN;
247*01826a49SYabin Cui         (void)deflate(strm, Z_NO_FLUSH);
248*01826a49SYabin Cui         fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
249*01826a49SYabin Cui     } while (strm->avail_out == 0);
250*01826a49SYabin Cui     return len;
251*01826a49SYabin Cui }
252*01826a49SYabin Cui 
253*01826a49SYabin Cui int gzread _Z_OF((gzFile, void *, unsigned));
254*01826a49SYabin Cui 
gzread(gzFile gz,void * buf,unsigned len)255*01826a49SYabin Cui int gzread(gzFile gz, void *buf, unsigned len) {
256*01826a49SYabin Cui     int ret;
257*01826a49SYabin Cui     unsigned got;
258*01826a49SYabin Cui     unsigned char in[1];
259*01826a49SYabin Cui     z_stream *strm;
260*01826a49SYabin Cui 
261*01826a49SYabin Cui     if (gz == NULL || gz->write)
262*01826a49SYabin Cui         return 0;
263*01826a49SYabin Cui     if (gz->err)
264*01826a49SYabin Cui         return 0;
265*01826a49SYabin Cui     strm = &(gz->strm);
266*01826a49SYabin Cui     strm->next_out = (void *)buf;
267*01826a49SYabin Cui     strm->avail_out = len;
268*01826a49SYabin Cui     do {
269*01826a49SYabin Cui         got = fread(in, 1, 1, gz->file);
270*01826a49SYabin Cui         if (got == 0)
271*01826a49SYabin Cui             break;
272*01826a49SYabin Cui         strm->next_in = in;
273*01826a49SYabin Cui         strm->avail_in = 1;
274*01826a49SYabin Cui         ret = inflate(strm, Z_NO_FLUSH);
275*01826a49SYabin Cui         if (ret == Z_DATA_ERROR) {
276*01826a49SYabin Cui             gz->err = Z_DATA_ERROR;
277*01826a49SYabin Cui             gz->msg = strm->msg;
278*01826a49SYabin Cui             return 0;
279*01826a49SYabin Cui         }
280*01826a49SYabin Cui         if (ret == Z_STREAM_END)
281*01826a49SYabin Cui             inflateReset(strm);
282*01826a49SYabin Cui     } while (strm->avail_out);
283*01826a49SYabin Cui     return len - strm->avail_out;
284*01826a49SYabin Cui }
285*01826a49SYabin Cui 
286*01826a49SYabin Cui int gzclose _Z_OF((gzFile));
287*01826a49SYabin Cui 
gzclose(gzFile gz)288*01826a49SYabin Cui int gzclose(gzFile gz) {
289*01826a49SYabin Cui     z_stream *strm;
290*01826a49SYabin Cui     unsigned char out[BUFLEN];
291*01826a49SYabin Cui 
292*01826a49SYabin Cui     if (gz == NULL)
293*01826a49SYabin Cui         return Z_STREAM_ERROR;
294*01826a49SYabin Cui     strm = &(gz->strm);
295*01826a49SYabin Cui     if (gz->write) {
296*01826a49SYabin Cui         strm->next_in = Z_NULL;
297*01826a49SYabin Cui         strm->avail_in = 0;
298*01826a49SYabin Cui         do {
299*01826a49SYabin Cui             strm->next_out = out;
300*01826a49SYabin Cui             strm->avail_out = BUFLEN;
301*01826a49SYabin Cui             (void)deflate(strm, Z_FINISH);
302*01826a49SYabin Cui             fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
303*01826a49SYabin Cui         } while (strm->avail_out == 0);
304*01826a49SYabin Cui         deflateEnd(strm);
305*01826a49SYabin Cui     }
306*01826a49SYabin Cui     else
307*01826a49SYabin Cui         inflateEnd(strm);
308*01826a49SYabin Cui     fclose(gz->file);
309*01826a49SYabin Cui     free(gz);
310*01826a49SYabin Cui     return Z_OK;
311*01826a49SYabin Cui }
312*01826a49SYabin Cui 
313*01826a49SYabin Cui const char *gzerror _Z_OF((gzFile, int *));
314*01826a49SYabin Cui 
gzerror(gzFile gz,int * err)315*01826a49SYabin Cui const char *gzerror(gzFile gz, int *err)
316*01826a49SYabin Cui {
317*01826a49SYabin Cui     *err = gz->err;
318*01826a49SYabin Cui     return gz->msg;
319*01826a49SYabin Cui }
320*01826a49SYabin Cui 
321*01826a49SYabin Cui #endif
322*01826a49SYabin Cui 
323*01826a49SYabin Cui char *prog;
324*01826a49SYabin Cui 
325*01826a49SYabin Cui void error            _Z_OF((const char *msg));
326*01826a49SYabin Cui void gz_compress      _Z_OF((FILE   *in, gzFile out));
327*01826a49SYabin Cui #ifdef USE_MMAP
328*01826a49SYabin Cui int  gz_compress_mmap _Z_OF((FILE   *in, gzFile out));
329*01826a49SYabin Cui #endif
330*01826a49SYabin Cui void gz_uncompress    _Z_OF((gzFile in, FILE   *out));
331*01826a49SYabin Cui void file_compress    _Z_OF((char  *file, char *mode));
332*01826a49SYabin Cui void file_uncompress  _Z_OF((char  *file));
333*01826a49SYabin Cui int  main             _Z_OF((int argc, char *argv[]));
334*01826a49SYabin Cui 
335*01826a49SYabin Cui /* ===========================================================================
336*01826a49SYabin Cui  * Display error message and exit
337*01826a49SYabin Cui  */
error(const char * msg)338*01826a49SYabin Cui void error(const char *msg)
339*01826a49SYabin Cui {
340*01826a49SYabin Cui     fprintf(stderr, "%s: %s\n", prog, msg);
341*01826a49SYabin Cui     exit(1);
342*01826a49SYabin Cui }
343*01826a49SYabin Cui 
344*01826a49SYabin Cui /* ===========================================================================
345*01826a49SYabin Cui  * Compress input to output then close both files.
346*01826a49SYabin Cui  */
347*01826a49SYabin Cui 
gz_compress(FILE * in,gzFile out)348*01826a49SYabin Cui void gz_compress(FILE *in, gzFile out)
349*01826a49SYabin Cui {
350*01826a49SYabin Cui     local char buf[BUFLEN];
351*01826a49SYabin Cui     int len;
352*01826a49SYabin Cui     int err;
353*01826a49SYabin Cui 
354*01826a49SYabin Cui #ifdef USE_MMAP
355*01826a49SYabin Cui     /* Try first compressing with mmap. If mmap fails (minigzip used in a
356*01826a49SYabin Cui      * pipe), use the normal fread loop.
357*01826a49SYabin Cui      */
358*01826a49SYabin Cui     if (gz_compress_mmap(in, out) == Z_OK) return;
359*01826a49SYabin Cui #endif
360*01826a49SYabin Cui     for (;;) {
361*01826a49SYabin Cui         len = (int)fread(buf, 1, sizeof(buf), in);
362*01826a49SYabin Cui         if (ferror(in)) {
363*01826a49SYabin Cui             perror("fread");
364*01826a49SYabin Cui             exit(1);
365*01826a49SYabin Cui         }
366*01826a49SYabin Cui         if (len == 0) break;
367*01826a49SYabin Cui 
368*01826a49SYabin Cui         if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
369*01826a49SYabin Cui     }
370*01826a49SYabin Cui     fclose(in);
371*01826a49SYabin Cui     if (gzclose(out) != Z_OK) error("failed gzclose");
372*01826a49SYabin Cui }
373*01826a49SYabin Cui 
374*01826a49SYabin Cui #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <[email protected]> */
375*01826a49SYabin Cui 
376*01826a49SYabin Cui /* Try compressing the input file at once using mmap. Return Z_OK if
377*01826a49SYabin Cui  * if success, Z_ERRNO otherwise.
378*01826a49SYabin Cui  */
gz_compress_mmap(FILE * in,gzFile out)379*01826a49SYabin Cui int gz_compress_mmap(FILE *in, gzFile out) {
380*01826a49SYabin Cui     int len;
381*01826a49SYabin Cui     int err;
382*01826a49SYabin Cui     int ifd = fileno(in);
383*01826a49SYabin Cui     caddr_t buf;    /* mmap'ed buffer for the entire input file */
384*01826a49SYabin Cui     off_t buf_len;  /* length of the input file */
385*01826a49SYabin Cui     struct stat sb;
386*01826a49SYabin Cui 
387*01826a49SYabin Cui     /* Determine the size of the file, needed for mmap: */
388*01826a49SYabin Cui     if (fstat(ifd, &sb) < 0) return Z_ERRNO;
389*01826a49SYabin Cui     buf_len = sb.st_size;
390*01826a49SYabin Cui     if (buf_len <= 0) return Z_ERRNO;
391*01826a49SYabin Cui 
392*01826a49SYabin Cui     /* Now do the actual mmap: */
393*01826a49SYabin Cui     buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
394*01826a49SYabin Cui     if (buf == (caddr_t)(-1)) return Z_ERRNO;
395*01826a49SYabin Cui 
396*01826a49SYabin Cui     /* Compress the whole file at once: */
397*01826a49SYabin Cui     len = gzwrite(out, (char *)buf, (unsigned)buf_len);
398*01826a49SYabin Cui 
399*01826a49SYabin Cui     if (len != (int)buf_len) error(gzerror(out, &err));
400*01826a49SYabin Cui 
401*01826a49SYabin Cui     munmap(buf, buf_len);
402*01826a49SYabin Cui     fclose(in);
403*01826a49SYabin Cui     if (gzclose(out) != Z_OK) error("failed gzclose");
404*01826a49SYabin Cui     return Z_OK;
405*01826a49SYabin Cui }
406*01826a49SYabin Cui #endif /* USE_MMAP */
407*01826a49SYabin Cui 
408*01826a49SYabin Cui /* ===========================================================================
409*01826a49SYabin Cui  * Uncompress input to output then close both files.
410*01826a49SYabin Cui  */
gz_uncompress(gzFile in,FILE * out)411*01826a49SYabin Cui void gz_uncompress(gzFile in, FILE *out) {
412*01826a49SYabin Cui     local char buf[BUFLEN];
413*01826a49SYabin Cui     int len;
414*01826a49SYabin Cui     int err;
415*01826a49SYabin Cui 
416*01826a49SYabin Cui     for (;;) {
417*01826a49SYabin Cui         len = gzread(in, buf, sizeof(buf));
418*01826a49SYabin Cui         if (len < 0) error (gzerror(in, &err));
419*01826a49SYabin Cui         if (len == 0) break;
420*01826a49SYabin Cui 
421*01826a49SYabin Cui         if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
422*01826a49SYabin Cui             error("failed fwrite");
423*01826a49SYabin Cui         }
424*01826a49SYabin Cui     }
425*01826a49SYabin Cui     if (fclose(out)) error("failed fclose");
426*01826a49SYabin Cui 
427*01826a49SYabin Cui     if (gzclose(in) != Z_OK) error("failed gzclose");
428*01826a49SYabin Cui }
429*01826a49SYabin Cui 
430*01826a49SYabin Cui 
431*01826a49SYabin Cui /* ===========================================================================
432*01826a49SYabin Cui  * Compress the given file: create a corresponding .gz file and remove the
433*01826a49SYabin Cui  * original.
434*01826a49SYabin Cui  */
file_compress(char * file,char * mode)435*01826a49SYabin Cui void file_compress(char *file, char *mode) {
436*01826a49SYabin Cui     local char outfile[MAX_NAME_LEN];
437*01826a49SYabin Cui     FILE  *in;
438*01826a49SYabin Cui     gzFile out;
439*01826a49SYabin Cui 
440*01826a49SYabin Cui     if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
441*01826a49SYabin Cui         fprintf(stderr, "%s: filename too long\n", prog);
442*01826a49SYabin Cui         exit(1);
443*01826a49SYabin Cui     }
444*01826a49SYabin Cui 
445*01826a49SYabin Cui     strcpy(outfile, file);
446*01826a49SYabin Cui     strcat(outfile, GZ_SUFFIX);
447*01826a49SYabin Cui 
448*01826a49SYabin Cui     in = fopen(file, "rb");
449*01826a49SYabin Cui     if (in == NULL) {
450*01826a49SYabin Cui         perror(file);
451*01826a49SYabin Cui         exit(1);
452*01826a49SYabin Cui     }
453*01826a49SYabin Cui     out = gzopen(outfile, mode);
454*01826a49SYabin Cui     if (out == NULL) {
455*01826a49SYabin Cui         fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
456*01826a49SYabin Cui         exit(1);
457*01826a49SYabin Cui     }
458*01826a49SYabin Cui     gz_compress(in, out);
459*01826a49SYabin Cui 
460*01826a49SYabin Cui     unlink(file);
461*01826a49SYabin Cui }
462*01826a49SYabin Cui 
463*01826a49SYabin Cui 
464*01826a49SYabin Cui /* ===========================================================================
465*01826a49SYabin Cui  * Uncompress the given file and remove the original.
466*01826a49SYabin Cui  */
file_uncompress(char * file)467*01826a49SYabin Cui void file_uncompress(char *file) {
468*01826a49SYabin Cui     local char buf[MAX_NAME_LEN];
469*01826a49SYabin Cui     char *infile, *outfile;
470*01826a49SYabin Cui     FILE  *out;
471*01826a49SYabin Cui     gzFile in;
472*01826a49SYabin Cui     size_t len = strlen(file);
473*01826a49SYabin Cui 
474*01826a49SYabin Cui     if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
475*01826a49SYabin Cui         fprintf(stderr, "%s: filename too long\n", prog);
476*01826a49SYabin Cui         exit(1);
477*01826a49SYabin Cui     }
478*01826a49SYabin Cui 
479*01826a49SYabin Cui     strcpy(buf, file);
480*01826a49SYabin Cui 
481*01826a49SYabin Cui     if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
482*01826a49SYabin Cui         infile = file;
483*01826a49SYabin Cui         outfile = buf;
484*01826a49SYabin Cui         outfile[len-3] = '\0';
485*01826a49SYabin Cui     } else {
486*01826a49SYabin Cui         outfile = file;
487*01826a49SYabin Cui         infile = buf;
488*01826a49SYabin Cui         strcat(infile, GZ_SUFFIX);
489*01826a49SYabin Cui     }
490*01826a49SYabin Cui     in = gzopen(infile, "rb");
491*01826a49SYabin Cui     if (in == NULL) {
492*01826a49SYabin Cui         fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
493*01826a49SYabin Cui         exit(1);
494*01826a49SYabin Cui     }
495*01826a49SYabin Cui     out = fopen(outfile, "wb");
496*01826a49SYabin Cui     if (out == NULL) {
497*01826a49SYabin Cui         perror(file);
498*01826a49SYabin Cui         exit(1);
499*01826a49SYabin Cui     }
500*01826a49SYabin Cui 
501*01826a49SYabin Cui     gz_uncompress(in, out);
502*01826a49SYabin Cui 
503*01826a49SYabin Cui     unlink(infile);
504*01826a49SYabin Cui }
505*01826a49SYabin Cui 
506*01826a49SYabin Cui 
507*01826a49SYabin Cui /* ===========================================================================
508*01826a49SYabin Cui  * Usage:  minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...]
509*01826a49SYabin Cui  *   -c : write to standard output
510*01826a49SYabin Cui  *   -d : decompress
511*01826a49SYabin Cui  *   -f : compress with Z_FILTERED
512*01826a49SYabin Cui  *   -h : compress with Z_HUFFMAN_ONLY
513*01826a49SYabin Cui  *   -r : compress with Z_RLE
514*01826a49SYabin Cui  *   -1 to -9 : compression level
515*01826a49SYabin Cui  */
516*01826a49SYabin Cui 
main(int argc,char * argv[])517*01826a49SYabin Cui int main(int argc, char *argv[]) {
518*01826a49SYabin Cui     int copyout = 0;
519*01826a49SYabin Cui     int uncompr = 0;
520*01826a49SYabin Cui     gzFile file;
521*01826a49SYabin Cui     char *bname, outmode[20];
522*01826a49SYabin Cui 
523*01826a49SYabin Cui     strcpy(outmode, "wb6 ");
524*01826a49SYabin Cui 
525*01826a49SYabin Cui     prog = argv[0];
526*01826a49SYabin Cui     bname = strrchr(argv[0], '/');
527*01826a49SYabin Cui     if (bname)
528*01826a49SYabin Cui       bname++;
529*01826a49SYabin Cui     else
530*01826a49SYabin Cui       bname = argv[0];
531*01826a49SYabin Cui     argc--, argv++;
532*01826a49SYabin Cui 
533*01826a49SYabin Cui     if (!strcmp(bname, "gunzip"))
534*01826a49SYabin Cui       uncompr = 1;
535*01826a49SYabin Cui     else if (!strcmp(bname, "zcat"))
536*01826a49SYabin Cui       copyout = uncompr = 1;
537*01826a49SYabin Cui 
538*01826a49SYabin Cui     while (argc > 0) {
539*01826a49SYabin Cui       if (strcmp(*argv, "-c") == 0)
540*01826a49SYabin Cui         copyout = 1;
541*01826a49SYabin Cui       else if (strcmp(*argv, "-d") == 0)
542*01826a49SYabin Cui         uncompr = 1;
543*01826a49SYabin Cui       else if (strcmp(*argv, "-f") == 0)
544*01826a49SYabin Cui         outmode[3] = 'f';
545*01826a49SYabin Cui       else if (strcmp(*argv, "-h") == 0)
546*01826a49SYabin Cui         outmode[3] = 'h';
547*01826a49SYabin Cui       else if (strcmp(*argv, "-r") == 0)
548*01826a49SYabin Cui         outmode[3] = 'R';
549*01826a49SYabin Cui       else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
550*01826a49SYabin Cui                (*argv)[2] == 0)
551*01826a49SYabin Cui         outmode[2] = (*argv)[1];
552*01826a49SYabin Cui       else
553*01826a49SYabin Cui         break;
554*01826a49SYabin Cui       argc--, argv++;
555*01826a49SYabin Cui     }
556*01826a49SYabin Cui     if (outmode[3] == ' ')
557*01826a49SYabin Cui         outmode[3] = 0;
558*01826a49SYabin Cui     if (argc == 0) {
559*01826a49SYabin Cui         SET_BINARY_MODE(stdin);
560*01826a49SYabin Cui         SET_BINARY_MODE(stdout);
561*01826a49SYabin Cui         if (uncompr) {
562*01826a49SYabin Cui             file = gzdopen(fileno(stdin), "rb");
563*01826a49SYabin Cui             if (file == NULL) error("can't gzdopen stdin");
564*01826a49SYabin Cui             gz_uncompress(file, stdout);
565*01826a49SYabin Cui         } else {
566*01826a49SYabin Cui             file = gzdopen(fileno(stdout), outmode);
567*01826a49SYabin Cui             if (file == NULL) error("can't gzdopen stdout");
568*01826a49SYabin Cui             gz_compress(stdin, file);
569*01826a49SYabin Cui         }
570*01826a49SYabin Cui     } else {
571*01826a49SYabin Cui         if (copyout) {
572*01826a49SYabin Cui             SET_BINARY_MODE(stdout);
573*01826a49SYabin Cui         }
574*01826a49SYabin Cui         do {
575*01826a49SYabin Cui             if (uncompr) {
576*01826a49SYabin Cui                 if (copyout) {
577*01826a49SYabin Cui                     file = gzopen(*argv, "rb");
578*01826a49SYabin Cui                     if (file == NULL)
579*01826a49SYabin Cui                         fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
580*01826a49SYabin Cui                     else
581*01826a49SYabin Cui                         gz_uncompress(file, stdout);
582*01826a49SYabin Cui                 } else {
583*01826a49SYabin Cui                     file_uncompress(*argv);
584*01826a49SYabin Cui                 }
585*01826a49SYabin Cui             } else {
586*01826a49SYabin Cui                 if (copyout) {
587*01826a49SYabin Cui                     FILE * in = fopen(*argv, "rb");
588*01826a49SYabin Cui 
589*01826a49SYabin Cui                     if (in == NULL) {
590*01826a49SYabin Cui                         perror(*argv);
591*01826a49SYabin Cui                     } else {
592*01826a49SYabin Cui                         file = gzdopen(fileno(stdout), outmode);
593*01826a49SYabin Cui                         if (file == NULL) error("can't gzdopen stdout");
594*01826a49SYabin Cui 
595*01826a49SYabin Cui                         gz_compress(in, file);
596*01826a49SYabin Cui                     }
597*01826a49SYabin Cui 
598*01826a49SYabin Cui                 } else {
599*01826a49SYabin Cui                     file_compress(*argv, outmode);
600*01826a49SYabin Cui                 }
601*01826a49SYabin Cui             }
602*01826a49SYabin Cui         } while (argv++, --argc);
603*01826a49SYabin Cui     }
604*01826a49SYabin Cui     return 0;
605*01826a49SYabin Cui }
606