File: //usr/include/dovecot/json-types.h
#ifndef JSON_TYPES_H
#define JSON_TYPES_H
#include "istream.h"
struct json_tree;
struct json_tree_node;
struct json_tree_node_list;
struct json_data;
struct json_value;
struct json_node;
/*
* Value
*/
/* The type of the JSON value */
enum json_type {
/* no value */
JSON_TYPE_NONE = 0,
/* object */
JSON_TYPE_OBJECT,
/* array */
JSON_TYPE_ARRAY,
/* string */
JSON_TYPE_STRING,
/* number */
JSON_TYPE_NUMBER,
/* true */
JSON_TYPE_TRUE,
/* false */
JSON_TYPE_FALSE,
/* null */
JSON_TYPE_NULL,
/* JSON-text; either sub-tree or literal JSON text */
JSON_TYPE_TEXT,
};
/* The content representation of the JSON value */
enum json_content_type {
/* true, false, null */
JSON_CONTENT_TYPE_NONE = 0,
/* object, array */
JSON_CONTENT_TYPE_LIST,
/* literal/string/text */
JSON_CONTENT_TYPE_STRING,
/* data buffer (for string/text containing \u0000) */
JSON_CONTENT_TYPE_DATA,
/* data stream (for potentially very long string/text) */
JSON_CONTENT_TYPE_STREAM,
/* integer number */
JSON_CONTENT_TYPE_INTEGER,
/* sub-tree */
JSON_CONTENT_TYPE_TREE,
};
struct json_data {
/* data[size] == 0x00 */
const unsigned char *data;
size_t size;
/* data contains 0x00 */
bool contains_nul:1;
/* data contains control character */
bool contains_control:1;
};
struct json_value {
enum json_content_type content_type;
union {
/* JSON_CONTENT_TYPE_LIST */
struct json_tree_node_list *list; /* only used by trees */
/* JSON_CONTENT_TYPE_STRING */
const char *str;
/* JSON_CONTENT_TYPE_DATA */
struct json_data *data;
/* JSON_CONTENT_TYPE_STREAM */
struct istream *stream;
/* JSON_CONTENT_TYPE_INTEGER */
intmax_t intnum;
/* JSON_CONTENT_TYPE_TREE */
struct json_tree *tree;
} content;
};
const char *json_type_get_name(enum json_type type);
const char *json_content_type_get_name(enum json_content_type ctype);
/* number */
static inline int
json_value_get_uintmax(const struct json_value *jvalue, uintmax_t *num_r)
{
i_assert(jvalue->content_type == JSON_CONTENT_TYPE_INTEGER);
if (jvalue->content.intnum < 0)
return -1;
*num_r = (uintmax_t)jvalue->content.intnum;
return 0;
}
static inline int
json_value_get_intmax(const struct json_value *jvalue, intmax_t *num_r)
{
i_assert(jvalue->content_type == JSON_CONTENT_TYPE_INTEGER);
*num_r = jvalue->content.intnum;
return 0;
}
#define JSON_VALUE_GET_U__TEMPLATE(name, type, uint_max) \
static inline int \
name(const struct json_value *jvalue, type *num_r) \
{ \
intmax_t l; \
i_assert(jvalue->content_type == JSON_CONTENT_TYPE_INTEGER); \
l = jvalue->content.intnum; \
if (l < 0 || (uintmax_t)l > uint_max) \
return -1; \
*num_r = (type)l; \
return 0; \
}
JSON_VALUE_GET_U__TEMPLATE(json_value_get_uint,
unsigned int, UINT_MAX)
JSON_VALUE_GET_U__TEMPLATE(json_value_get_ulong,
unsigned long, ULONG_MAX)
JSON_VALUE_GET_U__TEMPLATE(json_value_get_ullong,
unsigned long long, ULLONG_MAX)
JSON_VALUE_GET_U__TEMPLATE(json_value_get_uint32,
uint32_t, UINT32_MAX)
JSON_VALUE_GET_U__TEMPLATE(json_value_get_uint64,
uint64_t, UINT64_MAX)
#define JSON_VALUE_GET_S__TEMPLATE(name, type, int_min, int_max) \
static inline int \
name(const struct json_value *jvalue, type *num_r) \
{ \
intmax_t l; \
i_assert(jvalue->content_type == JSON_CONTENT_TYPE_INTEGER); \
l = jvalue->content.intnum; \
if (l < int_min || l > int_max) \
return -1; \
*num_r = (type)l; \
return 0; \
}
JSON_VALUE_GET_S__TEMPLATE(json_value_get_int,
int, INT_MIN, INT_MAX)
JSON_VALUE_GET_S__TEMPLATE(json_value_get_long,
long, LONG_MIN, LONG_MAX)
JSON_VALUE_GET_S__TEMPLATE(json_value_get_llong,
long long, LLONG_MIN, LLONG_MAX)
JSON_VALUE_GET_S__TEMPLATE(json_value_get_int32,
int32_t, INT32_MIN, INT32_MAX)
JSON_VALUE_GET_S__TEMPLATE(json_value_get_int64,
int64_t, INT64_MIN, INT64_MAX)
/* string */
static inline ATTR_PURE const char *
json_value_get_str(const struct json_value *jvalue)
{
i_assert(jvalue->content_type == JSON_CONTENT_TYPE_STRING);
return jvalue->content.str;
}
static inline ATTR_PURE const char *
json_value_as_str(const struct json_value *jvalue)
{
switch (jvalue->content_type) {
case JSON_CONTENT_TYPE_STRING:
break;
case JSON_CONTENT_TYPE_INTEGER:
return t_strdup_printf("%"PRIdMAX, jvalue->content.intnum);
default:
i_unreached();
}
return jvalue->content.str;
}
static inline const unsigned char *
json_value_get_data(const struct json_value *jvalue, size_t *size_r)
{
switch (jvalue->content_type) {
case JSON_CONTENT_TYPE_STRING:
*size_r = strlen(jvalue->content.str);
return (const unsigned char *)jvalue->content.str;
case JSON_CONTENT_TYPE_DATA:
*size_r = jvalue->content.data->size;
return jvalue->content.data->data;
default:
break;
}
i_unreached();
}
static inline int
json_value_get_stream(const struct json_value *jvalue,
struct istream **stream_r)
{
if (jvalue->content_type != JSON_CONTENT_TYPE_STREAM)
return -1;
*stream_r = jvalue->content.stream;
i_stream_ref(*stream_r);
return 0;
}
/*
* Node
*/
struct json_node {
/* object member name */
const char *name;
/* node type */
enum json_type type;
/* node value */
struct json_value value;
};
static inline ATTR_PURE bool
json_node_is_none(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_NONE);
}
const char *json_node_get_label(const struct json_node *jnode);
/* object, array */
static inline ATTR_PURE bool
json_node_is_object(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_OBJECT &&
jnode->value.content_type != JSON_CONTENT_TYPE_NONE);
}
static inline ATTR_PURE bool
json_node_is_array(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_ARRAY &&
jnode->value.content_type != JSON_CONTENT_TYPE_NONE);
}
static inline ATTR_PURE bool
json_node_is_object_end(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_OBJECT &&
jnode->value.content_type == JSON_CONTENT_TYPE_NONE);
}
static inline ATTR_PURE bool
json_node_is_array_end(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_ARRAY &&
jnode->value.content_type == JSON_CONTENT_TYPE_NONE);
}
static inline ATTR_PURE bool
json_node_is_end(const struct json_node *jnode)
{
switch (jnode->type) {
case JSON_TYPE_OBJECT:
case JSON_TYPE_ARRAY:
return (jnode->value.content_type == JSON_CONTENT_TYPE_NONE);
default:
break;
}
return FALSE;
}
/* string */
static inline ATTR_PURE bool
json_node_is_string(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_STRING);
}
static inline ATTR_PURE const char *
json_node_get_str(const struct json_node *jnode)
{
switch (jnode->type) {
case JSON_TYPE_STRING:
case JSON_TYPE_NUMBER:
case JSON_TYPE_TEXT:
break;
case JSON_TYPE_TRUE:
return "true";
case JSON_TYPE_FALSE:
return "false";
case JSON_TYPE_NULL:
return "null";
default:
i_unreached();
}
return json_value_get_str(&jnode->value);
}
static inline ATTR_PURE const char *
json_node_as_str(const struct json_node *jnode)
{
switch (jnode->type) {
case JSON_TYPE_STRING:
case JSON_TYPE_NUMBER:
case JSON_TYPE_TEXT:
break;
case JSON_TYPE_TRUE:
return "true";
case JSON_TYPE_FALSE:
return "false";
case JSON_TYPE_NULL:
return "null";
default:
i_unreached();
}
return json_value_as_str(&jnode->value);
}
static inline const unsigned char *
json_node_get_data(const struct json_node *jnode, size_t *size_r)
{
const char *literal;
switch (jnode->type) {
case JSON_TYPE_STRING:
case JSON_TYPE_NUMBER:
case JSON_TYPE_TEXT:
break;
case JSON_TYPE_TRUE:
literal = "true";
*size_r = strlen(literal);
return (const unsigned char *)literal;
case JSON_TYPE_FALSE:
literal = "false";
*size_r = strlen(literal);
return (const unsigned char *)literal;
case JSON_TYPE_NULL:
literal = "null";
*size_r = strlen(literal);
return (const unsigned char *)literal;
default:
i_unreached();
}
return json_value_get_data(&jnode->value, size_r);
}
static inline int
json_node_get_stream(const struct json_node *jnode,
struct istream **stream_r)
{
if (jnode->type != JSON_TYPE_STRING)
return -1;
return json_value_get_stream(&jnode->value, stream_r);
}
/* number */
static inline ATTR_PURE bool
json_node_is_number(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_NUMBER);
}
static inline int
json_node_get_intmax(const struct json_node *jnode, intmax_t *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_intmax(&jnode->value, num_r);
}
static inline int
json_node_get_int(const struct json_node *jnode, int *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_int(&jnode->value, num_r);
}
static inline int
json_node_get_long(const struct json_node *jnode, long *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_long(&jnode->value, num_r);
}
static inline int
json_node_get_llong(const struct json_node *jnode, long long *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_llong(&jnode->value, num_r);
}
static inline int
json_node_get_int32(const struct json_node *jnode, int32_t *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_int32(&jnode->value, num_r);
}
static inline int
json_node_get_int64(const struct json_node *jnode, int64_t *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_int64(&jnode->value, num_r);
}
static inline int
json_node_get_uintmax(const struct json_node *jnode, uintmax_t *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_uintmax(&jnode->value, num_r);
}
static inline int
json_node_get_uint(const struct json_node *jnode, unsigned int *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_uint(&jnode->value, num_r);
}
static inline int
json_node_get_ulong(const struct json_node *jnode, unsigned long *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_ulong(&jnode->value, num_r);
}
static inline int
json_node_get_ullong(const struct json_node *jnode, unsigned long long *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_ullong(&jnode->value, num_r);
}
static inline int
json_node_get_uint32(const struct json_node *jnode, uint32_t *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_uint32(&jnode->value, num_r);
}
static inline int
json_node_get_uint64(const struct json_node *jnode, uint64_t *num_r)
{
if (jnode->type != JSON_TYPE_NUMBER)
return -1;
if (jnode->value.content_type != JSON_CONTENT_TYPE_INTEGER)
return -1;
return json_value_get_uint64(&jnode->value, num_r);
}
/* true, false */
static inline ATTR_PURE bool
json_node_is_true(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_TRUE);
}
static inline ATTR_PURE bool
json_node_is_false(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_FALSE);
}
static inline ATTR_PURE bool
json_node_is_boolean(const struct json_node *jnode)
{
switch (jnode->type) {
case JSON_TYPE_TRUE:
case JSON_TYPE_FALSE:
return TRUE;
default:
break;
}
return FALSE;
}
static inline int
json_node_get_boolean(const struct json_node *jnode, bool *bool_r)
{
switch (jnode->type) {
case JSON_TYPE_TRUE:
*bool_r = TRUE;
return 0;
case JSON_TYPE_FALSE:
*bool_r = FALSE;
return 0;
default:
break;
}
return -1;
}
/* null */
static inline ATTR_PURE bool
json_node_is_null(const struct json_node *jnode)
{
return (jnode->type == JSON_TYPE_NULL);
}
/* utility */
static inline ATTR_PURE bool
json_node_is_singular(const struct json_node *jnode)
{
switch (jnode->type) {
case JSON_TYPE_OBJECT:
case JSON_TYPE_ARRAY:
return FALSE;
default:
break;
}
return TRUE;
}
/*
* Limits
*/
// NOTE: There is currently no support for reading enormous object member names
// incrementally. This is usually not needed, but it could sometimes be
// nice to have.
#define JSON_DEFAULT_MAX_NAME_SIZE 1024
#define JSON_DEFAULT_MAX_STRING_SIZE 32*1024
#define JSON_DEFAULT_MAX_NESTING 32
#define JSON_DEFAULT_MAX_LIST_ITEMS 1024
struct json_limits {
/* Maximum size of object member name */
size_t max_name_size;
/* Maximum length of a string */
size_t max_string_size;
/* Maximum depth of object/array nesting */
unsigned int max_nesting;
/* Maximum number of object/array items */
unsigned int max_list_items;
};
/*
* Format
*/
struct json_format {
/* Number of indent characters (either TAB or SPACE) */
unsigned int indent_chars;
/* Indent character is TAB instead of SPACE */
bool indent_tab:1;
/* Insert whitespace at appropriate places around separators */
bool whitespace:1;
/* Insert newlines */
bool new_line:1;
/* Newlines are CRLF rather than the default LF */
bool crlf:1;
};
#endif