fb2save.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. #include <QtGui>
  2. #include <QtDebug>
  3. #include "fb2save.h"
  4. #include "fb2view.hpp"
  5. #include <QAbstractNetworkCache>
  6. #include <QNetworkReply>
  7. #include <QNetworkRequest>
  8. #include <QScopedPointer>
  9. //---------------------------------------------------------------------------
  10. // Fb2SaveWriter
  11. //---------------------------------------------------------------------------
  12. Fb2SaveWriter::Fb2SaveWriter(Fb2WebView &view, QByteArray *array, QList<int> *folds)
  13. : QXmlStreamWriter(array)
  14. , m_folds(folds)
  15. , m_view(view)
  16. , m_line(0)
  17. {
  18. Init();
  19. }
  20. Fb2SaveWriter::Fb2SaveWriter(Fb2WebView &view, QIODevice *device)
  21. : QXmlStreamWriter(device)
  22. , m_folds(0)
  23. , m_view(view)
  24. , m_line(0)
  25. {
  26. Init();
  27. }
  28. Fb2SaveWriter::Fb2SaveWriter(Fb2WebView &view, QString *string)
  29. : QXmlStreamWriter(string)
  30. , m_folds(0)
  31. , m_view(view)
  32. , m_line(0)
  33. {
  34. Init();
  35. }
  36. void Fb2SaveWriter::Init()
  37. {
  38. writeStartDocument();
  39. }
  40. Fb2SaveWriter::~Fb2SaveWriter()
  41. {
  42. writeEndDocument();
  43. }
  44. void Fb2SaveWriter::writeStartElement(const QString &name, int level)
  45. {
  46. if (level) writeLineEnd();
  47. for (int i = 1; i < level; i++) writeCharacters(" ");
  48. QXmlStreamWriter::writeStartElement(name);
  49. }
  50. void Fb2SaveWriter::writeEndElement(int level)
  51. {
  52. if (level) writeLineEnd();
  53. for (int i = 1; i < level; i++) writeCharacters(" ");
  54. QXmlStreamWriter::writeEndElement();
  55. }
  56. void Fb2SaveWriter::writeLineEnd()
  57. {
  58. writeCharacters("\n");
  59. m_line++;
  60. }
  61. QByteArray Fb2SaveWriter::downloadFile(const QString &src)
  62. {
  63. QUrl url(src);
  64. QNetworkRequest request(url);
  65. QNetworkAccessManager * network = m_view.page()->networkAccessManager();
  66. QNetworkReply * reply = network->get(request);
  67. return reply->readAll();
  68. }
  69. QString Fb2SaveWriter::newFileName(const QString &path)
  70. {
  71. QFileInfo info(path);
  72. QString name = info.fileName();
  73. if (!m_view.files().exists(name) && !m_files.exists(name)) return name;
  74. QString base = info.baseName();
  75. QString suff = info.suffix();
  76. for (int i = 1; ; i++) {
  77. QString name = QString("%1(%2).%3").arg(base).arg(i).arg(suff);
  78. if (m_view.files().exists(name)) continue;
  79. if (m_files.exists(name)) continue;
  80. return name;
  81. }
  82. }
  83. QString Fb2SaveWriter::getFileName(const QString &path)
  84. {
  85. QString hash = m_view.files().hash(path);
  86. if (hash.isEmpty()) {
  87. QUrl url(path);
  88. QNetworkRequest request(url);
  89. QNetworkAccessManager * network = m_view.page()->networkAccessManager();
  90. QScopedPointer<QNetworkReply> reply(network->get(request));
  91. if (reply.isNull()) return QString();
  92. QEventLoop loop;
  93. QObject::connect(reply.data(), SIGNAL(finished()), &loop, SLOT(quit()));
  94. loop.exec();
  95. QByteArray data = reply->readAll();
  96. hash = Fb2TemporaryFile::md5(data);
  97. QString name = newFileName(url.path());
  98. m_files.set(name, data, hash);
  99. m_names.append(name);
  100. return name;
  101. } else {
  102. QString name = m_view.files().name(hash);
  103. if (name.isEmpty()) return QString();
  104. if (m_names.indexOf(name) == -1) m_names.append(name);
  105. return name;
  106. }
  107. }
  108. QString Fb2SaveWriter::getFileData(const QString &name)
  109. {
  110. QString data = m_view.files().data(name);
  111. if (data.isEmpty()) data = m_files.data(name);
  112. return data;
  113. }
  114. void Fb2SaveWriter::writeFiles()
  115. {
  116. QStringListIterator it(m_names);
  117. while (it.hasNext()) {
  118. QString name = it.next();
  119. if (name.isEmpty()) continue;
  120. QString data = getFileData(name);
  121. if (data.isEmpty()) continue;
  122. writeStartElement("binary", 2);
  123. if (m_folds) m_folds->append(m_line);
  124. writeAttribute("id", name);
  125. writeLineEnd();
  126. int pos = 0;
  127. while (true) {
  128. QString text = data.mid(pos, 76);
  129. if (text.isEmpty()) break;
  130. writeCharacters(text);
  131. writeLineEnd();
  132. pos += 76;
  133. }
  134. writeCharacters(" ");
  135. QXmlStreamWriter::writeEndElement();
  136. }
  137. }
  138. //---------------------------------------------------------------------------
  139. // Fb2SaveHandler::BodyHandler
  140. //---------------------------------------------------------------------------
  141. FB2_BEGIN_KEYHASH(Fb2SaveHandler::BodyHandler)
  142. FB2_KEY( Section , "div" );
  143. FB2_KEY( Anchor , "a" );
  144. FB2_KEY( Image , "img" );
  145. FB2_KEY( Table , "table" );
  146. FB2_KEY( Parag , "p" );
  147. FB2_KEY( Strong , "b" );
  148. FB2_KEY( Emphas , "i" );
  149. FB2_KEY( Strike , "strike" );
  150. FB2_KEY( Sub , "sub" );
  151. FB2_KEY( Sup , "sup" );
  152. FB2_KEY( Code , "tt" );
  153. FB2_END_KEYHASH
  154. Fb2SaveHandler::BodyHandler::BodyHandler(Fb2SaveWriter &writer, const QString &name, const QXmlAttributes &atts, const QString &tag)
  155. : NodeHandler(name)
  156. , m_writer(writer)
  157. , m_tag(tag)
  158. , m_level(1)
  159. , m_hasChild(false)
  160. {
  161. Init(atts);
  162. }
  163. Fb2SaveHandler::BodyHandler::BodyHandler(BodyHandler *parent, const QString &name, const QXmlAttributes &atts, const QString &tag)
  164. : NodeHandler(name)
  165. , m_writer(parent->m_writer)
  166. , m_tag(tag)
  167. , m_level(parent->nextLevel())
  168. , m_hasChild(false)
  169. {
  170. Init(atts);
  171. }
  172. void Fb2SaveHandler::BodyHandler::Init(const QXmlAttributes &atts)
  173. {
  174. if (m_tag.isEmpty()) return;
  175. m_writer.writeStartElement(m_tag, m_level);
  176. int count = atts.count();
  177. for (int i = 0; i < count; i++) {
  178. QString name = atts.qName(i);
  179. if (name == "id") {
  180. m_writer.writeAttribute(name, atts.value(i));
  181. } else if (name == "name") {
  182. m_writer.writeAttribute(name, atts.value(i));
  183. } else if (name.left(4) == "fb2:") {
  184. m_writer.writeAttribute(name.mid(4), atts.value(i));
  185. }
  186. }
  187. }
  188. Fb2XmlHandler::NodeHandler * Fb2SaveHandler::BodyHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  189. {
  190. m_hasChild = true;
  191. QString tag = QString();
  192. switch (toKeyword(name)) {
  193. case Section : tag = atts.value("class") ; break;
  194. case Anchor : return new AnchorHandler(this, name, atts);
  195. case Image : return new ImageHandler(this, name, atts);
  196. case Parag : return new ParagHandler(this, name, atts);
  197. case Strong : tag = "strong" ; break;
  198. case Emphas : tag = "emphasis" ; break;
  199. case Strike : tag = "strikethrough" ; break;
  200. case Code : tag = "code" ; break;
  201. case Sub : tag = "sub" ; break;
  202. case Sup : tag = "sup" ; break;
  203. default: ;
  204. }
  205. return new BodyHandler(this, name, atts, tag);
  206. }
  207. void Fb2SaveHandler::BodyHandler::TxtTag(const QString &text)
  208. {
  209. m_writer.writeCharacters(text);
  210. }
  211. void Fb2SaveHandler::BodyHandler::EndTag(const QString &name)
  212. {
  213. Q_UNUSED(name);
  214. if (m_tag.isEmpty()) return;
  215. m_writer.writeEndElement(m_hasChild ? m_level : 0);
  216. }
  217. int Fb2SaveHandler::BodyHandler::nextLevel() const
  218. {
  219. return m_level ? m_level + 1 : 0;
  220. }
  221. //---------------------------------------------------------------------------
  222. // Fb2SaveHandler::RootHandler
  223. //---------------------------------------------------------------------------
  224. Fb2SaveHandler::RootHandler::RootHandler(Fb2SaveWriter &writer, const QString &name, const QXmlAttributes &atts)
  225. : BodyHandler(writer, name, atts, "FictionBook")
  226. {
  227. m_writer.writeAttribute("xmlns", "http://www.gribuser.ru/xml/fictionbook/2.0");
  228. m_writer.writeAttribute("xmlns:l", "http://www.w3.org/1999/xlink");
  229. }
  230. void Fb2SaveHandler::RootHandler::EndTag(const QString &name)
  231. {
  232. m_writer.writeFiles();
  233. BodyHandler::EndTag(name);
  234. }
  235. //---------------------------------------------------------------------------
  236. // Fb2SaveHandler::AnchorHandler
  237. //---------------------------------------------------------------------------
  238. Fb2SaveHandler::AnchorHandler::AnchorHandler(BodyHandler *parent, const QString &name, const QXmlAttributes &atts)
  239. : BodyHandler(parent, name, atts, "a")
  240. {
  241. QString href = Value(atts, "href");
  242. m_writer.writeAttribute("l:href", href);
  243. }
  244. //---------------------------------------------------------------------------
  245. // Fb2SaveHandler::ImageHandler
  246. //---------------------------------------------------------------------------
  247. Fb2SaveHandler::ImageHandler::ImageHandler(BodyHandler *parent, const QString &name, const QXmlAttributes &atts)
  248. : BodyHandler(parent, name, atts, "image")
  249. {
  250. QString src = Value(atts, "src");
  251. QString file = m_writer.getFileName(src);
  252. file.prepend('#');
  253. m_writer.writeAttribute("l:href", file);
  254. m_writer.writeEndElement(0);
  255. }
  256. //---------------------------------------------------------------------------
  257. // Fb2SaveHandler::ParagHandler
  258. //---------------------------------------------------------------------------
  259. Fb2SaveHandler::ParagHandler::ParagHandler(BodyHandler *parent, const QString &name, const QXmlAttributes &atts)
  260. : BodyHandler(parent, name, atts, "")
  261. , m_parent(parent->tag())
  262. , m_empty(true)
  263. {
  264. }
  265. Fb2XmlHandler::NodeHandler * Fb2SaveHandler::ParagHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  266. {
  267. if (m_empty) start();
  268. return BodyHandler::NewTag(name, atts);
  269. }
  270. void Fb2SaveHandler::ParagHandler::TxtTag(const QString &text)
  271. {
  272. if (m_empty) {
  273. if (isWhiteSpace(text)) return;
  274. start();
  275. }
  276. BodyHandler::TxtTag(text);
  277. }
  278. void Fb2SaveHandler::ParagHandler::EndTag(const QString &name)
  279. {
  280. Q_UNUSED(name);
  281. if (m_empty) m_writer.writeStartElement("empty-line", m_level);
  282. m_writer.writeEndElement(0);
  283. }
  284. void Fb2SaveHandler::ParagHandler::start()
  285. {
  286. if (!m_empty) return;
  287. QString tag = m_parent == "stanza" ? "v" : "p";
  288. m_writer.writeStartElement(tag, m_level);
  289. m_empty = false;
  290. }
  291. //---------------------------------------------------------------------------
  292. // Fb2SaveHandler
  293. //---------------------------------------------------------------------------
  294. Fb2SaveHandler::Fb2SaveHandler(Fb2WebView &view, QIODevice *device)
  295. : Fb2XmlHandler()
  296. , m_writer(view, device)
  297. {
  298. }
  299. Fb2SaveHandler::Fb2SaveHandler(Fb2WebView &view, QByteArray *array, QList<int> *folds)
  300. : Fb2XmlHandler()
  301. , m_writer(view, array, folds)
  302. {
  303. }
  304. Fb2XmlHandler::NodeHandler * Fb2SaveHandler::CreateRoot(const QString &name, const QXmlAttributes &atts)
  305. {
  306. if (name == "body") return new RootHandler(m_writer, name, atts);
  307. m_error = QObject::tr("The tag <body> was not found.");
  308. return 0;
  309. }