Fossil SCM

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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button