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