Warning, file /office/calligra/filters/libmsooxml/MsooXmlImport.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 }