fb2save.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include <QtGui>
  2. #include <QtDebug>
  3. #include "fb2save.h"
  4. #include "fb2view.h"
  5. //---------------------------------------------------------------------------
  6. // Fb2SaveWriter
  7. //---------------------------------------------------------------------------
  8. Fb2SaveWriter::Fb2SaveWriter(Fb2WebView &view, QIODevice &device)
  9. : QXmlStreamWriter(&device)
  10. , m_view(view)
  11. {
  12. setAutoFormatting(true);
  13. setAutoFormattingIndent(2);
  14. writeStartDocument();
  15. }
  16. Fb2SaveWriter::~Fb2SaveWriter()
  17. {
  18. writeEndDocument();
  19. }
  20. QString Fb2SaveWriter::getFile(const QString &path)
  21. {
  22. StringHash::const_iterator it = m_files.find(path);
  23. if (it == m_files.end()) {
  24. QString name = m_view.fileName(path);
  25. if (name.isEmpty()) return QString();
  26. m_files[name] = path;
  27. m_names << name;
  28. return name;
  29. }
  30. return it.value();
  31. }
  32. QString Fb2SaveWriter::getData(const QString &name)
  33. {
  34. return m_view.fileData(name);
  35. }
  36. void Fb2SaveWriter::writeFiles()
  37. {
  38. StringList::const_iterator it;
  39. for (it = m_names.constBegin(); it != m_names.constEnd(); it++) {
  40. QString name = *it;
  41. if (name.isEmpty()) continue;
  42. QString data = getData(name);
  43. if (data.isEmpty()) continue;
  44. writeStartElement("binary");
  45. writeAttribute("id", name);
  46. writeCharacters(data);
  47. writeEndElement();
  48. }
  49. }
  50. //---------------------------------------------------------------------------
  51. // Fb2SaveHandler::BodyHandler
  52. //---------------------------------------------------------------------------
  53. FB2_BEGIN_KEYHASH(Fb2SaveHandler::BodyHandler)
  54. FB2_KEY( Section , "div" );
  55. FB2_KEY( Anchor , "a" );
  56. FB2_KEY( Image , "img" );
  57. FB2_KEY( Table , "table" );
  58. FB2_KEY( Parag , "p" );
  59. FB2_KEY( Strong , "b" );
  60. FB2_KEY( Emphas , "i" );
  61. FB2_KEY( Strike , "strike" );
  62. FB2_KEY( Sub , "sub" );
  63. FB2_KEY( Sup , "sup" );
  64. FB2_KEY( Code , "tt" );
  65. FB2_END_KEYHASH
  66. Fb2SaveHandler::BodyHandler::BodyHandler(Fb2SaveWriter &writer, const QString &name, const QXmlAttributes &atts, const QString &tag, const QString &style)
  67. : NodeHandler(name)
  68. , m_writer(writer)
  69. , m_tag(tag)
  70. , m_style(style)
  71. {
  72. Init(atts);
  73. }
  74. Fb2SaveHandler::BodyHandler::BodyHandler(BodyHandler *parent, const QString &name, const QXmlAttributes &atts, const QString &tag, const QString &style)
  75. : NodeHandler(name)
  76. , m_writer(parent->m_writer)
  77. , m_tag(tag)
  78. , m_style(style)
  79. {
  80. Init(atts);
  81. }
  82. void Fb2SaveHandler::BodyHandler::Init(const QXmlAttributes &atts)
  83. {
  84. if (m_tag.isEmpty()) return;
  85. m_writer.writeStartElement(m_tag);
  86. int count = atts.count();
  87. for (int i = 0; i < count; i++) {
  88. QString name = atts.qName(i);
  89. if (name.left(4) != "fb2:") continue;
  90. m_writer.writeAttribute(name.mid(4), atts.value(i));
  91. }
  92. }
  93. Fb2XmlHandler::NodeHandler * Fb2SaveHandler::BodyHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  94. {
  95. QString tag, style;
  96. switch (toKeyword(name)) {
  97. case Section : tag = atts.value("class") ; break;
  98. case Anchor : return new AnchorHandler(this, name, atts);
  99. case Image : return new ImageHandler(this, name, atts);
  100. case Parag : return new ParagHandler(this, name, atts);
  101. case Strong : tag = "strong" ; break;
  102. case Emphas : tag = "emphasis" ; break;
  103. case Strike : tag = "strikethrough" ; break;
  104. case Code : tag = "code" ; break;
  105. case Sub : tag = "sub" ; break;
  106. case Sup : tag = "sup" ; break;
  107. default: ;
  108. }
  109. return new BodyHandler(this, name, atts, tag, style);
  110. }
  111. void Fb2SaveHandler::BodyHandler::TxtTag(const QString &text)
  112. {
  113. m_writer.writeCharacters(text);
  114. }
  115. void Fb2SaveHandler::BodyHandler::EndTag(const QString &name)
  116. {
  117. Q_UNUSED(name);
  118. if (m_tag.isEmpty()) return;
  119. m_writer.writeEndElement();
  120. }
  121. //---------------------------------------------------------------------------
  122. // Fb2SaveHandler::RootHandler
  123. //---------------------------------------------------------------------------
  124. Fb2SaveHandler::RootHandler::RootHandler(Fb2SaveWriter &writer, const QString &name, const QXmlAttributes &atts)
  125. : BodyHandler(writer, name, atts, "FictionBook")
  126. {
  127. m_writer.writeAttribute("xmlns", "http://www.gribuser.ru/xml/fictionbook/2.0");
  128. m_writer.writeAttribute("xmlns:l", "http://www.w3.org/1999/xlink");
  129. }
  130. void Fb2SaveHandler::RootHandler::EndTag(const QString &name)
  131. {
  132. m_writer.writeFiles();
  133. BodyHandler::EndTag(name);
  134. }
  135. //---------------------------------------------------------------------------
  136. // Fb2SaveHandler::AnchorHandler
  137. //---------------------------------------------------------------------------
  138. Fb2SaveHandler::AnchorHandler::AnchorHandler(BodyHandler *parent, const QString &name, const QXmlAttributes &atts)
  139. : BodyHandler(parent, name, atts, "a")
  140. {
  141. QString href = Value(atts, "href");
  142. m_writer.writeAttribute("l:href", href);
  143. }
  144. //---------------------------------------------------------------------------
  145. // Fb2SaveHandler::ImageHandler
  146. //---------------------------------------------------------------------------
  147. Fb2SaveHandler::ImageHandler::ImageHandler(BodyHandler *parent, const QString &name, const QXmlAttributes &atts)
  148. : BodyHandler(parent, name, atts, "image")
  149. {
  150. QString href = Value(atts, "src");
  151. QString file = m_writer.getFile(href);
  152. if (file.isEmpty()) return;
  153. file.prepend('#');
  154. m_writer.writeAttribute("l:href", file);
  155. m_writer.writeEndElement();
  156. }
  157. //---------------------------------------------------------------------------
  158. // Fb2SaveHandler::ParagHandler
  159. //---------------------------------------------------------------------------
  160. Fb2SaveHandler::ParagHandler::ParagHandler(BodyHandler *parent, const QString &name, const QXmlAttributes &atts)
  161. : BodyHandler(parent, name, atts, "")
  162. , m_parent(parent->tag())
  163. , m_empty(true)
  164. {
  165. }
  166. Fb2XmlHandler::NodeHandler * Fb2SaveHandler::ParagHandler::NewTag(const QString &name, const QXmlAttributes &atts)
  167. {
  168. if (m_empty) start();
  169. return BodyHandler::NewTag(name, atts);
  170. }
  171. void Fb2SaveHandler::ParagHandler::TxtTag(const QString &text)
  172. {
  173. if (m_empty) {
  174. if (isWhiteSpace(text)) return;
  175. start();
  176. }
  177. BodyHandler::TxtTag(text);
  178. }
  179. void Fb2SaveHandler::ParagHandler::EndTag(const QString &name)
  180. {
  181. Q_UNUSED(name);
  182. if (m_empty) m_writer.writeStartElement("empty-line");
  183. m_writer.writeEndElement();
  184. }
  185. void Fb2SaveHandler::ParagHandler::start()
  186. {
  187. if (!m_empty) return;
  188. QString tag = m_parent == "stanza" ? "v" : "p";
  189. m_writer.writeStartElement(tag);
  190. m_empty = false;
  191. }
  192. //---------------------------------------------------------------------------
  193. // Fb2SaveHandler
  194. //---------------------------------------------------------------------------
  195. Fb2SaveHandler::Fb2SaveHandler(Fb2WebView &view, QIODevice &device)
  196. : Fb2XmlHandler()
  197. , m_writer(view, device)
  198. {
  199. }
  200. Fb2XmlHandler::NodeHandler * Fb2SaveHandler::CreateRoot(const QString &name, const QXmlAttributes &atts)
  201. {
  202. if (name == "body") return new RootHandler(m_writer, name, atts);
  203. m_error = QObject::tr("The tag <body> was not found.");
  204. return 0;
  205. }