1 /* gzwrite.c contains minimal changes required to be compiled with zlibWrapper:
2 * - gz_statep was converted to union to work with -Wstrict-aliasing=1 */
4 /* gzwrite.c -- zlib functions for writing gzip files
5 * Copyright (C) 2004-2017 Mark Adler
6 * For conditions of distribution and use, see https://www.zlib.net/zlib_license.html
14 local int gz_init _Z_OF((gz_statep));
15 local int gz_comp _Z_OF((gz_statep, int));
16 local int gz_zero _Z_OF((gz_statep, z_off64_t));
17 local z_size_t gz_write _Z_OF((gz_statep, voidpc, z_size_t));
19 /* Initialize state for writing a gzip file. Mark initialization by setting
20 state.state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
22 local int gz_init(state)
26 z_streamp strm = &(state.state->strm);
28 /* allocate input buffer (double size for gzprintf) */
29 state.state->in = (unsigned char*)malloc(state.state->want << 1);
30 if (state.state->in == NULL) {
31 gz_error(state, Z_MEM_ERROR, "out of memory");
35 /* only need output buffer and deflate state if compressing */
36 if (!state.state->direct) {
37 /* allocate output buffer */
38 state.state->out = (unsigned char*)malloc(state.state->want);
39 if (state.state->out == NULL) {
40 free(state.state->in);
41 gz_error(state, Z_MEM_ERROR, "out of memory");
45 /* allocate deflate memory, set up for gzip compression */
46 strm->zalloc = Z_NULL;
48 strm->opaque = Z_NULL;
49 ret = deflateInit2(strm, state.state->level, Z_DEFLATED,
50 MAX_WBITS + 16, DEF_MEM_LEVEL, state.state->strategy);
52 free(state.state->out);
53 free(state.state->in);
54 gz_error(state, Z_MEM_ERROR, "out of memory");
60 /* mark state as initialized */
61 state.state->size = state.state->want;
63 /* initialize write buffer if compressing */
64 if (!state.state->direct) {
65 strm->avail_out = state.state->size;
66 strm->next_out = state.state->out;
67 state.state->x.next = strm->next_out;
72 /* Compress whatever is at avail_in and next_in and write to the output file.
73 Return -1 if there is an error writing to the output file or if gz_init()
74 fails to allocate memory, otherwise 0. flush is assumed to be a valid
75 deflate() flush value. If flush is Z_FINISH, then the deflate() state is
76 reset to start a new gzip stream. If gz->direct is true, then simply write
77 to the output file without compressing, and ignore flush. */
78 local int gz_comp(state, flush)
83 unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
84 z_streamp strm = &(state.state->strm);
86 /* allocate memory if this is the first time through */
87 if (state.state->size == 0 && gz_init(state) == -1)
90 /* write directly if requested */
91 if (state.state->direct) {
92 while (strm->avail_in) {
93 put = strm->avail_in > max ? max : strm->avail_in;
94 writ = (int)write(state.state->fd, strm->next_in, put);
96 gz_error(state, Z_ERRNO, zstrerror());
99 strm->avail_in -= (unsigned)writ;
100 strm->next_in += writ;
105 /* run deflate() on provided input until it produces no more output */
108 /* write out current buffer contents if full, or if flushing, but if
109 doing Z_FINISH then don't write until we get to Z_STREAM_END */
110 if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
111 (flush != Z_FINISH || ret == Z_STREAM_END))) {
112 while (strm->next_out > state.state->x.next) {
113 put = strm->next_out - state.state->x.next > (int)max ? max :
114 (unsigned)(strm->next_out - state.state->x.next);
115 writ = (int)write(state.state->fd, state.state->x.next, put);
117 gz_error(state, Z_ERRNO, zstrerror());
120 state.state->x.next += writ;
122 if (strm->avail_out == 0) {
123 strm->avail_out = state.state->size;
124 strm->next_out = state.state->out;
125 state.state->x.next = state.state->out;
130 have = strm->avail_out;
131 ret = deflate(strm, flush);
132 if (ret == Z_STREAM_ERROR) {
133 gz_error(state, Z_STREAM_ERROR,
134 "internal error: deflate stream corrupt");
137 have -= strm->avail_out;
140 /* if that completed a deflate stream, allow another to start */
141 if (flush == Z_FINISH)
144 /* all done, no errors */
148 /* Compress len zeros to output. Return -1 on a write error or memory
149 allocation failure by gz_comp(), or 0 on success. */
150 local int gz_zero(state, len)
156 z_streamp strm = &(state.state->strm);
158 /* consume whatever's left in the input buffer */
159 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
162 /* compress len zeros (len guaranteed > 0) */
165 n = GT_OFF(state.state->size) || (z_off64_t)state.state->size > len ?
166 (unsigned)len : state.state->size;
168 memset(state.state->in, 0, n);
172 strm->next_in = state.state->in;
173 state.state->x.pos += n;
174 if (gz_comp(state, Z_NO_FLUSH) == -1)
181 /* Write len bytes from buf to file. Return the number of bytes written. If
182 the returned value is less than len, then there was an error. */
183 local z_size_t gz_write(state, buf, len)
190 /* if len is zero, avoid unnecessary operations */
194 /* allocate memory if this is the first time through */
195 if (state.state->size == 0 && gz_init(state) == -1)
198 /* check for seek request */
199 if (state.state->seek) {
200 state.state->seek = 0;
201 if (gz_zero(state, state.state->skip) == -1)
205 /* for small len, copy to input buffer, otherwise compress directly */
206 if (len < state.state->size) {
207 /* copy to input buffer, compress when full */
211 if (state.state->strm.avail_in == 0)
212 state.state->strm.next_in = state.state->in;
213 have = (unsigned)((state.state->strm.next_in + state.state->strm.avail_in) -
215 copy = state.state->size - have;
218 memcpy(state.state->in + have, buf, copy);
219 state.state->strm.avail_in += copy;
220 state.state->x.pos += copy;
221 buf = (const char *)buf + copy;
223 if (len && gz_comp(state, Z_NO_FLUSH) == -1)
228 /* consume whatever's left in the input buffer */
229 if (state.state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
232 /* directly compress user buffer to file */
233 state.state->strm.next_in = (z_const Bytef *)buf;
235 z_size_t n = (unsigned)-1;
238 state.state->strm.avail_in = (z_uInt)n;
239 state.state->x.pos += n;
240 if (gz_comp(state, Z_NO_FLUSH) == -1)
246 /* input was all buffered or compressed */
250 /* -- see zlib.h -- */
251 int ZEXPORT gzwrite(file, buf, len)
258 /* get internal structure */
263 /* check that we're writing and that there's no error */
264 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
267 /* since an int is returned, make sure len fits in one, otherwise return
268 with an error (this avoids a flaw in the interface) */
270 gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
274 /* write len bytes from buf (the return value will fit in an int) */
275 return (int)gz_write(state, buf, len);
278 /* -- see zlib.h -- */
279 z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
288 /* get internal structure */
294 /* check that we're writing and that there's no error */
295 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
298 /* compute bytes to read -- error on overflow */
300 if (size && (len / size != nitems)) {
301 gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
305 /* write len bytes to buf, return the number of full items written */
306 return len ? gz_write(state, buf, len) / size : 0;
309 /* -- see zlib.h -- */
310 int ZEXPORT gzputc(file, c)
315 unsigned char buf[1];
319 /* get internal structure */
323 strm = &(state.state->strm);
325 /* check that we're writing and that there's no error */
326 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
329 /* check for seek request */
330 if (state.state->seek) {
331 state.state->seek = 0;
332 if (gz_zero(state, state.state->skip) == -1)
336 /* try writing to input buffer for speed (state.state->size == 0 if buffer not
338 if (state.state->size) {
339 if (strm->avail_in == 0)
340 strm->next_in = state.state->in;
341 have = (unsigned)((strm->next_in + strm->avail_in) - state.state->in);
342 if (have < state.state->size) {
343 state.state->in[have] = (unsigned char)c;
345 state.state->x.pos++;
350 /* no room in buffer or not initialized, use gz_write() */
351 buf[0] = (unsigned char)c;
352 if (gz_write(state, buf, 1) != 1)
357 /* -- see zlib.h -- */
358 int ZEXPORT gzputs(file, str)
366 /* get internal structure */
371 /* check that we're writing and that there's no error */
372 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
377 ret = (int)gz_write(state, str, len);
378 return ret == 0 && len != 0 ? -1 : ret;
381 #if defined(STDC) || defined(Z_HAVE_STDARG_H)
384 /* -- see zlib.h -- */
385 int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
393 /* get internal structure */
395 return Z_STREAM_ERROR;
397 strm = &(state.state->strm);
399 /* check that we're writing and that there's no error */
400 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
401 return Z_STREAM_ERROR;
403 /* make sure we have some buffer space */
404 if (state.state->size == 0 && gz_init(state) == -1)
405 return state.state->err;
407 /* check for seek request */
408 if (state.state->seek) {
409 state.state->seek = 0;
410 if (gz_zero(state, state.state->skip) == -1)
411 return state.state->err;
414 /* do the printf() into the input buffer, put length in len -- the input
415 buffer is double-sized just for this function, so there is guaranteed to
416 be state.state->size bytes available after the current contents */
417 if (strm->avail_in == 0)
418 strm->next_in = state.state->in;
419 next = (char *)(state.state->in + (strm->next_in - state.state->in) + strm->avail_in);
420 next[state.state->size - 1] = 0;
422 # ifdef HAS_vsprintf_void
423 (void)vsprintf(next, format, va);
424 for (len = 0; len < state.state->size; len++)
425 if (next[len] == 0) break;
427 len = vsprintf(next, format, va);
430 # ifdef HAS_vsnprintf_void
431 (void)vsnprintf(next, state.state->size, format, va);
434 len = vsnprintf(next, state.state->size, format, va);
438 /* check that printf() results fit in buffer */
439 if (len == 0 || (unsigned)len >= state.state->size || next[state.state->size - 1] != 0)
442 /* update buffer and position, compress first half if past that */
443 strm->avail_in += (unsigned)len;
444 state.state->x.pos += len;
445 if (strm->avail_in >= state.state->size) {
446 left = strm->avail_in - state.state->size;
447 strm->avail_in = state.state->size;
448 if (gz_comp(state, Z_NO_FLUSH) == -1)
449 return state.state->err;
450 memcpy(state.state->in, state.state->in + state.state->size, left);
451 strm->next_in = state.state->in;
452 strm->avail_in = left;
457 int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
462 va_start(va, format);
463 ret = gzvprintf(file, format, va);
468 #else /* !STDC && !Z_HAVE_STDARG_H */
470 /* -- see zlib.h -- */
471 int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
472 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
475 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
476 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
483 /* get internal structure */
485 return Z_STREAM_ERROR;
486 state = (gz_statep)file;
487 strm = &(state.state->strm);
489 /* check that can really pass pointer in ints */
490 if (sizeof(int) != sizeof(void *))
491 return Z_STREAM_ERROR;
493 /* check that we're writing and that there's no error */
494 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
495 return Z_STREAM_ERROR;
497 /* make sure we have some buffer space */
498 if (state.state->size == 0 && gz_init(state) == -1)
499 return state.state->error;
501 /* check for seek request */
502 if (state.state->seek) {
503 state.state->seek = 0;
504 if (gz_zero(state, state.state->skip) == -1)
505 return state.state->error;
508 /* do the printf() into the input buffer, put length in len -- the input
509 buffer is double-sized just for this function, so there is guaranteed to
510 be state.state->size bytes available after the current contents */
511 if (strm->avail_in == 0)
512 strm->next_in = state.state->in;
513 next = (char *)(strm->next_in + strm->avail_in);
514 next[state.state->size - 1] = 0;
516 # ifdef HAS_sprintf_void
517 sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
518 a13, a14, a15, a16, a17, a18, a19, a20);
519 for (len = 0; len < size; len++)
523 len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
524 a12, a13, a14, a15, a16, a17, a18, a19, a20);
527 # ifdef HAS_snprintf_void
528 snprintf(next, state.state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,
529 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
532 len = snprintf(next, state.state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,
533 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
537 /* check that printf() results fit in buffer */
538 if (len == 0 || len >= state.state->size || next[state.state->size - 1] != 0)
541 /* update buffer and position, compress first half if past that */
542 strm->avail_in += len;
543 state.state->x.pos += len;
544 if (strm->avail_in >= state.state->size) {
545 left = strm->avail_in - state.state->size;
546 strm->avail_in = state.state->size;
547 if (gz_comp(state, Z_NO_FLUSH) == -1)
548 return state.state->err;
549 memcpy(state.state->in, state.state->in + state.state->size, left);
550 strm->next_in = state.state->in;
551 strm->avail_in = left;
558 /* -- see zlib.h -- */
559 int ZEXPORT gzflush(file, flush)
565 /* get internal structure */
567 return Z_STREAM_ERROR;
570 /* check that we're writing and that there's no error */
571 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
572 return Z_STREAM_ERROR;
574 /* check flush parameter */
575 if (flush < 0 || flush > Z_FINISH)
576 return Z_STREAM_ERROR;
578 /* check for seek request */
579 if (state.state->seek) {
580 state.state->seek = 0;
581 if (gz_zero(state, state.state->skip) == -1)
582 return state.state->err;
585 /* compress remaining data with requested flush */
586 (void)gz_comp(state, flush);
587 return state.state->err;
590 /* -- see zlib.h -- */
591 int ZEXPORT gzsetparams(file, level, strategy)
599 /* get internal structure */
601 return Z_STREAM_ERROR;
603 strm = &(state.state->strm);
605 /* check that we're writing and that there's no error */
606 if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
607 return Z_STREAM_ERROR;
609 /* if no change is requested, then do nothing */
610 if (level == state.state->level && strategy == state.state->strategy)
613 /* check for seek request */
614 if (state.state->seek) {
615 state.state->seek = 0;
616 if (gz_zero(state, state.state->skip) == -1)
617 return state.state->err;
620 /* change compression parameters for subsequent input */
621 if (state.state->size) {
622 /* flush previous input with previous parameters before changing */
623 if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
624 return state.state->err;
625 deflateParams(strm, level, strategy);
627 state.state->level = level;
628 state.state->strategy = strategy;
632 /* -- see zlib.h -- */
633 int ZEXPORT gzclose_w(file)
639 /* get internal structure */
641 return Z_STREAM_ERROR;
644 /* check that we're writing */
645 if (state.state->mode != GZ_WRITE)
646 return Z_STREAM_ERROR;
648 /* check for seek request */
649 if (state.state->seek) {
650 state.state->seek = 0;
651 if (gz_zero(state, state.state->skip) == -1)
652 ret = state.state->err;
655 /* flush, free memory, and close file */
656 if (gz_comp(state, Z_FINISH) == -1)
657 ret = state.state->err;
658 if (state.state->size) {
659 if (!state.state->direct) {
660 (void)deflateEnd(&(state.state->strm));
661 free(state.state->out);
663 free(state.state->in);
665 gz_error(state, Z_OK, NULL);
666 free(state.state->path);
667 if (close(state.state->fd) == -1)