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