gzwrite.c revision 205194
138494Sobrien/* gzwrite.c -- zlib functions for writing gzip files 2131702Smbr * Copyright (C) 2004, 2005, 2010 Mark Adler 338494Sobrien * For conditions of distribution and use, see copyright notice in zlib.h 438494Sobrien */ 538494Sobrien 638494Sobrien#include "gzguts.h" 738494Sobrien 838494Sobrien/* Local functions */ 938494Sobrienlocal int gz_init OF((gz_statep)); 1038494Sobrienlocal int gz_comp OF((gz_statep, int)); 1138494Sobrienlocal int gz_zero OF((gz_statep, z_off64_t)); 1238494Sobrien 1338494Sobrien/* Initialize state for writing a gzip file. Mark initialization by setting 1438494Sobrien state->size to non-zero. Return -1 on failure or 0 on success. */ 1538494Sobrienlocal int gz_init(state) 1638494Sobrien gz_statep state; 1738494Sobrien{ 1838494Sobrien int ret; 1938494Sobrien z_streamp strm = &(state->strm); 2042629Sobrien 2138494Sobrien /* allocate input and output buffers */ 2238494Sobrien state->in = malloc(state->want); 2338494Sobrien state->out = malloc(state->want); 2438494Sobrien if (state->in == NULL || state->out == NULL) { 2538494Sobrien if (state->out != NULL) 2638494Sobrien free(state->out); 2738494Sobrien if (state->in != NULL) 2838494Sobrien free(state->in); 2938494Sobrien gz_error(state, Z_MEM_ERROR, "out of memory"); 3038494Sobrien return -1; 3138494Sobrien } 3238494Sobrien 3338494Sobrien /* allocate deflate memory, set up for gzip compression */ 3438494Sobrien strm->zalloc = Z_NULL; 3538494Sobrien strm->zfree = Z_NULL; 3638494Sobrien strm->opaque = Z_NULL; 3738494Sobrien ret = deflateInit2(strm, state->level, Z_DEFLATED, 3838494Sobrien 15 + 16, 8, state->strategy); 3938494Sobrien if (ret != Z_OK) { 4038494Sobrien free(state->in); 41131702Smbr gz_error(state, Z_MEM_ERROR, "out of memory"); 42131709Smbr return -1; 4338494Sobrien } 4438494Sobrien 4538494Sobrien /* mark state as initialized */ 4638494Sobrien state->size = state->want; 4738494Sobrien 4838494Sobrien /* initialize write buffer */ 4938494Sobrien strm->avail_out = state->size; 5038494Sobrien strm->next_out = state->out; 5138494Sobrien state->next = strm->next_out; 5238494Sobrien return 0; 5338494Sobrien} 5438494Sobrien 5538494Sobrien/* Compress whatever is at avail_in and next_in and write to the output file. 5638494Sobrien Return -1 if there is an error writing to the output file, otherwise 0. 5738494Sobrien flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, 5838494Sobrien then the deflate() state is reset to start a new gzip stream. */ 5938494Sobrienlocal int gz_comp(state, flush) 6038494Sobrien gz_statep state; 6138494Sobrien int flush; 6238494Sobrien{ 6338494Sobrien int ret, got; 6438494Sobrien unsigned have; 6538494Sobrien z_streamp strm = &(state->strm); 6638494Sobrien 6738494Sobrien /* allocate memory if this is the first time through */ 6838494Sobrien if (state->size == 0 && gz_init(state) == -1) 6938494Sobrien return -1; 7038494Sobrien 7138494Sobrien /* run deflate() on provided input until it produces no more output */ 7238494Sobrien ret = Z_OK; 7338494Sobrien do { 7438494Sobrien /* write out current buffer contents if full, or if flushing, but if 7538494Sobrien doing Z_FINISH then don't write until we get to Z_STREAM_END */ 7638494Sobrien if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && 7738494Sobrien (flush != Z_FINISH || ret == Z_STREAM_END))) { 7838494Sobrien have = (unsigned)(strm->next_out - state->next); 7938494Sobrien if (have && ((got = write(state->fd, state->next, have)) < 0 || 8038494Sobrien (unsigned)got != have)) { 8138494Sobrien gz_error(state, Z_ERRNO, zstrerror()); 8238494Sobrien return -1; 8338494Sobrien } 8438494Sobrien if (strm->avail_out == 0) { 8538494Sobrien strm->avail_out = state->size; 8638494Sobrien strm->next_out = state->out; 8738494Sobrien } 8838494Sobrien state->next = strm->next_out; 8938494Sobrien } 9038494Sobrien 9138494Sobrien /* compress */ 9238494Sobrien have = strm->avail_out; 9338494Sobrien ret = deflate(strm, flush); 9438494Sobrien if (ret == Z_STREAM_ERROR) { 9538494Sobrien gz_error(state, Z_STREAM_ERROR, 9638494Sobrien "internal error: deflate stream corrupt"); 9738494Sobrien return -1; 9838494Sobrien } 9938494Sobrien have -= strm->avail_out; 10038494Sobrien } while (have); 10138494Sobrien 10238494Sobrien /* if that completed a deflate stream, allow another to start */ 10338494Sobrien if (flush == Z_FINISH) 10438494Sobrien deflateReset(strm); 10538494Sobrien 10638494Sobrien /* all done, no errors */ 10738494Sobrien return 0; 10838494Sobrien} 10938494Sobrien 11038494Sobrien/* Compress len zeros to output. Return -1 on error, 0 on success. */ 11138494Sobrienlocal int gz_zero(state, len) 11238494Sobrien gz_statep state; 11338494Sobrien z_off64_t len; 11438494Sobrien{ 11538494Sobrien int first; 11638494Sobrien unsigned n; 11738494Sobrien z_streamp strm = &(state->strm); 11838494Sobrien 11938494Sobrien /* consume whatever's left in the input buffer */ 12038494Sobrien if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 12138494Sobrien return -1; 12238494Sobrien 12338494Sobrien /* compress len zeros (len guaranteed > 0) */ 12438494Sobrien first = 1; 12538494Sobrien while (len) { 12638494Sobrien n = GT_OFF(state->size) || (z_off64_t)state->size > len ? 12738494Sobrien (unsigned)len : state->size; 12838494Sobrien if (first) { 12938494Sobrien memset(state->in, 0, n); 130119679Smbr first = 0; 13138494Sobrien } 132119679Smbr strm->avail_in = n; 13338494Sobrien strm->next_in = state->in; 134119679Smbr state->pos += n; 13538494Sobrien if (gz_comp(state, Z_NO_FLUSH) == -1) 136119679Smbr return -1; 13738494Sobrien len -= n; 138131709Smbr } 139131709Smbr return 0; 140131709Smbr} 141131709Smbr 142119679Smbr/* -- see zlib.h -- */ 14338494Sobrienint ZEXPORT gzwrite(file, buf, len) 144119679Smbr gzFile file; 14538494Sobrien voidpc buf; 146119679Smbr unsigned len; 14738494Sobrien{ 148119679Smbr unsigned put = len; 14938494Sobrien unsigned n; 150119679Smbr gz_statep state; 15138494Sobrien z_streamp strm; 152119679Smbr 153119679Smbr /* get internal structure */ 15438494Sobrien if (file == NULL) 155119679Smbr return 0; 15638494Sobrien state = (gz_statep)file; 15738494Sobrien strm = &(state->strm); 15838494Sobrien 15938494Sobrien /* check that we're writing and that there's no error */ 16038494Sobrien if (state->mode != GZ_WRITE || state->err != Z_OK) 16138494Sobrien return 0; 16238494Sobrien 16338494Sobrien /* since an int is returned, make sure len fits in one, otherwise return 16438494Sobrien with an error (this avoids the flaw in the interface) */ 16538494Sobrien if ((int)len < 0) { 16638494Sobrien gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); 16738494Sobrien return 0; 16838494Sobrien } 16938494Sobrien 17038494Sobrien /* if len is zero, avoid unnecessary operations */ 17138494Sobrien if (len == 0) 17238494Sobrien return 0; 17338494Sobrien 17438494Sobrien /* allocate memory if this is the first time through */ 17538494Sobrien if (state->size == 0 && gz_init(state) == -1) 17638494Sobrien return 0; 17738494Sobrien 17838494Sobrien /* check for seek request */ 17938494Sobrien if (state->seek) { 18038494Sobrien state->seek = 0; 18138494Sobrien if (gz_zero(state, state->skip) == -1) 18238494Sobrien return 0; 18338494Sobrien } 18438494Sobrien 185 /* for small len, copy to input buffer, otherwise compress directly */ 186 if (len < state->size) { 187 /* copy to input buffer, compress when full */ 188 do { 189 if (strm->avail_in == 0) 190 strm->next_in = state->in; 191 n = state->size - strm->avail_in; 192 if (n > len) 193 n = len; 194 memcpy(strm->next_in + strm->avail_in, buf, n); 195 strm->avail_in += n; 196 state->pos += n; 197 buf = (char *)buf + n; 198 len -= n; 199 if (len && gz_comp(state, Z_NO_FLUSH) == -1) 200 return 0; 201 } while (len); 202 } 203 else { 204 /* consume whatever's left in the input buffer */ 205 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 206 return 0; 207 208 /* directly compress user buffer to file */ 209 strm->avail_in = len; 210 strm->next_in = (voidp)buf; 211 state->pos += len; 212 if (gz_comp(state, Z_NO_FLUSH) == -1) 213 return 0; 214 } 215 216 /* input was all buffered or compressed (put will fit in int) */ 217 return (int)put; 218} 219 220/* -- see zlib.h -- */ 221int ZEXPORT gzputc(file, c) 222 gzFile file; 223 int c; 224{ 225 unsigned char buf[1]; 226 gz_statep state; 227 z_streamp strm; 228 229 /* get internal structure */ 230 if (file == NULL) 231 return -1; 232 state = (gz_statep)file; 233 strm = &(state->strm); 234 235 /* check that we're writing and that there's no error */ 236 if (state->mode != GZ_WRITE || state->err != Z_OK) 237 return -1; 238 239 /* check for seek request */ 240 if (state->seek) { 241 state->seek = 0; 242 if (gz_zero(state, state->skip) == -1) 243 return -1; 244 } 245 246 /* try writing to input buffer for speed (state->size == 0 if buffer not 247 initialized) */ 248 if (strm->avail_in < state->size) { 249 if (strm->avail_in == 0) 250 strm->next_in = state->in; 251 strm->next_in[strm->avail_in++] = c; 252 state->pos++; 253 return c; 254 } 255 256 /* no room in buffer or not initialized, use gz_write() */ 257 buf[0] = c; 258 if (gzwrite(file, buf, 1) != 1) 259 return -1; 260 return c; 261} 262 263/* -- see zlib.h -- */ 264int ZEXPORT gzputs(file, str) 265 gzFile file; 266 const char *str; 267{ 268 int ret; 269 unsigned len; 270 271 /* write string */ 272 len = (unsigned)strlen(str); 273 ret = gzwrite(file, str, len); 274 return ret == 0 && len != 0 ? -1 : ret; 275} 276 277#ifdef STDC 278#include <stdarg.h> 279 280/* -- see zlib.h -- */ 281int ZEXPORTVA gzprintf (gzFile file, const char *format, ...) 282{ 283 int size, len; 284 gz_statep state; 285 z_streamp strm; 286 va_list va; 287 288 /* get internal structure */ 289 if (file == NULL) 290 return -1; 291 state = (gz_statep)file; 292 strm = &(state->strm); 293 294 /* check that we're writing and that there's no error */ 295 if (state->mode != GZ_WRITE || state->err != Z_OK) 296 return 0; 297 298 /* make sure we have some buffer space */ 299 if (state->size == 0 && gz_init(state) == -1) 300 return 0; 301 302 /* check for seek request */ 303 if (state->seek) { 304 state->seek = 0; 305 if (gz_zero(state, state->skip) == -1) 306 return 0; 307 } 308 309 /* consume whatever's left in the input buffer */ 310 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 311 return 0; 312 313 /* do the printf() into the input buffer, put length in len */ 314 size = (int)(state->size); 315 state->in[size - 1] = 0; 316 va_start(va, format); 317#ifdef NO_vsnprintf 318# ifdef HAS_vsprintf_void 319 (void)vsprintf(state->in, format, va); 320 va_end(va); 321 for (len = 0; len < size; len++) 322 if (state->in[len] == 0) break; 323# else 324 len = vsprintf(state->in, format, va); 325 va_end(va); 326# endif 327#else 328# ifdef HAS_vsnprintf_void 329 (void)vsnprintf(state->in, size, format, va); 330 va_end(va); 331 len = strlen(state->in); 332# else 333 len = vsnprintf((char *)(state->in), size, format, va); 334 va_end(va); 335# endif 336#endif 337 338 /* check that printf() results fit in buffer */ 339 if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) 340 return 0; 341 342 /* update buffer and position, defer compression until needed */ 343 strm->avail_in = (unsigned)len; 344 strm->next_in = state->in; 345 state->pos += len; 346 return len; 347} 348 349#else /* !STDC */ 350 351/* -- see zlib.h -- */ 352int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, 353 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 354 gzFile file; 355 const char *format; 356 int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, 357 a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; 358{ 359 int size, len; 360 gz_statep state; 361 z_streamp strm; 362 363 /* get internal structure */ 364 if (file == NULL) 365 return -1; 366 state = (gz_statep)file; 367 strm = &(state->strm); 368 369 /* check that we're writing and that there's no error */ 370 if (state->mode != GZ_WRITE || state->err != Z_OK) 371 return 0; 372 373 /* make sure we have some buffer space */ 374 if (state->size == 0 && gz_init(state) == -1) 375 return 0; 376 377 /* check for seek request */ 378 if (state->seek) { 379 state->seek = 0; 380 if (gz_zero(state, state->skip) == -1) 381 return 0; 382 } 383 384 /* consume whatever's left in the input buffer */ 385 if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) 386 return 0; 387 388 /* do the printf() into the input buffer, put length in len */ 389 size = (int)(state->size); 390 state->in[size - 1] = 0; 391#ifdef NO_snprintf 392# ifdef HAS_sprintf_void 393 sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, 394 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 395 for (len = 0; len < size; len++) 396 if (state->in[len] == 0) break; 397# else 398 len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, 399 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 400# endif 401#else 402# ifdef HAS_snprintf_void 403 snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, 404 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 405 len = strlen(state->in); 406# else 407 len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, 408 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); 409# endif 410#endif 411 412 /* check that printf() results fit in buffer */ 413 if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) 414 return 0; 415 416 /* update buffer and position, defer compression until needed */ 417 strm->avail_in = (unsigned)len; 418 strm->next_in = state->in; 419 state->pos += len; 420 return len; 421} 422 423#endif 424 425/* -- see zlib.h -- */ 426int ZEXPORT gzflush(file, flush) 427 gzFile file; 428 int flush; 429{ 430 gz_statep state; 431 432 /* get internal structure */ 433 if (file == NULL) 434 return -1; 435 state = (gz_statep)file; 436 437 /* check that we're writing and that there's no error */ 438 if (state->mode != GZ_WRITE || state->err != Z_OK) 439 return Z_STREAM_ERROR; 440 441 /* check flush parameter */ 442 if (flush < 0 || flush > Z_FINISH) 443 return Z_STREAM_ERROR; 444 445 /* check for seek request */ 446 if (state->seek) { 447 state->seek = 0; 448 if (gz_zero(state, state->skip) == -1) 449 return -1; 450 } 451 452 /* compress remaining data with requested flush */ 453 gz_comp(state, flush); 454 return state->err; 455} 456 457/* -- see zlib.h -- */ 458int ZEXPORT gzsetparams(file, level, strategy) 459 gzFile file; 460 int level; 461 int strategy; 462{ 463 gz_statep state; 464 z_streamp strm; 465 466 /* get internal structure */ 467 if (file == NULL) 468 return Z_STREAM_ERROR; 469 state = (gz_statep)file; 470 strm = &(state->strm); 471 472 /* check that we're writing and that there's no error */ 473 if (state->mode != GZ_WRITE || state->err != Z_OK) 474 return Z_STREAM_ERROR; 475 476 /* if no change is requested, then do nothing */ 477 if (level == state->level && strategy == state->strategy) 478 return Z_OK; 479 480 /* check for seek request */ 481 if (state->seek) { 482 state->seek = 0; 483 if (gz_zero(state, state->skip) == -1) 484 return -1; 485 } 486 487 /* change compression parameters for subsequent input */ 488 if (state->size) { 489 /* flush previous input with previous parameters before changing */ 490 if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) 491 return state->err; 492 deflateParams(strm, level, strategy); 493 } 494 state->level = level; 495 state->strategy = strategy; 496 return Z_OK; 497} 498 499/* -- see zlib.h -- */ 500int ZEXPORT gzclose_w(file) 501 gzFile file; 502{ 503 int ret = 0; 504 gz_statep state; 505 506 /* get internal structure */ 507 if (file == NULL) 508 return Z_STREAM_ERROR; 509 state = (gz_statep)file; 510 511 /* check that we're writing */ 512 if (state->mode != GZ_WRITE) 513 return Z_STREAM_ERROR; 514 515 /* check for seek request */ 516 if (state->seek) { 517 state->seek = 0; 518 ret += gz_zero(state, state->skip); 519 } 520 521 /* flush, free memory, and close file */ 522 ret += gz_comp(state, Z_FINISH); 523 (void)deflateEnd(&(state->strm)); 524 free(state->out); 525 free(state->in); 526 gz_error(state, Z_OK, NULL); 527 free(state->path); 528 ret += close(state->fd); 529 free(state); 530 return ret ? Z_ERRNO : Z_OK; 531} 532