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