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