aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2018-07-27 23:54:15 -0400
committerLibravatarUnit 193 <unit193@ubuntu.com>2018-07-27 23:54:15 -0400
commit6d3d39356473078c6b47e03b8a7616e4b34de928 (patch)
treefe5be2e6a08e4cfc73207746aba4c9fccfecfa10 /SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp
parentf98e49169a40876bcf1df832de6e908d1b350193 (diff)
parentfeda8a7db8d1d7c5439aa8f8feef7cc0dd2b59a0 (diff)
Update upstream source from tag 'upstream/3.2.1+dfsg1'
Update to upstream version '3.2.1+dfsg1' with Debian dir 5ea0333565de4dc898c062cc0ff4ba1153e2c1e4
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp214
1 files changed, 116 insertions, 98 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp b/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp
index ce568e9..4c4ed0e 100644
--- a/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp
+++ b/SQLiteStudio3/coreSQLiteStudio/csvserializer.cpp
@@ -1,167 +1,193 @@
#include "csvserializer.h"
#include <QStringList>
+#include <QList>
+#include <QDebug>
+#include <QTime>
-// TODO write unit tests for CsvSerializer
+template <class C>
+bool isCsvSeparator(QList<C>& ahead, const C& theChar, const QStringList& separators)
+{
+ for (const QString& sep : separators)
+ if (isCsvSeparator(ahead, theChar, sep))
+ return true;
+
+ return false;
+}
template <class C>
-bool isCsvColumnSeparator(QTextStream& data, const C& theChar, const CsvFormat& format)
+bool isCsvSeparator(QList<C>& ahead, const C& theChar, const QString& singleSeparator)
+{
+ if (singleSeparator[0] != theChar)
+ return false;
+
+ typename QList<C>::const_iterator aheadIter = ahead.begin();
+ int singleSeparatorSize = singleSeparator.size();
+ int i = 1;
+ while (aheadIter != ahead.end() && i < singleSeparatorSize)
+ {
+ if (singleSeparator[i++] != *aheadIter++)
+ return false;
+ }
+
+ if (i < singleSeparatorSize)
+ return false;
+
+ for (int i = 1, total = singleSeparator.size(); i < total; ++i)
+ ahead.removeFirst();
+
+ return true;
+}
+
+template <class C>
+bool isCsvColumnSeparator(QList<C>& ahead, const C& theChar, const CsvFormat& format)
{
if (!format.strictColumnSeparator)
return format.columnSeparator.contains(theChar);
// Strict checking (characters in defined order make a separator)
- QStringList separators;
if (format.multipleColumnSeparators)
- separators = format.columnSeparators;
- else
- separators << format.columnSeparator;
+ return isCsvSeparator(ahead, theChar, format.columnSeparators);
- qint64 origPos = data.pos();
- bool match = true;
- for (const QString sep : separators)
- {
- match = true;
- data.seek(origPos - 1);
- C nextChar;
- for (const QChar& c : sep)
- {
- data >> nextChar;
- if (c != nextChar)
- {
- data.seek(origPos);
- match = false;
- break;
- }
- }
- if (match)
- break;
- }
-
- return match;
+ return isCsvSeparator(ahead, theChar, format.columnSeparator);
}
template <class C>
-bool isCsvRowSeparator(QTextStream& data, const C& theChar, const CsvFormat& format)
+bool isCsvRowSeparator(QList<C>& ahead, const C& theChar, const CsvFormat& format)
{
if (!format.strictRowSeparator)
return format.rowSeparator.contains(theChar);
// Strict checking (characters in defined order make a separator)
- QStringList separators;
if (format.multipleRowSeparators)
- separators = format.rowSeparators;
- else
- separators << format.rowSeparator;
+ return isCsvSeparator(ahead, theChar, format.rowSeparators);
+
+ return isCsvSeparator(ahead, theChar, format.rowSeparator);
+}
- qint64 origPos = data.pos();
- bool match = true;
- for (const QString sep : separators)
+template <class C>
+void readAhead(QTextStream& data, QList<C>& ahead, int desiredSize)
+{
+ C singleValue;
+ while (!data.atEnd() && ahead.size() < desiredSize)
{
- match = true;
- data.seek(origPos - 1);
- C nextChar;
- for (const QChar& c : sep)
- {
- data >> nextChar;
- if (data.atEnd() || c != nextChar)
- {
- data.seek(origPos);
- match = false;
- break;
- }
- }
- if (match)
- break;
+ data >> singleValue;
+ ahead << singleValue;
}
-
- return match;
}
template <class T, class C>
-QList<QList<T>> typedDeserialize(QTextStream& data, const CsvFormat& format, bool oneEntry)
+void typedDeserializeInternal(QTextStream& data, const CsvFormat& format, QList<T>* cells, QList<QList<T>>* rows)
{
- QList<QList<T>> rows;
- QList<T> cells;
-
bool quotes = false;
bool sepAsLast = false;
+ int separatorMaxAhead = qMax(format.maxColumnSeparatorLength, format.maxRowSeparatorLength) - 1;
T field = "";
- C c0;
- C c1;
+ field.reserve(3);
+ C theChar;
+ QList<C> ahead;
- while (!data.atEnd())
+ while (!data.atEnd() || !ahead.isEmpty())
{
- data >> c0;
+ if (!ahead.isEmpty())
+ theChar = ahead.takeFirst();
+ else
+ data >> theChar;
+
sepAsLast = false;
- if (!quotes && c0 == '"' )
+ if (!quotes && theChar == '"' )
{
quotes = true;
}
- else if (quotes && c0 == '"' )
+ else if (quotes && theChar == '"' )
{
if (!data.atEnd())
{
- data >> c1;
- if (c1 == '"' )
+ readAhead(data, ahead, 1);
+ if (ahead.isEmpty())
+ {
+ field += theChar;
+ }
+ else if (ahead.first() == '"' )
{
- field += c0;
+ field += theChar;
+ ahead.removeFirst();
}
else
{
quotes = false;
- data.seek(data.pos() - 1);
}
}
else
{
if (field.length() == 0)
- cells << field;
+ *cells << field;
quotes = false;
}
}
else if (!quotes)
{
- if (isCsvColumnSeparator(data, c0, format))
+ readAhead(data, ahead, separatorMaxAhead);
+ if (isCsvColumnSeparator(ahead, theChar, format))
{
- cells << field;
- field = "";
+ *cells << field;
+ field.truncate(0);
sepAsLast = true;
}
- else if (isCsvRowSeparator(data, c0, format))
+ else if (isCsvRowSeparator(ahead, theChar, format))
{
- cells << field;
- rows << cells;
- cells.clear();
- field = "";
- if (oneEntry)
+ *cells << field;
+ field.truncate(0);
+ if (rows)
+ {
+ *rows << *cells;
+ cells->clear();
+ }
+ else
+ {
break;
+ }
}
else
{
- field += c0;
+ field += theChar;
}
}
else
{
- field += c0;
+ field += theChar;
}
}
if (field.size() > 0 || sepAsLast)
- cells << field;
+ *cells << field;
- if (cells.size() > 0)
- rows << cells;
+ if (rows && cells->size() > 0)
+ *rows << *cells;
+}
+template <class T, class C>
+QList<QList<T>> typedDeserialize(QTextStream& data, const CsvFormat& format)
+{
+ QList<QList<T>> rows;
+ QList<T> cells;
+ typedDeserializeInternal<T, C>(data, format, &cells, &rows);
return rows;
}
+template <class T, class C>
+QList<T> typedDeserializeOneEntry(QTextStream& data, const CsvFormat& format)
+{
+ QList<T> cells;
+ typedDeserializeInternal<T, C>(data, format, &cells, nullptr);
+ return cells;
+}
+
QString CsvSerializer::serialize(const QList<QStringList>& data, const CsvFormat& format)
{
QStringList outputRows;
- foreach (const QStringList& dataRow, data)
+ for (const QStringList& dataRow : data)
outputRows << serialize(dataRow, format);
return outputRows.join(format.rowSeparator);
@@ -172,7 +198,7 @@ QString CsvSerializer::serialize(const QStringList& data, const CsvFormat& forma
QString value;
bool hasQuote;
QStringList outputCells;
- foreach (const QString& rowValue, data)
+ for (const QString& rowValue : data)
{
value = rowValue;
@@ -191,27 +217,19 @@ QString CsvSerializer::serialize(const QStringList& data, const CsvFormat& forma
QStringList CsvSerializer::deserializeOneEntry(QTextStream& data, const CsvFormat& format)
{
- QList<QStringList> deserialized = CsvSerializer::deserialize(data, format, true);
- if (deserialized.size() > 0)
- return deserialized.first();
-
- return QStringList();
-}
-
-QList<QStringList> CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format)
-{
- return CsvSerializer::deserialize(data, format, false);
+ QList<QString> deserialized = typedDeserializeOneEntry<QString, QChar>(data, format);
+ return QStringList(deserialized);
}
QList<QList<QByteArray>> CsvSerializer::deserialize(const QByteArray& data, const CsvFormat& format)
{
QTextStream stream(data, QIODevice::ReadWrite);
- return typedDeserialize<QByteArray,char>(stream, format, false);
+ return typedDeserialize<QByteArray,char>(stream, format);
}
-QList<QStringList> CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format, bool oneEntry)
+QList<QStringList> CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format)
{
- QList<QList<QString>> deserialized = typedDeserialize<QString, QChar>(data, format, oneEntry);
+ QList<QList<QString>> deserialized = typedDeserialize<QString, QChar>(data, format);
QList<QStringList> finalList;
for (const QList<QString>& resPart : deserialized)
@@ -224,6 +242,6 @@ QList<QStringList> CsvSerializer::deserialize(const QString& data, const CsvForm
{
QString dataString = data;
QTextStream stream(&dataString, QIODevice::ReadWrite);
- return deserialize(stream, format, false);
+ return deserialize(stream, format);
}