diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-10-28 12:04:09 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-10-28 12:04:09 -0700 |
commit | fab83ed0ade087a4a55648fb09c0c9cc95295a3f (patch) | |
tree | 8096651c122293ba1c176085a014549c4a48f840 | |
parent | ed88bc7051a61e05c6e85e792d56513826722d2e (diff) | |
parent | f1e8583e475e32e47aa1fd7d42388b144604477b (diff) |
Merge pull request #651 from larsxschneider/json_parser
Fix -O1 warning and use proper pointers for Jansson library.
-rw-r--r-- | src/library_jansson.js | 265 | ||||
-rw-r--r-- | system/include/jansson.h | 80 | ||||
-rwxr-xr-x | tests/runner.py | 30 |
3 files changed, 255 insertions, 120 deletions
diff --git a/src/library_jansson.js b/src/library_jansson.js index 8ecb535b..368584a7 100644 --- a/src/library_jansson.js +++ b/src/library_jansson.js @@ -10,122 +10,199 @@ var LibraryJansson = { $JANSSON: { - load: function(string, flags, error) { - var json_obj = eval('(' + string + ')'); + // Returns the node ID to which the pointer `nodePtr` points to + getNodeIDByPtr: function(nodePtr) { + if (nodePtr) + return {{{ makeGetValue('nodePtr', '0', 'i32') }}}; + else + return 0; + }, - if (json_obj != null) { - // Create the root node with the nodeID `1` - g_json_context = [null, {"name" : "root", "node" : json_obj}]; - return 1; - } else { - g_json_context = null; + // Returns the Javascript node object which is referenced by `nodeID` + getNodeByID: function(nodeID) { + if (!g_json_context) { + console.log("Jansson: No JSON context."); return null; } - }, - type: function(nodeID) { - if (!g_json_context) + var node = g_json_context[nodeID]; + if (!node) { + console.log("Jansson: Node with ID `" + nodeID + "` not found. Context has `" + g_json_context.length + "` nodes."); return null; + } - var node = g_json_context[nodeID].node; - if (typeof(node) === 'object' && (node instanceof Array)) - return 'array' - else - return typeof(node); + return node; }, - getNode: function(parentNodeID) { - if (!g_json_context) + // Returns the Javascript node object to which is referenced by `nodePtr` (via node ID). + getNodeByPtr: function(nodePtr) { + var nodeID = JANSSON.getNodeIDByPtr(nodePtr); + var node = JANSSON.getNodeByID(nodeID); + return node; + }, + + // Returns the pointer to the `nodeID` of the node that is referenced by `nodeID` + getNodePtrByID: function(nodeID) { + if (nodeID <= 0) return null; + + var node = JANSSON.getNodeByID(nodeID); - var parentNode = g_json_context[parentNodeID]; - - if (!parentNode) { - console.log("Jansson: Node with ID `" + parentNodeID + "` not found."); + if (!node) + return null; + + return node['nodeIDPtr']; + }, + + // Adds a Javascript node object to the Javascript JSON context + allocNode: function(name, node) { + var id = g_json_context.length; + g_json_context[id] = {}; + g_json_context[id]['name'] = name; + g_json_context[id]['node'] = node; + g_json_context[id]['nodeIDPtr'] = _malloc(32); + {{{ makeSetValue('g_json_context[id][\'nodeIDPtr\']', '0', 'id', 'i32') }}} + return id; + }, + + // Frees all memory that might have been allocated for a given node + freeNode: function(node) { + node['name'] = null; + node['node'] = null; + _free(node['nodeIDPtr']); + _free(node['keyPtr']); + _free(node['stringValuePtr']); + }, + + // Loads a string into the Javascript JSNON context + // Only the root node is loaded. Child nodes are loaded on demand via `loadChildNodes` method. + load: function(string, flags, error) { + // This is potentially a security problem. + // TODO: Make sure everything is properly escaped + var json_obj = eval('(' + string + ')'); + + if (json_obj != null) { + // The context is an array storing all child nodes. + // These child nodes are added to the array on demand. + // The root node is at index `1` (index `0` is intentionally `null`) + g_json_context = [null]; + var nodeID = JANSSON.allocNode('root', json_obj); + return JANSSON.getNodePtrByID(nodeID); + } else { + g_json_context = null; return null; } + }, + + // Loads the child nodes of a given node (if the node has any) into the Javascript JSON context. + loadChildNodes: function(node) { + if (!node) + return null; // Add all child nodes of the parent node to the context. // Consequently we can access these child nodes with an ID (pointer) // TODO: Here is room for performance improvements - if (!parentNode.begin) { + if (!node.begin) { var childNodeID = g_json_context.length; - for(var childNode in parentNode.node) { - var childNodeID = g_json_context.length; - g_json_context[childNodeID] = {"name" : childNode, "node" : parentNode.node[childNode]}; - if (!parentNode.begin) parentNode.begin = childNodeID; + for(var childNode in node['node']) { + var childNodeID = JANSSON.allocNode(childNode, node['node'][childNode]); + if (!node.begin) node.begin = childNodeID; }; - parentNode.end = childNodeID; + node.end = childNodeID; } - return parentNode; + return node; + }, + + // Returns the content type (object, array, string, number, null) of the node referenced by `nodePtr` + type: function(nodePtr) { + var node = JANSSON.getNodeByPtr(nodePtr); + if (!node) + return null; + + var content = node['node']; + if (typeof(content) === 'object' && (content instanceof Array)) + return 'array' + else + { + return typeof(content); + } } }, json_loads: function(string, flags, error) { - return JANSSON.load(Pointer_stringify(string), flags, error); + return JANSSON.load(Pointer_stringify(string), flags, error); }, json_loadb: function(buffer, buflen, flags, error) { return JANSSON.load(Pointer_stringify(buffer).substr(0, buflen), flags, error); }, - json_is_object: function(nodeID) { - return (JANSSON.type(nodeID) === 'object'); + json_is_object: function(nodePtr) { + return (JANSSON.type(nodePtr) === 'object'); }, - json_is_array: function(nodeID) { - return (JANSSON.type(nodeID) === 'array'); + json_is_array: function(nodePtr) { + return (JANSSON.type(nodePtr) === 'array'); }, - json_is_string: function(nodeID) { - return (JANSSON.type(nodeID) === 'string'); + json_is_string: function(nodePtr) { + return (JANSSON.type(nodePtr) === 'string'); }, - json_is_integer: function(nodeID) { - return (JANSSON.type(nodeID) === 'number'); + json_is_integer: function(nodePtr) { + return (JANSSON.type(nodePtr) === 'number'); }, - json_is_real: function(nodeID) { - return (JANSSON.type(nodeID) === 'number'); + json_is_real: function(nodePtr) { + return (JANSSON.type(nodePtr) === 'number'); }, - json_is_number: function(nodeID) { - return (JANSSON.type(nodeID) === 'number'); + json_is_number: function(nodePtr) { + return (JANSSON.type(nodePtr) === 'number'); }, - json_is_null: function(nodeID) { - var nodeType = JANSSON.type(nodeID); + json_is_null: function(nodePtr) { + var nodeType = JANSSON.type(nodePtr); return (nodeType === 'undefined' || nodeType === 'null'); }, - json_object_get: function(parentNodeID, key) { + // Returns the pointer to the child node with the key `key` of the given parent node + json_object_get: function(parentNodePtr, key) { var key = Pointer_stringify(key); - var parentNode = JANSSON.getNode(parentNodeID); + var parentNode = JANSSON.getNodeByPtr(parentNodePtr); if (!parentNode) return null; - // Find the ID (pointer) of the requested child node + JANSSON.loadChildNodes(parentNode); + + // Find the requested child node for (var i=parentNode.begin; i<=parentNode.end; i++) { - if (g_json_context[i].name == key) return i; + if (g_json_context[i]['name'] === key) + return JANSSON.getNodePtrByID(i); } return null; }, - json_object_iter: function(parentNodeID) { - var parentNode = JANSSON.getNode(parentNodeID); + // Returns the pointer to the first child node of the given parent node + json_object_iter: function(parentNodePtr) { + var parentNode = JANSSON.getNodeByPtr(parentNodePtr); if (!parentNode) return null; - return parentNode.begin; + JANSSON.loadChildNodes(parentNode); + + return JANSSON.getNodePtrByID(parentNode.begin); }, - json_object_iter_next: function(parentNodeID, childNodeID) { - var parentNode = JANSSON.getNode(parentNodeID); + // Returns a pointer to the child node after the given child node of the given parent node + json_object_iter_next: function(parentNodePtr, childNodePtr) { + var parentNode = JANSSON.getNodeByPtr(parentNodePtr); + var childNodeID = JANSSON.getNodeIDByPtr(childNodePtr); if (!parentNode) return null; @@ -133,91 +210,109 @@ var LibraryJansson = { if (childNodeID < parentNode.begin || childNodeID >= parentNode.end) return null; else - return childNodeID+1; + return JANSSON.getNodePtrByID(childNodeID+1); }, - json_array_size: function(parentNodeID, index) { - var parentNode = JANSSON.getNode(parentNodeID); + // Returns a integer containing the size of an array + json_array_size: function(parentNodePtr) { + var parentNode = JANSSON.getNodeByPtr(parentNodePtr); if (!parentNode) return 0; - var size = parentNode.end - parentNode.begin + 1; + JANSSON.loadChildNodes(parentNode); + var size = parentNode.end - parentNode.begin + 1; if (size < 0) size = 0; - return size; }, - json_array_get: function(parentNodeID, index) { - var parentNode = JANSSON.getNode(parentNodeID); - var position = parentNode.begin + index; + // Returns the pointer of the node with the index `index` in a given array parent node + json_array_get: function(parentNodePtr, index) { + var parentNode = JANSSON.getNodeByPtr(parentNodePtr); + JANSSON.loadChildNodes(parentNode); + var position = parentNode.begin + index; if (position < parentNode.begin || position > parentNode.end) return null; else - return position; + return JANSSON.getNodePtrByID(position); }, - json_object_iter_key: function(nodeID) { - var node = g_json_context[nodeID]; - + json_object_iter_key: function(nodePtr) { + var node = JANSSON.getNodeByPtr(nodePtr); if (!node) return null; - return allocate(intArrayFromString(node.name), 'i8', ALLOC_NORMAL); + if (!node['keyPtr']) { + node['keyPtr'] = allocate(intArrayFromString(node['name']), 'i8', ALLOC_NORMAL); + } + + return node['keyPtr']; }, - json_object_iter_value: function(nodeID) { - return nodeID; + json_object_iter_value: function(nodePtr) { + return nodePtr; }, - json_string_value: function(nodeID) { - var node = g_json_context[nodeID]; + json_string_value: function(nodePtr) { + var node = JANSSON.getNodeByPtr(nodePtr); if (!node) + { + console.log("Jansson: invalid node in `function json_string_value`"); return null; + } + + if (!node['stringValuePtr']) { + node['stringValuePtr'] = allocate(intArrayFromString(node['node']), 'i8', ALLOC_NORMAL); + } - return allocate(intArrayFromString(node.node), 'i8', ALLOC_NORMAL); + return node['stringValuePtr']; }, - json_integer_value: function(nodeID) { - var node = g_json_context[nodeID]; + json_integer_value: function(nodePtr) { + var node = JANSSON.getNodeByPtr(nodePtr); if (!node) return null; // Convert JSON number to an integer // c.f. http://stackoverflow.com/questions/596467/how-do-i-convert-a-float-to-an-int-in-javascript - if (node.node<0) - return Math.ceil(node.node); + if (node['node']<0) + return Math.ceil(node['node']); else - return Math.floor(node.node); + return Math.floor(node['node']); }, - json_real_value: function(nodeID) { - var node = g_json_context[nodeID]; + json_real_value: function(nodePtr) { + var node = JANSSON.getNodeByPtr(nodePtr); if (!node) return null; - return node.node; + return node['node']; }, - json_number_value: function(nodeID) { - var node = g_json_context[nodeID]; + json_number_value: function(nodePtr) { + var node = JANSSON.getNodeByPtr(nodePtr); if (!node) return null; - return node.node; + return node['node']; }, - json_delete: function(nodeID) { - // We assume, if the root node's reference count is decreased, we can forget the context. - if (nodeID == 1) + json_delete: function(nodePtr) { + // We assume, if the root node is deleted, all nodes and the context are deleted. + if (JANSSON.getNodeIDByPtr(nodePtr) == 1) { + for (var node in g_json_context) { + JANSSON.freeNode(node); + } + g_json_context = null; + } } }; diff --git a/system/include/jansson.h b/system/include/jansson.h index fc9d7f70..04c345e9 100644 --- a/system/include/jansson.h +++ b/system/include/jansson.h @@ -94,7 +94,25 @@ typedef long json_int_t; extern "C" bool json_is_false(const void *object); extern "C" bool json_is_boolean(const void *object); extern "C" bool json_is_null(const void *object); + + static JSON_INLINE + json_t *json_incref(json_t *json) + { + return json; + } + + void json_delete(json_t *json); + + static JSON_INLINE + void json_decref(json_t *json) + { + json_delete(json); + } + #else + + // typedef json_t* json_ptr_t; + #define json_typeof(json) ((json)->type) #define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT) #define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY) @@ -106,38 +124,38 @@ typedef long json_int_t; #define json_is_false(json) (json && json_typeof(json) == JSON_FALSE) #define json_is_boolean(json) (json_is_true(json) || json_is_false(json)) #define json_is_null(json) (json && json_typeof(json) == JSON_NULL) -#endif - -/* construction, destruction, reference counting */ - -json_t *json_object(void); -json_t *json_array(void); -json_t *json_string(const char *value); -json_t *json_string_nocheck(const char *value); -json_t *json_integer(json_int_t value); -json_t *json_real(double value); -json_t *json_true(void); -json_t *json_false(void); -#define json_boolean(val) ((val) ? json_true() : json_false()) -json_t *json_null(void); -static JSON_INLINE -json_t *json_incref(json_t *json) -{ - if(json && json->refcount != (size_t)-1) - ++json->refcount; - return json; -} - -/* do not call json_delete directly */ -void json_delete(json_t *json); - -static JSON_INLINE -void json_decref(json_t *json) -{ - if(json && json->refcount != (size_t)-1 && --json->refcount == 0) - json_delete(json); -} + /* construction, destruction, reference counting */ + + json_t *json_object(void); + json_t *json_array(void); + json_t *json_string(const char *value); + json_t *json_string_nocheck(const char *value); + json_t *json_integer(json_int_t value); + json_t *json_real(double value); + json_t *json_true(void); + json_t *json_false(void); + #define json_boolean(val) ((val) ? json_true() : json_false()) + json_t *json_null(void); + + static JSON_INLINE + json_t *json_incref(json_t *json) + { + if(json && json->refcount != (size_t)-1) + ++json->refcount; + return json; + } + + /* do not call json_delete directly */ + void json_delete(json_t *json); + + static JSON_INLINE + void json_decref(json_t *json) + { + if(json && json->refcount != (size_t)-1 && --json->refcount == 0) + json_delete(json); + } +#endif /* error reporting */ diff --git a/tests/runner.py b/tests/runner.py index 5780b910..71acb4da 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -5324,13 +5324,29 @@ int main(int argc, char **argv) { json_error_t error; json_t *root = json_loadb(jsonString, strlen(jsonString), 0, &error); - if(!root || !json_is_object(root)) + if(!root) { + printf("Node `root` is `null`."); return 0; + } + + if(!json_is_object(root)) { + printf("Node `root` is no object."); + return 0; + } + printf("%s\\n", json_string_value(json_object_get(root, "key"))); json_t *array = json_object_get(root, "array"); - if(!array || !json_is_array(array)) + if(!array) { + printf("Node `array` is `null`."); + return 0; + } + + if(!json_is_array(array)) { + printf("Node `array` is no array."); return 0; + } + for(size_t i=0; i<json_array_size(array); ++i) { json_t *arrayNode = json_array_get(array, i); @@ -5349,11 +5365,17 @@ int main(int argc, char **argv) { if(!numberNode || !json_is_number(numberNode) || !floatNode || !json_is_real(floatNode)) return 0; - + printf("%i\\n", json_integer_value(numberNode)); printf("%.2f\\n", json_number_value(numberNode)); printf("%.2f\\n", json_real_value(floatNode)); + json_t *invalidNode = json_object_get(dict, "invalidNode"); + if(invalidNode) + return 0; + + printf("%i\\n", json_number_value(invalidNode)); + json_decref(root); if(!json_is_object(root)) @@ -5362,7 +5384,7 @@ int main(int argc, char **argv) { return 0; } ''' - self.do_run(src, 'value\narray_item1\narray_item2\narray_item3\n3\n3.00\n2.20\njansson!') + self.do_run(src, 'value\narray_item1\narray_item2\narray_item3\n3\n3.00\n2.20\nJansson: Node with ID `0` not found. Context has `10` nodes.\n0\nJansson: No JSON context.\njansson!') ### 'Medium' tests |