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