diff --git a/libaegisub/common/cajun/elements.cpp b/libaegisub/common/cajun/elements.cpp index c38b08317..44103655a 100644 --- a/libaegisub/common/cajun/elements.cpp +++ b/libaegisub/common/cajun/elements.cpp @@ -24,10 +24,10 @@ namespace { void Visit(Null&) { is_null = true; } void Visit(Array const&) { } void Visit(Object const&) { } - void Visit(Integer const&) { } - void Visit(Double const&) { } + void Visit(Integer) { } + void Visit(Double) { } void Visit(String const&) { } - void Visit(Boolean const&) { } + void Visit(Boolean) { } void Visit(Null const&) { is_null = true; } public: bool is_null = false; diff --git a/libaegisub/common/cajun/writer.cpp b/libaegisub/common/cajun/writer.cpp index b2724f64b..6f337d44e 100644 --- a/libaegisub/common/cajun/writer.cpp +++ b/libaegisub/common/cajun/writer.cpp @@ -1,125 +1,100 @@ -/********************************************** - -License: BSD -Project Webpage: http://cajun-jsonapi.sourceforge.net/ -Author: Terry Caton - -***********************************************/ +// Copyright (c) 2014, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ #include "libaegisub/cajun/writer.h" #include #include -/* - -TODO: -* better documentation -* unicode character encoding - -*/ - -namespace json { - -Writer::Writer(std::ostream& ostr) : m_ostr(ostr) { } - -void Writer::Write(Array const& array) { - if (array.empty()) - m_ostr << "[]"; - else { - m_ostr << '[' << std::endl; - ++tab_depth; - - Array::const_iterator it(array.begin()), itend(array.end()); - while (it != itend) { - m_ostr << std::string(tab_depth, '\t'); - - Write(*it); - - if (++it != itend) - m_ostr << ','; - m_ostr << std::endl; - } - - --tab_depth; - m_ostr << std::string(tab_depth, '\t') << ']'; +namespace agi { +void JsonWriter::Visit(json::Array const& array) { + if (array.empty()) { + ostr << "[]"; + return; } + + indent += '\t'; + ostr << "[\n"; + + bool first = true; + for (auto const& entry : array) { + if (!first) ostr << ",\n"; + first = false; + + ostr << indent; + Visit(entry); + } + + indent.pop_back(); + ostr << '\n' << indent << ']'; } -void Writer::Write(Object const& object) { - if (object.empty()) - m_ostr << "{}"; - else { - m_ostr << '{' << std::endl; - ++tab_depth; - - Object::const_iterator it(object.begin()), itend(object.end()); - while (it != itend) { - m_ostr << std::string(tab_depth, '\t'); - Write(it->first); - m_ostr << " : "; - Write(it->second); - - if (++it != itend) - m_ostr << ','; - m_ostr << std::endl; - } - - --tab_depth; - m_ostr << std::string(tab_depth, '\t') << '}'; +void JsonWriter::Visit(json::Object const& object) { + if (object.empty()) { + ostr << "{}"; + return; } + + indent += '\t'; + ostr << "{\n"; + + bool first = true; + for (auto const& entry : object) { + if (!first) ostr << ",\n"; + first = false; + + ostr << indent; + Visit(entry.first); + ostr << " : "; + Visit(entry.second); + } + + indent.pop_back(); + ostr << '\n' << indent << '}'; } -void Writer::Write(Double const& numberElement) { - m_ostr << std::setprecision(20) << numberElement; +void JsonWriter::Visit(double d) { + ostr << std::setprecision(20) << d; double unused; - if (!std::modf(numberElement, &unused)) - m_ostr << ".0"; + if (!std::modf(d, &unused)) + ostr << ".0"; } -void Writer::Write(Integer const& numberElement) { - m_ostr << numberElement; -} +void JsonWriter::Visit(std::string const& str) { + ostr << '"'; -void Writer::Write(Boolean const& booleanElement) { - m_ostr << (booleanElement ? "true" : "false"); -} - -void Writer::Write(String const& stringElement) { - m_ostr << '"'; - - std::string::const_iterator it(stringElement.begin()), itend(stringElement.end()); - for (; it != itend; ++it) { - switch (*it) { - case '"': m_ostr << "\\\""; break; - case '\\': m_ostr << "\\\\"; break; - case '\b': m_ostr << "\\b"; break; - case '\f': m_ostr << "\\f"; break; - case '\n': m_ostr << "\\n"; break; - case '\r': m_ostr << "\\r"; break; - case '\t': m_ostr << "\\t"; break; - default: m_ostr << *it; break; + for (auto c : str) { + switch (c) { + case '"': ostr << "\\\""; break; + case '\\': ostr << "\\\\"; break; + case '\b': ostr << "\\b"; break; + case '\f': ostr << "\\f"; break; + case '\n': ostr << "\\n"; break; + case '\r': ostr << "\\r"; break; + case '\t': ostr << "\\t"; break; + default: ostr << c; break; } } - m_ostr << '"'; + ostr << '"'; } -void Writer::Write(Null const&) { - m_ostr << "null"; +void JsonWriter::Visit(int64_t i) { ostr << i; } +void JsonWriter::Visit(bool b) { ostr << (b ? "true" : "false"); } +void JsonWriter::Visit(json::Null const&) { ostr << "null"; } +void JsonWriter::Visit(json::UnknownElement const& unknown) { unknown.Accept(*this); } } - -void Writer::Write(UnknownElement const& unknown) { - unknown.Accept(*this); -} - -void Writer::Visit(Array const& array) { Write(array); } -void Writer::Visit(Object const& object) { Write(object); } -void Writer::Visit(Integer const& integer) { Write(integer); } -void Writer::Visit(Double const& dbl) { Write(dbl); } -void Writer::Visit(String const& string) { Write(string); } -void Writer::Visit(Boolean const& boolean) { Write(boolean); } -void Writer::Visit(Null const& null) { Write(null); } - -} // end namespace diff --git a/libaegisub/common/hotkey.cpp b/libaegisub/common/hotkey.cpp index abe6cc346..538beb1bf 100644 --- a/libaegisub/common/hotkey.cpp +++ b/libaegisub/common/hotkey.cpp @@ -162,7 +162,7 @@ void Hotkey::Flush() { } io::Save file(config_file); - json::Writer::Write(root, file.Get()); + agi::JsonWriter::Write(root, file.Get()); } void Hotkey::SetHotkeyMap(HotkeyMap const& new_map) { diff --git a/libaegisub/common/log.cpp b/libaegisub/common/log.cpp index 2179a9fce..575033021 100644 --- a/libaegisub/common/log.cpp +++ b/libaegisub/common/log.cpp @@ -113,7 +113,7 @@ void JsonEmitter::log(SinkMessage const& sm) { entry["func"] = sm.func; entry["line"] = sm.line; entry["message"] = sm.message; - json::Writer::Write(entry, *fp); + agi::JsonWriter::Write(entry, *fp); fp->flush(); } diff --git a/libaegisub/common/mru.cpp b/libaegisub/common/mru.cpp index 42176f727..1d589f388 100644 --- a/libaegisub/common/mru.cpp +++ b/libaegisub/common/mru.cpp @@ -89,11 +89,11 @@ void MRUManager::Flush() { for (auto const& mru_map : mru) { json::Array &array = out[mru_map.first]; - transform(begin(mru_map.second), end(mru_map.second), - back_inserter(array), [](agi::fs::path const& p) { return p.string(); }); + for (auto const& p : mru_map.second) + array.push_back(p.string()); } - json::Writer::Write(out, io::Save(config_name).Get()); + agi::JsonWriter::Write(out, io::Save(config_name).Get()); } void MRUManager::Prune(std::string const& key, MRUListMap& map) const { diff --git a/libaegisub/common/option.cpp b/libaegisub/common/option.cpp index 71a496e1c..43689fac4 100644 --- a/libaegisub/common/option.cpp +++ b/libaegisub/common/option.cpp @@ -106,11 +106,11 @@ class ConfigVisitor final : public json::ConstVisitor { Error("Array type not handled"); } - void Visit(const json::Integer& number) { + void Visit(int64_t number) { values.push_back(agi::make_unique(name, number)); } - void Visit(const json::Double& number) { + void Visit(double number) { values.push_back(agi::make_unique(name, number)); } @@ -127,7 +127,7 @@ class ConfigVisitor final : public json::ConstVisitor { } } - void Visit(const json::Boolean& boolean) { + void Visit(bool boolean) { values.push_back(agi::make_unique(name, boolean)); } @@ -316,7 +316,7 @@ void Options::Flush() const { } } - json::Writer::Write(obj_out, io::Save(config_file).Get()); + agi::JsonWriter::Write(obj_out, io::Save(config_file).Get()); } } // namespace agi diff --git a/libaegisub/include/libaegisub/cajun/visitor.h b/libaegisub/include/libaegisub/cajun/visitor.h index b4b270ea1..ac91a9a08 100644 --- a/libaegisub/include/libaegisub/cajun/visitor.h +++ b/libaegisub/include/libaegisub/cajun/visitor.h @@ -30,10 +30,10 @@ struct ConstVisitor { virtual void Visit(const Array& array) = 0; virtual void Visit(const Object& object) = 0; - virtual void Visit(const Integer& number) = 0; - virtual void Visit(const Double& number) = 0; + virtual void Visit(int64_t number) = 0; + virtual void Visit(double number) = 0; virtual void Visit(const String& string) = 0; - virtual void Visit(const Boolean& boolean) = 0; + virtual void Visit(bool boolean) = 0; virtual void Visit(const Null& null) = 0; }; diff --git a/libaegisub/include/libaegisub/cajun/writer.h b/libaegisub/include/libaegisub/cajun/writer.h index 27dc4b1e4..9b2bac23e 100644 --- a/libaegisub/include/libaegisub/cajun/writer.h +++ b/libaegisub/include/libaegisub/cajun/writer.h @@ -1,54 +1,47 @@ -/********************************************** +// Copyright (c) 2014, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ -License: BSD -Project Webpage: http://cajun-jsonapi.sourceforge.net/ -Author: Terry Caton - -***********************************************/ - -#pragma once - -#include "elements.h" #include "visitor.h" #include +#include -namespace json { +namespace agi { -class Writer final : private ConstVisitor { - Writer(std::ostream& ostr); - void Write(const Object& object); - void Write(const Array& array); - void Write(const String& string); - void Write(const Integer& number); - void Write(const Double& number); - void Write(const Boolean& boolean); - void Write(const Null& null); - void Write(const UnknownElement& unknown); +class JsonWriter final : json::ConstVisitor { + std::ostream &ostr; + std::string indent; - void Visit(const Array& array) override; - void Visit(const Object& object) override; - void Visit(const Integer& number) override; - void Visit(const Double& number) override; - void Visit(const String& string) override; - void Visit(const Boolean& boolean) override; - void Visit(const Null& null) override; + JsonWriter(std::ostream &ostr) : ostr(ostr) { } - std::ostream& m_ostr; - int tab_depth = 0; + void Visit(json::Array const& array) override; + void Visit(bool boolean) override; + void Visit(double number) override; + void Visit(int64_t number) override; + void Visit(json::Null const& null) override; + void Visit(json::Object const& object) override; + void Visit(std::string const& string) override; + void Visit(json::UnknownElement const& unknown); public: - template - static void Write(const ElementTypeT& element, std::ostream& ostr) { - Writer writer(ostr); - writer.Write(element); - ostr.flush(); // all done + template + static void Write(T const& value, std::ostream& ostr) { + JsonWriter(ostr).Visit(value); + ostr.flush(); } }; -inline std::ostream& operator <<(std::ostream& ostr, UnknownElement const& elementRoot) { - Writer::Write(elementRoot, ostr); - return ostr; } - -} // End namespace diff --git a/src/dialog_shift_times.cpp b/src/dialog_shift_times.cpp index c6ade8b1f..8d7f00799 100644 --- a/src/dialog_shift_times.cpp +++ b/src/dialog_shift_times.cpp @@ -321,7 +321,7 @@ void DialogShiftTimes::SaveHistory(json::Array const& shifted_blocks) { history.resize(50); try { - json::Writer::Write(history, agi::io::Save(history_filename).Get()); + agi::JsonWriter::Write(history, agi::io::Save(history_filename).Get()); } catch (agi::fs::FileSystemError const& e) { LOG_E("dialog_shift_times/save_history") << "Cannot save shift times history: " << e.GetMessage(); @@ -333,9 +333,8 @@ void DialogShiftTimes::LoadHistory() { history_box->Freeze(); try { - std::unique_ptr file(agi::io::Open(history_filename)); json::UnknownElement root; - json::Reader::Read(root, *file); + json::Reader::Read(root, *agi::io::Open(history_filename)); history = root; for (auto& history_entry : history) diff --git a/tests/tests/cajun.cpp b/tests/tests/cajun.cpp index d5e091498..b843cd8e9 100644 --- a/tests/tests/cajun.cpp +++ b/tests/tests/cajun.cpp @@ -281,27 +281,27 @@ TEST_F(lagi_cajun, Write) { obj["String"] = "This \"is\" \\a \t test"; std::stringstream stream; - EXPECT_NO_THROW(json::Writer::Write(obj, stream)); + EXPECT_NO_THROW(agi::JsonWriter::Write(obj, stream)); EXPECT_STREQ("{\n\t\"Boolean\" : true,\n\t\"String\" : \"This \\\"is\\\" \\\\a \\t test\"\n}", stream.str().c_str()); stream.str(""); - EXPECT_NO_THROW(json::Writer::Write(json::Array(), stream)); + EXPECT_NO_THROW(agi::JsonWriter::Write(json::Array(), stream)); EXPECT_STREQ("[]", stream.str().c_str()); stream.str(""); - EXPECT_NO_THROW(json::Writer::Write(json::Object(), stream)); + EXPECT_NO_THROW(agi::JsonWriter::Write(json::Object(), stream)); EXPECT_STREQ("{}", stream.str().c_str()); stream.str(""); - EXPECT_NO_THROW(json::Writer::Write(true, stream)); + EXPECT_NO_THROW(agi::JsonWriter::Write(true, stream)); EXPECT_STREQ("true", stream.str().c_str()); stream.str(""); - EXPECT_NO_THROW(json::Writer::Write(false, stream)); + EXPECT_NO_THROW(agi::JsonWriter::Write(false, stream)); EXPECT_STREQ("false", stream.str().c_str()); stream.str(""); - EXPECT_NO_THROW(json::Writer::Write(json::Null(), stream)); + EXPECT_NO_THROW(agi::JsonWriter::Write(json::Null(), stream)); EXPECT_STREQ("null", stream.str().c_str()); } @@ -355,7 +355,7 @@ std::string roundtrip_test(const char *in) { json::Reader::Read(ele, iss); std::stringstream oss; - json::Writer::Write(ele, oss); + agi::JsonWriter::Write(ele, oss); return oss.str(); }