File indexing completed on 2025-01-12 13:05:53

0001 /* This file is part of the KDE project
0002    Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com>
0003    Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
0004    Copyright (c) 2003 David Faure <faure@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "ooutils.h"
0023 #include <KoStyleStack.h>
0024 #include <KoXmlReader.h>
0025 #include <QDomDocument>
0026 #include <QColor>
0027 #include <QImage>
0028 #include <KoUnit.h>
0029 #include <QRegExp>
0030 #include <kdebug.h>
0031 #include <kzip.h>
0032 
0033 const char ooNS::office[] = "http://openoffice.org/2000/office";
0034 const char ooNS::style[] = "http://openoffice.org/2000/style";
0035 const char ooNS::text[] = "http://openoffice.org/2000/text";
0036 const char ooNS::table[] = "http://openoffice.org/2000/table";
0037 const char ooNS::draw[] = "http://openoffice.org/2000/drawing";
0038 const char ooNS::presentation[] = "http://openoffice.org/2000/presentation";
0039 const char ooNS::fo[] = "http://www.w3.org/1999/XSL/Format";
0040 const char ooNS::xlink[] = "http://www.w3.org/1999/xlink";
0041 const char ooNS::number[] = "http://openoffice.org/2000/datastyle";
0042 const char ooNS::svg[] = "http://www.w3.org/2000/svg";
0043 const char ooNS::dc[] = "http://purl.org/dc/elements/1.1/";
0044 const char ooNS::meta[] = "http://openoffice.org/2000/meta";
0045 const char ooNS::config[] = "http://openoffice.org/2001/config";
0046 
0047 QString OoUtils::expandWhitespace(const KoXmlElement& tag)
0048 {
0049     //tags like <text:s text:c="4">
0050 
0051     int howmany = 1;
0052     if (tag.hasAttributeNS(ooNS::text, "c"))
0053         howmany = tag.attributeNS(ooNS::text, "c", QString()).toInt();
0054 
0055     QString result;
0056     return result.fill(32, howmany);
0057 }
0058 
0059 bool OoUtils::parseBorder(const QString & tag, double * width, int * style, QColor * color)
0060 {
0061     //string like "0.088cm solid #800000"
0062 
0063     if (tag.isEmpty() || tag == "none" || tag == "hidden") // in fact no border
0064         return false;
0065 
0066     QString _width = tag.section(' ', 0, 0);
0067     QString _style = tag.section(' ', 1, 1);
0068     QString _color = tag.section(' ', 2, 2);
0069 
0070     *width = KoUnit::parseValue(_width, 1.0);
0071 
0072     if (_style == "dashed")
0073         *style = 1;
0074     else if (_style == "dotted")
0075         *style = 2;
0076     else if (_style == "dot-dash")   // not in xsl/fo, but in OASIS (in other places)
0077         *style = 3;
0078     else if (_style == "dot-dot-dash")   // not in xsl/fo, but in OASIS (in other places)
0079         *style = 4;
0080     else if (_style == "double")
0081         *style = 5;
0082     else
0083         *style = 0;
0084 
0085     if (_color.isEmpty())
0086         *color = QColor();
0087     else
0088         color->setNamedColor(_color);
0089 
0090     return true;
0091 }
0092 
0093 void OoUtils::importIndents(QDomElement& parentElement, const KoStyleStack& styleStack)
0094 {
0095     if (styleStack.hasProperty(ooNS::fo, "margin-left") ||    // 3.11.19
0096             styleStack.hasProperty(ooNS::fo, "margin-right"))
0097         // *text-indent must always be bound to either margin-left or margin-right
0098     {
0099         double marginLeft = KoUnit::parseValue(styleStack.property(ooNS::fo, "margin-left"));
0100         double marginRight = KoUnit::parseValue(styleStack.property(ooNS::fo, "margin-right"));
0101         double first = 0;
0102         if (styleStack.property(ooNS::style, "auto-text-indent") == "true")  // style:auto-text-indent takes precedence
0103             // ### "indented by a value that is based on the current font size"
0104             // ### and "requires margin-left and margin-right
0105             // ### but how much is the indent?
0106             first = 10;
0107         else if (styleStack.hasProperty(ooNS::fo, "text-indent"))
0108             first = KoUnit::parseValue(styleStack.property(ooNS::fo, "text-indent"));
0109 
0110         if (marginLeft != 0 || marginRight != 0 || first != 0) {
0111             QDomElement indent = parentElement.ownerDocument().createElement("INDENTS");
0112             if (marginLeft != 0)
0113                 indent.setAttribute("left", QString::number(marginLeft));
0114             if (marginRight != 0)
0115                 indent.setAttribute("right", QString::number(marginRight));
0116             if (first != 0)
0117                 indent.setAttribute("first", QString::number(first));
0118             parentElement.appendChild(indent);
0119         }
0120     }
0121 }
0122 
0123 void OoUtils::importLineSpacing(QDomElement& parentElement, const KoStyleStack& styleStack)
0124 {
0125     if (styleStack.hasProperty(ooNS::fo, "line-height")) {
0126         // Fixed line height
0127         QString value = styleStack.property(ooNS::fo, "line-height");   // 3.11.1
0128         if (value != "normal") {
0129             QDomElement lineSpacing = parentElement.ownerDocument().createElement("LINESPACING");
0130             if (value == "100%")
0131                 lineSpacing.setAttribute("type", "single");
0132             else if (value == "150%")
0133                 lineSpacing.setAttribute("type", "oneandhalf");
0134             else if (value == "200%")
0135                 lineSpacing.setAttribute("type", "double");
0136             else if (value.contains('%')) {
0137                 double percent = value.toDouble();
0138                 lineSpacing.setAttribute("type", "multiple");
0139                 lineSpacing.setAttribute("spacingvalue", QString::number(percent / 100));
0140             } else { // fixed value (use KoUnit::parseValue to get it in pt)
0141                 kWarning(30519) << "Unhandled value for fo:line-height: " << value;
0142             }
0143             parentElement.appendChild(lineSpacing);
0144         }
0145     }
0146     // Line-height-at-least is mutually exclusive with line-height
0147     else if (styleStack.hasProperty(ooNS::style, "line-height-at-least")) {  // 3.11.2
0148         QString value = styleStack.property(ooNS::style, "line-height-at-least");
0149         // kotext has "at least" but that's for the linespacing, not for the entire line height!
0150         // Strange. kotext also has "at least" for the whole line height....
0151         // Did we make the wrong choice in kotext?
0152         //kWarning(30519) << "Unimplemented support for style:line-height-at-least: " << value;
0153         // Well let's see if this makes a big difference.
0154         QDomElement lineSpacing = parentElement.ownerDocument().createElement("LINESPACING");
0155         lineSpacing.setAttribute("type", "atleast");
0156         lineSpacing.setAttribute("spacingvalue", QString::number(KoUnit::parseValue(value)));
0157         parentElement.appendChild(lineSpacing);
0158     }
0159     // Line-spacing is mutually exclusive with line-height and line-height-at-least
0160     else if (styleStack.hasProperty(ooNS::style, "line-spacing")) {  // 3.11.3
0161         double value = KoUnit::parseValue(styleStack.property(ooNS::style, "line-spacing"));
0162         if (value != 0.0) {
0163             QDomElement lineSpacing = parentElement.ownerDocument().createElement("LINESPACING");
0164             lineSpacing.setAttribute("type", "custom");
0165             lineSpacing.setAttribute("spacingvalue", QString::number(value));
0166             parentElement.appendChild(lineSpacing);
0167         }
0168     }
0169 
0170 }
0171 
0172 void OoUtils::importTopBottomMargin(QDomElement& parentElement, const KoStyleStack& styleStack)
0173 {
0174     if (styleStack.hasProperty(ooNS::fo, "margin-top") ||  // 3.11.22
0175             styleStack.hasProperty(ooNS::fo, "margin-bottom")) {
0176         double mtop = KoUnit::parseValue(styleStack.property(ooNS::fo, "margin-top"));
0177         double mbottom = KoUnit::parseValue(styleStack.property(ooNS::fo, "margin-bottom"));
0178         if (mtop != 0 || mbottom != 0) {
0179             QDomElement offset = parentElement.ownerDocument().createElement("OFFSETS");
0180             if (mtop != 0)
0181                 offset.setAttribute("before", QString::number(mtop));
0182             if (mbottom != 0)
0183                 offset.setAttribute("after", QString::number(mbottom));
0184             parentElement.appendChild(offset);
0185         }
0186     }
0187 }
0188 
0189 void OoUtils::importTabulators(QDomElement& parentElement, const KoStyleStack& styleStack)
0190 {
0191     if (!styleStack.hasChildNode(ooNS::style, "tab-stops"))     // 3.11.10
0192         return;
0193     KoXmlElement tabStops = styleStack.childNode(ooNS::style, "tab-stops");
0194     //kDebug(30519) << tabStops.childNodes().count() <<" tab stops in layout.";
0195     for (KoXmlNode it = tabStops.firstChild(); !it.isNull(); it = it.nextSibling()) {
0196         KoXmlElement tabStop = it.toElement();
0197         Q_ASSERT(tabStop.prefix() == "style");
0198         Q_ASSERT(tabStop.tagName() == "tab-stop");
0199         QString type = tabStop.attributeNS(ooNS::style, "type", QString());   // left, right, center or char
0200 
0201         QDomElement elem = parentElement.ownerDocument().createElement("TABULATOR");
0202         int calligraType = 0;
0203         if (type == "left")
0204             calligraType = 0;
0205         else if (type == "center")
0206             calligraType = 1;
0207         else if (type == "right")
0208             calligraType = 2;
0209         else if (type == "char") {
0210             QString delimiterChar = tabStop.attributeNS(ooNS::style, "char", QString());   // single character
0211             elem.setAttribute("alignchar", delimiterChar);
0212             calligraType = 3; // "alignment on decimal point"
0213         }
0214 
0215         elem.setAttribute("type", calligraType);
0216 
0217         double pos = KoUnit::parseValue(tabStop.attributeNS(ooNS::style, "position", QString()));
0218         elem.setAttribute("ptpos", QString::number(pos));
0219 
0220         // TODO Convert leaderChar's unicode value to the Calligra enum
0221         // (blank/dots/line/dash/dash-dot/dash-dot-dot, 0 to 5)
0222         QString leaderChar = tabStop.attributeNS(ooNS::style, "leader-char", QString());   // single character
0223         if (!leaderChar.isEmpty()) {
0224             int filling = 0;
0225             QChar ch = leaderChar[0];
0226             switch (ch.toLatin1()) {
0227             case '.':
0228                 filling = 1; break;
0229             case '-':
0230             case '_':  // TODO in Words: differentiate --- and ___
0231                 filling = 2; break;
0232             default:
0233                 // Words doesn't have support for "any char" as filling.
0234                 // Instead it has dash-dot and dash-dot-dot - but who uses that in a tabstop?
0235                 break;
0236             }
0237             elem.setAttribute("filling", filling);
0238         }
0239         parentElement.appendChild(elem);
0240     }
0241 
0242 }
0243 
0244 void OoUtils::importBorders(QDomElement& parentElement, const KoStyleStack& styleStack)
0245 {
0246     if (styleStack.hasProperty(ooNS::fo, "border", "left")) {
0247         double width;
0248         int style;
0249         QColor color;
0250         if (OoUtils::parseBorder(styleStack.property(ooNS::fo, "border", "left"), &width, &style, &color)) {
0251             QDomElement lbElem = parentElement.ownerDocument().createElement("LEFTBORDER");
0252             lbElem.setAttribute("width", QString::number(width));
0253             lbElem.setAttribute("style", QString::number(style));
0254             if (color.isValid()) {
0255                 lbElem.setAttribute("red", color.red());
0256                 lbElem.setAttribute("green", color.green());
0257                 lbElem.setAttribute("blue", color.blue());
0258             }
0259             parentElement.appendChild(lbElem);
0260         }
0261     }
0262 
0263     if (styleStack.hasProperty(ooNS::fo, "border", "right")) {
0264         double width;
0265         int style;
0266         QColor color;
0267         if (OoUtils::parseBorder(styleStack.property(ooNS::fo, "border", "right"), &width, &style, &color)) {
0268             QDomElement lbElem = parentElement.ownerDocument().createElement("RIGHTBORDER");
0269             lbElem.setAttribute("width", QString::number(width));
0270             lbElem.setAttribute("style", QString::number(style));
0271             if (color.isValid()) {
0272                 lbElem.setAttribute("red", color.red());
0273                 lbElem.setAttribute("green", color.green());
0274                 lbElem.setAttribute("blue", color.blue());
0275             }
0276             parentElement.appendChild(lbElem);
0277         }
0278     }
0279 
0280     if (styleStack.hasProperty(ooNS::fo, "border", "top")) {
0281         double width;
0282         int style;
0283         QColor color;
0284         if (OoUtils::parseBorder(styleStack.property(ooNS::fo, "border", "top"), &width, &style, &color)) {
0285             QDomElement lbElem = parentElement.ownerDocument().createElement("TOPBORDER");
0286             lbElem.setAttribute("width", QString::number(width));
0287             lbElem.setAttribute("style", QString::number(style));
0288             if (color.isValid()) {
0289                 lbElem.setAttribute("red", color.red());
0290                 lbElem.setAttribute("green", color.green());
0291                 lbElem.setAttribute("blue", color.blue());
0292             }
0293             parentElement.appendChild(lbElem);
0294         }
0295     }
0296 
0297     if (styleStack.hasProperty(ooNS::fo, "border", "bottom")) {
0298         double width;
0299         int style;
0300         QColor color;
0301         if (OoUtils::parseBorder(styleStack.property(ooNS::fo, "border", "bottom"), &width, &style, &color)) {
0302             QDomElement lbElem = parentElement.ownerDocument().createElement("BOTTOMBORDER");
0303             lbElem.setAttribute("width", QString::number(width));
0304             lbElem.setAttribute("style", QString::number(style));
0305             if (color.isValid()) {
0306                 lbElem.setAttribute("red", color.red());
0307                 lbElem.setAttribute("green", color.green());
0308                 lbElem.setAttribute("blue", color.blue());
0309             }
0310             parentElement.appendChild(lbElem);
0311         }
0312     }
0313 }
0314 
0315 void OoUtils::importUnderline(const QString& in, QString& underline, QString& styleline)
0316 {
0317     underline = "single";
0318     if (in == "none")
0319         underline = "0";
0320     else if (in == "single")
0321         styleline = "solid";
0322     else if (in == "double") {
0323         underline = in;
0324         styleline = "solid";
0325     } else if (in == "dotted" || in == "bold-dotted")  // bold-dotted not in libkotext
0326         styleline = "dot";
0327     else if (in == "dash"
0328              // those are not in libkotext:
0329              || in == "long-dash"
0330              || in == "bold-dash"
0331              || in == "bold-long-dash"
0332             )
0333         styleline = "dash";
0334     else if (in == "dot-dash"
0335              || in == "bold-dot-dash") // not in libkotext
0336         styleline = "dashdot"; // tricky ;)
0337     else if (in == "dot-dot-dash"
0338              || in == "bold-dot-dot-dash") // not in libkotext
0339         styleline = "dashdotdot"; // this is getting fun...
0340     else if (in == "wave"
0341              || in == "bold-wave" // not in libkotext
0342              || in == "double-wave" // not in libkotext
0343              || in == "small-wave") { // not in libkotext
0344         underline = in;
0345         styleline = "solid";
0346     } else if (in == "bold") {
0347         underline = "single-bold";
0348         styleline = "solid";
0349     } else
0350         kWarning(30519) << " unsupported text-underline value: " << in;
0351 }
0352 
0353 void OoUtils::importTextPosition(const QString& text_position, QString& value, QString& relativetextsize)
0354 {
0355     //OO: <vertical position (% or sub or super)> [<size as %>]
0356     //Examples: "super" or "super 58%" or "82% 58%" (where 82% is the vertical position)
0357     // TODO in words: vertical positions other than sub/super
0358     QStringList lst = text_position.split(' ');
0359     if (!lst.isEmpty()) {
0360         QString textPos = lst.front().trimmed();
0361         QString textSize;
0362         lst.pop_front();
0363         if (!lst.isEmpty())
0364             textSize = lst.front().trimmed();
0365         if (!lst.isEmpty())
0366             kWarning(30519) << "Strange text position: " << text_position;
0367         bool super = textPos == "super";
0368         bool sub = textPos == "sub";
0369         if (textPos.endsWith(QLatin1Char('%'))) {
0370             textPos.chop(1);
0371             // This is where we interpret the text position into kotext's simpler
0372             // "super" or "sub".
0373             double val = textPos.toDouble();
0374             if (val > 0)
0375                 super = true;
0376             else if (val < 0)
0377                 sub = true;
0378         }
0379         if (super)
0380             value = "2";
0381         else if (sub)
0382             value = "1";
0383         else
0384             value = "0";
0385         if (!textSize.isEmpty() && textSize.endsWith(QLatin1Char('%'))) {
0386             textSize.chop(1);
0387             double textSizeValue = textSize.toDouble() / 100; // e.g. 0.58
0388             relativetextsize = QString::number(textSizeValue);
0389         }
0390     } else
0391         value = "0";
0392 }
0393 
0394 void OoUtils::createDocumentInfo(KoXmlDocument &_meta, QDomDocument & docinfo)
0395 {
0396     KoXmlNode meta   = KoXml::namedItemNS(_meta, ooNS::office, "document-meta");
0397     KoXmlNode office = KoXml::namedItemNS(meta, ooNS::office, "meta");
0398 
0399     if (office.isNull())
0400         return;
0401     QDomElement elementDocInfo  = docinfo.documentElement();
0402 
0403     KoXmlElement e = KoXml::namedItemNS(office, ooNS::dc, "creator");
0404     if (!e.isNull() && !e.text().isEmpty()) {
0405         QDomElement author = docinfo.createElement("author");
0406         QDomElement t = docinfo.createElement("full-name");
0407         author.appendChild(t);
0408         t.appendChild(docinfo.createTextNode(e.text()));
0409         elementDocInfo.appendChild(author);
0410     }
0411 
0412     e = KoXml::namedItemNS(office, ooNS::dc, "title");
0413     if (!e.isNull() && !e.text().isEmpty()) {
0414         QDomElement about = docinfo.createElement("about");
0415         QDomElement title = docinfo.createElement("title");
0416         about.appendChild(title);
0417         title.appendChild(docinfo.createTextNode(e.text()));
0418         elementDocInfo.appendChild(about);
0419     }
0420 
0421     e = KoXml::namedItemNS(office, ooNS::dc, "description");
0422     if (!e.isNull() && !e.text().isEmpty()) {
0423         QDomElement about = elementDocInfo.namedItem("about").toElement();
0424         if (about.isNull()) {
0425             about = docinfo.createElement("about");
0426             elementDocInfo.appendChild(about);
0427         }
0428         QDomElement title = docinfo.createElement("abstract");
0429         about.appendChild(title);
0430         title.appendChild(docinfo.createTextNode(e.text()));
0431     }
0432     e = KoXml::namedItemNS(office, ooNS::dc, "subject");
0433     if (!e.isNull() && !e.text().isEmpty()) {
0434         QDomElement about = elementDocInfo.namedItem("about").toElement();
0435         if (about.isNull()) {
0436             about = docinfo.createElement("about");
0437             elementDocInfo.appendChild(about);
0438         }
0439         QDomElement subject = docinfo.createElement("subject");
0440         about.appendChild(subject);
0441         subject.appendChild(docinfo.createTextNode(e.text()));
0442     }
0443     e = KoXml::namedItemNS(office, ooNS::meta, "keywords");
0444     if (!e.isNull()) {
0445         QDomElement about = elementDocInfo.namedItem("about").toElement();
0446         if (about.isNull()) {
0447             about = docinfo.createElement("about");
0448             elementDocInfo.appendChild(about);
0449         }
0450         KoXmlElement tmp = KoXml::namedItemNS(e, ooNS::meta, "keyword");
0451         if (!tmp.isNull() && !tmp.text().isEmpty()) {
0452             QDomElement keyword = docinfo.createElement("keyword");
0453             about.appendChild(keyword);
0454             keyword.appendChild(docinfo.createTextNode(tmp.text()));
0455         }
0456     }
0457 }
0458 
0459 KoFilter::ConversionStatus OoUtils::loadAndParse(const QString& fileName, KoXmlDocument& doc, KoStore* store)
0460 {
0461     kDebug(30518) << "loadAndParse: Trying to open" << fileName;
0462 
0463     if (!store->open(fileName)) {
0464         kWarning(30519) << "Entry " << fileName << " not found!";
0465         return KoFilter::FileNotFound;
0466     }
0467     KoFilter::ConversionStatus convertStatus = loadAndParse(store->device(), doc, fileName);
0468     store->close();
0469     return convertStatus;
0470 
0471 }
0472 
0473 KoFilter::ConversionStatus OoUtils::loadAndParse(QIODevice* io, KoXmlDocument& doc, const QString & fileName)
0474 {
0475     // Error variables for QDomDocument::setContent
0476     QString errorMsg;
0477     int errorLine, errorColumn;
0478     if (!doc.setContent(io, &errorMsg, &errorLine, &errorColumn)) {
0479         kError(30519) << "Parsing error in " << fileName << "! Aborting!" << endl
0480         << " In line: " << errorLine << ", column: " << errorColumn << endl
0481         << " Error message: " << errorMsg << endl;
0482         return KoFilter::ParsingError;
0483     }
0484 
0485     kDebug(30519) << "File" << fileName << " loaded and parsed!";
0486 
0487     return KoFilter::OK;
0488 }
0489 
0490 KoFilter::ConversionStatus OoUtils::loadAndParse(const QString& filename, KoXmlDocument& doc, KZip* zip)
0491 {
0492     kDebug(30519) << "Trying to open" << filename;
0493 
0494     if (!zip) {
0495         kError(30519) << "No ZIP file!" << endl;
0496         return KoFilter::CreationError; // Should not happen
0497     }
0498 
0499     const KArchiveEntry* entry = zip->directory()->entry(filename);
0500     if (!entry) {
0501         kWarning(30519) << "Entry " << filename << " not found!";
0502         return KoFilter::FileNotFound;
0503     }
0504     if (entry->isDirectory()) {
0505         kWarning(30519) << "Entry " << filename << " is a directory!";
0506         return KoFilter::WrongFormat;
0507     }
0508     const KZipFileEntry* f = static_cast<const KZipFileEntry *>(entry);
0509     kDebug(30519) << "Entry" << filename << " has size" << f->size();
0510     QIODevice* io = f->createDevice();
0511     KoFilter::ConversionStatus convertStatus = loadAndParse(io, doc, filename);
0512     delete io;
0513     return convertStatus;
0514 }
0515 
0516 KoFilter::ConversionStatus OoUtils::loadThumbnail(QImage& thumbnail, KZip* zip)
0517 {
0518     const QString filename("Thumbnails/thumbnail.png");
0519     kDebug(30519) << "Trying to open thumbnail" << filename;
0520 
0521     if (!zip) {
0522         kError(30519) << "No ZIP file!" << endl;
0523         return KoFilter::CreationError; // Should not happen
0524     }
0525 
0526     const KArchiveEntry* entry = zip->directory()->entry(filename);
0527     if (!entry) {
0528         kWarning(30519) << "Entry " << filename << " not found!";
0529         return KoFilter::FileNotFound;
0530     }
0531     if (entry->isDirectory()) {
0532         kWarning(30519) << "Entry " << filename << " is a directory!";
0533         return KoFilter::WrongFormat;
0534     }
0535     const KZipFileEntry* f = static_cast<const KZipFileEntry *>(entry);
0536     QIODevice* io = f->createDevice();
0537     kDebug(30519) << "Entry" << filename << " has size" << f->size();
0538 
0539     if (! io->open(QIODevice::ReadOnly)) {
0540         kWarning(30519) << "Thumbnail could not be opened!";
0541         delete io;
0542         return KoFilter::StupidError;
0543     }
0544 
0545     if (! thumbnail.load(io, "PNG")) {
0546         kWarning(30519) << "Thumbnail could not be read!";
0547         delete io;
0548         return KoFilter::StupidError;
0549     }
0550 
0551     io->close();
0552 
0553     if (thumbnail.isNull()) {
0554         kWarning(30519) << "Read thumbnail is null!";
0555         delete io;
0556         return KoFilter::StupidError;
0557     }
0558 
0559     delete io;
0560 
0561     kDebug(30519) << "File" << filename << " loaded!";
0562 
0563     return KoFilter::OK;
0564 }