strigi/src/streams
listinginprogress.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 "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
00041
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
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
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
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
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
00140 if (i->first(c, n)) {
00141
00142 ss = i->second(s);
00143 if (ss->nextEntry()) {
00144 streams.push_back(ss);
00145
00146 return ss;
00147 }
00148
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
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
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
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 }