fb2read.cpp 14 KB

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