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

strigi/src/streams

listinginprogress.cpp

Go to the documentation of this file.
00001 /* This file is part of Strigi Desktop Search
00002  *
00003  * Copyright (C) 2006,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 "listinginprogress.h"
00021 #include "gzipinputstream.h"
00022 #include "bz2inputstream.h"
00023 #include "lzmainputstream.h"
00024 #include <iostream>
00025 
00026 using namespace Strigi;
00027 using namespace std;
00028 
00029 namespace {
00037 void
00038 addEntry(ArchiveEntryCache::SubEntry* parent,
00039         ArchiveEntryCache::SubEntry* se) {
00040     // split path into components, the components are placed in the array
00041     // 'names'. The filename is kept in the filename member of se
00042     vector<string> names;
00043     string& name = se->entry.filename;
00044     string::size_type p = name.find('/');
00045     while (p != string::npos) {
00046         names.push_back(name.substr(0, p));
00047         name.erase(0, p + 1);
00048         p = name.find('/');
00049     }
00050 
00051     // find the right entry
00052     ArchiveEntryCache::SubEntry* child;
00053     for (size_t i=0; i<names.size(); ++i) {
00054         child = parent->entries[names[i]];
00055         if (child == NULL) {
00056             // create a new directory entry if it is not yet in the cache
00057             child = new ArchiveEntryCache::SubEntry();
00058             child->entry.filename = names[i];
00059             child->entry.type = EntryInfo::Dir;
00060             child->entry.size = 0;
00061             parent->entries[names[i]] = child;
00062         }
00063         parent = child;
00064     }
00065     // this is what we came for: add the entry to the parent
00066     parent->entries[name] = se;
00067 }
00068 }
00069 
00070 void
00071 free(list<StreamPtr>& l) {
00072     list<StreamPtr>::iterator i;
00073     for (i=l.begin(); i!=l.end(); ++i) {
00074         i->free();
00075     }
00076     l.clear();
00077 }
00078 
00079 SubStreamProvider*
00080 subStreamProvider(const Subs& subs, InputStream* input,
00081          list<StreamPtr>& streams) {
00082     if (input == 0) return 0;
00083     InputStream* s = input;
00084 
00085     bool foundCompressedStream;
00086     int nestingDepth = 0;
00087     do {
00088         foundCompressedStream = false;
00089         // check if this is a compressed stream
00090         const char* c;
00091         int32_t n = s->read(c, 16, 0);
00092         s->reset(0);
00093         if (BZ2InputStream::checkHeader(c, n)) {
00094             InputStream* ns = new BZ2InputStream(s);
00095             if (ns->status() == Ok) {
00096                 foundCompressedStream = true;
00097                 s = ns;
00098                 streams.push_back(s);
00099             } else {
00100                 delete ns;
00101                 s->reset(0);
00102             }
00103         }
00104         n = s->read(c, 2, 0);
00105         s->reset(0);
00106         if (n >= 2 && c[0] == 0x1f && c[1] == (char)0x8b) {
00107             InputStream* ns = new GZipInputStream(s);
00108             if (ns->status() == Ok) {
00109                 foundCompressedStream = true;
00110                 s = ns;
00111                 streams.push_back(s);
00112             } else {
00113                 delete ns;
00114                 s->reset(0);
00115             }
00116         }
00117         n = s->read(c, 2, 0);
00118         s->reset(0);
00119         if (LZMAInputStream::checkHeader(c, n)) {
00120             InputStream* ns = new LZMAInputStream(s);
00121             if (ns->status() == Ok) {
00122                 foundCompressedStream = true;
00123                 s = ns;
00124                 streams.push_back(s);
00125             } else {
00126                 delete ns;
00127                 s->reset(0);
00128             }
00129         }
00130     } while (foundCompressedStream && nestingDepth++ < 32);
00131  
00132     const char* c;
00133     int32_t n = s->read(c, 1024, 0);
00134     s->reset(0);
00135     SubStreamProvider* ss;
00136     map<bool (*)(const char*, int32_t),
00137         SubStreamProvider* (*)(InputStream*)>::const_iterator i;
00138     for (i = subs.begin(); i != subs.end(); ++i) {
00139         // check if the header matches for each substreamprovider
00140         if (i->first(c, n)) {
00141             // create a new SubStreamProvider
00142             ss = i->second(s);
00143             if (ss->nextEntry()) {
00144                 streams.push_back(ss);
00145                 // return the first substream
00146                 return ss;
00147             }
00148             // even though the header was good, this stream has no substream
00149             delete ss;
00150             s->reset(0);
00151             n = s->read(c, 1, 0);
00152             s->reset(0);
00153         }
00154     }
00155     free(streams);
00156     return 0;
00157 }
00158 
00159 ListingInProgress::ListingInProgress(const Subs& sbs,
00160         const EntryInfo& entry, const std::string& u, InputStream* s)
00161         :subs(sbs), stream(s), refcount(0), url(u) {
00162     root = new ArchiveEntryCache::RootSubEntry();
00163     root->entry = entry;
00164     root->indexed = true;
00165     stack.resize(10);
00166     StackEntry& e = stack[0];
00167     e.entry = root;
00168     e.p = subStreamProvider(subs, s, e.streams);
00169     if (e.p) {
00170         e.entry->entry.type
00171                 = (EntryInfo::Type)(e.entry->entry.type|EntryInfo::Dir);
00172         currentdepth = 0;
00173     } else {
00174         currentdepth = -1;
00175     }
00176 }
00177 ListingInProgress::~ListingInProgress() {
00178     for (size_t i=0; i<stack.size(); ++i) {
00179         free(stack[i].streams);
00180     }
00181     delete root;
00182     delete stream;
00183 }
00184 void
00185 ListingInProgress::fillEntry(InputStream* s) {
00186     stack.resize(10);
00187     StackEntry& e = stack[0];
00188     e.entry = root;
00189     e.p = subStreamProvider(subs, s, e.streams);
00190     if (e.p) {
00191         e.entry->entry.type
00192                 = (EntryInfo::Type)(e.entry->entry.type|EntryInfo::Dir);
00193         int depth = 0;
00194         do {
00195             depth = nextEntry(depth);
00196         } while (depth >= 0);
00197     }
00198 }
00199 int
00200 ListingInProgress::nextEntry(int depth) {
00201     if (stack.size() < (size_t)(depth+1)) {
00202         stack.resize(depth+1);
00203     }
00204     StackEntry* e = &stack[depth];
00205     StackEntry* ce = &stack[depth+1];
00206     if (e->p) {
00207         // create a child entry
00208         ce->entry = new ArchiveEntryCache::SubEntry();
00209         ce->entry->entry = e->p->entryInfo();
00210         ce->p = subStreamProvider(subs, e->p->currentEntry(), ce->streams);
00211         if (ce->p) {
00212             // the child has substreams too
00213             ce->entry->entry.type
00214                 = (EntryInfo::Type)(ce->entry->entry.type|EntryInfo::Dir);
00215             return nextEntry(depth+1);
00216         }
00217     } else if (depth--) {
00218         ce = e;
00219         e = &stack[depth];
00220     }
00221     if (depth >= 0) {
00222         if (ce->entry->entry.size < 0) {
00223             // read entire stream to determine it's size
00224             InputStream *es = e->p->currentEntry();
00225             const char* c;
00226             while (es->read(c, 1, 0) > 0) {}
00227             ce->entry->entry.size = max(es->size(), (int64_t)0);
00228         }
00229         addEntry(e->entry, ce->entry);
00230         if (!e->p->nextEntry()) {
00231             free(e->streams);
00232             e->p = 0;
00233         }
00234     }
00235     return depth;
00236 }
00237 bool
00238 ListingInProgress::nextEntry() {
00239     if (currentdepth >= 0) {
00240         currentdepth = nextEntry(currentdepth);
00241     }
00242     if (currentdepth < 0) {
00243         delete stream;
00244         stream = 0;
00245     }
00246     return currentdepth >= 0;
00247 }
00248 const ArchiveEntryCache::SubEntry*
00249 ListingInProgress::nextEntry(const std::string& url) {
00250     if (url == this->url) {
00251         return (root->entries.size() || nextEntry(root)) ?root :NULL;
00252     }
00253     const ArchiveEntryCache::SubEntry* entry = root->findEntry(this->url, url);
00254     bool ok = true;
00255     while (ok && (entry == NULL || entry->entries.size() == 0)) {
00256         ok = nextEntry();
00257         entry = root->findEntry(this->url, url);
00258     }
00259     return entry;
00260 }
00261 bool
00262 ListingInProgress::nextEntry(const ArchiveEntryCache::SubEntry* entry) {
00263     if (currentdepth < 0) return false;
00264     size_t initialSize = entry->entries.size();
00265     bool ok;
00266     do {
00267         ok = nextEntry();
00268     } while (ok && initialSize == entry->entries.size());
00269     return entry->entries.size() > initialSize;
00270 }
00271 bool
00272 ListingInProgress::isDone() const {
00273     return stream == NULL;
00274 }

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