1
0
Fork 0
arangodb/JsonParserX/InputParser.cpp

778 lines
22 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// @brief input parsers
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "InputParser.h"
#include <Basics/Exceptions.h>
#include <Variant/VariantArray.h>
#include <Variant/VariantBoolean.h>
#include <Variant/VariantDouble.h>
#include <Variant/VariantInt64.h>
#include <Variant/VariantNull.h>
#include <Variant/VariantObject.h>
#include <Variant/VariantString.h>
#include <Variant/VariantVector.h>
#include <Rest/HttpRequest.h>
#include "JsonParserX/JsonParserXDriver.h"
using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
// -----------------------------------------------------------------------------
// helper functions
// -----------------------------------------------------------------------------
namespace triagens {
namespace rest {
enum ObjectDescriptionType {
OD_BOOLEAN,
OD_DOUBLE,
OD_INTEGER,
OD_STRING,
OD_STRING_LIST,
OD_VARIANT_ARRAY,
OD_VARIANT_BOOLEAN,
OD_VARIANT_DOUBLE,
OD_VARIANT_INTEGER,
OD_VARIANT_NULL,
OD_VARIANT_STRING,
OD_VARIANT_STRING_LIST,
OD_VARIANT_VECTOR
};
struct AttributeDescription {
AttributeDescription () {
}
AttributeDescription (ObjectDescriptionType type, void* store, bool* hasAttribute)
: type(type), store(store), hasAttribute(hasAttribute) {
}
ObjectDescriptionType type;
void* store;
bool* hasAttribute;
};
}
}
namespace {
void clearObject (ObjectDescriptionType type, void* store) {
switch (type) {
case OD_BOOLEAN:
*reinterpret_cast<bool*>(store) = false;
break;
case OD_DOUBLE:
*reinterpret_cast<double*>(store) = false;
break;
case OD_INTEGER:
*reinterpret_cast<int64_t*>(store) = 0;
break;
case OD_STRING:
*reinterpret_cast<string*>(store) = "";
break;
case OD_VARIANT_ARRAY:
case OD_VARIANT_BOOLEAN:
case OD_VARIANT_DOUBLE:
case OD_VARIANT_INTEGER:
case OD_VARIANT_NULL:
case OD_VARIANT_STRING:
case OD_VARIANT_VECTOR:
*reinterpret_cast<void**>(store) = 0;
break;
case OD_STRING_LIST:
case OD_VARIANT_STRING_LIST:
break;
}
}
bool checkObjectType (string const& name, ObjectDescriptionType type, VariantObject* object, string& errorMessage) {
char const* expecting;
VariantObject::ObjectType otype;
switch (type) {
case OD_VARIANT_ARRAY:
expecting = "ARRAY";
otype = VariantObject::VARIANT_ARRAY;
break;
case OD_BOOLEAN:
case OD_VARIANT_BOOLEAN:
expecting = "BOOLEAN";
otype = VariantObject::VARIANT_BOOLEAN;
break;
case OD_DOUBLE:
case OD_VARIANT_DOUBLE:
expecting = "DOUBLE";
otype = VariantObject::VARIANT_DOUBLE;
break;
case OD_INTEGER:
case OD_VARIANT_INTEGER:
expecting = "INTEGER";
otype = VariantObject::VARIANT_INT64;
break;
case OD_VARIANT_NULL:
expecting = "NULL";
otype = VariantObject::VARIANT_NULL;
break;
case OD_STRING:
case OD_VARIANT_STRING:
expecting = "STRING";
otype = VariantObject::VARIANT_STRING;
break;
case OD_STRING_LIST:
case OD_VARIANT_STRING_LIST:
expecting = "VECTOR OF STRINGS";
otype = VariantObject::VARIANT_VECTOR;
break;
case OD_VARIANT_VECTOR:
expecting = "VECTOR";
otype = VariantObject::VARIANT_VECTOR;
break;
default:
THROW_INTERNAL_ERROR("wrong type");
}
if (otype != object->type()) {
errorMessage = "attribute '"
+ name
+ "' is of wrong type (expecting "
+ expecting
+ ", got "
+ VariantObject::NameObjectType(object->type())
+ ")";
return false;
}
else {
return true;
}
}
template<typename VT>
bool extractObjects (string const& name,
VariantVector* list,
ObjectDescriptionType type,
vector< VT* >* store,
string& errorMessage) {
vector<VariantObject*> const& values = list->getValues();
for (vector<VariantObject*>::const_iterator i = values.begin(); i != values.end(); ++i) {
VariantObject* object = *i;
bool ok = checkObjectType(name, type, object, errorMessage);
if (! ok) {
return false;
}
VT* vt = object->as<VT>();
store->push_back(vt);
}
return true;
}
template<typename VT, typename T>
bool extractObjects (string const& name,
VariantVector* list,
ObjectDescriptionType type,
vector< T >* store,
string& errorMessage) {
vector<VariantObject*> const& values = list->getValues();
for (vector<VariantObject*>::const_iterator i = values.begin(); i != values.end(); ++i) {
VariantObject* object = *i;
bool ok = checkObjectType(name, type, object, errorMessage);
if (! ok) {
return false;
}
VT* vt = object->as<VT>();
store->push_back(vt->getValue());
}
return true;
}
bool extractObject (string const& name,
VariantObject* object,
AttributeDescription const& desc,
string& errorMessage) {
switch (desc.type) {
case OD_VARIANT_ARRAY:
*reinterpret_cast<VariantArray**>(desc.store) = object->as<VariantArray>();
return true;
case OD_BOOLEAN:
*reinterpret_cast<bool*>(desc.store) = object->as<VariantBoolean>()->getValue();
return true;
case OD_VARIANT_BOOLEAN:
*reinterpret_cast<VariantBoolean**>(desc.store) = object->as<VariantBoolean>();
return true;
case OD_DOUBLE:
*reinterpret_cast<double*>(desc.store) = object->as<VariantDouble>()->getValue();
return true;
case OD_VARIANT_DOUBLE:
*reinterpret_cast<VariantDouble**>(desc.store) = object->as<VariantDouble>();
return true;
case OD_INTEGER:
*reinterpret_cast<int64_t*>(desc.store) = object->as<VariantInt64>()->getValue();
return true;
case OD_VARIANT_INTEGER:
*reinterpret_cast<VariantInt64**>(desc.store) = object->as<VariantInt64>();
return true;
case OD_VARIANT_NULL:
*reinterpret_cast<VariantNull**>(desc.store) = object->as<VariantNull>();
return true;
case OD_STRING:
*reinterpret_cast<string*>(desc.store) = object->as<VariantString>()->getValue();
return true;
case OD_VARIANT_STRING:
*reinterpret_cast<VariantString**>(desc.store) = object->as<VariantString>();
return true;
case OD_STRING_LIST:
return extractObjects<VariantString>(name,
object->as<VariantVector>(),
OD_VARIANT_STRING,
reinterpret_cast< vector<string>* >(desc.store),
errorMessage);
case OD_VARIANT_STRING_LIST:
return extractObjects(name,
object->as<VariantVector>(),
OD_VARIANT_STRING,
reinterpret_cast< vector<VariantString*>* >(desc.store),
errorMessage);
case OD_VARIANT_VECTOR:
*reinterpret_cast<VariantVector**>(desc.store) = object->as<VariantVector>();
return true;
default:
THROW_INTERNAL_ERROR("wrong type");
}
}
bool loadObject (VariantArray* array, string const& name, AttributeDescription const& desc, bool optional, string& errorMessage) {
clearObject(desc.type, desc.store);
if (desc.hasAttribute != 0) {
*desc.hasAttribute = false;
}
VariantObject* object = array->lookup(name);
if (object == 0) {
if (optional) {
return true;
}
else {
errorMessage = "attribute '" + name + "' not found";
return false;
}
}
if (object->is<VariantNull>() && optional) {
return true;
}
if (desc.hasAttribute != 0) {
*desc.hasAttribute = true;
}
bool ok = checkObjectType(name, desc.type, object, errorMessage);
if (! ok) {
return false;
}
return extractObject(name, object, desc, errorMessage);
}
bool loadAlternatives (VariantArray* array,
string const& name,
vector<AttributeDescription> const& alternatives,
string& errorMessage) {
for (vector<AttributeDescription>::const_iterator i = alternatives.begin(); i != alternatives.end(); ++i) {
clearObject(i->type, i->store);
}
VariantObject* object = array->lookup(name);
if (object == 0) {
return true;
}
for (vector<AttributeDescription>::const_iterator i = alternatives.begin(); i != alternatives.end(); ++i) {
AttributeDescription const& desc = *i;
if (checkObjectType(name, desc.type, object, errorMessage)) {
return extractObject(name, object, desc, errorMessage);
}
}
errorMessage = "attribute '" + name + "' is of wrong type";
return false;
}
}
namespace triagens {
namespace rest {
namespace InputParser {
// -----------------------------------------------------------------------------
// object description implementation
// -----------------------------------------------------------------------------
struct ObjectDescriptionImpl {
map< string, AttributeDescription > attributes;
map< string, AttributeDescription > optionals;
map< string, vector<AttributeDescription> > alternatives;
string lastError;
};
// -----------------------------------------------------------------------------
// object description
// -----------------------------------------------------------------------------
ObjectDescription::ObjectDescription () {
impl = new ObjectDescriptionImpl();
}
ObjectDescription::~ObjectDescription () {
delete impl;
}
string const& ObjectDescription::lastError () {
return impl->lastError;
}
bool ObjectDescription::parse (VariantObject* object) {
impl->lastError.clear();
// object must be a json array
if (object == 0) {
impl->lastError = "cannot parse object";
return false;
}
if (! object->is<VariantArray>()) {
impl->lastError = "not an object";
return false;
}
VariantArray* array = object->as<VariantArray>();
// now find the attributes, optionals, and alternatives
for (map<string, AttributeDescription>::iterator i = impl->attributes.begin(); i != impl->attributes.end(); ++i) {
string const& name = i->first;
AttributeDescription& desc = i->second;
bool ok = loadObject(array, name, desc, false, impl->lastError);
if (! ok) {
return false;
}
}
for (map<string, AttributeDescription>::iterator i = impl->optionals.begin(); i != impl->optionals.end(); ++i) {
string const& name = i->first;
AttributeDescription& desc = i->second;
bool ok = loadObject(array, name, desc, true, impl->lastError);
if (! ok) {
return false;
}
}
for (map< string, vector<AttributeDescription> >::iterator i = impl->alternatives.begin(); i != impl->alternatives.end(); ++i) {
string const& name = i->first;
bool ok = loadAlternatives(array, name, i->second, impl->lastError);
if (! ok) {
return false;
}
}
transform();
return true;
}
void ObjectDescription::transform () {
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// attribute
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ObjectDescription& ObjectDescription::attribute (string const& name, VariantArray*& store) {
impl->attributes[name] = AttributeDescription(OD_VARIANT_ARRAY, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, VariantBoolean*& store) {
impl->attributes[name] = AttributeDescription(OD_VARIANT_BOOLEAN, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, bool& store) {
impl->attributes[name] = AttributeDescription(OD_BOOLEAN, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, VariantDouble*& store) {
impl->attributes[name] = AttributeDescription(OD_VARIANT_DOUBLE, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, double& store) {
impl->attributes[name] = AttributeDescription(OD_DOUBLE, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, VariantInt64*& store) {
impl->attributes[name] = AttributeDescription(OD_VARIANT_INTEGER, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, int64_t& store) {
impl->attributes[name] = AttributeDescription(OD_INTEGER, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, VariantNull*& store) {
impl->attributes[name] = AttributeDescription(OD_VARIANT_NULL, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, VariantString*& store) {
impl->attributes[name] = AttributeDescription(OD_VARIANT_STRING, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, string& store) {
impl->attributes[name] = AttributeDescription(OD_STRING, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, vector<VariantString*>& store) {
impl->attributes[name] = AttributeDescription(OD_VARIANT_STRING_LIST, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, vector<string>& store) {
impl->attributes[name] = AttributeDescription(OD_STRING_LIST, reinterpret_cast<void*>(&store), 0);
return *this;
}
ObjectDescription& ObjectDescription::attribute (string const& name, VariantVector*& store) {
impl->attributes[name] = AttributeDescription(OD_VARIANT_VECTOR, reinterpret_cast<void*>(&store), 0);
return *this;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// optional
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ObjectDescription& ObjectDescription::optional (string const& name, VariantArray*& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_VARIANT_ARRAY, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, VariantBoolean*& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_VARIANT_BOOLEAN, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, bool& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_BOOLEAN, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, VariantDouble*& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_VARIANT_DOUBLE, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, double& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_DOUBLE, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, VariantInt64*& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_VARIANT_INTEGER, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, int64_t& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_INTEGER, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, VariantNull*& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_VARIANT_NULL, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, VariantString*& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_VARIANT_STRING, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, string& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_STRING, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, vector<VariantString*>& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_VARIANT_STRING_LIST, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, vector<string>& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_STRING_LIST, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
ObjectDescription& ObjectDescription::optional (string const& name, VariantVector*& store, bool* hasAttribute) {
impl->optionals[name] = AttributeDescription(OD_VARIANT_VECTOR, reinterpret_cast<void*>(&store), hasAttribute);
return *this;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// alternative
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ObjectDescription& ObjectDescription::alternative (string const& name, VariantArray*& store) {
impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_ARRAY, reinterpret_cast<void*>(&store), 0));
return *this;
}
ObjectDescription& ObjectDescription::alternative (string const& name, VariantBoolean*& store) {
impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_BOOLEAN, reinterpret_cast<void*>(&store), 0));
return *this;
}
ObjectDescription& ObjectDescription::alternative (string const& name, VariantInt64*& store) {
impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_INTEGER, reinterpret_cast<void*>(&store), 0));
return *this;
}
ObjectDescription& ObjectDescription::alternative (string const& name, VariantNull*& store) {
impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_NULL, reinterpret_cast<void*>(&store), 0));
return *this;
}
ObjectDescription& ObjectDescription::alternative (string const& name, VariantString*& store) {
impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_STRING, reinterpret_cast<void*>(&store), 0));
return *this;
}
ObjectDescription& ObjectDescription::alternative (string const& name, VariantVector*& store) {
impl->alternatives[name].push_back(AttributeDescription(OD_VARIANT_VECTOR, reinterpret_cast<void*>(&store), 0));
return *this;
}
// -----------------------------------------------------------------------------
// public fucntions
// -----------------------------------------------------------------------------
VariantObject* json (string const& input) {
JsonParserXDriver parser;
return parser.parse(input);
}
VariantObject* json (HttpRequest* request) {
JsonParserXDriver parser;
return parser.parse(request->body());
}
VariantArray* jsonArray (string const& input) {
JsonParserXDriver parser;
VariantObject* object = parser.parse(input);
if (object == 0) {
return 0;
}
else if (object->type() == VariantObject::VARIANT_ARRAY) {
return dynamic_cast<VariantArray*>(object);
}
else {
delete object;
return 0;
}
}
VariantArray* jsonArray (HttpRequest* request) {
JsonParserXDriver parser;
VariantObject* object = parser.parse(request->body());
if (object == 0) {
return 0;
}
else if (object->type() == VariantObject::VARIANT_ARRAY) {
return dynamic_cast<VariantArray*>(object);
}
else {
delete object;
return 0;
}
}
}
}
}