fb2read.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. #include <QtGui>
  2. #include <QtDebug>
  3. #include "fb2read.hpp"
  4. #include "fb2xml2.h"
  5. //---------------------------------------------------------------------------
  6. // Fb2ReadThread
  7. //---------------------------------------------------------------------------
  8. Fb2ReadThread::Fb2ReadThread(QObject *parent, const QString &filename, const QString &xml)
  9. : QThread(parent)
  10. , m_filename(filename)
  11. , m_xml(xml)
  12. , m_abort(false)
  13. {
  14. connect(this, SIGNAL(html(QString, QString)), parent, SLOT(html(QString, QString)));
  15. }
  16. Fb2ReadThread::~Fb2ReadThread()
  17. {
  18. stop();
  19. wait();
  20. }
  21. void Fb2ReadThread::stop()
  22. {
  23. QMutexLocker locker(&mutex);
  24. Q_UNUSED(locker);
  25. m_abort = true;
  26. }
  27. void Fb2ReadThread::run()
  28. {
  29. if (parse()) emit html(m_filename, m_html);
  30. }
  31. #ifdef FB2_USE_LIBXML2
  32. bool Fb2ReadThread::parse()
  33. {
  34. QXmlStreamWriter writer(&m_html);
  35. Fb2ReadHandler handler(*this, writer);
  36. XML2::XmlReader reader;
  37. reader.setContentHandler(&handler);
  38. reader.setLexicalHandler(&handler);
  39. reader.setErrorHandler(&handler);
  40. if (m_xml.isEmpty()) {
  41. QFile file(m_filename);
  42. if (!file.open(QFile::ReadOnly | QFile::Text)) {
  43. qCritical() << QObject::tr("Cannot read file %1: %2.").arg(m_filename).arg(file.errorString());
  44. return false;
  45. }
  46. return reader.parse(file);
  47. } else {
  48. QXmlInputSource source;
  49. source.setData(m_xml);
  50. return reader.parse(source);
  51. }
  52. }
  53. #else
  54. bool Fb2ReadThread::parse()
  55. {
  56. QXmlStreamWriter writer(&m_html);
  57. Fb2ReadHandler handler(*this, writer);
  58. QXmlSimpleReader reader;
  59. reader.setContentHandler(&handler);
  60. reader.setLexicalHandler(&handler);
  61. reader.setErrorHandler(&handler);
  62. QXmlInputSource source;
  63. if (m_xml.isEmpty()) {
  64. QFile file(m_filename);
  65. if (!file.open(QFile::ReadOnly | QFile::Text)) {
  66. qCritical() << QObject::tr("Cannot read file %1: %2.").arg(m_filename).arg(file.errorString());
  67. return false;
  68. }
  69. source.setData(file.readAll());
  70. } else {
  71. source.setData(m_xml);
  72. }
  73. return reader.parse(source);
  74. }
  75. #endif
  76. //---------------------------------------------------------------------------
  77. // Fb2ReadHandler::BaseHandler
  78. //---------------------------------------------------------------------------
  79. void Fb2ReadHandler::BaseHandler::writeAttributes(const QXmlAttributes &atts)
  80. {
  81. int count = atts.count();
  82. for (int i = 0; i < count; i++) {
  83. if (atts.localName(i) == "href") continue;
  84. QString name = atts.qName(i);
  85. if (name != "id") name.prepend("fb2_");
  86. writer().writeAttribute(name, atts.value(i));
  87. }
  88. }
  89. //---------------------------------------------------------------------------
  90. // Fb2ReadHandler::RootHandler
  91. //---------------------------------------------------------------------------
  92. FB2_BEGIN_KEYHASH(Fb2ReadHandler::RootHandler)
  93. FB2_KEY( Style , "stylesheet" );
  94. FB2_KEY( Descr , "description" );
  95. FB2_KEY( Body , "body" );
  96. FB2_KEY( Binary , "binary" );
  97. FB2_END_KEYHASH
  98. Fb2ReadHandler::RootHandler::RootHandler(Fb2ReadHandler &owner, const QString &name)
  99. : BaseHandler(owner, name)
  100. {
  101. writer().writeStartElement("body");
  102. }
  103. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::RootHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  104. {
  105. switch (toKeyword(name)) {
  106. case Body : return new TextHandler(m_owner, name, atts, "div", name);
  107. case Descr : return new DescrHandler(m_owner, name, atts);
  108. case Style : return new StyleHandler(m_owner, name, atts);
  109. case Binary : return new BinaryHandler(m_owner, name, atts);
  110. default: return NULL;
  111. }
  112. }
  113. void Fb2ReadHandler::RootHandler::EndTag(const QString &name)
  114. {
  115. Q_UNUSED(name);
  116. writer().writeEndElement();
  117. }
  118. //---------------------------------------------------------------------------
  119. // Fb2ReadHandler::StyleHandler
  120. //---------------------------------------------------------------------------
  121. Fb2ReadHandler::StyleHandler::StyleHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  122. : BaseHandler(owner, name)
  123. , m_empty(true)
  124. {
  125. writer().writeStartElement("div");
  126. writer().writeAttribute("class", name);
  127. writeAttributes(atts);
  128. }
  129. void Fb2ReadHandler::StyleHandler::TxtTag(const QString &text)
  130. {
  131. writer().writeCharacters(text);
  132. m_empty = false;
  133. }
  134. void Fb2ReadHandler::StyleHandler::EndTag(const QString &name)
  135. {
  136. Q_UNUSED(name);
  137. if (m_empty) writer().writeCharacters(" ");
  138. writer().writeEndElement();
  139. }
  140. //---------------------------------------------------------------------------
  141. // Fb2ReadHandler::HeadHandler
  142. //---------------------------------------------------------------------------
  143. FB2_BEGIN_KEYHASH(Fb2ReadHandler::HeadHandler)
  144. FB2_KEY( Image , "image" );
  145. FB2_END_KEYHASH
  146. Fb2ReadHandler::HeadHandler::HeadHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  147. : BaseHandler(owner, name)
  148. , m_empty(true)
  149. {
  150. writer().writeStartElement("div");
  151. writer().writeAttribute("class", name);
  152. writeAttributes(atts);
  153. }
  154. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::HeadHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  155. {
  156. Q_UNUSED(atts);
  157. m_empty = false;
  158. switch (toKeyword(name)) {
  159. case Image: return new ImageHandler(m_owner, name, atts);
  160. default: return new HeadHandler(m_owner, name, atts);
  161. }
  162. }
  163. void Fb2ReadHandler::HeadHandler::TxtTag(const QString &text)
  164. {
  165. m_empty = false;
  166. writer().writeCharacters(text);
  167. }
  168. void Fb2ReadHandler::HeadHandler::EndTag(const QString &name)
  169. {
  170. Q_UNUSED(name);
  171. if (m_empty) writer().writeCharacters(" ");
  172. writer().writeEndElement();
  173. }
  174. //---------------------------------------------------------------------------
  175. // Fb2ReadHandler::DescrHandler
  176. //---------------------------------------------------------------------------
  177. FB2_BEGIN_KEYHASH(Fb2ReadHandler::DescrHandler)
  178. FB2_KEY( Title , "title-info" );
  179. FB2_KEY( Document , "document-info" );
  180. FB2_KEY( Publish , "publish-info" );
  181. FB2_KEY( Custom , "custom-info" );
  182. FB2_END_KEYHASH
  183. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::DescrHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  184. {
  185. Q_UNUSED(atts);
  186. switch (toKeyword(name)) {
  187. case Title :
  188. case Document :
  189. case Publish :
  190. return new TitleHandler(m_owner, name, atts);
  191. case Custom :
  192. return new HeadHandler(m_owner, name, atts);
  193. default:
  194. return NULL;
  195. }
  196. }
  197. //---------------------------------------------------------------------------
  198. // Fb2ReadHandler::TitleHandler
  199. //---------------------------------------------------------------------------
  200. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::TitleHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  201. {
  202. if (name == "annotation" || name == "history") {
  203. return new TextHandler(m_owner, name, atts, "div", name);
  204. }
  205. return new HeadHandler(m_owner, name, atts);
  206. }
  207. //---------------------------------------------------------------------------
  208. // Fb2ReadHandler::TextHandler
  209. //---------------------------------------------------------------------------
  210. FB2_BEGIN_KEYHASH(Fb2ReadHandler::TextHandler)
  211. FB2_KEY( Section , "annotation" );
  212. FB2_KEY( Section , "author" );
  213. FB2_KEY( Section , "cite" );
  214. FB2_KEY( Section , "date" );
  215. FB2_KEY( Section , "epigraph" );
  216. FB2_KEY( Section , "poem" );
  217. FB2_KEY( Section , "section" );
  218. FB2_KEY( Section , "stanza" );
  219. FB2_KEY( Section , "subtitle" );
  220. FB2_KEY( Section , "title" );
  221. FB2_KEY( Anchor , "a" );
  222. FB2_KEY( Table , "table" );
  223. FB2_KEY( Image , "image" );
  224. FB2_KEY( Parag , "empty-line" );
  225. FB2_KEY( Parag , "p" );
  226. FB2_KEY( Parag , "v" );
  227. FB2_KEY( Style , "style" );
  228. FB2_KEY( Strong , "strong" );
  229. FB2_KEY( Emphas , "emphasis" );
  230. FB2_KEY( Strike , "strikethrough" );
  231. FB2_KEY( Sub , "sub" );
  232. FB2_KEY( Sup , "sup" );
  233. FB2_KEY( Code , "code" );
  234. FB2_END_KEYHASH
  235. Fb2ReadHandler::TextHandler::TextHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts, const QString &tag, const QString &style)
  236. : BaseHandler(owner, name)
  237. , m_parent(NULL)
  238. , m_tag(tag)
  239. , m_style(style)
  240. {
  241. Init(atts);
  242. }
  243. Fb2ReadHandler::TextHandler::TextHandler(TextHandler *parent, const QString &name, const QXmlAttributes &atts, const QString &tag, const QString &style)
  244. : BaseHandler(parent->m_owner, name)
  245. , m_parent(parent)
  246. , m_tag(tag)
  247. , m_style(style)
  248. {
  249. Init(atts);
  250. if (name == "empty-line") {
  251. writer().writeEmptyElement("br");
  252. }
  253. }
  254. void Fb2ReadHandler::TextHandler::Init(const QXmlAttributes &atts)
  255. {
  256. if (m_tag.isEmpty()) return;
  257. writer().writeStartElement(m_tag);
  258. QString id = Value(atts, "id");
  259. if (!m_style.isEmpty()) {
  260. writer().writeAttribute("class", m_style);
  261. }
  262. writeAttributes(atts);
  263. }
  264. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::TextHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  265. {
  266. QString tag, style;
  267. switch (toKeyword(name)) {
  268. case Anchor : return new AnchorHandler(this, name, atts);
  269. case Image : return new ImageHandler(m_owner, name, atts);
  270. case Section : tag = "div"; style = name; break;
  271. case Parag : tag = "p"; break;
  272. case Strong : tag = "b"; break;
  273. case Emphas : tag = "i"; break;
  274. case Strike : tag = "s"; break;
  275. case Code : tag = "tt"; break;
  276. case Sub : tag = "sub"; break;
  277. case Sup : tag = "sup"; break;
  278. case Style : tag = "span"; break;
  279. default: ;
  280. }
  281. return new TextHandler(this, name, atts, tag, style);
  282. }
  283. void Fb2ReadHandler::TextHandler::TxtTag(const QString &text)
  284. {
  285. writer().writeCharacters(text);
  286. }
  287. void Fb2ReadHandler::TextHandler::EndTag(const QString &name)
  288. {
  289. Q_UNUSED(name);
  290. if (m_tag.isEmpty()) return;
  291. if (m_tag == "div") writer().writeCharacters(" ");
  292. writer().writeEndElement();
  293. }
  294. bool Fb2ReadHandler::TextHandler::isNotes() const
  295. {
  296. if (m_style == "notes") return true;
  297. return m_parent ? m_parent->isNotes() : false;
  298. }
  299. //---------------------------------------------------------------------------
  300. // Fb2ReadHandler::SpanHandler
  301. //---------------------------------------------------------------------------
  302. Fb2ReadHandler::SpanHandler::SpanHandler(TextHandler *parent, const QString &name, const QXmlAttributes &atts)
  303. : TextHandler(parent, name, atts, "span")
  304. {
  305. }
  306. //---------------------------------------------------------------------------
  307. // Fb2ReadHandler::AnchorHandler
  308. //---------------------------------------------------------------------------
  309. Fb2ReadHandler::AnchorHandler::AnchorHandler(TextHandler *parent, const QString &name, const QXmlAttributes &atts)
  310. : TextHandler(parent, name, atts, "a")
  311. {
  312. QString href = Value(atts, "href");
  313. writer().writeAttribute("href", href);
  314. }
  315. //---------------------------------------------------------------------------
  316. // Fb2ReadHandler::ImageHandler
  317. //---------------------------------------------------------------------------
  318. Fb2ReadHandler::ImageHandler::ImageHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  319. : TextHandler(owner, name, atts, "img")
  320. {
  321. QString href = Value(atts, "href");
  322. writer().writeAttribute("src", href);
  323. }
  324. //---------------------------------------------------------------------------
  325. // Fb2ReadHandler::BinaryHandler
  326. //---------------------------------------------------------------------------
  327. Fb2ReadHandler::BinaryHandler::BinaryHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  328. : BaseHandler(owner, name)
  329. , m_file(Value(atts, "id"))
  330. {
  331. }
  332. void Fb2ReadHandler::BinaryHandler::TxtTag(const QString &text)
  333. {
  334. m_text += text;
  335. }
  336. void Fb2ReadHandler::BinaryHandler::EndTag(const QString &name)
  337. {
  338. Q_UNUSED(name);
  339. QByteArray in; in.append(m_text);
  340. if (!m_file.isEmpty()) m_owner.addFile(m_file, QByteArray::fromBase64(in));
  341. }
  342. //---------------------------------------------------------------------------
  343. // Fb2ReadHandler
  344. //---------------------------------------------------------------------------
  345. Fb2ReadHandler::Fb2ReadHandler(Fb2ReadThread &thread, QXmlStreamWriter &writer)
  346. : Fb2XmlHandler()
  347. , m_thread(thread)
  348. , m_writer(writer)
  349. {
  350. m_writer.setAutoFormatting(true);
  351. m_writer.setAutoFormattingIndent(2);
  352. m_writer.writeStartElement("html");
  353. m_writer.writeStartElement("head");
  354. m_writer.writeStartElement("script");
  355. m_writer.writeAttribute("type", "text/javascript");
  356. m_writer.writeAttribute("src", "qrc:/js/jquery.js");
  357. m_writer.writeCharacters(" ");
  358. m_writer.writeEndElement();
  359. m_writer.writeEndElement();
  360. }
  361. Fb2ReadHandler::~Fb2ReadHandler()
  362. {
  363. m_writer.writeEndElement();
  364. }
  365. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::CreateRoot(const QString &name, const QXmlAttributes &atts)
  366. {
  367. Q_UNUSED(atts);
  368. if (name == "fictionbook") return new RootHandler(*this, name);
  369. m_error = QObject::tr("The file is not an FB2 file.");
  370. return 0;
  371. }
  372. bool Fb2ReadHandler::comment(const QString& ch)
  373. {
  374. m_writer.writeComment(ch);
  375. return true;
  376. }
  377. QString Fb2ReadHandler::getFile(const QString &name)
  378. {
  379. QString path;
  380. QMetaObject::invokeMethod(m_thread.parent(), "temp", Qt::DirectConnection, Q_RETURN_ARG(QString, path), Q_ARG(QString, name));
  381. return path;
  382. }
  383. void Fb2ReadHandler::addFile(const QString &name, const QByteArray &data)
  384. {
  385. QMetaObject::invokeMethod(m_thread.parent(), "data", Qt::QueuedConnection, Q_ARG(QString, name), Q_ARG(QByteArray, data));
  386. }