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