strigi/src/streams
lzmainputstream.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 "lzmainputstream.h"
00021 extern "C" {
00022 #include "lzma/LzmaDec.h"
00023 }
00024 #include "textutils.h"
00025 #include <iostream>
00026 #include <sstream>
00027
00028 using namespace Strigi;
00029 using namespace std;
00030
00031 class LZMAInputStream::Private {
00032 public:
00033 LZMAInputStream* const p;
00034 CLzmaProps props;
00035 CLzmaDec state;
00036 InputStream *input;
00037 const char* next_in;
00038 int32_t avail_in;
00039 int64_t bytesDecompressed;
00040
00041 Private(LZMAInputStream* p, InputStream* i);
00042 ~Private();
00043 void readFromStream();
00044 int32_t fillBuffer(char* start, int32_t space);
00045 };
00046 bool
00047 LZMAInputStream::checkHeader(const char* data, int32_t datasize) {
00048 if (datasize < LZMA_PROPS_SIZE + 8) return false;
00049
00050
00051
00052
00053 if (data[0] != 0x5d || data[1] != 0x00) return false;
00054
00055
00056
00057
00058 CLzmaProps props;
00059 SRes res = LzmaProps_Decode(&props, (const Byte*)data, LZMA_PROPS_SIZE);
00060 int64_t size = readLittleEndianInt64(data + LZMA_PROPS_SIZE);
00061 return res == SZ_OK && props.dicSize <= 8388608 && (size == -1 ||
00062 (props.dicSize < size && size < 1099511627776LL));
00063 }
00064 LZMAInputStream::LZMAInputStream(InputStream* input)
00065 :p(new Private(this, input)){
00066 }
00067 static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
00068 static void SzFree(void *p, void *address) { p = p; free(address); }
00069 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
00070 LZMAInputStream::Private::Private(LZMAInputStream* bis, InputStream* i)
00071 :p(bis), input(i) {
00072
00073
00074 SRes res = SZ_ERROR_UNSUPPORTED;
00075 LzmaDec_Construct(&state);
00076 const char* data;
00077 int32_t nread;
00078 const int32_t headersize = LZMA_PROPS_SIZE+8;
00079 nread = input->read(data, headersize, headersize);
00080 if (nread == headersize && checkHeader(data, headersize)) {
00081
00082 res = LzmaDec_Allocate(&state, (const Byte*)data, LZMA_PROPS_SIZE,
00083 &g_Alloc);
00084 p->m_size = readLittleEndianInt64(data + LZMA_PROPS_SIZE);
00085 }
00086 if (res != SZ_OK || p->m_size < -1) {
00087 p->m_error = "LZMA header is not supported.";
00088 p->m_status = Error;
00089 return;
00090 }
00091 LzmaDec_Init(&state);
00092 bytesDecompressed = 0;
00093
00094
00095 avail_in = 0;
00096
00097
00098 p->setMinBufSize(262144);
00099 }
00100 LZMAInputStream::~LZMAInputStream() {
00101 delete p;
00102 }
00103 LZMAInputStream::Private::~Private() {
00104 LzmaDec_Free(&state, &g_Alloc);
00105 }
00106 void
00107 LZMAInputStream::Private::readFromStream() {
00108
00109 avail_in = input->read(next_in, 1, 0);
00110 if (avail_in <= -1) {
00111 p->m_status = Error;
00112 p->m_error = input->error();
00113 } else if (avail_in < 1) {
00114 p->m_status = Error;
00115 p->m_error = "unexpected end of stream";
00116 }
00117 }
00118 int32_t
00119 LZMAInputStream::fillBuffer(char* start, int32_t space) {
00120 if (m_status != Ok) return -1;
00121 if (m_size == p->bytesDecompressed) {
00122 return -1;
00123 }
00124 return p->fillBuffer(start, space);
00125 }
00126 int32_t
00127 LZMAInputStream::Private::fillBuffer(char* start, int32_t space) {
00128
00129 if (avail_in == 0) {
00130 readFromStream();
00131 if (p->m_status != Ok) {
00132
00133 return -1;
00134 }
00135 }
00136
00137 SizeT outProcessed = space;
00138 SizeT inProcessed = avail_in;
00139 ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
00140 int64_t bytesTodo = p->m_size - bytesDecompressed;
00141 if (p->m_size != -1 && outProcessed > bytesTodo) {
00142 outProcessed = (SizeT)bytesTodo;
00143 finishMode = LZMA_FINISH_END;
00144 }
00145 ELzmaStatus status;
00146 SRes res = LzmaDec_DecodeToBuf(&state, (Byte*)start, &outProcessed,
00147 (const Byte*)next_in, &inProcessed, finishMode, &status);
00148 avail_in -= inProcessed;
00149 next_in += inProcessed;
00150 bytesDecompressed += outProcessed;
00151 if (res != SZ_OK) {
00152 ostringstream str;
00153 str << "error decompressing dicsize: " << props.dicSize
00154 << " size: " << p->m_size
00155 << " decompressed: " << bytesDecompressed;
00156 p->m_error = str.str();
00157 p->m_status = Error;
00158 return -1;
00159 }
00160 if (inProcessed == 0 && outProcessed == 0) {
00161 if (p->m_size != -1 || status != LZMA_STATUS_FINISHED_WITH_MARK) {
00162 p->m_error = "unexpected end";
00163 p->m_status = Error;
00164 return -1;
00165 }
00166 p->m_size = bytesDecompressed;
00167 } else if (status == LZMA_STATUS_FINISHED_WITH_MARK) {
00168 p->m_size = bytesDecompressed;
00169 }
00170 return outProcessed;
00171 }