source: rtems/cpukit/zlib/minigzip.c @ d71b3a7

4.11
Last change on this file since d71b3a7 was f7d9aea2, checked in by Ralf Corsepius <ralf.corsepius@…>, on Mar 18, 2011 at 10:11:20 AM

Import from zlib-1.2.4

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/* minigzip.c -- simulate gzip using the zlib compression library
2 * Copyright (C) 1995-2006, 2010 Jean-loup Gailly.
3 * For conditions of distribution and use, see copyright notice in zlib.h
4 */
5
6/*
7 * minigzip is a minimal implementation of the gzip utility. This is
8 * only an example of using zlib and isn't meant to replace the
9 * full-featured gzip. No attempt is made to deal with file systems
10 * limiting names to 14 or 8+3 characters, etc... Error checking is
11 * very limited. So use minigzip only for testing; use gzip for the
12 * real thing. On MSDOS, use only on file names without extension
13 * or in pipe mode.
14 */
15
16/* @(#) $Id$ */
17
18#include "zlib.h"
19#include <stdio.h>
20
21#ifdef STDC
22#  include <string.h>
23#  include <stdlib.h>
24#endif
25
26#ifdef USE_MMAP
27#  include <sys/types.h>
28#  include <sys/mman.h>
29#  include <sys/stat.h>
30#endif
31
32#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
33#  include <fcntl.h>
34#  include <io.h>
35#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
36#else
37#  define SET_BINARY_MODE(file)
38#endif
39
40#ifdef VMS
41#  define unlink delete
42#  define GZ_SUFFIX "-gz"
43#endif
44#ifdef RISCOS
45#  define unlink remove
46#  define GZ_SUFFIX "-gz"
47#  define fileno(file) file->__file
48#endif
49#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
50#  include <unix.h> /* for fileno */
51#endif
52
53#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
54  extern int unlink OF((const char *));
55#endif
56
57#if defined(UNDER_CE) && defined(NO_ERRNO_H)
58#  include <windows.h>
59#  define perror(s) pwinerror(s)
60
61/* Map the Windows error number in ERROR to a locale-dependent error
62   message string and return a pointer to it.  Typically, the values
63   for ERROR come from GetLastError.
64
65   The string pointed to shall not be modified by the application,
66   but may be overwritten by a subsequent call to strwinerror
67
68   The strwinerror function does not change the current setting
69   of GetLastError.  */
70
71static char *strwinerror (error)
72     DWORD error;
73{
74    static char buf[1024];
75
76    wchar_t *msgbuf;
77    DWORD lasterr = GetLastError();
78    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
79        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
80        NULL,
81        error,
82        0, /* Default language */
83        (LPVOID)&msgbuf,
84        0,
85        NULL);
86    if (chars != 0) {
87        /* If there is an \r\n appended, zap it.  */
88        if (chars >= 2
89            && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
90            chars -= 2;
91            msgbuf[chars] = 0;
92        }
93
94        if (chars > sizeof (buf) - 1) {
95            chars = sizeof (buf) - 1;
96            msgbuf[chars] = 0;
97        }
98
99        wcstombs(buf, msgbuf, chars + 1);
100        LocalFree(msgbuf);
101    }
102    else {
103        sprintf(buf, "unknown win32 error (%ld)", error);
104    }
105
106    SetLastError(lasterr);
107    return buf;
108}
109
110static void pwinerror (s)
111    const char *s;
112{
113    if (s && *s)
114        fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
115    else
116        fprintf(stderr, "%s\n", strwinerror(GetLastError ()));
117}
118
119#endif /* UNDER_CE && NO_ERRNO_H */
120
121#ifndef GZ_SUFFIX
122#  define GZ_SUFFIX ".gz"
123#endif
124#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
125
126#define BUFLEN      16384
127#define MAX_NAME_LEN 1024
128
129#ifdef MAXSEG_64K
130#  define local static
131   /* Needed for systems with limitation on stack size. */
132#else
133#  define local
134#endif
135
136char *prog;
137
138void error            OF((const char *msg));
139void gz_compress      OF((FILE   *in, gzFile out));
140#ifdef USE_MMAP
141int  gz_compress_mmap OF((FILE   *in, gzFile out));
142#endif
143void gz_uncompress    OF((gzFile in, FILE   *out));
144void file_compress    OF((char  *file, char *mode));
145void file_uncompress  OF((char  *file));
146int  main             OF((int argc, char *argv[]));
147
148/* ===========================================================================
149 * Display error message and exit
150 */
151void error(msg)
152    const char *msg;
153{
154    fprintf(stderr, "%s: %s\n", prog, msg);
155    exit(1);
156}
157
158/* ===========================================================================
159 * Compress input to output then close both files.
160 */
161
162void gz_compress(in, out)
163    FILE   *in;
164    gzFile out;
165{
166    local char buf[BUFLEN];
167    int len;
168    int err;
169
170#ifdef USE_MMAP
171    /* Try first compressing with mmap. If mmap fails (minigzip used in a
172     * pipe), use the normal fread loop.
173     */
174    if (gz_compress_mmap(in, out) == Z_OK) return;
175#endif
176    for (;;) {
177        len = (int)fread(buf, 1, sizeof(buf), in);
178        if (ferror(in)) {
179            perror("fread");
180            exit(1);
181        }
182        if (len == 0) break;
183
184        if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
185    }
186    fclose(in);
187    if (gzclose(out) != Z_OK) error("failed gzclose");
188}
189
190#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
191
192/* Try compressing the input file at once using mmap. Return Z_OK if
193 * if success, Z_ERRNO otherwise.
194 */
195int gz_compress_mmap(in, out)
196    FILE   *in;
197    gzFile out;
198{
199    int len;
200    int err;
201    int ifd = fileno(in);
202    caddr_t buf;    /* mmap'ed buffer for the entire input file */
203    off_t buf_len;  /* length of the input file */
204    struct stat sb;
205
206    /* Determine the size of the file, needed for mmap: */
207    if (fstat(ifd, &sb) < 0) return Z_ERRNO;
208    buf_len = sb.st_size;
209    if (buf_len <= 0) return Z_ERRNO;
210
211    /* Now do the actual mmap: */
212    buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
213    if (buf == (caddr_t)(-1)) return Z_ERRNO;
214
215    /* Compress the whole file at once: */
216    len = gzwrite(out, (char *)buf, (unsigned)buf_len);
217
218    if (len != (int)buf_len) error(gzerror(out, &err));
219
220    munmap(buf, buf_len);
221    fclose(in);
222    if (gzclose(out) != Z_OK) error("failed gzclose");
223    return Z_OK;
224}
225#endif /* USE_MMAP */
226
227/* ===========================================================================
228 * Uncompress input to output then close both files.
229 */
230void gz_uncompress(in, out)
231    gzFile in;
232    FILE   *out;
233{
234    local char buf[BUFLEN];
235    int len;
236    int err;
237
238    for (;;) {
239        len = gzread(in, buf, sizeof(buf));
240        if (len < 0) error (gzerror(in, &err));
241        if (len == 0) break;
242
243        if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
244            error("failed fwrite");
245        }
246    }
247    if (fclose(out)) error("failed fclose");
248
249    if (gzclose(in) != Z_OK) error("failed gzclose");
250}
251
252
253/* ===========================================================================
254 * Compress the given file: create a corresponding .gz file and remove the
255 * original.
256 */
257void file_compress(file, mode)
258    char  *file;
259    char  *mode;
260{
261    local char outfile[MAX_NAME_LEN];
262    FILE  *in;
263    gzFile out;
264
265    if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
266        fprintf(stderr, "%s: filename too long\n", prog);
267        exit(1);
268    }
269
270    strcpy(outfile, file);
271    strcat(outfile, GZ_SUFFIX);
272
273    in = fopen(file, "rb");
274    if (in == NULL) {
275        perror(file);
276        exit(1);
277    }
278    out = gzopen(outfile, mode);
279    if (out == NULL) {
280        fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
281        exit(1);
282    }
283    gz_compress(in, out);
284
285    unlink(file);
286}
287
288
289/* ===========================================================================
290 * Uncompress the given file and remove the original.
291 */
292void file_uncompress(file)
293    char  *file;
294{
295    local char buf[MAX_NAME_LEN];
296    char *infile, *outfile;
297    FILE  *out;
298    gzFile in;
299    size_t len = strlen(file);
300
301    if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
302        fprintf(stderr, "%s: filename too long\n", prog);
303        exit(1);
304    }
305
306    strcpy(buf, file);
307
308    if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
309        infile = file;
310        outfile = buf;
311        outfile[len-3] = '\0';
312    } else {
313        outfile = file;
314        infile = buf;
315        strcat(infile, GZ_SUFFIX);
316    }
317    in = gzopen(infile, "rb");
318    if (in == NULL) {
319        fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
320        exit(1);
321    }
322    out = fopen(outfile, "wb");
323    if (out == NULL) {
324        perror(file);
325        exit(1);
326    }
327
328    gz_uncompress(in, out);
329
330    unlink(infile);
331}
332
333
334/* ===========================================================================
335 * Usage:  minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...]
336 *   -c : write to standard output
337 *   -d : decompress
338 *   -f : compress with Z_FILTERED
339 *   -h : compress with Z_HUFFMAN_ONLY
340 *   -r : compress with Z_RLE
341 *   -1 to -9 : compression level
342 */
343
344int main(argc, argv)
345    int argc;
346    char *argv[];
347{
348    int copyout = 0;
349    int uncompr = 0;
350    gzFile file;
351    char *bname, outmode[20];
352
353    strcpy(outmode, "wb6 ");
354
355    prog = argv[0];
356    bname = strrchr(argv[0], '/');
357    if (bname)
358      bname++;
359    else
360      bname = argv[0];
361    argc--, argv++;
362
363    if (!strcmp(bname, "gunzip"))
364      uncompr = 1;
365    else if (!strcmp(bname, "zcat"))
366      copyout = uncompr = 1;
367
368    while (argc > 0) {
369      if (strcmp(*argv, "-c") == 0)
370        copyout = 1;
371      else if (strcmp(*argv, "-d") == 0)
372        uncompr = 1;
373      else if (strcmp(*argv, "-f") == 0)
374        outmode[3] = 'f';
375      else if (strcmp(*argv, "-h") == 0)
376        outmode[3] = 'h';
377      else if (strcmp(*argv, "-r") == 0)
378        outmode[3] = 'R';
379      else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
380               (*argv)[2] == 0)
381        outmode[2] = (*argv)[1];
382      else
383        break;
384      argc--, argv++;
385    }
386    if (outmode[3] == ' ')
387        outmode[3] = 0;
388    if (argc == 0) {
389        SET_BINARY_MODE(stdin);
390        SET_BINARY_MODE(stdout);
391        if (uncompr) {
392            file = gzdopen(fileno(stdin), "rb");
393            if (file == NULL) error("can't gzdopen stdin");
394            gz_uncompress(file, stdout);
395        } else {
396            file = gzdopen(fileno(stdout), outmode);
397            if (file == NULL) error("can't gzdopen stdout");
398            gz_compress(stdin, file);
399        }
400    } else {
401        if (copyout) {
402            SET_BINARY_MODE(stdout);
403        }
404        do {
405            if (uncompr) {
406                if (copyout) {
407                    file = gzopen(*argv, "rb");
408                    if (file == NULL)
409                        fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
410                    else
411                        gz_uncompress(file, stdout);
412                } else {
413                    file_uncompress(*argv);
414                }
415            } else {
416                if (copyout) {
417                    FILE * in = fopen(*argv, "rb");
418
419                    if (in == NULL) {
420                        perror(*argv);
421                    } else {
422                        file = gzdopen(fileno(stdout), outmode);
423                        if (file == NULL) error("can't gzdopen stdout");
424
425                        gz_compress(in, file);
426                    }
427
428                } else {
429                    file_compress(*argv, outmode);
430                }
431            }
432        } while (argv++, --argc);
433    }
434    return 0;
435}
Note: See TracBrowser for help on using the repository browser.