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 #include "zstd_zlibwrapper.h" 22 #include <stdio.h> 23 24 #ifdef STDC 25 # include <string.h> 26 # include <stdlib.h> 27 #endif 28 29 #ifdef USE_MMAP 30 # include <sys/types.h> 31 # include <sys/mman.h> 32 # include <sys/stat.h> 33 #endif 34 35 #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) 36 # include <fcntl.h> 37 # include <io.h> 38 # ifdef UNDER_CE 39 # include <stdlib.h> 40 # endif 41 # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) 42 #else 43 # define SET_BINARY_MODE(file) 44 #endif 45 46 #ifdef _MSC_VER 47 # define snprintf _snprintf 48 #endif 49 50 #ifdef VMS 51 # define unlink delete 52 # define GZ_SUFFIX "-gz" 53 #endif 54 #ifdef RISCOS 55 # define unlink remove 56 # define GZ_SUFFIX "-gz" 57 # define fileno(file) file->__file 58 #endif 59 #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os 60 # include <unix.h> /* for fileno */ 61 #endif 62 63 #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) 64 #ifndef WIN32 /* unlink already in stdio.h for WIN32 */ 65 extern int unlink OF((const char *)); 66 #endif 67 #endif 68 69 #if defined(UNDER_CE) 70 # include <windows.h> 71 # define perror(s) pwinerror(s) 72 73 /* Map the Windows error number in ERROR to a locale-dependent error 74 message string and return a pointer to it. Typically, the values 75 for ERROR come from GetLastError. 76 77 The string pointed to shall not be modified by the application, 78 but may be overwritten by a subsequent call to strwinerror 79 80 The strwinerror function does not change the current setting 81 of GetLastError. */ 82 83 static char *strwinerror (error) 84 DWORD error; 85 { 86 static char buf[1024]; 87 88 wchar_t *msgbuf; 89 DWORD lasterr = GetLastError(); 90 DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM 91 | FORMAT_MESSAGE_ALLOCATE_BUFFER, 92 NULL, 93 error, 94 0, /* Default language */ 95 (LPVOID)&msgbuf, 96 0, 97 NULL); 98 if (chars != 0) { 99 /* If there is an \r\n appended, zap it. */ 100 if (chars >= 2 101 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { 102 chars -= 2; 103 msgbuf[chars] = 0; 104 } 105 106 if (chars > sizeof (buf) - 1) { 107 chars = sizeof (buf) - 1; 108 msgbuf[chars] = 0; 109 } 110 111 wcstombs(buf, msgbuf, chars + 1); 112 LocalFree(msgbuf); 113 } 114 else { 115 sprintf(buf, "unknown win32 error (%ld)", error); 116 } 117 118 SetLastError(lasterr); 119 return buf; 120 } 121 122 static void pwinerror (s) 123 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 OF((void *, unsigned, unsigned)); 156 void myfree OF((void *, void *)); 157 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 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 OF((const char *, const char *)); 182 gzFile gzdopen OF((int, const char *)); 183 gzFile gz_open OF((const char *, int, const char *)); 184 185 gzFile gzopen(path, mode) 186 const char *path; 187 const char *mode; 188 { 189 return gz_open(path, -1, mode); 190 } 191 192 gzFile gzdopen(fd, mode) 193 int fd; 194 const char *mode; 195 { 196 return gz_open(NULL, fd, mode); 197 } 198 199 gzFile gz_open(path, fd, mode) 200 const char *path; 201 int fd; 202 const char *mode; 203 { 204 gzFile gz; 205 int ret; 206 207 gz = malloc(sizeof(struct gzFile_s)); 208 if (gz == NULL) 209 return NULL; 210 gz->write = strchr(mode, 'w') != NULL; 211 gz->strm.zalloc = myalloc; 212 gz->strm.zfree = myfree; 213 gz->strm.opaque = Z_NULL; 214 if (gz->write) 215 ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0); 216 else { 217 gz->strm.next_in = 0; 218 gz->strm.avail_in = Z_NULL; 219 ret = inflateInit2(&(gz->strm), 15 + 16); 220 } 221 if (ret != Z_OK) { 222 free(gz); 223 return NULL; 224 } 225 gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") : 226 fopen(path, gz->write ? "wb" : "rb"); 227 if (gz->file == NULL) { 228 gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm)); 229 free(gz); 230 return NULL; 231 } 232 gz->err = 0; 233 gz->msg = ""; 234 return gz; 235 } 236 237 int gzwrite OF((gzFile, const void *, unsigned)); 238 239 int gzwrite(gz, buf, len) 240 gzFile gz; 241 const void *buf; 242 unsigned len; 243 { 244 z_stream *strm; 245 unsigned char out[BUFLEN]; 246 247 if (gz == NULL || !gz->write) 248 return 0; 249 strm = &(gz->strm); 250 strm->next_in = (void *)buf; 251 strm->avail_in = len; 252 do { 253 strm->next_out = out; 254 strm->avail_out = BUFLEN; 255 (void)deflate(strm, Z_NO_FLUSH); 256 fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); 257 } while (strm->avail_out == 0); 258 return len; 259 } 260 261 int gzread OF((gzFile, void *, unsigned)); 262 263 int gzread(gz, buf, len) 264 gzFile gz; 265 void *buf; 266 unsigned len; 267 { 268 int ret; 269 unsigned got; 270 unsigned char in[1]; 271 z_stream *strm; 272 273 if (gz == NULL || gz->write) 274 return 0; 275 if (gz->err) 276 return 0; 277 strm = &(gz->strm); 278 strm->next_out = (void *)buf; 279 strm->avail_out = len; 280 do { 281 got = fread(in, 1, 1, gz->file); 282 if (got == 0) 283 break; 284 strm->next_in = in; 285 strm->avail_in = 1; 286 ret = inflate(strm, Z_NO_FLUSH); 287 if (ret == Z_DATA_ERROR) { 288 gz->err = Z_DATA_ERROR; 289 gz->msg = strm->msg; 290 return 0; 291 } 292 if (ret == Z_STREAM_END) 293 inflateReset(strm); 294 } while (strm->avail_out); 295 return len - strm->avail_out; 296 } 297 298 int gzclose OF((gzFile)); 299 300 int gzclose(gz) 301 gzFile gz; 302 { 303 z_stream *strm; 304 unsigned char out[BUFLEN]; 305 306 if (gz == NULL) 307 return Z_STREAM_ERROR; 308 strm = &(gz->strm); 309 if (gz->write) { 310 strm->next_in = Z_NULL; 311 strm->avail_in = 0; 312 do { 313 strm->next_out = out; 314 strm->avail_out = BUFLEN; 315 (void)deflate(strm, Z_FINISH); 316 fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); 317 } while (strm->avail_out == 0); 318 deflateEnd(strm); 319 } 320 else 321 inflateEnd(strm); 322 fclose(gz->file); 323 free(gz); 324 return Z_OK; 325 } 326 327 const char *gzerror OF((gzFile, int *)); 328 329 const char *gzerror(gz, err) 330 gzFile gz; 331 int *err; 332 { 333 *err = gz->err; 334 return gz->msg; 335 } 336 337 #endif 338 339 char *prog; 340 341 void error OF((const char *msg)); 342 void gz_compress OF((FILE *in, gzFile out)); 343 #ifdef USE_MMAP 344 int gz_compress_mmap OF((FILE *in, gzFile out)); 345 #endif 346 void gz_uncompress OF((gzFile in, FILE *out)); 347 void file_compress OF((char *file, char *mode)); 348 void file_uncompress OF((char *file)); 349 int main OF((int argc, char *argv[])); 350 351 /* =========================================================================== 352 * Display error message and exit 353 */ 354 void error(msg) 355 const char *msg; 356 { 357 fprintf(stderr, "%s: %s\n", prog, msg); 358 exit(1); 359 } 360 361 /* =========================================================================== 362 * Compress input to output then close both files. 363 */ 364 365 void gz_compress(in, out) 366 FILE *in; 367 gzFile out; 368 { 369 local char buf[BUFLEN]; 370 int len; 371 int err; 372 373 #ifdef USE_MMAP 374 /* Try first compressing with mmap. If mmap fails (minigzip used in a 375 * pipe), use the normal fread loop. 376 */ 377 if (gz_compress_mmap(in, out) == Z_OK) return; 378 #endif 379 for (;;) { 380 len = (int)fread(buf, 1, sizeof(buf), in); 381 if (ferror(in)) { 382 perror("fread"); 383 exit(1); 384 } 385 if (len == 0) break; 386 387 if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); 388 } 389 fclose(in); 390 if (gzclose(out) != Z_OK) error("failed gzclose"); 391 } 392 393 #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */ 394 395 /* Try compressing the input file at once using mmap. Return Z_OK if 396 * if success, Z_ERRNO otherwise. 397 */ 398 int gz_compress_mmap(in, out) 399 FILE *in; 400 gzFile out; 401 { 402 int len; 403 int err; 404 int ifd = fileno(in); 405 caddr_t buf; /* mmap'ed buffer for the entire input file */ 406 off_t buf_len; /* length of the input file */ 407 struct stat sb; 408 409 /* Determine the size of the file, needed for mmap: */ 410 if (fstat(ifd, &sb) < 0) return Z_ERRNO; 411 buf_len = sb.st_size; 412 if (buf_len <= 0) return Z_ERRNO; 413 414 /* Now do the actual mmap: */ 415 buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); 416 if (buf == (caddr_t)(-1)) return Z_ERRNO; 417 418 /* Compress the whole file at once: */ 419 len = gzwrite(out, (char *)buf, (unsigned)buf_len); 420 421 if (len != (int)buf_len) error(gzerror(out, &err)); 422 423 munmap(buf, buf_len); 424 fclose(in); 425 if (gzclose(out) != Z_OK) error("failed gzclose"); 426 return Z_OK; 427 } 428 #endif /* USE_MMAP */ 429 430 /* =========================================================================== 431 * Uncompress input to output then close both files. 432 */ 433 void gz_uncompress(in, out) 434 gzFile in; 435 FILE *out; 436 { 437 local char buf[BUFLEN]; 438 int len; 439 int err; 440 441 for (;;) { 442 len = gzread(in, buf, sizeof(buf)); 443 if (len < 0) error (gzerror(in, &err)); 444 if (len == 0) break; 445 446 if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { 447 error("failed fwrite"); 448 } 449 } 450 if (fclose(out)) error("failed fclose"); 451 452 if (gzclose(in) != Z_OK) error("failed gzclose"); 453 } 454 455 456 /* =========================================================================== 457 * Compress the given file: create a corresponding .gz file and remove the 458 * original. 459 */ 460 void file_compress(file, mode) 461 char *file; 462 char *mode; 463 { 464 local char outfile[MAX_NAME_LEN]; 465 FILE *in; 466 gzFile out; 467 468 if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { 469 fprintf(stderr, "%s: filename too long\n", prog); 470 exit(1); 471 } 472 473 #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 474 snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); 475 #else 476 strcpy(outfile, file); 477 strcat(outfile, GZ_SUFFIX); 478 #endif 479 480 in = fopen(file, "rb"); 481 if (in == NULL) { 482 perror(file); 483 exit(1); 484 } 485 out = gzopen(outfile, mode); 486 if (out == NULL) { 487 fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); 488 exit(1); 489 } 490 gz_compress(in, out); 491 492 unlink(file); 493 } 494 495 496 /* =========================================================================== 497 * Uncompress the given file and remove the original. 498 */ 499 void file_uncompress(file) 500 char *file; 501 { 502 local char buf[MAX_NAME_LEN]; 503 char *infile, *outfile; 504 FILE *out; 505 gzFile in; 506 size_t len = strlen(file); 507 508 if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { 509 fprintf(stderr, "%s: filename too long\n", prog); 510 exit(1); 511 } 512 513 #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 514 snprintf(buf, sizeof(buf), "%s", file); 515 #else 516 strcpy(buf, file); 517 #endif 518 519 if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { 520 infile = file; 521 outfile = buf; 522 outfile[len-3] = '\0'; 523 } else { 524 outfile = file; 525 infile = buf; 526 #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 527 snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); 528 #else 529 strcat(infile, GZ_SUFFIX); 530 #endif 531 } 532 in = gzopen(infile, "rb"); 533 if (in == NULL) { 534 fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); 535 exit(1); 536 } 537 out = fopen(outfile, "wb"); 538 if (out == NULL) { 539 perror(file); 540 exit(1); 541 } 542 543 gz_uncompress(in, out); 544 545 unlink(infile); 546 } 547 548 549 /* =========================================================================== 550 * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] 551 * -c : write to standard output 552 * -d : decompress 553 * -f : compress with Z_FILTERED 554 * -h : compress with Z_HUFFMAN_ONLY 555 * -r : compress with Z_RLE 556 * -1 to -9 : compression level 557 */ 558 559 int main(argc, argv) 560 int argc; 561 char *argv[]; 562 { 563 int copyout = 0; 564 int uncompr = 0; 565 gzFile file; 566 char *bname, outmode[20]; 567 568 #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 569 snprintf(outmode, sizeof(outmode), "%s", "wb6 "); 570 #else 571 strcpy(outmode, "wb6 "); 572 #endif 573 574 prog = argv[0]; 575 bname = strrchr(argv[0], '/'); 576 if (bname) 577 bname++; 578 else 579 bname = argv[0]; 580 argc--, argv++; 581 582 if (!strcmp(bname, "gunzip")) 583 uncompr = 1; 584 else if (!strcmp(bname, "zcat")) 585 copyout = uncompr = 1; 586 587 while (argc > 0) { 588 if (strcmp(*argv, "-c") == 0) 589 copyout = 1; 590 else if (strcmp(*argv, "-d") == 0) 591 uncompr = 1; 592 else if (strcmp(*argv, "-f") == 0) 593 outmode[3] = 'f'; 594 else if (strcmp(*argv, "-h") == 0) 595 outmode[3] = 'h'; 596 else if (strcmp(*argv, "-r") == 0) 597 outmode[3] = 'R'; 598 else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && 599 (*argv)[2] == 0) 600 outmode[2] = (*argv)[1]; 601 else 602 break; 603 argc--, argv++; 604 } 605 if (outmode[3] == ' ') 606 outmode[3] = 0; 607 if (argc == 0) { 608 SET_BINARY_MODE(stdin); 609 SET_BINARY_MODE(stdout); 610 if (uncompr) { 611 file = gzdopen(fileno(stdin), "rb"); 612 if (file == NULL) error("can't gzdopen stdin"); 613 gz_uncompress(file, stdout); 614 } else { 615 file = gzdopen(fileno(stdout), outmode); 616 if (file == NULL) error("can't gzdopen stdout"); 617 gz_compress(stdin, file); 618 } 619 } else { 620 if (copyout) { 621 SET_BINARY_MODE(stdout); 622 } 623 do { 624 if (uncompr) { 625 if (copyout) { 626 file = gzopen(*argv, "rb"); 627 if (file == NULL) 628 fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); 629 else 630 gz_uncompress(file, stdout); 631 } else { 632 file_uncompress(*argv); 633 } 634 } else { 635 if (copyout) { 636 FILE * in = fopen(*argv, "rb"); 637 638 if (in == NULL) { 639 perror(*argv); 640 } else { 641 file = gzdopen(fileno(stdout), outmode); 642 if (file == NULL) error("can't gzdopen stdout"); 643 644 gz_compress(in, file); 645 } 646 647 } else { 648 file_compress(*argv, outmode); 649 } 650 } 651 } while (argv++, --argc); 652 } 653 return 0; 654 } 655