Skip to content

Commit

Permalink
Allow JsonParse to parse primitives at top level
Browse files Browse the repository at this point in the history
Also, add JsonPrimitiveTypeToString

cherry-picked from 2c49aba
  • Loading branch information
Sigurd Teigen committed Apr 15, 2014
1 parent 72d1996 commit c4a8cbc
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 9 deletions.
9 changes: 6 additions & 3 deletions libpromises/evalfunction.c
Original file line number Diff line number Diff line change
Expand Up @@ -5518,7 +5518,8 @@ static FnCallResult FnCallReadJson(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const
}
JsonElement *json = NULL;
const char *data = StringWriterData(contents);
if (JsonParse(&data, &json) != JSON_PARSE_OK)
if ((JsonParse(&data, &json) != JSON_PARSE_OK) ||
(JsonGetElementType(json) == JSON_ELEMENT_TYPE_PRIMITIVE))
{
Log(LOG_LEVEL_ERR, "Error parsing JSON file '%s'", input_path);
WriterClose(contents);
Expand All @@ -5533,7 +5534,8 @@ static FnCallResult FnCallParseJson(ARG_UNUSED EvalContext *ctx, ARG_UNUSED cons
{
const char *data = RlistScalarValue(args);
JsonElement *json = NULL;
if (JsonParse(&data, &json) != JSON_PARSE_OK)
if ((JsonParse(&data, &json) != JSON_PARSE_OK)||
(JsonGetElementType(json) == JSON_ELEMENT_TYPE_PRIMITIVE))
{
Log(LOG_LEVEL_ERR, "Error parsing JSON expression '%s'", data);
return FnFailure();
Expand Down Expand Up @@ -6690,7 +6692,8 @@ void ModuleProtocol(EvalContext *ctx, char *command, const char *line, int print
const char *hold = BufferData(holder);
Log(LOG_LEVEL_DEBUG, "Module protocol parsing JSON %s", content);

if (JsonParse(&hold, &json) != JSON_PARSE_OK)
if ((JsonParse(&hold, &json) != JSON_PARSE_OK) ||
(JsonGetElementType(json) == JSON_ELEMENT_TYPE_PRIMITIVE))
{
Log(LOG_LEVEL_INFO, "Module protocol passed an invalid or too-long JSON structure, must be object or array");
}
Expand Down
71 changes: 67 additions & 4 deletions libutils/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ struct JsonElement_
// JsonElement Functions
// *******************************************************************************************

const char *JsonPrimitiveTypeToString(JsonPrimitiveType type)
{
switch (type)
{
case JSON_PRIMITIVE_TYPE_STRING:
return "string";
case JSON_PRIMITIVE_TYPE_REAL:
case JSON_PRIMITIVE_TYPE_INTEGER:
return "number";
case JSON_PRIMITIVE_TYPE_BOOL:
return "boolean";
default:
assert(false && "Never reach");
return "(null)";
}
}

static void JsonElementSetPropertyName(JsonElement *element, const char *propertyName)
{
assert(element);
Expand Down Expand Up @@ -919,7 +936,7 @@ JsonElement *JsonObjectDetachKey(JsonElement *object, const char *key)
return detached;
}

const char *JsonObjectGetAsString(JsonElement *object, const char *key)
const char *JsonObjectGetAsString(const JsonElement *object, const char *key)
{
assert(object);
assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
Expand Down Expand Up @@ -976,7 +993,7 @@ JsonElement *JsonObjectGetAsArray(JsonElement *object, const char *key)
return NULL;
}

JsonElement *JsonObjectGet(JsonElement *object, const char *key)
JsonElement *JsonObjectGet(const JsonElement *object, const char *key)
{
assert(object);
assert(object->type == JSON_ELEMENT_TYPE_CONTAINER);
Expand Down Expand Up @@ -1667,6 +1684,53 @@ static JsonParseError JsonParseAsNumber(const char **data, JsonElement **json_ou
}
}

static JsonParseError JsonParseAsPrimitive(const char **data, JsonElement **json_out)
{
switch (**data)
{
case '"':
{
char *value = NULL;
JsonParseError err = JsonParseAsString(data, &value);
if (err != JSON_PARSE_OK)
{
return err;
}
*json_out = JsonElementCreatePrimitive(JSON_PRIMITIVE_TYPE_STRING, JsonDecodeString(value));
free(value);
}
return JSON_PARSE_OK;

default:
if (**data == '-' || **data == '0' || IsDigit(**data))
{
JsonParseError err = JsonParseAsNumber(data, json_out);
if (err != JSON_PARSE_OK)
{
return err;
}
return JSON_PARSE_OK;
}

JsonElement *child_bool = JsonParseAsBoolean(data);
if (child_bool)
{
*json_out = child_bool;
return JSON_PARSE_OK;
}

JsonElement *child_null = JsonParseAsNull(data);
if (child_null)
{
*json_out = child_null;
return JSON_PARSE_OK;
}

*json_out = NULL;
return JSON_PARSE_ERROR_OBJECT_BAD_SYMBOL;
}
}

static JsonParseError JsonParseAsArray(const char **data, JsonElement **json_out)
{
if (**data != '[')
Expand Down Expand Up @@ -1983,8 +2047,7 @@ JsonParseError JsonParse(const char **data, JsonElement **json_out)
}
else
{
*json_out = NULL;
return JSON_PARSE_ERROR_INVALID_START;
return JsonParseAsPrimitive(data, json_out);
}
}

Expand Down
6 changes: 4 additions & 2 deletions libutils/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ void JsonObjectAppendElement(JsonElement *object, const char *key, JsonElement *
@param key [in] the key of the field.
@returns A pointer to the string value, or NULL if non-existant.
*/
const char *JsonObjectGetAsString(JsonElement *object, const char *key);
const char *JsonObjectGetAsString(const JsonElement *object, const char *key);

/**
@brief Get the value of a field in an object, as an object.
Expand All @@ -260,7 +260,7 @@ JsonElement *JsonObjectGetAsObject(JsonElement *object, const char *key);
*/
JsonElement *JsonObjectGetAsArray(JsonElement *object, const char *key);

JsonElement *JsonObjectGet(JsonElement *object, const char *key);
JsonElement *JsonObjectGet(const JsonElement *object, const char *key);

/**
@brief Append a string to an array.
Expand Down Expand Up @@ -382,6 +382,8 @@ void JsonSort(JsonElement *container, JsonComparator *Compare, void *user_data);
JsonElement *JsonAt(const JsonElement *container, size_t index);
JsonElement *JsonSelect(JsonElement *element, size_t num_indices, char **indices);

const char *JsonPrimitiveTypeToString(JsonPrimitiveType type);


JsonIterator JsonIteratorInit(const JsonElement *container);
const char *JsonIteratorNextKey(JsonIterator *iter);
Expand Down
26 changes: 26 additions & 0 deletions tests/unit/json_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,31 @@ static void test_parse_tzz_evil_key(void)
JsonDestroy(obj);
}

static void test_parse_primitives(void)
{
JsonElement *pri = NULL;

const char *data = "\"foo\"";
assert_int_equal(JSON_PARSE_OK, JsonParse(&data, &pri));
assert_string_equal("foo", JsonPrimitiveGetAsString(pri));
JsonDestroy(pri);

data = "-123";
assert_int_equal(JSON_PARSE_OK, JsonParse(&data, &pri));
assert_true(-123 == JsonPrimitiveGetAsInteger(pri));
JsonDestroy(pri);

data = "1.23";
assert_int_equal(JSON_PARSE_OK, JsonParse(&data, &pri));
assert_double_close(1.23, JsonPrimitiveGetAsReal(pri));
JsonDestroy(pri);

data = "true";
assert_int_equal(JSON_PARSE_OK, JsonParse(&data, &pri));
assert_true(JsonPrimitiveGetAsBool(pri));
JsonDestroy(pri);
}

static void test_parse_array_simple(void)
{
const char *data = ARRAY_SIMPLE;
Expand Down Expand Up @@ -1197,6 +1222,7 @@ int main()
unit_test(test_parse_array_nested_garbage),
unit_test(test_parse_object_escaped),
unit_test(test_parse_tzz_evil_key),
unit_test(test_parse_primitives),
unit_test(test_array_remove_range),
unit_test(test_remove_key_from_object),
unit_test(test_detach_key_from_object),
Expand Down

0 comments on commit c4a8cbc

Please sign in to comment.