Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions docs/02.API-REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5561,3 +5561,73 @@ jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value,
**See also**

- [jerry_create_typedarray](#jerry_create_typedarray)

# JSON functions

## jerry_json_parse

**Summary**

Returns the same result as JSON.parse ecmascript function.

**Prototype**

```c
jerry_value_t jerry_json_parse (const jerry_char_t *string_p, jerry_size_t string_size)
```

- `string_p` - a JSON string
- `string_size` - size of the string
- return
- jerry_value_t containing the same as json.parse()
- jerry_value_t containing error massage

**Example**

```c
{
const char *data = "{\"name\": \"John\", \"age\": 5}";
jerry_size_t str_length = (jerry_size_t)strlen (data);
jerry_value_t parsed_json = jerry_json_parse ((jerry_char_t*)data, str_length);

// parsed_json now conatins all data stored in data_in_json

jerry_release_value (parsed_json);
}
```

## jerry_stringify

**Summary**

Returns the same value as JSON.stringify() ecmascript function.

**Prototype**

```c
jerry_value_t jerry_json_stringfy (const jerry_value_t object_to_stringify)
```

- `object_to_stringify` - a jerry_value_t object to stringify
- return
- jerry_value_t containing the same as json.stringify()
- jerry_value_t containing error massage

**Example**

```c
{
jerry_value_t obj = jerry_create_object ();
jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name");
jerry_value_t value = jerry_create_string ((const jerry_char_t *) "John");
jerry_set_property (obj, key, value);
jerry_value_t stringified = jerry_json_stringfy (obj);

//stringified now contains a json formated string

jerry_release_value (obj);
jerry_release_value (key);
jerry_release_value (value);
jerry_release_value (stringified);
}
```
57 changes: 57 additions & 0 deletions jerry-core/api/jerry.c
Original file line number Diff line number Diff line change
Expand Up @@ -3334,6 +3334,63 @@ jerry_get_typedarray_buffer (jerry_value_t value, /**< TypedArray to get the arr
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
} /* jerry_get_typedarray_buffer */

/**
* Create an object from JSON
*
* Note:
* The returned value must be freed with jerry_release_value
* @return jerry_value_t from json formated string or an error massage
*/
jerry_value_t
jerry_json_parse (const jerry_char_t *string_p, /**< json string */
jerry_size_t string_size) /**< json string size */
{
jerry_assert_api_available ();

#ifndef CONFIG_DISABLE_JSON_BUILTIN
ecma_value_t ret_value = ecma_builtin_json_parse_buffer (string_p, string_size);

if (ecma_is_value_undefined (ret_value))
{
ret_value = jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("JSON string parse error.")));
}

return ret_value;
#else /* CONFIG_DISABLE_JSON_BUILTIN */
JERRY_UNUSED (string_p);
JERRY_UNUSED (string_size);

return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The JSON has been disabled.")));
#endif /* !CONFIG_DISABLE_JSON_BUILTIN */
} /* jerry_json_parse */

/**
* Create a Json formated string from an object
*
* Note:
* The returned value must be freed with jerry_release_value
* @return json formated jerry_value_t or an error massage
*/
jerry_value_t
jerry_json_stringfy (const jerry_value_t object_to_stringify) /**< a jerry_object_t to stringify */
{
jerry_assert_api_available ();
#ifndef CONFIG_DISABLE_JSON_BUILTIN
ecma_value_t ret_value = ecma_builtin_json_string_from_object (object_to_stringify);

if (ecma_is_value_undefined (ret_value))
{
ret_value = jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("JSON stringify error.")));
}

return ret_value;
#else /* CONFIG_DISABLE_JSON_BUILTIN */
JERRY_UNUSED (object_to_stringify);

return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The JSON has been disabled.")));
#endif /* !CONFIG_DISABLE_JSON_BUILTIN */
} /* jerry_json_stringfy */

/**
* @}
*/
4 changes: 4 additions & 0 deletions jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "ecma-builtin-helpers.h"
#include "lit-char-helpers.h"

#ifndef CONFIG_DISABLE_JSON_BUILTIN

/** \addtogroup ecma ECMA
* @{
*
Expand Down Expand Up @@ -221,6 +223,8 @@ ecma_builtin_helper_json_create_non_formatted_json (lit_utf8_byte_t left_bracket
return ecma_make_string_value (result_str_p);
} /* ecma_builtin_helper_json_create_non_formatted_json */

#endif /* !CONFIG_DISABLE_JSON_BUILTIN */

/**
* @}
* @}
Expand Down
3 changes: 3 additions & 0 deletions jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ typedef struct
ecma_object_t *replacer_function_p;
} ecma_json_stringify_context_t;

ecma_value_t ecma_builtin_json_parse_buffer (const lit_utf8_byte_t * str_start_p,
lit_utf8_size_t string_size);
ecma_value_t ecma_builtin_json_string_from_object (const ecma_value_t arg1);
bool ecma_json_has_object_in_stack (ecma_json_occurence_stack_item_t *stack_p, ecma_object_t *object_p);
bool ecma_has_string_value_in_collection (ecma_collection_header_t *collection_p, ecma_value_t string_value);

Expand Down
124 changes: 86 additions & 38 deletions jerry-core/ecma/builtin-objects/ecma-builtin-json.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,35 @@ ecma_builtin_json_walk (ecma_object_t *reviver_p, /**< reviver function */
return ret_value;
} /* ecma_builtin_json_walk */

/**
* Function to set a string token from the given arguments, fills its fields and advances the string pointer.
*
* @return ecma_value_t containing an object or an error massage
* Returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_builtin_json_parse_buffer (const lit_utf8_byte_t * str_start_p, /**< String to parse */
lit_utf8_size_t string_size) /**< size of the string */
{
ecma_json_token_t token;
token.current_p = str_start_p;
token.end_p = str_start_p + string_size;

ecma_value_t final_result = ecma_builtin_json_parse_value (&token);

if (!ecma_is_value_undefined (final_result))
{
ecma_builtin_json_parse_next_token (&token, false);

if (token.type != end_token)
{
ecma_free_value (final_result);
final_result = ECMA_VALUE_UNDEFINED;
}
}
return final_result;
} /*ecma_builtin_json_parse_buffer*/

/**
* The JSON object's 'parse' routine
*
Expand All @@ -830,22 +859,7 @@ ecma_builtin_json_parse (ecma_value_t this_arg, /**< 'this' argument */

ECMA_STRING_TO_UTF8_STRING (string_p, str_start_p, string_size);

ecma_json_token_t token;
token.current_p = str_start_p;
token.end_p = str_start_p + string_size;

ecma_value_t final_result = ecma_builtin_json_parse_value (&token);

if (!ecma_is_value_undefined (final_result))
{
ecma_builtin_json_parse_next_token (&token, false);

if (token.type != end_token)
{
ecma_free_value (final_result);
final_result = ECMA_VALUE_UNDEFINED;
}
}
ecma_value_t final_result = ecma_builtin_json_parse_buffer (str_start_p, string_size);

if (ecma_is_value_undefined (final_result))
{
Expand Down Expand Up @@ -892,6 +906,61 @@ ecma_builtin_json_object (ecma_object_t *obj_p, ecma_json_stringify_context_t *c
static ecma_value_t
ecma_builtin_json_array (ecma_object_t *obj_p, ecma_json_stringify_context_t *context_p);

/**
* Helper function to stringify an object in JSON format representing an ecma_value.
*
* @return ecma_value_t string created from an abject formating by a given context
* Returned value must be freed with ecma_free_value.
*
*/
static ecma_value_t ecma_builtin_json_str_helper (const ecma_value_t arg1, /**< object argument */
ecma_json_stringify_context_t context) /**< context argument */
{
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg ();
ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p,
empty_str_p,
arg1,
false);
JERRY_ASSERT (ecma_is_value_true (put_comp_val));
ecma_free_value (put_comp_val);
ECMA_TRY_CATCH (str_val,
ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context),
ret_value);
ret_value = ecma_copy_value (str_val);
ECMA_FINALIZE (str_val);
ecma_free_value (put_comp_val);
ecma_deref_ecma_string (empty_str_p);
ecma_deref_object (obj_wrapper_p);

return ret_value;
} /* ecma_builtin_json_str_helper */

/**
* Function to create a json formated string from an object
*
* @return ecma_value_t containing a json string
* Returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_builtin_json_string_from_object (const ecma_value_t arg1) /**< object argument */
{
ecma_json_stringify_context_t context;
context.occurence_stack_last_p = NULL;
context.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
context.property_list_p = ecma_new_values_collection ();
context.replacer_function_p = NULL;
context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);

ecma_value_t ret_value = ecma_builtin_json_str_helper (arg1, context);

ecma_deref_ecma_string (context.gap_str_p);
ecma_deref_ecma_string (context.indent_str_p);
ecma_free_values_collection (context.property_list_p, 0);
return ret_value;
} /*ecma_builtin_json_string_from_object*/

/**
* The JSON object's 'stringify' routine
*
Expand Down Expand Up @@ -1119,28 +1188,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */
if (ecma_is_value_empty (ret_value))
{
/* 9. */
ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg ();
ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);

/* 10. */
ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p,
empty_str_p,
arg1,
false);

JERRY_ASSERT (ecma_is_value_true (put_comp_val));
ecma_free_value (put_comp_val);

/* 11. */
ECMA_TRY_CATCH (str_val,
ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context),
ret_value);

ret_value = ecma_copy_value (str_val);

ECMA_FINALIZE (str_val);

ecma_deref_object (obj_wrapper_p);
ret_value = ecma_builtin_json_str_helper (arg1, context);
}

ecma_deref_ecma_string (context.gap_str_p);
Expand Down
2 changes: 2 additions & 0 deletions jerry-core/include/jerryscript-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ jerry_length_t jerry_get_typedarray_length (jerry_value_t value);
jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value,
jerry_length_t *byte_offset,
jerry_length_t *byte_length);
jerry_value_t jerry_json_parse (const jerry_char_t *string_p, jerry_size_t string_size);
jerry_value_t jerry_json_stringfy (const jerry_value_t object_to_stringify);

/**
* @}
Expand Down
42 changes: 42 additions & 0 deletions tests/unit-core/test-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,48 @@ main (void)

jerry_release_value (args[1]);

{
/*json parser check*/
char data_check[]="John";
jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name");
const char *data = "{\"name\": \"John\", \"age\": 5}";
jerry_size_t str_length = (jerry_size_t) strlen (data);
jerry_value_t parsed_json = jerry_json_parse ((jerry_char_t *) data, str_length);
jerry_value_t has_prop_js = jerry_has_property (parsed_json, key);
TEST_ASSERT (jerry_get_boolean_value (has_prop_js));
jerry_release_value (has_prop_js);
jerry_value_t parsed_data = jerry_get_property (parsed_json, key);
TEST_ASSERT (jerry_value_is_string (parsed_data)== true);
jerry_size_t buff_size = (jerry_size_t) jerry_get_string_length (parsed_data);
char buff[jerry_get_string_length (parsed_data)];
jerry_char_t *buff_p = (jerry_char_t *) buff;
jerry_string_to_char_buffer (parsed_data, buff_p, buff_size);
buff[buff_size] = '\0';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it there is an error in utittests, as I told you.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using strncmp instead of strcmp?

TEST_ASSERT (strcmp ((const char *) data_check, (const char *) buff) == false);
jerry_release_value (parsed_json);
jerry_release_value (key);
jerry_release_value (parsed_data);
}

/*json stringify test*/
{
jerry_value_t obj = jerry_create_object ();
char check_value[] = "{\"name\":\"John\"}";
jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name");
jerry_value_t value = jerry_create_string ((const jerry_char_t *) "John");
jerry_set_property (obj, key, value);
jerry_value_t stringified = jerry_json_stringfy (obj);
TEST_ASSERT (jerry_value_is_string (stringified));
char buff[jerry_get_string_length (stringified)];
jerry_string_to_char_buffer (stringified, (jerry_char_t *) buff,
(jerry_size_t) jerry_get_string_length (stringified));
buff[jerry_get_string_length (stringified)] = '\0';
TEST_ASSERT (strcmp ((const char *) check_value, (const char *) buff) == 0);
jerry_release_value (stringified);
jerry_release_value (obj);
jerry_release_value (key);
jerry_release_value (value);
}
jerry_cleanup ();

return 0;
Expand Down