summaryrefslogtreecommitdiff
path: root/json.c
diff options
context:
space:
mode:
authorJoey Adams2010-08-06 08:06:01 +0000
committerJoey Adams2010-08-06 08:06:01 +0000
commitf9f677a465a5746874dc2f2c86cc444ffa28a020 (patch)
treedaae58795aaf5c7facc04fa5939a8a5e25884aac /json.c
parente87340e2b0c533d1c1d08ddee6471757bc27b74f (diff)
Added more comments to json.c / json.h and cleaned it up a bit.
Also made json_delete a little less confusing (but it still uses gotos).
Diffstat (limited to 'json.c')
-rw-r--r--json.c93
1 files changed, 72 insertions, 21 deletions
diff --git a/json.c b/json.c
index 948971a..46953fa 100644
--- a/json.c
+++ b/json.c
@@ -51,7 +51,7 @@ end_parenthesis(JSON * node)
/*
* Reads exactly 4 hex characters (capital or lowercase).
* Writes the result to *out .
- * Returns true on success, false on failure.
+ * Returns true on success, false if any input chars are not [0-9A-Fa-f] .
*/
static bool
read_hex16(const char *in, unsigned int *out)
@@ -81,6 +81,10 @@ read_hex16(const char *in, unsigned int *out)
return true;
}
+/*
+ * Encodes a 16-bit number into hexadecimal,
+ * writing exactly 4 hex chars.
+ */
static void
write_hex16(char *out, unsigned int val)
{
@@ -137,7 +141,8 @@ json_mknumber(const char *number, size_t length)
return node;
}
-/* Indicate that the node's value has changed,
+/*
+ * Indicate that the node's value has changed,
* marking ancestors as necessary.
*
* Call json_touch_value so that json_encode(, JSONOPT_ORIG)
@@ -153,6 +158,12 @@ json_touch_value(JSON * node)
}
}
+/*
+ * Add child to parent, but don't clear orig pointers of ancestors.
+ *
+ * This is used by json_decode to ensure that original text segments
+ * are preserved while building the JSON tree.
+ */
static void
json_append_notouch(JSON * parent, JSON * child)
{
@@ -175,6 +186,12 @@ json_append_notouch(JSON * parent, JSON * child)
}
}
+/*
+ * json_append
+ * Add child to parent, putting it at the end of its child list.
+ *
+ * Child must not already have another parent.
+ */
void
json_append(JSON * parent, JSON * child)
{
@@ -182,6 +199,10 @@ json_append(JSON * parent, JSON * child)
json_touch_value(parent);
}
+/*
+ * json_remove
+ * Remove node from its parent, but do not delete it.
+ */
void
json_remove(JSON * node)
{
@@ -209,6 +230,16 @@ json_remove(JSON * node)
json_touch_value(parent);
}
+/*
+ * Update the value of a node, preserving position and key information.
+ *
+ * Note well: If replacement is an array or object with children, the parent
+ * pointers of those children will be incorrect
+ * (they'll still refer to their original parent).
+ *
+ * Untrustworthy parent pointers is the price to pay for
+ * being able to copy JSON values by reference.
+ */
void
json_replace_value(JSON * node, JSON * replacement)
{
@@ -289,7 +320,14 @@ free_node(JSON * node)
pfree(node);
}
-void
+/*
+ * Free a JSON node and all its descendants.
+ *
+ * Do not use this function if you have performed json_replace_value on
+ * a descendant, as this function relies on each node's ->parent field
+ * being trustworthy.
+ */
+static void
json_delete(JSON * node)
{
JSON *parent,
@@ -301,12 +339,9 @@ json_delete(JSON * node)
/* Remove node from parent (if it has one). */
json_remove(node);
- goto descend;
-
descend:
while (is_internal(node) && node->v.children.head)
node = node->v.children.head;
- goto advance;
advance:
parent = node->parent;
@@ -315,16 +350,17 @@ advance:
node = next;
if (node)
+ {
goto descend;
+ }
else
- goto ascend;
-
-ascend:
- node = parent;
- if (node)
- goto advance;
- else
- return;
+ {
+ node = parent;
+ if (node)
+ goto advance;
+ else
+ return;
+ }
}
@@ -701,9 +737,9 @@ decode_number(const char **sp)
* Also, no whitespace skipping is done, so the caller should only
* call this function when it expects **sp to be either " or '
*
- * On success, returns the decoded string, passes that string's length
- * through *length (which must not be NULL), and advances *sp to point
- * to the end of string literal (including the quote character).
+ * On success, returns the decoded string, passes the decoded string's
+ * length through *length (which must not be NULL), and advances *sp to point
+ * to the end of string literal (after the closing quote character).
*
* On failure (parse error), returns NULL and
* leaves *length and *sp untouched.
@@ -825,6 +861,12 @@ failed:
return NULL;
}
+/*
+ * json_text_type
+ * Determines the type of a JSON string without fully decoding it.
+ * Expects the given string to be valid JSON.
+ * Might return JSON_INVALID if something is wrong with the input.
+ */
json_type
json_text_type(const char *str, size_t nbytes)
{
@@ -871,8 +913,9 @@ encode_string(StringInfo out, const char *string, size_t length, char quote,
const char *s = string;
const char *e = s + length;
- Assert(utf8_validate(string, length));
Assert(quote != '\\');
+ if (escape_unicode)
+ Assert(utf8_validate(string, length));
appendStringInfoChar(out, quote);
@@ -990,6 +1033,13 @@ typedef struct
static bool json_encode_recurse(JSON * node, json_encode_ctx * ctx);
+/*
+ * json_encode
+ * Encode a JSON node.
+ *
+ * The JSONOPT_ESCAPE_UNICODE option may only be used
+ * if the strings in the JSON tree are UTF-8-encoded.
+ */
char *
json_encode(JSON * node, int options)
{
@@ -1127,9 +1177,10 @@ json_encode_recurse(JSON * node, json_encode_ctx * ctx)
* Note that using anything but '"' as the quote character will result
* in invalid JSON.
*
- * @str must be valid UTF-8, though it may contain null characters
- * (hence the length argument).
- * @quote must not be a backslash.
+ * If escape_unicode is true, str must be valid UTF-8.
+ * In any case, str may contain null characters (hence the length argument).
+ *
+ * quote must not be a backslash.
*/
char *
json_encode_string(const char *str, size_t length, char quote,