1 /* 2 * Copyright (C) 2006 Tommi Maekitalo 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied 11 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and 12 * NON-INFRINGEMENT. See the GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 * 18 */ 19 20 #include <zim/article.h> 21 #include "template.h" 22 #include "_dirent.h" 23 #include "cluster.h" 24 #include <zim/fileheader.h> 25 #include "fileimpl.h" 26 #include "file_part.h" 27 #include <sstream> 28 #include <iostream> 29 #include <stdexcept> 30 #include <limits> 31 #include "log.h" 32 33 log_define("zim.article") 34 35 namespace zim 36 { getArticleSize() const37 size_type Article::getArticleSize() const 38 { 39 auto dirent = getDirent(); 40 return size_type(file->getCluster(dirent->getClusterNumber()) 41 ->getBlobSize(dirent->getBlobNumber())); 42 } 43 44 namespace 45 { 46 class Ev : public TemplateParser::Event 47 { 48 std::ostream& out; 49 Article& article; 50 std::shared_ptr<FileImpl> file; 51 unsigned maxRecurse; 52 53 public: Ev(std::ostream & out_,Article & article_,std::shared_ptr<FileImpl> file_,unsigned maxRecurse_)54 Ev(std::ostream& out_, Article& article_, std::shared_ptr<FileImpl> file_, unsigned maxRecurse_) 55 : out(out_), 56 article(article_), 57 file(file_), 58 maxRecurse(maxRecurse_) 59 { } 60 void onData(const std::string& data); 61 void onToken(const std::string& token); 62 void onLink(char ns, const std::string& title); 63 }; 64 onData(const std::string & data)65 void Ev::onData(const std::string& data) 66 { 67 out << data; 68 } 69 onToken(const std::string & token)70 void Ev::onToken(const std::string& token) 71 { 72 log_trace("onToken(\"" << token << "\")"); 73 74 if (token == "title") 75 out << article.getTitle(); 76 else if (token == "url") 77 out << article.getUrl(); 78 else if (token == "namespace") 79 out << article.getNamespace(); 80 else if (token == "content") 81 { 82 if (maxRecurse <= 0) 83 throw std::runtime_error("maximum recursive limit is reached"); 84 article.getPage(out, false, maxRecurse - 1); 85 } 86 else 87 { 88 log_warn("unknown token \"" << token << "\" found in template"); 89 out << "<%" << token << "%>"; 90 } 91 } 92 onLink(char ns,const std::string & url)93 void Ev::onLink(char ns, const std::string& url) 94 { 95 if (maxRecurse <= 0) 96 throw std::runtime_error("maximum recursive limit is reached"); 97 std::pair<bool, article_index_t> r = file->findx(ns, url); 98 if (r.first) { 99 Article(file, article_index_type(r.second)).getPage(out, false, maxRecurse - 1); 100 } else { 101 throw std::runtime_error(std::string("impossible to find article ") + std::string(1, ns) + std::string("/") + url); 102 } 103 } 104 105 } 106 getDirent() const107 std::shared_ptr<const Dirent> Article::getDirent() const 108 { 109 return file->getDirent(article_index_t(idx)); 110 } 111 getParameter() const112 std::string Article::getParameter() const 113 { 114 return getDirent()->getParameter(); 115 } 116 getTitle() const117 std::string Article::getTitle() const 118 { 119 return getDirent()->getTitle(); 120 } 121 getUrl() const122 std::string Article::getUrl() const 123 { 124 return getDirent()->getUrl(); 125 } 126 getLongUrl() const127 std::string Article::getLongUrl() const 128 { 129 return getDirent()->getLongUrl(); 130 } 131 getLibraryMimeType() const132 uint16_t Article::getLibraryMimeType() const 133 { 134 return getDirent()->getMimeType(); 135 } 136 getMimeType() const137 const std::string& Article::getMimeType() const 138 { 139 return file->getMimeType(getLibraryMimeType()); 140 } 141 isRedirect() const142 bool Article::isRedirect() const 143 { 144 return getDirent()->isRedirect(); 145 } 146 isLinktarget() const147 bool Article::isLinktarget() const 148 { 149 return getDirent()->isLinktarget(); 150 } 151 isDeleted() const152 bool Article::isDeleted() const 153 { 154 return getDirent()->isDeleted(); 155 } 156 getNamespace() const157 char Article::getNamespace() const 158 { 159 return getDirent()->getNamespace(); 160 } 161 getRedirectIndex() const162 article_index_type Article::getRedirectIndex() const 163 { 164 return article_index_type(getDirent()->getRedirectIndex()); 165 } 166 getRedirectArticle() const167 Article Article::getRedirectArticle() const 168 { 169 return Article(file, getRedirectIndex()); 170 } 171 getCluster() const172 std::shared_ptr<const Cluster> Article::getCluster() const 173 { 174 auto dirent = getDirent(); 175 if ( !dirent->isArticle() ) { 176 return std::shared_ptr<const Cluster>(); 177 } 178 return file->getCluster(dirent->getClusterNumber()); 179 } getClusterNumber() const180 cluster_index_type Article::getClusterNumber() const { 181 auto dirent= getDirent(); 182 if ( !dirent->isArticle() ) { 183 return std::numeric_limits<cluster_index_type>::max(); 184 } 185 return dirent->getClusterNumber().v; 186 } 187 getData(offset_type offset) const188 Blob Article::getData(offset_type offset) const 189 { 190 auto size = getArticleSize()-offset; 191 return getData(offset, size); 192 } 193 getData(offset_type offset,size_type size) const194 Blob Article::getData(offset_type offset, size_type size) const 195 { 196 std::shared_ptr<const Cluster> cluster = getCluster(); 197 if (!cluster) { 198 return Blob(); 199 } 200 return cluster->getBlob(getDirent()->getBlobNumber(), offset_t(offset), zsize_t(size)); 201 } 202 getOffset() const203 offset_type Article::getOffset() const 204 { 205 auto dirent = getDirent(); 206 if ( !dirent->isArticle() ) 207 return 0; 208 return offset_type(file->getBlobOffset(dirent->getClusterNumber(), dirent->getBlobNumber())); 209 } 210 getDirectAccessInformation() const211 std::pair<std::string, offset_type> Article::getDirectAccessInformation() const 212 { 213 auto dirent = getDirent(); 214 if ( !dirent->isArticle() ) { 215 return std::make_pair("", 0); 216 } 217 218 auto full_offset = file->getBlobOffset(dirent->getClusterNumber(), 219 dirent->getBlobNumber()); 220 221 if (!full_offset) { 222 // cluster is compressed 223 return std::make_pair("", 0); 224 } 225 auto part_its = file->getFileParts(full_offset, zsize_t(getArticleSize())); 226 auto range = part_its.first->first; 227 auto part = part_its.first->second; 228 if (++part_its.first != part_its.second) { 229 return std::make_pair("", 0); 230 } 231 auto local_offset = full_offset - range.min; 232 return std::make_pair(part->filename(), offset_type(local_offset)); 233 } 234 getPage(bool layout,unsigned maxRecurse)235 std::string Article::getPage(bool layout, unsigned maxRecurse) 236 { 237 std::ostringstream s; 238 getPage(s, layout, maxRecurse); 239 return s.str(); 240 } 241 getPage(std::ostream & out,bool layout,unsigned maxRecurse)242 void Article::getPage(std::ostream& out, bool layout, unsigned maxRecurse) 243 { 244 log_trace("Article::getPage(" << layout << ", " << maxRecurse << ')'); 245 246 if (getMimeType().compare(0, 9, "text/html") == 0 || getMimeType() == MimeHtmlTemplate) 247 { 248 if (layout && file->getFileheader().hasLayoutPage()) 249 { 250 Article layoutPage(file, file->getFileheader().getLayoutPage()); 251 Blob data = layoutPage.getData(); 252 253 Ev ev(out, *this, file, maxRecurse); 254 log_debug("call template parser"); 255 TemplateParser parser(&ev); 256 for (const char* p = data.data(); p != data.end(); ++p) 257 parser.parse(*p); 258 parser.flush(); 259 260 return; 261 } 262 else if (getMimeType() == MimeHtmlTemplate) 263 { 264 Blob data = getData(); 265 266 Ev ev(out, *this, file, maxRecurse); 267 TemplateParser parser(&ev); 268 for (const char* p = data.data(); p != data.end(); ++p) 269 parser.parse(*p); 270 parser.flush(); 271 272 return; 273 } 274 } 275 276 // default case - template cases has return above 277 out << getData(); 278 } 279 280 } 281