xref: /netbsd-src/external/gpl3/gdb/dist/zlib/minigzip.c (revision 924795e69c8bb3f17afd8fcbb799710cc1719dc4)
1212397c6Schristos /* minigzip.c -- simulate gzip using the zlib compression library
2212397c6Schristos  * Copyright (C) 1995-2006, 2010 Jean-loup Gailly.
3212397c6Schristos  * For conditions of distribution and use, see copyright notice in zlib.h
4212397c6Schristos  */
5212397c6Schristos 
6212397c6Schristos /*
7212397c6Schristos  * minigzip is a minimal implementation of the gzip utility. This is
8212397c6Schristos  * only an example of using zlib and isn't meant to replace the
9212397c6Schristos  * full-featured gzip. No attempt is made to deal with file systems
10212397c6Schristos  * limiting names to 14 or 8+3 characters, etc... Error checking is
11212397c6Schristos  * very limited. So use minigzip only for testing; use gzip for the
12212397c6Schristos  * real thing. On MSDOS, use only on file names without extension
13212397c6Schristos  * or in pipe mode.
14212397c6Schristos  */
15212397c6Schristos 
16*924795e6Schristos /* @(#) Id: minigzip.c,v 1.1.1.2 2002/03/11 21:53:26 tromey Exp  */
17212397c6Schristos 
18212397c6Schristos #include "zlib.h"
19212397c6Schristos #include <stdio.h>
20212397c6Schristos 
21212397c6Schristos #ifdef STDC
22212397c6Schristos #  include <string.h>
23212397c6Schristos #  include <stdlib.h>
24212397c6Schristos #endif
25212397c6Schristos 
26212397c6Schristos #ifdef USE_MMAP
27212397c6Schristos #  include <sys/types.h>
28212397c6Schristos #  include <sys/mman.h>
29212397c6Schristos #  include <sys/stat.h>
30212397c6Schristos #endif
31212397c6Schristos 
32212397c6Schristos #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
33212397c6Schristos #  include <fcntl.h>
34212397c6Schristos #  include <io.h>
35212397c6Schristos #  ifdef UNDER_CE
36212397c6Schristos #    include <stdlib.h>
37212397c6Schristos #  endif
38212397c6Schristos #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
39212397c6Schristos #else
40212397c6Schristos #  define SET_BINARY_MODE(file)
41212397c6Schristos #endif
42212397c6Schristos 
43212397c6Schristos #ifdef VMS
44212397c6Schristos #  define unlink delete
45212397c6Schristos #  define GZ_SUFFIX "-gz"
46212397c6Schristos #endif
47212397c6Schristos #ifdef RISCOS
48212397c6Schristos #  define unlink remove
49212397c6Schristos #  define GZ_SUFFIX "-gz"
50212397c6Schristos #  define fileno(file) file->__file
51212397c6Schristos #endif
52212397c6Schristos #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
53212397c6Schristos #  include <unix.h> /* for fileno */
54212397c6Schristos #endif
55212397c6Schristos 
56212397c6Schristos #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE)
57212397c6Schristos #ifndef WIN32 /* unlink already in stdio.h for WIN32 */
58212397c6Schristos   extern int unlink OF((const char *));
59212397c6Schristos #endif
60212397c6Schristos #endif
61212397c6Schristos 
62212397c6Schristos #if defined(UNDER_CE)
63212397c6Schristos #  include <windows.h>
64212397c6Schristos #  define perror(s) pwinerror(s)
65212397c6Schristos 
66212397c6Schristos /* Map the Windows error number in ERROR to a locale-dependent error
67212397c6Schristos    message string and return a pointer to it.  Typically, the values
68212397c6Schristos    for ERROR come from GetLastError.
69212397c6Schristos 
70212397c6Schristos    The string pointed to shall not be modified by the application,
71212397c6Schristos    but may be overwritten by a subsequent call to strwinerror
72212397c6Schristos 
73212397c6Schristos    The strwinerror function does not change the current setting
74212397c6Schristos    of GetLastError.  */
75212397c6Schristos 
strwinerror(error)76212397c6Schristos static char *strwinerror (error)
77212397c6Schristos      DWORD error;
78212397c6Schristos {
79212397c6Schristos     static char buf[1024];
80212397c6Schristos 
81212397c6Schristos     wchar_t *msgbuf;
82212397c6Schristos     DWORD lasterr = GetLastError();
83212397c6Schristos     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
84212397c6Schristos         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
85212397c6Schristos         NULL,
86212397c6Schristos         error,
87212397c6Schristos         0, /* Default language */
88212397c6Schristos         (LPVOID)&msgbuf,
89212397c6Schristos         0,
90212397c6Schristos         NULL);
91212397c6Schristos     if (chars != 0) {
92212397c6Schristos         /* If there is an \r\n appended, zap it.  */
93212397c6Schristos         if (chars >= 2
94212397c6Schristos             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
95212397c6Schristos             chars -= 2;
96212397c6Schristos             msgbuf[chars] = 0;
97212397c6Schristos         }
98212397c6Schristos 
99212397c6Schristos         if (chars > sizeof (buf) - 1) {
100212397c6Schristos             chars = sizeof (buf) - 1;
101212397c6Schristos             msgbuf[chars] = 0;
102212397c6Schristos         }
103212397c6Schristos 
104212397c6Schristos         wcstombs(buf, msgbuf, chars + 1);
105212397c6Schristos         LocalFree(msgbuf);
106212397c6Schristos     }
107212397c6Schristos     else {
108212397c6Schristos         sprintf(buf, "unknown win32 error (%ld)", error);
109212397c6Schristos     }
110212397c6Schristos 
111212397c6Schristos     SetLastError(lasterr);
112212397c6Schristos     return buf;
113212397c6Schristos }
114212397c6Schristos 
pwinerror(s)115212397c6Schristos static void pwinerror (s)
116212397c6Schristos     const char *s;
117212397c6Schristos {
118212397c6Schristos     if (s && *s)
119212397c6Schristos         fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
120212397c6Schristos     else
121212397c6Schristos         fprintf(stderr, "%s\n", strwinerror(GetLastError ()));
122212397c6Schristos }
123212397c6Schristos 
124212397c6Schristos #endif /* UNDER_CE */
125212397c6Schristos 
126212397c6Schristos #ifndef GZ_SUFFIX
127212397c6Schristos #  define GZ_SUFFIX ".gz"
128212397c6Schristos #endif
129212397c6Schristos #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
130212397c6Schristos 
131212397c6Schristos #define BUFLEN      16384
132212397c6Schristos #define MAX_NAME_LEN 1024
133212397c6Schristos 
134212397c6Schristos #ifdef MAXSEG_64K
135212397c6Schristos #  define local static
136212397c6Schristos    /* Needed for systems with limitation on stack size. */
137212397c6Schristos #else
138212397c6Schristos #  define local
139212397c6Schristos #endif
140212397c6Schristos 
141212397c6Schristos char *prog;
142212397c6Schristos 
143212397c6Schristos void error            OF((const char *msg));
144212397c6Schristos void gz_compress      OF((FILE   *in, gzFile out));
145212397c6Schristos #ifdef USE_MMAP
146212397c6Schristos int  gz_compress_mmap OF((FILE   *in, gzFile out));
147212397c6Schristos #endif
148212397c6Schristos void gz_uncompress    OF((gzFile in, FILE   *out));
149212397c6Schristos void file_compress    OF((char  *file, char *mode));
150212397c6Schristos void file_uncompress  OF((char  *file));
151212397c6Schristos int  main             OF((int argc, char *argv[]));
152212397c6Schristos 
153212397c6Schristos /* ===========================================================================
154212397c6Schristos  * Display error message and exit
155212397c6Schristos  */
error(msg)156212397c6Schristos void error(msg)
157212397c6Schristos     const char *msg;
158212397c6Schristos {
159212397c6Schristos     fprintf(stderr, "%s: %s\n", prog, msg);
160212397c6Schristos     exit(1);
161212397c6Schristos }
162212397c6Schristos 
163212397c6Schristos /* ===========================================================================
164212397c6Schristos  * Compress input to output then close both files.
165212397c6Schristos  */
166212397c6Schristos 
gz_compress(in,out)167212397c6Schristos void gz_compress(in, out)
168212397c6Schristos     FILE   *in;
169212397c6Schristos     gzFile out;
170212397c6Schristos {
171212397c6Schristos     local char buf[BUFLEN];
172212397c6Schristos     int len;
173212397c6Schristos     int err;
174212397c6Schristos 
175212397c6Schristos #ifdef USE_MMAP
176212397c6Schristos     /* Try first compressing with mmap. If mmap fails (minigzip used in a
177212397c6Schristos      * pipe), use the normal fread loop.
178212397c6Schristos      */
179212397c6Schristos     if (gz_compress_mmap(in, out) == Z_OK) return;
180212397c6Schristos #endif
181212397c6Schristos     for (;;) {
182212397c6Schristos         len = (int)fread(buf, 1, sizeof(buf), in);
183212397c6Schristos         if (ferror(in)) {
184212397c6Schristos             perror("fread");
185212397c6Schristos             exit(1);
186212397c6Schristos         }
187212397c6Schristos         if (len == 0) break;
188212397c6Schristos 
189212397c6Schristos         if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
190212397c6Schristos     }
191212397c6Schristos     fclose(in);
192212397c6Schristos     if (gzclose(out) != Z_OK) error("failed gzclose");
193212397c6Schristos }
194212397c6Schristos 
195212397c6Schristos #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
196212397c6Schristos 
197212397c6Schristos /* Try compressing the input file at once using mmap. Return Z_OK if
198212397c6Schristos  * if success, Z_ERRNO otherwise.
199212397c6Schristos  */
gz_compress_mmap(in,out)200212397c6Schristos int gz_compress_mmap(in, out)
201212397c6Schristos     FILE   *in;
202212397c6Schristos     gzFile out;
203212397c6Schristos {
204212397c6Schristos     int len;
205212397c6Schristos     int err;
206212397c6Schristos     int ifd = fileno(in);
207212397c6Schristos     caddr_t buf;    /* mmap'ed buffer for the entire input file */
208212397c6Schristos     off_t buf_len;  /* length of the input file */
209212397c6Schristos     struct stat sb;
210212397c6Schristos 
211212397c6Schristos     /* Determine the size of the file, needed for mmap: */
212212397c6Schristos     if (fstat(ifd, &sb) < 0) return Z_ERRNO;
213212397c6Schristos     buf_len = sb.st_size;
214212397c6Schristos     if (buf_len <= 0) return Z_ERRNO;
215212397c6Schristos 
216212397c6Schristos     /* Now do the actual mmap: */
217212397c6Schristos     buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
218212397c6Schristos     if (buf == (caddr_t)(-1)) return Z_ERRNO;
219212397c6Schristos 
220212397c6Schristos     /* Compress the whole file at once: */
221212397c6Schristos     len = gzwrite(out, (char *)buf, (unsigned)buf_len);
222212397c6Schristos 
223212397c6Schristos     if (len != (int)buf_len) error(gzerror(out, &err));
224212397c6Schristos 
225212397c6Schristos     munmap(buf, buf_len);
226212397c6Schristos     fclose(in);
227212397c6Schristos     if (gzclose(out) != Z_OK) error("failed gzclose");
228212397c6Schristos     return Z_OK;
229212397c6Schristos }
230212397c6Schristos #endif /* USE_MMAP */
231212397c6Schristos 
232212397c6Schristos /* ===========================================================================
233212397c6Schristos  * Uncompress input to output then close both files.
234212397c6Schristos  */
gz_uncompress(in,out)235212397c6Schristos void gz_uncompress(in, out)
236212397c6Schristos     gzFile in;
237212397c6Schristos     FILE   *out;
238212397c6Schristos {
239212397c6Schristos     local char buf[BUFLEN];
240212397c6Schristos     int len;
241212397c6Schristos     int err;
242212397c6Schristos 
243212397c6Schristos     for (;;) {
244212397c6Schristos         len = gzread(in, buf, sizeof(buf));
245212397c6Schristos         if (len < 0) error (gzerror(in, &err));
246212397c6Schristos         if (len == 0) break;
247212397c6Schristos 
248212397c6Schristos         if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
249212397c6Schristos             error("failed fwrite");
250212397c6Schristos         }
251212397c6Schristos     }
252212397c6Schristos     if (fclose(out)) error("failed fclose");
253212397c6Schristos 
254212397c6Schristos     if (gzclose(in) != Z_OK) error("failed gzclose");
255212397c6Schristos }
256212397c6Schristos 
257212397c6Schristos 
258212397c6Schristos /* ===========================================================================
259212397c6Schristos  * Compress the given file: create a corresponding .gz file and remove the
260212397c6Schristos  * original.
261212397c6Schristos  */
file_compress(file,mode)262212397c6Schristos void file_compress(file, mode)
263212397c6Schristos     char  *file;
264212397c6Schristos     char  *mode;
265212397c6Schristos {
266212397c6Schristos     local char outfile[MAX_NAME_LEN];
267212397c6Schristos     FILE  *in;
268212397c6Schristos     gzFile out;
269212397c6Schristos 
270212397c6Schristos     if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
271212397c6Schristos         fprintf(stderr, "%s: filename too long\n", prog);
272212397c6Schristos         exit(1);
273212397c6Schristos     }
274212397c6Schristos 
275212397c6Schristos     strcpy(outfile, file);
276212397c6Schristos     strcat(outfile, GZ_SUFFIX);
277212397c6Schristos 
278212397c6Schristos     in = fopen(file, "rb");
279212397c6Schristos     if (in == NULL) {
280212397c6Schristos         perror(file);
281212397c6Schristos         exit(1);
282212397c6Schristos     }
283212397c6Schristos     out = gzopen(outfile, mode);
284212397c6Schristos     if (out == NULL) {
285212397c6Schristos         fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
286212397c6Schristos         exit(1);
287212397c6Schristos     }
288212397c6Schristos     gz_compress(in, out);
289212397c6Schristos 
290212397c6Schristos     unlink(file);
291212397c6Schristos }
292212397c6Schristos 
293212397c6Schristos 
294212397c6Schristos /* ===========================================================================
295212397c6Schristos  * Uncompress the given file and remove the original.
296212397c6Schristos  */
file_uncompress(file)297212397c6Schristos void file_uncompress(file)
298212397c6Schristos     char  *file;
299212397c6Schristos {
300212397c6Schristos     local char buf[MAX_NAME_LEN];
301212397c6Schristos     char *infile, *outfile;
302212397c6Schristos     FILE  *out;
303212397c6Schristos     gzFile in;
304212397c6Schristos     size_t len = strlen(file);
305212397c6Schristos 
306212397c6Schristos     if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
307212397c6Schristos         fprintf(stderr, "%s: filename too long\n", prog);
308212397c6Schristos         exit(1);
309212397c6Schristos     }
310212397c6Schristos 
311212397c6Schristos     strcpy(buf, file);
312212397c6Schristos 
313212397c6Schristos     if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
314212397c6Schristos         infile = file;
315212397c6Schristos         outfile = buf;
316212397c6Schristos         outfile[len-3] = '\0';
317212397c6Schristos     } else {
318212397c6Schristos         outfile = file;
319212397c6Schristos         infile = buf;
320212397c6Schristos         strcat(infile, GZ_SUFFIX);
321212397c6Schristos     }
322212397c6Schristos     in = gzopen(infile, "rb");
323212397c6Schristos     if (in == NULL) {
324212397c6Schristos         fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
325212397c6Schristos         exit(1);
326212397c6Schristos     }
327212397c6Schristos     out = fopen(outfile, "wb");
328212397c6Schristos     if (out == NULL) {
329212397c6Schristos         perror(file);
330212397c6Schristos         exit(1);
331212397c6Schristos     }
332212397c6Schristos 
333212397c6Schristos     gz_uncompress(in, out);
334212397c6Schristos 
335212397c6Schristos     unlink(infile);
336212397c6Schristos }
337212397c6Schristos 
338212397c6Schristos 
339212397c6Schristos /* ===========================================================================
340212397c6Schristos  * Usage:  minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...]
341212397c6Schristos  *   -c : write to standard output
342212397c6Schristos  *   -d : decompress
343212397c6Schristos  *   -f : compress with Z_FILTERED
344212397c6Schristos  *   -h : compress with Z_HUFFMAN_ONLY
345212397c6Schristos  *   -r : compress with Z_RLE
346212397c6Schristos  *   -1 to -9 : compression level
347212397c6Schristos  */
348212397c6Schristos 
main(argc,argv)349212397c6Schristos int main(argc, argv)
350212397c6Schristos     int argc;
351212397c6Schristos     char *argv[];
352212397c6Schristos {
353212397c6Schristos     int copyout = 0;
354212397c6Schristos     int uncompr = 0;
355212397c6Schristos     gzFile file;
356212397c6Schristos     char *bname, outmode[20];
357212397c6Schristos 
358212397c6Schristos     strcpy(outmode, "wb6 ");
359212397c6Schristos 
360212397c6Schristos     prog = argv[0];
361212397c6Schristos     bname = strrchr(argv[0], '/');
362212397c6Schristos     if (bname)
363212397c6Schristos       bname++;
364212397c6Schristos     else
365212397c6Schristos       bname = argv[0];
366212397c6Schristos     argc--, argv++;
367212397c6Schristos 
368212397c6Schristos     if (!strcmp(bname, "gunzip"))
369212397c6Schristos       uncompr = 1;
370212397c6Schristos     else if (!strcmp(bname, "zcat"))
371212397c6Schristos       copyout = uncompr = 1;
372212397c6Schristos 
373212397c6Schristos     while (argc > 0) {
374212397c6Schristos       if (strcmp(*argv, "-c") == 0)
375212397c6Schristos         copyout = 1;
376212397c6Schristos       else if (strcmp(*argv, "-d") == 0)
377212397c6Schristos         uncompr = 1;
378212397c6Schristos       else if (strcmp(*argv, "-f") == 0)
379212397c6Schristos         outmode[3] = 'f';
380212397c6Schristos       else if (strcmp(*argv, "-h") == 0)
381212397c6Schristos         outmode[3] = 'h';
382212397c6Schristos       else if (strcmp(*argv, "-r") == 0)
383212397c6Schristos         outmode[3] = 'R';
384212397c6Schristos       else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
385212397c6Schristos                (*argv)[2] == 0)
386212397c6Schristos         outmode[2] = (*argv)[1];
387212397c6Schristos       else
388212397c6Schristos         break;
389212397c6Schristos       argc--, argv++;
390212397c6Schristos     }
391212397c6Schristos     if (outmode[3] == ' ')
392212397c6Schristos         outmode[3] = 0;
393212397c6Schristos     if (argc == 0) {
394212397c6Schristos         SET_BINARY_MODE(stdin);
395212397c6Schristos         SET_BINARY_MODE(stdout);
396212397c6Schristos         if (uncompr) {
397212397c6Schristos             file = gzdopen(fileno(stdin), "rb");
398212397c6Schristos             if (file == NULL) error("can't gzdopen stdin");
399212397c6Schristos             gz_uncompress(file, stdout);
400212397c6Schristos         } else {
401212397c6Schristos             file = gzdopen(fileno(stdout), outmode);
402212397c6Schristos             if (file == NULL) error("can't gzdopen stdout");
403212397c6Schristos             gz_compress(stdin, file);
404212397c6Schristos         }
405212397c6Schristos     } else {
406212397c6Schristos         if (copyout) {
407212397c6Schristos             SET_BINARY_MODE(stdout);
408212397c6Schristos         }
409212397c6Schristos         do {
410212397c6Schristos             if (uncompr) {
411212397c6Schristos                 if (copyout) {
412212397c6Schristos                     file = gzopen(*argv, "rb");
413212397c6Schristos                     if (file == NULL)
414212397c6Schristos                         fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
415212397c6Schristos                     else
416212397c6Schristos                         gz_uncompress(file, stdout);
417212397c6Schristos                 } else {
418212397c6Schristos                     file_uncompress(*argv);
419212397c6Schristos                 }
420212397c6Schristos             } else {
421212397c6Schristos                 if (copyout) {
422212397c6Schristos                     FILE * in = fopen(*argv, "rb");
423212397c6Schristos 
424212397c6Schristos                     if (in == NULL) {
425212397c6Schristos                         perror(*argv);
426212397c6Schristos                     } else {
427212397c6Schristos                         file = gzdopen(fileno(stdout), outmode);
428212397c6Schristos                         if (file == NULL) error("can't gzdopen stdout");
429212397c6Schristos 
430212397c6Schristos                         gz_compress(in, file);
431212397c6Schristos                     }
432212397c6Schristos 
433212397c6Schristos                 } else {
434212397c6Schristos                     file_compress(*argv, outmode);
435212397c6Schristos                 }
436212397c6Schristos             }
437212397c6Schristos         } while (argv++, --argc);
438212397c6Schristos     }
439212397c6Schristos     return 0;
440212397c6Schristos }
441