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.
This commit is contained in:
Thomas Goyne 2011-12-22 21:12:25 +00:00
parent daff67b150
commit 07da6f6f1b
13 changed files with 658 additions and 739 deletions

View file

@ -20,13 +20,15 @@ namespace {
class CastVisitorBase : public Visitor, public ConstVisitor { class CastVisitorBase : public Visitor, public ConstVisitor {
void Visit(Array&) { } void Visit(Array&) { }
void Visit(Object&) { } void Visit(Object&) { }
void Visit(Number&) { } void Visit(Integer&) { }
void Visit(Double&) { }
void Visit(String&) { } void Visit(String&) { }
void Visit(Boolean&) { } void Visit(Boolean&) { }
void Visit(Null&) { is_null = true; } void Visit(Null&) { is_null = true; }
void Visit(Array const&) { } void Visit(Array const&) { }
void Visit(Object const&) { } void Visit(Object const&) { }
void Visit(Number const&) { } void Visit(Integer const&) { }
void Visit(Double const&) { }
void Visit(String const&) { } void Visit(String const&) { }
void Visit(Boolean const&) { } void Visit(Boolean const&) { }
void Visit(Null const&) { is_null = true; } void Visit(Null const&) { is_null = true; }
@ -86,9 +88,10 @@ UnknownElement::UnknownElement() : m_pImp( new Imp
UnknownElement::UnknownElement(const UnknownElement& unknown) : m_pImp( unknown.m_pImp->Clone()) {} UnknownElement::UnknownElement(const UnknownElement& unknown) : m_pImp( unknown.m_pImp->Clone()) {}
UnknownElement::UnknownElement(const Object& object) : m_pImp( new Imp_T<Object>(object) ) {} UnknownElement::UnknownElement(const Object& object) : m_pImp( new Imp_T<Object>(object) ) {}
UnknownElement::UnknownElement(const Array& array) : m_pImp( new Imp_T<Array>(array) ) {} UnknownElement::UnknownElement(const Array& array) : m_pImp( new Imp_T<Array>(array) ) {}
UnknownElement::UnknownElement(double number) : m_pImp( new Imp_T<Number>(number) ) {} UnknownElement::UnknownElement(double number) : m_pImp( new Imp_T<Double>(number) ) {}
UnknownElement::UnknownElement(int number) : m_pImp( new Imp_T<Number>(number) ) {} UnknownElement::UnknownElement(int number) : m_pImp( new Imp_T<Integer>(number) ) {}
UnknownElement::UnknownElement(long number) : m_pImp( new Imp_T<Number>(number) ) {} UnknownElement::UnknownElement(int64_t number) : m_pImp( new Imp_T<Integer>(number) ) {}
UnknownElement::UnknownElement(long number) : m_pImp( new Imp_T<Integer>(number) ) {}
UnknownElement::UnknownElement(bool boolean) : m_pImp( new Imp_T<Boolean>(boolean) ) {} UnknownElement::UnknownElement(bool boolean) : m_pImp( new Imp_T<Boolean>(boolean) ) {}
UnknownElement::UnknownElement(const char *string) : m_pImp( new Imp_T<String>(string) ) {} UnknownElement::UnknownElement(const char *string) : m_pImp( new Imp_T<String>(string) ) {}
UnknownElement::UnknownElement(const String& string) : m_pImp( new Imp_T<String>(string) ) {} UnknownElement::UnknownElement(const String& string) : m_pImp( new Imp_T<String>(string) ) {}
@ -98,14 +101,16 @@ UnknownElement::~UnknownElement() { delete m_pImp; }
UnknownElement::operator Object const&() const { return CastTo<Object>(); } UnknownElement::operator Object const&() const { return CastTo<Object>(); }
UnknownElement::operator Array const&() const { return CastTo<Array>(); } UnknownElement::operator Array const&() const { return CastTo<Array>(); }
UnknownElement::operator Number const&() const { return CastTo<Number>(); } UnknownElement::operator Integer const&() const { return CastTo<Integer>(); }
UnknownElement::operator Double const&() const { return CastTo<Double>(); }
UnknownElement::operator Boolean const&() const { return CastTo<Boolean>(); } UnknownElement::operator Boolean const&() const { return CastTo<Boolean>(); }
UnknownElement::operator String const&() const { return CastTo<String>(); } UnknownElement::operator String const&() const { return CastTo<String>(); }
UnknownElement::operator Null const&() const { return CastTo<Null>(); } UnknownElement::operator Null const&() const { return CastTo<Null>(); }
UnknownElement::operator Object&() { return CastTo<Object>(); } UnknownElement::operator Object&() { return CastTo<Object>(); }
UnknownElement::operator Array&() { return CastTo<Array>(); } UnknownElement::operator Array&() { return CastTo<Array>(); }
UnknownElement::operator Number&() { return CastTo<Number>(); } UnknownElement::operator Integer&() { return CastTo<Integer>(); }
UnknownElement::operator Double&() { return CastTo<Double>(); }
UnknownElement::operator Boolean&() { return CastTo<Boolean>(); } UnknownElement::operator Boolean&() { return CastTo<Boolean>(); }
UnknownElement::operator String&() { return CastTo<String>(); } UnknownElement::operator String&() { return CastTo<String>(); }
UnknownElement::operator Null&() { return CastTo<Null>(); } UnknownElement::operator Null&() { return CastTo<Null>(); }

View file

@ -22,27 +22,15 @@ TODO:
*/ */
namespace json namespace json {
{
std::istream& operator >> (std::istream& istr, UnknownElement& elementRoot) { std::istream& operator >> (std::istream& istr, UnknownElement& elementRoot) {
Reader::Read(elementRoot, istr); Reader::Read(elementRoot, istr);
return istr; return istr;
} }
Reader::Location::Location() : /// Wrapper around istream to keep track of document/line offsets
m_nLine(0), class Reader::InputStream {
m_nLineOffset(0),
m_nDocOffset(0)
{}
//////////////////////
// Reader::InputStream
// wrapper around istream to keep track of document/line offsets
class Reader::InputStream
{
std::istream& m_iStr; std::istream& m_iStr;
Location m_Location; Location m_Location;
public: public:
@ -63,6 +51,7 @@ public:
return c; return c;
} }
int Peek() { int Peek() {
assert(!m_iStr.eof()); assert(!m_iStr.eof());
return m_iStr.peek(); return m_iStr.peek();
@ -73,49 +62,40 @@ public:
return m_iStr.eof(); return m_iStr.eof();
} }
const Location& GetLocation() const { return m_Location; } Location const& GetLocation() const { return m_Location; }
}; };
////////////////////// class Reader::TokenStream {
// Reader::TokenStream Tokens const& m_Tokens;
class Reader::TokenStream
{
const Tokens& m_Tokens;
Tokens::const_iterator m_itCurrent; Tokens::const_iterator m_itCurrent;
public: public:
TokenStream(const Tokens& tokens) TokenStream(Tokens const& tokens) : m_Tokens(tokens), m_itCurrent(tokens.begin())
: m_Tokens(tokens), m_itCurrent(tokens.begin())
{ } { }
const Token& Peek() { Token const& Peek() {
assert(!EOS()); assert(!EOS());
return *m_itCurrent; return *m_itCurrent;
} }
const Token& Get() { Token const& Get() {
assert(!EOS()); assert(!EOS());
return *m_itCurrent++; return *m_itCurrent++;
} }
bool EOS() const { bool EOS() const { return m_itCurrent == m_Tokens.end(); }
return m_itCurrent == m_Tokens.end();
}
}; };
///////////////////
// Reader (finally)
void Reader::Read(Object& object, std::istream& istr) { Read_i(object, istr); } void Reader::Read(Object& object, std::istream& istr) { Read_i(object, istr); }
void Reader::Read(Array& array, std::istream& istr) { Read_i(array, istr); } void Reader::Read(Array& array, std::istream& istr) { Read_i(array, istr); }
void Reader::Read(String& string, std::istream& istr) { Read_i(string, istr); } void Reader::Read(String& string, std::istream& istr) { Read_i(string, istr); }
void Reader::Read(Number& number, std::istream& istr) { Read_i(number, istr); } void Reader::Read(Integer& number, std::istream& istr) { Read_i(number, istr); }
void Reader::Read(Double& number, std::istream& istr) { Read_i(number, istr); }
void Reader::Read(Boolean& boolean, std::istream& istr) { Read_i(boolean, istr); } void Reader::Read(Boolean& boolean, std::istream& istr) { Read_i(boolean, istr); }
void Reader::Read(Null& null, std::istream& istr) { Read_i(null, istr); } void Reader::Read(Null& null, std::istream& istr) { Read_i(null, istr); }
void Reader::Read(UnknownElement& unknown, std::istream& istr) { Read_i(unknown, istr); } void Reader::Read(UnknownElement& unknown, std::istream& istr) { Read_i(unknown, istr); }
template <typename ElementTypeT> template <typename ElementTypeT>
void Reader::Read_i(ElementTypeT& element, std::istream& istr) void Reader::Read_i(ElementTypeT& element, std::istream& istr) {
{
Reader reader; Reader reader;
Tokens tokens; Tokens tokens;
@ -125,17 +105,14 @@ void Reader::Read_i(ElementTypeT& element, std::istream& istr)
TokenStream tokenStream(tokens); TokenStream tokenStream(tokens);
element = reader.Parse(tokenStream); element = reader.Parse(tokenStream);
if (!tokenStream.EOS()) if (!tokenStream.EOS()) {
{ Token const& token = tokenStream.Peek();
const Token& token = tokenStream.Peek();
throw ParseException("Expected End of token stream; found " + token.sValue, token.locBegin, token.locEnd); throw ParseException("Expected End of token stream; found " + token.sValue, token.locBegin, token.locEnd);
} }
} }
void Reader::Scan(Tokens& tokens, InputStream& inputStream) void Reader::Scan(Tokens& tokens, InputStream& inputStream) {
{ while (EatWhiteSpace(inputStream), !inputStream.EOS()) {
while (EatWhiteSpace(inputStream), !inputStream.EOS())
{
// if all goes well, we'll create a token each pass // if all goes well, we'll create a token each pass
Token token; Token token;
token.locBegin = inputStream.GetLocation(); token.locBegin = inputStream.GetLocation();
@ -144,8 +121,7 @@ void Reader::Scan(Tokens& tokens, InputStream& inputStream)
std::string sChar; std::string sChar;
sChar.push_back(inputStream.Peek()); sChar.push_back(inputStream.Peek());
switch (sChar[0]) switch (sChar[0]) {
{
case '{': case '{':
token.sValue = sChar[0]; token.sValue = sChar[0];
MatchExpectedString(sChar, inputStream); MatchExpectedString(sChar, inputStream);
@ -230,16 +206,13 @@ void Reader::Scan(Tokens& tokens, InputStream& inputStream)
} }
void Reader::EatWhiteSpace(InputStream& inputStream) void Reader::EatWhiteSpace(InputStream& inputStream) {
{
while (!inputStream.EOS() && ::isspace(inputStream.Peek())) while (!inputStream.EOS() && ::isspace(inputStream.Peek()))
inputStream.Get(); inputStream.Get();
} }
void Reader::MatchExpectedString(const std::string& sExpected, InputStream& inputStream) void Reader::MatchExpectedString(std::string const& sExpected, InputStream& inputStream) {
{ std::string::const_iterator it(sExpected.begin()), itEnd(sExpected.end());
std::string::const_iterator it(sExpected.begin()),
itEnd(sExpected.end());
for ( ; it != itEnd; ++it) { for ( ; it != itEnd; ++it) {
if (inputStream.EOS() || // did we reach the end before finding what we're looking for... if (inputStream.EOS() || // did we reach the end before finding what we're looking for...
inputStream.Get() != *it) // ...or did we find something different? inputStream.Get() != *it) // ...or did we find something different?
@ -247,24 +220,16 @@ void Reader::MatchExpectedString(const std::string& sExpected, InputStream& inpu
throw ScanException("Expected string: " + sExpected, inputStream.GetLocation()); throw ScanException("Expected string: " + sExpected, inputStream.GetLocation());
} }
} }
// all's well if we made it here, return quietly
} }
void Reader::MatchString(std::string& string, InputStream& inputStream) {
void Reader::MatchString(std::string& string, InputStream& inputStream)
{
MatchExpectedString("\"", inputStream); MatchExpectedString("\"", inputStream);
while (inputStream.EOS() == false && while (!inputStream.EOS() && inputStream.Peek() != '"') {
inputStream.Peek() != '"')
{
char c = inputStream.Get(); char c = inputStream.Get();
// escape? // escape?
if (c == '\\' && if (c == '\\' && !inputStream.EOS()) { // shouldn't have reached the end yet
inputStream.EOS() == false) // shouldn't have reached the end yet
{
c = inputStream.Get(); c = inputStream.Get();
switch (c) { switch (c) {
case '/': string.push_back('/'); break; case '/': string.push_back('/'); break;
@ -285,27 +250,20 @@ void Reader::MatchString(std::string& string, InputStream& inputStream)
} }
} }
// eat the last '"' that we just peeked // eat the last '"' that we hopefully just peeked
MatchExpectedString("\"", inputStream); MatchExpectedString("\"", inputStream);
} }
void Reader::MatchNumber(std::string& sNumber, InputStream& inputStream) {
void Reader::MatchNumber(std::string& sNumber, InputStream& inputStream)
{
const char sNumericChars[] = "0123456789.eE-+"; const char sNumericChars[] = "0123456789.eE-+";
std::set<char> numericChars; std::set<char> numericChars;
numericChars.insert(sNumericChars, sNumericChars + sizeof(sNumericChars)); numericChars.insert(sNumericChars, sNumericChars + sizeof(sNumericChars));
while (inputStream.EOS() == false && while (!inputStream.EOS()&& numericChars.count(inputStream.Peek()))
numericChars.find(inputStream.Peek()) != numericChars.end())
{
sNumber.push_back(inputStream.Get()); sNumber.push_back(inputStream.Get());
} }
}
UnknownElement Reader::Parse(Reader::TokenStream& tokenStream) {
UnknownElement Reader::Parse(Reader::TokenStream& tokenStream)
{
if (tokenStream.EOS()) if (tokenStream.EOS())
throw ParseException("Unexpected end of token stream", Location(), Location()); // nowhere to point to throw ParseException("Unexpected end of token stream", Location(), Location()); // nowhere to point to
@ -322,16 +280,14 @@ UnknownElement Reader::Parse(Reader::TokenStream& tokenStream)
} }
} }
Object Reader::ParseObject(Reader::TokenStream& tokenStream) UnknownElement Reader::ParseObject(Reader::TokenStream& tokenStream) {
{
MatchExpectedToken(Token::TOKEN_OBJECT_BEGIN, tokenStream); MatchExpectedToken(Token::TOKEN_OBJECT_BEGIN, tokenStream);
Object object; Object object;
while (!tokenStream.EOS() && tokenStream.Peek().nType != Token::TOKEN_OBJECT_END) while (!tokenStream.EOS() && tokenStream.Peek().nType != Token::TOKEN_OBJECT_END) {
{
// first the member name. save the token in case we have to throw an exception // first the member name. save the token in case we have to throw an exception
const Token& tokenName = tokenStream.Peek(); Token const& tokenName = tokenStream.Peek();
std::string const& name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream); std::string const& name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
if (object.count(name)) if (object.count(name))
@ -352,8 +308,7 @@ Object Reader::ParseObject(Reader::TokenStream& tokenStream)
return object; return object;
} }
Array Reader::ParseArray(Reader::TokenStream& tokenStream) UnknownElement Reader::ParseArray(Reader::TokenStream& tokenStream) {
{
MatchExpectedToken(Token::TOKEN_ARRAY_BEGIN, tokenStream); MatchExpectedToken(Token::TOKEN_ARRAY_BEGIN, tokenStream);
Array array; Array array;
@ -371,53 +326,53 @@ Array Reader::ParseArray(Reader::TokenStream& tokenStream)
return array; return array;
} }
String Reader::ParseString(Reader::TokenStream& tokenStream) UnknownElement Reader::ParseString(Reader::TokenStream& tokenStream) {
{
return MatchExpectedToken(Token::TOKEN_STRING, tokenStream); return MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
} }
Number Reader::ParseNumber(Reader::TokenStream& tokenStream) UnknownElement Reader::ParseNumber(Reader::TokenStream& tokenStream) {
{ Token const& currentToken = tokenStream.Peek(); // might need this later for throwing exception
const Token& currentToken = tokenStream.Peek(); // might need this later for throwing exception std::string const& sValue = MatchExpectedToken(Token::TOKEN_NUMBER, tokenStream);
const std::string& sValue = MatchExpectedToken(Token::TOKEN_NUMBER, tokenStream);
// First try to parse it as an int
std::istringstream iStr(sValue); std::istringstream iStr(sValue);
int64_t iValue;
iStr >> iValue;
// If the entire token was consumed then it's not a double
if (iStr.eof())
return iValue;
// Try again as a double
iStr.seekg(0, std::ios::beg);
double dValue; double dValue;
iStr >> dValue; iStr >> dValue;
// did we consume all characters in the token? // If there's still stuff left in the token then it's malformed
if (!iStr.eof()) if (!iStr.eof())
throw ParseException("Unexpected character in NUMBER token: " + iStr.peek(), currentToken.locBegin, currentToken.locEnd); throw ParseException("Unexpected character in NUMBER token: " + iStr.peek(), currentToken.locBegin, currentToken.locEnd);
return dValue; return dValue;
} }
Boolean Reader::ParseBoolean(Reader::TokenStream& tokenStream) UnknownElement Reader::ParseBoolean(Reader::TokenStream& tokenStream) {
{
return MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream) == "true"; return MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream) == "true";
} }
Null Reader::ParseNull(Reader::TokenStream& tokenStream) UnknownElement Reader::ParseNull(Reader::TokenStream& tokenStream) {
{
MatchExpectedToken(Token::TOKEN_NULL, tokenStream); MatchExpectedToken(Token::TOKEN_NULL, tokenStream);
return Null(); return Null();
} }
std::string const& Reader::MatchExpectedToken(Token::Type nExpected, Reader::TokenStream& tokenStream) {
const std::string& Reader::MatchExpectedToken(Token::Type nExpected, Reader::TokenStream& tokenStream)
{
if (tokenStream.EOS()) if (tokenStream.EOS())
{
throw ParseException("Unexpected End of token stream", Location(), Location()); // nowhere to point to throw ParseException("Unexpected End of token stream", Location(), Location()); // nowhere to point to
}
const Token& token = tokenStream.Get(); Token const& token = tokenStream.Get();
if (token.nType != nExpected) if (token.nType != nExpected)
{
throw ParseException("Unexpected token: " + token.sValue, token.locBegin, token.locEnd); throw ParseException("Unexpected token: " + token.sValue, token.locBegin, token.locEnd);
}
return token.sValue; return token.sValue;
} }
} // End namespace }

View file

@ -9,6 +9,7 @@ Author: Terry Caton
#include "libaegisub/cajun/writer.h" #include "libaegisub/cajun/writer.h"
#ifndef LAGI_PRE #ifndef LAGI_PRE
#include <cmath>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#endif #endif
@ -24,23 +25,22 @@ TODO:
namespace json namespace json
{ {
Writer::Writer(std::ostream& ostr) : Writer::Writer(std::ostream& ostr)
m_ostr(ostr), : m_ostr(ostr)
m_nTabDepth(0) , tab_depth(0)
{}
void Writer::Write(const Array& array)
{ {
}
void Writer::Write(Array const& array) {
if (array.empty()) if (array.empty())
m_ostr << "[]"; m_ostr << "[]";
else else {
{
m_ostr << '[' << std::endl; m_ostr << '[' << std::endl;
++m_nTabDepth; ++tab_depth;
Array::const_iterator it(array.begin()), itend(array.end()); Array::const_iterator it(array.begin()), itend(array.end());
while (it != itend) { while (it != itend) {
m_ostr << std::string(m_nTabDepth, '\t'); m_ostr << std::string(tab_depth, '\t');
Write(*it); Write(*it);
@ -49,23 +49,21 @@ void Writer::Write(const Array& array)
m_ostr << std::endl; m_ostr << std::endl;
} }
--m_nTabDepth; --tab_depth;
m_ostr << std::string(m_nTabDepth, '\t') << ']'; m_ostr << std::string(tab_depth, '\t') << ']';
} }
} }
void Writer::Write(const Object& object) void Writer::Write(Object const& object) {
{
if (object.empty()) if (object.empty())
m_ostr << "{}"; m_ostr << "{}";
else else {
{
m_ostr << '{' << std::endl; m_ostr << '{' << std::endl;
++m_nTabDepth; ++tab_depth;
Object::const_iterator it(object.begin()), itend(object.end()); Object::const_iterator it(object.begin()), itend(object.end());
while (it != itend) { while (it != itend) {
m_ostr << std::string(m_nTabDepth, '\t') << '"' << it->first << "\" : "; m_ostr << std::string(tab_depth, '\t') << '"' << it->first << "\" : ";
Write(it->second); Write(it->second);
if (++it != itend) if (++it != itend)
@ -73,31 +71,33 @@ void Writer::Write(const Object& object)
m_ostr << std::endl; m_ostr << std::endl;
} }
--m_nTabDepth; --tab_depth;
m_ostr << std::string(m_nTabDepth, '\t') << '}'; m_ostr << std::string(tab_depth, '\t') << '}';
} }
} }
void Writer::Write(const Number& numberElement) void Writer::Write(Double const& numberElement) {
{
m_ostr << std::setprecision(20) << numberElement; m_ostr << std::setprecision(20) << numberElement;
double unused;
if (!std::modf(numberElement, &unused))
m_ostr << ".0";
} }
void Writer::Write(const Boolean& booleanElement) void Writer::Write(Integer const& numberElement) {
{ m_ostr << numberElement;
}
void Writer::Write(Boolean const& booleanElement) {
m_ostr << (booleanElement ? "true" : "false"); m_ostr << (booleanElement ? "true" : "false");
} }
void Writer::Write(const String& stringElement) void Writer::Write(String const& stringElement) {
{
m_ostr << '"'; m_ostr << '"';
const std::string& s = stringElement; std::string::const_iterator it(stringElement.begin()), itend(stringElement.end());
std::string::const_iterator it(s.begin()), itend(s.end()); for (; it != itend; ++it) {
for (; it != itend; ++it) switch (*it) {
{
switch (*it)
{
case '"': m_ostr << "\\\""; break; case '"': m_ostr << "\\\""; break;
case '\\': m_ostr << "\\\\"; break; case '\\': m_ostr << "\\\\"; break;
case '\b': m_ostr << "\\b"; break; case '\b': m_ostr << "\\b"; break;
@ -105,7 +105,6 @@ void Writer::Write(const String& stringElement)
case '\n': m_ostr << "\\n"; break; case '\n': m_ostr << "\\n"; break;
case '\r': m_ostr << "\\r"; break; case '\r': m_ostr << "\\r"; break;
case '\t': m_ostr << "\\t"; break; case '\t': m_ostr << "\\t"; break;
//case '\u': m_ostr << ""; break; ??
default: m_ostr << *it; break; default: m_ostr << *it; break;
} }
} }
@ -113,21 +112,20 @@ void Writer::Write(const String& stringElement)
m_ostr << '"'; m_ostr << '"';
} }
void Writer::Write(const Null& ) void Writer::Write(Null const&) {
{
m_ostr << "null"; m_ostr << "null";
} }
void Writer::Write(const UnknownElement& unknown) void Writer::Write(UnknownElement const& unknown) {
{
unknown.Accept(*this); unknown.Accept(*this);
} }
void Writer::Visit(const Array& array) { Write(array); } void Writer::Visit(Array const& array) { Write(array); }
void Writer::Visit(const Object& object) { Write(object); } void Writer::Visit(Object const& object) { Write(object); }
void Writer::Visit(const Number& number) { Write(number); } void Writer::Visit(Integer const& integer) { Write(integer); }
void Writer::Visit(const String& string) { Write(string); } void Writer::Visit(Double const& dbl) { Write(dbl); }
void Writer::Visit(const Boolean& boolean) { Write(boolean); } void Writer::Visit(String const& string) { Write(string); }
void Writer::Visit(const Null& null) { Write(null); } void Writer::Visit(Boolean const& boolean) { Write(boolean); }
void Writer::Visit(Null const& null) { Write(null); }
} // end namespace } // end namespace

View file

@ -21,10 +21,11 @@
#include "libaegisub/option.h" #include "libaegisub/option.h"
#ifndef LAGI_PRE #ifndef LAGI_PRE
#include <cassert>
#include <fstream> #include <fstream>
#include <sstream>
#include <map> #include <map>
#include <memory> #include <memory>
#include <sstream>
#endif #endif
#include "libaegisub/cajun/reader.h" #include "libaegisub/cajun/reader.h"
@ -38,6 +39,39 @@
#include "option_visit.h" #include "option_visit.h"
namespace {
/// @brief Write an option to a json object
/// @param[out] obj Parent object
/// @param[in] path Path option should be stored in.
/// @param[in] value Value to write.
void put_option(json::Object &obj, const std::string &path, const json::UnknownElement &value) {
std::string::size_type pos = path.find('/');
// Not having a '/' denotes it is a leaf.
if (pos == std::string::npos) {
assert(obj.find(path) == obj.end());
obj[path] = value;
}
else {
put_option(
obj[path.substr(0, pos)],
path.substr(pos + 1),
value);
}
}
template<class T>
void put_array(json::Object &obj, const std::string &path, const char *element_key, std::vector<T> const& value) {
json::Array array;
for (typename std::vector<T>::const_iterator it = value.begin(); it != value.end(); ++it) {
json::Object obj;
obj[element_key] = *it;
array.push_back(obj);
}
put_option(obj, path, array);
}
}
namespace agi { namespace agi {
Options::Options(const std::string &file, const std::string& default_config, const OptionSetting setting) Options::Options(const std::string &file, const std::string& default_config, const OptionSetting setting)
@ -108,92 +142,43 @@ void Options::Flush() {
for (OptionValueMap::const_iterator i = values.begin(); i != values.end(); ++i) { for (OptionValueMap::const_iterator i = values.begin(); i != values.end(); ++i) {
switch (i->second->GetType()) { switch (i->second->GetType()) {
case OptionValue::Type_String: case OptionValue::Type_String:
PutOption(obj_out, i->first, i->second->GetString()); put_option(obj_out, i->first, i->second->GetString());
break; break;
case OptionValue::Type_Int: case OptionValue::Type_Int:
PutOption(obj_out, i->first, (double)i->second->GetInt()); put_option(obj_out, i->first, i->second->GetInt());
break; break;
case OptionValue::Type_Double: case OptionValue::Type_Double:
PutOption(obj_out, i->first, i->second->GetDouble()); put_option(obj_out, i->first, i->second->GetDouble());
break; break;
case OptionValue::Type_Colour: case OptionValue::Type_Colour:
PutOption(obj_out, i->first, i->second->GetColour()); put_option(obj_out, i->first, i->second->GetColour());
break; break;
case OptionValue::Type_Bool: case OptionValue::Type_Bool:
PutOption(obj_out, i->first, i->second->GetBool()); put_option(obj_out, i->first, i->second->GetBool());
break; break;
case OptionValue::Type_List_String: { case OptionValue::Type_List_String:
std::vector<std::string> const& array_string(i->second->GetListString()); put_array(obj_out, i->first, "string", i->second->GetListString());
json::Array array;
for (std::vector<std::string>::const_iterator i_str = array_string.begin(); i_str != array_string.end(); ++i_str) {
json::Object obj;
obj["string"] = *i_str;
array.push_back(obj);
}
PutOption(obj_out, i->first, array);
}
break; break;
case OptionValue::Type_List_Int: { case OptionValue::Type_List_Int:
std::vector<int64_t> const& array_int(i->second->GetListInt()); put_array(obj_out, i->first, "int", i->second->GetListInt());
json::Array array;
for (std::vector<int64_t>::const_iterator i_int = array_int.begin(); i_int != array_int.end(); ++i_int) {
json::Object obj;
obj["int"] = (double)*i_int;
array.push_back(obj);
}
PutOption(obj_out, i->first, array);
}
break; break;
case OptionValue::Type_List_Double: { case OptionValue::Type_List_Double:
std::vector<double> const& array_double(i->second->GetListDouble()); put_array(obj_out, i->first, "double", i->second->GetListDouble());
json::Array array;
for (std::vector<double>::const_iterator i_double = array_double.begin(); i_double != array_double.end(); ++i_double) {
json::Object obj;
obj["double"] = *i_double;
array.push_back(obj);
}
PutOption(obj_out, i->first, array);
}
break; break;
case OptionValue::Type_List_Colour: { case OptionValue::Type_List_Colour:
std::vector<Colour> const& array_colour(i->second->GetListColour()); put_array(obj_out, i->first, "colour", i->second->GetListColour());
json::Array array;
for (std::vector<Colour>::const_iterator i_colour = array_colour.begin(); i_colour != array_colour.end(); ++i_colour) {
json::Object obj;
obj["colour"] = *i_colour;
array.push_back(obj);
}
PutOption(obj_out, i->first, array);
}
break; break;
case OptionValue::Type_List_Bool: { case OptionValue::Type_List_Bool:
std::vector<bool> const& array_bool(i->second->GetListBool()); put_array(obj_out, i->first, "bool", i->second->GetListBool());
json::Array array;
for (std::vector<bool>::const_iterator i_bool = array_bool.begin(); i_bool != array_bool.end(); ++i_bool) {
json::Object obj;
obj["bool"] = *i_bool;
array.push_back(obj);
}
PutOption(obj_out, i->first, array);
}
break; break;
} }
} }
@ -202,19 +187,4 @@ void Options::Flush() {
json::Writer::Write(obj_out, file.Get()); json::Writer::Write(obj_out, file.Get());
} }
void Options::PutOption(json::Object &obj, const std::string &path, const json::UnknownElement &value) {
std::string::size_type pos = path.find('/');
// Not having a '/' denotes it is a leaf.
if (pos == std::string::npos) {
assert(obj.find(path) == obj.end());
obj[path] = value;
}
else {
PutOption(
obj[path.substr(0, pos)],
path.substr(pos + 1),
value);
}
}
} // namespace agi } // namespace agi

View file

@ -22,6 +22,7 @@
#include "option_visit.h" #include "option_visit.h"
#ifndef LAGI_PRE #ifndef LAGI_PRE
#include <cassert>
#include <cmath> #include <cmath>
#include <memory> #include <memory>
#endif #endif
@ -59,16 +60,6 @@ void ConfigVisitor::Visit(const json::Object& object) {
} }
} }
template<class T>
static inline T convert_unknown(json::UnknownElement const& ue) {
return ue;
}
template<>
inline int64_t convert_unknown(json::UnknownElement const& ue) {
return (int64_t)(double)ue;
}
template<class OptionValueType, class ValueType> template<class OptionValueType, class ValueType>
OptionValue *ConfigVisitor::ReadArray(json::Array const& src, std::string const& array_type, void (OptionValueType::*set_list)(const std::vector<ValueType>&)) { OptionValue *ConfigVisitor::ReadArray(json::Array const& src, std::string const& array_type, void (OptionValueType::*set_list)(const std::vector<ValueType>&)) {
std::vector<ValueType> arr; std::vector<ValueType> arr;
@ -86,7 +77,7 @@ OptionValue *ConfigVisitor::ReadArray(json::Array const& src, std::string const&
return 0; return 0;
} }
arr.push_back(convert_unknown<ValueType>(obj.begin()->second)); arr.push_back(obj.begin()->second);
} }
OptionValueType *ret = new OptionValueType(name); OptionValueType *ret = new OptionValueType(name);
@ -122,13 +113,12 @@ void ConfigVisitor::Visit(const json::Array& array) {
Error<OptionJsonValueArray>("Array type not handled"); Error<OptionJsonValueArray>("Array type not handled");
} }
void ConfigVisitor::Visit(const json::Integer& number) {
void ConfigVisitor::Visit(const json::Number& number) { AddOptionValue(new OptionValueInt(name, number));
if (int64_t(number) == number) {
AddOptionValue(new OptionValueInt(name, int64_t(number)));
} else {
AddOptionValue(new OptionValueDouble(name, number));
} }
void ConfigVisitor::Visit(const json::Double& number) {
AddOptionValue(new OptionValueDouble(name, number));
} }
void ConfigVisitor::Visit(const json::String& string) { void ConfigVisitor::Visit(const json::String& string) {

View file

@ -23,6 +23,10 @@
#include "libaegisub/cajun/elements.h" #include "libaegisub/cajun/elements.h"
#include "libaegisub/cajun/visitor.h" #include "libaegisub/cajun/visitor.h"
#ifndef LAGI_PRE
#include <vector>
#endif
namespace agi { namespace agi {
DEFINE_BASE_EXCEPTION_NOINNER(OptionJsonValueError, Exception) DEFINE_BASE_EXCEPTION_NOINNER(OptionJsonValueError, Exception)
@ -47,7 +51,8 @@ public:
void Visit(const json::Array& array); void Visit(const json::Array& array);
void Visit(const json::Object& object); void Visit(const json::Object& object);
void Visit(const json::Number& number); void Visit(const json::Integer& number);
void Visit(const json::Double& number);
void Visit(const json::String& string); void Visit(const json::String& string);
void Visit(const json::Boolean& boolean); void Visit(const json::Boolean& boolean);
void Visit(const json::Null& null); void Visit(const json::Null& null);

View file

@ -14,6 +14,8 @@ Author: Terry Caton
#include <map> #include <map>
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include "stdint.h"
#endif #endif
namespace json namespace json
@ -21,14 +23,15 @@ namespace json
///////////////////////////////////////////////// /////////////////////////////////////////////////
// forward declarations (more info further below) // forward declarations (more info further below)
class Visitor; struct Visitor;
class ConstVisitor; struct ConstVisitor;
class UnknownElement; class UnknownElement;
template <typename ValueTypeT> template <typename ValueTypeT>
class TrivialType_T; class TrivialType_T;
typedef double Number; typedef int64_t Integer;
typedef double Double;
typedef bool Boolean; typedef bool Boolean;
typedef std::string String; typedef std::string String;
typedef std::deque<UnknownElement> Array; typedef std::deque<UnknownElement> Array;
@ -69,6 +72,7 @@ public:
UnknownElement(double number); UnknownElement(double number);
UnknownElement(int number); UnknownElement(int number);
UnknownElement(long number); UnknownElement(long number);
UnknownElement(int64_t number);
UnknownElement(bool boolean); UnknownElement(bool boolean);
UnknownElement(const char *string); UnknownElement(const char *string);
UnknownElement(const String& string); UnknownElement(const String& string);
@ -81,13 +85,15 @@ public:
// implicit cast to actual element type. throws on failure // implicit cast to actual element type. throws on failure
operator Object const&() const; operator Object const&() const;
operator Array const&() const; operator Array const&() const;
operator Number const&() const; operator Integer const&() const;
operator Double const&() const;
operator Boolean const&() const; operator Boolean const&() const;
operator String const&() const; operator String const&() const;
operator Null const&() const; operator Null const&() const;
operator Object&(); operator Object&();
operator Array&(); operator Array&();
operator Number&(); operator Integer&();
operator Double&();
operator Boolean&(); operator Boolean&();
operator String&(); operator String&();
operator Null&(); operator Null&();

View file

@ -18,51 +18,49 @@ Author: Terry Caton
namespace json namespace json
{ {
class Reader class Reader {
{
public: public:
// this structure will be reported in one of the exceptions defined below // this structure will be reported in one of the exceptions defined below
struct Location struct Location {
{ Location() : m_nLine(0), m_nLineOffset(0), m_nDocOffset(0) { }
Location();
unsigned int m_nLine; // document line, zero-indexed unsigned int m_nLine; // document line, zero-indexed
unsigned int m_nLineOffset; // character offset from beginning of line, zero indexed unsigned int m_nLineOffset; // character offset from beginning of line, zero indexed
unsigned int m_nDocOffset; // character offset from entire document, zero indexed unsigned int m_nDocOffset; // character offset from entire document, zero indexed
}; };
// thrown during the first phase of reading. generally catches low-level problems such // thrown during the first phase of reading. generally catches low-level
// as errant characters or corrupt/incomplete documents // problems such as errant characters or corrupt/incomplete documents
class ScanException : public Exception class ScanException : public Exception {
{
public: public:
ScanException(const std::string& sMessage, const Reader::Location& locError) : ScanException(std::string const& sMessage, Reader::Location const& locError)
Exception(sMessage), : Exception(sMessage)
m_locError(locError) {} , m_locError(locError)
{ }
Reader::Location m_locError; Reader::Location m_locError;
}; };
// thrown during the second phase of reading. generally catches higher-level problems such // thrown during the second phase of reading. generally catches
// as missing commas or brackets // higher-level problems such as missing commas or brackets
class ParseException : public Exception class ParseException : public Exception {
{
public: public:
ParseException(const std::string& sMessage, const Reader::Location& locTokenBegin, const Reader::Location& locTokenEnd) : ParseException(std::string const& sMessage, Reader::Location const& locTokenBegin, Reader::Location const& locTokenEnd)
Exception(sMessage), : Exception(sMessage)
m_locTokenBegin(locTokenBegin), , m_locTokenBegin(locTokenBegin)
m_locTokenEnd(locTokenEnd) {} , m_locTokenEnd(locTokenEnd)
{ }
Reader::Location m_locTokenBegin; Reader::Location m_locTokenBegin;
Reader::Location m_locTokenEnd; Reader::Location m_locTokenEnd;
}; };
// if you know what the document looks like, call one of these... // if you know what the document looks like, call one of these...
static void Read(Object& object, std::istream& istr); static void Read(Object& object, std::istream& istr);
static void Read(Array& array, std::istream& istr); static void Read(Array& array, std::istream& istr);
static void Read(String& string, std::istream& istr); static void Read(String& string, std::istream& istr);
static void Read(Number& number, std::istream& istr); static void Read(Integer& number, std::istream& istr);
static void Read(Double& number, std::istream& istr);
static void Read(Boolean& boolean, std::istream& istr); static void Read(Boolean& boolean, std::istream& istr);
static void Read(Null& null, std::istream& istr); static void Read(Null& null, std::istream& istr);
@ -70,10 +68,8 @@ public:
static void Read(UnknownElement& elementRoot, std::istream& istr); static void Read(UnknownElement& elementRoot, std::istream& istr);
private: private:
struct Token struct Token {
{ enum Type {
enum Type
{
TOKEN_OBJECT_BEGIN, // { TOKEN_OBJECT_BEGIN, // {
TOKEN_OBJECT_END, // } TOKEN_OBJECT_END, // }
TOKEN_ARRAY_BEGIN, // [ TOKEN_ARRAY_BEGIN, // [
@ -107,18 +103,18 @@ private:
void EatWhiteSpace(InputStream& inputStream); void EatWhiteSpace(InputStream& inputStream);
void MatchString(std::string& sValue, InputStream& inputStream); void MatchString(std::string& sValue, InputStream& inputStream);
void MatchNumber(std::string& sNumber, InputStream& inputStream); void MatchNumber(std::string& sNumber, InputStream& inputStream);
void MatchExpectedString(const std::string& sExpected, InputStream& inputStream); void MatchExpectedString(std::string const& sExpected, InputStream& inputStream);
// parsing token sequence into element structure // parsing token sequence into element structure
UnknownElement Parse(TokenStream& tokenStream); UnknownElement Parse(TokenStream& tokenStream);
Object ParseObject(TokenStream& tokenStream); UnknownElement ParseObject(TokenStream& tokenStream);
Array ParseArray(TokenStream& tokenStream); UnknownElement ParseArray(TokenStream& tokenStream);
String ParseString(TokenStream& tokenStream); UnknownElement ParseString(TokenStream& tokenStream);
Number ParseNumber(TokenStream& tokenStream); UnknownElement ParseNumber(TokenStream& tokenStream);
Boolean ParseBoolean(TokenStream& tokenStream); UnknownElement ParseBoolean(TokenStream& tokenStream);
Null ParseNull(TokenStream& tokenStream); UnknownElement ParseNull(TokenStream& tokenStream);
const std::string& MatchExpectedToken(Token::Type nExpected, TokenStream& tokenStream); std::string const& MatchExpectedToken(Token::Type nExpected, TokenStream& tokenStream);
}; };
} // End namespace }

View file

@ -13,32 +13,28 @@ Author: Terry Caton
namespace json namespace json
{ {
struct Visitor {
class Visitor
{
public:
virtual ~Visitor() { } virtual ~Visitor() { }
virtual void Visit(Array& array) = 0; virtual void Visit(Array& array) = 0;
virtual void Visit(Object& object) = 0; virtual void Visit(Object& object) = 0;
virtual void Visit(Number& number) = 0; virtual void Visit(Integer& number) = 0;
virtual void Visit(Double& number) = 0;
virtual void Visit(String& string) = 0; virtual void Visit(String& string) = 0;
virtual void Visit(Boolean& boolean) = 0; virtual void Visit(Boolean& boolean) = 0;
virtual void Visit(Null& null) = 0; virtual void Visit(Null& null) = 0;
}; };
class ConstVisitor struct ConstVisitor {
{
public:
virtual ~ConstVisitor() { } virtual ~ConstVisitor() { }
virtual void Visit(const Array& array) = 0; virtual void Visit(const Array& array) = 0;
virtual void Visit(const Object& object) = 0; virtual void Visit(const Object& object) = 0;
virtual void Visit(const Number& number) = 0; virtual void Visit(const Integer& number) = 0;
virtual void Visit(const Double& number) = 0;
virtual void Visit(const String& string) = 0; virtual void Visit(const String& string) = 0;
virtual void Visit(const Boolean& boolean) = 0; virtual void Visit(const Boolean& boolean) = 0;
virtual void Visit(const Null& null) = 0; virtual void Visit(const Null& null) = 0;
}; };
} // End namespace } // End namespace

View file

@ -14,36 +14,35 @@ Author: Terry Caton
namespace json namespace json
{ {
class Writer : private ConstVisitor class Writer : private ConstVisitor {
{
public:
template <typename ElementTypeT>
static void Write(const ElementTypeT& element, std::ostream& ostr)
{
Writer writer(ostr);
writer.Write(element);
ostr.flush(); // all done
}
private:
Writer(std::ostream& ostr); Writer(std::ostream& ostr);
void Write(const Object& object); void Write(const Object& object);
void Write(const Array& array); void Write(const Array& array);
void Write(const String& string); void Write(const String& string);
void Write(const Number& number); void Write(const Integer& number);
void Write(const Double& number);
void Write(const Boolean& boolean); void Write(const Boolean& boolean);
void Write(const Null& null); void Write(const Null& null);
void Write(const UnknownElement& unknown); void Write(const UnknownElement& unknown);
void Visit(const Array& array); void Visit(const Array& array);
void Visit(const Object& object); void Visit(const Object& object);
void Visit(const Number& number); void Visit(const Integer& number);
void Visit(const Double& number);
void Visit(const String& string); void Visit(const String& string);
void Visit(const Boolean& boolean); void Visit(const Boolean& boolean);
void Visit(const Null& null); void Visit(const Null& null);
std::ostream& m_ostr; std::ostream& m_ostr;
int m_nTabDepth; int tab_depth;
public:
template <typename ElementTypeT>
static void Write(const ElementTypeT& element, std::ostream& ostr) {
Writer writer(ostr);
writer.Write(element);
ostr.flush(); // all done
}
}; };

View file

@ -78,12 +78,6 @@ private:
/// @param ignore_errors Log invalid entires in the option file and continue rather than throwing an exception /// @param ignore_errors Log invalid entires in the option file and continue rather than throwing an exception
void LoadConfig(std::istream& stream, bool ignore_errors = false); void LoadConfig(std::istream& stream, bool ignore_errors = false);
/// @brief Write an option to file.
/// @param[out] obj Parent object
/// @param[in] path Path option should be stored in.
/// @param[in] value Value to write.
static void PutOption(::json::Object &obj, const std::string &path, const ::json::UnknownElement &value);
public: public:
/// @brief Constructor /// @brief Constructor
/// @param file User config that will be loaded from and written back to. /// @param file User config that will be loaded from and written back to.

View file

@ -40,100 +40,83 @@ Report::Report() {
Platform *p = Platform::GetPlatform(); Platform *p = Platform::GetPlatform();
Aegisub a; Aegisub a;
json::Object general; json::Object& general = root["General"];
general["Signature"] = json::String(p->Signature()); general["Signature"] = p->Signature();
general["Date"] = json::String(p->Date()); general["Date"] = p->Date();
general["Architecture"] = json::String(p->ArchName()); general["Architecture"] = p->ArchName();
general["OS Family"] = json::String(p->OSFamily()); general["OS Family"] = p->OSFamily();
general["OS Name"] = json::String(p->OSName()); general["OS Name"] = p->OSName();
general["Endian"] = json::String(p->Endian()); general["Endian"] = p->Endian();
general["OS Version"] = json::String(p->OSVersion()); general["OS Version"] = p->OSVersion();
general["wx Version"] = json::String(p->wxVersion()); general["wx Version"] = p->wxVersion();
general["Locale"] = json::String(p->Locale()); general["Locale"] = p->Locale();
general["Language"] = json::String(p->Language()); general["Language"] = p->Language();
general["System Language"] = json::String(p->SystemLanguage()); general["System Language"] = p->SystemLanguage();
root["General"] = general;
try { try {
json::Object aegisub; json::Object& aegisub = root["Aegisub"];
aegisub["Last Version"] = json::String(a.GetString("Version/Last Version")); aegisub["Last Version"] = a.GetString("Version/Last Version");
aegisub["Spelling Language"] = json::String(a.GetString("Tool/Spell Checker/Language")); aegisub["Spelling Language"] = a.GetString("Tool/Spell Checker/Language");
aegisub["Thesaurus Language"] = json::String(a.GetString("Tool/Thesaurus/Language")); aegisub["Thesaurus Language"] = a.GetString("Tool/Thesaurus/Language");
aegisub["Audio Player"] = json::String(a.GetString("Audio/Player")); aegisub["Audio Player"] = a.GetString("Audio/Player");
aegisub["Audio Provider"] = json::String(a.GetString("Audio/Provider")); aegisub["Audio Provider"] = a.GetString("Audio/Provider");
aegisub["Video Provider"] = json::String(a.GetString("Video/Provider")); aegisub["Video Provider"] = a.GetString("Video/Provider");
aegisub["Subtitles Provider"] = json::String(a.GetString("Subtitle/Provider")); aegisub["Subtitles Provider"] = a.GetString("Subtitle/Provider");
aegisub["Save Charset"] = json::String(a.GetString("App/Save Charset")); aegisub["Save Charset"] = a.GetString("App/Save Charset");
aegisub["Grid Font Size"] = json::Number(a.GetInt("Grid/Font Size")); aegisub["Grid Font Size"] = a.GetInt("Grid/Font Size");
aegisub["Edit Font Size"] = json::Number(a.GetInt("Subtitle/Edit Box/Font Size")); aegisub["Edit Font Size"] = a.GetInt("Subtitle/Edit Box/Font Size");
aegisub["Spectrum Enabled"] = json::Boolean(a.GetBool("Audio/Spectrum")); aegisub["Spectrum Enabled"] = a.GetBool("Audio/Spectrum");
aegisub["Spectrum Quality"] = json::Number(a.GetInt("Audio/Renderer/Spectrum/Quality")); aegisub["Spectrum Quality"] = a.GetInt("Audio/Renderer/Spectrum/Quality");
aegisub["Call Tips Enabled"] = json::Boolean(a.GetBool("App/Call Tips")); aegisub["Call Tips Enabled"] = a.GetBool("App/Call Tips");
aegisub["Medusa Hotkeys Enabled"] = json::Boolean(a.GetBool("Audio/Medusa Timing Hotkeys")); aegisub["Medusa Hotkeys Enabled"] = a.GetBool("Audio/Medusa Timing Hotkeys");
root["Aegisub"] = aegisub;
} catch(...) { } catch(...) {
root["Aegisub"]["Error"] = json::String("Config file is corrupted"); root["Aegisub"]["Error"] = json::String("Config file is corrupted");
} }
json::Object& hardware = root["Hardware"];
hardware["Memory Size"] = 0;
json::Object& cpu = root["CPU"];
cpu["Id"] = p->CPUId();
cpu["Speed"] = p->CPUSpeed();
cpu["Count"] = p->CPUCount();
cpu["Cores"] = p->CPUCores();
cpu["Features"] = p->CPUFeatures();
cpu["Features2"] = p->CPUFeatures2();
json::Object hardware; json::Object& display = root["Display"];
hardware["Memory Size"] = json::Number(); display["Depth"] = p->DisplayDepth();
root["Hardware"] = hardware; display["Size"] = p->DisplaySize();
display["Pixels Per Inch"] = p->DisplayPPI();
json::Object cpu; json::Object& gl = display["OpenGL"];
cpu["Id"] = json::String(p->CPUId()); gl["Vendor"] = p->OpenGLVendor();
cpu["Speed"] = json::String(p->CPUSpeed()); gl["Renderer"] = p->OpenGLRenderer();
cpu["Count"] = json::Number(p->CPUCount()); gl["Version"] = p->OpenGLVersion();
cpu["Cores"] = json::Number(p->CPUCores()); gl["Extensions"] = p->OpenGLExt();
cpu["Features"] = json::String(p->CPUFeatures());
cpu["Features2"] = json::String(p->CPUFeatures2());
root["CPU"] = cpu;
json::Object display;
display["Depth"] = json::Number(p->DisplayDepth());
display["Size"] = json::String(p->DisplaySize());
display["Pixels Per Inch"] = json::String(p->DisplayPPI());
json::Object gl;
gl["Vendor"] = json::String(p->OpenGLVendor());
gl["Renderer"] = json::String(p->OpenGLRenderer());
gl["Version"] = json::String(p->OpenGLVersion());
gl["Extensions"] = json::String(p->OpenGLExt());
display["OpenGL"] = gl; display["OpenGL"] = gl;
root["Display"] = display;
#ifdef __WINDOWS__ #ifdef __WINDOWS__
json::Object windows; json::Object& windows = root["Windows"];
windows["Service Pack"] = json::String(); windows["Service Pack"] = json::String();
windows["Graphics Driver Version"] = json::String(); windows["Graphics Driver Version"] = json::String();
windows["DirectShow Filters"] = json::String(); windows["DirectShow Filters"] = json::String();
windows["AntiVirus Installed"] = json::Boolean(); windows["AntiVirus Installed"] = json::Boolean();
windows["Firewall Installed"] = json::Boolean(); windows["Firewall Installed"] = json::Boolean();
windows["DLL"] = json::String(); windows["DLL"] = json::String();
root["Windows"] = windows;
#endif #endif
#ifdef __UNIX__ #ifdef __UNIX__
json::Object u_nix; json::Object& u_nix = root["Unix"];
u_nix["Desktop Environment"] = json::String(p->DesktopEnvironment()); u_nix["Desktop Environment"] = p->DesktopEnvironment();
u_nix["Libraries"] = json::String(p->UnixLibraries()); u_nix["Libraries"] = p->UnixLibraries();
root["Unix"] = u_nix;
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
json::Object osx; json::Object& osx = root["OS X"];
osx["Patch"] = json::String(p->PatchLevel()); osx["Patch"] = p->PatchLevel();
osx["QuickTime Extensions"] = json::String(p->QuickTimeExt()); osx["QuickTime Extensions"] = p->QuickTimeExt();
osx["Model"] = json::String(p->HardwareModel()); osx["Model"] = p->HardwareModel();
root["OS X"] = osx;
#endif #endif
agi::io::Save file("./t.json"); agi::io::Save file("./t.json");

View file

@ -98,18 +98,21 @@ TEST_F(lagi_cajun, Compare) {
TEST_F(lagi_cajun, CastNonConst) { TEST_F(lagi_cajun, CastNonConst) {
json::UnknownElement Integer = 0; json::UnknownElement Integer = 0;
json::UnknownElement Double = 0.0;
json::UnknownElement String = "1"; json::UnknownElement String = "1";
json::UnknownElement Boolean = false; json::UnknownElement Boolean = false;
json::UnknownElement Array = json::Array(); json::UnknownElement Array = json::Array();
json::UnknownElement Object = json::Object(); json::UnknownElement Object = json::Object();
EXPECT_NO_THROW(static_cast<json::Number&>(Integer)); EXPECT_NO_THROW(static_cast<json::Integer&>(Integer));
EXPECT_NO_THROW(static_cast<json::Double&>(Double));
EXPECT_NO_THROW(static_cast<json::String&>(String)); EXPECT_NO_THROW(static_cast<json::String&>(String));
EXPECT_NO_THROW(static_cast<json::Boolean&>(Boolean)); EXPECT_NO_THROW(static_cast<json::Boolean&>(Boolean));
EXPECT_NO_THROW(static_cast<json::Array&>(Array)); EXPECT_NO_THROW(static_cast<json::Array&>(Array));
EXPECT_NO_THROW(static_cast<json::Object&>(Object)); EXPECT_NO_THROW(static_cast<json::Object&>(Object));
EXPECT_NO_THROW(static_cast<json::Number const&>(Integer)); EXPECT_NO_THROW(static_cast<json::Integer const&>(Integer));
EXPECT_NO_THROW(static_cast<json::Double const&>(Double));
EXPECT_NO_THROW(static_cast<json::String const&>(String)); EXPECT_NO_THROW(static_cast<json::String const&>(String));
EXPECT_NO_THROW(static_cast<json::Boolean const&>(Boolean)); EXPECT_NO_THROW(static_cast<json::Boolean const&>(Boolean));
EXPECT_NO_THROW(static_cast<json::Array const&>(Array)); EXPECT_NO_THROW(static_cast<json::Array const&>(Array));
@ -118,26 +121,30 @@ TEST_F(lagi_cajun, CastNonConst) {
TEST_F(lagi_cajun, CastConst) { TEST_F(lagi_cajun, CastConst) {
const json::UnknownElement Integer = 10; const json::UnknownElement Integer = 10;
const json::UnknownElement Double = 10.0;
const json::UnknownElement String = "1"; const json::UnknownElement String = "1";
const json::UnknownElement Boolean = false; const json::UnknownElement Boolean = false;
const json::UnknownElement Array = json::Array(); const json::UnknownElement Array = json::Array();
const json::UnknownElement Object = json::Object(); const json::UnknownElement Object = json::Object();
/* these shouldn't compile /* these shouldn't compile
EXPECT_NO_THROW(static_cast<json::Number&>(Integer)); EXPECT_NO_THROW(static_cast<json::Integer&>(Integer));
EXPECT_NO_THROW(static_cast<json::Double&>(Double));
EXPECT_NO_THROW(static_cast<json::String&>(String)); EXPECT_NO_THROW(static_cast<json::String&>(String));
EXPECT_NO_THROW(static_cast<json::Boolean&>(Boolean)); EXPECT_NO_THROW(static_cast<json::Boolean&>(Boolean));
EXPECT_NO_THROW(static_cast<json::Array&>(Array)); EXPECT_NO_THROW(static_cast<json::Array&>(Array));
EXPECT_NO_THROW(static_cast<json::Object&>(Object)); EXPECT_NO_THROW(static_cast<json::Object&>(Object));
*/ */
EXPECT_NO_THROW(static_cast<json::Number const&>(Integer)); EXPECT_NO_THROW(static_cast<json::Integer const&>(Integer));
EXPECT_NO_THROW(static_cast<json::Double const&>(Double));
EXPECT_NO_THROW(static_cast<json::String const&>(String)); EXPECT_NO_THROW(static_cast<json::String const&>(String));
EXPECT_NO_THROW(static_cast<json::Boolean const&>(Boolean)); EXPECT_NO_THROW(static_cast<json::Boolean const&>(Boolean));
EXPECT_NO_THROW(static_cast<json::Array const&>(Array)); EXPECT_NO_THROW(static_cast<json::Array const&>(Array));
EXPECT_NO_THROW(static_cast<json::Object const&>(Object)); EXPECT_NO_THROW(static_cast<json::Object const&>(Object));
EXPECT_EQ(10, static_cast<json::Number const&>(Integer)); EXPECT_EQ(10, static_cast<json::Integer const&>(Integer));
EXPECT_EQ(10, static_cast<json::Double const&>(Double));
EXPECT_STREQ("1", static_cast<json::String const&>(String).c_str()); EXPECT_STREQ("1", static_cast<json::String const&>(String).c_str());
EXPECT_EQ(false, static_cast<json::Boolean const&>(Boolean)); EXPECT_EQ(false, static_cast<json::Boolean const&>(Boolean));
EXPECT_EQ(true, static_cast<json::Array const&>(Array).empty()); EXPECT_EQ(true, static_cast<json::Array const&>(Array).empty());
@ -150,7 +157,7 @@ TEST_F(lagi_cajun, UnknownIsIndexable) {
json::UnknownElement unk_obj = obj; json::UnknownElement unk_obj = obj;
EXPECT_NO_THROW(unk_obj["Integer"]); EXPECT_NO_THROW(unk_obj["Integer"]);
EXPECT_EQ(1, (json::Number)unk_obj["Integer"]); EXPECT_EQ(1, (json::Integer)unk_obj["Integer"]);
EXPECT_THROW(unk_obj[0], json::Exception); EXPECT_THROW(unk_obj[0], json::Exception);
EXPECT_NO_THROW(unk_obj["Nonexistent Key"]); EXPECT_NO_THROW(unk_obj["Nonexistent Key"]);
@ -163,20 +170,20 @@ TEST_F(lagi_cajun, UnknownIsIndexable) {
json::UnknownElement unk_arr = arr; json::UnknownElement unk_arr = arr;
EXPECT_NO_THROW(unk_arr[0]); EXPECT_NO_THROW(unk_arr[0]);
EXPECT_EQ(1, (json::Number)unk_arr[0]); EXPECT_EQ(1, (json::Integer)unk_arr[0]);
EXPECT_THROW(unk_arr["Integer"], json::Exception); EXPECT_THROW(unk_arr["Integer"], json::Exception);
json::Number number = 1; json::Integer number = 1;
json::UnknownElement const& unk_num = number; json::UnknownElement const& unk_num = number;
EXPECT_THROW(unk_num[0], json::Exception); EXPECT_THROW(unk_num[0], json::Exception);
EXPECT_THROW(unk_num[""], json::Exception); EXPECT_THROW(unk_num[""], json::Exception);
} }
TEST_F(lagi_cajun, ObjectStoreNumber) { TEST_F(lagi_cajun, ObjectStoreInteger) {
json::Object obj; json::Object obj;
obj["Integer"] = 1; obj["Integer"] = 1;
EXPECT_EQ(1, static_cast<json::Number>(obj["Integer"])); EXPECT_EQ(1, static_cast<json::Integer>(obj["Integer"]));
EXPECT_THROW(static_cast<json::String const&>(obj["Integer"]), json::Exception); EXPECT_THROW(static_cast<json::String const&>(obj["Integer"]), json::Exception);
EXPECT_THROW(static_cast<json::Boolean>(obj["Integer"]), json::Exception); EXPECT_THROW(static_cast<json::Boolean>(obj["Integer"]), json::Exception);
@ -185,12 +192,24 @@ TEST_F(lagi_cajun, ObjectStoreNumber) {
EXPECT_THROW(static_cast<json::Object const&>(obj["Integer"]), json::Exception); EXPECT_THROW(static_cast<json::Object const&>(obj["Integer"]), json::Exception);
} }
TEST_F(lagi_cajun, ObjectStoreDouble) {
json::Object obj;
obj["Double"] = 1.0;
EXPECT_EQ(1.0, static_cast<json::Double>(obj["Double"]));
EXPECT_THROW(static_cast<json::String const&>(obj["Double"]), json::Exception);
EXPECT_THROW(static_cast<json::Boolean>(obj["Double"]), json::Exception);
EXPECT_THROW(static_cast<json::Null>(obj["Double"]), json::Exception);
EXPECT_THROW(static_cast<json::Array const&>(obj["Double"]), json::Exception);
EXPECT_THROW(static_cast<json::Object const&>(obj["Double"]), json::Exception);
}
TEST_F(lagi_cajun, ObjectStoreString) { TEST_F(lagi_cajun, ObjectStoreString) {
json::Object obj; json::Object obj;
obj["String"] = "test"; obj["String"] = "test";
EXPECT_STREQ("test", static_cast<std::string>(obj["String"]).c_str()); EXPECT_STREQ("test", static_cast<std::string>(obj["String"]).c_str());
EXPECT_THROW(static_cast<json::Number>(obj["String"]), json::Exception); EXPECT_THROW(static_cast<json::Integer>(obj["String"]), json::Exception);
EXPECT_THROW(static_cast<json::Boolean>(obj["String"]), json::Exception); EXPECT_THROW(static_cast<json::Boolean>(obj["String"]), json::Exception);
EXPECT_THROW(static_cast<json::Null>(obj["String"]), json::Exception); EXPECT_THROW(static_cast<json::Null>(obj["String"]), json::Exception);
EXPECT_THROW(static_cast<json::Array const&>(obj["String"]), json::Exception); EXPECT_THROW(static_cast<json::Array const&>(obj["String"]), json::Exception);
@ -203,7 +222,7 @@ TEST_F(lagi_cajun, ObjectStoreBoolean) {
EXPECT_EQ(true, static_cast<json::Boolean>(obj["Boolean"])); EXPECT_EQ(true, static_cast<json::Boolean>(obj["Boolean"]));
EXPECT_THROW(static_cast<json::String const&>(obj["Boolean"]), json::Exception); EXPECT_THROW(static_cast<json::String const&>(obj["Boolean"]), json::Exception);
EXPECT_THROW(static_cast<json::Number>(obj["Boolean"]), json::Exception); EXPECT_THROW(static_cast<json::Integer>(obj["Boolean"]), json::Exception);
EXPECT_THROW(static_cast<json::Null>(obj["Boolean"]), json::Exception); EXPECT_THROW(static_cast<json::Null>(obj["Boolean"]), json::Exception);
EXPECT_THROW(static_cast<json::Array const&>(obj["Boolean"]), json::Exception); EXPECT_THROW(static_cast<json::Array const&>(obj["Boolean"]), json::Exception);
EXPECT_THROW(static_cast<json::Object const&>(obj["Boolean"]), json::Exception); EXPECT_THROW(static_cast<json::Object const&>(obj["Boolean"]), json::Exception);
@ -219,7 +238,10 @@ TEST_F(lagi_cajun, ObjectStoreNull) {
EXPECT_NO_THROW(static_cast<json::String const&>(obj["Null"])); EXPECT_NO_THROW(static_cast<json::String const&>(obj["Null"]));
obj["Null"] = json::Null(); obj["Null"] = json::Null();
EXPECT_NO_THROW(static_cast<json::Number>(obj["Null"])); EXPECT_NO_THROW(static_cast<json::Integer>(obj["Null"]));
obj["Null"] = json::Null();
EXPECT_NO_THROW(static_cast<json::Double>(obj["Null"]));
obj["Null"] = json::Null(); obj["Null"] = json::Null();
EXPECT_NO_THROW(static_cast<json::Boolean>(obj["Null"])); EXPECT_NO_THROW(static_cast<json::Boolean>(obj["Null"]));
@ -303,7 +325,7 @@ TEST_F(lagi_cajun, ReaderParserErrors) {
std::istringstream missing_comma("[1 2]"); std::istringstream missing_comma("[1 2]");
EXPECT_THROW(json::Reader::Read(arr, missing_comma), json::Exception); EXPECT_THROW(json::Reader::Read(arr, missing_comma), json::Exception);
json::Number num; json::Double num;
std::istringstream garbage_after_number("123eee"); std::istringstream garbage_after_number("123eee");
EXPECT_THROW(json::Reader::Read(num, garbage_after_number), json::Exception); EXPECT_THROW(json::Reader::Read(num, garbage_after_number), json::Exception);
@ -335,7 +357,7 @@ TEST_F(lagi_cajun, ReaderScanErrors) {
EXPECT_THROW(json::Reader::Read(obj, doc), json::Exception); EXPECT_THROW(json::Reader::Read(obj, doc), json::Exception);
json::Number num; json::Double num;
std::istringstream garbage_after_number("123abc"); std::istringstream garbage_after_number("123abc");
EXPECT_THROW(json::Reader::Read(num, garbage_after_number), json::Exception); EXPECT_THROW(json::Reader::Read(num, garbage_after_number), json::Exception);