fb2read.cpp 8.1 KB

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