Files
libguestfs/common/mltools/JSON_parser-c.c
Richard W.M. Jones 05d4fcb64d Update copyright dates for 2019.
This command run over the source:

perl -pi.bak -e 's/(20[01][0-9])-2018/$1-2019/g' `git ls-files`
2019-01-08 11:58:30 +00:00

170 lines
4.7 KiB
C

/* JSON parser
* Copyright (C) 2015-2019 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <config.h>
#include <caml/alloc.h>
#include <caml/fail.h>
#include <caml/memory.h>
#include <caml/mlvalues.h>
#include <jansson.h>
#include <stdio.h>
#include <string.h>
#define JSON_NULL (Val_int (0)) /* Variants without parameters. */
#define JSON_STRING_TAG 0 /* Variants with parameters. */
#define JSON_INT_TAG 1
#define JSON_FLOAT_TAG 2
#define JSON_BOOL_TAG 3
#define JSON_LIST_TAG 4
#define JSON_DICT_TAG 5
value virt_builder_json_parser_tree_parse (value stringv);
value virt_builder_json_parser_tree_parse_file (value stringv);
static value
convert_json_t (json_t *val, int level)
{
CAMLparam0 ();
CAMLlocal5 (rv, v, tv, sv, consv);
if (level > 20)
caml_invalid_argument ("too many levels of object/array nesting");
if (json_is_object (val)) {
const char *key;
json_t *jvalue;
rv = caml_alloc (1, JSON_DICT_TAG);
v = Val_int (0);
/* This will create the OCaml list backwards, but JSON
* dictionaries are supposed to be unordered so that shouldn't
* matter, right? Well except that for some consumers this does
* matter (eg. simplestreams which incorrectly uses a dict when it
* really should use an array).
*/
json_object_foreach (val, key, jvalue) {
tv = caml_alloc_tuple (2);
sv = caml_copy_string (key);
Store_field (tv, 0, sv);
sv = convert_json_t (jvalue, level + 1);
Store_field (tv, 1, sv);
consv = caml_alloc (2, 0);
Store_field (consv, 1, v);
Store_field (consv, 0, tv);
v = consv;
}
Store_field (rv, 0, v);
}
else if (json_is_array (val)) {
const size_t len = json_array_size (val);
size_t i;
json_t *jvalue;
rv = caml_alloc (1, JSON_LIST_TAG);
v = Val_int (0);
for (i = 0; i < len; ++i) {
/* Note we have to create the OCaml list backwards. */
jvalue = json_array_get (val, len-i-1);
tv = convert_json_t (jvalue, level + 1);
consv = caml_alloc (2, 0);
Store_field (consv, 1, v);
Store_field (consv, 0, tv);
v = consv;
}
Store_field (rv, 0, v);
}
else if (json_is_string (val)) {
rv = caml_alloc (1, JSON_STRING_TAG);
v = caml_copy_string (json_string_value (val));
Store_field (rv, 0, v);
}
else if (json_is_real (val)) {
rv = caml_alloc (1, JSON_FLOAT_TAG);
v = caml_copy_double (json_real_value (val));
Store_field (rv, 0, v);
}
else if (json_is_integer (val)) {
rv = caml_alloc (1, JSON_INT_TAG);
v = caml_copy_int64 (json_integer_value (val));
Store_field (rv, 0, v);
}
else if (json_is_true (val)) {
rv = caml_alloc (1, JSON_BOOL_TAG);
Store_field (rv, 0, Val_true);
}
else if (json_is_false (val)) {
rv = caml_alloc (1, JSON_BOOL_TAG);
Store_field (rv, 0, Val_false);
}
else
rv = JSON_NULL;
CAMLreturn (rv);
}
value
virt_builder_json_parser_tree_parse (value stringv)
{
CAMLparam1 (stringv);
CAMLlocal1 (rv);
json_t *tree;
json_error_t err;
tree = json_loads (String_val (stringv), JSON_DECODE_ANY, &err);
if (tree == NULL) {
char buf[256 + JSON_ERROR_TEXT_LENGTH];
if (strlen (err.text) > 0)
snprintf (buf, sizeof buf, "JSON parse error: %s", err.text);
else
snprintf (buf, sizeof buf, "unknown JSON parse error");
caml_invalid_argument (buf);
}
rv = convert_json_t (tree, 1);
json_decref (tree);
CAMLreturn (rv);
}
value
virt_builder_json_parser_tree_parse_file (value filev)
{
CAMLparam1 (filev);
CAMLlocal1 (rv);
json_t *tree;
json_error_t err;
tree = json_load_file (String_val (filev), JSON_DECODE_ANY, &err);
if (tree == NULL) {
char buf[1024 + JSON_ERROR_TEXT_LENGTH];
if (strlen (err.text) > 0)
snprintf (buf, sizeof buf, "%s: JSON parse error: %s", String_val (filev), err.text);
else
snprintf (buf, sizeof buf, "%s: unknown JSON parse error", String_val (filev));
caml_invalid_argument (buf);
}
rv = convert_json_t (tree, 1);
json_decref (tree);
CAMLreturn (rv);
}