1 |
/* gzwrite.c -- zlib functions for writing gzip files |
2 |
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler |
3 |
* For conditions of distribution and use, see copyright notice in zlib.h |
4 |
*/ |
5 |
|
6 |
#include "gzguts.h" |
7 |
|
8 |
/* Local functions */ |
9 |
local int gz_init OF((gz_statep)); |
10 |
local int gz_comp OF((gz_statep, int)); |
11 |
local int gz_zero OF((gz_statep, z_off64_t)); |
12 |
|
13 |
/* Initialize state for writing a gzip file. Mark initialization by setting |
14 |
state->size to non-zero. Return -1 on failure or 0 on success. */ |
15 |
local int gz_init(state) |
16 |
gz_statep state; |
17 |
{ |
18 |
int ret; |
19 |
z_streamp strm = &(state->strm); |
20 |
|
21 |
/* allocate input buffer */ |
22 |
state->in = (unsigned char *)malloc(state->want); |
23 |
if (state->in == NULL) { |
24 |
gz_error(state, Z_MEM_ERROR, "out of memory"); |
25 |
return -1; |
26 |
} |
27 |
|
28 |
/* only need output buffer and deflate state if compressing */ |
29 |
if (!state->direct) { |
30 |
/* allocate output buffer */ |
31 |
state->out = (unsigned char *)malloc(state->want); |
32 |
if (state->out == NULL) { |
33 |
free(state->in); |
34 |
gz_error(state, Z_MEM_ERROR, "out of memory"); |
35 |
return -1; |
36 |
} |
37 |
|
38 |
/* allocate deflate memory, set up for gzip compression */ |
39 |
strm->zalloc = Z_NULL; |
40 |
strm->zfree = Z_NULL; |
41 |
strm->opaque = Z_NULL; |
42 |
ret = deflateInit2(strm, state->level, Z_DEFLATED, |
43 |
MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); |
44 |
if (ret != Z_OK) { |
45 |
free(state->out); |
46 |
free(state->in); |
47 |
gz_error(state, Z_MEM_ERROR, "out of memory"); |
48 |
return -1; |
49 |
} |
50 |
} |
51 |
|
52 |
/* mark state as initialized */ |
53 |
state->size = state->want; |
54 |
|
55 |
/* initialize write buffer if compressing */ |
56 |
if (!state->direct) { |
57 |
strm->avail_out = state->size; |
58 |
strm->next_out = state->out; |
59 |
state->x.next = strm->next_out; |
60 |
} |
61 |
return 0; |
62 |
} |
63 |
|
64 |
/* Compress whatever is at avail_in and next_in and write to the output file. |
65 |
Return -1 if there is an error writing to the output file, otherwise 0. |
66 |
flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, |
67 |
then the deflate() state is reset to start a new gzip stream. If gz->direct |
68 |
is true, then simply write to the output file without compressing, and |
69 |
ignore flush. */ |
70 |
local int gz_comp(state, flush) |
71 |
gz_statep state; |
72 |
int flush; |
73 |
{ |
74 |
int ret, got; |
75 |
unsigned have; |
76 |
z_streamp strm = &(state->strm); |
77 |
|
78 |
/* allocate memory if this is the first time through */ |
79 |
if (state->size == 0 && gz_init(state) == -1) |
80 |
return -1; |
81 |
|
82 |
/* write directly if requested */ |
83 |
if (state->direct) { |
84 |
got = write(state->fd, strm->next_in, strm->avail_in); |
85 |
if (got < 0 || (unsigned)got != strm->avail_in) { |
86 |
gz_error(state, Z_ERRNO, zstrerror()); |
87 |
return -1; |
88 |
} |
89 |
strm->avail_in = 0; |
90 |
return 0; |
91 |
} |
92 |
|
93 |
/* run deflate() on provided input until it produces no more output */ |
94 |
ret = Z_OK; |
95 |
do { |
96 |
/* write out current buffer contents if full, or if flushing, but if |
97 |
doing Z_FINISH then don't write until we get to Z_STREAM_END */ |
98 |
if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && |
99 |
(flush != Z_FINISH || ret == Z_STREAM_END))) { |
100 |
have = (unsigned)(strm->next_out - state->x.next); |
101 |
if (have && ((got = write(state->fd, state->x.next, have)) < 0 || |
102 |
(unsigned)got != have)) { |
103 |
gz_error(state, Z_ERRNO, zstrerror()); |
104 |
return -1; |
105 |
} |
106 |
if (strm->avail_out == 0) { |
107 |
strm->avail_out = state->size; |
108 |
strm->next_out = state->out; |
109 |
} |
110 |
state->x.next = strm->next_out; |
111 |
} |
112 |
|
113 |
/* compress */ |
114 |
have = strm->avail_out; |
115 |
ret = deflate(strm, flush); |
116 |
if (ret == Z_STREAM_ERROR) { |
117 |
gz_error(state, Z_STREAM_ERROR, |
118 |
"internal error: deflate stream corrupt"); |
119 |
return -1; |
120 |
} |
121 |
have -= strm->avail_out; |
122 |
} while (have); |
123 |
|
124 |
/* if that completed a deflate stream, allow another to start */ |
125 |
if (flush == Z_FINISH) |
126 |
deflateReset(strm); |
127 |
|
128 |
/* all done, no errors */ |
129 |
return 0; |
130 |
} |
131 |
|
132 |
/* Compress len zeros to output. Return -1 on error, 0 on success. */ |
133 |
local int gz_zero(state, len) |
134 |
gz_statep state; |
135 |
z_off64_t len; |
136 |
{ |
137 |
int first; |
138 |
unsigned n; |
139 |
z_streamp strm = &(state->strm); |
140 |
|
141 |
/* consume whatever's left in the input buffer */ |
142 |
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) |
143 |
return -1; |
144 |
|
145 |
/* compress len zeros (len guaranteed > 0) */ |
146 |
first = 1; |
147 |
while (len) { |
148 |
n = GT_OFF(state->size) || (z_off64_t)state->size > len ? |
149 |
(unsigned)len : state->size; |
150 |
if (first) { |
151 |
memset(state->in, 0, n); |
152 |
first = 0; |
153 |
} |
154 |
strm->avail_in = n; |
155 |
strm->next_in = state->in; |
156 |
state->x.pos += n; |
157 |
if (gz_comp(state, Z_NO_FLUSH) == -1) |
158 |
return -1; |
159 |
len -= n; |
160 |
} |
161 |
return 0; |
162 |
} |
163 |
|
164 |
/* -- see zlib.h -- */ |
165 |
int ZEXPORT gzwrite(file, buf, len) |
166 |
gzFile file; |
167 |
voidpc buf; |
168 |
unsigned len; |
169 |
{ |
170 |
unsigned put = len; |
171 |
gz_statep state; |
172 |
z_streamp strm; |
173 |
|
174 |
/* get internal structure */ |
175 |
if (file == NULL) |
176 |
return 0; |
177 |
state = (gz_statep)file; |
178 |
strm = &(state->strm); |
179 |
|
180 |
/* check that we're writing and that there's no error */ |
181 |
if (state->mode != GZ_WRITE || state->err != Z_OK) |
182 |
return 0; |
183 |
|
184 |
/* since an int is returned, make sure len fits in one, otherwise return |
185 |
with an error (this avoids the flaw in the interface) */ |
186 |
if ((int)len < 0) { |
187 |
gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); |
188 |
return 0; |
189 |
} |
190 |
|
191 |
/* if len is zero, avoid unnecessary operations */ |
192 |
if (len == 0) |
193 |
return 0; |
194 |
|
195 |
/* allocate memory if this is the first time through */ |
196 |
if (state->size == 0 && gz_init(state) == -1) |
197 |
return 0; |
198 |
|
199 |
/* check for seek request */ |
200 |
if (state->seek) { |
201 |
state->seek = 0; |
202 |
if (gz_zero(state, state->skip) == -1) |
203 |
return 0; |
204 |
} |
205 |
|
206 |
/* for small len, copy to input buffer, otherwise compress directly */ |
207 |
if (len < state->size) { |
208 |
/* copy to input buffer, compress when full */ |
209 |
do { |
210 |
unsigned have, copy; |
211 |
|
212 |
if (strm->avail_in == 0) |
213 |
strm->next_in = state->in; |
214 |
have = (unsigned)((strm->next_in + strm->avail_in) - state->in); |
215 |
copy = state->size - have; |
216 |
if (copy > len) |
217 |
copy = len; |
218 |
memcpy(state->in + have, buf, copy); |
219 |
strm->avail_in += copy; |
220 |
state->x.pos += copy; |
221 |
buf = (const char *)buf + copy; |
222 |
len -= copy; |
223 |
if (len && gz_comp(state, Z_NO_FLUSH) == -1) |
224 |
return 0; |
225 |
} while (len); |
226 |
} |
227 |
else { |
228 |
/* consume whatever's left in the input buffer */ |
229 |
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) |
230 |
return 0; |
231 |
|
232 |
/* directly compress user buffer to file */ |
233 |
strm->avail_in = len; |
234 |
strm->next_in = (z_const Bytef *)buf; |
235 |
state->x.pos += len; |
236 |
if (gz_comp(state, Z_NO_FLUSH) == -1) |
237 |
return 0; |
238 |
} |
239 |
|
240 |
/* input was all buffered or compressed (put will fit in int) */ |
241 |
return (int)put; |
242 |
} |
243 |
|
244 |
/* -- see zlib.h -- */ |
245 |
int ZEXPORT gzputc(file, c) |
246 |
gzFile file; |
247 |
int c; |
248 |
{ |
249 |
unsigned have; |
250 |
unsigned char buf[1]; |
251 |
gz_statep state; |
252 |
z_streamp strm; |
253 |
|
254 |
/* get internal structure */ |
255 |
if (file == NULL) |
256 |
return -1; |
257 |
state = (gz_statep)file; |
258 |
strm = &(state->strm); |
259 |
|
260 |
/* check that we're writing and that there's no error */ |
261 |
if (state->mode != GZ_WRITE || state->err != Z_OK) |
262 |
return -1; |
263 |
|
264 |
/* check for seek request */ |
265 |
if (state->seek) { |
266 |
state->seek = 0; |
267 |
if (gz_zero(state, state->skip) == -1) |
268 |
return -1; |
269 |
} |
270 |
|
271 |
/* try writing to input buffer for speed (state->size == 0 if buffer not |
272 |
initialized) */ |
273 |
if (state->size) { |
274 |
if (strm->avail_in == 0) |
275 |
strm->next_in = state->in; |
276 |
have = (unsigned)((strm->next_in + strm->avail_in) - state->in); |
277 |
if (have < state->size) { |
278 |
state->in[have] = c; |
279 |
strm->avail_in++; |
280 |
state->x.pos++; |
281 |
return c & 0xff; |
282 |
} |
283 |
} |
284 |
|
285 |
/* no room in buffer or not initialized, use gz_write() */ |
286 |
buf[0] = c; |
287 |
if (gzwrite(file, buf, 1) != 1) |
288 |
return -1; |
289 |
return c & 0xff; |
290 |
} |
291 |
|
292 |
/* -- see zlib.h -- */ |
293 |
int ZEXPORT gzputs(file, str) |
294 |
gzFile file; |
295 |
const char *str; |
296 |
{ |
297 |
int ret; |
298 |
unsigned len; |
299 |
|
300 |
/* write string */ |
301 |
len = (unsigned)strlen(str); |
302 |
ret = gzwrite(file, str, len); |
303 |
return ret == 0 && len != 0 ? -1 : ret; |
304 |
} |
305 |
|
306 |
#if defined(STDC) || defined(Z_HAVE_STDARG_H) |
307 |
#include <stdarg.h> |
308 |
|
309 |
/* -- see zlib.h -- */ |
310 |
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) |
311 |
{ |
312 |
int size, len; |
313 |
gz_statep state; |
314 |
z_streamp strm; |
315 |
|
316 |
/* get internal structure */ |
317 |
if (file == NULL) |
318 |
return -1; |
319 |
state = (gz_statep)file; |
320 |
strm = &(state->strm); |
321 |
|
322 |
/* check that we're writing and that there's no error */ |
323 |
if (state->mode != GZ_WRITE || state->err != Z_OK) |
324 |
return 0; |
325 |
|
326 |
/* make sure we have some buffer space */ |
327 |
if (state->size == 0 && gz_init(state) == -1) |
328 |
return 0; |
329 |
|
330 |
/* check for seek request */ |
331 |
if (state->seek) { |
332 |
state->seek = 0; |
333 |
if (gz_zero(state, state->skip) == -1) |
334 |
return 0; |
335 |
} |
336 |
|
337 |
/* consume whatever's left in the input buffer */ |
338 |
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) |
339 |
return 0; |
340 |
|
341 |
/* do the printf() into the input buffer, put length in len */ |
342 |
size = (int)(state->size); |
343 |
state->in[size - 1] = 0; |
344 |
#ifdef NO_vsnprintf |
345 |
# ifdef HAS_vsprintf_void |
346 |
(void)vsprintf((char *)(state->in), format, va); |
347 |
for (len = 0; len < size; len++) |
348 |
if (state->in[len] == 0) break; |
349 |
# else |
350 |
len = vsprintf((char *)(state->in), format, va); |
351 |
# endif |
352 |
#else |
353 |
# ifdef HAS_vsnprintf_void |
354 |
(void)vsnprintf((char *)(state->in), size, format, va); |
355 |
len = strlen((char *)(state->in)); |
356 |
# else |
357 |
len = vsnprintf((char *)(state->in), size, format, va); |
358 |
# endif |
359 |
#endif |
360 |
|
361 |
/* check that printf() results fit in buffer */ |
362 |
if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) |
363 |
return 0; |
364 |
|
365 |
/* update buffer and position, defer compression until needed */ |
366 |
strm->avail_in = (unsigned)len; |
367 |
strm->next_in = state->in; |
368 |
state->x.pos += len; |
369 |
return len; |
370 |
} |
371 |
|
372 |
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) |
373 |
{ |
374 |
va_list va; |
375 |
int ret; |
376 |
|
377 |
va_start(va, format); |
378 |
ret = gzvprintf(file, format, va); |
379 |
va_end(va); |
380 |
return ret; |
381 |
} |
382 |
|
383 |
#else /* !STDC && !Z_HAVE_STDARG_H */ |
384 |
|
385 |
/* -- see zlib.h -- */ |
386 |
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, |
387 |
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) |
388 |
gzFile file; |
389 |
const char *format; |
390 |
int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, |
391 |
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; |
392 |
{ |
393 |
int size, len; |
394 |
gz_statep state; |
395 |
z_streamp strm; |
396 |
|
397 |
/* get internal structure */ |
398 |
if (file == NULL) |
399 |
return -1; |
400 |
state = (gz_statep)file; |
401 |
strm = &(state->strm); |
402 |
|
403 |
/* check that can really pass pointer in ints */ |
404 |
if (sizeof(int) != sizeof(void *)) |
405 |
return 0; |
406 |
|
407 |
/* check that we're writing and that there's no error */ |
408 |
if (state->mode != GZ_WRITE || state->err != Z_OK) |
409 |
return 0; |
410 |
|
411 |
/* make sure we have some buffer space */ |
412 |
if (state->size == 0 && gz_init(state) == -1) |
413 |
return 0; |
414 |
|
415 |
/* check for seek request */ |
416 |
if (state->seek) { |
417 |
state->seek = 0; |
418 |
if (gz_zero(state, state->skip) == -1) |
419 |
return 0; |
420 |
} |
421 |
|
422 |
/* consume whatever's left in the input buffer */ |
423 |
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) |
424 |
return 0; |
425 |
|
426 |
/* do the printf() into the input buffer, put length in len */ |
427 |
size = (int)(state->size); |
428 |
state->in[size - 1] = 0; |
429 |
#ifdef NO_snprintf |
430 |
# ifdef HAS_sprintf_void |
431 |
sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, |
432 |
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); |
433 |
for (len = 0; len < size; len++) |
434 |
if (state->in[len] == 0) break; |
435 |
# else |
436 |
len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, |
437 |
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); |
438 |
# endif |
439 |
#else |
440 |
# ifdef HAS_snprintf_void |
441 |
snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, |
442 |
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); |
443 |
len = strlen((char *)(state->in)); |
444 |
# else |
445 |
len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, |
446 |
a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, |
447 |
a19, a20); |
448 |
# endif |
449 |
#endif |
450 |
|
451 |
/* check that printf() results fit in buffer */ |
452 |
if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) |
453 |
return 0; |
454 |
|
455 |
/* update buffer and position, defer compression until needed */ |
456 |
strm->avail_in = (unsigned)len; |
457 |
strm->next_in = state->in; |
458 |
state->x.pos += len; |
459 |
return len; |
460 |
} |
461 |
|
462 |
#endif |
463 |
|
464 |
/* -- see zlib.h -- */ |
465 |
int ZEXPORT gzflush(file, flush) |
466 |
gzFile file; |
467 |
int flush; |
468 |
{ |
469 |
gz_statep state; |
470 |
|
471 |
/* get internal structure */ |
472 |
if (file == NULL) |
473 |
return -1; |
474 |
state = (gz_statep)file; |
475 |
|
476 |
/* check that we're writing and that there's no error */ |
477 |
if (state->mode != GZ_WRITE || state->err != Z_OK) |
478 |
return Z_STREAM_ERROR; |
479 |
|
480 |
/* check flush parameter */ |
481 |
if (flush < 0 || flush > Z_FINISH) |
482 |
return Z_STREAM_ERROR; |
483 |
|
484 |
/* check for seek request */ |
485 |
if (state->seek) { |
486 |
state->seek = 0; |
487 |
if (gz_zero(state, state->skip) == -1) |
488 |
return -1; |
489 |
} |
490 |
|
491 |
/* compress remaining data with requested flush */ |
492 |
gz_comp(state, flush); |
493 |
return state->err; |
494 |
} |
495 |
|
496 |
/* -- see zlib.h -- */ |
497 |
int ZEXPORT gzsetparams(file, level, strategy) |
498 |
gzFile file; |
499 |
int level; |
500 |
int strategy; |
501 |
{ |
502 |
gz_statep state; |
503 |
z_streamp strm; |
504 |
|
505 |
/* get internal structure */ |
506 |
if (file == NULL) |
507 |
return Z_STREAM_ERROR; |
508 |
state = (gz_statep)file; |
509 |
strm = &(state->strm); |
510 |
|
511 |
/* check that we're writing and that there's no error */ |
512 |
if (state->mode != GZ_WRITE || state->err != Z_OK) |
513 |
return Z_STREAM_ERROR; |
514 |
|
515 |
/* if no change is requested, then do nothing */ |
516 |
if (level == state->level && strategy == state->strategy) |
517 |
return Z_OK; |
518 |
|
519 |
/* check for seek request */ |
520 |
if (state->seek) { |
521 |
state->seek = 0; |
522 |
if (gz_zero(state, state->skip) == -1) |
523 |
return -1; |
524 |
} |
525 |
|
526 |
/* change compression parameters for subsequent input */ |
527 |
if (state->size) { |
528 |
/* flush previous input with previous parameters before changing */ |
529 |
if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) |
530 |
return state->err; |
531 |
deflateParams(strm, level, strategy); |
532 |
} |
533 |
state->level = level; |
534 |
state->strategy = strategy; |
535 |
return Z_OK; |
536 |
} |
537 |
|
538 |
/* -- see zlib.h -- */ |
539 |
int ZEXPORT gzclose_w(file) |
540 |
gzFile file; |
541 |
{ |
542 |
int ret = Z_OK; |
543 |
gz_statep state; |
544 |
|
545 |
/* get internal structure */ |
546 |
if (file == NULL) |
547 |
return Z_STREAM_ERROR; |
548 |
state = (gz_statep)file; |
549 |
|
550 |
/* check that we're writing */ |
551 |
if (state->mode != GZ_WRITE) |
552 |
return Z_STREAM_ERROR; |
553 |
|
554 |
/* check for seek request */ |
555 |
if (state->seek) { |
556 |
state->seek = 0; |
557 |
if (gz_zero(state, state->skip) == -1) |
558 |
ret = state->err; |
559 |
} |
560 |
|
561 |
/* flush, free memory, and close file */ |
562 |
if (gz_comp(state, Z_FINISH) == -1) |
563 |
ret = state->err; |
564 |
if (state->size) { |
565 |
if (!state->direct) { |
566 |
(void)deflateEnd(&(state->strm)); |
567 |
free(state->out); |
568 |
} |
569 |
free(state->in); |
570 |
} |
571 |
gz_error(state, Z_OK, NULL); |
572 |
free(state->path); |
573 |
if (close(state->fd) == -1) |
574 |
ret = Z_ERRNO; |
575 |
free(state); |
576 |
return ret; |
577 |
} |