• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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