Aegisub/aegisub/libaegisub/common/cajun/writer.cpp
Thomas Goyne 07da6f6f1b Split json::Number into json::Double and json::Integer
Trying to decide whether an option should be an int or double after
discarding the differences between "1.0" and "1" simply isn't possible,
and even if an option was initialized correctly, if it was changed to a
round number it could get written as an int and break later.

Also convert cajun to tabs because three spaces to indent is terrible.

Originally committed to SVN as r6018.
2011-12-22 21:12:25 +00:00

132 lines
2.8 KiB
C++

/**********************************************
License: BSD
Project Webpage: http://cajun-jsonapi.sourceforge.net/
Author: Terry Caton
***********************************************/
#include "libaegisub/cajun/writer.h"
#ifndef LAGI_PRE
#include <cmath>
#include <iostream>
#include <iomanip>
#endif
/*
TODO:
* better documentation
* unicode character encoding
*/
namespace json
{
Writer::Writer(std::ostream& ostr)
: m_ostr(ostr)
, tab_depth(0)
{
}
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') << ']';
}
}
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') << '"' << it->first << "\" : ";
Write(it->second);
if (++it != itend)
m_ostr << ',';
m_ostr << std::endl;
}
--tab_depth;
m_ostr << std::string(tab_depth, '\t') << '}';
}
}
void Writer::Write(Double const& numberElement) {
m_ostr << std::setprecision(20) << numberElement;
double unused;
if (!std::modf(numberElement, &unused))
m_ostr << ".0";
}
void Writer::Write(Integer const& numberElement) {
m_ostr << numberElement;
}
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;
}
}
m_ostr << '"';
}
void Writer::Write(Null const&) {
m_ostr << "null";
}
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