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