mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-21 15:51:43 +02:00
Copy JSON from SandBox to trunk
This commit is contained in:
147
JSON/src/Array.cpp
Normal file
147
JSON/src/Array.cpp
Normal 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
150
JSON/src/DefaultHandler.cpp
Normal 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
48
JSON/src/Handler.cpp
Normal 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
|
44
JSON/src/JSONException.cpp
Normal file
44
JSON/src/JSONException.cpp
Normal 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
155
JSON/src/Object.cpp
Normal 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
678
JSON/src/Parser.cpp
Normal 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
141
JSON/src/Query.cpp
Normal 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
114
JSON/src/Stringifier.cpp
Normal 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
736
JSON/src/Template.cpp
Normal 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
172
JSON/src/TemplateCache.cpp
Normal 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
|
Reference in New Issue
Block a user