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 http://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 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 85 static char *strwinerror (error) 86 DWORD error; 87 { 88 static char buf[1024]; 89 90 wchar_t *msgbuf; 91 DWORD lasterr = GetLastError(); 92 DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM 93 | FORMAT_MESSAGE_ALLOCATE_BUFFER, 94 NULL, 95 error, 96 0, /* Default language */ 97 (LPVOID)&msgbuf, 98 0, 99 NULL); 100 if (chars != 0) { 101 /* If there is an \r\n appended, zap it. */ 102 if (chars >= 2 103 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { 104 chars -= 2; 105 msgbuf[chars] = 0; 106 } 107 108 if (chars > sizeof (buf) - 1) { 109 chars = sizeof (buf) - 1; 110 msgbuf[chars] = 0; 111 } 112 113 wcstombs(buf, msgbuf, chars + 1); 114 LocalFree(msgbuf); 115 } 116 else { 117 sprintf(buf, "unknown win32 error (%ld)", error); 118 } 119 120 SetLastError(lasterr); 121 return buf; 122 } 123 124 static void pwinerror (s) 125 const char *s; 126 { 127 if (s && *s) 128 fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); 129 else 130 fprintf(stderr, "%s\n", strwinerror(GetLastError ())); 131 } 132 133 #endif /* UNDER_CE */ 134 135 #ifndef GZ_SUFFIX 136 # define GZ_SUFFIX ".gz" 137 #endif 138 #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) 139 140 #define BUFLEN 16384 141 #define MAX_NAME_LEN 1024 142 143 #ifdef MAXSEG_64K 144 # define local static 145 /* Needed for systems with limitation on stack size. */ 146 #else 147 # define local 148 #endif 149 150 #ifdef Z_SOLO 151 /* for Z_SOLO, create simplified gz* functions using deflate and inflate */ 152 153 #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) 154 # include <unistd.h> /* for unlink() */ 155 #endif 156 157 void *myalloc OF((void *, unsigned, unsigned)); 158 void myfree OF((void *, void *)); 159 160 void *myalloc(q, n, m) 161 void *q; 162 unsigned n, m; 163 { 164 q = Z_NULL; 165 return calloc(n, m); 166 } 167 168 void myfree(q, p) 169 void *q, *p; 170 { 171 q = Z_NULL; 172 free(p); 173 } 174 175 typedef struct gzFile_s { 176 FILE *file; 177 int write; 178 int err; 179 char *msg; 180 z_stream strm; 181 } *gzFile; 182 183 gzFile gzopen OF((const char *, const char *)); 184 gzFile gzdopen OF((int, const char *)); 185 gzFile gz_open OF((const char *, int, const char *)); 186 187 gzFile gzopen(path, mode) 188 const char *path; 189 const char *mode; 190 { 191 return gz_open(path, -1, mode); 192 } 193 194 gzFile gzdopen(fd, mode) 195 int fd; 196 const char *mode; 197 { 198 return gz_open(NULL, fd, mode); 199 } 200 201 gzFile gz_open(path, fd, mode) 202 const char *path; 203 int fd; 204 const char *mode; 205 { 206 gzFile gz; 207 int ret; 208 209 gz = malloc(sizeof(struct gzFile_s)); 210 if (gz == NULL) 211 return NULL; 212 gz->write = strchr(mode, 'w') != NULL; 213 gz->strm.zalloc = myalloc; 214 gz->strm.zfree = myfree; 215 gz->strm.opaque = Z_NULL; 216 if (gz->write) 217 ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0); 218 else { 219 gz->strm.next_in = 0; 220 gz->strm.avail_in = Z_NULL; 221 ret = inflateInit2(&(gz->strm), 15 + 16); 222 } 223 if (ret != Z_OK) { 224 free(gz); 225 return NULL; 226 } 227 gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") : 228 fopen(path, gz->write ? "wb" : "rb"); 229 if (gz->file == NULL) { 230 gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm)); 231 free(gz); 232 return NULL; 233 } 234 gz->err = 0; 235 gz->msg = ""; 236 return gz; 237 } 238 239 int gzwrite OF((gzFile, const void *, unsigned)); 240 241 int gzwrite(gz, buf, len) 242 gzFile gz; 243 const void *buf; 244 unsigned len; 245 { 246 z_stream *strm; 247 unsigned char out[BUFLEN]; 248 249 if (gz == NULL || !gz->write) 250 return 0; 251 strm = &(gz->strm); 252 strm->next_in = (void *)buf; 253 strm->avail_in = len; 254 do { 255 strm->next_out = out; 256 strm->avail_out = BUFLEN; 257 (void)deflate(strm, Z_NO_FLUSH); 258 fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); 259 } while (strm->avail_out == 0); 260 return len; 261 } 262 263 int gzread OF((gzFile, void *, unsigned)); 264 265 int gzread(gz, buf, len) 266 gzFile gz; 267 void *buf; 268 unsigned len; 269 { 270 int ret; 271 unsigned got; 272 unsigned char in[1]; 273 z_stream *strm; 274 275 if (gz == NULL || gz->write) 276 return 0; 277 if (gz->err) 278 return 0; 279 strm = &(gz->strm); 280 strm->next_out = (void *)buf; 281 strm->avail_out = len; 282 do { 283 got = fread(in, 1, 1, gz->file); 284 if (got == 0) 285 break; 286 strm->next_in = in; 287 strm->avail_in = 1; 288 ret = inflate(strm, Z_NO_FLUSH); 289 if (ret == Z_DATA_ERROR) { 290 gz->err = Z_DATA_ERROR; 291 gz->msg = strm->msg; 292 return 0; 293 } 294 if (ret == Z_STREAM_END) 295 inflateReset(strm); 296 } while (strm->avail_out); 297 return len - strm->avail_out; 298 } 299 300 int gzclose OF((gzFile)); 301 302 int gzclose(gz) 303 gzFile gz; 304 { 305 z_stream *strm; 306 unsigned char out[BUFLEN]; 307 308 if (gz == NULL) 309 return Z_STREAM_ERROR; 310 strm = &(gz->strm); 311 if (gz->write) { 312 strm->next_in = Z_NULL; 313 strm->avail_in = 0; 314 do { 315 strm->next_out = out; 316 strm->avail_out = BUFLEN; 317 (void)deflate(strm, Z_FINISH); 318 fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); 319 } while (strm->avail_out == 0); 320 deflateEnd(strm); 321 } 322 else 323 inflateEnd(strm); 324 fclose(gz->file); 325 free(gz); 326 return Z_OK; 327 } 328 329 const char *gzerror OF((gzFile, int *)); 330 331 const char *gzerror(gz, err) 332 gzFile gz; 333 int *err; 334 { 335 *err = gz->err; 336 return gz->msg; 337 } 338 339 #endif 340 341 char *prog; 342 343 void error OF((const char *msg)); 344 void gz_compress OF((FILE *in, gzFile out)); 345 #ifdef USE_MMAP 346 int gz_compress_mmap OF((FILE *in, gzFile out)); 347 #endif 348 void gz_uncompress OF((gzFile in, FILE *out)); 349 void file_compress OF((char *file, char *mode)); 350 void file_uncompress OF((char *file)); 351 int main OF((int argc, char *argv[])); 352 353 /* =========================================================================== 354 * Display error message and exit 355 */ 356 void error(msg) 357 const char *msg; 358 { 359 fprintf(stderr, "%s: %s\n", prog, msg); 360 exit(1); 361 } 362 363 /* =========================================================================== 364 * Compress input to output then close both files. 365 */ 366 367 void gz_compress(in, out) 368 FILE *in; 369 gzFile out; 370 { 371 local char buf[BUFLEN]; 372 int len; 373 int err; 374 375 #ifdef USE_MMAP 376 /* Try first compressing with mmap. If mmap fails (minigzip used in a 377 * pipe), use the normal fread loop. 378 */ 379 if (gz_compress_mmap(in, out) == Z_OK) return; 380 #endif 381 for (;;) { 382 len = (int)fread(buf, 1, sizeof(buf), in); 383 if (ferror(in)) { 384 perror("fread"); 385 exit(1); 386 } 387 if (len == 0) break; 388 389 if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); 390 } 391 fclose(in); 392 if (gzclose(out) != Z_OK) error("failed gzclose"); 393 } 394 395 #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */ 396 397 /* Try compressing the input file at once using mmap. Return Z_OK if 398 * if success, Z_ERRNO otherwise. 399 */ 400 int gz_compress_mmap(in, out) 401 FILE *in; 402 gzFile out; 403 { 404 int len; 405 int err; 406 int ifd = fileno(in); 407 caddr_t buf; /* mmap'ed buffer for the entire input file */ 408 off_t buf_len; /* length of the input file */ 409 struct stat sb; 410 411 /* Determine the size of the file, needed for mmap: */ 412 if (fstat(ifd, &sb) < 0) return Z_ERRNO; 413 buf_len = sb.st_size; 414 if (buf_len <= 0) return Z_ERRNO; 415 416 /* Now do the actual mmap: */ 417 buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); 418 if (buf == (caddr_t)(-1)) return Z_ERRNO; 419 420 /* Compress the whole file at once: */ 421 len = gzwrite(out, (char *)buf, (unsigned)buf_len); 422 423 if (len != (int)buf_len) error(gzerror(out, &err)); 424 425 munmap(buf, buf_len); 426 fclose(in); 427 if (gzclose(out) != Z_OK) error("failed gzclose"); 428 return Z_OK; 429 } 430 #endif /* USE_MMAP */ 431 432 /* =========================================================================== 433 * Uncompress input to output then close both files. 434 */ 435 void gz_uncompress(in, out) 436 gzFile in; 437 FILE *out; 438 { 439 local char buf[BUFLEN]; 440 int len; 441 int err; 442 443 for (;;) { 444 len = gzread(in, buf, sizeof(buf)); 445 if (len < 0) error (gzerror(in, &err)); 446 if (len == 0) break; 447 448 if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { 449 error("failed fwrite"); 450 } 451 } 452 if (fclose(out)) error("failed fclose"); 453 454 if (gzclose(in) != Z_OK) error("failed gzclose"); 455 } 456 457 458 /* =========================================================================== 459 * Compress the given file: create a corresponding .gz file and remove the 460 * original. 461 */ 462 void file_compress(file, mode) 463 char *file; 464 char *mode; 465 { 466 local char outfile[MAX_NAME_LEN]; 467 FILE *in; 468 gzFile out; 469 470 if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { 471 fprintf(stderr, "%s: filename too long\n", prog); 472 exit(1); 473 } 474 475 strcpy(outfile, file); 476 strcat(outfile, GZ_SUFFIX); 477 478 in = fopen(file, "rb"); 479 if (in == NULL) { 480 perror(file); 481 exit(1); 482 } 483 out = gzopen(outfile, mode); 484 if (out == NULL) { 485 fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); 486 exit(1); 487 } 488 gz_compress(in, out); 489 490 unlink(file); 491 } 492 493 494 /* =========================================================================== 495 * Uncompress the given file and remove the original. 496 */ 497 void file_uncompress(file) 498 char *file; 499 { 500 local char buf[MAX_NAME_LEN]; 501 char *infile, *outfile; 502 FILE *out; 503 gzFile in; 504 size_t len = strlen(file); 505 506 if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { 507 fprintf(stderr, "%s: filename too long\n", prog); 508 exit(1); 509 } 510 511 strcpy(buf, file); 512 513 if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { 514 infile = file; 515 outfile = buf; 516 outfile[len-3] = '\0'; 517 } else { 518 outfile = file; 519 infile = buf; 520 strcat(infile, GZ_SUFFIX); 521 } 522 in = gzopen(infile, "rb"); 523 if (in == NULL) { 524 fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); 525 exit(1); 526 } 527 out = fopen(outfile, "wb"); 528 if (out == NULL) { 529 perror(file); 530 exit(1); 531 } 532 533 gz_uncompress(in, out); 534 535 unlink(infile); 536 } 537 538 539 /* =========================================================================== 540 * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] 541 * -c : write to standard output 542 * -d : decompress 543 * -f : compress with Z_FILTERED 544 * -h : compress with Z_HUFFMAN_ONLY 545 * -r : compress with Z_RLE 546 * -1 to -9 : compression level 547 */ 548 549 int main(argc, argv) 550 int argc; 551 char *argv[]; 552 { 553 int copyout = 0; 554 int uncompr = 0; 555 gzFile file; 556 char *bname, outmode[20]; 557 558 strcpy(outmode, "wb6 "); 559 560 prog = argv[0]; 561 bname = strrchr(argv[0], '/'); 562 if (bname) 563 bname++; 564 else 565 bname = argv[0]; 566 argc--, argv++; 567 568 if (!strcmp(bname, "gunzip")) 569 uncompr = 1; 570 else if (!strcmp(bname, "zcat")) 571 copyout = uncompr = 1; 572 573 while (argc > 0) { 574 if (strcmp(*argv, "-c") == 0) 575 copyout = 1; 576 else if (strcmp(*argv, "-d") == 0) 577 uncompr = 1; 578 else if (strcmp(*argv, "-f") == 0) 579 outmode[3] = 'f'; 580 else if (strcmp(*argv, "-h") == 0) 581 outmode[3] = 'h'; 582 else if (strcmp(*argv, "-r") == 0) 583 outmode[3] = 'R'; 584 else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && 585 (*argv)[2] == 0) 586 outmode[2] = (*argv)[1]; 587 else 588 break; 589 argc--, argv++; 590 } 591 if (outmode[3] == ' ') 592 outmode[3] = 0; 593 if (argc == 0) { 594 SET_BINARY_MODE(stdin); 595 SET_BINARY_MODE(stdout); 596 if (uncompr) { 597 file = gzdopen(fileno(stdin), "rb"); 598 if (file == NULL) error("can't gzdopen stdin"); 599 gz_uncompress(file, stdout); 600 } else { 601 file = gzdopen(fileno(stdout), outmode); 602 if (file == NULL) error("can't gzdopen stdout"); 603 gz_compress(stdin, file); 604 } 605 } else { 606 if (copyout) { 607 SET_BINARY_MODE(stdout); 608 } 609 do { 610 if (uncompr) { 611 if (copyout) { 612 file = gzopen(*argv, "rb"); 613 if (file == NULL) 614 fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); 615 else 616 gz_uncompress(file, stdout); 617 } else { 618 file_uncompress(*argv); 619 } 620 } else { 621 if (copyout) { 622 FILE * in = fopen(*argv, "rb"); 623 624 if (in == NULL) { 625 perror(*argv); 626 } else { 627 file = gzdopen(fileno(stdout), outmode); 628 if (file == NULL) error("can't gzdopen stdout"); 629 630 gz_compress(in, file); 631 } 632 633 } else { 634 file_compress(*argv, outmode); 635 } 636 } 637 } while (argv++, --argc); 638 } 639 return 0; 640 } 641