1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <package/hpkg/ZlibDecompressor.h>
8
9#include <errno.h>
10#include <stdio.h>
11
12#include <package/hpkg/DataOutput.h>
13
14
15namespace BPackageKit {
16
17namespace BHPKG {
18
19namespace BPrivate {
20
21
22// TODO: For the kernel the buffer shouldn't be allocated on the stack.
23static const size_t kOutputBufferSize = 1024;
24
25
26ZlibDecompressor::ZlibDecompressor(BDataOutput* output)
27	:
28	fOutput(output),
29	fStreamInitialized(false),
30	fFinished(false)
31{
32}
33
34
35ZlibDecompressor::~ZlibDecompressor()
36{
37	if (fStreamInitialized)
38		inflateEnd(&fStream);
39}
40
41
42status_t
43ZlibDecompressor::Init()
44{
45	// initialize the stream
46	fStream.next_in = NULL;
47	fStream.avail_in = 0;
48	fStream.total_in = 0;
49	fStream.next_out = NULL;
50	fStream.avail_out = 0;
51	fStream.total_out = 0;
52	fStream.msg = 0;
53	fStream.state = 0;
54	fStream.zalloc = Z_NULL;
55	fStream.zfree = Z_NULL;
56	fStream.opaque = Z_NULL;
57	fStream.data_type = 0;
58	fStream.adler = 0;
59	fStream.reserved = 0;
60
61	int zlibError = inflateInit(&fStream);
62	if (zlibError != Z_OK)
63		return TranslateZlibError(zlibError);
64
65	fStreamInitialized = true;
66
67	return B_OK;
68}
69
70
71status_t
72ZlibDecompressor::DecompressNext(const void* input, size_t inputSize)
73{
74	fStream.next_in = (Bytef*)input;
75	fStream.avail_in = inputSize;
76
77	while (fStream.avail_in > 0) {
78		if (fFinished)
79			return B_BAD_DATA;
80
81		uint8 outputBuffer[kOutputBufferSize];
82		fStream.next_out = (Bytef*)outputBuffer;
83		fStream.avail_out = sizeof(outputBuffer);
84
85		int zlibError = inflate(&fStream, 0);
86		if (zlibError == Z_STREAM_END)
87			fFinished = true;
88		else if (zlibError != Z_OK)
89			return TranslateZlibError(zlibError);
90
91		if (fStream.avail_out < sizeof(outputBuffer)) {
92			status_t error = fOutput->WriteData(outputBuffer,
93				sizeof(outputBuffer) - fStream.avail_out);
94			if (error != B_OK)
95				return error;
96		}
97	}
98
99	return B_OK;
100}
101
102
103status_t
104ZlibDecompressor::Finish()
105{
106	fStream.next_in = (Bytef*)NULL;
107	fStream.avail_in = 0;
108
109	while (!fFinished) {
110		uint8 outputBuffer[kOutputBufferSize];
111		fStream.next_out = (Bytef*)outputBuffer;
112		fStream.avail_out = sizeof(outputBuffer);
113
114		int zlibError = inflate(&fStream, Z_FINISH);
115		if (zlibError == Z_STREAM_END)
116			fFinished = true;
117		else if (zlibError != Z_OK)
118			return TranslateZlibError(zlibError);
119
120		if (fStream.avail_out < sizeof(outputBuffer)) {
121			status_t error = fOutput->WriteData(outputBuffer,
122				sizeof(outputBuffer) - fStream.avail_out);
123			if (error != B_OK)
124				return error;
125		}
126	}
127
128	inflateEnd(&fStream);
129	fStreamInitialized = false;
130
131	return B_OK;
132}
133
134
135/*static*/ status_t
136ZlibDecompressor::DecompressSingleBuffer(const void* input, size_t inputSize,
137	void* output, size_t outputSize, size_t& _uncompressedSize)
138{
139	if (inputSize == 0 || outputSize == 0)
140		return B_BAD_VALUE;
141
142	// prepare stream
143	z_stream zStream = {
144		(Bytef*)input,				// next_in
145		inputSize,					// avail_in
146		0,							// total_in
147		(Bytef*)output,				// next_out
148		outputSize,					// avail_out
149		0,							// total_out
150		0,							// msg
151		0,							// state;
152		Z_NULL,						// zalloc
153		Z_NULL,						// zfree
154		Z_NULL,						// opaque
155		0,							// data_type
156		0,							// adler
157		0							// reserved
158	};
159
160	int zlibError = inflateInit(&zStream);
161	if (zlibError != Z_OK)
162		return TranslateZlibError(zlibError);
163
164
165	// inflate
166	status_t error = B_OK;
167	zlibError = inflate(&zStream, Z_FINISH);
168	if (zlibError != Z_STREAM_END) {
169		if (zlibError == Z_OK)
170			error = B_BUFFER_OVERFLOW;
171		else
172			error = TranslateZlibError(zlibError);
173	}
174
175	// clean up
176	zlibError = inflateEnd(&zStream);
177	if (zlibError != Z_OK && error == B_OK)
178		error = TranslateZlibError(zlibError);
179
180	if (error != B_OK)
181		return error;
182
183	_uncompressedSize = zStream.total_out;
184	return B_OK;
185}
186
187
188}	// namespace BPrivate
189
190}	// namespace BHPKG
191
192}	// namespace BPackageKit
193