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