src/versit/qversitreader_p.h
changeset 5 603d3f8b6302
parent 0 876b1a06bc25
--- a/src/versit/qversitreader_p.h	Fri Sep 17 08:34:34 2010 +0300
+++ b/src/versit/qversitreader_p.h	Mon Oct 04 01:37:06 2010 +0300
@@ -83,45 +83,93 @@
 // the more time spent moving bytes around.  The larger it is, the more memory is wasted.
 static const int MAX_OLD_BYTES_TO_KEEP = 8192;
 
-class Q_AUTOTEST_EXPORT VersitCursor
+/*
+ * An LByteArray has a subset of QByteArray's interface, plus an efficient chopLeft function
+ * 
+ * It stores a QByteArray internally, plus a marker of where it starts and where it ends.
+ */
+class Q_AUTOTEST_EXPORT LByteArray
 {
 public:
-    VersitCursor() : position(-1), selection(-1) {}
-    explicit VersitCursor(const QByteArray& d) :data(d), position(0), selection(0) {}
-    QByteArray data;
-    int position;
-    int selection;
+    LByteArray() : mStart(0), mEnd(0) {}
+    explicit LByteArray(const QByteArray& d) :mData(d), mStart(0), mEnd(d.size()) {}
+    bool isEmpty() const {
+        return mEnd <= mStart;
+    }
+    char at(int i) const {
+        return mData.at(mStart + i);
+    }
+    QByteArray toByteArray() const {
+        return mData.mid(mStart, mEnd-mStart);
+    }
+    /* Removes \a n bytes from the start of the QByteArray. */ 
+    void chopLeft(int n) {
+        Q_ASSERT(size() >= n && n >= 0);
+        mStart += n;
+    }
+    QByteArray left(int n) {
+        Q_ASSERT(size() >= n && n >= 0);
+        return mData.mid(mStart, n);
+    }
+    int indexOf(const QByteArray& needle) {
+        int index = mData.indexOf(needle, mStart) - mStart;
+        if (index < size())
+            return index;
+        return -1;
+    }
+    int size() const {
+        return mEnd - mStart;
+    }
+    const char* constData() const {
+        return mData.constData() + mStart;
+    }
+    LByteArray& operator=(const QByteArray& ba) {
+        mData = ba;
+        mStart = 0;
+        mEnd = mData.size();
+        return *this;
+    }
+    bool operator==(const QByteArray& ba) {
+        return toByteArray() == ba;
+    }
+    bool operator!=(const QByteArray& ba) {
+        return toByteArray() != ba;
+    }
 
-    void setData(const QByteArray& d) {data = d; position = selection = 0;}
-    void setPosition(int pos) {position = pos; selection = qMax(pos, selection);}
-    void setSelection(int pos) {selection = qMax(pos, position);}
-    void dropOldData()
-    {
-        if (position > MAX_OLD_BYTES_TO_KEEP && selection >= position) {
-            data.remove(0, position);
-            selection -= position;
-            position = 0;
+private:
+    /* Clears the memory of bytes before the start marker */
+    void dropOldData() {
+        if (mStart > MAX_OLD_BYTES_TO_KEEP && mEnd >= mStart) {
+            mData.remove(0, mStart);
+            mEnd -= mStart;
+            mStart = 0;
         }
     }
+    QByteArray mData;
+    int mStart;
+    int mEnd;
+    friend class LineReader;
 };
 
 class Q_AUTOTEST_EXPORT LineReader
 {
 public:
     LineReader(QIODevice* device, QTextCodec* codec, int chunkSize = 1000);
-    VersitCursor readLine();
+    LByteArray readLine();
+    void pushLine(const QByteArray& line);
     int odometer();
     bool atEnd();
     QTextCodec* codec();
 
 private:
-    bool tryReadLine(VersitCursor& cursor, bool atEnd);
+    bool tryReadLine(LByteArray& cursor, bool atEnd);
 
     QIODevice* mDevice;
     QTextCodec* mCodec;
     int mChunkSize; // How many bytes to read in one go.
     QList<QByteArrayMatcher> mCrlfList;
-    VersitCursor mBuffer;
+    QByteArray mFirstLine; // Stores a line that has been "pushed" in front by pushLine
+    LByteArray mBuffer;
     int mOdometer;
     int mSearchFrom;
 };
@@ -133,6 +181,9 @@
 public: // Constructors and destructor
     QVersitReaderPrivate();
     ~QVersitReaderPrivate();
+
+    static QHash<QPair<QVersitDocument::VersitType,QString>, QVersitProperty::ValueType>*
+        valueTypeMap();
     void init(QVersitReader* reader);
 
 signals:
@@ -153,21 +204,21 @@
     void setCanceling(bool cancelling);
     bool isCanceling();
 
-    bool parseVersitDocument(LineReader& device,
-                             QVersitDocument& document,
-                             bool foundBegin = false);
+    bool parseVersitDocument(LineReader& device, QVersitDocument& document);
+    bool parseVersitDocumentBody(LineReader& device, QVersitDocument& document);
 
     QVersitProperty parseNextVersitProperty(
         QVersitDocument::VersitType versitType,
         LineReader& lineReader);
 
     void parseVCard21Property(
-        VersitCursor& text,
+        LByteArray& text,
         QVersitProperty& property,
         LineReader& lineReader);
 
     void parseVCard30Property(
-        VersitCursor& text,
+        QVersitDocument::VersitType versitType,
+        LByteArray& text,
         QVersitProperty& property,
         LineReader& lineReader);
 
@@ -177,7 +228,6 @@
 
     bool unencode(
         QByteArray& value,
-        VersitCursor& cursor,
         QVersitProperty& property,
         LineReader& lineReader) const;
 
@@ -191,22 +241,21 @@
 
 
     /* These functions operate on a cursor describing a single line */
-    QPair<QStringList,QString> extractPropertyGroupsAndName(VersitCursor& line, QTextCodec* codec)
+    QPair<QStringList,QString> extractPropertyGroupsAndName(LByteArray& line, QTextCodec* codec)
             const;
-    QByteArray extractPropertyValue(VersitCursor& line) const;
-    QMultiHash<QString,QString> extractVCard21PropertyParams(VersitCursor& line, QTextCodec* codec)
+    QMultiHash<QString,QString> extractVCard21PropertyParams(LByteArray& line, QTextCodec* codec)
             const;
-    QMultiHash<QString,QString> extractVCard30PropertyParams(VersitCursor& line, QTextCodec* codec)
+    QMultiHash<QString,QString> extractVCard30PropertyParams(LByteArray& line, QTextCodec* codec)
             const;
 
     // "Private" functions
-    QList<QByteArray> extractParams(VersitCursor& line, QTextCodec *codec) const;
+    QList<QByteArray> extractParams(LByteArray& line, QTextCodec *codec) const;
     QList<QByteArray> extractParts(const QByteArray& text, const QByteArray& separator,
                                    QTextCodec *codec) const;
     QByteArray extractPart(const QByteArray& text, int startPosition, int length=-1) const;
     QString paramName(const QByteArray& parameter, QTextCodec* codec) const;
     QString paramValue(const QByteArray& parameter, QTextCodec* codec) const;
-    static bool containsAt(const QByteArray& text, const QByteArray& ba, int index);
+    template <class T> static bool containsAt(const T& text, const QByteArray& ba, int index);
     bool splitStructuredValue(QVersitProperty& property,
                               bool hasEscapedBackslashes) const;
     static QStringList splitValue(const QString& string,
@@ -215,10 +264,8 @@
                                   bool hasEscapedBackslashes);
     static void removeBackSlashEscaping(QString& text);
 
-public: // Data
-    /* key is the document type and property name, value is the type of property it is.
-       If there is no entry, assume it is a PlainType */
-    QHash<QPair<QVersitDocument::VersitType,QString>, QVersitProperty::ValueType> mValueTypeMap;
+// Data
+public:
     QPointer<QIODevice> mIoDevice;
     QScopedPointer<QBuffer> mInputBytes; // Holds the data set by setData()
     QList<QVersitDocument> mVersitDocuments;
@@ -228,6 +275,11 @@
     QVersitReader::Error mError;
     bool mIsCanceling;
     mutable QMutex mMutex;
+
+private:
+    /* key is the document type and property name, value is the type of property it is.
+       If there is no entry, assume it is a PlainType */
+    static QHash<QPair<QVersitDocument::VersitType,QString>, QVersitProperty::ValueType>* mValueTypeMap;
 };
 
 QTM_END_NAMESPACE