Make sure gdt values are escaped

This commit is contained in:
Jan 2021-03-06 14:13:46 +01:00
parent ea7b1eadae
commit 603994ce61
4 changed files with 120 additions and 5 deletions

View File

@ -63,9 +63,36 @@ bool GdtReader::ReadStringContent(std::string& str)
}
auto c = m_stream.get();
while (c != '"' && c != '\n' && c != EOF)
auto escaped = false;
while ((escaped || c != '"' && c != '\n') && c != EOF)
{
if (escaped)
{
switch (c)
{
case '\n':
case 'n':
ss << '\n';
break;
case 'r':
ss << '\r';
break;
default:
ss << static_cast<char>(c);
break;
}
escaped = false;
}
else if(c == '\\')
{
escaped = true;
}
else
{
ss << static_cast<char>(c);
}
c = m_stream.get();
}
@ -267,6 +294,55 @@ void GdtOutputStream::WriteVersion(const GdtVersion& gdtVersion)
WriteEntry(versionEntry);
}
void GdtOutputStream::WriteEscaped(const std::string& str) const
{
auto wroteBefore = false;
for(auto i = 0u; i < str.size(); i++)
{
auto needsEscape = false;
auto c = str[i];
switch(c)
{
case '\r':
needsEscape = true;
c = 'r';
break;
case '\n':
needsEscape = true;
c = 'n';
break;
case '\\':
needsEscape = true;
break;
default:
break;
}
if(needsEscape)
{
if(!wroteBefore)
{
wroteBefore = true;
m_stream << std::string(str, 0, i);
}
m_stream << '\\' << c;
}
else if(wroteBefore)
{
m_stream << c;
}
}
if(!wroteBefore)
{
m_stream << str;
}
}
void GdtOutputStream::WriteEntry(const GdtEntry& entry)
{
DoIntendation();
@ -283,7 +359,9 @@ void GdtOutputStream::WriteEntry(const GdtEntry& entry)
for (const auto& [propertyKey, propertyValue] : entry.m_properties)
{
DoIntendation();
m_stream << "\"" << propertyKey << "\" \"" << propertyValue << "\"\n";
m_stream << "\"" << propertyKey << "\" \"";
WriteEscaped(propertyValue);
m_stream << "\"\n";
}
m_intendation_level--;

View File

@ -36,6 +36,7 @@ public:
void BeginStream();
void WriteVersion(const GdtVersion& gdtVersion);
void WriteEscaped(const std::string& str) const;
void WriteEntry(const GdtEntry& entry);
void EndStream();

View File

@ -4,8 +4,7 @@
#include <string>
#include <vector>
#include "Obj/GDT/GdtEntry.h"
#include "Obj/Gdt/GdtEntry.h"
#include "Zone/ZoneTypes.h"
class InfoString

View File

@ -300,4 +300,41 @@ namespace obj::gdt
REQUIRE(entry.m_properties.at("idk") == "whattotypeanymore");
}
}
TEST_CASE("Gdt: Ensure can write gdt with escape values and parse it again", "[gdt]")
{
Gdt gdt;
gdt.m_version.m_game = "whatagame";
gdt.m_version.m_version = 6969;
{
auto entry = std::make_unique<GdtEntry>("sickentry", "verycool.gdf");
entry->m_properties["hello"] = "very\nkewl\\stuff";
gdt.m_entries.emplace_back(std::move(entry));
}
std::stringstream ss;
GdtOutputStream::WriteGdt(gdt, ss);
std::cout << ss.str();
Gdt gdt2;
GdtReader reader(ss);
REQUIRE(reader.Read(gdt2));
REQUIRE(gdt2.m_version.m_game == "whatagame");
REQUIRE(gdt2.m_version.m_version == 6969);
REQUIRE(gdt2.m_entries.size() == 1);
{
const auto& entry = *gdt2.m_entries[0];
REQUIRE(entry.m_name == "sickentry");
REQUIRE(entry.m_gdf_name == "verycool.gdf");
REQUIRE(entry.m_parent == nullptr);
REQUIRE(entry.m_properties.size() == 1);
REQUIRE(entry.m_properties.at("hello") == "very\nkewl\\stuff");
}
}
}