kgabis / parson Goto Github PK
View Code? Open in Web Editor NEWLightweight JSON library written in C.
License: MIT License
Lightweight JSON library written in C.
License: MIT License
Documentation is not crisp about when I need to free resources versus when the library will free resources on my behalf.
There are comments in the header file in some places that indicate how memory should be handled...
/* Works like dotget functions, but creates whole hierarchy if necessary.` * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
However, the header offers no advice for the management of the string returned by const char * json_object_get_string (const JSON_Object *object, const char *name);
The README ("Persistence" section) shows, json_object_get_string
being used without a call to free, but this is uncommon behavior for c libraries and it would be nice if it were well defined.
Example:
/* Initialising object with an array of strings */
JSON_Value *val = json_value_init_object();
JSON_Object *obj = json_object(val);
json_object_dotset_string(obj, "array[0]", "item0");
json_object_dotset_string(obj, "array[1]", "item1");
json_object_dotset_string(obj, "array[3]", "item3"); /* error, index 2 is missing */
json_object_dotset_string(obj, "array[2]", "item2");
json_object_dotset_string(obj, "array[3]", "item3"); /* ok */
/* Result:
{ "array": ["item0", "item1", "item2", item3"] }
*/
/* Getting a string at index */
const char *str = json_object_dotget_string(obj, "array[0]");
Changed compiler from gcc to g++ in Makefile.
Get error
parson.c: In function ‘JSON_Status json_array_resize(JSON_Array_, size_t)’:
parson.c:407:65: error: invalid conversion from ‘void_’ to ‘JSON_Value** {aka json_value_t*}’ [-fpermissive]
new_items = parson_malloc(new_capacity * sizeof(JSON_Value));
It seems to be as easy as adding a simple cast, changing line 407 to
new_items = (JSON_Value*)parson_malloc(new_capacity * sizeof(JSON_Value));
Hi, i tried using your lib to generate logs, which works fine for simple cases. I'm currently using VS2008 and will also use gcc.
But as soon as I add a longer message containing backslashes I do get a crash calling json_serialize_to_string():
const char* msg = "Environment: \npid=13232\nhostname=con-js\nALLUSERSPROFILE=C:\ProgramData\nAPPDATA=C:\Users\js\AppData\Roaming";
JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_value_get_object(root_value);
char *serialized_string = NULL;
json_object_set_string(root_object, "message", msg);
serialized_string = json_serialize_to_string(root_value);
json_free_serialized_string(serialized_string);
json_value_free(root_value);
It looks like json_serialize_string writes over the bounds of buf, which causes to stop.
The call stack:
msvcr90.dll!_crt_debugger_hook(int _Reserved=12770140) Zeile 65 C
msvcr90.dll!_invalid_parameter(const wchar_t * pszExpression=0x00000000, const wchar_t * pszFunction=0x00000000, const wchar_t * pszFile=0x00000000, unsigned int nLine=0, unsigned int pReserved=0) Zeile 112 + 0x7 Bytes C++
msvcr90.dll!sprintf(char * string=0x00000000, const char * format=0x040baff0, ...) Zeile 105 + 0x1c Bytes C
_cdbwrapc.pyd!json_serialize_to_buffer_r(const json_value_t * value=0x0490c068, char * buf=0x00000000) Zeile 698 + 0xf Bytes C
_cdbwrapc.pyd!json_serialize_to_buffer(const json_value_t * value=0x0490c068, char * buf=0x0496a380, unsigned int buf_size_in_bytes=97) Zeile 1075 + 0xd Bytes C
_cdbwrapc.pyd!json_serialize_to_string(const json_value_t * value=0x0490c068) Zeile 1107 + 0x11 Bytes C
Am I guessing right, or did you watch similar behaviour before?
Hello kgabis,
As per json.org, null is a valid JSON value.
I would expect the following code to print "parsing null success!". Instead it prints "cannot json_parse_string null".
#include <stdio.h>
#include "parson.h"
int main(int argc, char** argv)
{
JSON_Value* v = json_parse_string("null");
if (v == NULL)
{
printf("cannot json_parse_string null\n");
}
else
{
printf("parsing null is success!\n");
json_value_free(v);
}
return 0;
}
Thank you.
Best Regards,
Andrei Porumb
Hi,
I have been using parson for a while and I love it!
However, I have a problem with the json_object_dotget_number() function.
json_object_dotget_number() returns '0' on fail as shown below so there is no way to distinguish between an error and value '0'.
double json_object_dotget_number (const JSON_Object object, const char *name); / returns 0 on fail */
I suggest returning the value as a function argument and use the return value for error only.
I also suggest using 0 for success and -1 for failure.
int json_object_dotget_number (const JSON_Object object, const char *name, double *number);
/ returns 0 on success, -1 on fail */
U can publish new changes files as release?
Hi there,
I noticed that is missing a function such int json_object_string_exists( JSON_Object *object, const char *name ) that checks (and return like an int) if a key (or string) in a Object exists. If I use json_object_get_string over an unexisting string, program gives Segmentation Fault (code dump).
Could you add it? Thank you.
Just a question about max size in json_serialization_size and json_serialization_size_pretty functions, there's 1100 character long buffer for pre-parsing numbers, where's this number coming from? Wouldn't it be better to use parson_malloc + parson_free if there's need for such a long buffer for just a number, or is it misclicked 100? More than 1000 characters seems like an overkill?
Hello kgabis,
I would like to propose the following (small) improvement:
#ifdef _MSC_VER
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif /*_CRT_SECURE_NO_WARNINGS*/
#endif
Thank you.
Best Regards,
Andrei Porumb
PS: this helps in the cases where the build system blindly defines _CRT_SECURE_NO_WARNINGS for all files.
This fails to parse:
{"x":1,"x":2}
It's not clear to me from the JSON grammar whether it should parse or not. Most other JSON libraries (e.g. the validator at http://jsonlint.com/) appear to simply overwrite the value of a redefined key with the new value (i.e. the above is decoded to {"x":2}).
Hello.
I try to replace exising json object with another, but fail.
I use json_object_set_value. Return 0, but JSON invalid.
Code:
JSON_Value *root_value = json_parse_string(pcBuffer);
if (!root_value)
return 1;
JSON_Object *root_object = json_value_get_object(root_value);
if (!root_object)
return 1;
JSON_Object *protection = json_object_get_object(root_object, "protection");
if (!protection)
return 1;
status = json_object_set_value(protection, "macs", json_parse_string(pchAddedJSON));
if (status != 0)
return 1;
char* result = json_serialize_to_string(root_value);
pchAddedJSON file content:
http://pastebin.com/W2YnuXsj
Exiting JSON file content (before any operations, valid):
http://pastebin.com/X5tjG9hd
After insert JSON file content (invalid file):
http://pastebin.com/90P251D4
I have crashs when run test_suite_3:
json_parse_string("{,"); and json_parse_string("["\0"]");
Maybe you should validate in function skip_quotes()
When debugging applications, without access to the type definitions, attempting to access JSON Object names or values causes an "dereferencing pointer to incomplete type" compiler error.
names:
ubp.c: In function ‘json_to_response_two’: ubp.c:59:41: error: dereferencing pointer to incomplete type printf("name: %s, value: %s\n",object->names[j], json_value_get_string(object->values[j]));
and for values:
ubp.c:59:58: error: dereferencing pointer to incomplete type printf("name: %s, value: %s\n",object->names[j], json_value_get_string(object->values[j]));
Moving these to the header file resolves this issue, and allows for better debugging.
Around parson.c:276 tabs are used for indentation rather than spaces like everywhere else. This leads to a compiler warning. The warning is unfounded, IMHO.
gcc -std=gnu99 -g -fpic -Wall -c -o parson/parson.o parson/parson.c
parson/parson.c: In function ‘remove_comments’:
parson/parson.c:282:13: warning: this ‘for’ clause does not guard... [-Wmisleading-indentation]
for (i = 0; i < (ptr - string) + end_token_len; i++)
^~~
parson/parson.c:284:12: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘for’
string = ptr + end_token_len - 1;
^~~~~~
Would it be possible for parson to support at least one of the comment styles bellow ?
Comment are not part of the JSON specification but they are an invaluable tool when using JSON for configuration files, on when providing an example JSON data structure to another developer.
Currently parson opens files using a call to FILE *fp = fopen(filename, "r");
. This will assume the file is encoded as ANSI which is not always the case. fopen
can take an optional ccs=<encoding>
argument, and values of <encoding>
can be "UNICODE", "UTF-8", and "UTF-16LE". Please consider changing the call to fopen
passing the ccs=UNICODE
argument.
I played around with this and ended up changing a lot of parson internals such as allowing the switch between wchar_t* and char*, and modifying the file open calls to FILE *fp = fopen(filename, "r, ccs=UNICODE");
however there ended up being quite a bit of changes and more that I would have needed to do to make it complete, there was a simpler way to go about it which as just changing the functions which open files to read into a wchar_t* and then put that into a char*. I decided to table my work as it was starting to get extensive, and instead suggest the change here just in case you are already working on this or don't plan on supporting unicode.
Currently, when parsing fails a NULL value is returned and my software can only log a "something went wrong" message. It would be great to be able to log the line number and line contents that caused the failure.
I apologize for not reading the bottom of the readme about creating issues before a pull request. Pull request #78 shows a minimally invasive way to implement this. It returns a JSONError value with an error message in the string field.
We have JSON:
http://pastebin.com/CRxepHVa
This JSON have 2 same keys: "size".
JSON_Value *root_value = json_parse_file(jsonFile1);
We recieve NULL. Library can't process JSON files with several same keys.
Maybe add support? For example, we parse to struct only last key.
On example, skip size:0 and insert size:1 in struct.
Thanks.
I am suggesting to remove dependency on sscanf
. It was only used twice for parsing hex numbers "%4x"
and could be easily replaced.
Primarily, it is because of this issue in Azure IoT SDK for C. The SDK relies on parson. But since some Arduino devices did not implement sscanf
, thus, they cannot use Azure IoT SDK.
As I dig further, I found that parson only used sscanf
twice for parsing UTF-16 in hex. So I am suggesting if it could be replaced. Apart from Azure IoT SDK, the change could also benefit other Arduino users by using parson for their project.
I have forked parson and replaced sscanf
with this commit.
Thanks!
Since the pointer of the output is known and you control the end pointer, why not do a simple subtraction. It will be even faster than scanning the string for \0 with strlen.
Here the 1 line fix.
--- parson/parson.c
+++ parson/parson.c
@@ -435,11 +435,11 @@
}
output_ptr++;
input_ptr++;
}
*output_ptr = '\0';
- if (try_realloc((void**)&output, strlen(output) + 1) == JSONFailure)
+ if (try_realloc((void**)&output, (output_ptr-output) + 1) == JSONFailure)
goto error;
return output;
error:
free(output);
return NULL;
json_serialize_to_file
json_serialize_to_file_pretty
in read-only filesystem those function return JSONSuccess
Would it be possible to add a parent
field to objects, in order to allow back-navigation in the hierarchy?
The json_serialize_to_buffer_pretty() uses macro APPEND_STRING(str) to calculate how much data has been written to the ourput buffer. This macro uses append_string() then sprintf(). While in Std C lib, the return value of sprintf will not include the null terminator char.
As a result, the returned value of json_serialization_size_pretty() is always lack of 1 bytes, and json_serialize_to_string_pretty() will also always over write 1 byte of the allocated memory buffer.
As of RFC 4627 point 2.5, the unescaped allowed characters are 0x20-0x21 / 0x23-0x5B / 0x5D-0x10FFFF so 0x7F (DEL) is an allowed unescaped char.
In strings parsing, parson use iscntrl() to verify control characters. iscntrl() returns true even for 0x7F, yet it is an allowed character and should be accepted in unescaped form.
I posted a patch at https://gist.github.com/4270061
Regarding mattn/mruby-json#6, there should be a way to determine if a JSONNumber was specified as 1.0
or simply 1
. This would be very useful to programming languages that use different classes for integers and floats.
Please, take a little look to this SOpt post, i have an inssue with parsing response data.
http://pt.stackoverflow.com/q/148202/8984?problema-com-a-library-parson-ao-utilizar-json-object-get-string-com-resposta-do
JSON_Value const *user_data = json_parse_string(response);
const char *msgs = json_object_get_string(json_object(user_data), "message");
__android_log_print(ANDROID_LOG_INFO, "-----from--jni-1-----", "Json Message 1. [%s] \n", msgs);
example I/-----from--jni-1-----: Json Message 1. [(null)]
response: {"name":"qualquer um", "message":"ano 2016"}
What is going on with this code? @kgabis
Are there any documents describing the apis?
Is there function to serialize (similar to JSON.stringify) ?
Just a suggestion, but many json parsers escape "/" because in script tags "</" is not allowed, so there's a slight chance having some json in a script tag can lead to invalid html. I think it's just a matter of adding a case in json_serialize_string:
case '/': APPEND_STRING("\/"); break;
if there is a number field in json, and call json_object_get_number to get the number, it will return 0 in case of failed, and if it is a real 0, it returns 0. but get not existed field also returns 0, It can't be decide the call is failed or a real 0 or not existed.
Can't process some UTF-8 symbols.
JSON example: http://pastebin.com/3ZzNPup5
Fail to serialize "\u0001" in end of file.
My simple code:
JSON_Value *root_value = json_parse_file(jsonfile1);
assert(root_value);
json_serialize_to_file(root_value, jsonfile2);
JSON_Value * second_root_value = json_parse_file(jsonfile2);
assert(second_root_value);
jsonfile2 is incorrect JSON file.
second_root_value NULL.
just an fyi, tests are failing on ubuntu. see this gist.
[TestParson.json was here]
Repro code:
#include "parson.h"
#include <assert.h>
int main() {
JSON_Value * root_value = json_parse_file("TestParson.json");
assert(json_value_get_type(root_value) == JSONArray);
json_value_free(root_value);
}
Assert is triggered despite that JSON file is correct
Hi there,
I'm switched on the undefined behaviour sanitizer on clang. That gives me two runtime errors according to parson.c.
parson.c:420:24: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')
#0 0x42bc0c in json_object_free c/parson/parson.c:388
parson.c:477:24: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')
#0 0x42c209 in json_array_free /c/parson/parson.c:443
Both issues came from this statement: while (array->count--)
and count is an unsigned long. Please fix it by adding an additional check, maybe in this way: while (array->count && array->count--)
so that you only decrement if not zero.
Best Regards,
Ingo
Hello,
Is there any way to insert JSON objects in to JSON Array?
Eg:-
"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter","lastName":"Jones"}
]
I tried to parse the string in the above format and put it in to an array using json_parse_string(). Which I couldn't succeed.
Could you give some pointers to this?
Thanks,
Sajeesh.
Here's the input that will trigger the issue:
leak.txt
Feed it into the json_parse_string() function on master(e410fc7) built with AddressSanitizer will crash the program:
> ./parse leak.txt
=================================================================
==9905==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 2 byte(s) in 1 object(s) allocated from:
#0 0x4d6250 in __interceptor_malloc /home/grieve/LLVM/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:88
#1 0x521788 in process_string (/home/grieve/scratch/parson/main+0x521788)
#2 0x51f29e in get_quoted_string (/home/grieve/scratch/parson/main+0x51f29e)
#3 0x51ba2d in parse_object_value (/home/grieve/scratch/parson/main+0x51ba2d)
#4 0x50e8d5 in parse_value (/home/grieve/scratch/parson/main+0x50e8d5)
#5 0x50e137 in json_parse_string (/home/grieve/scratch/parson/main+0x50e137)
#6 0x50d993 in main (/home/grieve/scratch/parson/main+0x50d993)
#7 0x7f80f45784c9 in __libc_start_main (/usr/lib/libc.so.6+0x204c9)
SUMMARY: AddressSanitizer: 2 byte(s) leaked in 1 allocation(s).
Here's the full source code of parse.c I used in testing:
#include "parson.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
if (argc > 1) {
const char* filename = argv[1];
FILE* file = fopen(filename, "rb");
if (file != NULL) {
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
rewind(file);
char* buf = (char*)malloc(file_size + 1);
if (buf != NULL) {
fread(buf, file_size, 1, file);
buf[file_size] = 0;
JSON_Value* val = json_parse_string(buf);
if (val != NULL) {
json_value_free(val);
}
free(buf);
}
fclose(file);
}
}
}
something like:
char *string = json_serialize_to_pretty_string(value, " ");
/*
{
"foo": "bar",
"array": [
1,
2
"hello"
]
}
*/
would be wonderful :)
Hi,
I've found in trying to programatically generate a JSON structure that I'm having to make a lot of snprintf() calls to form the key name for a dotset*() operation when iterating over various pieces of data.
I was wondering if parson would benefit from understanding a printf-style string, and to interpolate that appropriately? I'm happy to do the work on the basis that it might be accepted.
This seems related to the fixes put in place for issue #24, but I'm now seeing NULL
values returned for any string which contains an escaped backslash.
Given the following code I'd expect name
to contain the value John\ Smith
. Instead, it's returned as NULL
.
JSON_Value *v = json_parse_string("{\"name\":\"John\\ Smith\"}");
JSON_Object *o = json_value_get_object(v);
const char *name = json_object_get_string(o, "name");
printf("name: %s\n", name);
Hi,
Use of some custom allocators requires passing a context object with (mutable) allocator state. Currently parson doesn't really support such allocators and trying to get a saved state would require for example playing with static variables.
I forked the project and made an implementation that allows that, which you can check at my repo: https://github.com/Matthew-Jemielity/parson . It doesn't change the existing API, but adds some new types and a function. I'm creating this issue as per readme to discuss it. If you think the change is useful, I'll make a pull request.
Regards,
Matt.
Maybe settable in config value for return of get_number function would be good idea. Currently return if it's wrong is 0, so if you expect 0 in some of numbers, without validation using schema before-hand it's impossible to easily check if returned value is caused by failure.
json_serialize_to_string()
escapes "/"
, though it doesn't need to:
int main(void) {
JSON_Value *object = NULL;
JSON_Status ret;
char *json = NULL;
object = json_value_init_object();
ret = json_object_set_string(json_object(object), "foo/bar", "1.2.3");
if (JSONSuccess != ret) {
fprintf(stderr, "OH NO!!\n");
json_value_free(object);
return 1;
}
json = json_serialize_to_string(object);
printf("%s\n", json);
free(json);
json_value_free(object);
return 0;
}
yields:
./example
{"foo\/bar":"1.2.3"}
though {"foo/bar":"1.2.3"}
is perfectly valid.
I have the patch here: https://gist.github.com/jamesbond3142/19a857d2cc31e2fd550f8fd129d5802f
It's quick and dirty and the format is supposed to be constant (not malloc-ed or snprintf etc) as no memory management is done for that.
Backward compatible (I created new function name).
Currently used version of the library (Clone-Version 08.02.2016)
We have couple of findings from Code-quality tool:
File ID Severity Method Message
parson.c 142 Critical json_serialize_to_buffer_r Pointer 'key' returned from call to function 'json_object_get_name' at line 768 may be NULL and may be dereferenced at line 771.
parson.c 148 Critical json_value_equals Pointer 'a_string' returned from call to function 'json_value_get_string' at line 1722 may be NULL and will be dereferenced at line 1724.
parson.c 150 Critical json_serialize_to_buffer_r Pointer 'string' returned from call to function 'json_value_get_string' at line 797 may be NULL and will be dereferenced at line 798.
parson.c 152 Critical json_value_equals Pointer 'b_string' returned from call to function 'json_value_get_string' at line 1723 may be NULL and will be dereferenced at line 1724.
parson.c 155 Critical json_value_deep_copy Pointer 'temp_string' returned from call to function 'json_value_get_string' at line 1197 may be NULL and will be dereferenced at line 1198.
According to JSON standard, objects in array is supposed to be order sensitive (https://www.tutorialspoint.com/json/json_data_types.htm). However, according to the source code, when an object in the array is removed, last object in the array is to be used to replace the index it occupies.
This logic could potentially disrupt some functions that take advantage of the ordered nature of array. Do you think this logic should be adjusted to shifting all indices larger than ix left by 1
?
In the implementation, I see multiple instances where NULL
is used to check the sanity of the array. If pointer pointing to NULL
while a pointer to an JSON_Value
is expected, the function returns JSONFailure
. This design is OK if allocated space is properly zerorized. However, in current implementation, json_malloc
is a simple wrapper over the system malloc
, and does not provide all zero memory block. I recommend us change the implementation into a standard malloc followed by a memset.
On the other hand, in memory extension, is there any specific reason why malloc
and manual copy over is preferred over realloc
?
How can we wrap a JSON_Object *
, JSON_Array *
, const char*
, or double
around a JSON_Value
? Or is there such a feature that I've missed?
This could also be useful if e.g. you have a JSON_Object
but you want to use json_value_deep_copy
or json_serialize_to_string
—both receive JSON_Value *
arguments. Situations where you have an object but not a value include when it has been passed as a function argument.
Then we could do something like:
void a(const char *s) {
JSON_Value *v = json_parse_string(s);
JSON_Object *o = json_value_get_object(v);
// do lots of processing with o
b(o);
json_value_free(v);
}
void b(JSON_Object *o) {
// do lots of processing with o
printSomewhere(json_serialize_to_string(json_object_to_value(o)));
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.