1 /*
2 	C-Dogs SDL
3 	A port of the legendary (and fun) action/arcade cdogs.
4 
5 	Copyright (c) 2013-2021 Cong Xu
6 	All rights reserved.
7 
8 	Redistribution and use in source and binary forms, with or without
9 	modification, are permitted provided that the following conditions are met:
10 
11 	Redistributions of source code must retain the above copyright notice, this
12 	list of conditions and the following disclaimer.
13 	Redistributions in binary form must reproduce the above copyright notice,
14 	this list of conditions and the following disclaimer in the documentation
15 	and/or other materials provided with the distribution.
16 
17 	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 	POSSIBILITY OF SUCH DAMAGE.
28 */
29 #include "json_utils.h"
30 
31 #include <errno.h>
32 #include <stdlib.h>
33 
34 #include "config.h"
35 #include "log.h"
36 #include "pic_manager.h"
37 #include "sys_config.h"
38 #include "weapon.h"
39 
AddIntPair(json_t * parent,const char * name,int number)40 void AddIntPair(json_t *parent, const char *name, int number)
41 {
42 	char buf[32];
43 	sprintf(buf, "%d", number);
44 	json_insert_pair_into_object(parent, name, json_new_number(buf));
45 }
AddBoolPair(json_t * parent,const char * name,int value)46 void AddBoolPair(json_t *parent, const char *name, int value)
47 {
48 	json_insert_pair_into_object(parent, name, json_new_bool(value));
49 }
AddStringPair(json_t * parent,const char * name,const char * s)50 void AddStringPair(json_t *parent, const char *name, const char *s)
51 {
52 	if (!s)
53 	{
54 		json_insert_pair_into_object(parent, name, json_new_string(""));
55 	}
56 	else
57 	{
58 		json_insert_pair_into_object(
59 			parent, name, json_new_string(json_escape(s)));
60 	}
61 }
AddColorPair(json_t * parent,const char * name,const color_t c)62 void AddColorPair(json_t *parent, const char *name, const color_t c)
63 {
64 	char buf[COLOR_STR_BUF];
65 	ColorStr(buf, c);
66 	AddStringPair(parent, name, buf);
67 }
AddVec2iPair(json_t * parent,const char * name,const struct vec2i v)68 void AddVec2iPair(json_t *parent, const char *name, const struct vec2i v)
69 {
70 	json_t *node = json_new_array();
71 	char buf[32];
72 	sprintf(buf, "%d", v.x);
73 	json_insert_child(node, json_new_number(buf));
74 	sprintf(buf, "%d", v.y);
75 	json_insert_child(node, json_new_number(buf));
76 	json_insert_pair_into_object(parent, name, node);
77 }
AddRect2iPair(json_t * parent,const char * name,const Rect2i r)78 void AddRect2iPair(json_t *parent, const char *name, const Rect2i r)
79 {
80 	json_t *node = json_new_array();
81 	char buf[32];
82 	sprintf(buf, "%d", r.Pos.x);
83 	json_insert_child(node, json_new_number(buf));
84 	sprintf(buf, "%d", r.Pos.y);
85 	json_insert_child(node, json_new_number(buf));
86 	sprintf(buf, "%d", r.Size.x);
87 	json_insert_child(node, json_new_number(buf));
88 	sprintf(buf, "%d", r.Size.y);
89 	json_insert_child(node, json_new_number(buf));
90 	json_insert_pair_into_object(parent, name, node);
91 }
AddIntArray(json_t * parent,const char * name,const CArray * a)92 void AddIntArray(json_t *parent, const char *name, const CArray *a)
93 {
94 	json_t *node = json_new_array();
95 	CA_FOREACH(int, i, *a)
96 	char buf[32];
97 	sprintf(buf, "%d", *i);
98 	json_insert_child(node, json_new_number(buf));
99 	CA_FOREACH_END()
100 	json_insert_pair_into_object(parent, name, node);
101 }
102 
TryLoadValue(json_t ** node,const char * name)103 bool TryLoadValue(json_t **node, const char *name)
104 {
105 	if (*node == NULL || (*node)->type != JSON_OBJECT)
106 	{
107 		return 0;
108 	}
109 	*node = json_find_first_label(*node, name);
110 	if (*node == NULL)
111 	{
112 		return 0;
113 	}
114 	*node = (*node)->child;
115 	if (*node == NULL)
116 	{
117 		return 0;
118 	}
119 	return 1;
120 }
LoadBool(bool * value,json_t * node,const char * name)121 void LoadBool(bool *value, json_t *node, const char *name)
122 {
123 	if (!TryLoadValue(&node, name))
124 	{
125 		return;
126 	}
127 	*value = node->type == JSON_TRUE;
128 }
LoadInt(int * value,json_t * node,const char * name)129 void LoadInt(int *value, json_t *node, const char *name)
130 {
131 	if (!TryLoadValue(&node, name))
132 	{
133 		return;
134 	}
135 	*value = atoi(node->text);
136 }
LoadDouble(double * value,json_t * node,const char * name)137 void LoadDouble(double *value, json_t *node, const char *name)
138 {
139 	if (!TryLoadValue(&node, name))
140 	{
141 		return;
142 	}
143 	*value = atof(node->text);
144 }
LoadFloat(float * value,json_t * node,const char * name)145 void LoadFloat(float *value, json_t *node, const char *name)
146 {
147 	if (!TryLoadValue(&node, name))
148 	{
149 		return;
150 	}
151 	*value = strtof(node->text, NULL);
152 }
LoadFullInt(float * value,json_t * node,const char * name)153 void LoadFullInt(float *value, json_t *node, const char *name)
154 {
155 	if (!TryLoadValue(&node, name))
156 	{
157 		return;
158 	}
159 	const int fullValue = atoi(node->text);
160 	*value = fullValue / 256.0f;
161 }
LoadVec2i(struct vec2i * value,json_t * node,const char * name)162 void LoadVec2i(struct vec2i *value, json_t *node, const char *name)
163 {
164 	if (!TryLoadValue(&node, name))
165 	{
166 		return;
167 	}
168 	node = node->child;
169 	value->x = atoi(node->text);
170 	node = node->next;
171 	value->y = atoi(node->text);
172 }
LoadVec2(struct vec2 * value,json_t * node,const char * name)173 void LoadVec2(struct vec2 *value, json_t *node, const char *name)
174 {
175 	if (!TryLoadValue(&node, name))
176 	{
177 		return;
178 	}
179 	node = node->child;
180 	value->x = strtof(node->text, NULL);
181 	node = node->next;
182 	value->y = strtof(node->text, NULL);
183 }
LoadRect2i(Rect2i * value,json_t * node,const char * name)184 void LoadRect2i(Rect2i *value, json_t *node, const char *name)
185 {
186 	if (!TryLoadValue(&node, name))
187 	{
188 		return;
189 	}
190 	node = node->child;
191 	value->Pos.x = atoi(node->text);
192 	node = node->next;
193 	value->Pos.y = atoi(node->text);
194 	node = node->next;
195 	value->Size.x = atoi(node->text);
196 	node = node->next;
197 	value->Size.y = atoi(node->text);
198 }
LoadIntArray(CArray * a,const json_t * node,const char * name)199 void LoadIntArray(CArray *a, const json_t *node, const char *name)
200 {
201 	const json_t *child = json_find_first_label(node, name);
202 	if (!child || !child->child)
203 	{
204 		return;
205 	}
206 	child = child->child;
207 	for (child = child->child; child; child = child->next)
208 	{
209 		const int n = atoi(child->text);
210 		CArrayPushBack(a, &n);
211 	}
212 }
213 
LoadStr(char ** value,json_t * node,const char * name)214 void LoadStr(char **value, json_t *node, const char *name)
215 {
216 	if (!TryLoadValue(&node, name))
217 	{
218 		return;
219 	}
220 	*value = json_unescape(node->text);
221 }
GetString(const json_t * node,const char * name)222 char *GetString(const json_t *node, const char *name)
223 {
224 	return json_unescape(json_find_first_label(node, name)->child->text);
225 }
LoadSoundFromNode(Mix_Chunk ** value,json_t * node,const char * name)226 void LoadSoundFromNode(Mix_Chunk **value, json_t *node, const char *name)
227 {
228 	if (json_find_first_label(node, name) == NULL)
229 	{
230 		return;
231 	}
232 	if (!TryLoadValue(&node, name))
233 	{
234 		return;
235 	}
236 	*value = StrSound(node->text);
237 }
LoadPic(const Pic ** value,json_t * node,const char * name)238 void LoadPic(const Pic **value, json_t *node, const char *name)
239 {
240 	if (json_find_first_label(node, name))
241 	{
242 		char *tmp = GetString(node, name);
243 		*value = PicManagerGetPic(&gPicManager, tmp);
244 		CFREE(tmp);
245 	}
246 }
LoadBulletGuns(CArray * guns,json_t * node,const char * name)247 void LoadBulletGuns(CArray *guns, json_t *node, const char *name)
248 {
249 	node = json_find_first_label(node, name);
250 	if (node == NULL || node->child == NULL)
251 	{
252 		return;
253 	}
254 	CArrayInit(guns, sizeof(const WeaponClass *));
255 	for (json_t *gun = node->child->child; gun; gun = gun->next)
256 	{
257 		const WeaponClass *wc = StrWeaponClass(gun->text);
258 		CArrayPushBack(guns, &wc);
259 	}
260 }
LoadColor(color_t * c,json_t * node,const char * name)261 void LoadColor(color_t *c, json_t *node, const char *name)
262 {
263 	if (json_find_first_label(node, name) == NULL)
264 	{
265 		return;
266 	}
267 	if (!TryLoadValue(&node, name))
268 	{
269 		return;
270 	}
271 	*c = StrColor(node->text);
272 }
273 
JSONFindNode(json_t * node,const char * path)274 json_t *JSONFindNode(json_t *node, const char *path)
275 {
276 	char *pathCopy;
277 	CSTRDUP(pathCopy, path);
278 	char *pch = strtok(pathCopy, "/");
279 	while (pch != NULL)
280 	{
281 		node = json_find_first_label(node, pch);
282 		if (node == NULL)
283 		{
284 			goto bail;
285 		}
286 		node = node->child;
287 		if (node == NULL)
288 		{
289 			goto bail;
290 		}
291 		pch = strtok(NULL, "/");
292 	}
293 bail:
294 	CFREE(pathCopy);
295 	return node;
296 }
297 
TrySaveJSONFile(json_t * node,const char * filename)298 bool TrySaveJSONFile(json_t *node, const char *filename)
299 {
300 	bool res = true;
301 	char *text;
302 	json_tree_to_string(node, &text);
303 	char *ftext = json_format_string(text);
304 	FILE *f = fopen(filename, "w");
305 	if (f == NULL)
306 	{
307 		LOG(LM_MAIN, LL_ERROR, "failed to open file(%s) for saving: %s",
308 			filename, strerror(errno));
309 		res = false;
310 		goto bail;
311 	}
312 	size_t writeLen = strlen(ftext);
313 	const size_t rc = fwrite(ftext, 1, writeLen, f);
314 	if (rc != writeLen)
315 	{
316 		LOG(LM_MAIN, LL_ERROR, "Wrote (%d) of (%d) bytes: %s", (int)rc,
317 			(int)writeLen, strerror(errno));
318 		res = false;
319 		goto bail;
320 	}
321 
322 bail:
323 	CFREE(text);
324 	CFREE(ftext);
325 	if (f != NULL)
326 		fclose(f);
327 	return res;
328 }
329