xref: /netbsd-src/external/gpl3/binutils.old/dist/zlib/minigzip.c (revision ede781334f5dc56e6b74c3945d364b5b98850996)
175fd0b74Schristos /* minigzip.c -- simulate gzip using the zlib compression library
275fd0b74Schristos  * Copyright (C) 1995-2006, 2010 Jean-loup Gailly.
375fd0b74Schristos  * For conditions of distribution and use, see copyright notice in zlib.h
475fd0b74Schristos  */
575fd0b74Schristos 
675fd0b74Schristos /*
775fd0b74Schristos  * minigzip is a minimal implementation of the gzip utility. This is
875fd0b74Schristos  * only an example of using zlib and isn't meant to replace the
975fd0b74Schristos  * full-featured gzip. No attempt is made to deal with file systems
1075fd0b74Schristos  * limiting names to 14 or 8+3 characters, etc... Error checking is
1175fd0b74Schristos  * very limited. So use minigzip only for testing; use gzip for the
1275fd0b74Schristos  * real thing. On MSDOS, use only on file names without extension
1375fd0b74Schristos  * or in pipe mode.
1475fd0b74Schristos  */
1575fd0b74Schristos 
16*ede78133Schristos /* @(#) Id: minigzip.c,v 1.1.1.2 2002/03/11 21:53:26 tromey Exp  */
1775fd0b74Schristos 
1875fd0b74Schristos #include "zlib.h"
1975fd0b74Schristos #include <stdio.h>
2075fd0b74Schristos 
2175fd0b74Schristos #ifdef STDC
2275fd0b74Schristos #  include <string.h>
2375fd0b74Schristos #  include <stdlib.h>
2475fd0b74Schristos #endif
2575fd0b74Schristos 
2675fd0b74Schristos #ifdef USE_MMAP
2775fd0b74Schristos #  include <sys/types.h>
2875fd0b74Schristos #  include <sys/mman.h>
2975fd0b74Schristos #  include <sys/stat.h>
3075fd0b74Schristos #endif
3175fd0b74Schristos 
3275fd0b74Schristos #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
3375fd0b74Schristos #  include <fcntl.h>
3475fd0b74Schristos #  include <io.h>
3575fd0b74Schristos #  ifdef UNDER_CE
3675fd0b74Schristos #    include <stdlib.h>
3775fd0b74Schristos #  endif
3875fd0b74Schristos #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
3975fd0b74Schristos #else
4075fd0b74Schristos #  define SET_BINARY_MODE(file)
4175fd0b74Schristos #endif
4275fd0b74Schristos 
4375fd0b74Schristos #ifdef VMS
4475fd0b74Schristos #  define unlink delete
4575fd0b74Schristos #  define GZ_SUFFIX "-gz"
4675fd0b74Schristos #endif
4775fd0b74Schristos #ifdef RISCOS
4875fd0b74Schristos #  define unlink remove
4975fd0b74Schristos #  define GZ_SUFFIX "-gz"
5075fd0b74Schristos #  define fileno(file) file->__file
5175fd0b74Schristos #endif
5275fd0b74Schristos #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
5375fd0b74Schristos #  include <unix.h> /* for fileno */
5475fd0b74Schristos #endif
5575fd0b74Schristos 
5675fd0b74Schristos #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE)
5775fd0b74Schristos #ifndef WIN32 /* unlink already in stdio.h for WIN32 */
5875fd0b74Schristos   extern int unlink OF((const char *));
5975fd0b74Schristos #endif
6075fd0b74Schristos #endif
6175fd0b74Schristos 
6275fd0b74Schristos #if defined(UNDER_CE)
6375fd0b74Schristos #  include <windows.h>
6475fd0b74Schristos #  define perror(s) pwinerror(s)
6575fd0b74Schristos 
6675fd0b74Schristos /* Map the Windows error number in ERROR to a locale-dependent error
6775fd0b74Schristos    message string and return a pointer to it.  Typically, the values
6875fd0b74Schristos    for ERROR come from GetLastError.
6975fd0b74Schristos 
7075fd0b74Schristos    The string pointed to shall not be modified by the application,
7175fd0b74Schristos    but may be overwritten by a subsequent call to strwinerror
7275fd0b74Schristos 
7375fd0b74Schristos    The strwinerror function does not change the current setting
7475fd0b74Schristos    of GetLastError.  */
7575fd0b74Schristos 
strwinerror(error)7675fd0b74Schristos static char *strwinerror (error)
7775fd0b74Schristos      DWORD error;
7875fd0b74Schristos {
7975fd0b74Schristos     static char buf[1024];
8075fd0b74Schristos 
8175fd0b74Schristos     wchar_t *msgbuf;
8275fd0b74Schristos     DWORD lasterr = GetLastError();
8375fd0b74Schristos     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
8475fd0b74Schristos         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
8575fd0b74Schristos         NULL,
8675fd0b74Schristos         error,
8775fd0b74Schristos         0, /* Default language */
8875fd0b74Schristos         (LPVOID)&msgbuf,
8975fd0b74Schristos         0,
9075fd0b74Schristos         NULL);
9175fd0b74Schristos     if (chars != 0) {
9275fd0b74Schristos         /* If there is an \r\n appended, zap it.  */
9375fd0b74Schristos         if (chars >= 2
9475fd0b74Schristos             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
9575fd0b74Schristos             chars -= 2;
9675fd0b74Schristos             msgbuf[chars] = 0;
9775fd0b74Schristos         }
9875fd0b74Schristos 
9975fd0b74Schristos         if (chars > sizeof (buf) - 1) {
10075fd0b74Schristos             chars = sizeof (buf) - 1;
10175fd0b74Schristos             msgbuf[chars] = 0;
10275fd0b74Schristos         }
10375fd0b74Schristos 
10475fd0b74Schristos         wcstombs(buf, msgbuf, chars + 1);
10575fd0b74Schristos         LocalFree(msgbuf);
10675fd0b74Schristos     }
10775fd0b74Schristos     else {
10875fd0b74Schristos         sprintf(buf, "unknown win32 error (%ld)", error);
10975fd0b74Schristos     }
11075fd0b74Schristos 
11175fd0b74Schristos     SetLastError(lasterr);
11275fd0b74Schristos     return buf;
11375fd0b74Schristos }
11475fd0b74Schristos 
pwinerror(s)11575fd0b74Schristos static void pwinerror (s)
11675fd0b74Schristos     const char *s;
11775fd0b74Schristos {
11875fd0b74Schristos     if (s && *s)
11975fd0b74Schristos         fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
12075fd0b74Schristos     else
12175fd0b74Schristos         fprintf(stderr, "%s\n", strwinerror(GetLastError ()));
12275fd0b74Schristos }
12375fd0b74Schristos 
12475fd0b74Schristos #endif /* UNDER_CE */
12575fd0b74Schristos 
12675fd0b74Schristos #ifndef GZ_SUFFIX
12775fd0b74Schristos #  define GZ_SUFFIX ".gz"
12875fd0b74Schristos #endif
12975fd0b74Schristos #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
13075fd0b74Schristos 
13175fd0b74Schristos #define BUFLEN      16384
13275fd0b74Schristos #define MAX_NAME_LEN 1024
13375fd0b74Schristos 
13475fd0b74Schristos #ifdef MAXSEG_64K
13575fd0b74Schristos #  define local static
13675fd0b74Schristos    /* Needed for systems with limitation on stack size. */
13775fd0b74Schristos #else
13875fd0b74Schristos #  define local
13975fd0b74Schristos #endif
14075fd0b74Schristos 
14175fd0b74Schristos char *prog;
14275fd0b74Schristos 
14375fd0b74Schristos void error            OF((const char *msg));
14475fd0b74Schristos void gz_compress      OF((FILE   *in, gzFile out));
14575fd0b74Schristos #ifdef USE_MMAP
14675fd0b74Schristos int  gz_compress_mmap OF((FILE   *in, gzFile out));
14775fd0b74Schristos #endif
14875fd0b74Schristos void gz_uncompress    OF((gzFile in, FILE   *out));
14975fd0b74Schristos void file_compress    OF((char  *file, char *mode));
15075fd0b74Schristos void file_uncompress  OF((char  *file));
15175fd0b74Schristos int  main             OF((int argc, char *argv[]));
15275fd0b74Schristos 
15375fd0b74Schristos /* ===========================================================================
15475fd0b74Schristos  * Display error message and exit
15575fd0b74Schristos  */
error(msg)15675fd0b74Schristos void error(msg)
15775fd0b74Schristos     const char *msg;
15875fd0b74Schristos {
15975fd0b74Schristos     fprintf(stderr, "%s: %s\n", prog, msg);
16075fd0b74Schristos     exit(1);
16175fd0b74Schristos }
16275fd0b74Schristos 
16375fd0b74Schristos /* ===========================================================================
16475fd0b74Schristos  * Compress input to output then close both files.
16575fd0b74Schristos  */
16675fd0b74Schristos 
gz_compress(in,out)16775fd0b74Schristos void gz_compress(in, out)
16875fd0b74Schristos     FILE   *in;
16975fd0b74Schristos     gzFile out;
17075fd0b74Schristos {
17175fd0b74Schristos     local char buf[BUFLEN];
17275fd0b74Schristos     int len;
17375fd0b74Schristos     int err;
17475fd0b74Schristos 
17575fd0b74Schristos #ifdef USE_MMAP
17675fd0b74Schristos     /* Try first compressing with mmap. If mmap fails (minigzip used in a
17775fd0b74Schristos      * pipe), use the normal fread loop.
17875fd0b74Schristos      */
17975fd0b74Schristos     if (gz_compress_mmap(in, out) == Z_OK) return;
18075fd0b74Schristos #endif
18175fd0b74Schristos     for (;;) {
18275fd0b74Schristos         len = (int)fread(buf, 1, sizeof(buf), in);
18375fd0b74Schristos         if (ferror(in)) {
18475fd0b74Schristos             perror("fread");
18575fd0b74Schristos             exit(1);
18675fd0b74Schristos         }
18775fd0b74Schristos         if (len == 0) break;
18875fd0b74Schristos 
18975fd0b74Schristos         if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
19075fd0b74Schristos     }
19175fd0b74Schristos     fclose(in);
19275fd0b74Schristos     if (gzclose(out) != Z_OK) error("failed gzclose");
19375fd0b74Schristos }
19475fd0b74Schristos 
19575fd0b74Schristos #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
19675fd0b74Schristos 
19775fd0b74Schristos /* Try compressing the input file at once using mmap. Return Z_OK if
19875fd0b74Schristos  * if success, Z_ERRNO otherwise.
19975fd0b74Schristos  */
gz_compress_mmap(in,out)20075fd0b74Schristos int gz_compress_mmap(in, out)
20175fd0b74Schristos     FILE   *in;
20275fd0b74Schristos     gzFile out;
20375fd0b74Schristos {
20475fd0b74Schristos     int len;
20575fd0b74Schristos     int err;
20675fd0b74Schristos     int ifd = fileno(in);
20775fd0b74Schristos     caddr_t buf;    /* mmap'ed buffer for the entire input file */
20875fd0b74Schristos     off_t buf_len;  /* length of the input file */
20975fd0b74Schristos     struct stat sb;
21075fd0b74Schristos 
21175fd0b74Schristos     /* Determine the size of the file, needed for mmap: */
21275fd0b74Schristos     if (fstat(ifd, &sb) < 0) return Z_ERRNO;
21375fd0b74Schristos     buf_len = sb.st_size;
21475fd0b74Schristos     if (buf_len <= 0) return Z_ERRNO;
21575fd0b74Schristos 
21675fd0b74Schristos     /* Now do the actual mmap: */
21775fd0b74Schristos     buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
21875fd0b74Schristos     if (buf == (caddr_t)(-1)) return Z_ERRNO;
21975fd0b74Schristos 
22075fd0b74Schristos     /* Compress the whole file at once: */
22175fd0b74Schristos     len = gzwrite(out, (char *)buf, (unsigned)buf_len);
22275fd0b74Schristos 
22375fd0b74Schristos     if (len != (int)buf_len) error(gzerror(out, &err));
22475fd0b74Schristos 
22575fd0b74Schristos     munmap(buf, buf_len);
22675fd0b74Schristos     fclose(in);
22775fd0b74Schristos     if (gzclose(out) != Z_OK) error("failed gzclose");
22875fd0b74Schristos     return Z_OK;
22975fd0b74Schristos }
23075fd0b74Schristos #endif /* USE_MMAP */
23175fd0b74Schristos 
23275fd0b74Schristos /* ===========================================================================
23375fd0b74Schristos  * Uncompress input to output then close both files.
23475fd0b74Schristos  */
gz_uncompress(in,out)23575fd0b74Schristos void gz_uncompress(in, out)
23675fd0b74Schristos     gzFile in;
23775fd0b74Schristos     FILE   *out;
23875fd0b74Schristos {
23975fd0b74Schristos     local char buf[BUFLEN];
24075fd0b74Schristos     int len;
24175fd0b74Schristos     int err;
24275fd0b74Schristos 
24375fd0b74Schristos     for (;;) {
24475fd0b74Schristos         len = gzread(in, buf, sizeof(buf));
24575fd0b74Schristos         if (len < 0) error (gzerror(in, &err));
24675fd0b74Schristos         if (len == 0) break;
24775fd0b74Schristos 
24875fd0b74Schristos         if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
24975fd0b74Schristos             error("failed fwrite");
25075fd0b74Schristos         }
25175fd0b74Schristos     }
25275fd0b74Schristos     if (fclose(out)) error("failed fclose");
25375fd0b74Schristos 
25475fd0b74Schristos     if (gzclose(in) != Z_OK) error("failed gzclose");
25575fd0b74Schristos }
25675fd0b74Schristos 
25775fd0b74Schristos 
25875fd0b74Schristos /* ===========================================================================
25975fd0b74Schristos  * Compress the given file: create a corresponding .gz file and remove the
26075fd0b74Schristos  * original.
26175fd0b74Schristos  */
file_compress(file,mode)26275fd0b74Schristos void file_compress(file, mode)
26375fd0b74Schristos     char  *file;
26475fd0b74Schristos     char  *mode;
26575fd0b74Schristos {
26675fd0b74Schristos     local char outfile[MAX_NAME_LEN];
26775fd0b74Schristos     FILE  *in;
26875fd0b74Schristos     gzFile out;
26975fd0b74Schristos 
27075fd0b74Schristos     if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
27175fd0b74Schristos         fprintf(stderr, "%s: filename too long\n", prog);
27275fd0b74Schristos         exit(1);
27375fd0b74Schristos     }
27475fd0b74Schristos 
27575fd0b74Schristos     strcpy(outfile, file);
27675fd0b74Schristos     strcat(outfile, GZ_SUFFIX);
27775fd0b74Schristos 
27875fd0b74Schristos     in = fopen(file, "rb");
27975fd0b74Schristos     if (in == NULL) {
28075fd0b74Schristos         perror(file);
28175fd0b74Schristos         exit(1);
28275fd0b74Schristos     }
28375fd0b74Schristos     out = gzopen(outfile, mode);
28475fd0b74Schristos     if (out == NULL) {
28575fd0b74Schristos         fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
28675fd0b74Schristos         exit(1);
28775fd0b74Schristos     }
28875fd0b74Schristos     gz_compress(in, out);
28975fd0b74Schristos 
29075fd0b74Schristos     unlink(file);
29175fd0b74Schristos }
29275fd0b74Schristos 
29375fd0b74Schristos 
29475fd0b74Schristos /* ===========================================================================
29575fd0b74Schristos  * Uncompress the given file and remove the original.
29675fd0b74Schristos  */
file_uncompress(file)29775fd0b74Schristos void file_uncompress(file)
29875fd0b74Schristos     char  *file;
29975fd0b74Schristos {
30075fd0b74Schristos     local char buf[MAX_NAME_LEN];
30175fd0b74Schristos     char *infile, *outfile;
30275fd0b74Schristos     FILE  *out;
30375fd0b74Schristos     gzFile in;
30475fd0b74Schristos     size_t len = strlen(file);
30575fd0b74Schristos 
30675fd0b74Schristos     if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
30775fd0b74Schristos         fprintf(stderr, "%s: filename too long\n", prog);
30875fd0b74Schristos         exit(1);
30975fd0b74Schristos     }
31075fd0b74Schristos 
31175fd0b74Schristos     strcpy(buf, file);
31275fd0b74Schristos 
31375fd0b74Schristos     if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
31475fd0b74Schristos         infile = file;
31575fd0b74Schristos         outfile = buf;
31675fd0b74Schristos         outfile[len-3] = '\0';
31775fd0b74Schristos     } else {
31875fd0b74Schristos         outfile = file;
31975fd0b74Schristos         infile = buf;
32075fd0b74Schristos         strcat(infile, GZ_SUFFIX);
32175fd0b74Schristos     }
32275fd0b74Schristos     in = gzopen(infile, "rb");
32375fd0b74Schristos     if (in == NULL) {
32475fd0b74Schristos         fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
32575fd0b74Schristos         exit(1);
32675fd0b74Schristos     }
32775fd0b74Schristos     out = fopen(outfile, "wb");
32875fd0b74Schristos     if (out == NULL) {
32975fd0b74Schristos         perror(file);
33075fd0b74Schristos         exit(1);
33175fd0b74Schristos     }
33275fd0b74Schristos 
33375fd0b74Schristos     gz_uncompress(in, out);
33475fd0b74Schristos 
33575fd0b74Schristos     unlink(infile);
33675fd0b74Schristos }
33775fd0b74Schristos 
33875fd0b74Schristos 
33975fd0b74Schristos /* ===========================================================================
34075fd0b74Schristos  * Usage:  minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...]
34175fd0b74Schristos  *   -c : write to standard output
34275fd0b74Schristos  *   -d : decompress
34375fd0b74Schristos  *   -f : compress with Z_FILTERED
34475fd0b74Schristos  *   -h : compress with Z_HUFFMAN_ONLY
34575fd0b74Schristos  *   -r : compress with Z_RLE
34675fd0b74Schristos  *   -1 to -9 : compression level
34775fd0b74Schristos  */
34875fd0b74Schristos 
main(argc,argv)34975fd0b74Schristos int main(argc, argv)
35075fd0b74Schristos     int argc;
35175fd0b74Schristos     char *argv[];
35275fd0b74Schristos {
35375fd0b74Schristos     int copyout = 0;
35475fd0b74Schristos     int uncompr = 0;
35575fd0b74Schristos     gzFile file;
35675fd0b74Schristos     char *bname, outmode[20];
35775fd0b74Schristos 
35875fd0b74Schristos     strcpy(outmode, "wb6 ");
35975fd0b74Schristos 
36075fd0b74Schristos     prog = argv[0];
36175fd0b74Schristos     bname = strrchr(argv[0], '/');
36275fd0b74Schristos     if (bname)
36375fd0b74Schristos       bname++;
36475fd0b74Schristos     else
36575fd0b74Schristos       bname = argv[0];
36675fd0b74Schristos     argc--, argv++;
36775fd0b74Schristos 
36875fd0b74Schristos     if (!strcmp(bname, "gunzip"))
36975fd0b74Schristos       uncompr = 1;
37075fd0b74Schristos     else if (!strcmp(bname, "zcat"))
37175fd0b74Schristos       copyout = uncompr = 1;
37275fd0b74Schristos 
37375fd0b74Schristos     while (argc > 0) {
37475fd0b74Schristos       if (strcmp(*argv, "-c") == 0)
37575fd0b74Schristos         copyout = 1;
37675fd0b74Schristos       else if (strcmp(*argv, "-d") == 0)
37775fd0b74Schristos         uncompr = 1;
37875fd0b74Schristos       else if (strcmp(*argv, "-f") == 0)
37975fd0b74Schristos         outmode[3] = 'f';
38075fd0b74Schristos       else if (strcmp(*argv, "-h") == 0)
38175fd0b74Schristos         outmode[3] = 'h';
38275fd0b74Schristos       else if (strcmp(*argv, "-r") == 0)
38375fd0b74Schristos         outmode[3] = 'R';
38475fd0b74Schristos       else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
38575fd0b74Schristos                (*argv)[2] == 0)
38675fd0b74Schristos         outmode[2] = (*argv)[1];
38775fd0b74Schristos       else
38875fd0b74Schristos         break;
38975fd0b74Schristos       argc--, argv++;
39075fd0b74Schristos     }
39175fd0b74Schristos     if (outmode[3] == ' ')
39275fd0b74Schristos         outmode[3] = 0;
39375fd0b74Schristos     if (argc == 0) {
39475fd0b74Schristos         SET_BINARY_MODE(stdin);
39575fd0b74Schristos         SET_BINARY_MODE(stdout);
39675fd0b74Schristos         if (uncompr) {
39775fd0b74Schristos             file = gzdopen(fileno(stdin), "rb");
39875fd0b74Schristos             if (file == NULL) error("can't gzdopen stdin");
39975fd0b74Schristos             gz_uncompress(file, stdout);
40075fd0b74Schristos         } else {
40175fd0b74Schristos             file = gzdopen(fileno(stdout), outmode);
40275fd0b74Schristos             if (file == NULL) error("can't gzdopen stdout");
40375fd0b74Schristos             gz_compress(stdin, file);
40475fd0b74Schristos         }
40575fd0b74Schristos     } else {
40675fd0b74Schristos         if (copyout) {
40775fd0b74Schristos             SET_BINARY_MODE(stdout);
40875fd0b74Schristos         }
40975fd0b74Schristos         do {
41075fd0b74Schristos             if (uncompr) {
41175fd0b74Schristos                 if (copyout) {
41275fd0b74Schristos                     file = gzopen(*argv, "rb");
41375fd0b74Schristos                     if (file == NULL)
41475fd0b74Schristos                         fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
41575fd0b74Schristos                     else
41675fd0b74Schristos                         gz_uncompress(file, stdout);
41775fd0b74Schristos                 } else {
41875fd0b74Schristos                     file_uncompress(*argv);
41975fd0b74Schristos                 }
42075fd0b74Schristos             } else {
42175fd0b74Schristos                 if (copyout) {
42275fd0b74Schristos                     FILE * in = fopen(*argv, "rb");
42375fd0b74Schristos 
42475fd0b74Schristos                     if (in == NULL) {
42575fd0b74Schristos                         perror(*argv);
42675fd0b74Schristos                     } else {
42775fd0b74Schristos                         file = gzdopen(fileno(stdout), outmode);
42875fd0b74Schristos                         if (file == NULL) error("can't gzdopen stdout");
42975fd0b74Schristos 
43075fd0b74Schristos                         gz_compress(in, file);
43175fd0b74Schristos                     }
43275fd0b74Schristos 
43375fd0b74Schristos                 } else {
43475fd0b74Schristos                     file_compress(*argv, outmode);
43575fd0b74Schristos                 }
43675fd0b74Schristos             }
43775fd0b74Schristos         } while (argv++, --argc);
43875fd0b74Schristos     }
43975fd0b74Schristos     return 0;
44075fd0b74Schristos }
441