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