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