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