81 |
81 |
82 // The maximum number of bytes allowed to stay in memory after being read. The smaller this is, |
82 // The maximum number of bytes allowed to stay in memory after being read. The smaller this is, |
83 // the more time spent moving bytes around. The larger it is, the more memory is wasted. |
83 // the more time spent moving bytes around. The larger it is, the more memory is wasted. |
84 static const int MAX_OLD_BYTES_TO_KEEP = 8192; |
84 static const int MAX_OLD_BYTES_TO_KEEP = 8192; |
85 |
85 |
86 class Q_AUTOTEST_EXPORT VersitCursor |
86 /* |
|
87 * An LByteArray has a subset of QByteArray's interface, plus an efficient chopLeft function |
|
88 * |
|
89 * It stores a QByteArray internally, plus a marker of where it starts and where it ends. |
|
90 */ |
|
91 class Q_AUTOTEST_EXPORT LByteArray |
87 { |
92 { |
88 public: |
93 public: |
89 VersitCursor() : position(-1), selection(-1) {} |
94 LByteArray() : mStart(0), mEnd(0) {} |
90 explicit VersitCursor(const QByteArray& d) :data(d), position(0), selection(0) {} |
95 explicit LByteArray(const QByteArray& d) :mData(d), mStart(0), mEnd(d.size()) {} |
91 QByteArray data; |
96 bool isEmpty() const { |
92 int position; |
97 return mEnd <= mStart; |
93 int selection; |
98 } |
94 |
99 char at(int i) const { |
95 void setData(const QByteArray& d) {data = d; position = selection = 0;} |
100 return mData.at(mStart + i); |
96 void setPosition(int pos) {position = pos; selection = qMax(pos, selection);} |
101 } |
97 void setSelection(int pos) {selection = qMax(pos, position);} |
102 QByteArray toByteArray() const { |
98 void dropOldData() |
103 return mData.mid(mStart, mEnd-mStart); |
99 { |
104 } |
100 if (position > MAX_OLD_BYTES_TO_KEEP && selection >= position) { |
105 /* Removes \a n bytes from the start of the QByteArray. */ |
101 data.remove(0, position); |
106 void chopLeft(int n) { |
102 selection -= position; |
107 Q_ASSERT(size() >= n && n >= 0); |
103 position = 0; |
108 mStart += n; |
|
109 } |
|
110 QByteArray left(int n) { |
|
111 Q_ASSERT(size() >= n && n >= 0); |
|
112 return mData.mid(mStart, n); |
|
113 } |
|
114 int indexOf(const QByteArray& needle) { |
|
115 int index = mData.indexOf(needle, mStart) - mStart; |
|
116 if (index < size()) |
|
117 return index; |
|
118 return -1; |
|
119 } |
|
120 int size() const { |
|
121 return mEnd - mStart; |
|
122 } |
|
123 const char* constData() const { |
|
124 return mData.constData() + mStart; |
|
125 } |
|
126 LByteArray& operator=(const QByteArray& ba) { |
|
127 mData = ba; |
|
128 mStart = 0; |
|
129 mEnd = mData.size(); |
|
130 return *this; |
|
131 } |
|
132 bool operator==(const QByteArray& ba) { |
|
133 return toByteArray() == ba; |
|
134 } |
|
135 bool operator!=(const QByteArray& ba) { |
|
136 return toByteArray() != ba; |
|
137 } |
|
138 |
|
139 private: |
|
140 /* Clears the memory of bytes before the start marker */ |
|
141 void dropOldData() { |
|
142 if (mStart > MAX_OLD_BYTES_TO_KEEP && mEnd >= mStart) { |
|
143 mData.remove(0, mStart); |
|
144 mEnd -= mStart; |
|
145 mStart = 0; |
104 } |
146 } |
105 } |
147 } |
|
148 QByteArray mData; |
|
149 int mStart; |
|
150 int mEnd; |
|
151 friend class LineReader; |
106 }; |
152 }; |
107 |
153 |
108 class Q_AUTOTEST_EXPORT LineReader |
154 class Q_AUTOTEST_EXPORT LineReader |
109 { |
155 { |
110 public: |
156 public: |
111 LineReader(QIODevice* device, QTextCodec* codec, int chunkSize = 1000); |
157 LineReader(QIODevice* device, QTextCodec* codec, int chunkSize = 1000); |
112 VersitCursor readLine(); |
158 LByteArray readLine(); |
|
159 void pushLine(const QByteArray& line); |
113 int odometer(); |
160 int odometer(); |
114 bool atEnd(); |
161 bool atEnd(); |
115 QTextCodec* codec(); |
162 QTextCodec* codec(); |
116 |
163 |
117 private: |
164 private: |
118 bool tryReadLine(VersitCursor& cursor, bool atEnd); |
165 bool tryReadLine(LByteArray& cursor, bool atEnd); |
119 |
166 |
120 QIODevice* mDevice; |
167 QIODevice* mDevice; |
121 QTextCodec* mCodec; |
168 QTextCodec* mCodec; |
122 int mChunkSize; // How many bytes to read in one go. |
169 int mChunkSize; // How many bytes to read in one go. |
123 QList<QByteArrayMatcher> mCrlfList; |
170 QList<QByteArrayMatcher> mCrlfList; |
124 VersitCursor mBuffer; |
171 QByteArray mFirstLine; // Stores a line that has been "pushed" in front by pushLine |
|
172 LByteArray mBuffer; |
125 int mOdometer; |
173 int mOdometer; |
126 int mSearchFrom; |
174 int mSearchFrom; |
127 }; |
175 }; |
128 |
176 |
129 class Q_AUTOTEST_EXPORT QVersitReaderPrivate : public QThread |
177 class Q_AUTOTEST_EXPORT QVersitReaderPrivate : public QThread |
151 void setError(QVersitReader::Error); |
202 void setError(QVersitReader::Error); |
152 QVersitReader::Error error() const; |
203 QVersitReader::Error error() const; |
153 void setCanceling(bool cancelling); |
204 void setCanceling(bool cancelling); |
154 bool isCanceling(); |
205 bool isCanceling(); |
155 |
206 |
156 bool parseVersitDocument(LineReader& device, |
207 bool parseVersitDocument(LineReader& device, QVersitDocument& document); |
157 QVersitDocument& document, |
208 bool parseVersitDocumentBody(LineReader& device, QVersitDocument& document); |
158 bool foundBegin = false); |
|
159 |
209 |
160 QVersitProperty parseNextVersitProperty( |
210 QVersitProperty parseNextVersitProperty( |
161 QVersitDocument::VersitType versitType, |
211 QVersitDocument::VersitType versitType, |
162 LineReader& lineReader); |
212 LineReader& lineReader); |
163 |
213 |
164 void parseVCard21Property( |
214 void parseVCard21Property( |
165 VersitCursor& text, |
215 LByteArray& text, |
166 QVersitProperty& property, |
216 QVersitProperty& property, |
167 LineReader& lineReader); |
217 LineReader& lineReader); |
168 |
218 |
169 void parseVCard30Property( |
219 void parseVCard30Property( |
170 VersitCursor& text, |
220 QVersitDocument::VersitType versitType, |
|
221 LByteArray& text, |
171 QVersitProperty& property, |
222 QVersitProperty& property, |
172 LineReader& lineReader); |
223 LineReader& lineReader); |
173 |
224 |
174 bool setVersionFromProperty( |
225 bool setVersionFromProperty( |
175 QVersitDocument& document, |
226 QVersitDocument& document, |
176 const QVersitProperty& property) const; |
227 const QVersitProperty& property) const; |
177 |
228 |
178 bool unencode( |
229 bool unencode( |
179 QByteArray& value, |
230 QByteArray& value, |
180 VersitCursor& cursor, |
|
181 QVersitProperty& property, |
231 QVersitProperty& property, |
182 LineReader& lineReader) const; |
232 LineReader& lineReader) const; |
183 |
233 |
184 QString decodeCharset( |
234 QString decodeCharset( |
185 const QByteArray& value, |
235 const QByteArray& value, |
189 |
239 |
190 void decodeQuotedPrintable(QByteArray& text) const; |
240 void decodeQuotedPrintable(QByteArray& text) const; |
191 |
241 |
192 |
242 |
193 /* These functions operate on a cursor describing a single line */ |
243 /* These functions operate on a cursor describing a single line */ |
194 QPair<QStringList,QString> extractPropertyGroupsAndName(VersitCursor& line, QTextCodec* codec) |
244 QPair<QStringList,QString> extractPropertyGroupsAndName(LByteArray& line, QTextCodec* codec) |
195 const; |
245 const; |
196 QByteArray extractPropertyValue(VersitCursor& line) const; |
246 QMultiHash<QString,QString> extractVCard21PropertyParams(LByteArray& line, QTextCodec* codec) |
197 QMultiHash<QString,QString> extractVCard21PropertyParams(VersitCursor& line, QTextCodec* codec) |
|
198 const; |
247 const; |
199 QMultiHash<QString,QString> extractVCard30PropertyParams(VersitCursor& line, QTextCodec* codec) |
248 QMultiHash<QString,QString> extractVCard30PropertyParams(LByteArray& line, QTextCodec* codec) |
200 const; |
249 const; |
201 |
250 |
202 // "Private" functions |
251 // "Private" functions |
203 QList<QByteArray> extractParams(VersitCursor& line, QTextCodec *codec) const; |
252 QList<QByteArray> extractParams(LByteArray& line, QTextCodec *codec) const; |
204 QList<QByteArray> extractParts(const QByteArray& text, const QByteArray& separator, |
253 QList<QByteArray> extractParts(const QByteArray& text, const QByteArray& separator, |
205 QTextCodec *codec) const; |
254 QTextCodec *codec) const; |
206 QByteArray extractPart(const QByteArray& text, int startPosition, int length=-1) const; |
255 QByteArray extractPart(const QByteArray& text, int startPosition, int length=-1) const; |
207 QString paramName(const QByteArray& parameter, QTextCodec* codec) const; |
256 QString paramName(const QByteArray& parameter, QTextCodec* codec) const; |
208 QString paramValue(const QByteArray& parameter, QTextCodec* codec) const; |
257 QString paramValue(const QByteArray& parameter, QTextCodec* codec) const; |
209 static bool containsAt(const QByteArray& text, const QByteArray& ba, int index); |
258 template <class T> static bool containsAt(const T& text, const QByteArray& ba, int index); |
210 bool splitStructuredValue(QVersitProperty& property, |
259 bool splitStructuredValue(QVersitProperty& property, |
211 bool hasEscapedBackslashes) const; |
260 bool hasEscapedBackslashes) const; |
212 static QStringList splitValue(const QString& string, |
261 static QStringList splitValue(const QString& string, |
213 const QChar& sep, |
262 const QChar& sep, |
214 QString::SplitBehavior behaviour, |
263 QString::SplitBehavior behaviour, |
215 bool hasEscapedBackslashes); |
264 bool hasEscapedBackslashes); |
216 static void removeBackSlashEscaping(QString& text); |
265 static void removeBackSlashEscaping(QString& text); |
217 |
266 |
218 public: // Data |
267 // Data |
219 /* key is the document type and property name, value is the type of property it is. |
268 public: |
220 If there is no entry, assume it is a PlainType */ |
|
221 QHash<QPair<QVersitDocument::VersitType,QString>, QVersitProperty::ValueType> mValueTypeMap; |
|
222 QPointer<QIODevice> mIoDevice; |
269 QPointer<QIODevice> mIoDevice; |
223 QScopedPointer<QBuffer> mInputBytes; // Holds the data set by setData() |
270 QScopedPointer<QBuffer> mInputBytes; // Holds the data set by setData() |
224 QList<QVersitDocument> mVersitDocuments; |
271 QList<QVersitDocument> mVersitDocuments; |
225 int mDocumentNestingLevel; // Depth in parsing nested Versit documents |
272 int mDocumentNestingLevel; // Depth in parsing nested Versit documents |
226 QTextCodec* mDefaultCodec; |
273 QTextCodec* mDefaultCodec; |
227 QVersitReader::State mState; |
274 QVersitReader::State mState; |
228 QVersitReader::Error mError; |
275 QVersitReader::Error mError; |
229 bool mIsCanceling; |
276 bool mIsCanceling; |
230 mutable QMutex mMutex; |
277 mutable QMutex mMutex; |
|
278 |
|
279 private: |
|
280 /* key is the document type and property name, value is the type of property it is. |
|
281 If there is no entry, assume it is a PlainType */ |
|
282 static QHash<QPair<QVersitDocument::VersitType,QString>, QVersitProperty::ValueType>* mValueTypeMap; |
231 }; |
283 }; |
232 |
284 |
233 QTM_END_NAMESPACE |
285 QTM_END_NAMESPACE |
234 |
286 |
235 #endif // QVERSITREADER_P_H |
287 #endif // QVERSITREADER_P_H |