/* ============================================================ * * This file is a part of kipi-plugins project * http://www.kipi-plugins.org * * Date : 2007-09-03 * Description : Exiv2 library interface for KDE * * Copyright (C) 2006-2009 by Gilles Caulier * Copyright (C) 2006-2009 by Marcel Wiesweg * * NOTE: Do not use kdDebug() in this implementation because * it will be multithreaded. Use tqDebug() instead. * See B.K.O #133026 for details. * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ // Local includes. #include "kexiv2private.h" namespace KExiv2Iface { KExiv2Priv::KExiv2Priv() { imageComments = std::string(); } KExiv2Priv::~KExiv2Priv() { #ifdef _XMP_SUPPORT_ // Fix memory leak if Exiv2 support XMP. Exiv2::XmpParser::terminate(); #endif // _XMP_SUPPORT_ } bool KExiv2Priv::setExif(Exiv2::DataBuf const data) { try { #if (EXIV2_TEST_VERSION(0,28,0)) if (data.size() != 0) { Exiv2::ExifParser::decode(exifMetadata, data.c_data(), data.size()); return (!exifMetadata.empty()); } #else if (data.size_ != 0) { Exiv2::ExifParser::decode(exifMetadata, data.pData_, data.size_); return (!exifMetadata.empty()); } #endif } catch( Exiv2::Error &e ) { if (!filePath.isEmpty()) tqDebug ("From file %s", filePath.ascii()); printExiv2ExceptionError("Cannot set Exif data using Exiv2 ", e); } return false; } bool KExiv2Priv::setIptc(Exiv2::DataBuf const data) { try { #if (EXIV2_TEST_VERSION(0,28,0)) if (data.size() != 0) { Exiv2::IptcParser::decode(iptcMetadata, data.c_data(), data.size()); return (!iptcMetadata.empty()); } #else if (data.size_ != 0) { Exiv2::IptcParser::decode(iptcMetadata, data.pData_, data.size_); return (!iptcMetadata.empty()); } #endif } catch( Exiv2::Error &e ) { if (!filePath.isEmpty()) tqDebug ("From file %s", filePath.ascii()); printExiv2ExceptionError("Cannot set Iptc data using Exiv2 ", e); } return false; } void KExiv2Priv::printExiv2ExceptionError(const TQString& msg, Exiv2::Error& e) { std::string s(e.what()); tqDebug("%s (Error #%i: %s)", msg.ascii(), (int)e.code(), s.c_str()); } TQString KExiv2Priv::convertCommentValue(const Exiv2::Exifdatum &exifDatum) { try { std::string comment; std::string charset; comment = exifDatum.toString(); // libexiv2 will prepend "charset=\"SomeCharset\" " if charset is specified // Before conversion to TQString, we must know the charset, so we stay with std::string for a while if (comment.length() > 8 && comment.substr(0, 8) == "charset=") { // the prepended charset specification is followed by a blank std::string::size_type pos = comment.find_first_of(' '); if (pos != std::string::npos) { // extract string between the = and the blank charset = comment.substr(8, pos-8); // get the rest of the string after the charset specification comment = comment.substr(pos+1); } } if (charset == "\"Unicode\"") { // TQString expects a null-terminated UCS-2 string. // Is it already null terminated? In any case, add termination "\0\0" for safety. comment.resize(comment.length() + 2, '\0'); return TQString::fromUcs2((unsigned short *)comment.data()); } else if (charset == "\"Jis\"") { TQTextCodec *codec = TQTextCodec::codecForName("JIS7"); return codec->toUnicode(comment.c_str()); } else if (charset == "\"Ascii\"") { return TQString::fromLatin1(comment.c_str()); } else { return detectEncodingAndDecode(comment); } } catch( Exiv2::Error &e ) { printExiv2ExceptionError("Cannot convert Comment using Exiv2 ", e); } return TQString(); } TQString KExiv2Priv::detectEncodingAndDecode(const std::string &value) { // For charset autodetection, we could use sophisticated code // (Mozilla chardet, TDEHTML's autodetection, TQTextCodec::codecForContent), // but that is probably too much. // We check for UTF8, Local encoding and ASCII. if (value.empty()) return TQString(); #if KDE_IS_VERSION(3,2,0) if (KStringHandler::isUtf8(value.c_str())) { return TQString::fromUtf8(value.c_str()); } #else // anyone who is still running KDE 3.0 or 3.1 is missing so many features // that he will have to accept this missing feature. return TQString::fromUtf8(value.c_str()); #endif // Utf8 has a pretty unique byte pattern. // Thats not true for ASCII, it is not possible // to reliably autodetect different ISO-8859 charsets. // We try if TQTextCodec can decide here, otherwise we use Latin1. // Or use local8Bit as default? // load TQTextCodecs TQTextCodec *latin1Codec = TQTextCodec::codecForName("iso8859-1"); //TQTextCodec *utf8Codec = TQTextCodec::codecForName("utf8"); TQTextCodec *localCodec = TQTextCodec::codecForLocale(); // make heuristic match int latin1Score = latin1Codec->heuristicContentMatch(value.c_str(), value.length()); int localScore = localCodec->heuristicContentMatch(value.c_str(), value.length()); // convert string: // Use whatever has the larger score, local or ASCII if (localScore >= 0 && localScore >= latin1Score) { // workaround for bug #134999: // The TQLatin15Codec may crash if strlen < value.length() int length = value.length(); if (localCodec->name() == TQString::fromLatin1("ISO 8859-15")) length = strlen(value.c_str()); return localCodec->toUnicode(value.c_str(), length); } else return TQString::fromLatin1(value.c_str()); } } // NameSpace KExiv2Iface