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 */ 9 local int gz_init OF((gz_statep)); 10 local int gz_comp OF((gz_statep, int)); 11 local int gz_zero OF((gz_statep, z_off64_t)); 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( 16 gz_statep state) 17 { 18 int ret; 19 z_streamp strm = &(state->strm); 20 21 /* allocate input buffer */ 22 state->in = (unsigned char *)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 = (unsigned char *)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( 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( 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( 166 gzFile file, 167 voidpc buf, 168 unsigned len) 169 { 170 unsigned put = len; 171 gz_statep state; 172 z_streamp strm; 173 174 /* get internal structure */ 175 if (file == NULL) 176 return 0; 177 state = (gz_statep)file; 178 strm = &(state->strm); 179 180 /* check that we're writing and that there's no error */ 181 if (state->mode != GZ_WRITE || state->err != Z_OK) 182 return 0; 183 184 /* since an int is returned, make sure len fits in one, otherwise return 185 with an error (this avoids the flaw in the interface) */ 186 if ((int)len < 0) { 187 gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); 188 return 0; 189 } 190 191 /* if len is zero, avoid unnecessary operations */ 192 if (len == 0) 193 return 0; 194 195 /* allocate memory if this is the first time through */ 196 if (state->size == 0 && gz_init(state) == -1) 197 return 0; 198 199 /* check for seek request */ 200 if (state->seek) { 201 state->seek = 0; 202 if (gz_zero(state, state->skip) == -1) 203 return 0; 204 } 205 206 /* for small len, copy to input buffer, otherwise compress directly */ 207 if (len < state->size) { 208 /* copy to input buffer, compress when full */ 209 do { 210 unsigned have, copy; 211 212 if (strm->avail_in == 0) 213 strm->next_in = state->in; 214 have = (unsigned)((strm->next_in + strm->avail_in) - state->in); 215 copy = state->size - have; 216 if (copy > len) 217 copy = len; 218 memcpy(state->in + have, buf, copy); 219 strm->avail_in += copy; 220 state->x.pos += copy; 221 buf = (const char *)buf + copy; 222 len -= copy; 223 if (len && gz_comp(state, Z_NO_FLUSH) == -1) 224 return 0; 225 } while (len); 226 } 227 else { 228 /* consume whatever's left in the input buffer */ 229 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 230 return 0; 231 232 /* directly compress user buffer to file */ 233 strm->avail_in = len; 234 strm->next_in = (z_const Bytef *)buf; 235 state->x.pos += len; 236 if (gz_comp(state, Z_NO_FLUSH) == -1) 237 return 0; 238 } 239 240 /* input was all buffered or compressed (put will fit in int) */ 241 return (int)put; 242 } 243 244 /* -- see zlib.h -- */ 245 int ZEXPORT gzputc( 246 gzFile file, 247 int c) 248 { 249 unsigned have; 250 unsigned char buf[1]; 251 gz_statep state; 252 z_streamp strm; 253 254 /* get internal structure */ 255 if (file == NULL) 256 return -1; 257 state = (gz_statep)file; 258 strm = &(state->strm); 259 260 /* check that we're writing and that there's no error */ 261 if (state->mode != GZ_WRITE || state->err != Z_OK) 262 return -1; 263 264 /* check for seek request */ 265 if (state->seek) { 266 state->seek = 0; 267 if (gz_zero(state, state->skip) == -1) 268 return -1; 269 } 270 271 /* try writing to input buffer for speed (state->size == 0 if buffer not 272 initialized) */ 273 if (state->size) { 274 if (strm->avail_in == 0) 275 strm->next_in = state->in; 276 have = (unsigned)((strm->next_in + strm->avail_in) - state->in); 277 if (have < state->size) { 278 state->in[have] = c; 279 strm->avail_in++; 280 state->x.pos++; 281 return c & 0xff; 282 } 283 } 284 285 /* no room in buffer or not initialized, use gz_write() */ 286 buf[0] = c; 287 if (gzwrite(file, buf, 1) != 1) 288 return -1; 289 return c & 0xff; 290 } 291 292 /* -- see zlib.h -- */ 293 int ZEXPORT gzputs( 294 gzFile file, 295 const char *str) 296 { 297 int ret; 298 unsigned len; 299 300 /* write string */ 301 len = (unsigned)strlen(str); 302 ret = gzwrite(file, str, len); 303 return ret == 0 && len != 0 ? -1 : ret; 304 } 305 306 #if defined(STDC) || defined(Z_HAVE_STDARG_H) 307 #include <stdarg.h> 308 309 /* -- see zlib.h -- */ 310 int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) 311 { 312 int size, len; 313 gz_statep state; 314 z_streamp strm; 315 316 /* get internal structure */ 317 if (file == NULL) 318 return -1; 319 state = (gz_statep)file; 320 strm = &(state->strm); 321 322 /* check that we're writing and that there's no error */ 323 if (state->mode != GZ_WRITE || state->err != Z_OK) 324 return 0; 325 326 /* make sure we have some buffer space */ 327 if (state->size == 0 && gz_init(state) == -1) 328 return 0; 329 330 /* check for seek request */ 331 if (state->seek) { 332 state->seek = 0; 333 if (gz_zero(state, state->skip) == -1) 334 return 0; 335 } 336 337 /* consume whatever's left in the input buffer */ 338 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 339 return 0; 340 341 /* do the printf() into the input buffer, put length in len */ 342 size = (int)(state->size); 343 state->in[size - 1] = 0; 344 #ifdef NO_vsnprintf 345 # ifdef HAS_vsprintf_void 346 (void)vsprintf((char *)(state->in), format, va); 347 for (len = 0; len < size; len++) 348 if (state->in[len] == 0) break; 349 # else 350 len = vsprintf((char *)(state->in), format, va); 351 # endif 352 #else 353 # ifdef HAS_vsnprintf_void 354 (void)vsnprintf((char *)(state->in), size, format, va); 355 len = strlen((char *)(state->in)); 356 # else 357 len = vsnprintf((char *)(state->in), size, format, va); 358 # endif 359 #endif 360 361 /* check that printf() results fit in buffer */ 362 if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) 363 return 0; 364 365 /* update buffer and position, defer compression until needed */ 366 strm->avail_in = (unsigned)len; 367 strm->next_in = state->in; 368 state->x.pos += len; 369 return len; 370 } 371 372 int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) 373 { 374 va_list va; 375 int ret; 376 377 va_start(va, format); 378 ret = gzvprintf(file, format, va); 379 va_end(va); 380 return ret; 381 } 382 383 #else /* !STDC && !Z_HAVE_STDARG_H */ 384 385 /* -- see zlib.h -- */ 386 int ZEXPORTVA gzprintf ( 387 gzFile file, 388 const char *format, 389 int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, 390 int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20) 391 { 392 int size, len; 393 gz_statep state; 394 z_streamp strm; 395 396 /* get internal structure */ 397 if (file == NULL) 398 return -1; 399 state = (gz_statep)file; 400 strm = &(state->strm); 401 402 /* check that can really pass pointer in ints */ 403 if (sizeof(int) != sizeof(void *)) 404 return 0; 405 406 /* check that we're writing and that there's no error */ 407 if (state->mode != GZ_WRITE || state->err != Z_OK) 408 return 0; 409 410 /* make sure we have some buffer space */ 411 if (state->size == 0 && gz_init(state) == -1) 412 return 0; 413 414 /* check for seek request */ 415 if (state->seek) { 416 state->seek = 0; 417 if (gz_zero(state, state->skip) == -1) 418 return 0; 419 } 420 421 /* consume whatever's left in the input buffer */ 422 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 423 return 0; 424 425 /* do the printf() into the input buffer, put length in len */ 426 size = (int)(state->size); 427 state->in[size - 1] = 0; 428 #ifdef NO_snprintf 429 # ifdef HAS_sprintf_void 430 sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, 431 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 432 for (len = 0; len < size; len++) 433 if (state->in[len] == 0) break; 434 # else 435 len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, 436 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 437 # endif 438 #else 439 # ifdef HAS_snprintf_void 440 snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, 441 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 442 len = strlen((char *)(state->in)); 443 # else 444 len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, 445 a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, 446 a19, a20); 447 # endif 448 #endif 449 450 /* check that printf() results fit in buffer */ 451 if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) 452 return 0; 453 454 /* update buffer and position, defer compression until needed */ 455 strm->avail_in = (unsigned)len; 456 strm->next_in = state->in; 457 state->x.pos += len; 458 return len; 459 } 460 461 #endif 462 463 /* -- see zlib.h -- */ 464 int ZEXPORT gzflush( 465 gzFile file, 466 int flush) 467 { 468 gz_statep state; 469 470 /* get internal structure */ 471 if (file == NULL) 472 return -1; 473 state = (gz_statep)file; 474 475 /* check that we're writing and that there's no error */ 476 if (state->mode != GZ_WRITE || state->err != Z_OK) 477 return Z_STREAM_ERROR; 478 479 /* check flush parameter */ 480 if (flush < 0 || flush > Z_FINISH) 481 return Z_STREAM_ERROR; 482 483 /* check for seek request */ 484 if (state->seek) { 485 state->seek = 0; 486 if (gz_zero(state, state->skip) == -1) 487 return -1; 488 } 489 490 /* compress remaining data with requested flush */ 491 gz_comp(state, flush); 492 return state->err; 493 } 494 495 /* -- see zlib.h -- */ 496 int ZEXPORT gzsetparams( 497 gzFile file, 498 int level, 499 int strategy) 500 { 501 gz_statep state; 502 z_streamp strm; 503 504 /* get internal structure */ 505 if (file == NULL) 506 return Z_STREAM_ERROR; 507 state = (gz_statep)file; 508 strm = &(state->strm); 509 510 /* check that we're writing and that there's no error */ 511 if (state->mode != GZ_WRITE || state->err != Z_OK) 512 return Z_STREAM_ERROR; 513 514 /* if no change is requested, then do nothing */ 515 if (level == state->level && strategy == state->strategy) 516 return Z_OK; 517 518 /* check for seek request */ 519 if (state->seek) { 520 state->seek = 0; 521 if (gz_zero(state, state->skip) == -1) 522 return -1; 523 } 524 525 /* change compression parameters for subsequent input */ 526 if (state->size) { 527 /* flush previous input with previous parameters before changing */ 528 if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) 529 return state->err; 530 deflateParams(strm, level, strategy); 531 } 532 state->level = level; 533 state->strategy = strategy; 534 return Z_OK; 535 } 536 537 /* -- see zlib.h -- */ 538 int ZEXPORT gzclose_w( 539 gzFile file) 540 { 541 int ret = Z_OK; 542 gz_statep state; 543 544 /* get internal structure */ 545 if (file == NULL) 546 return Z_STREAM_ERROR; 547 state = (gz_statep)file; 548 549 /* check that we're writing */ 550 if (state->mode != GZ_WRITE) 551 return Z_STREAM_ERROR; 552 553 /* check for seek request */ 554 if (state->seek) { 555 state->seek = 0; 556 if (gz_zero(state, state->skip) == -1) 557 ret = state->err; 558 } 559 560 /* flush, free memory, and close file */ 561 if (gz_comp(state, Z_FINISH) == -1) 562 ret = state->err; 563 if (state->size) { 564 if (!state->direct) { 565 (void)deflateEnd(&(state->strm)); 566 free(state->out); 567 } 568 free(state->in); 569 } 570 gz_error(state, Z_OK, NULL); 571 free(state->path); 572 if (close(state->fd) == -1) 573 ret = Z_ERRNO; 574 free(state); 575 return ret; 576 } 577