| 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 | { |
| 8 | FILE* f = fopen(p, "rb"); |
| 9 | if (!f) return 1; |
| 10 | if (fseek(f, 0, SEEK_END) != 0) |
| 11 | { |
| 12 | fclose(f); |
| 13 | return 1; |
| 14 | } |
| 15 | long s = ftell(f); |
| 16 | if (s < 0) |
| 17 | { |
| 18 | fclose(f); |
| 19 | return 1; |
| 20 | } |
| 21 | if (fseek(f, 0, SEEK_SET) != 0) |
| 22 | { |
| 23 | fclose(f); |
| 24 | return 1; |
| 25 | } |
| 26 | *n = (size_t)s; |
| 27 | *o = *n ? (unsigned char*)malloc(*n) : NULL; |
| 28 | if (*n && !*o) |
| 29 | { |
| 30 | fclose(f); |
| 31 | return 1; |
| 32 | } |
| 33 | if (*n && fread(*o, 1, *n, f) != *n) |
| 34 | { |
| 35 | free(*o); |
| 36 | fclose(f); |
| 37 | return 1; |
| 38 | } |
| 39 | fclose(f); |
| 40 | return 0; |
| 41 | } |
| 42 | |
| 43 | static int wf(const char* p, const unsigned char* b, size_t n) |
| 44 | { |
| 45 | FILE* f = fopen(p, "wb"); |
| 46 | if (!f) return 1; |
| 47 | if (n && fwrite(b, 1, n, f) != n) |
| 48 | { |
| 49 | fclose(f); |
| 50 | return 1; |
| 51 | } |
| 52 | fclose(f); |
| 53 | return 0; |
| 54 | } |
| 55 | |
| 56 | int main(int argc, char** argv) |
| 57 | { |
| 58 | static const unsigned char dummy = 0; |
| 59 | if (argc != 4) |
| 60 | { |
| 61 | fputs("usage: zlib_ref compress|decompress in out\n", stderr); |
| 62 | return 2; |
| 63 | } |
| 64 | unsigned char* in = NULL; |
| 65 | size_t in_n = 0; |
| 66 | if (rf(argv[2], &in, &in_n)) |
| 67 | { |
| 68 | fputs("read error\n", stderr); |
| 69 | return 1; |
| 70 | } |
| 71 | const unsigned char* in_ptr = in_n ? in : &dummy; |
| 72 | if (strcmp(argv[1], "compress") == 0) |
| 73 | { |
| 74 | uLongf out_n = compressBound((uLong)in_n); |
| 75 | unsigned char* out = (unsigned char*)malloc(out_n ? out_n : 1); |
| 76 | if (!out) |
| 77 | { |
| 78 | free(in); |
| 79 | return 1; |
| 80 | } |
| 81 | if (compress2(out, &out_n, in_ptr, (uLong)in_n, Z_DEFAULT_COMPRESSION) != Z_OK) |
| 82 | { |
| 83 | fputs("compress2 failed\n", stderr); |
| 84 | free(in); |
| 85 | free(out); |
| 86 | return 1; |
| 87 | } |
| 88 | if (wf(argv[3], out, (size_t)out_n)) |
| 89 | { |
| 90 | fputs("write error\n", stderr); |
| 91 | free(in); |
| 92 | free(out); |
| 93 | return 1; |
| 94 | } |
| 95 | free(out); |
| 96 | } |
| 97 | else if (strcmp(argv[1], "decompress") == 0) |
| 98 | { |
| 99 | uLongf out_n = in_n * 8 + 64; |
| 100 | if (out_n < 256) out_n = 256; |
| 101 | unsigned char* out = NULL; |
| 102 | int rc = Z_BUF_ERROR; |
| 103 | while (rc == Z_BUF_ERROR) |
| 104 | { |
| 105 | unsigned char* next = (unsigned char*)realloc(out, out_n); |
| 106 | if (!next) |
| 107 | { |
| 108 | free(in); |
| 109 | free(out); |
| 110 | return 1; |
| 111 | } |
| 112 | out = next; |
| 113 | uLongf cap = out_n; |
| 114 | rc = uncompress(out, &cap, in_ptr, (uLong)in_n); |
| 115 | if (rc == Z_OK) |
| 116 | { |
| 117 | out_n = cap; |
| 118 | break; |
| 119 | } |
| 120 | if (rc == Z_BUF_ERROR) |
| 121 | { |
| 122 | out_n *= 2; |
| 123 | if (out_n < 256) out_n = 256; |
| 124 | } |
| 125 | } |
| 126 | if (rc != Z_OK) |
| 127 | { |
| 128 | fputs("uncompress failed\n", stderr); |
| 129 | free(in); |
| 130 | free(out); |
| 131 | return 1; |
| 132 | } |
| 133 | if (wf(argv[3], out, (size_t)out_n)) |
| 134 | { |
| 135 | fputs("write error\n", stderr); |
| 136 | free(in); |
| 137 | free(out); |
| 138 | return 1; |
| 139 | } |
| 140 | free(out); |
| 141 | } |
| 142 | else |
| 143 | { |
| 144 | fputs("unknown mode\n", stderr); |
| 145 | free(in); |
| 146 | return 2; |
| 147 | } |
| 148 | free(in); |
| 149 | return 0; |
| 150 | } |
| 151 | |