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

0001 /*
0002  * This file is part of Office 2007 Filters for Calligra
0003  * Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com>
0004  * Copyright (C) 2003 David Faure <faure@kde.org>
0005  * Copyright (C) 2002, 2003, 2004 Nicolas GOUTTE <goutte@kde.org>
0006  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
0007  *
0008  * Contact: Suresh Chande suresh.chande@nokia.com
0009  *
0010  * This library is free software; you can redistribute it and/or
0011  * modify it under the terms of the GNU Lesser General Public License
0012  * version 2.1 as published by the Free Software Foundation.
0013  *
0014  * This library is distributed in the hope that it will be useful, but
0015  * WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017  * Lesser General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Lesser General Public
0020  * License along with this library; if not, write to the Free Software
0021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0022  * 02110-1301 USA
0023  *
0024  */
0025 
0026 #include "MsooXmlImport.h"
0027 #include "MsooXmlReader.h"
0028 #include "MsooXmlUtils.h"
0029 #include "MsooXmlSchemas.h"
0030 #include "MsooXmlContentTypes.h"
0031 #include "MsooXmlRelationships.h"
0032 #include "MsooXmlTheme.h"
0033 #include "ooxml_pole.h"
0034 
0035 #include <QColor>
0036 #include <QFile>
0037 #include <QFont>
0038 #include <QPen>
0039 #include <QRegExp>
0040 #include <QImage>
0041 #include <QInputDialog>
0042 #include <QImageReader>
0043 #include <QFileInfo>
0044 
0045 #include "MsooXmlDebug.h"
0046 #include <kzip.h>
0047 #include <QTemporaryFile>
0048 
0049 #include <KoEmbeddedDocumentSaver.h>
0050 #include <KoDocumentInfo.h>
0051 #include <KoDocument.h>
0052 #include <KoFilterChain.h>
0053 #include <KoPageLayout.h>
0054 #include <KoXmlWriter.h>
0055 
0056 #include <memory>
0057 
0058 #ifdef HAVE_QCA2
0059 // QCA headers have "slots" and "signals", which QT_NO_SIGNALS_SLOTS_KEYWORDS does not like
0060 #define slots Q_SLOTS
0061 #define signals Q_SIGNALS
0062 #include <QtCrypto>
0063 #undef slots
0064 #undef signals
0065 #endif
0066 
0067 using namespace MSOOXML;
0068 
0069 MsooXmlImport::MsooXmlImport(const QString& bodyContentElement, QObject* parent)
0070         : KoOdfExporter(bodyContentElement, parent),
0071         m_zip(0),
0072         m_outputStore(0)
0073 {
0074 }
0075 
0076 MsooXmlImport::~MsooXmlImport()
0077 {
0078 }
0079 
0080 void MsooXmlImport::reportProgress(unsigned progress)
0081 {
0082     emit sigProgress(progress);
0083 }
0084 
0085 void MsooXmlImport::writeConfigurationSettings(KoXmlWriter* settings) const
0086 {
0087     settings->startElement("config:config-item");
0088     settings->addAttribute("config:name", "UseFormerLineSpacing");
0089     settings->addAttribute("config:type", "boolean");
0090     settings->addTextSpan("false");
0091     settings->endElement();
0092 
0093     settings->startElement("config:config-item");
0094     settings->addAttribute("config:name", "TabsRelativeToIndent");
0095     settings->addAttribute("config:type", "boolean");
0096     settings->addTextSpan("false"); // ODF=true, MSOffice=false
0097     settings->endElement();
0098 }
0099 
0100 KoFilter::ConversionStatus MsooXmlImport::createDocument(KoStore *outputStore,
0101                                                          KoOdfWriters *writers)
0102 {
0103     debugMsooXml << "######################## start ####################";
0104     KoFilter::ConversionStatus status = OK;
0105 //! @todo show this message in error details in the GUI:
0106     QString errorMessage;
0107 
0108     KZip* zip = new KZip(m_chain->inputFile());
0109     debugMsooXml << "Store created";
0110 
0111     QTemporaryFile* tempFile = 0;
0112 
0113     if (!zip->open(QIODevice::ReadOnly)) {
0114         errorMessage = i18n("Could not open the requested file %1", m_chain->inputFile());
0115 //! @todo transmit the error to the GUI...
0116         debugMsooXml << errorMessage;
0117         delete zip;
0118 
0119         // If the file can't be opened by the zip, it may be a
0120         // password protected file.  In OOXML, this is stored as a
0121         // standard OLE file with some special streams.
0122         QString  inputFilename = m_chain->inputFile();
0123         if (isPasswordProtectedFile(inputFilename)) {
0124             if ((tempFile = tryDecryptFile(inputFilename))) {
0125                 zip = new KZip(tempFile->fileName());
0126                 if (!zip->open(QIODevice::ReadOnly)) {
0127                     return KoFilter::PasswordProtected;
0128                 }
0129             } else {
0130                 return KoFilter::PasswordProtected;
0131             }
0132         } else
0133             return KoFilter::FileNotFound;
0134     }
0135 
0136     if (!zip->directory()) {
0137         errorMessage = i18n("Could not read ZIP directory of the requested file %1", m_chain->inputFile());
0138 //! @todo transmit the error to the GUI...
0139         debugMsooXml << errorMessage;
0140         delete zip;
0141         return KoFilter::FileNotFound;
0142     }
0143 
0144     m_zip = zip; // set context
0145     m_outputStore = outputStore; // set context
0146 
0147     status = openFile(writers, errorMessage);
0148 
0149     m_zip = 0; // clear context
0150     m_outputStore = 0; // clear context
0151 
0152     QImage thumbnail;
0153     if (status == KoFilter::OK) {
0154         // We do not care about the failure
0155         Utils::loadThumbnail(thumbnail, zip);
0156     } else {
0157         debugMsooXml << "openFile() != OK";
0158 //! @todo transmit the error to the GUI...
0159         debugMsooXml << errorMessage;
0160         delete tempFile;
0161         delete zip;
0162         return status;
0163     }
0164 
0165     if (!zip->close()) {
0166         delete tempFile;
0167         delete zip;
0168         return KoFilter::StorageCreationError;
0169     }
0170 
0171     if (status != KoFilter::OK) {
0172 //! @todo transmit the error to the GUI...
0173         debugMsooXml << errorMessage;
0174     }
0175     debugMsooXml << "######################## done ####################";
0176     delete tempFile;
0177     delete zip;
0178     return status;
0179 }
0180 
0181 static inline unsigned long readU32(const void* p)
0182 {
0183     const unsigned char* ptr = (const unsigned char*) p;
0184     return ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24);
0185 }
0186 
0187 static inline unsigned long readU16(const void* p)
0188 {
0189     const unsigned char* ptr = (const unsigned char*) p;
0190     return ptr[0] + (ptr[1] << 8);
0191 }
0192 
0193 static inline quint64 readU64(const void* p)
0194 {
0195     return quint64(readU32(p)) | quint64(readU32(reinterpret_cast<const char*>(p)+4)) << 32;
0196 }
0197 
0198 #ifdef HAVE_QCA2
0199 static QByteArray sha1sum(const QByteArray& data)
0200 {
0201     QCA::Hash sha1Hash("sha1");
0202     sha1Hash.update(data);
0203     return sha1Hash.final().toByteArray();
0204 }
0205 #endif
0206 
0207 bool MsooXmlImport::isPasswordProtectedFile(QString &filename)
0208 {
0209     // Open the file.
0210     QFile  file(filename);
0211     if (!file.open(QIODevice::ReadOnly)) {
0212         //debugMsooXml << "Cannot open " << filename;
0213         return false;
0214     }
0215 
0216     // Open the OLE storage.
0217     OOXML_POLE::Storage storage(&file);
0218     if (!storage.open()) {
0219         //debugMsooXml << "Cannot open" << filename << "as storage";
0220         file.close();
0221         return false;
0222     }
0223 
0224     //debugMsooXml << "This seems to be an OLE file";
0225 
0226     // Loop through the streams in the file and if one of them is named
0227     // "EncryptionInfo", then we probably have a password protected file.
0228     bool result = false;
0229     std::list<std::string> entries = storage.entries();
0230     std::list<std::string>::iterator it;
0231     for (it = entries.begin(); it != entries.end(); ++it) {
0232         debugMsooXml << it->c_str();
0233         if (*it == "EncryptionInfo") {
0234             result = true;
0235             break;
0236         }
0237     }
0238 
0239     // Clean up after us.
0240     storage.close();
0241     file.close();
0242 
0243     return result;
0244 }
0245 
0246 #ifdef HAVE_QCA2
0247 QCA::Cipher createCipher(const QByteArray& blockKey, const QByteArray& hn, const QByteArray& salt)
0248 {
0249     QByteArray hfinal = sha1sum(hn + blockKey);
0250     if (hfinal.size() * 8 < 128) hfinal.append(QByteArray(128/8 - hfinal.size(), 0x36));
0251     if (hfinal.size() * 8 > 128) hfinal = hfinal.left(128/8);
0252     // not clear which is correct
0253     //QByteArray iv = sha1sum(salt + blockKey);
0254     QByteArray iv = salt;
0255     QCA::Cipher aes("aes128", // TODO: size from xml
0256                     QCA::Cipher::CBC, // TODO: from xml
0257                     QCA::Cipher::NoPadding,
0258                     QCA::Decode,
0259                     hfinal, // key
0260                     iv);
0261     return aes;
0262 }
0263 #endif
0264 
0265 QTemporaryFile* MsooXmlImport::tryDecryptFile(QString &filename)
0266 {
0267 #ifdef HAVE_QCA2
0268     QCA::Initializer qcainit;
0269     debugMsooXml << QCA::isSupported("sha1") << QCA::isSupported("aes128-ecb") << QCA::supportedFeatures();
0270     if (!QCA::isSupported("sha1") || !QCA::isSupported("aes128-ecb")) {
0271 #endif
0272         debugMsooXml << "sha1 or aes128_ecb are not supported";
0273         return 0;
0274 #ifdef HAVE_QCA2
0275     }
0276 
0277     // Open the file.
0278     QFile  file(filename);
0279     if (!file.open(QIODevice::ReadOnly)) {
0280         //debugMsooXml << "Cannot open " << filename;
0281         return 0;
0282     }
0283 
0284     // Open the OLE storage.
0285     OOXML_POLE::Storage storage(&file);
0286     if (!storage.open()) {
0287         //debugMsooXml << "Cannot open" << filename << "as storage";
0288         file.close();
0289         return 0;
0290     }
0291 
0292     OOXML_POLE::Stream infoStream(&storage, "/EncryptionInfo");
0293     if (infoStream.size() < 50) {
0294         debugMsooXml << "Invalid encryption info";
0295         return 0;
0296     }
0297 
0298     unsigned char buffer[4096];
0299     unsigned bytes_read = infoStream.read(buffer, 8);
0300     Q_ASSERT(bytes_read == 8);
0301     unsigned vMajor = readU16(buffer + 0);
0302     unsigned vMinor = readU16(buffer + 2);
0303     unsigned flags = readU32(buffer + 4);
0304     debugMsooXml << "major:" << vMajor << "minor:" << vMinor << "flags:" << flags;
0305     if ((vMajor != 3 && vMajor != 4) || (vMinor != 2 && vMinor != 4)) {
0306         debugMsooXml << "unsupported encryption version";
0307         return 0;
0308     }
0309 
0310     if (vMinor == 2) {
0311         bytes_read = infoStream.read(buffer, 4);
0312         unsigned headerSize = readU32(buffer);
0313         debugMsooXml << "headersize:" << headerSize;
0314 
0315         bytes_read = infoStream.read(buffer, qMin(4096u, headerSize));
0316         unsigned flags2 = readU32(buffer + 0);
0317         if (bytes_read != headerSize || flags != flags2) {
0318             debugMsooXml << "corrupt encrypted file";
0319             return 0;
0320         }
0321 
0322         unsigned algId = readU32(buffer + 8);
0323         unsigned algIdHash = readU32(buffer + 12);
0324         unsigned keySize = readU32(buffer + 16);
0325         unsigned providerType = readU32(buffer + 20);
0326         QString cspName;
0327         for (unsigned i = 32; i < headerSize; i += 2) {
0328             unsigned c = readU16(buffer + i);
0329             if (c) {
0330                 cspName += QChar(c);
0331             } else break;
0332         }
0333         debugMsooXml << QString::number(algId, 16) << QString::number(algIdHash, 16) << keySize << QString::number(providerType, 16) << cspName;
0334 
0335         // now read verifier info
0336         bytes_read = infoStream.read(buffer, 40);
0337         if (bytes_read != 40 || readU32(buffer) != 16) {
0338             debugMsooXml << "Invalid verifier info";
0339             return 0;
0340         }
0341 
0342         QByteArray salt(reinterpret_cast<const char*>(buffer + 4), 16);
0343         QByteArray encryptedVerifier(reinterpret_cast<const char*>(buffer + 20), 16);
0344         unsigned verifierHashSize = readU32(buffer + 36);
0345         // verifier hash
0346         unsigned rem = infoStream.size() - infoStream.tell();
0347         bytes_read = infoStream.read(buffer, qMin(4096u, rem));
0348         QByteArray encryptedVerifierHash(reinterpret_cast<const char*>(buffer), bytes_read);
0349         const int spinCount = 50000; //FIXME better use long int or qint32
0350 
0351         bool first = true;
0352         while (true) {
0353             bool ok;
0354             QString password = QInputDialog::getText(0, i18n("Enter password"),
0355                                                      first ?
0356                                                          i18n("This document is encrypted, please enter the password to decrypt it:")
0357                                                        : i18n("Incorrect password, please enter the password to decrypt this document:"),
0358                                                      QLineEdit::Password, "", &ok);
0359             first = false;
0360             if (!ok) {
0361                 return 0;
0362             }
0363             QByteArray unicodePassword(reinterpret_cast<const char*>(password.utf16()), password.length()*2);
0364             QByteArray h0 = sha1sum(salt + unicodePassword);
0365             QByteArray hn = h0;
0366             for (int i = 0; i < spinCount; i++) {
0367                 QByteArray it;
0368                 it.append(i & 0xff).append((i >> 8) & 0xff).append((i >> 16) & 0xff).append((i >> 24) & 0xff);
0369                 hn = sha1sum(it + hn);
0370             }
0371             QByteArray block(4, '\0');
0372             QByteArray hfinal = sha1sum(hn + block);
0373             //debugMsooXml << hfinal;
0374             QByteArray x1(64, 0x36);
0375             QByteArray x2(64, 0x5C);
0376             for (int i = 0; i < hfinal.size(); i++) {
0377                 x1[i] = x1[i] ^ hfinal[i];
0378                 x2[i] = x2[i] ^ hfinal[i];
0379             }
0380             x1 = sha1sum(x1);
0381             x2 = sha1sum(x2);
0382             QByteArray x3 = x1 + x2;
0383             QByteArray key = x3.left(128 / 8);
0384 
0385             QCA::Cipher aes("aes128", QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Decode, key);
0386             QByteArray verifier = aes.update(encryptedVerifier).toByteArray();
0387             verifier += aes.final().toByteArray();
0388             debugMsooXml << verifier.size() << QCA::arrayToHex(verifier);
0389             QByteArray hashedVerifier = sha1sum(verifier);
0390             aes.clear();
0391             QByteArray verifierHash = aes.update(encryptedVerifierHash).toByteArray();
0392             debugMsooXml << verifierHash.size() << QCA::arrayToHex(verifierHash);
0393             verifierHash += aes.final().toByteArray();
0394             debugMsooXml << QCA::arrayToHex(hashedVerifier) << QCA::arrayToHex(verifierHash) << verifierHash.size();
0395             bool passwordCorrect = hashedVerifier.left(verifierHashSize) == verifierHash.left(verifierHashSize);
0396             debugMsooXml << "Correct?" << passwordCorrect;
0397 
0398             if (!passwordCorrect) {
0399                 continue;
0400             }
0401 
0402             OOXML_POLE::Stream *dataStream = new OOXML_POLE::Stream(&storage, "/EncryptedPackage");
0403             QTemporaryFile* outf = new QTemporaryFile;
0404             outf->open();
0405 
0406             aes.clear();
0407             bytes_read = dataStream->read(buffer, 8);
0408             debugMsooXml << readU32(buffer);
0409             while (bytes_read > 0) {
0410                 bytes_read = dataStream->read(buffer, 4096);
0411                 debugMsooXml << bytes_read;
0412                 outf->write(aes.update(QByteArray::fromRawData(reinterpret_cast<const char*>(buffer), bytes_read)).toByteArray());
0413             }
0414             outf->write(aes.final().toByteArray());
0415 
0416             outf->close(); delete dataStream;
0417 
0418             return outf;
0419         }
0420     } else {
0421         QByteArray xmlData;
0422         do {
0423             bytes_read = infoStream.read(buffer, 4096);
0424             xmlData.append(reinterpret_cast<const char*>(buffer), bytes_read);
0425         } while (bytes_read > 0);
0426         // bah, seems there is some random garbage at the end
0427         int lastIdx = xmlData.lastIndexOf('>');
0428         if (lastIdx >= 0) xmlData = xmlData.left(lastIdx+1);
0429         debugMsooXml << xmlData;
0430         QBuffer b(&xmlData);
0431         KoXmlDocument doc;
0432         QString errorMsg; int errorLine, errorColumn;
0433         if (!doc.setContent(&b, true, &errorMsg, &errorLine, &errorColumn)) {
0434             debugMsooXml << errorMsg << errorLine << errorColumn;
0435             return 0;
0436         }
0437         const QString encNS = QString::fromLatin1("http://schemas.microsoft.com/office/2006/encryption");
0438         const QString pNS = QString::fromLatin1("http://schemas.microsoft.com/office/2006/keyEncryptor/password");
0439         KoXmlElement keyData = KoXml::namedItemNS(doc.documentElement(), encNS, "keyData");
0440         KoXmlElement keyEncryptors = KoXml::namedItemNS(doc.documentElement(), encNS, "keyEncryptors");
0441         KoXmlElement keyEncryptor = keyEncryptors.firstChild().toElement();
0442         if (keyEncryptor.namespaceURI() != encNS || keyEncryptor.localName() != "keyEncryptor") {
0443             debugMsooXml << "can't parse encryption xml";
0444             return 0;
0445         }
0446         if (keyEncryptor.attribute("uri") != "http://schemas.microsoft.com/office/2006/keyEncryptor/password") {
0447             debugMsooXml << "unsupported key encryptor " << keyEncryptor.attribute("uri");
0448             return 0;
0449         }
0450         KoXmlElement encryptedKey = keyEncryptor.firstChild().toElement();
0451         if (encryptedKey.namespaceURI() != pNS || encryptedKey.localName() != "encryptedKey") {
0452             debugMsooXml << "unexpected element in key encryptor";
0453             return 0;
0454         }
0455         const int spinCount = encryptedKey.attribute("spinCount").toInt();
0456         QByteArray keyDataSalt = QByteArray::fromBase64(keyData.attribute("saltValue").toLatin1());
0457         QByteArray salt = QByteArray::fromBase64(encryptedKey.attribute("saltValue").toLatin1());
0458         QByteArray encryptedVerifierHashInput = QByteArray::fromBase64(encryptedKey.attribute("encryptedVerifierHashInput").toLatin1());
0459         QByteArray encryptedVerifierHashValue = QByteArray::fromBase64(encryptedKey.attribute("encryptedVerifierHashValue").toLatin1());
0460         QByteArray encryptedKeyValue = QByteArray::fromBase64(encryptedKey.attribute("encryptedKeyValue").toLatin1());
0461         debugMsooXml << spinCount << QCA::arrayToHex(salt) << QCA::arrayToHex(encryptedVerifierHashInput) << QCA::arrayToHex(encryptedVerifierHashValue) << QCA::arrayToHex(encryptedKeyValue);
0462         debugMsooXml << QCA::arrayToHex(keyDataSalt) << keyDataSalt.length();
0463 
0464         bool first = true;
0465         while (true) {
0466             bool ok;
0467             QString password = QInputDialog::getText(0, i18n("Enter password"),
0468                                                      first ?
0469                                                          i18n("This document is encrypted, please enter the password to decrypt it:")
0470                                                        : i18n("Incorrect password, please enter the password to decrypt this document:"),
0471                                                      QLineEdit::Password, "", &ok);
0472             first = false;
0473             if (!ok) {
0474                 return 0;
0475             }
0476 
0477             QByteArray unicodePassword(reinterpret_cast<const char*>(password.utf16()), password.length()*2);
0478             QByteArray h0 = sha1sum(salt + unicodePassword);
0479             QByteArray hn = h0;
0480             for (int i = 0; i < spinCount; i++) {
0481                 QByteArray it;
0482                 it.append(i & 0xff).append((i >> 8) & 0xff).append((i >> 16) & 0xff).append((i >> 24) & 0xff);
0483                 hn = sha1sum(it + hn);
0484             }
0485             const char blockKeyData1[] = "\xfe\xa7\xd2\x76\x3b\x4b\x9e\x79";
0486             QByteArray blockKey1(blockKeyData1, sizeof(blockKeyData1) - 1);
0487             QCA::Cipher aes1 = createCipher(blockKey1, hn, salt);
0488 
0489             QByteArray verifierHashInput = aes1.update(encryptedVerifierHashInput.append(QByteArray(4, 0))).toByteArray();
0490             verifierHashInput.append(aes1.final().toByteArray());
0491             verifierHashInput = verifierHashInput.left(16);
0492 
0493             debugMsooXml << "verifier hash input:" << QCA::arrayToHex(verifierHashInput);
0494             QByteArray hashedVerifierHashInput = sha1sum(verifierHashInput);
0495             debugMsooXml << "hashed verifier hash input:" << QCA::arrayToHex(hashedVerifierHashInput);
0496 
0497             const char blockKeyData2[] = "\xd7\xaa\x0f\x6d\x30\x61\x34\x4e";
0498             QByteArray blockKey2(blockKeyData2, sizeof(blockKeyData2) - 1);
0499             QCA::Cipher aes2 = createCipher(blockKey2, hn, salt);
0500             QByteArray verifierHashValue = aes2.update(encryptedVerifierHashValue.append(QByteArray(12, 0))).toByteArray();
0501             verifierHashValue.append(aes2.final().toByteArray());
0502 
0503             debugMsooXml << "verifier hash value:" << QCA::arrayToHex(verifierHashValue);
0504             bool passwordCorrect = hashedVerifierHashInput == verifierHashValue.left(20);
0505             if (!passwordCorrect) {
0506                 continue;
0507             }
0508 
0509             const char blockKeyData3[] = "\x14\x6e\x0b\xe7\xab\xac\xd0\xd6";
0510             QByteArray blockKey3(blockKeyData3, sizeof(blockKeyData3) - 1);
0511             QCA::Cipher aes3 = createCipher(blockKey3, hn, salt);
0512             QByteArray keyValue = aes3.update(encryptedKeyValue.append(QByteArray(4, 0))).toByteArray();
0513             keyValue.append(aes3.final().toByteArray());
0514             keyValue = keyValue.left(128/8);
0515             debugMsooXml << "key value:" << QCA::arrayToHex(keyValue);
0516 
0517             OOXML_POLE::Stream *dataStream = new OOXML_POLE::Stream(&storage, "/EncryptedPackage");
0518             QTemporaryFile* outf = new QTemporaryFile;
0519             outf->open();
0520 
0521             bytes_read = dataStream->read(buffer, 8);
0522             quint64 totSize = readU64(buffer);
0523             debugMsooXml << totSize;
0524             quint64 sizeRead = 0;
0525             unsigned segment = 0;
0526             while (bytes_read > 0) {
0527                 bytes_read = dataStream->read(buffer, 4096);
0528                 QByteArray blockKey;
0529                 blockKey.append(segment & 0xff).append((segment >> 8) & 0xff).append((segment >> 16) & 0xff).append((segment >> 24) & 0xff);
0530                 //blockKey.append((segment >> 24) & 0xff).append((segment >> 16) & 0xff).append((segment >> 8) & 0xff).append(segment & 0xff);
0531                 QByteArray iv = sha1sum(keyDataSalt + blockKey);
0532                 if (iv.size() * 8 < 128) iv.append(QByteArray(128/8 - iv.size(), 0x36));
0533                 if (iv.size() * 8 > 128) iv = iv.left(128/8);
0534                 QCA::Cipher aes("aes128",
0535                                 QCA::Cipher::CBC,
0536                                 QCA::Cipher::NoPadding,
0537                                 QCA::Decode,
0538                                 keyValue,
0539                                 iv);
0540 
0541                 QByteArray d = aes.update(QByteArray::fromRawData(reinterpret_cast<const char*>(buffer), bytes_read)).toByteArray();
0542                 d.append(aes.final().toByteArray());
0543                 if (sizeRead + d.size() > totSize) {
0544                     d = d.left(totSize - sizeRead);
0545                 }
0546                 outf->write(d);
0547                 sizeRead += d.size();
0548                 segment++;
0549             }
0550 
0551             outf->close(); delete dataStream;
0552 
0553             return outf;
0554         }
0555     }
0556 #endif
0557 }
0558 
0559 KoFilter::ConversionStatus MsooXmlImport::createImage(const QImage& source,
0560                                        const QString& destinationName)
0561 {
0562     if (!m_zip || !m_outputStore) {
0563         return KoFilter::UsageError;
0564     }
0565     QString errorMessage;
0566     const KoFilter::ConversionStatus status = Utils::createImage(errorMessage, source, m_outputStore, destinationName);
0567     if (status != KoFilter::OK) {
0568         warnMsooXml << "Failed to createImage:" << errorMessage;
0569     }
0570     return status;
0571 }
0572 
0573 KoFilter::ConversionStatus MsooXmlImport::copyFile(const QString& sourceName,
0574         const QString& destinationName, bool oleFile)
0575 {
0576     if (!m_zip || !m_outputStore) {
0577         return KoFilter::UsageError;
0578     }
0579     QString errorMessage;
0580     const KoFilter::ConversionStatus status = Utils::copyFile(
0581                 m_zip, errorMessage, sourceName, m_outputStore, destinationName, oleFile);
0582 //! @todo transmit the error to the GUI...
0583     if(status != KoFilter::OK)
0584         warnMsooXml << "Failed to copyFile:" << errorMessage;
0585     return status;
0586 }
0587 
0588 KoFilter::ConversionStatus MsooXmlImport::imageFromFile(const QString& sourceName, QImage& image)
0589 {
0590     if (!m_zip) {
0591         return KoFilter::UsageError;
0592     }
0593 
0594     QString errorMessage;
0595     KoFilter::ConversionStatus status = KoFilter::OK;
0596 
0597     std::auto_ptr<QIODevice> inputDevice(Utils::openDeviceForFile(m_zip, errorMessage, sourceName, status));
0598     if (!inputDevice.get()) {
0599         return status;
0600     }
0601     QImageReader r(inputDevice.get(), QFileInfo(sourceName).suffix().toLatin1());
0602     if (!r.canRead()) {
0603         return KoFilter::WrongFormat;
0604     }
0605     image = r.read();
0606 
0607     return status;
0608 }
0609 
0610 KoFilter::ConversionStatus MsooXmlImport::imageSize(const QString& sourceName, QSize& size)
0611 {
0612     if (!m_zip) {
0613         return KoFilter::UsageError;
0614     }
0615 
0616     QString errorMessage;
0617     KoFilter::ConversionStatus status = KoFilter::OK;
0618 
0619     const QMap<QString, QSize>::ConstIterator it(m_imageSizes.constFind(sourceName));
0620     if (it == m_imageSizes.constEnd()) {
0621         status = Utils::imageSize(m_zip, errorMessage, sourceName, &size);
0622 
0623         if (status != KoFilter::OK)
0624             size = QSize(-1, -1);
0625         m_imageSizes.insert(sourceName, size);
0626     }
0627     else {
0628         size = it.value();
0629     }
0630 
0631 //! @todo transmit the error to the GUI...
0632     debugMsooXml << errorMessage;
0633     return status;
0634 }
0635 
0636 // private
0637 KoFilter::ConversionStatus MsooXmlImport::loadAndParseDocumentInternal(
0638     const QByteArray& contentType, MsooXmlReader *reader, KoOdfWriters *writers,
0639     QString& errorMessage, MsooXmlReaderContext* context, bool *pathFound)
0640 {
0641     *pathFound = false;
0642     const QString fileName = m_contentTypes.value(contentType);
0643     debugMsooXml << contentType << "fileName=" << fileName;
0644     if (fileName.isEmpty()) {
0645         errorMessage = i18n("Could not find path for type %1", QString(contentType));
0646         warnMsooXml << errorMessage;
0647         return KoFilter::FileNotFound;
0648     }
0649     KoFilter::ConversionStatus status = loadAndParseDocumentFromFileInternal(
0650         fileName, reader, writers, errorMessage, context, pathFound);
0651     *pathFound = status != KoFilter::FileNotFound;
0652     return status;
0653 }
0654 
0655 // private
0656 KoFilter::ConversionStatus MsooXmlImport::loadAndParseDocumentFromFileInternal(
0657     const QString& fileName, MsooXmlReader *reader, KoOdfWriters *writers,
0658     QString& errorMessage, MsooXmlReaderContext* context, bool *pathFound)
0659 {
0660     *pathFound = false;
0661     if (!m_zip) {
0662         return KoFilter::UsageError;
0663     }
0664     KoFilter::ConversionStatus status = Utils::loadAndParseDocument(
0665                reader, m_zip, writers, errorMessage, fileName, context);
0666     *pathFound = status != KoFilter::FileNotFound;
0667     return status;
0668 }
0669 
0670 // protected
0671 KoFilter::ConversionStatus MsooXmlImport::loadAndParseDocument(
0672     const QByteArray& contentType, MsooXmlReader *reader, KoOdfWriters *writers,
0673     QString& errorMessage, MsooXmlReaderContext* context)
0674 {
0675     bool pathFound;
0676     return loadAndParseDocumentInternal(contentType, reader, writers, errorMessage, context, &pathFound);
0677 }
0678 
0679 // protected
0680 KoFilter::ConversionStatus MsooXmlImport::loadAndParseDocumentFromFile(
0681     const QString& fileName, MsooXmlReader *reader, KoOdfWriters *writers,
0682     QString& errorMessage, MsooXmlReaderContext* context)
0683 {
0684     bool pathFound;
0685     return loadAndParseDocumentFromFileInternal(fileName, reader, writers, errorMessage, context, &pathFound);
0686 }
0687 
0688 // protected
0689 KoFilter::ConversionStatus MsooXmlImport::loadAndParseDocumentIfExists(
0690     const QByteArray& contentType, MsooXmlReader *reader, KoOdfWriters *writers,
0691     QString& errorMessage, MsooXmlReaderContext* context)
0692 {
0693     bool pathFound;
0694     const KoFilter::ConversionStatus status( loadAndParseDocumentInternal(
0695         contentType, reader, writers, errorMessage, context, &pathFound) );
0696     if (!pathFound)
0697         return KoFilter::OK;
0698     return status;
0699 }
0700 
0701 // protected
0702 KoFilter::ConversionStatus MsooXmlImport::loadAndParseDocumentFromFileIfExists(
0703     const QString& fileName, MsooXmlReader *reader, KoOdfWriters *writers,
0704     QString& errorMessage, MsooXmlReaderContext* context)
0705 {
0706     bool pathFound;
0707     const KoFilter::ConversionStatus status( loadAndParseDocumentFromFileInternal(
0708         fileName, reader, writers, errorMessage, context, &pathFound) );
0709     if (!pathFound)
0710         return KoFilter::OK;
0711     return status;
0712 }
0713 
0714 KoFilter::ConversionStatus MsooXmlImport::loadAndParseDocument(
0715     MsooXmlReader *reader, const QString& path,
0716     MsooXmlReaderContext* context)
0717 {
0718     if (!m_zip) {
0719         return KoFilter::UsageError;
0720     }
0721     QString errorMessage;
0722     KoFilter::ConversionStatus status = Utils::loadAndParseDocument(
0723                                             reader, m_zip, reader, errorMessage, path, context);
0724     if (status != KoFilter::OK)
0725         reader->raiseError(errorMessage);
0726     return status;
0727 }
0728 
0729 KoFilter::ConversionStatus MsooXmlImport::loadAndParseDocument(
0730     MsooXmlReader *reader, const QString& path,
0731     QString& errorMessage, MsooXmlReaderContext* context)
0732 {
0733     if (!m_zip) {
0734         return KoFilter::UsageError;
0735     }
0736     KoFilter::ConversionStatus status = Utils::loadAndParseDocument(
0737                                             reader, m_zip, reader, errorMessage, path, context);
0738     return status;
0739 }
0740 
0741 KoFilter::ConversionStatus MsooXmlImport::loadAndParseFromDevice(MsooXmlReader* reader, QIODevice* device,
0742         MsooXmlReaderContext* context)
0743 {
0744     KoFilter::ConversionStatus status;
0745     reader->setDevice(device);
0746     reader->setFileName("PreDefinedDrawingMLTables"); // for error reporting
0747     status = reader->read(context);
0748     if (status != KoFilter::OK) {
0749         reader->raiseError(reader->errorString());
0750         return status;
0751     }
0752     return status;
0753 }
0754 
0755 KoFilter::ConversionStatus MsooXmlImport::openFile(KoOdfWriters *writers, QString& errorMessage)
0756 {
0757     static const char Content_Types_xml[] = "[Content_Types].xml";
0758     KoFilter::ConversionStatus status = loadAndParse(Content_Types_xml, m_contentTypesXML, errorMessage);
0759     if (status != KoFilter::OK) {
0760         debugMsooXml << Content_Types_xml << "could not be parsed correctly! Aborting!";
0761         return status;
0762     }
0763     RETURN_IF_ERROR( Utils::loadContentTypes(m_contentTypesXML, m_contentTypes) )
0764 
0765     static const char docPropy_core_xml[] = "docProps/core.xml";
0766     KoXmlDocument coreXML;
0767     if (loadAndParse(docPropy_core_xml, coreXML, errorMessage) == KoFilter::OK) {
0768         RETURN_IF_ERROR( Utils::loadDocumentProperties(coreXML, m_documentProperties) )
0769     }
0770 
0771     static const char docPropy_app_xml[] = "docProps/app.xml";
0772     KoXmlDocument appXML;
0773     if (loadAndParse(docPropy_app_xml, appXML, errorMessage) == KoFilter::OK) {
0774         RETURN_IF_ERROR( Utils::loadDocumentProperties(appXML, m_documentProperties) )
0775     }
0776 
0777     MsooXmlRelationships relationships(*this, writers, errorMessage);
0778     RETURN_IF_ERROR( parseParts(writers, &relationships, errorMessage) )
0779 //! @todo sigProgress()
0780     emit sigProgress(10);
0781 
0782     return KoFilter::OK;
0783 }
0784 
0785 KoFilter::ConversionStatus MsooXmlImport::loadAndParse(const QString& filename, KoXmlDocument& doc, QString& errorMessage)
0786 {
0787     return Utils::loadAndParse(doc, m_zip, errorMessage, filename);
0788 }