xref: /haiku/src/kits/support/CompressionAlgorithm.cpp (revision 548149fe48f59cf27f6071e9629b8bbe2ad32c1f)
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 
18 BCompressionParameters::BCompressionParameters()
19 {
20 }
21 
22 
23 BCompressionParameters::~BCompressionParameters()
24 {
25 }
26 
27 
28 // #pragma mark - BDecompressionParameters
29 
30 
31 BDecompressionParameters::BDecompressionParameters()
32 {
33 }
34 
35 
36 BDecompressionParameters::~BDecompressionParameters()
37 {
38 }
39 
40 
41 // #pragma mark - BCompressionAlgorithm
42 
43 
44 BCompressionAlgorithm::BCompressionAlgorithm()
45 {
46 }
47 
48 
49 BCompressionAlgorithm::~BCompressionAlgorithm()
50 {
51 }
52 
53 
54 status_t
55 BCompressionAlgorithm::CreateCompressingInputStream(BDataIO* input,
56 	const BCompressionParameters* parameters, BDataIO*& _stream)
57 {
58 	return B_NOT_SUPPORTED;
59 }
60 
61 
62 status_t
63 BCompressionAlgorithm::CreateCompressingOutputStream(BDataIO* output,
64 	const BCompressionParameters* parameters, BDataIO*& _stream)
65 {
66 	return B_NOT_SUPPORTED;
67 }
68 
69 
70 status_t
71 BCompressionAlgorithm::CreateDecompressingInputStream(BDataIO* input,
72 	const BDecompressionParameters* parameters, BDataIO*& _stream)
73 {
74 	return B_NOT_SUPPORTED;
75 }
76 
77 
78 status_t
79 BCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
80 	const BDecompressionParameters* parameters, BDataIO*& _stream)
81 {
82 	return B_NOT_SUPPORTED;
83 }
84 
85 
86 status_t
87 BCompressionAlgorithm::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 
95 status_t
96 BCompressionAlgorithm::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 
107 BCompressionAlgorithm::BAbstractStream::BAbstractStream()
108 	:
109 	BDataIO(),
110 	fBuffer(NULL),
111 	fBufferCapacity(0),
112 	fBufferOffset(0),
113 	fBufferSize(0)
114 {
115 }
116 
117 
118 BCompressionAlgorithm::BAbstractStream::~BAbstractStream()
119 {
120 	free(fBuffer);
121 }
122 
123 
124 status_t
125 BCompressionAlgorithm::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 
137 BCompressionAlgorithm::BAbstractInputStream::BAbstractInputStream(
138 		BDataIO* input)
139 	:
140 	BAbstractStream(),
141 	fInput(input),
142 	fEndOfInput(false),
143 	fNoMorePendingData(false)
144 {
145 }
146 
147 
148 BCompressionAlgorithm::BAbstractInputStream::~BAbstractInputStream()
149 {
150 }
151 
152 
153 ssize_t
154 BCompressionAlgorithm::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 
233 BCompressionAlgorithm::BAbstractOutputStream::BAbstractOutputStream(
234 		BDataIO* output)
235 	:
236 	BAbstractStream(),
237 	fOutput(output)
238 {
239 }
240 
241 
242 BCompressionAlgorithm::BAbstractOutputStream::~BAbstractOutputStream()
243 {
244 }
245 
246 
247 ssize_t
248 BCompressionAlgorithm::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 
297 status_t
298 BCompressionAlgorithm::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