• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDE Support
  • Sitemap
  • Contact Us
 

strigi/src/streams

lzmainputstream.cpp

Go to the documentation of this file.
00001 /* This file is part of Strigi Desktop Search
00002  *
00003  * Copyright (C) 2009 Jos van den Oever <jos@vandenoever.info>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
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     // lzma does not have magic bytes, but it has a function for parsing
00051     // the header which contains the stream properties
00052     // nevertheless some use '5d 00' as the magic bytes
00053     if (data[0] != 0x5d || data[1] != 0x00) return false;
00054 
00055     // by limiting the range of sizes and doing a sanity check on the
00056     // size of the dictionary, the number of files that are regarded as valid
00057     // can be limited
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)); // only support < 1Tb 
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     // check the header and read the size of the uncompressed stream
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         // allocate the decompressor
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     // signal that we need to read into the buffer
00095     avail_in = 0;
00096 
00097     // set the minimum size for the output buffer
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     // read data from the input stream
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     // make sure there is data to decompress
00129     if (avail_in == 0) {
00130         readFromStream();
00131         if (p->m_status != Ok) {
00132             // no data was read
00133             return -1;
00134         }
00135     }
00136     // decompress
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 }

strigi/src/streams

Skip menu "strigi/src/streams"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

KDE Support

Skip menu "KDE Support"
  • akonadi
  • Decibel
  • grantlee
  • kdewin
  • phonon
  •     Backend
  • polkit-qt
  • qca
  • qimageblitz
  • soprano
  • strigi
  •     searchclient
  •     streamanalyzer
  •     streams
Generated for KDE Support by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal