mirror of https://gitee.com/bigwinds/arangodb
1196 lines
46 KiB
C++
1196 lines
46 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief json helper functions
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
|
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Jan Steemann
|
|
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
|
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef ARANGODB_BASICS_JSON_HELPER_H
|
|
#define ARANGODB_BASICS_JSON_HELPER_H 1
|
|
|
|
#include "Basics/Common.h"
|
|
#include "Basics/Exceptions.h"
|
|
#include "Basics/json.h"
|
|
#include "Basics/StringBuffer.h"
|
|
|
|
namespace triagens {
|
|
namespace basics {
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- class JsonHelper
|
|
// -----------------------------------------------------------------------------
|
|
|
|
class JsonHelper {
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- constructors / destructors
|
|
// -----------------------------------------------------------------------------
|
|
|
|
private:
|
|
|
|
JsonHelper () = delete;
|
|
~JsonHelper () = delete;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public static methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
public:
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief convert a uint64 into a JSON string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t* uint64String (TRI_memory_zone_t*,
|
|
uint64_t);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief convert a uint64 into a JSON string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static uint64_t stringUInt64 (TRI_json_t const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief convert a uint64 into a JSON string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static uint64_t stringUInt64 (TRI_json_t const*,
|
|
char const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates a JSON object from a key/value object of strings
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t* stringObject (TRI_memory_zone_t*,
|
|
std::map<std::string, std::string> const&);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates a key/value object of strings from a JSON (sub-) object
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::map<std::string, std::string> stringObject (TRI_json_t const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates a JSON object from an array of strings
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t* stringArray (TRI_memory_zone_t*,
|
|
std::vector<std::string> const&);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates an array of strings from a JSON (sub-) object
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::vector<std::string> stringArray (TRI_json_t const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create JSON from string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t* fromString (std::string const&);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create JSON from string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t* fromString (char const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create JSON from string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t* fromString (char const*,
|
|
size_t);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief stringify json
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::string toString (TRI_json_t const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns true for objects
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static inline bool isObject (TRI_json_t const* json) {
|
|
return json != nullptr && json->_type == TRI_JSON_OBJECT;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns true for arrays
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static inline bool isArray (TRI_json_t const* json) {
|
|
return json != nullptr && json->_type == TRI_JSON_ARRAY;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns true for strings
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static inline bool isString (TRI_json_t const* json) {
|
|
return TRI_IsStringJson(json);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns true for numbers
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static inline bool isNumber (TRI_json_t const* json) {
|
|
return json != nullptr && json->_type == TRI_JSON_NUMBER;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns true for booleans
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static inline bool isBoolean (TRI_json_t const* json) {
|
|
return json != nullptr && json->_type == TRI_JSON_BOOLEAN;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns an object sub-element
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t* getObjectElement (TRI_json_t const*,
|
|
char const* name);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a string element, or a default it is does not exist
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::string getStringValue (TRI_json_t const*,
|
|
std::string const&);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a string sub-element, or a default it is does not exist
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::string getStringValue (TRI_json_t const*,
|
|
char const*,
|
|
std::string const&);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a numeric value
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename T>
|
|
static T getNumericValue (TRI_json_t const* json,
|
|
T defaultValue) {
|
|
if (isNumber(json)) {
|
|
return (T) json->_value._number;
|
|
}
|
|
|
|
return defaultValue;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a numeric sub-element, or a default it is does not exist
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename T>
|
|
static T getNumericValue (TRI_json_t const* json,
|
|
char const* name,
|
|
T defaultValue) {
|
|
TRI_json_t const* sub = getObjectElement(json, name);
|
|
|
|
if (isNumber(sub)) {
|
|
return (T) sub->_value._number;
|
|
}
|
|
|
|
return defaultValue;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a boolean sub-element, or a default it is does not exist
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool getBooleanValue (TRI_json_t const*,
|
|
char const*,
|
|
bool);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a boolean sub-element, or a throws an exception if the
|
|
/// sub-element does not exist or if it is not boolean
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool checkAndGetBooleanValue (TRI_json_t const*,
|
|
char const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a numeric sub-element, or throws if <name> does not exist
|
|
/// or it is not a number
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<typename T>
|
|
static T checkAndGetNumericValue (TRI_json_t const* json,
|
|
char const* name) {
|
|
TRI_json_t const* sub = getObjectElement(json, name);
|
|
|
|
if (! isNumber(sub)) {
|
|
std::string msg = "The attribute '" + std::string(name)
|
|
+ "' was not found or is not a number.";
|
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
|
|
}
|
|
return static_cast<T>(sub->_value._number);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a string sub-element, or throws if <name> does not exist
|
|
/// or it is not a string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::string checkAndGetStringValue (TRI_json_t const*,
|
|
char const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns an object sub-element, or a throws an exception if the
|
|
/// sub-element does not exist or if it is not an object
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t const* checkAndGetObjectValue (TRI_json_t const*,
|
|
char const*);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns an array sub-element, or a throws an exception if the
|
|
/// sub-element does not exist or if it is not an array
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_json_t const* checkAndGetArrayValue (TRI_json_t const*,
|
|
char const*);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief JsonException, an exception class for the Json class
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class JsonException : public virtual std::exception {
|
|
std::string _msg;
|
|
public:
|
|
JsonException () : _msg("Json exception") {
|
|
#ifdef TRI_ENABLE_MAINTAINER_MODE
|
|
#if HAVE_BACKTRACE
|
|
_msg += std::string("\n\n");
|
|
TRI_GetBacktrace(_msg);
|
|
_msg += std::string("\n\n");
|
|
#endif
|
|
#endif
|
|
}
|
|
JsonException (std::string msg) : _msg(msg) {
|
|
#ifdef TRI_ENABLE_MAINTAINER_MODE
|
|
#if HAVE_BACKTRACE
|
|
_msg += std::string("\n\n");
|
|
TRI_GetBacktrace(_msg);
|
|
_msg += std::string("\n\n");
|
|
#endif
|
|
#endif
|
|
}
|
|
char const* what () const noexcept {
|
|
return _msg.c_str();
|
|
}
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Json, a class to fabricate TRI_json_t* conveniently
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class Json {
|
|
|
|
public:
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief enum for the type of a Json structure
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
enum type_e {
|
|
Null,
|
|
Bool,
|
|
Number,
|
|
String,
|
|
Array,
|
|
Object
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief enum to say whether we are automatically freeing the TRI_json_t*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
enum autofree_e {
|
|
AUTOFREE,
|
|
NOFREE
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
private:
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief internal helper for the generic constructor
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void make (type_e t, size_t sizeHint) {
|
|
// convert to an actual memory zone
|
|
TRI_memory_zone_t* zone = TRI_MemoryZone(_zone);
|
|
|
|
switch (t) {
|
|
case Null:
|
|
_json = TRI_CreateNullJson(zone);
|
|
break;
|
|
case Bool:
|
|
_json = TRI_CreateBooleanJson(zone, true);
|
|
break;
|
|
case Number:
|
|
_json = TRI_CreateNumberJson(zone, 0.0);
|
|
break;
|
|
case String:
|
|
_json = TRI_CreateStringCopyJson(zone, "", 0);
|
|
break;
|
|
case Array:
|
|
_json = TRI_CreateArrayJson(zone, sizeHint);
|
|
break;
|
|
case Object:
|
|
_json = TRI_CreateObjectJson(zone, 2 * sizeHint);
|
|
break;
|
|
}
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public constructors
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief default constructor making an empty Json
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
public:
|
|
|
|
explicit Json ()
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(AUTOFREE) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief generic constructor for a type_e
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (type_e t,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(autofree) {
|
|
|
|
make(t, 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief generic constructor for a memzone and a type_e
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
type_e t,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
|
|
make(t, 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief generic constructor for a type_e with a size hint
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (type_e t,
|
|
size_t sizeHint,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(autofree) {
|
|
|
|
make(t, sizeHint);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief generic constructor for a memzone, a type_e and a size hint
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
type_e t,
|
|
size_t sizeHint,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
|
|
make(t, sizeHint);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a bool
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (bool x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, x);
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a memzone and a bool
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
bool x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateBooleanJson(z, x);
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for an int32_t
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (int32_t x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, static_cast<double>(x));
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a memzone and an int32_t
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
int32_t x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateNumberJson(z, static_cast<double>(x));
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a double
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (double x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, x);
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a memzone and a double
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
double x, autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateNumberJson(z, x);
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a char const*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (char const* x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, x, strlen(x));
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a char const*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (char const* x,
|
|
size_t length,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, x, length);
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a memzone and a char const*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
char const* x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateStringCopyJson(z, x, strlen(x));
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a memzone and a char const*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
char const* x,
|
|
size_t length,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateStringCopyJson(z, x, length);
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (std::string const& x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(TRI_UNKNOWN_MEM_ZONE)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, x.c_str(), x.size());
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a memzone and a string
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
std::string const& x,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(nullptr),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
|
|
_json = TRI_CreateStringCopyJson(z, x.c_str(), x.size());
|
|
|
|
if (_json == nullptr) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a memzone and a TRI_json_t*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
TRI_json_t* j,
|
|
autofree_e autofree = AUTOFREE)
|
|
: _json(j),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief constructor for a memzone and a const TRI_json_t*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
explicit Json (TRI_memory_zone_t* z,
|
|
TRI_json_t const* j,
|
|
autofree_e autofree = NOFREE)
|
|
: _json(const_cast<TRI_json_t*>(j)),
|
|
_zone(TRI_MemoryZoneId(z)),
|
|
_autofree(autofree) {
|
|
}
|
|
|
|
explicit Json (TRI_json_t* j) = delete;
|
|
explicit Json (TRI_json_t const *) = delete;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief "copy" constructor, note that in the AUTOFREE case this steals
|
|
/// the structure from j to allow returning Json objects by value without
|
|
/// copying the whole structure.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json (Json& j)
|
|
: _json(j.steal()),
|
|
_zone(j._zone),
|
|
_autofree(j._autofree) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief move constructor, note that in the AUTOFREE case this steals
|
|
/// the structure from j to allow returning Json objects by value without
|
|
/// copying the whole structure.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json (Json&& j)
|
|
: _json(j.steal()),
|
|
_zone(j._zone),
|
|
_autofree(j._autofree) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief delete the normal move constructor, because we do not want
|
|
/// invisible recursive copies to be taken of TRI_json_t* managed by this
|
|
/// Json class. Also, we do not want a const copy constructor stealing
|
|
/// the reference.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json (Json const&&) = delete;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief destructor
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
~Json () noexcept {
|
|
if (_json != nullptr && _autofree == AUTOFREE) {
|
|
TRI_FreeJson(TRI_MemoryZone(_zone), _json);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public methods
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief return internal TRI_json_t*, this does not change the ownership
|
|
/// of the pointer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_json_t* json () const noexcept {
|
|
return _json;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief steal the TRI_json_t*, that is, in the AUTOFREE case the pointer
|
|
/// _json is changed to a nullptr. This is used in the copy and the move
|
|
/// constructor and in the cast operator to TRI_json_t*.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_json_t* steal () noexcept {
|
|
TRI_json_t* res = _json;
|
|
if (_autofree == AUTOFREE) {
|
|
_json = nullptr;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief assignment operator, note that, as the copy constructor, this
|
|
/// has steal semantics, which avoids deep copies in situations that
|
|
/// people will use. If you need an actual copy, use the copy method.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& operator= (Json& j) {
|
|
if (_json != nullptr && _autofree == AUTOFREE) {
|
|
TRI_FreeJson(TRI_MemoryZone(_zone), _json);
|
|
}
|
|
_zone = j._zone;
|
|
_autofree = j._autofree;
|
|
_json = j.steal();
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief move assignment operator, this has steal semantics.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& operator= (Json&& j) {
|
|
if (_json != nullptr && _autofree == AUTOFREE) {
|
|
TRI_FreeJson(TRI_MemoryZone(_zone), _json);
|
|
}
|
|
_zone = j._zone;
|
|
_autofree = j._autofree;
|
|
_json = j.steal();
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief copy recursively, even if NOFREE is set! Note that the copy is
|
|
// AUTOFREE
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json copy (autofree_e autofree = AUTOFREE) const {
|
|
Json c;
|
|
c._zone = _zone;
|
|
if (_json != nullptr) {
|
|
c._json = TRI_CopyJson(TRI_MemoryZone(_zone), _json);
|
|
}
|
|
else {
|
|
c._json = nullptr;
|
|
}
|
|
c._autofree = autofree;
|
|
return c;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief set an attribute value in an array, an exception is thrown
|
|
/// if *this is not a Json object. The pointer managed by sub is
|
|
/// stolen. The purpose of this method is that you can do
|
|
/// Json(Json::Object).set("a",Json(12)).set("b",Json(true))
|
|
/// and that this is both legal and efficient.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& set (char const* name, Json sub) {
|
|
if (! TRI_IsObjectJson(_json)) {
|
|
throw JsonException("Json is no object");
|
|
}
|
|
TRI_Insert3ObjectJson(TRI_MemoryZone(_zone), _json, name, sub.steal());
|
|
return *this;
|
|
}
|
|
|
|
Json& set (std::string const& name, Json sub) {
|
|
if (! TRI_IsObjectJson(_json)) {
|
|
throw JsonException("Json is no object");
|
|
}
|
|
TRI_Insert3ObjectJson(TRI_MemoryZone(_zone), _json, name.c_str(), sub.steal());
|
|
return *this;
|
|
}
|
|
|
|
bool unset (char const* name) {
|
|
if (! TRI_IsObjectJson(_json)) {
|
|
throw JsonException("Json is no object");
|
|
}
|
|
return TRI_DeleteObjectJson(TRI_MemoryZone(_zone), _json, name);
|
|
}
|
|
|
|
bool unset (std::string const& name) {
|
|
if (! TRI_IsObjectJson(_json)) {
|
|
throw JsonException("Json is no object");
|
|
}
|
|
return TRI_DeleteObjectJson(TRI_MemoryZone(_zone), _json, name.c_str());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief set an attribute value in an object, an exception is thrown if
|
|
/// *this is not a Json object. The pointer sub is integrated into the
|
|
/// object and will be freed if and only if the main thing is freed.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& set (char const* name, TRI_json_t* sub) {
|
|
if (! TRI_IsObjectJson(_json)) {
|
|
throw JsonException("Json is no object");
|
|
}
|
|
TRI_Insert3ObjectJson(TRI_MemoryZone(_zone), _json, name, sub);
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief this gets an attribute value of a Json object. An exception is
|
|
/// thrown if *this is not a Json object. The resulting TRI_json_t* is
|
|
/// wrapped in a NOFREE Json to allow things like
|
|
/// j.get("a").get("b")
|
|
/// to access j.a.b. The ownership of the whole structure remains with
|
|
/// *this.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json get (char const* name) const {
|
|
if (! TRI_IsObjectJson(_json)) {
|
|
throw JsonException("Json is no object");
|
|
}
|
|
return Json(TRI_MemoryZone(_zone), TRI_LookupObjectJson(_json, name), NOFREE);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief this is a syntactic shortcut for the set method using operator()
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& operator() (char const* name, Json sub) {
|
|
return set(name, sub);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief this is a syntactic shortcut for the set method using operator()
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& operator() (char const* name, TRI_json_t* sub) {
|
|
return set(name, sub);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief whether or not the JSON object has a specific attribute
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool has (char const* name) const {
|
|
if (! TRI_IsObjectJson(_json)) {
|
|
throw JsonException("Json is no object");
|
|
}
|
|
return (TRI_LookupObjectJson(_json, name) != nullptr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief append a Json value to the end of a Json array, an exception
|
|
/// is thrown if *this is not a Json array. The pointer managed by sub is
|
|
/// stolen. The purpose of this method is that you can do
|
|
/// Json(Json::Array).add(Json(12)).add(Json(13))
|
|
/// and that this is both legal and efficient.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& add (Json sub) {
|
|
if (! TRI_IsArrayJson(_json)) {
|
|
throw JsonException("Json is no array");
|
|
}
|
|
TRI_PushBack3ArrayJson(TRI_MemoryZone(_zone), _json, sub.steal());
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief append a TRI_json_t value to the end of a Json array, an exception
|
|
/// is thrown if *this is not a Json array. The pointer sub is integrated
|
|
/// into the array and will be freed if and only if the main thing is
|
|
/// freed.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& add (TRI_json_t* sub) {
|
|
if (! TRI_IsArrayJson(_json)) {
|
|
throw JsonException("Json is no array");
|
|
}
|
|
TRI_PushBack3ArrayJson(TRI_MemoryZone(_zone), _json, sub);
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief append a Json value to the end of a Json array, an exception
|
|
/// is thrown if *this is not a Json array. The data pointed to by the source
|
|
/// json pointer is copied into the result, and the original data is nullified
|
|
/// (so it can be destroyed safely later by its original possessor).
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& transfer (TRI_json_t* json) {
|
|
if (! TRI_IsArrayJson(_json)) {
|
|
throw JsonException("Json is no array");
|
|
}
|
|
TRI_PushBack2ArrayJson(_json, json);
|
|
TRI_InitNullJson(json);
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief reserve space for n additional items in an array
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& reserve (size_t n) {
|
|
if (! TRI_IsArrayJson(_json)) {
|
|
throw JsonException("Json is no array");
|
|
}
|
|
|
|
if (TRI_ReserveVector(&_json->_value._objects, n) != TRI_ERROR_NO_ERROR) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief this is a syntactic shortcut for the add method using operator()
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& operator() (Json sub) {
|
|
return add(sub);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief this is a syntactic shortcut for the add method using operator()
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json& operator() (TRI_json_t* sub) {
|
|
return add(sub);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief this gets an array entry of a Json array. An exception is
|
|
/// thrown if *this is not a Json array. The resulting TRI_json_t* is
|
|
/// wrapped in a NOFREE Json to allow things like
|
|
/// j.at(0).at(1)
|
|
/// to access j[0][1]. The ownership of the whole structure remains with
|
|
/// *this. If the position given is not bound, then an empty Json is
|
|
/// returned.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
Json at (size_t pos) const {
|
|
return at(static_cast<int>(pos));
|
|
}
|
|
|
|
Json at (int pos) const {
|
|
if (! TRI_IsArrayJson(_json)) {
|
|
throw JsonException("Json is no array");
|
|
}
|
|
TRI_json_t* j;
|
|
if (pos >= 0) {
|
|
j = TRI_LookupArrayJson(_json, pos);
|
|
if (j != nullptr) {
|
|
return Json(TRI_MemoryZone(_zone), j, NOFREE);
|
|
}
|
|
else {
|
|
return Json(TRI_MemoryZone(_zone), Json::Null, AUTOFREE);
|
|
}
|
|
}
|
|
else {
|
|
size_t pos2 = -pos;
|
|
size_t len = TRI_LengthVector(&_json->_value._objects);
|
|
if (pos2 > len) {
|
|
return Json(TRI_MemoryZone(_zone), Json::Null, AUTOFREE);
|
|
}
|
|
j = TRI_LookupArrayJson(_json, len-pos2);
|
|
if (j != nullptr) {
|
|
return Json(TRI_MemoryZone(_zone), j, NOFREE);
|
|
}
|
|
else {
|
|
return Json(TRI_MemoryZone(_zone), Json::Null, AUTOFREE);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief destroy the contents of the JSON
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void destroy () {
|
|
if (_json != nullptr) {
|
|
TRI_FreeJson(TRI_MemoryZone(_zone), _json);
|
|
_json = nullptr;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief return the JSON's memory zone
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_memory_zone_t* zone () const {
|
|
return TRI_MemoryZone(_zone);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks whether *this is a Json that is equal to null.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isNull () const noexcept {
|
|
return _json != nullptr && _json->_type == TRI_JSON_NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks whether *this is a boolean Json.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isBoolean () const noexcept {
|
|
return TRI_IsBooleanJson(_json);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks whether *this is a number Json.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isNumber () const noexcept {
|
|
return TRI_IsNumberJson(_json);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks whether *this is a string Json.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isString () const noexcept {
|
|
return TRI_IsStringJson(_json);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks whether *this is an object Json.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isObject () const noexcept {
|
|
return TRI_IsObjectJson(_json);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks whether *this is an array Json.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isArray () const noexcept {
|
|
return TRI_IsArrayJson(_json);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns the length of the array
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
size_t size () const {
|
|
if (! TRI_IsArrayJson(_json)) {
|
|
throw JsonException("Json is no array");
|
|
}
|
|
return TRI_LengthVector(&_json->_value._objects);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns the length of the array
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
size_t members () const {
|
|
if (! TRI_IsObjectJson(_json)) {
|
|
throw JsonException("Json is no object");
|
|
}
|
|
return TRI_LengthVector(&_json->_value._objects) / 2;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks whether *this is an empty Json (not even null).
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool isEmpty () const noexcept {
|
|
return _json == nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief converts the Json recursively into a string.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
std::string toString () const {
|
|
if (_json != nullptr) {
|
|
return JsonHelper::toString(_json);
|
|
}
|
|
return std::string("");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief appends JSON to a string buffer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void dump (triagens::basics::StringBuffer& buffer) const {
|
|
if (_json != nullptr) {
|
|
int res = TRI_StringifyJson(buffer.stringBuffer(), _json);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
throw JsonException("Json: out of memory");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private variables
|
|
// -----------------------------------------------------------------------------
|
|
|
|
private:
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief the actual TRI_json_t*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_json_t* _json;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief the memory zone used
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_memory_zone_id_t _zone;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief flag, whether we automatically free the TRI_json_t*.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
autofree_e _autofree;
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
std::ostream& operator<< (std::ostream&, triagens::basics::Json const*);
|
|
std::ostream& operator<< (std::ostream&, triagens::basics::Json const&);
|
|
std::ostream& operator<< (std::ostream&, TRI_json_t const*);
|
|
std::ostream& operator<< (std::ostream&, TRI_json_t const&);
|
|
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- END-OF-FILE
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
|
// End:
|