fb2read.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #include <QtGui>
  2. #include <QtDebug>
  3. #include "fb2read.hpp"
  4. #include "fb2xml2.h"
  5. //---------------------------------------------------------------------------
  6. // FbReadThread
  7. //---------------------------------------------------------------------------
  8. FbReadThread::FbReadThread(const QString &html, QObject *parent)
  9. : QThread(parent)
  10. , m_html(html)
  11. {
  12. connect(this, SIGNAL(html(QString,QUrl)), parent, SLOT(html(QString,QUrl)));
  13. }
  14. void FbReadThread::run()
  15. {
  16. sleep(1);
  17. static int number = 0;
  18. QUrl url(QString("fb2:/%1/").arg(number++));
  19. emit html(m_html, url);
  20. deleteLater();
  21. }
  22. /*
  23. FbReadThread::FbReadThread(QObject *parent, const QString &filename, const QString &xml)
  24. : QThread(parent)
  25. , m_temp(0)
  26. , m_filename(filename)
  27. , m_xml(xml)
  28. , m_abort(false)
  29. {
  30. connect(this, SIGNAL(html(QString)), parent, SLOT(html(QString)));
  31. }
  32. FbReadThread::~FbReadThread()
  33. {
  34. stop();
  35. wait();
  36. }
  37. void FbReadThread::stop()
  38. {
  39. QMutexLocker locker(&mutex);
  40. Q_UNUSED(locker);
  41. m_abort = true;
  42. }
  43. void FbReadThread::run()
  44. {
  45. if (parse()) emit html(m_html);
  46. }
  47. #ifdef FB2_USE_LIBXML2
  48. bool FbReadThread::parse()
  49. {
  50. QXmlStreamWriter writer(&m_html);
  51. FbReadHandler handler(*this, writer);
  52. XML2::XmlReader reader;
  53. reader.setContentHandler(&handler);
  54. reader.setLexicalHandler(&handler);
  55. reader.setErrorHandler(&handler);
  56. if (m_xml.isEmpty()) {
  57. QFile file(m_filename);
  58. if (!file.open(QFile::ReadOnly | QFile::Text)) {
  59. qCritical() << QObject::tr("Cannot read file %1: %2.").arg(m_filename).arg(file.errorString());
  60. return false;
  61. }
  62. return reader.parse(file);
  63. } else {
  64. QXmlInputSource source;
  65. source.setData(m_xml);
  66. return reader.parse(source);
  67. }
  68. }
  69. #else
  70. bool FbReadThread::parse()
  71. {
  72. QXmlStreamWriter writer(&m_html);
  73. FbReadHandler handler(*this, writer);
  74. connect(&handler, SIGNAL(binary(QString,QByteArray)), this, SLOT(data(QString,QByteArray)));
  75. QXmlSimpleReader reader;
  76. reader.setContentHandler(&handler);
  77. reader.setLexicalHandler(&handler);
  78. reader.setErrorHandler(&handler);
  79. QXmlInputSource source;
  80. if (m_xml.isEmpty()) {
  81. QFile file(m_filename);
  82. if (!file.open(QFile::ReadOnly | QFile::Text)) {
  83. qCritical() << QObject::tr("Cannot read file %1: %2.").arg(m_filename).arg(file.errorString());
  84. return false;
  85. }
  86. source.setData(file.readAll());
  87. } else {
  88. source.setData(m_xml);
  89. }
  90. return reader.parse(source);
  91. }
  92. #endif
  93. */
  94. //---------------------------------------------------------------------------
  95. // FbReadHandler::RootHandler
  96. //---------------------------------------------------------------------------
  97. FB2_BEGIN_KEYHASH(FbReadHandler::RootHandler)
  98. FB2_KEY( Style , "stylesheet" );
  99. FB2_KEY( Descr , "description" );
  100. FB2_KEY( Body , "body" );
  101. FB2_KEY( Binary , "binary" );
  102. FB2_END_KEYHASH
  103. FbReadHandler::RootHandler::RootHandler(FbReadHandler &owner, const QString &name)
  104. : BaseHandler(owner, name)
  105. , m_head(true)
  106. {
  107. }
  108. FbXmlHandler::NodeHandler * FbReadHandler::RootHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  109. {
  110. switch (toKeyword(name)) {
  111. case Binary: return new BinaryHandler(m_owner, name, atts);
  112. case Style: return new StyleHandler(m_owner, name, m_style);
  113. default: ;
  114. }
  115. if (m_head) {
  116. writeHeader();
  117. m_head = false;
  118. }
  119. return new TextHandler(m_owner, name, atts, "fb:" + name);
  120. }
  121. void FbReadHandler::RootHandler::EndTag(const QString &name)
  122. {
  123. Q_UNUSED(name);
  124. if (!m_head) writer().writeEndElement();
  125. }
  126. void FbReadHandler::RootHandler::writeScript(const QString &src)
  127. {
  128. writer().writeStartElement("script");
  129. writer().writeAttribute("type", "text/javascript");
  130. writer().writeAttribute("src", src);
  131. writer().writeCharacters(" ");
  132. writer().writeEndElement();
  133. }
  134. void FbReadHandler::RootHandler::writeHeader()
  135. {
  136. writer().writeStartElement("head");
  137. writeScript("qrc:/js/jquery.js");
  138. writeScript("qrc:/js/location.js");
  139. if (!m_style.isEmpty()) {
  140. writer().writeStartElement("style");
  141. writer().writeAttribute("type", "text/css");
  142. writer().writeCharacters(m_style);
  143. writer().writeEndElement();
  144. }
  145. writer().writeEndElement();
  146. writer().writeStartElement("body");
  147. }
  148. //---------------------------------------------------------------------------
  149. // FbReadHandler::StyleHandler
  150. //---------------------------------------------------------------------------
  151. FbReadHandler::StyleHandler::StyleHandler(FbReadHandler &owner, const QString &name, QString &text)
  152. : BaseHandler(owner, name)
  153. , m_text(text)
  154. {
  155. }
  156. void FbReadHandler::StyleHandler::TxtTag(const QString &text)
  157. {
  158. m_text += text;
  159. }
  160. //---------------------------------------------------------------------------
  161. // FbReadHandler::TextHandler
  162. //---------------------------------------------------------------------------
  163. FB2_BEGIN_KEYHASH(FbReadHandler::TextHandler)
  164. FB2_KEY( Anchor , "a" );
  165. FB2_KEY( Image , "image" );
  166. FB2_KEY( Origin , "table" );
  167. FB2_KEY( Origin , "td" );
  168. FB2_KEY( Origin , "th" );
  169. FB2_KEY( Origin , "tr" );
  170. FB2_KEY( Parag , "empty-line" );
  171. FB2_KEY( Parag , "text-author" );
  172. FB2_KEY( Parag , "subtitle" );
  173. FB2_KEY( Parag , "p" );
  174. FB2_KEY( Parag , "v" );
  175. FB2_KEY( Style , "style" );
  176. FB2_KEY( Strong , "strong" );
  177. FB2_KEY( Emphas , "emphasis" );
  178. FB2_KEY( Strike , "strikethrough" );
  179. FB2_KEY( Sub , "sub" );
  180. FB2_KEY( Sup , "sup" );
  181. FB2_KEY( Code , "code" );
  182. FB2_END_KEYHASH
  183. FbReadHandler::TextHandler::TextHandler(FbReadHandler &owner, const QString &name, const QXmlAttributes &atts, const QString &tag)
  184. : BaseHandler(owner, name)
  185. , m_parent(NULL)
  186. , m_tag(tag)
  187. , m_empty(true)
  188. {
  189. Init(name, atts);
  190. }
  191. FbReadHandler::TextHandler::TextHandler(TextHandler *parent, const QString &name, const QXmlAttributes &atts, const QString &tag)
  192. : BaseHandler(parent->m_owner, name)
  193. , m_parent(parent)
  194. , m_tag(tag)
  195. , m_empty(true)
  196. {
  197. Init(name, atts);
  198. }
  199. void FbReadHandler::TextHandler::Init(const QString &name, const QXmlAttributes &atts)
  200. {
  201. Keyword key = toKeyword(name);
  202. writer().writeStartElement(m_tag);
  203. int count = atts.count();
  204. for (int i = 0; i < count; i++) {
  205. QString name = atts.qName(i);
  206. switch (key) {
  207. case Anchor: { if (atts.localName(i) == "href") name = "href"; break; }
  208. case Image: { if (atts.localName(i) == "href") name = "src"; break; }
  209. default: ;
  210. }
  211. writer().writeAttribute(name, atts.value(i));
  212. }
  213. if (m_tag == "p" && (name == "text-author" || name == "subtitle")) {
  214. writer().writeAttribute("fb:class", name);
  215. }
  216. }
  217. FbXmlHandler::NodeHandler * FbReadHandler::TextHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  218. {
  219. m_empty = false;
  220. QString tag;
  221. switch (toKeyword(name)) {
  222. case Origin : tag = name; break;
  223. case Anchor : tag = "a"; break;
  224. case Image : tag = "img"; break;
  225. case Parag : tag = "p"; break;
  226. case Strong : tag = "b"; break;
  227. case Emphas : tag = "i"; break;
  228. case Strike : tag = "s"; break;
  229. case Code : tag = "tt"; break;
  230. case Sub : tag = "sub"; break;
  231. case Sup : tag = "sup"; break;
  232. case Style : tag = "span"; break;
  233. default : tag = "fb:" + name;
  234. }
  235. return new TextHandler(this, name, atts, tag);
  236. }
  237. void FbReadHandler::TextHandler::TxtTag(const QString &text)
  238. {
  239. writer().writeCharacters(text);
  240. m_empty = false;
  241. }
  242. void FbReadHandler::TextHandler::EndTag(const QString &name)
  243. {
  244. if (m_empty) {
  245. if (name == "p") {
  246. writer().writeEmptyElement("br");
  247. } else {
  248. writer().writeCharacters(" ");
  249. }
  250. }
  251. writer().writeEndElement();
  252. }
  253. bool FbReadHandler::TextHandler::isNotes() const
  254. {
  255. if (m_style == "notes") return true;
  256. return m_parent ? m_parent->isNotes() : false;
  257. }
  258. //---------------------------------------------------------------------------
  259. // FbReadHandler::BinaryHandler
  260. //---------------------------------------------------------------------------
  261. FbReadHandler::BinaryHandler::BinaryHandler(FbReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  262. : BaseHandler(owner, name)
  263. , m_file(Value(atts, "id"))
  264. {
  265. }
  266. void FbReadHandler::BinaryHandler::TxtTag(const QString &text)
  267. {
  268. m_text += text;
  269. }
  270. void FbReadHandler::BinaryHandler::EndTag(const QString &name)
  271. {
  272. Q_UNUSED(name);
  273. QByteArray in; in.append(m_text);
  274. if (!m_file.isEmpty()) m_owner.addFile(m_file, QByteArray::fromBase64(in));
  275. }
  276. //---------------------------------------------------------------------------
  277. // FbReadHandler
  278. //---------------------------------------------------------------------------
  279. bool FbReadHandler::load(QObject *page, QXmlInputSource &source, QString &html)
  280. {
  281. QXmlStreamWriter writer(&html);
  282. FbReadHandler handler(writer);
  283. connect(&handler, SIGNAL(binary(QString,QByteArray)), page, SLOT(binary(QString,QByteArray)));
  284. #ifdef FB2_USE_LIBXML2
  285. XML2::XmlReader reader;
  286. #else
  287. QXmlSimpleReader reader;
  288. #endif
  289. reader.setContentHandler(&handler);
  290. reader.setLexicalHandler(&handler);
  291. reader.setErrorHandler(&handler);
  292. return reader.parse(source);
  293. }
  294. FbReadHandler::FbReadHandler(QXmlStreamWriter &writer)
  295. : FbXmlHandler()
  296. , m_writer(writer)
  297. {
  298. m_writer.setAutoFormatting(true);
  299. m_writer.setAutoFormattingIndent(2);
  300. m_writer.writeStartElement("html");
  301. }
  302. FbReadHandler::~FbReadHandler()
  303. {
  304. m_writer.writeEndElement();
  305. }
  306. FbXmlHandler::NodeHandler * FbReadHandler::CreateRoot(const QString &name, const QXmlAttributes &atts)
  307. {
  308. Q_UNUSED(atts);
  309. if (name == "fictionbook") return new RootHandler(*this, name);
  310. m_error = QObject::tr("The file is not an FB2 file.");
  311. return 0;
  312. }
  313. bool FbReadHandler::comment(const QString& ch)
  314. {
  315. m_writer.writeComment(ch);
  316. return true;
  317. }
  318. void FbReadHandler::addFile(const QString &name, const QByteArray &data)
  319. {
  320. emit binary(name, data);
  321. }