fb2read.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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( Table , "table" );
  101. FB2_KEY( Image , "image" );
  102. FB2_KEY( Parag , "empty-line" );
  103. FB2_KEY( Parag , "p" );
  104. FB2_KEY( Parag , "v" );
  105. FB2_KEY( Style , "style" );
  106. FB2_KEY( Strong , "strong" );
  107. FB2_KEY( Emphas , "emphasis" );
  108. FB2_KEY( Strike , "strikethrough" );
  109. FB2_KEY( Sub , "sub" );
  110. FB2_KEY( Sup , "sup" );
  111. FB2_KEY( Code , "code" );
  112. FB2_END_KEYHASH
  113. FbReadHandler::TextHandler::TextHandler(FbReadHandler &owner, const QString &name, const QXmlAttributes &atts, const QString &tag)
  114. : BaseHandler(owner, name)
  115. , m_parent(NULL)
  116. , m_tag(tag)
  117. , m_empty(true)
  118. {
  119. Init(name, atts);
  120. }
  121. FbReadHandler::TextHandler::TextHandler(TextHandler *parent, const QString &name, const QXmlAttributes &atts, const QString &tag)
  122. : BaseHandler(parent->m_owner, name)
  123. , m_parent(parent)
  124. , m_tag(tag)
  125. , m_empty(true)
  126. {
  127. Init(name, atts);
  128. }
  129. void FbReadHandler::TextHandler::Init(const QString &name, const QXmlAttributes &atts)
  130. {
  131. Keyword key = toKeyword(name);
  132. writer().writeStartElement(m_tag);
  133. int count = atts.count();
  134. for (int i = 0; i < count; i++) {
  135. QString name = atts.qName(i);
  136. switch (key) {
  137. case Anchor: { if (atts.localName(i) == "href") name = "href"; break; }
  138. case Image: { if (atts.localName(i) == "href") name = "src"; break; }
  139. default: ;
  140. }
  141. writer().writeAttribute(name, atts.value(i));
  142. }
  143. if (name == "empty-line") {
  144. writer().writeEmptyElement("br");
  145. m_empty = false;
  146. }
  147. }
  148. FbXmlHandler::NodeHandler * FbReadHandler::TextHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  149. {
  150. m_empty = false;
  151. QString tag;
  152. switch (toKeyword(name)) {
  153. case Anchor : tag = "a"; break;
  154. case Image : tag = "img"; break;
  155. case Parag : tag = "p"; break;
  156. case Strong : tag = "b"; break;
  157. case Emphas : tag = "i"; break;
  158. case Strike : tag = "s"; break;
  159. case Code : tag = "tt"; break;
  160. case Sub : tag = "sub"; break;
  161. case Sup : tag = "sup"; break;
  162. case Style : tag = "span"; break;
  163. default : tag = "fb:" + name;
  164. }
  165. return new TextHandler(this, name, atts, tag);
  166. }
  167. void FbReadHandler::TextHandler::TxtTag(const QString &text)
  168. {
  169. writer().writeCharacters(text);
  170. m_empty = false;
  171. }
  172. void FbReadHandler::TextHandler::EndTag(const QString &name)
  173. {
  174. Q_UNUSED(name);
  175. if (m_empty) writer().writeCharacters(" ");
  176. writer().writeEndElement();
  177. }
  178. bool FbReadHandler::TextHandler::isNotes() const
  179. {
  180. if (m_style == "notes") return true;
  181. return m_parent ? m_parent->isNotes() : false;
  182. }
  183. //---------------------------------------------------------------------------
  184. // FbReadHandler::BinaryHandler
  185. //---------------------------------------------------------------------------
  186. FbReadHandler::BinaryHandler::BinaryHandler(FbReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  187. : BaseHandler(owner, name)
  188. , m_file(Value(atts, "id"))
  189. {
  190. }
  191. void FbReadHandler::BinaryHandler::TxtTag(const QString &text)
  192. {
  193. m_text += text;
  194. }
  195. void FbReadHandler::BinaryHandler::EndTag(const QString &name)
  196. {
  197. Q_UNUSED(name);
  198. QByteArray in; in.append(m_text);
  199. if (!m_file.isEmpty()) m_owner.addFile(m_file, QByteArray::fromBase64(in));
  200. }
  201. //---------------------------------------------------------------------------
  202. // FbReadHandler
  203. //---------------------------------------------------------------------------
  204. FbReadHandler::FbReadHandler(FbReadThread &thread, QXmlStreamWriter &writer)
  205. : FbXmlHandler()
  206. , m_thread(thread)
  207. , m_writer(writer)
  208. , m_temp(thread.temp())
  209. {
  210. m_writer.setAutoFormatting(true);
  211. m_writer.setAutoFormattingIndent(2);
  212. m_writer.writeStartElement("html");
  213. m_writer.writeStartElement("head");
  214. writeScript("qrc:/js/jquery.js");
  215. writeScript("qrc:/js/location.js");
  216. m_writer.writeEndElement();
  217. }
  218. FbReadHandler::~FbReadHandler()
  219. {
  220. m_writer.writeEndElement();
  221. }
  222. void FbReadHandler::writeScript(const QString &src)
  223. {
  224. m_writer.writeStartElement("script");
  225. m_writer.writeAttribute("type", "text/javascript");
  226. m_writer.writeAttribute("src", src);
  227. m_writer.writeCharacters(" ");
  228. m_writer.writeEndElement();
  229. }
  230. FbXmlHandler::NodeHandler * FbReadHandler::CreateRoot(const QString &name, const QXmlAttributes &atts)
  231. {
  232. Q_UNUSED(atts);
  233. if (name == "fictionbook") return new RootHandler(*this, name);
  234. m_error = QObject::tr("The file is not an FB2 file.");
  235. return 0;
  236. }
  237. bool FbReadHandler::comment(const QString& ch)
  238. {
  239. m_writer.writeComment(ch);
  240. return true;
  241. }
  242. void FbReadHandler::addFile(const QString &name, const QByteArray &data)
  243. {
  244. QMetaObject::invokeMethod(m_temp, "data", Qt::QueuedConnection, Q_ARG(QString, name), Q_ARG(QByteArray, data));
  245. }