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/ZlibCompressor.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
22static const size_t kOutputBufferSize = 1024;
23
24
25ZlibCompressor::ZlibCompressor(BDataOutput* output)
26	:
27	fOutput(output),
28	fStreamInitialized(false)
29{
30}
31
32
33ZlibCompressor::~ZlibCompressor()
34{
35	if (fStreamInitialized)
36		deflateEnd(&fStream);
37}
38
39
40status_t
41ZlibCompressor::Init()
42{
43	// initialize the stream
44	fStream.next_in = NULL;
45	fStream.avail_in = 0;
46	fStream.total_in = 0;
47	fStream.next_out = NULL;
48	fStream.avail_out = 0;
49	fStream.total_out = 0;
50	fStream.msg = 0;
51	fStream.state = 0;
52	fStream.zalloc = Z_NULL;
53	fStream.zfree = Z_NULL;
54	fStream.opaque = Z_NULL;
55	fStream.data_type = 0;
56	fStream.adler = 0;
57	fStream.reserved = 0;
58
59	int zlibError = deflateInit(&fStream, Z_BEST_COMPRESSION);
60	if (zlibError != Z_OK)
61		return TranslateZlibError(zlibError);
62
63	fStreamInitialized = true;
64
65	return B_OK;
66}
67
68
69status_t
70ZlibCompressor::CompressNext(const void* input, size_t inputSize)
71{
72	fStream.next_in = (Bytef*)input;
73	fStream.avail_in = inputSize;
74
75	while (fStream.avail_in > 0) {
76		uint8 outputBuffer[kOutputBufferSize];
77		fStream.next_out = (Bytef*)outputBuffer;
78		fStream.avail_out = sizeof(outputBuffer);
79
80		int zlibError = deflate(&fStream, 0);
81		if (zlibError != Z_OK)
82			return TranslateZlibError(zlibError);
83
84		if (fStream.avail_out < sizeof(outputBuffer)) {
85			status_t error = fOutput->WriteData(outputBuffer,
86				sizeof(outputBuffer) - fStream.avail_out);
87			if (error != B_OK)
88				return error;
89		}
90	}
91
92	return B_OK;
93}
94
95
96status_t
97ZlibCompressor::Finish()
98{
99	fStream.next_in = (Bytef*)NULL;
100	fStream.avail_in = 0;
101
102	while (true) {
103		uint8 outputBuffer[kOutputBufferSize];
104		fStream.next_out = (Bytef*)outputBuffer;
105		fStream.avail_out = sizeof(outputBuffer);
106
107		int zlibError = deflate(&fStream, Z_FINISH);
108		if (zlibError != Z_OK && zlibError != Z_STREAM_END)
109			return TranslateZlibError(zlibError);
110
111		if (fStream.avail_out < sizeof(outputBuffer)) {
112			status_t error = fOutput->WriteData(outputBuffer,
113				sizeof(outputBuffer) - fStream.avail_out);
114			if (error != B_OK)
115				return error;
116		}
117
118		if (zlibError == Z_STREAM_END)
119			break;
120	}
121
122	deflateEnd(&fStream);
123	fStreamInitialized = false;
124
125	return B_OK;
126}
127
128
129/*static*/ status_t
130ZlibCompressor::CompressSingleBuffer(const void* input, size_t inputSize,
131	void* output, size_t outputSize, size_t& _compressedSize)
132{
133	if (inputSize == 0 || outputSize == 0)
134		return B_BAD_VALUE;
135
136	// prepare stream
137	z_stream zStream = {
138		(Bytef*)input,				// next_in
139		inputSize,					// avail_in
140		0,							// total_in
141		(Bytef*)output,				// next_out
142		outputSize,					// avail_out
143		0,							// total_out
144		0,							// msg
145		0,							// state;
146		Z_NULL,						// zalloc
147		Z_NULL,						// zfree
148		Z_NULL,						// opaque
149		0,							// data_type
150		0,							// adler
151		0							// reserved
152	};
153
154	int zlibError = deflateInit(&zStream, Z_BEST_COMPRESSION);
155	if (zlibError != Z_OK)
156		return TranslateZlibError(zlibError);
157
158	// deflate
159	status_t error = B_OK;
160	zlibError = deflate(&zStream, Z_FINISH);
161	if (zlibError != Z_STREAM_END) {
162		if (zlibError == Z_OK)
163			error = B_BUFFER_OVERFLOW;
164		else
165			error = TranslateZlibError(zlibError);
166	}
167
168	// clean up
169	zlibError = deflateEnd(&zStream);
170	if (zlibError != Z_OK && error == B_OK)
171		error = TranslateZlibError(zlibError);
172
173	if (error != B_OK)
174		return error;
175
176	_compressedSize = zStream.total_out;
177	return B_OK;
178}
179
180
181}	// namespace BPrivate
182
183}	// namespace BHPKG
184
185}	// namespace BPackageKit
186