aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-10-28 12:04:09 -0700
committerAlon Zakai <alonzakai@gmail.com>2012-10-28 12:04:09 -0700
commitfab83ed0ade087a4a55648fb09c0c9cc95295a3f (patch)
tree8096651c122293ba1c176085a014549c4a48f840
parented88bc7051a61e05c6e85e792d56513826722d2e (diff)
parentf1e8583e475e32e47aa1fd7d42388b144604477b (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.js265
-rw-r--r--system/include/jansson.h80
-rwxr-xr-xtests/runner.py30
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