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