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