1 /* $NetBSD: unbzip2.c,v 1.13 2009/12/05 03:23:37 mrg Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Simon Burge. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 /* This file is #included by gzip.c */ 35 36 static off_t 37 unbzip2(int in, int out, char *pre, size_t prelen, off_t *bytes_in) 38 { 39 int ret, end_of_file, cold = 0; 40 off_t bytes_out = 0; 41 bz_stream bzs; 42 static char *inbuf, *outbuf; 43 44 if (inbuf == NULL) 45 inbuf = malloc(BUFLEN); 46 if (outbuf == NULL) 47 outbuf = malloc(BUFLEN); 48 if (inbuf == NULL || outbuf == NULL) 49 maybe_err("malloc"); 50 51 bzs.bzalloc = NULL; 52 bzs.bzfree = NULL; 53 bzs.opaque = NULL; 54 55 end_of_file = 0; 56 ret = BZ2_bzDecompressInit(&bzs, 0, 0); 57 if (ret != BZ_OK) 58 maybe_errx("bzip2 init"); 59 60 /* Prepend. */ 61 bzs.avail_in = prelen; 62 bzs.next_in = pre; 63 64 if (bytes_in) 65 *bytes_in = prelen; 66 67 while (ret == BZ_OK) { 68 if (bzs.avail_in == 0 && !end_of_file) { 69 ssize_t n; 70 71 n = read(in, inbuf, BUFLEN); 72 if (n < 0) 73 maybe_err("read"); 74 if (n == 0) 75 end_of_file = 1; 76 bzs.next_in = inbuf; 77 bzs.avail_in = n; 78 if (bytes_in) 79 *bytes_in += n; 80 } 81 82 bzs.next_out = outbuf; 83 bzs.avail_out = BUFLEN; 84 ret = BZ2_bzDecompress(&bzs); 85 86 switch (ret) { 87 case BZ_STREAM_END: 88 case BZ_OK: 89 if (ret == BZ_OK && end_of_file) { 90 /* 91 * If we hit this after a stream end, consider 92 * it as the end of the whole file and don't 93 * bail out. 94 */ 95 if (cold == 1) 96 ret = BZ_STREAM_END; 97 else 98 maybe_errx("truncated file"); 99 } 100 cold = 0; 101 if (!tflag && bzs.avail_out != BUFLEN) { 102 ssize_t n; 103 104 n = write(out, outbuf, BUFLEN - bzs.avail_out); 105 if (n < 0) 106 maybe_err("write"); 107 bytes_out += n; 108 } 109 if (ret == BZ_STREAM_END && !end_of_file) { 110 if (BZ2_bzDecompressEnd(&bzs) != BZ_OK || 111 BZ2_bzDecompressInit(&bzs, 0, 0) != BZ_OK) 112 maybe_errx("bzip2 re-init"); 113 cold = 1; 114 ret = BZ_OK; 115 } 116 break; 117 118 case BZ_DATA_ERROR: 119 maybe_warnx("bzip2 data integrity error"); 120 break; 121 122 case BZ_DATA_ERROR_MAGIC: 123 maybe_warnx("bzip2 magic number error"); 124 break; 125 126 case BZ_MEM_ERROR: 127 maybe_warnx("bzip2 out of memory"); 128 break; 129 130 default: 131 maybe_warnx("unknown bzip2 error: %d", ret); 132 break; 133 } 134 } 135 136 if (ret != BZ_STREAM_END || BZ2_bzDecompressEnd(&bzs) != BZ_OK) 137 return (-1); 138 139 return (bytes_out); 140 } 141 142