1206387Sdelphij/*	$NetBSD: unbzip2.c,v 1.13 2009/12/05 03:23:37 mrg Exp $	*/
2166255Sdelphij
3166255Sdelphij/*-
4166255Sdelphij * Copyright (c) 2006 The NetBSD Foundation, Inc.
5166255Sdelphij * All rights reserved.
6166255Sdelphij *
7166255Sdelphij * This code is derived from software contributed to The NetBSD Foundation
8166255Sdelphij * by Simon Burge.
9166255Sdelphij *
10166255Sdelphij * Redistribution and use in source and binary forms, with or without
11166255Sdelphij * modification, are permitted provided that the following conditions
12166255Sdelphij * are met:
13166255Sdelphij * 1. Redistributions of source code must retain the above copyright
14166255Sdelphij *    notice, this list of conditions and the following disclaimer.
15166255Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
16166255Sdelphij *    notice, this list of conditions and the following disclaimer in the
17166255Sdelphij *    documentation and/or other materials provided with the distribution.
18166255Sdelphij *
19166255Sdelphij * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20166255Sdelphij * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21166255Sdelphij * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22166255Sdelphij * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23166255Sdelphij * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24166255Sdelphij * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25166255Sdelphij * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26166255Sdelphij * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27166255Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28166255Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29166255Sdelphij * POSSIBILITY OF SUCH DAMAGE.
30166255Sdelphij *
31166255Sdelphij * $FreeBSD$
32166255Sdelphij */
33166255Sdelphij
34166255Sdelphij/* This file is #included by gzip.c */
35166255Sdelphij
36166255Sdelphijstatic off_t
37166255Sdelphijunbzip2(int in, int out, char *pre, size_t prelen, off_t *bytes_in)
38166255Sdelphij{
39199339Sdelphij	int		ret, end_of_file, cold = 0;
40166255Sdelphij	off_t		bytes_out = 0;
41166255Sdelphij	bz_stream	bzs;
42166255Sdelphij	static char	*inbuf, *outbuf;
43166255Sdelphij
44166255Sdelphij	if (inbuf == NULL)
45166255Sdelphij		inbuf = malloc(BUFLEN);
46166255Sdelphij	if (outbuf == NULL)
47166255Sdelphij		outbuf = malloc(BUFLEN);
48166255Sdelphij	if (inbuf == NULL || outbuf == NULL)
49166255Sdelphij	        maybe_err("malloc");
50166255Sdelphij
51166255Sdelphij	bzs.bzalloc = NULL;
52166255Sdelphij	bzs.bzfree = NULL;
53166255Sdelphij	bzs.opaque = NULL;
54166255Sdelphij
55166255Sdelphij	end_of_file = 0;
56166255Sdelphij	ret = BZ2_bzDecompressInit(&bzs, 0, 0);
57166255Sdelphij	if (ret != BZ_OK)
58166255Sdelphij	        maybe_errx("bzip2 init");
59166255Sdelphij
60166255Sdelphij	/* Prepend. */
61166255Sdelphij	bzs.avail_in = prelen;
62166255Sdelphij	bzs.next_in = pre;
63166255Sdelphij
64166255Sdelphij	if (bytes_in)
65166255Sdelphij		*bytes_in = prelen;
66166255Sdelphij
67199066Sdelphij	while (ret == BZ_OK) {
68166255Sdelphij	        if (bzs.avail_in == 0 && !end_of_file) {
69166255Sdelphij			ssize_t	n;
70166255Sdelphij
71166255Sdelphij	                n = read(in, inbuf, BUFLEN);
72166255Sdelphij	                if (n < 0)
73166255Sdelphij	                        maybe_err("read");
74166255Sdelphij	                if (n == 0)
75166255Sdelphij	                        end_of_file = 1;
76166255Sdelphij	                bzs.next_in = inbuf;
77166255Sdelphij	                bzs.avail_in = n;
78166255Sdelphij			if (bytes_in)
79166255Sdelphij				*bytes_in += n;
80166255Sdelphij	        }
81166255Sdelphij
82166255Sdelphij	        bzs.next_out = outbuf;
83166255Sdelphij	        bzs.avail_out = BUFLEN;
84166255Sdelphij	        ret = BZ2_bzDecompress(&bzs);
85166255Sdelphij
86166255Sdelphij	        switch (ret) {
87166255Sdelphij	        case BZ_STREAM_END:
88166255Sdelphij	        case BZ_OK:
89199339Sdelphij	                if (ret == BZ_OK && end_of_file) {
90199339Sdelphij				/*
91199339Sdelphij				 * If we hit this after a stream end, consider
92199339Sdelphij				 * it as the end of the whole file and don't
93199339Sdelphij				 * bail out.
94199339Sdelphij				 */
95199339Sdelphij				if (cold == 1)
96199339Sdelphij					ret = BZ_STREAM_END;
97199339Sdelphij				else
98199339Sdelphij					maybe_errx("truncated file");
99199339Sdelphij			}
100199339Sdelphij			cold = 0;
101199066Sdelphij	                if (!tflag && bzs.avail_out != BUFLEN) {
102166255Sdelphij				ssize_t	n;
103166255Sdelphij
104166255Sdelphij	                        n = write(out, outbuf, BUFLEN - bzs.avail_out);
105166255Sdelphij	                        if (n < 0)
106166255Sdelphij	                                maybe_err("write");
107166255Sdelphij	                	bytes_out += n;
108166255Sdelphij	                }
109199066Sdelphij			if (ret == BZ_STREAM_END && !end_of_file) {
110199066Sdelphij				if (BZ2_bzDecompressEnd(&bzs) != BZ_OK ||
111199066Sdelphij				    BZ2_bzDecompressInit(&bzs, 0, 0) != BZ_OK)
112199066Sdelphij					maybe_errx("bzip2 re-init");
113199339Sdelphij				cold = 1;
114199066Sdelphij				ret = BZ_OK;
115199066Sdelphij			}
116199066Sdelphij			break;
117166255Sdelphij
118166255Sdelphij	        case BZ_DATA_ERROR:
119166255Sdelphij	                maybe_warnx("bzip2 data integrity error");
120166255Sdelphij			break;
121166255Sdelphij
122166255Sdelphij	        case BZ_DATA_ERROR_MAGIC:
123166255Sdelphij	                maybe_warnx("bzip2 magic number error");
124166255Sdelphij			break;
125166255Sdelphij
126166255Sdelphij	        case BZ_MEM_ERROR:
127166255Sdelphij	                maybe_warnx("bzip2 out of memory");
128166255Sdelphij			break;
129199066Sdelphij
130199066Sdelphij		default:
131199066Sdelphij			maybe_warnx("unknown bzip2 error: %d", ret);
132199066Sdelphij			break;
133166255Sdelphij	        }
134166255Sdelphij	}
135166255Sdelphij
136166255Sdelphij	if (ret != BZ_STREAM_END || BZ2_bzDecompressEnd(&bzs) != BZ_OK)
137166255Sdelphij	        return (-1);
138166255Sdelphij
139166255Sdelphij	return (bytes_out);
140166255Sdelphij}
141166255Sdelphij
142