Copy JSON from SandBox to trunk

This commit is contained in:
Franky Braem
2012-04-29 20:09:55 +00:00
parent 5a639074d9
commit 95c62c00df
121 changed files with 5085 additions and 0 deletions

147
JSON/src/Array.cpp Normal file
View File

@@ -0,0 +1,147 @@
//
// Array.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: Array
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/JSON/Array.h"
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Stringifier.h"
namespace Poco
{
namespace JSON
{
Array::Array()
{
}
Array::Array(const Array& copy) : _values(copy._values)
{
}
Array::~Array()
{
}
DynamicAny Array::get(unsigned int index) const
{
DynamicAny value;
try
{
value = _values.at(index);
}
catch(std::out_of_range)
{
//Ignore, we return an empty value
}
return value;
}
Array::Ptr Array::getArray(unsigned int index) const
{
Array::Ptr result;
DynamicAny value = get(index);
if ( value.type() == typeid(Array::Ptr) )
{
result = value.extract<Array::Ptr>();
}
return result;
}
Object::Ptr Array::getObject(unsigned int index) const
{
Object::Ptr result;
DynamicAny value = get(index);
if ( value.type() == typeid(Object::Ptr) )
{
result = value.extract<Object::Ptr>();
}
return result;
}
bool Array::isObject(unsigned int index) const
{
DynamicAny value = get(index);
return value.type() == typeid(Object::Ptr);
}
void Array::stringify(std::ostream& out, unsigned int indent) const
{
out << "[";
if ( indent > 0 )
out << std::endl;
for(ValueVector::const_iterator it = _values.begin(); it != _values.end();)
{
for(int i = 0; i < indent; i++)
{
out << ' ';
}
Stringifier::stringify(*it, out, indent);
if ( ++it != _values.end() )
{
out << ",";
if ( indent > 0 )
{
out << std::endl;
}
}
}
if ( indent > 0 )
{
out << std::endl;
}
if ( indent > 0 )
indent -= 2;
for(int i = 0; i < indent; i++)
{
out << ' ';
}
out << "]";
}
}} // Namespace Poco::JSON

150
JSON/src/DefaultHandler.cpp Normal file
View File

@@ -0,0 +1,150 @@
//
// DefaultHandler.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: DefaultHandler
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/JSON/DefaultHandler.h"
#include "Poco/JSON/Object.h"
namespace Poco
{
namespace JSON
{
DefaultHandler::DefaultHandler() : Handler()
{
}
DefaultHandler::~DefaultHandler()
{
}
void DefaultHandler::startObject()
{
Object::Ptr newObj = new Object();
if ( _stack.empty() ) // The first object
{
_result = newObj;
}
else
{
DynamicAny parent = _stack.top();
if ( parent.type() == typeid(Array::Ptr) )
{
Array::Ptr arr = parent.extract<Array::Ptr>();
arr->add(newObj);
}
else if ( parent.type() == typeid(Object::Ptr) )
{
poco_assert_dbg(!_key.empty());
Object::Ptr obj = parent.extract<Object::Ptr>();
obj->set(_key, newObj);
_key.clear();
}
}
_stack.push(newObj);
}
void DefaultHandler::endObject()
{
_stack.pop();
}
void DefaultHandler::startArray()
{
Array::Ptr newArr = new Array();
if ( _stack.empty() ) // The first array
{
_result = newArr;
}
else
{
DynamicAny parent = _stack.top();
if ( parent.type() == typeid(Array::Ptr) )
{
Array::Ptr arr = parent.extract<Array::Ptr>();
arr->add(newArr);
}
else if ( parent.type() == typeid(Object::Ptr) )
{
poco_assert_dbg(!_key.empty());
Object::Ptr obj = parent.extract<Object::Ptr>();
obj->set(_key, newArr);
_key.clear();
}
}
_stack.push(newArr);
}
void DefaultHandler::endArray()
{
_stack.pop();
}
void DefaultHandler::key(const std::string& k)
{
_key = k;
}
void DefaultHandler::setValue(const Poco::DynamicAny& value)
{
DynamicAny parent = _stack.top();
if ( parent.type() == typeid(Array::Ptr) )
{
Array::Ptr arr = parent.extract<Array::Ptr>();
arr->add(value);
}
else if ( parent.type() == typeid(Object::Ptr) )
{
poco_assert_dbg(!_key.empty());
Object::Ptr obj = parent.extract<Object::Ptr>();
obj->set(_key, value);
_key.clear();
}
}
}} // Namespace Poco::JSON

48
JSON/src/Handler.cpp Normal file
View File

@@ -0,0 +1,48 @@
//
// Handler.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: Handler
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/JSON/Handler.h"
#include "Poco/JSON/Object.h"
namespace Poco
{
namespace JSON
{
Handler::~Handler()
{
}
}} // Namespace Poco::JSON

View File

@@ -0,0 +1,44 @@
//
// JSONException.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: JSONException
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/JSON/JSONException.h"
#include <typeinfo>
namespace Poco {
namespace JSON {
POCO_IMPLEMENT_EXCEPTION(JSONException, Exception, "JSON Exception")
}} // Namespace Poco::JSON

155
JSON/src/Object.cpp Normal file
View File

@@ -0,0 +1,155 @@
//
// Object.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: Object
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Array.h"
#include "Poco/JSON/Stringifier.h"
#include <iostream>
#include <sstream>
namespace Poco
{
namespace JSON
{
Object::Object()
{
}
Object::Object(const Object& copy) : _values(copy._values)
{
}
Object::~Object()
{
}
DynamicAny Object::get(const std::string& key) const
{
DynamicAny value;
ValueMap::const_iterator it = _values.find(key);
if ( it != _values.end() )
{
value = it->second;
}
return value;
}
Array::Ptr Object::getArray(const std::string& key) const
{
Array::Ptr result;
DynamicAny value = get(key);
if ( value.type() == typeid(Array::Ptr) )
{
result = value.extract<Array::Ptr>();
}
return result;
}
Object::Ptr Object::getObject(const std::string& key) const
{
Object::Ptr result;
DynamicAny value = get(key);
if ( value.type() == typeid(Object::Ptr) )
{
result = value.extract<Object::Ptr>();
}
return result;
}
void Object::getNames(std::vector<std::string>& names) const
{
names.clear();
for(ValueMap::const_iterator it = _values.begin(); it != _values.end(); ++it)
{
names.push_back(it->first);
}
}
void Object::stringify(std::ostream& out, unsigned int indent) const
{
out << '{';
if ( indent > 0 )
{
out << std::endl;
}
for(ValueMap::const_iterator it = _values.begin(); it != _values.end();)
{
for(int i = 0; i < indent; i++)
{
out << ' ';
}
out << '"' << it->first << '"';
out << (( indent > 0 ) ? " : " : ":");
Stringifier::stringify(it->second, out, indent);
if ( ++it != _values.end() )
{
out << ',';
}
if ( indent > 0 )
{
out << std::endl;
}
}
if ( indent > 0 )
indent -= 2;
for(int i = 0; i < indent; i++)
{
out << ' ';
}
out << '}';
}
}} // Namespace Poco::JSON

678
JSON/src/Parser.cpp Normal file
View File

@@ -0,0 +1,678 @@
//
// Parser.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: Parser
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Ascii.h"
#include "Poco/Token.h"
#include "Poco/JSON/Parser.h"
#include "Poco/JSON/JSONException.h"
namespace Poco
{
namespace JSON
{
class SeparatorToken: public Token
{
public:
SeparatorToken()
{
}
virtual ~SeparatorToken()
{
}
Class tokenClass() const
{
return Token::SEPARATOR_TOKEN;
}
bool start(char c, std::istream& istr)
{
if ( c == '{'
|| c == '}'
|| c == ']'
|| c == '['
|| c == ','
|| c == ':' )
{
_value = c;
return true;
}
if ( c == '\'' )
{
throw JSONException("Invalid quote found");
}
else return false;
}
void finish(std::istream& istr)
{
}
};
class StringToken: public Token
{
public:
StringToken()
{
}
virtual ~StringToken()
{
}
Class tokenClass() const
{
return Token::STRING_LITERAL_TOKEN;
}
bool start(char c, std::istream& istr)
{
if ( c == '"')
{
_value = ""; // We don't need the quote!
return true;
}
else return false;
}
void finish(std::istream& istr)
{
int c = istr.get();
while (c != -1)
{
if ( c == 0 )
{
throw JSONException("Null byte not allowed");
}
if ( 0 < c && c <= 0x1F )
{
throw JSONException(format("Control character 0x%x not allowed", (unsigned int) c));
}
if ( c == '"' )
break;
if ( c == '\\' ) // Escaped String
{
c = istr.get();
switch(c)
{
case '"' :
c = '"';
break;
case '\\' :
c = '\\';
break;
case '/' :
c = '/';
break;
case 'b' :
c = '\b';
break;
case 'f' :
c = '\f';
break;
case 'n' :
c = '\n';
break;
case 'r' :
c = '\r';
break;
case 't' :
c = '\t';
break;
case 'u' : // Unicode
{
Poco::Int32 unicode = decodeUnicode(istr);
if ( unicode == 0 )
{
throw JSONException("\\u0000 is not allowed");
}
if ( unicode >= 0xD800 && unicode <= 0xDBFF )
{
c = istr.get();
if ( c != '\\' )
{
throw JSONException("Invalid unicode surrogate pair");
}
c = istr.get();
if ( c != 'u' )
{
throw JSONException("Invalid unicode surrogate pair");
}
Poco::Int32 surrogatePair = decodeUnicode(istr);
if ( 0xDC00 <= surrogatePair && surrogatePair <= 0xDFFF )
{
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
}
else
{
throw JSONException("Invalid unicode surrogate pair");
}
}
else if ( 0xDC00 <= unicode && unicode <= 0xDFFF )
{
throw JSONException("Invalid unicode");
}
c = unicode;
break;
}
default:
{
throw JSONException(format("Invalid escape '%c' character used", (char) c));
}
}
}
_value += c;
c = istr.get();
}
if ( c == -1 )
{
throw JSONException("Unterminated string found");
}
}
Poco::Int32 decodeUnicode(std::istream& istr)
{
Poco::Int32 value = 0;
for(int i = 0; i < 4; i++)
{
value <<= 4;
int nc = istr.peek();
if ( nc == -1 )
{
throw JSONException("Invalid unicode sequence");
}
istr.get(); // No EOF, so read the character
if (nc >= '0' && nc <= '9')
value += nc - '0';
else if (nc >= 'A' && nc <= 'F')
value += 10 + nc - 'A';
else if (nc >= 'a' && nc <= 'f')
value += 10 + nc - 'a';
else
throw JSONException("Invalid unicode sequence. Hexadecimal digit expected");
}
return value;
}
};
class KeywordToken : public Token
{
public:
KeywordToken()
{
}
virtual ~KeywordToken()
{
}
Class tokenClass() const
{
return Token::KEYWORD_TOKEN;
}
bool start(char c, std::istream& istr)
{
if ( Ascii::isAlpha(c) )
{
_value = c;
return true;
}
return false;
}
void finish(std::istream& istr)
{
int c = istr.peek();
while (c != -1 && Ascii::isAlpha(c) )
{
istr.get();
_value += c;
c = istr.peek();
}
}
};
class NumberToken: public Token
{
public:
NumberToken() : _activeClass(INTEGER_LITERAL_TOKEN)
{
}
virtual ~NumberToken()
{
}
Class tokenClass() const
{
return _activeClass;
}
bool start(char c, std::istream& istr)
{
// Reset the active class to integer
_activeClass = INTEGER_LITERAL_TOKEN;
if ( c == -1 )
return false;
if ( Ascii::isDigit(c) )
{
if ( c == '0' )
{
int nc = istr.peek();
if ( Ascii::isDigit(nc) ) // A digit after a zero is not allowed
{
throw JSONException("Number can't start with a zero");
}
}
_value = c;
return true;
}
if ( c == '-' )
{
_value = c;
int nc = istr.peek();
if ( Ascii::isDigit(nc) )
{
if ( nc == '0' )
{
_value += '0';
istr.get();
nc = istr.peek();
if ( Ascii::isDigit(nc) ) // A digit after -0 is not allowed
{
throw JSONException("Number can't start with a zero");
}
}
return true;
}
}
return false;
}
void finish(std::istream& istr)
{
int c;
while( (c = istr.peek()) != -1)
{
if ( Ascii::isDigit(c) )
{
_value += c;
istr.get();
}
else
{
switch(c)
{
case '.': // Float
{
if ( _activeClass == Token::FLOAT_LITERAL_TOKEN )
{
throw JSONException("Invalid float value");
}
_activeClass = Token::FLOAT_LITERAL_TOKEN;
_value += c;
istr.get();
// After a . we need a digit
c = istr.peek();
if ( ! Ascii::isDigit(c) )
{
throw JSONException("Invalid float value");
}
break;
}
case 'E':
case 'e':
{
if ( _activeClass == Token::DOUBLE_LITERAL_TOKEN )
{
throw JSONException("Invalid double value");
}
_activeClass = Token::DOUBLE_LITERAL_TOKEN;
// Add the e or E
_value += c;
istr.get();
// When the next char is - or + then read the next char
c = istr.peek();
if ( c == '-' || c == '+' )
{
_value += c;
istr.get();
c = istr.peek();
}
if ( ! Ascii::isDigit(c) )
{
throw JSONException("Invalid double value");
}
break;
}
default:
return; // End of number token
}
istr.get(); // If we get here we have a valid character for a number
_value += c;
}
}
}
private:
Class _activeClass;
};
Parser::Parser() : _tokenizer(), _handler(NULL)
{
_tokenizer.addToken(new WhitespaceToken());
_tokenizer.addToken(new InvalidToken());
_tokenizer.addToken(new SeparatorToken());
_tokenizer.addToken(new StringToken());
_tokenizer.addToken(new NumberToken());
_tokenizer.addToken(new KeywordToken());
}
Parser::~Parser()
{
}
const Token* Parser::nextToken()
{
const Token* token = _tokenizer.next();
if ( token->is(Token::EOF_TOKEN) )
{
throw JSONException("Unexpected EOF found");
}
return token;
}
void Parser::parse(std::istream& in)
{
_tokenizer.attachToStream(in);
const Token* token = nextToken();
if ( token->is(Token::SEPARATOR_TOKEN) )
{
// This must be a { or a [
if ( token->asChar() == '{' )
{
readObject();
}
else if ( token->asChar() == '[' )
{
readArray();
}
else
{
throw JSONException(format("Invalid separator '%c' found. Expecting { or [", token->asChar()));
}
token = _tokenizer.next();
if ( ! token->is(Token::EOF_TOKEN) )
{
throw JSONException(format("EOF expected but found '%s'", token->asString()));
}
}
else
{
throw JSONException(format("Invalid token '%s' found. Expecting { or [", token->asString()));
}
}
void Parser::readObject()
{
if ( _handler != NULL )
{
_handler->startObject();
}
if ( readRow(true) ) // First call is special: check for empty object
{
while(readRow());
}
if ( _handler != NULL )
{
_handler->endObject();
}
}
bool Parser::readRow(bool firstCall)
{
const Token* token = nextToken();
if ( firstCall && token->tokenClass() == Token::SEPARATOR_TOKEN && token->asChar() == '}' )
{
return false; // End of object is possible for an empty object
}
if ( token->tokenClass() == Token::STRING_LITERAL_TOKEN )
{
std::string propertyName = token->tokenString();
if ( _handler != NULL )
{
_handler->key(propertyName);
}
token = nextToken();
if ( token->is(Token::SEPARATOR_TOKEN)
&& token->asChar() == ':' )
{
readValue(nextToken());
token = nextToken();
if ( token->is(Token::SEPARATOR_TOKEN) )
{
if ( token->asChar() == ',' )
{
return true; // Read next row
}
else if ( token->asChar() == '}' )
{
return false; // End of object
}
else
{
throw JSONException(format("Invalid separator '%c' found. Expecting , or }", token->asChar()));
}
}
else
{
throw JSONException(format("Invalid token '%s' found. Expecting , or }", token->asString()));
}
}
else
{
throw JSONException(format("Invalid token '%s' found. Expecting :", token->asString()));
}
}
else
{
throw JSONException(format("Invalid token '%s' found. Expecting key", token->asString()));
}
}
void Parser::readValue(const Token* token)
{
switch(token->tokenClass())
{
case Token::INTEGER_LITERAL_TOKEN:
if ( _handler != NULL )
{
_handler->value(token->asInteger());
}
break;
case Token::KEYWORD_TOKEN:
{
if ( token->tokenString().compare("null") == 0 )
{
if ( _handler != NULL )
{
_handler->null();
}
}
else if ( token->tokenString().compare("true") == 0 )
{
if ( _handler != NULL )
{
_handler->value(true);
}
}
else if ( token->tokenString().compare("false") == 0 )
{
if ( _handler != NULL )
{
_handler->value(false);
}
}
else
{
throw JSONException(format("Invalid keyword '%s' found", token->asString()));
}
break;
}
case Token::FLOAT_LITERAL_TOKEN:
// Fall through
case Token::DOUBLE_LITERAL_TOKEN:
if ( _handler != NULL )
{
_handler->value(token->asFloat());
}
break;
case Token::STRING_LITERAL_TOKEN:
if ( _handler != NULL )
{
_handler->value(token->tokenString());
}
break;
case Token::SEPARATOR_TOKEN:
{
if ( token->asChar() == '{' )
{
readObject();
}
else if ( token->asChar() == '[' )
{
readArray();
}
break;
}
}
}
void Parser::readArray()
{
if ( _handler != NULL )
{
_handler->startArray();
}
if ( readElements(true) ) // First call is special: check for empty array
{
while(readElements());
}
if ( _handler != NULL )
{
_handler->endArray();
}
}
bool Parser::readElements(bool firstCall)
{
const Token* token = nextToken();
if ( firstCall && token->is(Token::SEPARATOR_TOKEN) && token->asChar() == ']' )
{
// End of array is possible for an empty array
return false;
}
readValue(token);
token = nextToken();
if ( token->is(Token::SEPARATOR_TOKEN) )
{
if ( token->asChar() == ']' )
return false; // End of array
if ( token->asChar() == ',' )
return true;
throw JSONException(format("Invalid separator '%c' found. Expecting , or ]", token->asChar()));
}
throw JSONException(format("Invalid token '%s' found.", token->asString()));
}
}}

141
JSON/src/Query.cpp Normal file
View File

@@ -0,0 +1,141 @@
//
// Query.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: Query
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include <sstream>
#include "Poco/StringTokenizer.h"
#include "Poco/RegularExpression.h"
#include "Poco/NumberParser.h"
#include "Poco/JSON/Query.h"
namespace Poco
{
namespace JSON
{
Query::Query(const DynamicAny& source) : _source(source)
{
}
Query::~Query()
{
}
Object::Ptr Query::findObject(const std::string& path) const
{
Object::Ptr obj;
DynamicAny result = find(path);
if ( result.type() == typeid(Object::Ptr) )
{
obj = result.extract<Object::Ptr>();
}
return obj;
}
Array::Ptr Query::findArray(const std::string& path) const
{
Array::Ptr arr;
DynamicAny result = find(path);
if ( result.type() == typeid(Array::Ptr) )
{
arr = result.extract<Array::Ptr>();
}
return arr;
}
DynamicAny Query::find(const std::string& path) const
{
DynamicAny result = _source;
StringTokenizer tokenizer(path, ".");
for(StringTokenizer::Iterator token = tokenizer.begin(); token != tokenizer.end(); token++)
{
if ( !result.isEmpty() )
{
std::vector<int> indexes;
RegularExpression::MatchVec matches;
int firstOffset = -1;
int offset = 0;
RegularExpression regex("\\[([0-9]+)\\]");
while(regex.match(*token, offset, matches) > 0 )
{
if ( firstOffset == -1 )
{
firstOffset = matches[0].offset;
}
std::string num = token->substr(matches[1].offset, matches[1].length);
indexes.push_back(NumberParser::parse(num));
offset = matches[0].offset + matches[0].length;
}
std::string name(*token);
if ( firstOffset != -1 )
{
name = name.substr(0, firstOffset);
}
if ( name.length() > 0 )
{
if ( result.type() == typeid(Object::Ptr) )
{
Object::Ptr o = result.extract<Object::Ptr>();
result = o->get(name);
}
}
if ( !result.isEmpty()
&& !indexes.empty() )
{
for(std::vector<int>::iterator it = indexes.begin(); it != indexes.end(); ++it )
{
if ( result.type() == typeid(Array::Ptr) )
{
Array::Ptr array = result.extract<Array::Ptr>();
result = array->get(*it);
if ( result.isEmpty() )
{
break;
}
}
}
}
}
}
return result;
}
}} // Namespace Poco::JSON

114
JSON/src/Stringifier.cpp Normal file
View File

@@ -0,0 +1,114 @@
//
// Stringifier.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: Stringifier
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include <iomanip>
#include "Poco/JSON/Stringifier.h"
#include "Poco/JSON/Array.h"
#include "Poco/JSON/Object.h"
namespace Poco
{
namespace JSON
{
void Stringifier::stringify(const DynamicAny& any, std::ostream& out, unsigned int indent)
{
if ( any.type() == typeid(Object::Ptr) )
{
const Object::Ptr& o = any.extract<Object::Ptr>();
o->stringify(out, indent == 0 ? 0 : indent + 2);
}
else if ( any.type() == typeid(Array::Ptr) )
{
const Array::Ptr& a = any.extract<Array::Ptr>();
a->stringify(out, indent == 0 ? 0 : indent + 2);
}
else if ( any.isEmpty() )
{
out << "null";
}
else if ( any.isString() )
{
out << '"';
std::string value = any.convert<std::string>();
for(std::string::const_iterator it = value.begin(); it != value.end(); ++it)
{
switch (*it)
{
case '"':
out << "\\\"";
break;
case '\\':
out << "\\\\";
break;
case '\b':
out << "\\b";
break;
case '\f':
out << "\\f";
break;
case '\n':
out << "\\n";
break;
case '\r':
out << "\\r";
break;
case '\t':
out << "\\t";
break;
default:
{
if ( *it > 0 && *it <= 0x1F )
{
out << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*it);
}
else
{
out << *it;
}
break;
}
}
}
out << '"';
}
else
{
out << any.convert<std::string>();
}
}
}} // Namespace Poco::JSON

736
JSON/src/Template.cpp Normal file
View File

@@ -0,0 +1,736 @@
//
// Template.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: Template
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/File.h"
#include "Poco/FileStream.h"
#include "Poco/JSON/Template.h"
#include "Poco/JSON/TemplateCache.h"
#include "Poco/JSON/Query.h"
namespace Poco
{
namespace JSON
{
POCO_IMPLEMENT_EXCEPTION(JSONTemplateException, Exception, "Template Exception")
class Part
{
public:
Part()
{
}
virtual ~Part()
{
}
virtual void render(const DynamicAny& data, std::ostream& out) const = 0;
typedef std::vector<SharedPtr<Part> > VectorParts;
};
class StringPart : public Part
{
public:
StringPart() : Part()
{
}
StringPart(const std::string& content) : Part(), _content(content)
{
}
virtual ~StringPart()
{
}
void render(const DynamicAny& data, std::ostream& out) const
{
out << _content;
}
void setContent(const std::string& content)
{
_content = content;
}
inline std::string getContent() const
{
return _content;
}
private:
std::string _content;
};
class MultiPart : public Part
{
public:
MultiPart()
{
}
virtual ~MultiPart()
{
}
virtual void addPart(Part* part)
{
_parts.push_back(part);
}
void render(const DynamicAny& data, std::ostream& out) const
{
for(VectorParts::const_iterator it = _parts.begin(); it != _parts.end(); ++it)
{
(*it)->render(data, out);
}
}
protected:
VectorParts _parts;
};
class EchoPart : public Part
{
public:
EchoPart(const std::string& query) : Part(), _query(query)
{
}
virtual ~EchoPart()
{
}
void render(const DynamicAny& data, std::ostream& out) const
{
Query query(data);
DynamicAny value = query.find(_query);
if ( ! value.isEmpty() )
{
out << value.convert<std::string>();
}
}
private:
std::string _query;
};
class LogicQuery
{
public:
LogicQuery(const std::string& query) : _queryString(query)
{
}
virtual ~LogicQuery()
{
}
virtual bool apply(const DynamicAny& data) const
{
bool logic = false;
Query query(data);
DynamicAny value = query.find(_queryString);
if ( ! value.isEmpty() ) // When empty, logic will be false
{
if ( value.isString() )
// An empty string must result in false, otherwise true
// Which is not the case when we convert to bool with DynamicAny
{
std::string s = value.convert<std::string>();
logic = ! s.empty();
}
else
{
// All other values, try to convert to bool
// An empty object or array will turn into false
// all other values depend on the convert<> in DynamicAny
logic = value.convert<bool>();
}
}
return logic;
}
protected:
std::string _queryString;
};
class LogicExistQuery : public LogicQuery
{
public:
LogicExistQuery(const std::string& query) : LogicQuery(query)
{
}
virtual ~LogicExistQuery()
{
}
virtual bool apply(const DynamicAny& data) const
{
Query query(data);
DynamicAny value = query.find(_queryString);
return !value.isEmpty();
}
};
class LogicElseQuery : public LogicQuery
{
public:
LogicElseQuery() : LogicQuery("")
{
}
virtual ~LogicElseQuery()
{
}
virtual bool apply(const DynamicAny& data) const
{
return true;
}
};
class LogicPart : public MultiPart
{
public:
LogicPart() : MultiPart()
{
}
virtual ~LogicPart()
{
}
void addPart(LogicQuery* query, Part* part)
{
MultiPart::addPart(part);
_queries.push_back(query);
}
void addPart(Part* part)
{
MultiPart::addPart(part);
_queries.push_back(new LogicElseQuery());
}
void render(const DynamicAny& data, std::ostream& out) const
{
int count = 0;
for(std::vector<SharedPtr<LogicQuery> >::const_iterator it = _queries.begin(); it != _queries.end(); ++it, ++count)
{
if( (*it)->apply(data) && _parts.size() > count )
{
_parts[count]->render(data, out);
break;
}
}
}
private:
std::vector<SharedPtr<LogicQuery> > _queries;
};
class LoopPart : public MultiPart
{
public:
LoopPart(const std::string& name, const std::string& query) : MultiPart(), _name(name), _query(query)
{
}
virtual ~LoopPart()
{
}
void render(const DynamicAny& data, std::ostream& out) const
{
Query query(data);
if ( data.type() == typeid(Object::Ptr) )
{
Object::Ptr dataObject = data.extract<Object::Ptr>();
Array::Ptr array = query.findArray(_query);
if ( ! array.isNull() )
{
for(int i = 0; i < array->size(); i++)
{
DynamicAny value = array->get(i);
dataObject->set(_name, value);
MultiPart::render(data, out);
}
dataObject->remove(_name);
}
}
}
private:
std::string _name;
std::string _query;
};
class IncludePart : public Part
{
public:
IncludePart(const Path& parentPath, const Path& path)
: Part()
, _path(path)
{
// When the path is relative, try to make it absolute based
// on the path of the parent template. When the file doesn't
// exist, we keep it relative and hope that the cache can
// resolve it.
if ( _path.isRelative() )
{
Path templatePath(parentPath, _path);
File templateFile(templatePath);
if ( templateFile.exists() )
{
_path = templatePath;
}
}
}
virtual ~IncludePart()
{
}
void render(const DynamicAny& data, std::ostream& out) const
{
TemplateCache* cache = TemplateCache::instance();
if ( cache == NULL )
{
Template tpl(_path);
tpl.parse();
tpl.render(data, out);
}
else
{
Template::Ptr tpl = cache->getTemplate(_path);
tpl->render(data, out);
}
}
private:
Path _path;
};
Template::Template(const Path& templatePath)
: _parts(NULL)
, _templatePath(templatePath)
{
}
Template::Template()
: _parts(NULL)
{
}
Template::~Template()
{
if ( _parts != NULL )
{
delete _parts;
}
}
void Template::parse()
{
File file(_templatePath);
if ( file.exists() )
{
FileInputStream fis(_templatePath.toString());
parse(fis);
}
}
void Template::parse(std::istream& in)
{
_parseTime.update();
_parts = new MultiPart();
_currentPart = _parts;
while(in.good())
{
std::string text = readText(in); // Try to read text first
if ( text.length() > 0 )
{
_currentPart->addPart(new StringPart(text));
}
if ( in.bad() )
break; // Nothing to do anymore
std::string command = readTemplateCommand(in); // Try to read a template command
if ( command.empty() )
{
break;
}
readWhiteSpace(in);
if ( command.compare("echo") == 0 )
{
std::string query = readQuery(in);
if ( query.empty() )
{
throw JSONTemplateException("Missing query in <? echo ?>");
}
_currentPart->addPart(new EchoPart(query));
}
else if ( command.compare("for") == 0 )
{
std::string loopVariable = readWord(in);
if ( loopVariable.empty() )
{
throw JSONTemplateException("Missing variable in <? for ?> command");
}
readWhiteSpace(in);
std::string query = readQuery(in);
if ( query.empty() )
{
throw JSONTemplateException("Missing query in <? for ?> command");
}
_partStack.push(_currentPart);
LoopPart* part = new LoopPart(loopVariable, query);
_partStack.push(part);
_currentPart->addPart(part);
_currentPart = part;
}
else if ( command.compare("else") == 0 )
{
if ( _partStack.size() == 0 )
{
throw JSONTemplateException("Unexpected <? else ?> found");
}
_currentPart = _partStack.top();
LogicPart* lp = dynamic_cast<LogicPart*>(_currentPart);
if ( lp == NULL )
{
throw JSONTemplateException("Missing <? if ?> or <? ifexist ?> for <? else ?>");
}
MultiPart* part = new MultiPart();
lp->addPart(part);
_currentPart = part;
}
else if ( command.compare("elsif") == 0
|| command.compare("elif") == 0 )
{
std::string query = readQuery(in);
if ( query.empty() )
{
throw JSONTemplateException("Missing query in <? " + command + " ?>");
}
if ( _partStack.size() == 0 )
{
throw JSONTemplateException("Unexpected <? elsif / elif ?> found");
}
_currentPart = _partStack.top();
LogicPart* lp = dynamic_cast<LogicPart*>(_currentPart);
if ( lp == NULL )
{
throw JSONTemplateException("Missing <? if ?> or <? ifexist ?> for <? elsif / elif ?>");
}
MultiPart* part = new MultiPart();
lp->addPart(new LogicQuery(query), part);
_currentPart = part;
}
else if ( command.compare("endfor") == 0 )
{
if ( _partStack.size() < 2 )
{
throw JSONTemplateException("Unexpected <? endfor ?> found");
}
MultiPart* loopPart = _partStack.top();
LoopPart* lp = dynamic_cast<LoopPart*>(loopPart);
if ( lp == NULL )
{
throw JSONTemplateException("Missing <? for ?> command");
}
_partStack.pop();
_currentPart = _partStack.top();
_partStack.pop();
}
else if ( command.compare("endif") == 0 )
{
if ( _partStack.size() < 2 )
{
throw JSONTemplateException("Unexpected <? endif ?> found");
}
_currentPart = _partStack.top();
LogicPart* lp = dynamic_cast<LogicPart*>(_currentPart);
if ( lp == NULL )
{
throw JSONTemplateException("Missing <? if ?> or <? ifexist ?> for <? endif ?>");
}
_partStack.pop();
_currentPart = _partStack.top();
_partStack.pop();
}
else if ( command.compare("if") == 0
|| command.compare("ifexist") == 0 )
{
std::string query = readQuery(in);
if ( query.empty() )
{
throw JSONTemplateException("Missing query in <? " + command + " ?>");
}
_partStack.push(_currentPart);
LogicPart* lp = new LogicPart();
_partStack.push(lp);
_currentPart->addPart(lp);
_currentPart = new MultiPart();
if ( command.compare("ifexist") == 0 )
{
lp->addPart(new LogicExistQuery(query), _currentPart);
}
else
{
lp->addPart(new LogicQuery(query), _currentPart);
}
}
else if ( command.compare("include") == 0 )
{
readWhiteSpace(in);
std::string filename = readString(in);
if ( filename.empty() )
{
throw JSONTemplateException("Missing filename in <? include ?>");
}
else
{
Path resolvePath(_templatePath);
resolvePath.makeParent();
_currentPart->addPart(new IncludePart(resolvePath, filename));
}
}
else
{
throw JSONTemplateException("Unknown command " + command);
}
readWhiteSpace(in);
int c = in.get();
if ( c == '?' && in.peek() == '>' )
{
in.get(); // forget '>'
if ( command.compare("echo") != 0 )
{
if ( in.peek() == '\r' )
{
in.get();
}
if ( in.peek() == '\n' )
{
in.get();
}
}
}
else
{
throw JSONTemplateException("Missing ?>");
}
}
}
std::string Template::readText(std::istream& in)
{
std::string text;
int c = in.get();
while(c != -1)
{
if ( c == '<' )
{
if ( in.peek() == '?' )
{
in.get(); // forget '?'
break;
}
}
text += c;
c = in.get();
}
return text;
}
std::string Template::readTemplateCommand(std::istream& in)
{
std::string command;
readWhiteSpace(in);
int c = in.get();
while(c != -1)
{
if ( Ascii::isSpace(c) )
break;
if ( c == '?' && in.peek() == '>' )
{
in.putback(c);
break;
}
if ( c == '=' && command.length() == 0 )
{
command = "echo";
break;
}
command += c;
c = in.get();
}
return command;
}
std::string Template::readWord(std::istream& in)
{
std::string word;
int c;
while((c = in.peek()) != -1 && ! Ascii::isSpace(c))
{
in.get();
word += c;
}
return word;
}
std::string Template::readQuery(std::istream& in)
{
std::string word;
int c;
while((c = in.get()) != -1)
{
if ( c == '?' && in.peek() == '>' )
{
in.putback(c);
break;
}
if ( Ascii::isSpace(c) )
{
break;
}
word += c;
}
return word;
}
void Template::readWhiteSpace(std::istream& in)
{
int c;
while((c = in.peek()) != -1 && Ascii::isSpace(c))
{
in.get();
}
}
std::string Template::readString(std::istream& in)
{
std::string str;
int c = in.get();
if ( c == '"' )
{
while((c = in.get()) != -1 && c != '"')
{
str += c;
}
}
return str;
}
void Template::render(const DynamicAny& data, std::ostream& out) const
{
_parts->render(data, out);
}
}} // Namespace Poco::JSON

172
JSON/src/TemplateCache.cpp Normal file
View File

@@ -0,0 +1,172 @@
//
// TemplateCache.cpp
//
// $Id$
//
// Library: JSON
// Package: JSON
// Module: TemplateCache
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/File.h"
#include "Poco/JSON/TemplateCache.h"
namespace Poco
{
namespace JSON
{
TemplateCache* TemplateCache::_instance = NULL;
TemplateCache::TemplateCache() : _logger(NULL)
{
setup();
}
TemplateCache::~TemplateCache()
{
_instance = NULL;
}
void TemplateCache::setup()
{
poco_assert (_instance == NULL);
_instance = this;
}
Template::Ptr TemplateCache::getTemplate(const Path& path)
{
if ( _logger )
{
poco_trace_f1(*_logger, "Trying to load %s", path.toString());
}
Path templatePath = resolvePath(path);
std::string templatePathname = templatePath.toString();
if ( _logger )
{
poco_trace_f1(*_logger, "Path resolved to %s", templatePathname);
}
File templateFile(templatePathname);
Template::Ptr tpl;
std::map<std::string, Template::Ptr>::iterator it = _cache.find(templatePathname);
if ( it == _cache.end() )
{
if ( templateFile.exists() )
{
if ( _logger )
{
poco_information_f1(*_logger, "Loading template %s", templatePath.toString());
}
tpl = new Template(templatePath);
try
{
tpl->parse();
_cache[templatePathname] = tpl;
}
catch(JSONTemplateException jte)
{
if ( _logger )
{
poco_error_f2(*_logger, "Template %s contains an error: %s", templatePath.toString(), jte.message());
}
}
}
else
{
if ( _logger )
{
poco_error_f1(*_logger, "Template file %s doesn't exist", templatePath.toString());
}
throw FileNotFoundException(templatePathname);
}
}
else
{
tpl = it->second;
if ( tpl->parseTime() < templateFile.getLastModified() )
{
if ( _logger )
{
poco_information_f1(*_logger, "Reloading template %s", templatePath.toString());
}
tpl = new Template(templatePath);
try
{
tpl->parse();
_cache[templatePathname] = tpl;
}
catch(JSONTemplateException jte)
{
if ( _logger )
{
poco_error_f2(*_logger, "Template %s contains an error: %s", templatePath.toString(), jte.message());
}
}
}
}
return tpl;
}
Path TemplateCache::resolvePath(const Path& path) const
{
if ( path.isAbsolute() )
return path;
for(std::vector<Path>::const_iterator it = _includePaths.begin(); it != _includePaths.end(); ++it)
{
Path templatePath(*it, path);
File templateFile(templatePath);
if ( templateFile.exists() )
{
if ( _logger )
{
poco_trace_f2(*_logger, "%s template file resolved to %s", path.toString(), templatePath.toString());
}
return templatePath;
}
if ( _logger )
{
poco_trace_f1(*_logger, "%s doesn't exist", templatePath.toString());
}
}
throw FileNotFoundException(path.toString());
}
}} // Poco::JSON