fb2read.cpp 10 KB

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