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 http://www.zlib.net/zlib_license.html
7 */
8
9#include <assert.h>
10
11#include "gzguts.h"
12
13/* Local functions */
14local int gz_init OF((gz_statep));
15local int gz_comp OF((gz_statep, int));
16local int gz_zero OF((gz_statep, z_off64_t));
17local z_size_t gz_write 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. */
22local int gz_init(state)
23    gz_statep state;
24{
25    int ret;
26    z_streamp strm = &(state.state->strm);
27
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");
32        return -1;
33    }
34
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");
42            return -1;
43        }
44
45        /* allocate deflate memory, set up for gzip compression */
46        strm->zalloc = Z_NULL;
47        strm->zfree = 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);
51        if (ret != Z_OK) {
52            free(state.state->out);
53            free(state.state->in);
54            gz_error(state, Z_MEM_ERROR, "out of memory");
55            return -1;
56        }
57        strm->next_in = NULL;
58    }
59
60    /* mark state as initialized */
61    state.state->size = state.state->want;
62
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;
68    }
69    return 0;
70}
71
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. */
78local int gz_comp(state, flush)
79    gz_statep state;
80    int flush;
81{
82    int ret, writ;
83    unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
84    z_streamp strm = &(state.state->strm);
85
86    /* allocate memory if this is the first time through */
87    if (state.state->size == 0 && gz_init(state) == -1)
88        return -1;
89
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);
95            if (writ < 0) {
96                gz_error(state, Z_ERRNO, zstrerror());
97                return -1;
98            }
99            strm->avail_in -= (unsigned)writ;
100            strm->next_in += writ;
101        }
102        return 0;
103    }
104
105    /* run deflate() on provided input until it produces no more output */
106    ret = Z_OK;
107    do {
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);
116                if (writ < 0) {
117                    gz_error(state, Z_ERRNO, zstrerror());
118                    return -1;
119                }
120                state.state->x.next += writ;
121            }
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;
126            }
127        }
128
129        /* compress */
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");
135            return -1;
136        }
137        have -= strm->avail_out;
138    } while (have);
139
140    /* if that completed a deflate stream, allow another to start */
141    if (flush == Z_FINISH)
142        deflateReset(strm);
143
144    /* all done, no errors */
145    return 0;
146}
147
148/* Compress len zeros to output.  Return -1 on a write error or memory
149   allocation failure by gz_comp(), or 0 on success. */
150local int gz_zero(state, len)
151    gz_statep state;
152    z_off64_t len;
153{
154    int first;
155    unsigned n;
156    z_streamp strm = &(state.state->strm);
157
158    /* consume whatever's left in the input buffer */
159    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
160        return -1;
161
162    /* compress len zeros (len guaranteed > 0) */
163    first = 1;
164    while (len) {
165        n = GT_OFF(state.state->size) || (z_off64_t)state.state->size > len ?
166            (unsigned)len : state.state->size;
167        if (first) {
168            memset(state.state->in, 0, n);
169            first = 0;
170        }
171        strm->avail_in = n;
172        strm->next_in = state.state->in;
173        state.state->x.pos += n;
174        if (gz_comp(state, Z_NO_FLUSH) == -1)
175            return -1;
176        len -= n;
177    }
178    return 0;
179}
180
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. */
183local z_size_t gz_write(state, buf, len)
184    gz_statep state;
185    voidpc buf;
186    z_size_t len;
187{
188    z_size_t put = len;
189
190    /* if len is zero, avoid unnecessary operations */
191    if (len == 0)
192        return 0;
193
194    /* allocate memory if this is the first time through */
195    if (state.state->size == 0 && gz_init(state) == -1)
196        return 0;
197
198    /* check for seek request */
199    if (state.state->seek) {
200        state.state->seek = 0;
201        if (gz_zero(state, state.state->skip) == -1)
202            return 0;
203    }
204
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 */
208        do {
209            z_size_t have, copy;
210
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) -
214                              state.state->in);
215            copy = state.state->size - have;
216            if (copy > len)
217                copy = len;
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;
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 (state.state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
230            return 0;
231
232        /* directly compress user buffer to file */
233        state.state->strm.next_in = (z_const Bytef *)buf;
234        do {
235            z_size_t n = (unsigned)-1;
236            if (n > len)
237                n = len;
238            state.state->strm.avail_in = (z_uInt)n;
239            state.state->x.pos += n;
240            if (gz_comp(state, Z_NO_FLUSH) == -1)
241                return 0;
242            len -= n;
243        } while (len);
244    }
245
246    /* input was all buffered or compressed */
247    return put;
248}
249
250/* -- see zlib.h -- */
251int ZEXPORT gzwrite(file, buf, len)
252    gzFile file;
253    voidpc buf;
254    unsigned len;
255{
256    gz_statep state;
257
258    /* get internal structure */
259    if (file == NULL)
260        return 0;
261    state.file = file;
262
263    /* check that we're writing and that there's no error */
264    if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
265        return 0;
266
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) */
269    if ((int)len < 0) {
270        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
271        return 0;
272    }
273
274    /* write len bytes from buf (the return value will fit in an int) */
275    return (int)gz_write(state, buf, len);
276}
277
278/* -- see zlib.h -- */
279z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
280    voidpc buf;
281    z_size_t size;
282    z_size_t nitems;
283    gzFile file;
284{
285    z_size_t len;
286    gz_statep state;
287
288    /* get internal structure */
289    assert(size != 0);
290    if (file == NULL)
291        return 0;
292    state.file = file;
293
294    /* check that we're writing and that there's no error */
295    if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
296        return 0;
297
298    /* compute bytes to read -- error on overflow */
299    len = nitems * size;
300    if (size && (len / size != nitems)) {
301        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
302        return 0;
303    }
304
305    /* write len bytes to buf, return the number of full items written */
306    return len ? gz_write(state, buf, len) / size : 0;
307}
308
309/* -- see zlib.h -- */
310int ZEXPORT gzputc(file, c)
311    gzFile file;
312    int c;
313{
314    unsigned have;
315    unsigned char buf[1];
316    gz_statep state;
317    z_streamp strm;
318
319    /* get internal structure */
320    if (file == NULL)
321        return -1;
322    state.file = file;
323    strm = &(state.state->strm);
324
325    /* check that we're writing and that there's no error */
326    if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
327        return -1;
328
329    /* check for seek request */
330    if (state.state->seek) {
331        state.state->seek = 0;
332        if (gz_zero(state, state.state->skip) == -1)
333            return -1;
334    }
335
336    /* try writing to input buffer for speed (state.state->size == 0 if buffer not
337       initialized) */
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;
344            strm->avail_in++;
345            state.state->x.pos++;
346            return c & 0xff;
347        }
348    }
349
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)
353        return -1;
354    return c & 0xff;
355}
356
357/* -- see zlib.h -- */
358int ZEXPORT gzputs(file, str)
359    gzFile file;
360    const char *str;
361{
362    int ret;
363    z_size_t len;
364    gz_statep state;
365
366    /* get internal structure */
367    if (file == NULL)
368        return -1;
369    state.file = file;
370
371    /* check that we're writing and that there's no error */
372    if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
373        return -1;
374
375    /* write string */
376    len = strlen(str);
377    ret = (int)gz_write(state, str, len);
378    return ret == 0 && len != 0 ? -1 : ret;
379}
380
381#if defined(STDC) || defined(Z_HAVE_STDARG_H)
382#include <stdarg.h>
383
384/* -- see zlib.h -- */
385int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
386{
387    int len;
388    unsigned left;
389    char *next;
390    gz_statep state;
391    z_streamp strm;
392
393    /* get internal structure */
394    if (file == NULL)
395        return Z_STREAM_ERROR;
396    state.file = file;
397    strm = &(state.state->strm);
398
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;
402
403    /* make sure we have some buffer space */
404    if (state.state->size == 0 && gz_init(state) == -1)
405        return state.state->err;
406
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;
412    }
413
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;
421#ifdef NO_vsnprintf
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;
426#  else
427    len = vsprintf(next, format, va);
428#  endif
429#else
430#  ifdef HAS_vsnprintf_void
431    (void)vsnprintf(next, state.state->size, format, va);
432    len = strlen(next);
433#  else
434    len = vsnprintf(next, state.state->size, format, va);
435#  endif
436#endif
437
438    /* check that printf() results fit in buffer */
439    if (len == 0 || (unsigned)len >= state.state->size || next[state.state->size - 1] != 0)
440        return 0;
441
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;
453    }
454    return len;
455}
456
457int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
458{
459    va_list va;
460    int ret;
461
462    va_start(va, format);
463    ret = gzvprintf(file, format, va);
464    va_end(va);
465    return ret;
466}
467
468#else /* !STDC && !Z_HAVE_STDARG_H */
469
470/* -- see zlib.h -- */
471int 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)
473    gzFile file;
474    const char *format;
475    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
476        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
477{
478    unsigned len, left;
479    char *next;
480    gz_statep state;
481    z_streamp strm;
482
483    /* get internal structure */
484    if (file == NULL)
485        return Z_STREAM_ERROR;
486    state = (gz_statep)file;
487    strm = &(state.state->strm);
488
489    /* check that can really pass pointer in ints */
490    if (sizeof(int) != sizeof(void *))
491        return Z_STREAM_ERROR;
492
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;
496
497    /* make sure we have some buffer space */
498    if (state.state->size == 0 && gz_init(state) == -1)
499        return state.state->error;
500
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;
506    }
507
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;
515#ifdef NO_snprintf
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++)
520        if (next[len] == 0)
521            break;
522#  else
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);
525#  endif
526#else
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);
530    len = strlen(next);
531#  else
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);
534#  endif
535#endif
536
537    /* check that printf() results fit in buffer */
538    if (len == 0 || len >= state.state->size || next[state.state->size - 1] != 0)
539        return 0;
540
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;
552    }
553    return (int)len;
554}
555
556#endif
557
558/* -- see zlib.h -- */
559int ZEXPORT gzflush(file, flush)
560    gzFile file;
561    int flush;
562{
563    gz_statep state;
564
565    /* get internal structure */
566    if (file == NULL)
567        return Z_STREAM_ERROR;
568    state.file = file;
569
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;
573
574    /* check flush parameter */
575    if (flush < 0 || flush > Z_FINISH)
576        return Z_STREAM_ERROR;
577
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;
583    }
584
585    /* compress remaining data with requested flush */
586    (void)gz_comp(state, flush);
587    return state.state->err;
588}
589
590/* -- see zlib.h -- */
591int ZEXPORT gzsetparams(file, level, strategy)
592    gzFile file;
593    int level;
594    int strategy;
595{
596    gz_statep state;
597    z_streamp strm;
598
599    /* get internal structure */
600    if (file == NULL)
601        return Z_STREAM_ERROR;
602    state.file = file;
603    strm = &(state.state->strm);
604
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;
608
609    /* if no change is requested, then do nothing */
610    if (level == state.state->level && strategy == state.state->strategy)
611        return Z_OK;
612
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;
618    }
619
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);
626    }
627    state.state->level = level;
628    state.state->strategy = strategy;
629    return Z_OK;
630}
631
632/* -- see zlib.h -- */
633int ZEXPORT gzclose_w(file)
634    gzFile file;
635{
636    int ret = Z_OK;
637    gz_statep state;
638
639    /* get internal structure */
640    if (file == NULL)
641        return Z_STREAM_ERROR;
642    state.file = file;
643
644    /* check that we're writing */
645    if (state.state->mode != GZ_WRITE)
646        return Z_STREAM_ERROR;
647
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;
653    }
654
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);
662        }
663        free(state.state->in);
664    }
665    gz_error(state, Z_OK, NULL);
666    free(state.state->path);
667    if (close(state.state->fd) == -1)
668        ret = Z_ERRNO;
669    free(state.state);
670    return ret;
671}
672