File indexing completed on 2024-05-12 16:29:03

0001 /* This file is part of the KDE project
0002    Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
0003    Copyright (C) 2009 Jarosław Staniek <staniek@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KoOdfExporter.h"
0022 #include "MsooXmlUtils.h"
0023 
0024 #include <QBuffer>
0025 #include <QByteArray>
0026 
0027 #include "MsooXmlDebug.h"
0028 
0029 #include <KoOdfWriteStore.h>
0030 #include <KoStoreDevice.h>
0031 #include <KoFilterChain.h>
0032 #include <KoGenStyles.h>
0033 #include <KoXmlWriter.h>
0034 
0035 #include <memory>
0036 
0037 KoOdfWriters::KoOdfWriters()
0038         : content(0), body(0), meta(0), manifest(0), mainStyles(0)
0039 {
0040 }
0041 
0042 //------------------------------------------
0043 
0044 class Q_DECL_HIDDEN KoOdfExporter::Private
0045 {
0046 public:
0047     Private() {}
0048     QByteArray bodyContentElement;
0049 };
0050 
0051 //------------------------------------------
0052 
0053 KoOdfExporter::KoOdfExporter(const QString& bodyContentElement, QObject* parent)
0054         : KoFilter(parent)
0055         , d(new Private)
0056 {
0057     d->bodyContentElement = QByteArray("office:") + bodyContentElement.toLatin1();
0058 }
0059 
0060 KoOdfExporter::~KoOdfExporter()
0061 {
0062     delete d;
0063 }
0064 
0065 KoFilter::ConversionStatus KoOdfExporter::convert(const QByteArray& from, const QByteArray& to)
0066 {
0067     // check for proper conversion
0068     if (!acceptsSourceMimeType(from)) {
0069         warnMsooXml << "Invalid source mimetype" << from;
0070         return KoFilter::NotImplemented;
0071     }
0072     if (!acceptsDestinationMimeType(to)) {
0073         warnMsooXml << "Invalid destination mimetype" << to;
0074         return KoFilter::NotImplemented;
0075     }
0076 
0077     //create output files
0078     KoStore *outputStore = KoStore::createStore(m_chain->outputFile(), KoStore::Write, to, KoStore::Zip);
0079     if (!outputStore || outputStore->bad()) {
0080         warnMsooXml << "Unable to open output file!";
0081         delete outputStore;
0082         return KoFilter::FileNotFound;
0083     }
0084     debugMsooXml << "created outputStore.";
0085     KoOdfWriteStore oasisStore(outputStore);
0086 
0087     debugMsooXml << "created oasisStore.";
0088 
0089     // KoGenStyles for writing styles while we're parsing
0090     KoGenStyles mainStyles;
0091 
0092     KoOdfWriters writers;
0093     writers.mainStyles = &mainStyles;
0094 
0095     // create a writer for meta.xml
0096     QBuffer buf;
0097     buf.open(QIODevice::WriteOnly);
0098     KoXmlWriter metaWriter(&buf);
0099     writers.meta = &metaWriter;
0100 
0101     // create a writer for manifest.xml
0102     QBuffer manifestBuf;
0103     manifestBuf.open(QIODevice::WriteOnly);
0104     KoXmlWriter manifestWriter(&manifestBuf);
0105     writers.manifest = &manifestWriter;
0106 
0107     //open contentWriter & bodyWriter *temp* writers
0108     //so we can write picture files while we parse
0109     QBuffer contentBuf;
0110     KoXmlWriter contentWriter(&contentBuf);
0111     writers.content = &contentWriter;
0112     QBuffer bodyBuf;
0113     KoXmlWriter bodyWriter(&bodyBuf);
0114     writers.body = &bodyWriter;
0115 
0116     // open main tags
0117     bodyWriter.startElement("office:body");
0118     bodyWriter.startElement(d->bodyContentElement.constData());
0119 
0120     RETURN_IF_ERROR( createDocument(outputStore, &writers) )
0121 
0122     //save the office:automatic-styles & and fonts in content.xml
0123     mainStyles.saveOdfStyles(KoGenStyles::FontFaceDecls, &contentWriter);
0124     mainStyles.saveOdfStyles(KoGenStyles::DocumentAutomaticStyles, &contentWriter);
0125 
0126     //close tags in body
0127     bodyWriter.endElement();//office:*
0128     bodyWriter.endElement();//office:body
0129 
0130     //now create real content/body writers & dump the information there
0131     KoXmlWriter* realContentWriter = oasisStore.contentWriter();
0132     if (!realContentWriter) {
0133         warnMsooXml << "Error creating the content writer.";
0134         delete outputStore;
0135         return KoFilter::CreationError;
0136     }
0137     realContentWriter->addCompleteElement(&contentBuf);
0138 
0139     KoXmlWriter* realBodyWriter = oasisStore.bodyWriter();
0140     if (!realBodyWriter) {
0141         warnMsooXml << "Error creating the body writer.";
0142         delete outputStore;
0143         return KoFilter::CreationError;
0144     }
0145     realBodyWriter->addCompleteElement(&bodyBuf);
0146 
0147     //now close content & body writers
0148     if (!oasisStore.closeContentWriter()) {
0149         warnMsooXml << "Error closing content.";
0150         delete outputStore;
0151         return KoFilter::CreationError;
0152     }
0153 
0154     debugMsooXml << "closed content & body writers.";
0155 
0156     //create the manifest file
0157     KoXmlWriter* realManifestWriter = oasisStore.manifestWriter(to);
0158     //create the styles.xml file
0159     mainStyles.saveOdfStylesDotXml(outputStore, realManifestWriter);
0160     realManifestWriter->addManifestEntry("content.xml", "text/xml");
0161     realManifestWriter->addCompleteElement(&manifestBuf);
0162 
0163     debugMsooXml << "created manifest and styles.xml";
0164 
0165     // create settings.xml, apparently it is used to note calligra that msoffice files should
0166     // have different behavior with some things
0167     if (!outputStore->open("settings.xml")) {
0168         delete outputStore;
0169         return KoFilter::CreationError;
0170     }
0171 
0172     KoStoreDevice settingsDev(outputStore);
0173     KoXmlWriter* settings = KoOdfWriteStore::createOasisXmlWriter(&settingsDev, "office:document-settings");
0174     settings->startElement("office:settings");
0175     settings->startElement("config:config-item-set");
0176     settings->addAttribute("config:name", "ooo:configuration-settings");
0177     writeConfigurationSettings(settings);
0178     settings->endElement(); // config:config-item-set
0179     settings->endElement(); // office:settings
0180     settings->endElement(); // office:document-settings
0181     settings->endDocument();
0182     delete settings;
0183     realManifestWriter->addManifestEntry("settings.xml", "text/xml");
0184     if (!outputStore->close()) {
0185         delete outputStore;
0186         return KoFilter::CreationError;
0187     }
0188 
0189     //create meta.xml
0190     if (!outputStore->open("meta.xml")) {
0191         delete outputStore;
0192         return KoFilter::CreationError;
0193     }
0194     KoStoreDevice metaDev(outputStore);
0195     KoXmlWriter* meta = KoOdfWriteStore::createOasisXmlWriter(&metaDev, "office:document-meta");
0196     meta->startElement("office:meta");
0197     meta->addCompleteElement(&buf);
0198     meta->endElement(); //office:meta
0199     meta->endElement(); //office:document-meta
0200     meta->endDocument();
0201     delete meta;
0202     if (!outputStore->close()) {
0203         delete outputStore;
0204         return KoFilter::CreationError;
0205     }
0206     realManifestWriter->addManifestEntry("meta.xml", "text/xml");
0207     oasisStore.closeManifestWriter();
0208     delete outputStore;
0209 
0210     return KoFilter::OK;
0211 }