1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtVersit module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qvcard30writer_p.h"
35
36#include <QtCore/qbuffer.h>
37#include <QtCore/qtextcodec.h>
38#include <QtCore/qvariant.h>
39
40#include "qversitproperty.h"
41#include "qversitutils_p.h"
42
43#include <algorithm>
44
45QT_BEGIN_NAMESPACE_VERSIT
46
47/*! Constructs a writer. */
48QVCard30Writer::QVCard30Writer(QVersitDocument::VersitType type) : QVersitDocumentWriter(type)
49{
50 mPropertyNameMappings.insert(
51 QStringLiteral("X-NICKNAME"),QStringLiteral("NICKNAME"));
52 mPropertyNameMappings.insert(
53 QStringLiteral("X-IMPP"),QStringLiteral("IMPP"));
54}
55
56/*! Destroys a writer. */
57QVCard30Writer::~QVCard30Writer()
58{
59}
60
61/*!
62 * Encodes the \a property and writes it to the device.
63 */
64void QVCard30Writer::encodeVersitProperty(const QVersitProperty& property)
65{
66 QVersitProperty modifiedProperty(property);
67 QString name = mPropertyNameMappings.value(akey: property.name(),adefaultValue: property.name());
68 modifiedProperty.setName(name);
69 encodeGroupsAndName(property: modifiedProperty);
70
71 QVariant variant(modifiedProperty.variantValue());
72 if (variant.type() == QVariant::ByteArray) {
73 modifiedProperty.insertParameter(QStringLiteral("ENCODING"), QStringLiteral("b"));
74 }
75 encodeParameters(parameters: modifiedProperty.parameters());
76 writeString(QStringLiteral(":"));
77
78 QString renderedValue;
79 QByteArray renderedBytes;
80 if (variant.canConvert<QVersitDocument>()) {
81 QVersitDocument embeddedDocument = variant.value<QVersitDocument>();
82 QByteArray data;
83 QBuffer buffer(&data);
84 buffer.open(openMode: QIODevice::WriteOnly);
85 QVCard30Writer subWriter(mType);
86 subWriter.setCodec(mCodec);
87 subWriter.setDevice(&buffer);
88 subWriter.encodeVersitDocument(document: embeddedDocument);
89 QString documentString(mCodec->toUnicode(data));
90 backSlashEscape(text: &documentString);
91 renderedValue = documentString;
92 } else if (variant.type() == QVariant::String) {
93 renderedValue = variant.toString();
94 if (property.valueType() != QVersitProperty::PreformattedType) {
95 backSlashEscape(text: &renderedValue);
96 }
97 } else if (variant.type() == QVariant::StringList) {
98 // We need to backslash escape and concatenate the values in the list
99 QStringList values = property.variantValue().toStringList();
100 QString separator;
101 if (property.valueType() == QVersitProperty::CompoundType) {
102 separator = QStringLiteral(";");
103 } else {
104 if (property.valueType() != QVersitProperty::ListType) {
105 qWarning(msg: "Property: %s, variant value is a QStringList but the property's value type is neither "
106 "CompoundType or ListType", property.name().toLatin1().constData());
107 }
108 // Assume it's a ListType
109 separator = QStringLiteral(",");
110 }
111 bool first = true;
112 foreach (QString value, values) {
113 if (!(value.isEmpty() && property.valueType() == QVersitProperty::ListType)) {
114 if (!first) {
115 renderedValue += separator;
116 }
117 backSlashEscape(text: &value);
118 renderedValue += value;
119 first = false;
120 }
121 }
122 } else if (variant.type() == QVariant::ByteArray) {
123 if (mCodecIsAsciiCompatible) // optimize by not converting to unicode
124 renderedBytes = variant.toByteArray().toBase64();
125 else
126 renderedValue = QLatin1String(variant.toByteArray().toBase64().data());
127 }
128
129 if (renderedBytes.isEmpty())
130 writeString(value: renderedValue);
131 else
132 writeBytes(value: renderedBytes);
133 writeCrlf();
134}
135
136/*!
137 * Encodes the \a parameters and writes it to the device.
138 */
139void QVCard30Writer::encodeParameters(const QMultiHash<QString,QString>& parameters)
140{
141 // Sort the parameter names to yield deterministic ordering
142 QList<QString> names = parameters.uniqueKeys();
143 std::sort(first: names.begin(), last: names.end());
144 foreach (QString nameString, names) {
145 writeString(QStringLiteral(";"));
146 QStringList values = parameters.values(akey: nameString);
147 backSlashEscape(text: &nameString);
148 writeString(value: nameString);
149 writeString(QStringLiteral("="));
150 for (int i=0; i<values.size(); i++) {
151 if (i > 0)
152 writeString(QStringLiteral(","));
153 QString value = values.at(i);
154
155 backSlashEscape(text: &value);
156 writeString(value);
157 }
158 }
159}
160
161
162/*!
163 * Performs backslash escaping for line breaks (CRLFs), semicolons, backslashes and commas according
164 * to RFC 2426. This is called on parameter names and values and property values.
165 * Colons ARE NOT escaped because the examples in RFC2426 suggest that they shouldn't be.
166 */
167void QVCard30Writer::backSlashEscape(QString* text)
168{
169 static const QString m1(QStringLiteral("([;,\\\\])"));
170 static const QString r1(QStringLiteral("\\\\1"));
171 static const QString m2(QStringLiteral("\r\n|\r|\n"));
172 static const QString r2(QStringLiteral("\\n"));
173 /* replaces ; with \;
174 , with \,
175 \ with \\
176 */
177 text->replace(rx: QRegExp(m1), after: r1);
178 // replaces any CRLFs with \n
179 text->replace(rx: QRegExp(m2), after: r2);
180}
181
182QT_END_NAMESPACE_VERSIT
183

source code of qtpim/src/versit/qvcard30writer.cpp