#include "csvserializer.h" #include #include #include #include template bool isCsvSeparator(QList& ahead, const C& theChar, const QStringList& separators) { for (const QString& sep : separators) if (isCsvSeparator(ahead, theChar, sep)) return true; return false; } template bool isCsvSeparator(QList& ahead, const C& theChar, const QString& singleSeparator) { if (singleSeparator[0] != theChar) return false; typename QList::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 bool isCsvColumnSeparator(QList& ahead, const C& theChar, const CsvFormat& format) { if (!format.strictColumnSeparator) return format.columnSeparator.contains(theChar); // Strict checking (characters in defined order make a separator) if (format.multipleColumnSeparators) return isCsvSeparator(ahead, theChar, format.columnSeparators); return isCsvSeparator(ahead, theChar, format.columnSeparator); } template bool isCsvRowSeparator(QList& ahead, const C& theChar, const CsvFormat& format) { if (!format.strictRowSeparator) return format.rowSeparator.contains(theChar); // Strict checking (characters in defined order make a separator) if (format.multipleRowSeparators) return isCsvSeparator(ahead, theChar, format.rowSeparators); return isCsvSeparator(ahead, theChar, format.rowSeparator); } template void readAhead(QTextStream& data, QList& ahead, int desiredSize) { C singleValue; while (!data.atEnd() && ahead.size() < desiredSize) { data >> singleValue; ahead << singleValue; } } template void typedDeserializeInternal(QTextStream& data, const CsvFormat& format, QList* cells, QList>* rows) { bool quotes = false; bool sepAsLast = false; int separatorMaxAhead = qMax(format.maxColumnSeparatorLength, format.maxRowSeparatorLength) - 1; T field = ""; field.reserve(3); C theChar; QList ahead; while (!data.atEnd() || !ahead.isEmpty()) { if (!ahead.isEmpty()) theChar = ahead.takeFirst(); else data >> theChar; sepAsLast = false; if (!quotes && theChar == '"' ) { quotes = true; } else if (quotes && theChar == '"' ) { if (!data.atEnd()) { readAhead(data, ahead, 1); if (ahead.isEmpty()) { field += theChar; } else if (ahead.first() == '"' ) { field += theChar; ahead.removeFirst(); } else { quotes = false; } } else { if (field.length() == 0) *cells << field; quotes = false; } } else if (!quotes) { readAhead(data, ahead, separatorMaxAhead); if (isCsvColumnSeparator(ahead, theChar, format)) { *cells << field; field.truncate(0); sepAsLast = true; } else if (isCsvRowSeparator(ahead, theChar, format)) { *cells << field; field.truncate(0); if (rows) { *rows << *cells; cells->clear(); } else { break; } } else { field += theChar; } } else { field += theChar; } } if (field.size() > 0 || sepAsLast) *cells << field; if (rows && cells->size() > 0) *rows << *cells; } template QList> typedDeserialize(QTextStream& data, const CsvFormat& format) { QList> rows; QList cells; typedDeserializeInternal(data, format, &cells, &rows); return rows; } template QList typedDeserializeOneEntry(QTextStream& data, const CsvFormat& format) { QList cells; typedDeserializeInternal(data, format, &cells, nullptr); return cells; } QString CsvSerializer::serialize(const QList& data, const CsvFormat& format) { QStringList outputRows; for (const QStringList& dataRow : data) outputRows << serialize(dataRow, format); return outputRows.join(format.rowSeparator); } QString CsvSerializer::serialize(const QStringList& data, const CsvFormat& format) { QString value; bool hasQuote; QStringList outputCells; for (const QString& rowValue : data) { value = rowValue; hasQuote = value.contains("\""); if (hasQuote) value.replace("\"", "\"\""); if (hasQuote || value.contains(format.columnSeparator) || value.contains(format.rowSeparator)) value = "\""+value+"\""; outputCells << value; } return outputCells.join(format.columnSeparator); } QStringList CsvSerializer::deserializeOneEntry(QTextStream& data, const CsvFormat& format) { QList deserialized = typedDeserializeOneEntry(data, format); return QStringList(deserialized); } QList> CsvSerializer::deserialize(const QByteArray& data, const CsvFormat& format) { QTextStream stream(data, QIODevice::ReadWrite); return typedDeserialize(stream, format); } QList CsvSerializer::deserialize(QTextStream& data, const CsvFormat& format) { QList> deserialized = typedDeserialize(data, format); QList finalList; for (const QList& resPart : deserialized) finalList << QStringList(resPart); return finalList; } QList CsvSerializer::deserialize(const QString& data, const CsvFormat& format) { QString dataString = data; QTextStream stream(&dataString, QIODevice::ReadWrite); return deserialize(stream, format); }