strigi/src/streams
gzipinputstream.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 "gzipinputstream.h"
00021 #include <strigi/strigiconfig.h>
00022 #include <zlib.h>
00023 #include <stdlib.h>
00024
00025 using namespace Strigi;
00026
00027 class GZipInputStream::Private {
00028 public:
00029 GZipInputStream* const p;
00030 InputStream* input;
00031 z_stream_s* zstream;
00032
00033 Private(GZipInputStream* gi, InputStream* input, ZipFormat format);
00034 ~Private();
00035 void dealloc();
00036 void readFromStream();
00037 void decompressFromStream();
00038 bool checkMagic();
00039 };
00040 GZipInputStream::GZipInputStream(InputStream* input, ZipFormat format)
00041 :p(new Private(this, input, format)) {
00042 }
00043 GZipInputStream::Private::Private(GZipInputStream* gi,
00044 InputStream* i, ZipFormat format) :p(gi), input(i), zstream(0) {
00045
00046 p->m_status = Ok;
00047
00048
00049 if (format == GZIPFORMAT && !checkMagic()) {
00050 p->m_error = "Magic bytes for gz are wrong.";
00051 p->m_status = Error;
00052 return;
00053 }
00054
00055
00056 zstream = (z_stream_s*)malloc(sizeof(z_stream_s));
00057 zstream->zalloc = Z_NULL;
00058 zstream->zfree = Z_NULL;
00059 zstream->opaque = Z_NULL;
00060 zstream->avail_in = 0;
00061 zstream->next_in = Z_NULL;
00062
00063
00064 int r;
00065 switch(format) {
00066 case ZLIBFORMAT:
00067 r = inflateInit(zstream);
00068 break;
00069 case GZIPFORMAT:
00070 r = inflateInit2(zstream, 15+16);
00071 break;
00072 case ZIPFORMAT:
00073 default:
00074 r = inflateInit2(zstream, -MAX_WBITS);
00075 break;
00076 }
00077 if (r != Z_OK) {
00078 p->m_error = "Error initializing GZipInputStream.";
00079 dealloc();
00080 p->m_status = Error;
00081 return;
00082 }
00083
00084
00085 zstream->avail_out = 1;
00086
00087
00088 p->setMinBufSize(262144);
00089 }
00090 GZipInputStream::~GZipInputStream() {
00091 delete p;
00092 }
00093 GZipInputStream::Private::~Private() {
00094 dealloc();
00095 }
00096 void
00097 GZipInputStream::Private::dealloc() {
00098 if (zstream) {
00099 inflateEnd(zstream);
00100 free(zstream);
00101 zstream = 0;
00102 }
00103 }
00104 bool
00105 GZipInputStream::Private::checkMagic() {
00106 const unsigned char* buf;
00107 const char* begin;
00108 int32_t nread;
00109
00110 int64_t pos = input->position();
00111 nread = input->read(begin, 2, 2);
00112 input->reset(pos);
00113 if (nread != 2) {
00114 return false;
00115 }
00116
00117 buf = (const unsigned char*)begin;
00118 return buf[0] == 0x1f && buf[1] == 0x8b;
00119 }
00120 void
00121 GZipInputStream::Private::readFromStream() {
00122
00123 const char* inStart;
00124 int32_t nread;
00125 nread = input->read(inStart, 1, 0);
00126 if (nread < -1) {
00127 p->m_status = Error;
00128 p->m_error = input->error();
00129 } else if (nread < 1) {
00130 p->m_status = Error;
00131 p->m_error.assign("unexpected end of stream");
00132 } else {
00133 zstream->next_in = (Bytef*)inStart;
00134 zstream->avail_in = nread;
00135 }
00136 }
00137 int32_t
00138 GZipInputStream::fillBuffer(char* start, int32_t space) {
00139 z_stream_s* zstream = p->zstream;
00140 if (zstream == 0) return -1;
00141
00142 if (zstream->avail_out) {
00143 p->readFromStream();
00144 if (m_status == Error) {
00145
00146 return -1;
00147 }
00148 }
00149
00150 zstream->avail_out = space;
00151 zstream->next_out = (Bytef*)start;
00152
00153 int r = inflate(zstream, Z_SYNC_FLUSH);
00154
00155 int32_t nwritten = space - zstream->avail_out;
00156 switch (r) {
00157 case Z_NEED_DICT:
00158 m_error.assign("Z_NEED_DICT while inflating stream.");
00159 m_status = Error;
00160 break;
00161 case Z_DATA_ERROR:
00162 m_error.assign("Z_DATA_ERROR while inflating stream.");
00163 m_status = Error;
00164 break;
00165 case Z_MEM_ERROR:
00166 m_error.assign("Z_MEM_ERROR while inflating stream.");
00167 m_status = Error;
00168 break;
00169 case Z_STREAM_END:
00170 if (zstream->avail_in) {
00171 p->input->reset(p->input->position()-zstream->avail_in);
00172 }
00173
00174
00175 p->dealloc();
00176 }
00177 return nwritten;
00178 }