From 88b5eefe24b91ddee125759339513b6de2d49ab0 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 11 Mar 2021 12:43:33 +0100 Subject: [PATCH] Create CsvStream class to replace CsvWriter --- src/ObjCommon/Csv/CsvStream.cpp | 115 ++++++++++++++++++ src/ObjCommon/Csv/CsvStream.h | 28 +++++ src/ObjWriting/Dumping/CsvWriter.cpp | 74 ----------- src/ObjWriting/Dumping/CsvWriter.h | 20 --- .../AssetDumpers/AssetDumperStringTable.cpp | 4 +- .../T6/AssetDumpers/AssetDumperFontIcon.cpp | 4 +- .../AssetDumpers/AssetDumperStringTable.cpp | 4 +- 7 files changed, 149 insertions(+), 100 deletions(-) create mode 100644 src/ObjCommon/Csv/CsvStream.cpp create mode 100644 src/ObjCommon/Csv/CsvStream.h delete mode 100644 src/ObjWriting/Dumping/CsvWriter.cpp delete mode 100644 src/ObjWriting/Dumping/CsvWriter.h diff --git a/src/ObjCommon/Csv/CsvStream.cpp b/src/ObjCommon/Csv/CsvStream.cpp new file mode 100644 index 00000000..1f0ce46b --- /dev/null +++ b/src/ObjCommon/Csv/CsvStream.cpp @@ -0,0 +1,115 @@ +#include "CsvStream.h" + +#include + +constexpr char CSV_SEPARATOR = ','; + +CsvInputStream::CsvInputStream(std::istream& stream) + : m_stream(stream) +{ +} + +bool CsvInputStream::NextRow(std::vector& out) const +{ + if (!out.empty()) + out.clear(); + + auto c = m_stream.get(); + const auto isEof = c == EOF; + std::ostringstream col; + while(c != EOF) + { + if(c == CSV_SEPARATOR) + { + out.emplace_back(col.str()); + col.clear(); + col.str(std::string()); + } + else + { + col << c; + } + + c = m_stream.get(); + } + + if(!isEof) + { + const auto lastEntry = col.str(); + + if(!lastEntry.empty()) + out.emplace_back(col.str()); + } + + return !isEof; +} + +CsvOutputStream::CsvOutputStream(std::ostream& stream) + : m_stream(stream), + m_column_count(0), + m_current_column(0), + m_first_row(true) +{ +} + +void CsvOutputStream::WriteColumn(const std::string& value) +{ + if (m_current_column++ > 0) + m_stream << CSV_SEPARATOR; + + auto containsSeparator = false; + auto containsQuote = false; + for (const auto& c : value) + { + if (c == '"') + { + containsQuote = true; + break; + } + + if (c == CSV_SEPARATOR) + containsSeparator = true; + } + + if (containsQuote) + { + m_stream << "\""; + for (const auto& c : value) + { + if (c == '"') + m_stream << "\"\""; + else + m_stream << c; + } + + m_stream << "\""; + } + else if (containsSeparator) + { + m_stream << "\"" << value << "\""; + } + else + { + m_stream << value; + } +} + +void CsvOutputStream::NextRow() +{ + if (m_first_row) + { + m_first_row = false; + m_column_count = m_current_column; + } + else + { + while (m_current_column < m_column_count) + { + m_stream << CSV_SEPARATOR; + m_current_column++; + } + } + + m_stream << "\n"; + m_current_column = 0; +} diff --git a/src/ObjCommon/Csv/CsvStream.h b/src/ObjCommon/Csv/CsvStream.h new file mode 100644 index 00000000..1e039d2e --- /dev/null +++ b/src/ObjCommon/Csv/CsvStream.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include + +class CsvInputStream +{ + std::istream& m_stream; + +public: + explicit CsvInputStream(std::istream& stream); + + bool NextRow(std::vector& out) const; +}; + +class CsvOutputStream +{ + std::ostream& m_stream; + unsigned m_column_count; + unsigned m_current_column; + bool m_first_row; + +public: + explicit CsvOutputStream(std::ostream& stream); + + void WriteColumn(const std::string& value); + void NextRow(); +}; \ No newline at end of file diff --git a/src/ObjWriting/Dumping/CsvWriter.cpp b/src/ObjWriting/Dumping/CsvWriter.cpp deleted file mode 100644 index 51909685..00000000 --- a/src/ObjWriting/Dumping/CsvWriter.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "CsvWriter.h" - -#include - -CsvWriter::CsvWriter(std::ostream& stream) - : m_stream(stream), - m_column_count(0), - m_current_column(0), - m_first_row(true) -{ -} - -void CsvWriter::WriteColumn(const std::string& value) -{ - if (m_current_column++ > 0) - m_stream << ","; - - auto containsSeparator = false; - auto containsQuote = false; - for (const auto& c : value) - { - if (c == '"') - { - containsQuote = true; - break; - } - - if (c == SEPARATOR) - containsSeparator = true; - } - - if (containsQuote) - { - std::ostringstream str; - - for (const auto& c : value) - { - if (c == '"') - str << "\"\""; - else - str << c; - } - - m_stream << "\"" << str.str() << "\""; - } - else if (containsSeparator) - { - m_stream << "\"" << value << "\""; - } - else - { - m_stream << value; - } -} - -void CsvWriter::NextRow() -{ - if (m_first_row) - { - m_first_row = false; - m_column_count = m_current_column; - } - else - { - while (m_current_column < m_column_count) - { - m_stream << ","; - m_current_column++; - } - } - - m_stream << "\n"; - m_current_column = 0; -} diff --git a/src/ObjWriting/Dumping/CsvWriter.h b/src/ObjWriting/Dumping/CsvWriter.h deleted file mode 100644 index 0181f2f5..00000000 --- a/src/ObjWriting/Dumping/CsvWriter.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include -#include - -class CsvWriter -{ - static constexpr char SEPARATOR = ','; - - std::ostream& m_stream; - unsigned m_column_count; - unsigned m_current_column; - bool m_first_row; - -public: - explicit CsvWriter(std::ostream& stream); - - void WriteColumn(const std::string& value); - void NextRow(); -}; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStringTable.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStringTable.cpp index a54cf77a..a81504a9 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStringTable.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStringTable.cpp @@ -1,6 +1,6 @@ #include "AssetDumperStringTable.h" -#include "Dumping/CsvWriter.h" +#include "Csv/CsvStream.h" using namespace IW4; @@ -22,7 +22,7 @@ std::string AssetDumperStringTable::GetFileNameForAsset(Zone* zone, XAssetInfo* asset, std::ostream& stream) { const auto* stringTable = asset->Asset(); - CsvWriter csv(stream); + CsvOutputStream csv(stream); for (auto row = 0; row < stringTable->rowCount; row++) { diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp index 2e126213..ea7ef376 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp @@ -1,6 +1,6 @@ #include "AssetDumperFontIcon.h" -#include "Dumping/CsvWriter.h" +#include "Csv/CsvStream.h" #include "Game/T6/CommonT6.h" #include @@ -141,7 +141,7 @@ class AssetDumperFontIconInternal KnownAlias("Remote_LStick") }; - CsvWriter m_csv; + CsvOutputStream m_csv; static FontIconEntry* FindEntryByHash(FontIcon* fontIcon, const int hash) { diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperStringTable.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperStringTable.cpp index ee1378c6..34aa9e7f 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperStringTable.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperStringTable.cpp @@ -1,6 +1,6 @@ #include "AssetDumperStringTable.h" -#include "Dumping/CsvWriter.h" +#include "Csv/CsvStream.h" using namespace T6; @@ -22,7 +22,7 @@ std::string AssetDumperStringTable::GetFileNameForAsset(Zone* zone, XAssetInfo* asset, std::ostream& stream) { const auto* stringTable = asset->Asset(); - CsvWriter csv(stream); + CsvOutputStream csv(stream); for(auto row = 0; row < stringTable->rowCount; row++) {