diff -r e686773b3f54 -r 0ba2181d7c28 qtcontactsmobility/src/versit/versitutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qtcontactsmobility/src/versit/versitutils.cpp Fri Mar 19 09:27:18 2010 +0200 @@ -0,0 +1,459 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "versitutils_p.h" +#include "qmobilityglobal.h" + +#include +#include + +QTM_BEGIN_NAMESPACE + +/*! + * Folds \a text by making all lines \a maxChars long. + */ +QByteArray VersitUtils::fold(QByteArray& text, int maxChars) +{ + char previous = 0; + int charsSinceLastLineBreak = 0; + for (int i=0; i= 'a' && next <= 'f') || + (next >= 'A' && next <= 'F') || + (next >= '0' && next <= '9')) && + ((nextAfterNext >= 'a' && nextAfterNext <= 'f') || + (nextAfterNext >= 'A' && nextAfterNext <= 'F') || + (nextAfterNext >= '0' && nextAfterNext <= '9'))) { + QByteArray hexEncodedChar(text.mid(i+1,2)); + bool decoded = false; + char decodedChar = hexEncodedChar.toInt(&decoded,16); + QByteArray decodedCharAsByteArray; + decodedCharAsByteArray.append(decodedChar); + if (decoded) { + text.replace(i,3,decodedCharAsByteArray); + } + } + } + } +} + +/*! + * Performs backslash escaping for line breaks (CRLFs), + * semicolons, backslashes and commas according to RFC 2426. + */ +bool VersitUtils::backSlashEscape(QByteArray& text) +{ + bool escaped = false; + bool withinQuotes = false; + char previous = 0; + for (int i=0; i < text.length(); i++) { + char current = text.at(i); + if (previous != '\\' && !withinQuotes) { + char next = 0; + if (i != text.length()-1) + next = text.at(i+1); + if (current == ';' || current == ',' || + (current == '\\' && + next != '\\' && next != ';' && next != ',' && next != 'n')) { + text.insert(i,'\\'); + i++; + escaped = true; + } else if (previous == '\r' && current == '\n') { + text.replace(i-1,2,"\\n"); + escaped = true; + } else { + // NOP + } + } + if (current == '"') + withinQuotes = !withinQuotes; + previous = current; + } + return escaped; +} + +/*! + * Removes backslash escaping for line breaks (CRLFs), + * semicolons, backslashes and commas according to RFC 2426. + */ +void VersitUtils::removeBackSlashEscaping(QByteArray& text) +{ + char previous = 0; + bool withinQuotes = false; + for (int i=0; i < text.length(); i++) { + char current = text.at(i); + if (previous == '\\' && !withinQuotes) { + if (current == ';' || current == ',' || current == '\\') { + text.remove(i-1,1); + } else if (current == 'n' || current == 'N') { + text.replace(i-1,2,"\r\n"); + } else { + // NOP + } + } + if (current == '"') + withinQuotes = !withinQuotes; + previous = current; + } +} + +/*! + * Finds the position of the first non-soft line break + * in a Quoted-Printable encoded string. + */ +int VersitUtils::findHardLineBreakInQuotedPrintable(const QByteArray& encoded) +{ + int crlfIndex = encoded.indexOf("\r\n"); + if (crlfIndex <= 0) + return -1; + while (crlfIndex > 0 && encoded.at(crlfIndex-1) == '=') { + crlfIndex = encoded.indexOf("\r\n",crlfIndex+2); + } + + return crlfIndex; +} + +/*! + * Extracts the groups and the name of the property. + */ +QPair VersitUtils::extractPropertyGroupsAndName( + const QByteArray& property) +{ + QPair groupsAndName; + int length = 0; + char previous = 0; + for (int i=0; i < property.length(); i++) { + char current = property.at(i); + if ((current == ';' && previous != '\\') || + current == ':') { + length = i; + break; + } + previous = current; + } + if (length > 0) { + QString trimmedGroupsAndName = + QString::fromAscii(property.left(length).trimmed()); + QStringList parts = trimmedGroupsAndName.split(QString::fromAscii(".")); + if (parts.count() > 1) { + groupsAndName.second = parts.takeLast(); + groupsAndName.first = parts; + } else { + groupsAndName.second = trimmedGroupsAndName; + } + } + + return groupsAndName; +} + +/*! + * Extracts the value of the property. + * Returns an empty string if the value was not found + */ +QByteArray VersitUtils::extractPropertyValue(const QByteArray& property) +{ + QByteArray value; + int index = property.indexOf(':') + 1; + if (index > 0 && property.length() > index) + value = property.mid(index); + return value; +} + +/*! + * Extracts the property parameters as a QMultiHash. + * The parameters without names are added as "TYPE" parameters. + */ +QMultiHash VersitUtils::extractVCard21PropertyParams( + const QByteArray& property) +{ + QMultiHash result; + QList paramList = extractParams(property); + while (!paramList.isEmpty()) { + QByteArray param = paramList.takeLast(); + QString name = QString::fromAscii(paramName(param)); + QString value = QString::fromAscii(paramValue(param)); + result.insert(name,value); + } + + return result; +} + +/*! + * Extracts the property parameters as a QMultiHash. + * The parameters without names are added as "TYPE" parameters. + */ +QMultiHash VersitUtils::extractVCard30PropertyParams( + const QByteArray& property) +{ + QMultiHash result; + QList paramList = extractParams(property); + while (!paramList.isEmpty()) { + QByteArray param = paramList.takeLast(); + QByteArray name = paramName(param); + removeBackSlashEscaping(name); + QByteArray values = paramValue(param); + QList valueList = extractParts(values,','); + while (!valueList.isEmpty()) { + QByteArray value(valueList.takeLast()); + removeBackSlashEscaping(value); + result.insert(QString::fromAscii(name),QString::fromAscii(value)); + } + } + + return result; +} + +/*! + * Extracts the parameters as delimited by semicolons. + */ +QList VersitUtils::extractParams(const QByteArray& property) +{ + QList params; + int colonIndex = property.indexOf(':'); + if (colonIndex > 0) { + QByteArray nameAndParamsString = property.left(colonIndex); + params = extractParts(nameAndParamsString,';'); + if (!params.isEmpty()) + params.removeFirst(); // Remove property name + } + + return params; +} + +/*! + * Extracts the parts separated by separator + * discarding the separators escaped with a backslash + */ +QList VersitUtils::extractParts( + const QByteArray& text, + char separator) +{ + QList parts; + int partStartIndex = 0; + char previous = 0; + for (int i=0; i 0) + parts.append(part); + partStartIndex = i+1; + } + previous = current; + } + + // Add the last or only part + QByteArray part = extractPart(text,partStartIndex); + if (part.length() > 0) + parts.append(part); + return parts; +} + +/*! + * Extracts a substring limited by /a startPosition and /a length. + */ +QByteArray VersitUtils::extractPart( + const QByteArray& text, + int startPosition, + int length) +{ + QByteArray part; + if (startPosition >= 0) + part = text.mid(startPosition,length).trimmed(); + return part; +} + +/*! + * Extracts the name of the parameter. + * No name is interpreted as an implicit "TYPE". + */ +QByteArray VersitUtils::paramName(const QByteArray& parameter) +{ + if (parameter.trimmed().length() == 0) + return QByteArray(); + int equalsIndex = parameter.indexOf('='); + if (equalsIndex > 0) { + return parameter.left(equalsIndex).trimmed(); + } + + return QByteArray("TYPE"); +} + +/*! + * Extracts the value of the parameter + */ +QByteArray VersitUtils::paramValue(const QByteArray& parameter) +{ + QByteArray value(parameter); + int equalsIndex = parameter.indexOf('='); + if (equalsIndex > 0) { + if (equalsIndex == parameter.length()-1) { + value = QByteArray(); + } else { + int valueLength = parameter.length() - (equalsIndex + 1); + value = parameter.right(valueLength).trimmed(); + } + } + + return value; +} + +/*! + * Checks whether the \a chr should be Quoted-Printable encoded (RFC 1521). + */ +bool VersitUtils::shouldBeQuotedPrintableEncoded(char chr) +{ + return (chr < 32 || + chr == '!' || chr == '"' || chr == '#' || chr == '$' || + chr == '=' || chr == '@' || chr == '[' || chr == '\\' || + chr == ']' || chr == '^' || chr == '`' || + chr > 122 ); +} + +QTM_END_NAMESPACE