fb2read.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. #include <QtGui>
  2. #include <QtDebug>
  3. #include "fb2read.h"
  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_abort(false)
  12. , m_xml(xml)
  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. bool Fb2ReadThread::parse()
  32. {
  33. QXmlStreamWriter writer(&m_html);
  34. Fb2ReadHandler handler(*this, writer);
  35. #ifdef _WIN32
  36. QXmlSimpleReader reader;
  37. #else
  38. XML2::XmlReader reader;
  39. #endif
  40. reader.setContentHandler(&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. QXmlInputSource source(&file);
  49. return reader.parse(source);
  50. } else {
  51. QXmlInputSource source;
  52. source.setData(m_xml);
  53. return reader.parse(source);
  54. }
  55. }
  56. //---------------------------------------------------------------------------
  57. // Fb2ReadHandler::RootHandler
  58. //---------------------------------------------------------------------------
  59. FB2_BEGIN_KEYHASH(Fb2ReadHandler::RootHandler)
  60. FB2_KEY( Style , "stylesheet" );
  61. FB2_KEY( Descr , "description" );
  62. FB2_KEY( Body , "body" );
  63. FB2_KEY( Binary , "binary" );
  64. FB2_END_KEYHASH
  65. Fb2ReadHandler::RootHandler::RootHandler(Fb2ReadHandler &owner, const QString &name)
  66. : BaseHandler(owner, name)
  67. {
  68. writer().writeStartDocument();
  69. writer().writeStartElement("html");
  70. writer().writeStartElement("body");
  71. }
  72. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::RootHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  73. {
  74. switch (toKeyword(name)) {
  75. case Body : return new TextHandler(m_owner, name, atts, "div", name);
  76. case Descr : return new DescrHandler(m_owner, name, atts);
  77. case Binary : return new BinaryHandler(m_owner, name, atts);
  78. default: return NULL;
  79. }
  80. }
  81. void Fb2ReadHandler::RootHandler::EndTag(const QString &name)
  82. {
  83. Q_UNUSED(name);
  84. writer().writeEndElement();
  85. writer().writeEndElement();
  86. writer().writeEndDocument();
  87. }
  88. //---------------------------------------------------------------------------
  89. // Fb2ReadHandler::HeadHandler
  90. //---------------------------------------------------------------------------
  91. FB2_BEGIN_KEYHASH(Fb2ReadHandler::HeadHandler)
  92. FB2_KEY( Image , "image" );
  93. FB2_END_KEYHASH
  94. Fb2ReadHandler::HeadHandler::HeadHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  95. : BaseHandler(owner, name)
  96. , m_empty(true)
  97. {
  98. writer().writeStartElement("div");
  99. writer().writeAttribute("class", name);
  100. int count = atts.count();
  101. for (int i = 0; i < count; i++) {
  102. writer().writeAttribute("fb2:" + atts.qName(i), atts.value(i));
  103. }
  104. }
  105. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::HeadHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  106. {
  107. Q_UNUSED(atts);
  108. m_empty = false;
  109. switch (toKeyword(name)) {
  110. case Image: return new ImageHandler(m_owner, name, atts);
  111. default: return new HeadHandler(m_owner, name, atts);
  112. }
  113. }
  114. void Fb2ReadHandler::HeadHandler::TxtTag(const QString &text)
  115. {
  116. m_empty = false;
  117. writer().writeCharacters(text);
  118. }
  119. void Fb2ReadHandler::HeadHandler::EndTag(const QString &name)
  120. {
  121. Q_UNUSED(name);
  122. if (m_empty) writer().writeCharacters(" ");
  123. writer().writeEndElement();
  124. }
  125. //---------------------------------------------------------------------------
  126. // Fb2ReadHandler::DescrHandler
  127. //---------------------------------------------------------------------------
  128. FB2_BEGIN_KEYHASH(Fb2ReadHandler::DescrHandler)
  129. FB2_KEY( Title , "title-info" );
  130. FB2_KEY( Document , "document-info" );
  131. FB2_KEY( Publish , "publish-info" );
  132. FB2_KEY( Custom , "custom-info" );
  133. FB2_END_KEYHASH
  134. Fb2ReadHandler::DescrHandler::DescrHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  135. : HeadHandler(owner, name, atts)
  136. {
  137. writer().writeAttribute("id", m_owner.newId());
  138. }
  139. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::DescrHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  140. {
  141. Q_UNUSED(atts);
  142. switch (toKeyword(name)) {
  143. case Title :
  144. return new TitleHandler(m_owner, name, atts);
  145. case Document :
  146. case Publish :
  147. case Custom :
  148. return new HeadHandler(m_owner, name, atts);
  149. default:
  150. return NULL;
  151. }
  152. }
  153. //---------------------------------------------------------------------------
  154. // Fb2ReadHandler::TitleHandler
  155. //---------------------------------------------------------------------------
  156. Fb2ReadHandler::TitleHandler::TitleHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  157. : HeadHandler(owner, name, atts)
  158. {
  159. writer().writeAttribute("id", m_owner.newId());
  160. }
  161. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::TitleHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  162. {
  163. if (name == "annotation") return new TextHandler(m_owner, name, atts, "div", name);
  164. return new HeadHandler(m_owner, name, atts);
  165. }
  166. //---------------------------------------------------------------------------
  167. // Fb2ReadHandler::TextHandler
  168. //---------------------------------------------------------------------------
  169. FB2_BEGIN_KEYHASH(Fb2ReadHandler::TextHandler)
  170. FB2_KEY( Section , "annotation" );
  171. FB2_KEY( Section , "author" );
  172. FB2_KEY( Section , "cite" );
  173. FB2_KEY( Section , "date" );
  174. FB2_KEY( Section , "epigraph" );
  175. FB2_KEY( Section , "poem" );
  176. FB2_KEY( Section , "section" );
  177. FB2_KEY( Section , "stanza" );
  178. FB2_KEY( Section , "subtitle" );
  179. FB2_KEY( Section , "title" );
  180. FB2_KEY( Anchor , "a" );
  181. FB2_KEY( Table , "table" );
  182. FB2_KEY( Image , "image" );
  183. FB2_KEY( Parag , "empty-line" );
  184. FB2_KEY( Parag , "p" );
  185. FB2_KEY( Parag , "v" );
  186. FB2_KEY( Style , "style" );
  187. FB2_KEY( Strong , "strong" );
  188. FB2_KEY( Emphas , "emphasis" );
  189. FB2_KEY( Strike , "strikethrough" );
  190. FB2_KEY( Sub , "sub" );
  191. FB2_KEY( Sup , "sup" );
  192. FB2_KEY( Code , "code" );
  193. FB2_END_KEYHASH
  194. Fb2ReadHandler::TextHandler::TextHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts, const QString &tag, const QString &style)
  195. : BaseHandler(owner, name)
  196. , m_parent(NULL)
  197. , m_tag(tag)
  198. , m_style(style)
  199. {
  200. Init(atts);
  201. }
  202. Fb2ReadHandler::TextHandler::TextHandler(TextHandler *parent, const QString &name, const QXmlAttributes &atts, const QString &tag, const QString &style)
  203. : BaseHandler(parent->m_owner, name)
  204. , m_parent(parent)
  205. , m_tag(tag)
  206. , m_style(style)
  207. {
  208. Init(atts);
  209. }
  210. void Fb2ReadHandler::TextHandler::Init(const QXmlAttributes &atts)
  211. {
  212. if (m_tag.isEmpty()) return;
  213. writer().writeStartElement(m_tag);
  214. QString id = Value(atts, "id");
  215. if (!id.isEmpty()) {
  216. if (m_style == "section" && isNotes()) m_style = "note";
  217. writer().writeAttribute("id", id);
  218. } else if (m_tag == "div" || m_tag == "img") {
  219. writer().writeAttribute("id", m_owner.newId());
  220. }
  221. if (!m_style.isEmpty()) {
  222. if (m_style == "body" && Value(atts, "name").toLower() == "notes") m_style = "notes";
  223. writer().writeAttribute("class", m_style);
  224. }
  225. }
  226. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::TextHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  227. {
  228. QString tag, style;
  229. switch (toKeyword(name)) {
  230. case Anchor : return new AnchorHandler(this, name, atts);
  231. case Image : return new ImageHandler(m_owner, name, atts);
  232. case Section : tag = "div"; style = name; break;
  233. case Parag : tag = "p"; break;
  234. case Strong : tag = "b"; break;
  235. case Emphas : tag = "i"; break;
  236. case Strike : tag = "s"; break;
  237. case Code : tag = "tt"; break;
  238. case Sub : tag = "sub"; break;
  239. case Sup : tag = "sup"; break;
  240. default: ;
  241. }
  242. return new TextHandler(this, name, atts, tag, style);
  243. }
  244. void Fb2ReadHandler::TextHandler::TxtTag(const QString &text)
  245. {
  246. writer().writeCharacters(text);
  247. }
  248. void Fb2ReadHandler::TextHandler::EndTag(const QString &name)
  249. {
  250. Q_UNUSED(name);
  251. if (m_tag.isEmpty()) return;
  252. if (m_tag == "div") writer().writeCharacters(" ");
  253. writer().writeEndElement();
  254. }
  255. bool Fb2ReadHandler::TextHandler::isNotes() const
  256. {
  257. if (m_style == "notes") return true;
  258. return m_parent ? m_parent->isNotes() : false;
  259. }
  260. //---------------------------------------------------------------------------
  261. // Fb2ReadHandler::AnchorHandler
  262. //---------------------------------------------------------------------------
  263. Fb2ReadHandler::AnchorHandler::AnchorHandler(TextHandler *parent, const QString &name, const QXmlAttributes &atts)
  264. : TextHandler(parent, name, atts, "a")
  265. {
  266. QString href = Value(atts, "href");
  267. writer().writeAttribute("href", href);
  268. }
  269. //---------------------------------------------------------------------------
  270. // Fb2ReadHandler::ImageHandler
  271. //---------------------------------------------------------------------------
  272. Fb2ReadHandler::ImageHandler::ImageHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  273. : TextHandler(owner, name, atts, "img")
  274. {
  275. QString href = Value(atts, "href");
  276. while (href.left(1) == "#") href.remove(0, 1);
  277. QString path = m_owner.getFile(href);
  278. writer().writeAttribute("src", path);
  279. writer().writeAttribute("alt", href);
  280. }
  281. //---------------------------------------------------------------------------
  282. // Fb2ReadHandler::BinaryHandler
  283. //---------------------------------------------------------------------------
  284. Fb2ReadHandler::BinaryHandler::BinaryHandler(Fb2ReadHandler &owner, const QString &name, const QXmlAttributes &atts)
  285. : BaseHandler(owner, name)
  286. , m_file(Value(atts, "id"))
  287. {
  288. }
  289. void Fb2ReadHandler::BinaryHandler::TxtTag(const QString &text)
  290. {
  291. m_text += text;
  292. }
  293. void Fb2ReadHandler::BinaryHandler::EndTag(const QString &name)
  294. {
  295. Q_UNUSED(name);
  296. QByteArray in; in.append(m_text);
  297. if (!m_file.isEmpty()) m_owner.addFile(m_file, QByteArray::fromBase64(in));
  298. }
  299. //---------------------------------------------------------------------------
  300. // Fb2ReadHandler
  301. //---------------------------------------------------------------------------
  302. Fb2ReadHandler::Fb2ReadHandler(Fb2ReadThread &thread, QXmlStreamWriter &writer)
  303. : Fb2XmlHandler()
  304. , m_thread(thread)
  305. , m_writer(writer)
  306. , m_id(0)
  307. {
  308. m_writer.setAutoFormatting(true);
  309. m_writer.setAutoFormattingIndent(2);
  310. }
  311. Fb2XmlHandler::NodeHandler * Fb2ReadHandler::CreateRoot(const QString &name, const QXmlAttributes &atts)
  312. {
  313. Q_UNUSED(atts);
  314. if (name == "fictionbook") return new RootHandler(*this, name);
  315. m_error = QObject::tr("The file is not an FB2 file.");
  316. return 0;
  317. }
  318. QString Fb2ReadHandler::getFile(const QString &name)
  319. {
  320. QString path;
  321. QMetaObject::invokeMethod(m_thread.parent(), "temp", Qt::DirectConnection, Q_RETURN_ARG(QString, path), Q_ARG(QString, name));
  322. return path;
  323. }
  324. void Fb2ReadHandler::addFile(const QString &name, const QByteArray &data)
  325. {
  326. QMetaObject::invokeMethod(m_thread.parent(), "data", Qt::QueuedConnection, Q_ARG(QString, name), Q_ARG(QByteArray, data));
  327. }
  328. QString Fb2ReadHandler::newId()
  329. {
  330. return QString("FB2E%1").arg(++m_id);
  331. }