aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--matrix-json.c103
-rw-r--r--matrix-json.h4
2 files changed, 107 insertions, 0 deletions
diff --git a/matrix-json.c b/matrix-json.c
index 72a9deb..d2b9287 100644
--- a/matrix-json.c
+++ b/matrix-json.c
@@ -18,8 +18,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
+#include <stdio.h>
+#include <string.h>
#include "matrix-json.h"
+static GString *canonical_json_node(JsonNode *node, GString *result);
+static GString *canonical_json_object(JsonObject *object, GString *result);
+
/* node */
const gchar *matrix_json_node_get_string(JsonNode *node)
@@ -128,3 +133,101 @@ const gchar *matrix_json_array_get_string_element(JsonArray *array,
element = matrix_json_array_get_element(array, index);
return matrix_json_node_get_string(element);
}
+
+static gint canonical_json_sort(gconstpointer a, gconstpointer b)
+{
+ return strcmp((const gchar *)a, (const gchar *)b);
+}
+
+static GString *canonical_json_value(JsonNode *node, GString *result)
+{
+ GType vt = json_node_get_value_type(node);
+ switch (vt) {
+ case G_TYPE_STRING:
+ /* TODO: I'm assuming our strings are nice UTF-8 strings already */
+ result = g_string_append_c(result, '"');
+ result = g_string_append(result, json_node_get_string(node));
+ result = g_string_append_c(result, '"');
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown value type %zd\n", __func__,
+ (size_t)vt);
+ /* TODO: Other value types */
+ g_assert_not_reached();
+ }
+
+ return result;
+}
+
+static GString *canonical_json_array(JsonArray *arr, GString *result)
+{
+ guint nelems, i;
+ result = g_string_append_c(result, '[');
+ nelems = json_array_get_length(arr);
+ for(i = 0; i < nelems; i++) {
+ if (i) result=g_string_append_c(result, ',');
+ result = canonical_json_node(json_array_get_element(arr, i), result);
+ }
+ result = g_string_append_c(result, ']');
+
+ return result;
+}
+
+static GString *canonical_json_node(JsonNode *node, GString *result)
+{
+ switch (json_node_get_node_type(node)) {
+ case JSON_NODE_OBJECT:
+ result = canonical_json_object(json_node_get_object(node), result);
+ break;
+
+ case JSON_NODE_ARRAY:
+ result = canonical_json_array(json_node_get_array(node), result);
+ break;
+
+ case JSON_NODE_VALUE:
+ result = canonical_json_value(node, result);
+ break;
+
+ case JSON_NODE_NULL:
+ result = g_string_append(result, "null");
+ break;
+ }
+ return result;
+}
+
+static GString *canonical_json_object(JsonObject *object, GString *result)
+{
+ gboolean first = TRUE;
+ result = result ? g_string_append_c(result, '{') : g_string_new("{");
+
+ /* This gets an unsorted list of member names */
+ GList *members = json_object_get_members(object);
+ GList *cur;
+
+ members = g_list_sort(members, canonical_json_sort);
+ for(cur=g_list_first(members); cur; cur=g_list_next(cur)) {
+ const gchar *cur_name = cur->data;
+ JsonNode *cur_node = json_object_get_member(object, cur_name);
+ if (!first) result=g_string_append_c(result, ',');
+ first = FALSE;
+ result = g_string_append_c(result, '"');
+ result = g_string_append(result, cur_name);
+ result = g_string_append_c(result, '"');
+ result = g_string_append_c(result, ':');
+ result = canonical_json_node(cur_node, result);
+ }
+
+ g_list_free(members);
+
+ result = g_string_append_c(result, '}');
+ return result;
+}
+
+/* Produce a canonicalised string as defined in
+ * http://matrix.org/docs/spec/appendices.html#canonical-json
+ */
+GString *matrix_canonical_json(JsonObject *object)
+{
+ return canonical_json_object(object, NULL);
+}
diff --git a/matrix-json.h b/matrix-json.h
index b2c2820..1209a21 100644
--- a/matrix-json.h
+++ b/matrix-json.h
@@ -60,5 +60,9 @@ const gchar *matrix_json_array_get_string_element(JsonArray *array,
guint index);
+/* Produce a canonicalised string as defined in
+ * https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#canonical-json
+ */
+GString *matrix_canonical_json(JsonObject *object);
#endif /* MATRIX_JSON_H_ */