minigzip.c 15 KB

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