1 /* Compresses a user-specified number of chunks from stdin into stdout as a single gzip stream.
2 * Each chunk is compressed with a user-specified level.
3 */
4
5 #include "zbuild.h"
6 #ifdef ZLIB_COMPAT
7 # include "zlib.h"
8 #else
9 # include "zlib-ng.h"
10 #endif
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #if defined(_WIN32) || defined(__CYGWIN__)
17 # include <fcntl.h>
18 # include <io.h>
19 # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
20 #else
21 # define SET_BINARY_MODE(file)
22 #endif
23
read_all(unsigned char * buf,size_t size)24 static int read_all(unsigned char *buf, size_t size) {
25 size_t total_read = 0;
26 while (total_read < size) {
27 size_t n_read = fread(buf + total_read, 1, size - total_read, stdin);
28 if (ferror(stdin)) {
29 perror("fread\n");
30 return 1;
31 }
32 if (n_read == 0) {
33 fprintf(stderr, "Premature EOF\n");
34 return 1;
35 }
36 total_read += n_read;
37 }
38 return 0;
39 }
40
write_all(unsigned char * buf,size_t size)41 static int write_all(unsigned char *buf, size_t size) {
42 size_t total_written = 0;
43 while (total_written < size) {
44 size_t n_written = fwrite(buf + total_written, 1, size - total_written, stdout);
45 if (ferror(stdout)) {
46 perror("fwrite\n");
47 return 1;
48 }
49 total_written += n_written;
50 }
51 return 0;
52 }
53
compress_chunk(PREFIX3 (stream)* strm,int level,int size,int last)54 static int compress_chunk(PREFIX3(stream) *strm, int level, int size, int last) {
55 int ret = 1;
56 int err = 0;
57 unsigned long compsize;
58 unsigned char *buf;
59
60 if (size <= 0) {
61 fprintf(stderr, "compress_chunk() invalid size %d\n", size);
62 goto done;
63 }
64 if (level < 0 || level > 9) {
65 fprintf(stderr, "compress_chunk() invalid level %d\n", level);
66 goto done;
67 }
68
69 err = PREFIX(deflateParams)(strm, level, Z_DEFAULT_STRATEGY);
70 if (err != Z_OK) {
71 fprintf(stderr, "deflateParams() failed with code %d\n", err);
72 goto done;
73 }
74
75 compsize = 100 + 2 * PREFIX(deflateBound)(strm, size);
76 buf = malloc(size + compsize);
77 if (buf == NULL) {
78 fprintf(stderr, "Out of memory\n");
79 goto done;
80 }
81 if (read_all(buf, size) != 0) {
82 goto free_buf;
83 }
84
85 strm->next_in = buf;
86 strm->avail_in = size;
87 strm->next_out = buf + size;
88 strm->avail_out = compsize;
89
90 err = PREFIX(deflate)(strm, last ? Z_FINISH : Z_SYNC_FLUSH);
91 if ((!last && err != Z_OK) || (last && err != Z_STREAM_END)) {
92 fprintf(stderr, "deflate() failed with code %d\n", err);
93 goto free_buf;
94 }
95 if (strm->avail_in != 0) {
96 fprintf(stderr, "deflate() did not consume %d bytes of input\n", strm->avail_in);
97 goto free_buf;
98 }
99 if (write_all(buf + size, compsize - strm->avail_out) != 0) {
100 goto free_buf;
101 }
102 ret = 0;
103
104 free_buf:
105 free(buf);
106 done:
107 return ret;
108 }
109
show_help(void)110 void show_help(void)
111 {
112 printf("Usage: switchlevels [-w bits] level1 size1 [level2 size2 ...]\n\n" \
113 " -w : window bits (8 to 15 for gzip, -8 to -15 for zlib)\n\n");
114 }
115
main(int argc,char ** argv)116 int main(int argc, char **argv) {
117 int ret = EXIT_FAILURE;
118 int err = 0;
119 int size = 0;
120 int level = Z_DEFAULT_COMPRESSION;
121 int level_arg = 1;
122 int window_bits = MAX_WBITS + 16;
123 PREFIX3(stream) strm;
124
125
126 if ((argc == 1) || (argc == 2 && strcmp(argv[1], "--help") == 0)) {
127 show_help();
128 return 0;
129 }
130
131 SET_BINARY_MODE(stdin);
132 SET_BINARY_MODE(stdout);
133
134 memset(&strm, 0, sizeof(strm));
135
136 for (int i = 1; i < argc - 1; i++) {
137 if (strcmp(argv[i], "-w") == 0 && i+1 < argc) {
138 window_bits = atoi(argv[++i]);
139 } else {
140 level_arg = i;
141 level = atoi(argv[i]);
142 break;
143 }
144 }
145
146 err = PREFIX(deflateInit2)(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
147 if (err != Z_OK) {
148 fprintf(stderr, "deflateInit() failed with code %d\n", err);
149 goto done;
150 }
151
152 for (int i = level_arg; i < argc - 1; i += 2) {
153 level = atoi(argv[i]);
154 size = atoi(argv[i + 1]);
155 if (compress_chunk(&strm, level, size, i + 2 >= argc - 1) != 0) {
156 goto deflate_end;
157 }
158 }
159 ret = EXIT_SUCCESS;
160
161 deflate_end:
162 PREFIX(deflateEnd)(&strm);
163 done:
164 return ret;
165 }
166