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