strigi/src/streams
bz2inputstream.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "bz2inputstream.h"
00021 #include <bzlib.h>
00022 #include <stdlib.h>
00023 #include <cstring>
00024
00025 using namespace Strigi;
00026
00027 class BZ2InputStream::Private {
00028 public:
00029 BZ2InputStream* const p;
00030 InputStream *input;
00031 bz_stream* bzstream;
00032 bool allocatedBz;
00033
00034 Private(BZ2InputStream* p, InputStream* i);
00035 ~Private();
00036 void dealloc();
00037 void readFromStream();
00038 bool checkMagic();
00039 };
00040 bool
00041 BZ2InputStream::checkHeader(const char* data, int32_t datasize) {
00042 static const char magic[] = {0x42, 0x5a};
00043 static const char compressed_magic[] = {0x31, 0x41, 0x59, 0x26, 0x53, 0x59};
00044 if (datasize < 10) return false;
00045 return (std::memcmp(data, magic, 2) == 0
00046 && (data[2] == 0x68 || data[2] == 0x30)
00047 && std::memcmp(data + 4, compressed_magic, 6) == 0);
00048 }
00049 BZ2InputStream::BZ2InputStream(InputStream* input) :p(new Private(this, input)){
00050 }
00051 BZ2InputStream::Private::Private(BZ2InputStream* bis, InputStream* i)
00052 :p(bis), input(i) {
00053
00054 this->input = input;
00055
00056
00057 if (!checkMagic()) {
00058 p->m_error = "Magic bytes for bz2 are wrong.";
00059 p->m_status = Error;
00060 allocatedBz = false;
00061 return;
00062 }
00063
00064 bzstream = (bz_stream*)malloc(sizeof(bz_stream));
00065 bzstream->bzalloc = NULL;
00066 bzstream->bzfree = NULL;
00067 bzstream->opaque = NULL;
00068 bzstream->avail_in = 0;
00069 bzstream->next_in = NULL;
00070 int r;
00071 r = BZ2_bzDecompressInit(bzstream, 1, 0);
00072 if (r != BZ_OK) {
00073 p->m_error = "Error initializing BZ2InputStream.";
00074 fprintf(stderr, "Error initializing BZ2InputStream.\n");
00075 dealloc();
00076 p->m_status = Error;
00077 return;
00078 }
00079 allocatedBz = true;
00080
00081 bzstream->avail_out = 1;
00082
00083
00084 p->setMinBufSize(262144);
00085 }
00086 BZ2InputStream::~BZ2InputStream() {
00087 delete p;
00088 }
00089 BZ2InputStream::Private::~Private() {
00090 dealloc();
00091 }
00092 void
00093 BZ2InputStream::Private::dealloc() {
00094 if (allocatedBz) {
00095 BZ2_bzDecompressEnd(bzstream);
00096 free(bzstream);
00097 bzstream = 0;
00098 }
00099 }
00100 bool
00101 BZ2InputStream::Private::checkMagic() {
00102 const char* begin;
00103 int32_t nread;
00104
00105 int64_t pos = input->position();
00106 nread = input->read(begin, 10, 0);
00107 input->reset(pos);
00108 if (nread < 10) {
00109 return false;
00110 }
00111
00112 return checkHeader(begin, 10);
00113 }
00114 void
00115 BZ2InputStream::Private::readFromStream() {
00116
00117 const char* inStart;
00118 int32_t nread;
00119 nread = input->read(inStart, 1, 0);
00120 if (nread <= -1) {
00121 p->m_status = Error;
00122 p->m_error = input->error();
00123 } else if (nread < 1) {
00124 p->m_status = Error;
00125 p->m_error = "unexpected end of stream";
00126 } else {
00127 bzstream->next_in = (char*)inStart;
00128 bzstream->avail_in = nread;
00129 }
00130 }
00131 int32_t
00132 BZ2InputStream::fillBuffer(char* start, int32_t space) {
00133 bz_stream* bzstream = p->bzstream;
00134 if (bzstream == 0) return -1;
00135
00136 if (bzstream->avail_out != 0) {
00137 p->readFromStream();
00138 if (m_status != Ok) {
00139
00140 return -1;
00141 }
00142 }
00143
00144 bzstream->avail_out = space;
00145 bzstream->next_out = start;
00146
00147 int r = BZ2_bzDecompress(bzstream);
00148
00149 int32_t nwritten = space - bzstream->avail_out;
00150 switch (r) {
00151 case BZ_PARAM_ERROR:
00152 m_error = "BZ_PARAM_ERROR";
00153 m_status = Error;
00154 return -1;
00155 case BZ_DATA_ERROR:
00156 m_error = "BZ_DATA_ERROR";
00157 m_status = Error;
00158 return -1;
00159 case BZ_DATA_ERROR_MAGIC:
00160 m_error = "BZ_DATA_ERROR_MAGIC";
00161 m_status = Error;
00162 return -1;
00163 case BZ_MEM_ERROR:
00164 m_error = "BZ_MEM_ERROR";
00165 m_status = Error;
00166 return -1;
00167 case BZ_STREAM_END:
00168 if (bzstream->avail_in) {
00169 p->input->reset(p->input->position()-bzstream->avail_in);
00170 }
00171
00172
00173 p->dealloc();
00174 }
00175 return nwritten;
00176 }