1/*
2 * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <CompressionAlgorithm.h>
8
9#include <stdlib.h>
10#include <string.h>
11
12#include <Errors.h>
13
14
15// #pragma mark - BCompressionParameters
16
17
18BCompressionParameters::BCompressionParameters()
19{
20}
21
22
23BCompressionParameters::~BCompressionParameters()
24{
25}
26
27
28// #pragma mark - BDecompressionParameters
29
30
31BDecompressionParameters::BDecompressionParameters()
32{
33}
34
35
36BDecompressionParameters::~BDecompressionParameters()
37{
38}
39
40
41// #pragma mark - BCompressionAlgorithm
42
43
44BCompressionAlgorithm::BCompressionAlgorithm()
45{
46}
47
48
49BCompressionAlgorithm::~BCompressionAlgorithm()
50{
51}
52
53
54status_t
55BCompressionAlgorithm::CreateCompressingInputStream(BDataIO* input,
56	const BCompressionParameters* parameters, BDataIO*& _stream)
57{
58	return B_NOT_SUPPORTED;
59}
60
61
62status_t
63BCompressionAlgorithm::CreateCompressingOutputStream(BDataIO* output,
64	const BCompressionParameters* parameters, BDataIO*& _stream)
65{
66	return B_NOT_SUPPORTED;
67}
68
69
70status_t
71BCompressionAlgorithm::CreateDecompressingInputStream(BDataIO* input,
72	const BDecompressionParameters* parameters, BDataIO*& _stream)
73{
74	return B_NOT_SUPPORTED;
75}
76
77
78status_t
79BCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
80	const BDecompressionParameters* parameters, BDataIO*& _stream)
81{
82	return B_NOT_SUPPORTED;
83}
84
85
86status_t
87BCompressionAlgorithm::CompressBuffer(const void* input, size_t inputSize,
88	void* output, size_t outputSize, size_t& _compressedSize,
89	const BCompressionParameters* parameters)
90{
91	return B_NOT_SUPPORTED;
92}
93
94
95status_t
96BCompressionAlgorithm::DecompressBuffer(const void* input,
97	size_t inputSize, void* output, size_t outputSize,
98	size_t& _uncompressedSize, const BDecompressionParameters* parameters)
99{
100	return B_NOT_SUPPORTED;
101}
102
103
104// #pragma mark - BAbstractStream
105
106
107BCompressionAlgorithm::BAbstractStream::BAbstractStream()
108	:
109	BDataIO(),
110	fBuffer(NULL),
111	fBufferCapacity(0),
112	fBufferOffset(0),
113	fBufferSize(0)
114{
115}
116
117
118BCompressionAlgorithm::BAbstractStream::~BAbstractStream()
119{
120	free(fBuffer);
121}
122
123
124status_t
125BCompressionAlgorithm::BAbstractStream::Init(size_t bufferSize)
126{
127	fBuffer = (uint8*)malloc(bufferSize);
128	fBufferCapacity = bufferSize;
129
130	return fBuffer != NULL ? B_OK : B_NO_MEMORY;
131}
132
133
134// #pragma mark - BAbstractInputStream
135
136
137BCompressionAlgorithm::BAbstractInputStream::BAbstractInputStream(
138		BDataIO* input)
139	:
140	BAbstractStream(),
141	fInput(input),
142	fEndOfInput(false),
143	fNoMorePendingData(false)
144{
145}
146
147
148BCompressionAlgorithm::BAbstractInputStream::~BAbstractInputStream()
149{
150}
151
152
153ssize_t
154BCompressionAlgorithm::BAbstractInputStream::Read(void* buffer, size_t size)
155{
156	if (size == 0)
157		return 0;
158
159	size_t bytesRemaining = size;
160	uint8* output = (uint8*)buffer;
161
162	while (bytesRemaining > 0) {
163		// process the data still in the input buffer
164		if (fBufferSize > 0) {
165			size_t bytesConsumed;
166			size_t bytesProduced;
167			status_t error = ProcessData(fBuffer + fBufferOffset, fBufferSize,
168				output, bytesRemaining, bytesConsumed, bytesProduced);
169			if (error != B_OK)
170				return error;
171
172			fBufferOffset += bytesConsumed;
173			fBufferSize -= bytesConsumed;
174			output += bytesProduced;
175			bytesRemaining -= bytesProduced;
176			continue;
177		}
178
179		// We couldn't process anything, because we don't have any or not enough
180		// bytes in the input buffer.
181
182		if (fEndOfInput)
183			break;
184
185		// Move any remaining data to the start of the buffer.
186		if (fBufferSize > 0) {
187			if (fBufferSize == fBufferCapacity)
188				return B_ERROR;
189
190			if (fBufferOffset > 0)
191				memmove(fBuffer, fBuffer + fBufferOffset, fBufferSize);
192		}
193
194		fBufferOffset = 0;
195
196		// read from the source
197		ssize_t bytesRead = fInput->Read(fBuffer + fBufferSize,
198			fBufferCapacity - fBufferSize);
199		if (bytesRead < 0)
200			return bytesRead;
201		if (bytesRead == 0) {
202			fEndOfInput = true;
203			break;
204		}
205
206		fBufferSize += bytesRead;
207	}
208
209	// If we've reached the end of the input and still have room in the output
210	// buffer, we have consumed all input data and want to flush all pending
211	// data, now.
212	if (fEndOfInput && bytesRemaining > 0 && !fNoMorePendingData) {
213		size_t bytesProduced;
214		status_t error = FlushPendingData(output, bytesRemaining,
215			bytesProduced);
216		if (error != B_OK)
217			return error;
218
219		if (bytesProduced < bytesRemaining)
220			fNoMorePendingData = true;
221
222		output += bytesProduced;
223		bytesRemaining -= bytesProduced;
224	}
225
226	return size - bytesRemaining;
227}
228
229
230// #pragma mark - BAbstractOutputStream
231
232
233BCompressionAlgorithm::BAbstractOutputStream::BAbstractOutputStream(
234		BDataIO* output)
235	:
236	BAbstractStream(),
237	fOutput(output)
238{
239}
240
241
242BCompressionAlgorithm::BAbstractOutputStream::~BAbstractOutputStream()
243{
244}
245
246
247ssize_t
248BCompressionAlgorithm::BAbstractOutputStream::Write(const void* buffer,
249	size_t size)
250{
251	if (size == 0)
252		return 0;
253
254	size_t bytesRemaining = size;
255	uint8* input = (uint8*)buffer;
256
257	while (bytesRemaining > 0) {
258		// try to process more data
259		if (fBufferSize < fBufferCapacity) {
260			size_t bytesConsumed;
261			size_t bytesProduced;
262			status_t error = ProcessData(input, bytesRemaining,
263				fBuffer + fBufferSize, fBufferCapacity - fBufferSize,
264				bytesConsumed, bytesProduced);
265			if (error != B_OK)
266				return error;
267
268			input += bytesConsumed;
269			bytesRemaining -= bytesConsumed;
270			fBufferSize += bytesProduced;
271			continue;
272		}
273
274		// We couldn't process anything, because we don't have any or not enough
275		// room in the output buffer.
276
277		if (fBufferSize == 0)
278			return B_ERROR;
279
280		// write to the target
281		ssize_t bytesWritten = fOutput->Write(fBuffer, fBufferSize);
282		if (bytesWritten < 0)
283			return bytesWritten;
284		if (bytesWritten == 0)
285			break;
286
287		// Move any remaining data to the start of the buffer.
288		fBufferSize -= bytesWritten;
289		if (fBufferSize > 0)
290			memmove(fBuffer, fBuffer + bytesWritten, fBufferSize);
291	}
292
293	return size - bytesRemaining;
294}
295
296
297status_t
298BCompressionAlgorithm::BAbstractOutputStream::Flush()
299{
300	bool noMorePendingData = false;
301
302	for (;;) {
303		// let the derived class flush all pending data
304		if (fBufferSize < fBufferCapacity && !noMorePendingData) {
305			size_t bytesProduced;
306			status_t error = FlushPendingData(fBuffer + fBufferSize,
307				fBufferCapacity - fBufferSize, bytesProduced);
308			if (error != B_OK)
309				return error;
310
311			noMorePendingData = bytesProduced < fBufferCapacity - fBufferSize;
312
313			fBufferSize += bytesProduced;
314		}
315
316		// write buffered data to output
317		if (fBufferSize == 0)
318			break;
319
320		status_t error = fOutput->WriteExactly(fBuffer, fBufferSize);
321		if (error != B_OK)
322			return error;
323
324		fBufferSize = 0;
325	}
326
327	return fOutput->Flush();
328}
329