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#ifndef QVERSITREADER_P_H
35#define QVERSITREADER_P_H
36
37//
38// W A R N I N G
39// -------------
40//
41// This file is not part of the Qt API. It exists purely as an
42// implementation detail. This header file may change from version to
43// version without notice, or even be removed.
44//
45// We mean it.
46//
47
48#include <QtCore/qbytearray.h>
49#include <QtCore/qbytearraymatcher.h>
50#include <QtCore/qhash.h>
51#include <QtCore/qlist.h>
52#include <QtCore/qmutex.h>
53#include <QtCore/qpair.h>
54#include <QtCore/qpointer.h>
55#include <QtCore/qscopedpointer.h>
56#include <QtCore/qstack.h>
57#include <QtCore/qthread.h>
58
59#include <QtVersit/qversitreader.h>
60#include <QtVersit/qversitdocument.h>
61#include <QtVersit/qversitproperty.h>
62
63QT_FORWARD_DECLARE_CLASS(QBuffer)
64QT_FORWARD_DECLARE_CLASS(QIODevice)
65QT_FORWARD_DECLARE_CLASS(QTextCodec)
66
67QT_BEGIN_NAMESPACE_VERSIT
68
69// The maximum number of bytes allowed to stay in memory after being read. The smaller this is,
70// the more time spent moving bytes around. The larger it is, the more memory is wasted.
71static const int MAX_OLD_BYTES_TO_KEEP = 8192;
72
73/*
74 * An LByteArray has a subset of QByteArray's interface, plus an efficient chopLeft function
75 *
76 * It stores a QByteArray internally, plus a marker of where it starts and where it ends.
77 */
78class LByteArray
79{
80public:
81 LByteArray() : mStart(0), mEnd(0) {}
82 explicit LByteArray(const QByteArray& d) :mData(d), mStart(0), mEnd(d.size()) {}
83 LByteArray(const QByteArray& d, int start, int end) :mData(d), mStart(start), mEnd(end) {}
84 bool isEmpty() const {
85 return mEnd <= mStart;
86 }
87 char at(int i) const {
88 return mData.at(i: mStart + i);
89 }
90 QByteArray toByteArray() const {
91 return mData.mid(index: mStart, len: mEnd-mStart);
92 }
93 /* Removes \a n bytes from the start of the QByteArray. */
94 void chopLeft(int n) {
95 Q_ASSERT(size() >= n && n >= 0);
96 mStart += n;
97 }
98 QByteArray left(int n) {
99 Q_ASSERT(size() >= n && n >= 0);
100 return mData.mid(index: mStart, len: n);
101 }
102 int indexOf(const QByteArray& needle) {
103 int index = mData.indexOf(a: needle, from: mStart) - mStart;
104 if (index < size())
105 return index;
106 return -1;
107 }
108 int size() const {
109 return mEnd - mStart;
110 }
111 const char* constData() const {
112 return mData.constData() + mStart;
113 }
114 bool contains(const QByteArray& ba) const {
115 int i = mData.indexOf(a: ba, from: mStart);
116 return i > 0 && i <= mEnd - ba.length();
117 }
118 bool endsWith(const QByteArray& ba) const {
119 // Loop backwards from ba and from mData (starting from index mEnd)
120 if (ba.size() > size())
121 return false;
122 return memcmp(s1: mData.constData()+mEnd-ba.size(), s2: ba.constData(), n: ba.size()) == 0;
123 }
124 LByteArray& operator=(const QByteArray& ba) {
125 mData = ba;
126 mStart = 0;
127 mEnd = mData.size();
128 return *this;
129 }
130 bool operator==(const QByteArray& ba) {
131 return toByteArray() == ba;
132 }
133 bool operator!=(const QByteArray& ba) {
134 return toByteArray() != ba;
135 }
136
137private:
138 /* Clears the memory of bytes before the start marker */
139 void dropOldData() {
140 if (mStart > MAX_OLD_BYTES_TO_KEEP && mEnd >= mStart) {
141 mData.remove(index: 0, len: mStart);
142 mEnd -= mStart;
143 mStart = 0;
144 }
145 }
146 void setBounds(int start, int end) {
147 mStart = start;
148 mEnd = end;
149 }
150 QByteArray mData;
151 int mStart;
152 int mEnd;
153 friend class LineReader;
154};
155
156class Q_VERSIT_EXPORT LineReader
157{
158public:
159 LineReader(QIODevice* device, QTextCodec* codec);
160 LineReader(QIODevice* device);
161 LineReader(QIODevice* device, QTextCodec* codec, int chunkSize);
162 void init();
163 void pushLine(const QByteArray& line);
164 int odometer() const;
165 bool atEnd() const;
166 QTextCodec* codec() const;
167 bool isCodecCertain() const;
168 bool isCodecUtf8Compatible() const;
169 void setCodecUtf8Incompatible();
170 LByteArray readLine();
171
172private:
173 void readOneLine(LByteArray* cursor);
174 bool tryReadLine(LByteArray* cursor, bool atEnd);
175
176 QIODevice* const mDevice;
177 QTextCodec* mCodec;
178 bool mIsCodecCertain;
179 bool mIsCodecUtf8Compatible;
180 int mChunkSize; // How many bytes to read in one go.
181 QList<QByteArrayMatcher> mCrlfList;
182 QStack<QByteArray> mPushedLines; // Stores a lines that has been "pushed" in front by pushLine
183 LByteArray mBuffer;
184 int mOdometer;
185 int mSearchFrom;
186};
187
188class Q_VERSIT_EXPORT QVersitReaderPrivate : public QThread
189{
190 Q_OBJECT
191
192public: // Constructors and destructor
193 QVersitReaderPrivate();
194 ~QVersitReaderPrivate();
195
196 static QHash<QPair<QVersitDocument::VersitType,QString>, QVersitProperty::ValueType>*
197 valueTypeMap();
198 void init(QVersitReader* reader);
199
200signals:
201 void stateChanged(QVersitReader::State state);
202 void resultsAvailable();
203
204protected: // From QThread
205 void run();
206
207public: // New functions
208 void read();
209
210 // mutexed getters and setters.
211 void setState(QVersitReader::State);
212 QVersitReader::State state() const;
213 void setError(QVersitReader::Error);
214 QVersitReader::Error error() const;
215 void setCanceling(bool cancelling);
216 bool isCanceling();
217
218 bool parseVersitDocument(LineReader* lineReader, QVersitDocument* document);
219 bool parseVersitDocumentBody(LineReader* lineReader, QVersitDocument* document);
220
221 QVersitProperty parseNextVersitProperty(
222 QVersitDocument::VersitType versitType,
223 LineReader* lineReader);
224
225 void parseVCard21Property(
226 LByteArray* text,
227 QVersitProperty* property,
228 LineReader* lineReader);
229
230 void parseVCard30Property(
231 QVersitDocument::VersitType versitType,
232 LByteArray* text,
233 QVersitProperty* property,
234 LineReader* lineReader);
235
236 bool setVersionFromProperty(
237 QVersitDocument* document,
238 const QVersitProperty& property) const;
239
240 bool unencode(
241 QByteArray* value,
242 QVersitProperty* property,
243 LineReader* lineReader) const;
244
245 QString decodeCharset(
246 const QByteArray& value,
247 QVersitProperty* property,
248 LineReader* lineReader,
249 QTextCodec** codec) const;
250
251 void decodeQuotedPrintable(QByteArray* text) const;
252
253
254 /* These functions operate on a cursor describing a single line */
255 QPair<QStringList,QString> extractPropertyGroupsAndName(LByteArray* line, QTextCodec* codec)
256 const;
257 QMultiHash<QString,QString> extractVCard21PropertyParams(LByteArray* line, QTextCodec* codec)
258 const;
259 QMultiHash<QString,QString> extractVCard30PropertyParams(LByteArray* line, QTextCodec* codec)
260 const;
261
262 // "Private" functions
263 QList<QByteArray> extractParams(LByteArray* line, QTextCodec *codec) const;
264 QList<QByteArray> extractParts(const QByteArray& text, const QByteArray& separator,
265 QTextCodec *codec) const;
266 QByteArray extractPart(const QByteArray& text, int startPosition, int length=-1) const;
267 QString paramName(const QByteArray& parameter, QTextCodec* codec) const;
268 QString paramValue(const QByteArray& parameter, QTextCodec* codec) const;
269 template <class T> static bool containsAt(const T& text, const QByteArray& ba, int index);
270 bool splitStructuredValue(QVersitProperty* property,
271 bool hasEscapedBackslashes) const;
272 static QStringList splitValue(const QString& string,
273 const QChar& sep,
274 QString::SplitBehavior behaviour,
275 bool hasEscapedBackslashes);
276 static void removeBackSlashEscaping(QString* text);
277
278// Data
279public:
280 QPointer<QIODevice> mIoDevice;
281 QScopedPointer<QBuffer> mInputBytes; // Holds the data set by setData()
282 QList<QVersitDocument> mVersitDocuments;
283 int mDocumentNestingLevel; // Depth in parsing nested Versit documents
284 QTextCodec* mDefaultCodec;
285 QVersitReader::State mState;
286 QVersitReader::Error mError;
287 bool mIsCanceling;
288 mutable QMutex mMutex;
289
290private:
291 /* key is the document type and property name, value is the type of property it is.
292 If there is no entry, assume it is a PlainType */
293 static QHash<QPair<QVersitDocument::VersitType,QString>, QVersitProperty::ValueType>* mValueTypeMap;
294};
295
296QT_END_NAMESPACE_VERSIT
297
298#endif // QVERSITREADER_P_H
299

source code of qtpim/src/versit/qversitreader_p.h