| 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <string.h> |
| 4 | #include <zlib.h> |
| 5 | |
| 6 | static int rf(const char *p, unsigned char **o, size_t *n) { |
| 7 | FILE *f = fopen(p, "rb"); |
| 8 | if (!f) return 1; |
| 9 | fseek(f, 0, SEEK_END); |
| 10 | long s = ftell(f); |
| 11 | fseek(f, 0, SEEK_SET); |
| 12 | *o = malloc(*n = (size_t)s); |
| 13 | if (!*o) { |
| 14 | fclose(f); |
| 15 | return 1; |
| 16 | } |
| 17 | if (fread(*o, 1, *n, f) != *n) { |
| 18 | free(*o); |
| 19 | fclose(f); |
| 20 | return 1; |
| 21 | } |
| 22 | fclose(f); |
| 23 | return 0; |
| 24 | } |
| 25 | |
| 26 | static int wf(const char *p, const unsigned char *b, size_t n) { |
| 27 | FILE *f = fopen(p, "wb"); |
| 28 | if (!f) return 1; |
| 29 | if (fwrite(b, 1, n, f) != n) { |
| 30 | fclose(f); |
| 31 | return 1; |
| 32 | } |
| 33 | fclose(f); |
| 34 | return 0; |
| 35 | } |
| 36 | |
| 37 | int main(int argc, char **argv) { |
| 38 | if (argc != 4) { |
| 39 | fputs("usage: xval compress|decompress|gzip|gunzip in out\n", stderr); |
| 40 | return 2; |
| 41 | } |
| 42 | unsigned char *in; |
| 43 | size_t in_n; |
| 44 | if (rf(argv[2], &in, &in_n)) { |
| 45 | fputs("read error\n", stderr); |
| 46 | return 1; |
| 47 | } |
| 48 | |
| 49 | if (strcmp(argv[1], "compress") == 0) { |
| 50 | uLongf cap = compressBound((uLong)in_n); |
| 51 | unsigned char *out = malloc(cap); |
| 52 | if (!out) return 1; |
| 53 | if (compress2(out, &cap, in, (uLong)in_n, Z_DEFAULT_COMPRESSION) != Z_OK) { |
| 54 | fputs("compress2 failed\n", stderr); |
| 55 | free(in); |
| 56 | free(out); |
| 57 | return 1; |
| 58 | } |
| 59 | wf(argv[3], out, (size_t)cap); |
| 60 | free(out); |
| 61 | } else if (strcmp(argv[1], "decompress") == 0) { |
| 62 | uLongf cap = in_n * 8 + 65536; |
| 63 | unsigned char *out = malloc(cap); |
| 64 | if (!out) return 1; |
| 65 | if (uncompress(out, &cap, in, (uLong)in_n) != Z_OK) { |
| 66 | fputs("uncompress failed\n", stderr); |
| 67 | free(in); |
| 68 | free(out); |
| 69 | return 1; |
| 70 | } |
| 71 | wf(argv[3], out, (size_t)cap); |
| 72 | free(out); |
| 73 | } else if (strcmp(argv[1], "gzip") == 0) { |
| 74 | z_stream s; |
| 75 | memset(&s, 0, sizeof(s)); |
| 76 | if (deflateInit2(&s, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) { |
| 77 | free(in); |
| 78 | return 1; |
| 79 | } |
| 80 | uLongf cap = deflateBound(&s, (uLong)in_n) + 32; |
| 81 | unsigned char *out = malloc(cap); |
| 82 | if (!out) { |
| 83 | deflateEnd(&s); |
| 84 | free(in); |
| 85 | return 1; |
| 86 | } |
| 87 | s.next_in = in; |
| 88 | s.avail_in = (uInt)in_n; |
| 89 | s.next_out = out; |
| 90 | s.avail_out = (uInt)cap; |
| 91 | if (deflate(&s, Z_FINISH) != Z_STREAM_END) { |
| 92 | fputs("gzip deflate failed\n", stderr); |
| 93 | deflateEnd(&s); |
| 94 | free(in); |
| 95 | free(out); |
| 96 | return 1; |
| 97 | } |
| 98 | wf(argv[3], out, (size_t)s.total_out); |
| 99 | deflateEnd(&s); |
| 100 | free(out); |
| 101 | } else if (strcmp(argv[1], "gunzip") == 0) { |
| 102 | z_stream s; |
| 103 | memset(&s, 0, sizeof(s)); |
| 104 | if (inflateInit2(&s, 15 | 16) != Z_OK) { |
| 105 | free(in); |
| 106 | return 1; |
| 107 | } |
| 108 | uLongf cap = in_n * 8 + 65536; |
| 109 | unsigned char *out = malloc(cap); |
| 110 | if (!out) { |
| 111 | inflateEnd(&s); |
| 112 | free(in); |
| 113 | return 1; |
| 114 | } |
| 115 | s.next_in = in; |
| 116 | s.avail_in = (uInt)in_n; |
| 117 | s.next_out = out; |
| 118 | s.avail_out = (uInt)cap; |
| 119 | if (inflate(&s, Z_FINISH) != Z_STREAM_END) { |
| 120 | fputs("gunzip inflate failed\n", stderr); |
| 121 | inflateEnd(&s); |
| 122 | free(in); |
| 123 | free(out); |
| 124 | return 1; |
| 125 | } |
| 126 | wf(argv[3], out, (size_t)s.total_out); |
| 127 | inflateEnd(&s); |
| 128 | free(out); |
| 129 | } |
| 130 | |
| 131 | free(in); |
| 132 | return 0; |
| 133 | } |
| 134 | |
| 135 | |
| 136 | |