1 /*
2  * Hangouts Plugin for libpurple/Pidgin
3  * Copyright (c) 2015-2016 Eion Robb, Mike Ruprecht
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "hangouts_json.h"
20 
21 #include <debug.h>
22 
23 gchar *
json_encode(JsonNode * node,gsize * len)24 json_encode(JsonNode *node, gsize *len)
25 {
26 	gchar *data;
27 	JsonGenerator *generator = json_generator_new();
28 
29 	json_generator_set_root(generator, node);
30 
31 	data = json_generator_to_data(generator, len);
32 
33 	g_object_unref(generator);
34 
35 	return data;
36 }
37 
38 gchar *
json_pretty_encode(JsonNode * node,gsize * len)39 json_pretty_encode(JsonNode *node, gsize *len)
40 {
41 	gchar *data;
42 	JsonGenerator *generator = json_generator_new();
43 
44 	g_object_set(generator, "pretty", TRUE, NULL);
45 	g_object_set(generator, "indent-char", '\t', NULL);
46 	g_object_set(generator, "indent", 1, NULL);
47 
48 	json_generator_set_root(generator, node);
49 
50 	data = json_generator_to_data(generator, len);
51 
52 	g_object_unref(generator);
53 
54 	return data;
55 }
56 
57 gchar *
json_encode_array(JsonArray * array,gsize * len)58 json_encode_array(JsonArray *array, gsize *len)
59 {
60 	JsonNode *node = json_node_new(JSON_NODE_ARRAY);
61 	gchar *json;
62 
63 	json_node_set_array(node, array);
64 	json = json_encode(node, len);
65 
66 	json_node_free(node);
67 	return json;
68 }
69 
70 gchar *
json_encode_object(JsonObject * object,gsize * len)71 json_encode_object(JsonObject *object, gsize *len)
72 {
73 	JsonNode *node = json_node_new(JSON_NODE_OBJECT);
74 	gchar *json;
75 
76 	json_node_set_object(node, object);
77 	json = json_encode(node, len);
78 
79 	json_node_free(node);
80 	return json;
81 }
82 
83 JsonNode *
json_decode(const gchar * data,gssize len)84 json_decode(const gchar *data, gssize len)
85 {
86 	JsonParser *parser = json_parser_new();
87 	JsonNode *root = NULL;
88 
89 	if (!data || !json_parser_load_from_data(parser, data, len, NULL))
90 	{
91 		purple_debug_error("hangouts", "Error parsing JSON: %s\n", data);
92 	} else {
93 		root = json_parser_get_root(parser);
94 		if (root != NULL) {
95 			root = json_node_copy(root);
96 		}
97 	}
98 	g_object_unref(parser);
99 
100 	return root;
101 }
102 
103 JsonArray *
json_decode_array(const gchar * data,gssize len)104 json_decode_array(const gchar *data, gssize len)
105 {
106 	JsonNode *root = json_decode(data, len);
107 	JsonArray *ret;
108 
109 	g_return_val_if_fail(root, NULL);
110 
111 	if (!JSON_NODE_HOLDS_ARRAY(root)) {
112 		// That ain't my belly button!
113 		json_node_free(root);
114 		return NULL;
115 	}
116 
117 	ret = json_node_dup_array(root);
118 
119 	json_node_free(root);
120 
121 	return ret;
122 }
123 
124 JsonObject *
json_decode_object(const gchar * data,gssize len)125 json_decode_object(const gchar *data, gssize len)
126 {
127 	JsonNode *root = json_decode(data, len);
128 	JsonObject *ret;
129 
130 	g_return_val_if_fail(root, NULL);
131 
132 	if (!JSON_NODE_HOLDS_OBJECT(root)) {
133 		// That ain't my thumb, neither!
134 		json_node_free(root);
135 		return NULL;
136 	}
137 
138 	ret = json_node_dup_object(root);
139 
140 	json_node_free(root);
141 
142 	return ret;
143 }
144 
145 
146 JsonNode *
hangouts_json_path_query(JsonNode * root,const gchar * expr,GError ** error)147 hangouts_json_path_query(JsonNode *root, const gchar *expr, GError **error)
148 {
149 	JsonNode *ret;
150 	JsonNode *node;
151 	JsonArray *result;
152 
153 	if (g_str_equal(expr, "$")) {
154 		return root;
155 	}
156 
157 	node = json_path_query(expr, root, error);
158 
159 	if (error != NULL)
160 	{
161 		json_node_free(node);
162 		return NULL;
163 	}
164 
165 	result = json_node_get_array(node);
166 	if (json_array_get_length(result) == 0)
167 	{
168 		json_node_free(node);
169 		return NULL;
170 	}
171 	ret = json_array_dup_element(result, 0);
172 	json_node_free(node);
173 	return ret;
174 
175 }
176 
177 gchar *
hangouts_json_path_query_string(JsonNode * root,const gchar * expr,GError ** error)178 hangouts_json_path_query_string(JsonNode *root, const gchar *expr, GError **error)
179 {
180 	gchar *ret;
181 	JsonNode *rslt;
182 
183 	rslt = hangouts_json_path_query(root, expr, error);
184 
185 	if (rslt == NULL)
186 	{
187 		return NULL;
188 	}
189 
190 	ret = g_strdup(json_node_get_string(rslt));
191 	json_node_free(rslt);
192 	return ret;
193 }
194 
195 gint64
hangouts_json_path_query_int(JsonNode * root,const gchar * expr,GError ** error)196 hangouts_json_path_query_int(JsonNode *root, const gchar *expr, GError **error)
197 {
198 	gint64 ret;
199 	JsonNode *rslt;
200 
201 	rslt = hangouts_json_path_query(root, expr, error);
202 
203 	if (rslt == NULL)
204 	{
205 		return 0;
206 	}
207 
208 	ret = json_node_get_int(rslt);
209 	json_node_free(rslt);
210 	return ret;
211 }
212 
213 gchar *
hangouts_json_tidy_blank_arrays(const gchar * json)214 hangouts_json_tidy_blank_arrays(const gchar *json)
215 {
216 	static GRegex *tidy_regex = NULL;
217 
218 	if (tidy_regex == NULL) {
219 		tidy_regex = g_regex_new("\"(\\\\\"|.)*?\"(*SKIP)(*FAIL)|\\[\\](*SKIP)(*FAIL)|(?<=,|\\[)\\s*(?=,|\\])", G_REGEX_OPTIMIZE, 0, NULL);
220 	}
221 
222 	return g_regex_replace_literal(tidy_regex, json, -1, 0, "null", 0, NULL);
223 }
224 
225