1 /*
2 * Copyright (c) 2020, Rockchip Electronics Co., Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #include "j2s.h"
16
17 using namespace RkCam;
18
19 static bool j2s_template_dumping = false;
20
j2s_alloc_data(j2s_ctx * ctx,size_t size)21 __attribute__((weak)) void* j2s_alloc_data(j2s_ctx* ctx, size_t size)
22 {
23 return malloc(size);
24 }
25
j2s_release_data(j2s_ctx * ctx,void * ptr)26 __attribute__((weak)) void j2s_release_data(j2s_ctx* ctx, void* ptr)
27 {
28 free(ptr);
29 }
30
31 static cJSON* _j2s_obj_to_json(j2s_ctx* ctx, int obj_index, void* ptr);
32
33 static cJSON* _j2s_struct_to_json(j2s_ctx* ctx, int struct_index, void* ptr);
34
35 static int _j2s_json_to_obj(j2s_ctx* ctx, cJSON* json, cJSON* parent,
36 int obj_index, void* ptr, bool query);
37
38 static int _j2s_json_to_struct(j2s_ctx* ctx, cJSON* json, int struct_index,
39 void* ptr, bool query);
40
41 static int _j2s_obj_from_cache(j2s_ctx* ctx, int obj_index, int fd, void* ptr);
42
43 static int _j2s_struct_from_cache(j2s_ctx* ctx, int struct_index, int fd,
44 void* ptr);
45
46 static void _j2s_obj_to_cache(j2s_ctx* ctx, int obj_index, int fd, void* ptr);
47
48 static void _j2s_struct_to_cache(j2s_ctx* ctx, int struct_index, int fd,
49 void* ptr);
50
51 static int _j2s_struct_free(j2s_ctx* ctx, int struct_index, void* ptr);
52
j2s_find_struct_index(j2s_ctx * ctx,const char * name)53 static inline int j2s_find_struct_index(j2s_ctx* ctx, const char* name)
54 {
55 if (!name)
56 return -1;
57
58 for (int i = 0; i < ctx->num_struct; i++) {
59 j2s_struct* struct_obj = &ctx->structs[i];
60 if (!strcmp(struct_obj->name, name))
61 return i;
62 }
63
64 return -1;
65 }
66
j2s_struct_free(j2s_ctx * ctx,const char * name,void * ptr)67 int j2s_struct_free(j2s_ctx* ctx, const char* name, void* ptr)
68 {
69 int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
70
71 return _j2s_struct_free(ctx, struct_index, ptr);
72 }
73
j2s_struct_to_json(j2s_ctx * ctx,const char * name,void * ptr)74 cJSON* j2s_struct_to_json(j2s_ctx* ctx, const char* name, void* ptr)
75 {
76 int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
77
78 return _j2s_struct_to_json(ctx, struct_index, ptr);
79 }
80
j2s_json_to_struct(j2s_ctx * ctx,cJSON * json,const char * name,void * ptr)81 int j2s_json_to_struct(j2s_ctx* ctx, cJSON* json, const char* name, void* ptr)
82 {
83 int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
84
85 return _j2s_json_to_struct(ctx, json, struct_index, ptr, false);
86 }
87
j2s_json_from_struct(j2s_ctx * ctx,cJSON * json,const char * name,void * ptr)88 int j2s_json_from_struct(j2s_ctx* ctx, cJSON* json, const char* name,
89 void* ptr)
90 {
91 int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
92
93 return _j2s_json_to_struct(ctx, json, struct_index, ptr, true);
94 }
95
j2s_struct_to_cache(j2s_ctx * ctx,const char * name,int fd,void * ptr)96 void j2s_struct_to_cache(j2s_ctx* ctx, const char* name, int fd, void* ptr)
97 {
98 int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
99
100 _j2s_struct_to_cache(ctx, struct_index, fd, ptr);
101 }
102
j2s_struct_from_cache(j2s_ctx * ctx,const char * name,int fd,void * ptr)103 int j2s_struct_from_cache(j2s_ctx* ctx, const char* name, int fd, void* ptr)
104 {
105 int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
106
107 return _j2s_struct_from_cache(ctx, struct_index, fd, ptr);
108 }
109
110 /* Enum name to value */
j2s_enum_get_value(j2s_ctx * ctx,int enum_index,const char * name)111 static inline int j2s_enum_get_value(j2s_ctx* ctx, int enum_index,
112 const char* name)
113 {
114 j2s_enum* enum_obj;
115
116 if (enum_index < 0 || !name)
117 return -1;
118
119 enum_obj = &ctx->enums[enum_index];
120
121 for (int i = 0; i < enum_obj->num_value; i++) {
122 j2s_enum_value* enum_value = &ctx->enum_values[enum_obj->value_index + i];
123
124 if (!strcmp(enum_value->name, name))
125 return enum_value->value;
126 }
127
128 WARN("unknown enum name: %s for %s\n", name, enum_obj->name);
129 return -1;
130 }
131
132 /* Enum value to name */
j2s_enum_get_name(j2s_ctx * ctx,int enum_index,int value)133 static inline const char* j2s_enum_get_name(j2s_ctx* ctx, int enum_index,
134 int value)
135 {
136 j2s_enum* enum_obj;
137
138 if (enum_index < 0)
139 goto out;
140
141 enum_obj = &ctx->enums[enum_index];
142
143 for (int i = 0; i < enum_obj->num_value; i++) {
144 j2s_enum_value* enum_value = &ctx->enum_values[enum_obj->value_index + i];
145
146 if (enum_value->value == value)
147 return enum_value->name;
148 }
149
150 WARN("unknown enum value: %d for %s\n", value, enum_obj->name);
151 out:
152 return "INVALID";
153 }
154
_j2s_enum_to_json(j2s_ctx * ctx,int enum_index)155 static cJSON* _j2s_enum_to_json(j2s_ctx* ctx, int enum_index)
156 {
157 j2s_enum* enum_obj;
158 cJSON *root, *item;
159
160 if (enum_index < 0)
161 return NULL;
162
163 enum_obj = &ctx->enums[enum_index];
164
165 root = RkCam::cJSON_CreateObject();
166 DASSERT(root, return NULL);
167
168 for (int i = 0; i < enum_obj->num_value; i++) {
169 j2s_enum_value* enum_value = &ctx->enum_values[enum_obj->value_index + i];
170
171 item = RkCam::cJSON_CreateNumber(enum_value->value);
172 if (item)
173 RkCam::cJSON_AddItemToObject(root, enum_value->name, item);
174 }
175
176 return root;
177 }
178
j2s_enums_to_json(j2s_ctx * ctx)179 cJSON* j2s_enums_to_json(j2s_ctx* ctx)
180 {
181 cJSON *root, *item;
182
183 if (!ctx->num_enum)
184 return NULL;
185
186 root = cJSON_CreateObject();
187 DASSERT(root, return NULL);
188
189 for (int i = 0; i < ctx->num_enum; i++) {
190 j2s_enum* enum_obj = &ctx->enums[i];
191
192 item = _j2s_enum_to_json(ctx, i);
193 if (item)
194 cJSON_AddItemToObject(root, enum_obj->name, item);
195 }
196
197 return root;
198 }
199
_j2s_struct_to_template_json(j2s_ctx * ctx,int struct_index)200 static cJSON* _j2s_struct_to_template_json(j2s_ctx* ctx, int struct_index)
201 {
202 j2s_struct* struct_obj;
203 cJSON* json;
204
205 if (struct_index < 0)
206 return NULL;
207
208 struct_obj = &ctx->structs[struct_index];
209 if (struct_obj->child_index < 0)
210 return NULL;
211
212 DBG("start struct: %s\n", struct_obj->name);
213 j2s_template_dumping = true;
214 json = _j2s_struct_to_json(ctx, struct_index, NULL);
215 j2s_template_dumping = false;
216 DBG("finish struct: %s\n", struct_obj->name);
217
218 return json;
219 }
220
j2s_struct_to_template_json(j2s_ctx * ctx,const char * name)221 cJSON* j2s_struct_to_template_json(j2s_ctx* ctx, const char* name)
222 {
223 int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
224
225 return _j2s_struct_to_template_json(ctx, struct_index);
226 }
227
j2s_struct_size(j2s_ctx * ctx,int struct_index)228 int j2s_struct_size(j2s_ctx* ctx, int struct_index)
229 {
230 j2s_struct* struct_obj;
231 j2s_obj* child;
232 int child_index, child_size;
233
234 if (struct_index < 0)
235 return 0;
236
237 struct_obj = &ctx->structs[struct_index];
238
239 /* Find last child */
240 for (child = NULL, child_index = struct_obj->child_index; child_index >= 0;
241 child_index = child->next_index)
242 child = &ctx->objs[child_index];
243
244 if (!child)
245 return 0;
246
247 if (J2S_IS_POINTER(child)) {
248 child_size = (int)sizeof(void*);
249 } else if (J2S_IS_ARRAY(child)) {
250 child_size = child->elem_size * child->num_elem;
251 } else {
252 child_size = child->elem_size;
253 }
254
255 return child_size + child->offset;
256 }
257
j2s_type_name(j2s_type type)258 const char* j2s_type_name(j2s_type type)
259 {
260 switch (type) {
261 case J2S_TYPE_INT_8:
262 return "int8_t";
263 case J2S_TYPE_UINT_8:
264 return "uint8_t";
265 case J2S_TYPE_INT_16:
266 return "int16_t";
267 case J2S_TYPE_UINT_16:
268 return "uint16_t";
269 case J2S_TYPE_INT_32:
270 return "int32_t";
271 case J2S_TYPE_UINT_32:
272 return "uint32_t";
273 case J2S_TYPE_INT_64:
274 return "int64_t";
275 case J2S_TYPE_UINT_64:
276 return "uint64_t";
277 case J2S_TYPE_FLOAT:
278 return "float";
279 case J2S_TYPE_DOUBLE:
280 return "double";
281 case J2S_TYPE_STRING:
282 return "char";
283 case J2S_TYPE_STRUCT:
284 return "struct";
285 default:
286 return "unknown";
287 }
288 }
289
290 /* Get number value from a obj */
j2s_obj_get_value(j2s_ctx * ctx,int obj_index,void * ptr_)291 static inline double j2s_obj_get_value(j2s_ctx* ctx, int obj_index, void* ptr_)
292 {
293 j2s_obj* obj;
294 double value;
295 char* ptr = (char*)ptr_;
296
297 if (!ptr || obj_index < 0)
298 return 0;
299
300 obj = &ctx->objs[obj_index];
301 ptr += obj->offset;
302
303 #define J2S_FETCH_NUM(type, ptr) \
304 value = (double)*((type*)ptr); \
305 return value;
306
307 switch (obj->type) {
308 case J2S_TYPE_INT_8:
309 J2S_FETCH_NUM(int8_t, ptr);
310 case J2S_TYPE_UINT_8:
311 J2S_FETCH_NUM(uint8_t, ptr);
312 case J2S_TYPE_INT_16:
313 J2S_FETCH_NUM(int16_t, ptr);
314 case J2S_TYPE_UINT_16:
315 J2S_FETCH_NUM(uint16_t, ptr);
316 case J2S_TYPE_INT_32:
317 J2S_FETCH_NUM(int32_t, ptr);
318 case J2S_TYPE_UINT_32:
319 J2S_FETCH_NUM(uint32_t, ptr);
320 case J2S_TYPE_INT_64:
321 J2S_FETCH_NUM(int64_t, ptr);
322 case J2S_TYPE_UINT_64:
323 J2S_FETCH_NUM(uint64_t, ptr);
324 case J2S_TYPE_FLOAT:
325 J2S_FETCH_NUM(float, ptr);
326 case J2S_TYPE_DOUBLE:
327 J2S_FETCH_NUM(double, ptr);
328 default:
329 return 0;
330 }
331 }
332
333 /* Set number value to a obj */
j2s_obj_set_value(j2s_ctx * ctx,int obj_index,double value,void * ptr_)334 static inline int j2s_obj_set_value(j2s_ctx* ctx, int obj_index, double value,
335 void* ptr_)
336 {
337 j2s_obj* obj;
338 char* ptr = (char*)ptr_;
339
340 if (!ptr || obj_index < 0)
341 return 0;
342
343 obj = &ctx->objs[obj_index];
344 ptr += obj->offset;
345
346 #define J2S_STORE_NUM(type, value, ptr) \
347 *(type*)ptr = (type)value; \
348 return 0;
349
350 switch (obj->type) {
351 case J2S_TYPE_INT_8:
352 J2S_STORE_NUM(int8_t, value, ptr);
353 case J2S_TYPE_UINT_8:
354 J2S_STORE_NUM(uint8_t, value, ptr);
355 case J2S_TYPE_INT_16:
356 J2S_STORE_NUM(int16_t, value, ptr);
357 case J2S_TYPE_UINT_16:
358 J2S_STORE_NUM(uint16_t, value, ptr);
359 case J2S_TYPE_INT_32:
360 J2S_STORE_NUM(int32_t, value, ptr);
361 case J2S_TYPE_UINT_32:
362 J2S_STORE_NUM(uint32_t, value, ptr);
363 case J2S_TYPE_INT_64:
364 J2S_STORE_NUM(int64_t, value, ptr);
365 case J2S_TYPE_UINT_64:
366 J2S_STORE_NUM(uint64_t, value, ptr);
367 case J2S_TYPE_FLOAT:
368 J2S_STORE_NUM(float, value, ptr);
369 case J2S_TYPE_DOUBLE:
370 J2S_STORE_NUM(double, value, ptr);
371 default:
372 return 0;
373 }
374 }
375
376 /* Extract array to the first elem */
j2s_extract_array(j2s_obj * obj)377 static inline void j2s_extract_array(j2s_obj* obj)
378 {
379 if (obj->flags & J2S_FLAG_DEP_ARRAY) {
380 obj->flags &= ~J2S_FLAG_DEP_ARRAY;
381 obj->num_elem = obj->elem_size / obj->base_elem_size;
382 } else {
383 obj->flags &= ~J2S_FLAG_ARRAY;
384 obj->num_elem = 1;
385 }
386
387 obj->elem_size = obj->base_elem_size;
388 }
389
390 /* Extract dynamic array to normal array */
j2s_extract_dynamic_array(j2s_obj * obj,int len,void * ptr_)391 static inline void* j2s_extract_dynamic_array(j2s_obj* obj, int len,
392 void* ptr_)
393 {
394 char* ptr = (char*)ptr_;
395
396 if (!j2s_template_dumping) {
397 ptr += obj->offset;
398 ptr = (char*)(*(void**)ptr);
399 if (!ptr)
400 return NULL;
401 }
402
403 obj->offset = 0;
404 obj->len_index = -1;
405 obj->num_elem = len;
406
407 if (obj->flags & J2S_FLAG_DEP_POINTER) {
408 obj->flags &= ~J2S_FLAG_DEP_POINTER;
409 } else {
410 obj->flags &= ~J2S_FLAG_ARRAY_POINTER;
411 obj->flags &= ~J2S_FLAG_POINTER;
412 }
413
414 if (obj->flags & J2S_FLAG_ARRAY) {
415 obj->flags |= J2S_FLAG_DEP_ARRAY;
416 } else {
417 obj->flags |= J2S_FLAG_ARRAY;
418 }
419
420 return ptr;
421 }
422
j2s_get_index_json(j2s_ctx * ctx,cJSON * parent,int obj_index)423 static cJSON* j2s_get_index_json(j2s_ctx* ctx, cJSON* parent, int obj_index)
424 {
425 j2s_obj* obj;
426 char index_name[MAX_NAME + 10];
427
428 if (obj_index < 0)
429 return NULL;
430
431 obj = &ctx->objs[obj_index];
432
433 /* Handle array with index obj @<name>_index */
434 snprintf(index_name, sizeof(index_name), "@%s_index", obj->name);
435 return cJSON_GetObjectItemCaseSensitive(parent, index_name);
436 }
437
_j2s_obj_to_json(j2s_ctx * ctx,int obj_index,void * ptr_)438 static cJSON* _j2s_obj_to_json(j2s_ctx* ctx, int obj_index, void* ptr_)
439 {
440 j2s_obj* obj;
441 cJSON* root;
442 double value;
443 char* ptr = (char*)ptr_;
444
445 if (obj_index < 0)
446 return NULL;
447
448 obj = &ctx->objs[obj_index];
449
450 DBG("handling obj: %s from %p[%d]\n", obj->name, ptr, obj->offset);
451
452 /* Handle simple string */
453 if (J2S_IS_SIMPLE_STRING(obj)) {
454 if (j2s_template_dumping)
455 return cJSON_CreateString("");
456
457 ptr += obj->offset;
458 if (obj->flags & J2S_FLAG_POINTER)
459 ptr = *(char**)ptr;
460 return cJSON_CreateString(ptr ? ptr : "");
461 }
462
463 /* Handle array member */
464 if (J2S_IS_ARRAY(obj)) {
465 j2s_obj tmp_obj;
466 cJSON* item;
467
468 root = cJSON_CreateArray();
469 DASSERT(root, return NULL);
470
471 tmp_obj = *obj;
472
473 /* Walk into array */
474 j2s_extract_array(obj);
475
476 for (int i = 0; i < tmp_obj.num_elem; i++) {
477 DBG("handling array: %s %d/%d\n", obj->name, i, tmp_obj.num_elem);
478
479 item = _j2s_obj_to_json(ctx, obj_index, ptr);
480 if (item)
481 cJSON_AddItemToArray(root, item);
482
483 obj->offset += tmp_obj.elem_size;
484 }
485
486 *obj = tmp_obj;
487 return root;
488 }
489
490 /* Handle dynamic array */
491 if (J2S_IS_POINTER(obj)) {
492 j2s_obj tmp_obj;
493 int len;
494
495 DASSERT_MSG(obj->len_index >= 0, return NULL,
496 "dynamic array %s missing len\n", obj->name);
497
498 if (j2s_template_dumping) {
499 len = 1;
500 } else {
501 len = j2s_obj_get_value(ctx, obj->len_index, ptr);
502 }
503
504 if (!len)
505 return cJSON_CreateArray();
506
507 tmp_obj = *obj;
508
509 /* Walk into dynamic array */
510 ptr = (char*)j2s_extract_dynamic_array(obj, len, ptr);
511 DASSERT_MSG(j2s_template_dumping || ptr, return NULL,
512 "found null pointer at %s\n", obj->name);
513
514 DBG("handling dynamic array: %s %d*%d from %p\n", obj->name, obj->elem_size,
515 obj->num_elem, ptr);
516
517 root = _j2s_obj_to_json(ctx, obj_index, ptr);
518
519 *obj = tmp_obj;
520 return root;
521 }
522
523 /* Handle struct member */
524 if (obj->type == J2S_TYPE_STRUCT)
525 return _j2s_struct_to_json(ctx, obj->struct_index, ptr + obj->offset);
526
527 /* Handle basic member */
528 if (j2s_template_dumping) {
529 for (int i = 0; i < ctx->num_obj; i++) {
530 if (ctx->objs[i].len_index == obj_index)
531 return cJSON_CreateNumber(1);
532 }
533
534 if (obj->enum_index >= 0) {
535 /* Use first value as default */
536 j2s_enum* enum_obj = &ctx->enums[obj->enum_index];
537 j2s_enum_value* enum_value = &ctx->enum_values[enum_obj->value_index];
538
539 return cJSON_CreateString(enum_value->name);
540 }
541
542 return cJSON_CreateNumber(0);
543 }
544
545 value = j2s_obj_get_value(ctx, obj_index, ptr);
546
547 if (obj->enum_index >= 0) {
548 /* Convert enum value to name */
549 const char* name = j2s_enum_get_name(ctx, obj->enum_index, (int)value);
550 return cJSON_CreateString(name);
551 }
552
553 return cJSON_CreateNumber(value);
554 }
555
_j2s_struct_to_json(j2s_ctx * ctx,int struct_index,void * ptr)556 static cJSON* _j2s_struct_to_json(j2s_ctx* ctx, int struct_index, void* ptr)
557 {
558 j2s_struct* struct_obj;
559 j2s_obj* child;
560 cJSON *root, *item;
561 int child_index, ret = 0;
562
563 if (struct_index < 0)
564 return NULL;
565
566 struct_obj = &ctx->structs[struct_index];
567 if (struct_obj->child_index < 0)
568 return NULL;
569
570 root = cJSON_CreateObject();
571 DASSERT(root, return NULL);
572
573 DBG("start struct: %s from %p\n", struct_obj->name, ptr);
574
575 ret = -1;
576
577 /* Walk child list */
578 for (child_index = struct_obj->child_index; child_index >= 0;
579 child_index = child->next_index) {
580 child = &ctx->objs[child_index];
581
582 DBG("start child: %s (%s) from %p\n", child->name, struct_obj->name, ptr);
583
584 item = _j2s_obj_to_json(ctx, child_index, ptr);
585 DBG("finish child: %s (%s)\n", child->name, struct_obj->name);
586
587 if (item) {
588 if (ctx->dump_desc && child_index < ctx->num_desc) {
589 /* Dump desc to template JSON as @<member> */
590 char buf[MAX_NAME + 1] = "@";
591
592 const char* desc = ctx->descs[child_index];
593 if (desc) {
594 cJSON* json = cJSON_CreateString(desc);
595 DASSERT(json, goto out);
596
597 strcat(buf, child->name);
598 cJSON_AddItemToObject(root, buf, json);
599 }
600 }
601
602 cJSON_AddItemToObject(root, child->name, item);
603 }
604 }
605
606 ret = 0;
607 out:
608 DBG("finish struct: %s\n", struct_obj->name);
609
610 if (ret < 0) {
611 cJSON_Delete(root);
612 return NULL;
613 }
614 return root;
615 }
616
_j2s_obj_free(j2s_ctx * ctx,int obj_index,void * ptr_)617 static int _j2s_obj_free(j2s_ctx* ctx, int obj_index, void* ptr_)
618 {
619 j2s_obj* obj;
620 char* ptr = (char*)ptr_;
621
622 if (obj_index < 0)
623 return -1;
624
625 obj = &ctx->objs[obj_index];
626
627 /* Handle simple string */
628 if (J2S_IS_SIMPLE_STRING(obj)) {
629 ptr += obj->offset;
630
631 if (obj->flags & J2S_FLAG_ARRAY) {
632 return 0;
633 }
634
635 if (obj->flags & J2S_FLAG_POINTER) {
636 ptr = *(char**)ptr;
637 }
638
639 if (ptr) {
640 free(ptr);
641 }
642 return 0;
643 }
644
645 /* Handle array member */
646 if (J2S_IS_ARRAY(obj)) {
647 j2s_obj tmp_obj;
648 tmp_obj = *obj;
649
650 /* Walk into array */
651 j2s_extract_array(obj);
652
653 for (int i = 0; i < tmp_obj.num_elem; i++) {
654 _j2s_obj_free(ctx, obj_index, ptr);
655 obj->offset += tmp_obj.elem_size;
656 }
657
658 *obj = tmp_obj;
659 return 0;
660 }
661
662 /* Handle dynamic array */
663 if (J2S_IS_POINTER(obj)) {
664 j2s_obj tmp_obj;
665 void* root_ptr = *(void**)ptr;
666 int len;
667
668 if (obj->len_index < 0) {
669 DBG("dynamic array %s missing len\n", obj->name);
670 return -1;
671 }
672
673 len = j2s_obj_get_value(ctx, obj->len_index, ptr);
674
675 if (len <= 0) {
676 DBG("array size error: %s %d\n", obj->name, len);
677 return -1;
678 }
679
680 tmp_obj = *obj;
681
682 /* Walk into dynamic array */
683 ptr = (char*)j2s_extract_dynamic_array(obj, len, ptr);
684
685 _j2s_obj_free(ctx, obj_index, ptr);
686
687 if (ptr) {
688 free(ptr);
689 }
690
691 *obj = tmp_obj;
692 return 0;
693 }
694
695 /* Handle struct member */
696 if (obj->type == J2S_TYPE_STRUCT) {
697 return _j2s_struct_free(ctx, obj->struct_index, ptr + obj->offset);
698 }
699
700 return 0;
701 }
702
_j2s_struct_free(j2s_ctx * ctx,int struct_index,void * ptr)703 static int _j2s_struct_free(j2s_ctx* ctx, int struct_index, void* ptr)
704 {
705 j2s_struct* struct_obj = NULL;
706 j2s_obj* child = NULL;
707 int child_index, ret = 0;
708
709 if (struct_index < 0)
710 return -1;
711
712 struct_obj = &ctx->structs[struct_index];
713 if (struct_obj->child_index < 0)
714 return -1;
715
716 ret = -1;
717
718 /* Walk child list */
719 for (child_index = struct_obj->child_index; child_index >= 0;
720 child_index = child->next_index) {
721 child = &ctx->objs[child_index];
722 ret = _j2s_obj_free(ctx, child_index, ptr);
723 }
724
725 return ret;
726 }
727
j2s_json_to_array_with_index(j2s_ctx * ctx,cJSON * json,cJSON * index_json,cJSON * parent,j2s_obj * obj,void * ptr,bool query)728 static int j2s_json_to_array_with_index(j2s_ctx* ctx, cJSON* json,
729 cJSON* index_json, cJSON* parent,
730 j2s_obj* obj, void* ptr, bool query)
731 {
732 j2s_obj tmp_obj;
733 cJSON *index_item, *item;
734 int size, index, ret = -1;
735
736 size = cJSON_GetArraySize(index_json);
737 if (!size)
738 return 0;
739
740 tmp_obj = *obj;
741
742 /* Walk into array */
743 j2s_extract_array(obj);
744
745 if (query) {
746 cJSON* root;
747
748 /* Clear the original array */
749 root = cJSON_CreateArray();
750 cJSON_ReplaceItemInObjectCaseSensitive(parent, obj->name, root);
751
752 for (int i = 0; i < size; i++) {
753 index_item = cJSON_GetArrayItem(index_json, i);
754 index = cJSON_GetNumberValue(index_item);
755 obj->offset = tmp_obj.offset + index * tmp_obj.elem_size;
756 item = NULL;
757
758 DBG("handling index array: %s %d/%d\n", obj->name, index,
759 tmp_obj.num_elem);
760
761 /* Query item */
762 if (index < tmp_obj.num_elem)
763 item = _j2s_obj_to_json(ctx, obj - ctx->objs, ptr);
764
765 if (!item) {
766 item = cJSON_CreateObject();
767 if (!item) {
768 ret = -1;
769 break;
770 }
771 }
772
773 cJSON_AddItemToArray(root, item);
774 }
775 } else {
776 for (int i = 0; i < size; i++) {
777 index_item = cJSON_GetArrayItem(index_json, i);
778 index = cJSON_GetNumberValue(index_item);
779 obj->offset = tmp_obj.offset + index * tmp_obj.elem_size;
780
781 DBG("handling index array: %s %d/%d\n", obj->name, index,
782 tmp_obj.num_elem);
783
784 if (index >= tmp_obj.num_elem)
785 continue;
786
787 /* Apply item */
788 item = cJSON_GetArrayItem(json, i);
789 if (!item)
790 break;
791
792 ret = _j2s_json_to_obj(ctx, item, parent, obj - ctx->objs, ptr, false);
793 if (ret < 0)
794 break;
795 }
796 }
797
798 *obj = tmp_obj;
799 return ret;
800 }
801
_j2s_json_to_obj(j2s_ctx * ctx,cJSON * json,cJSON * parent,int obj_index,void * ptr_,bool query)802 static int _j2s_json_to_obj(j2s_ctx* ctx, cJSON* json, cJSON* parent,
803 int obj_index, void* ptr_, bool query)
804 {
805 j2s_obj* obj;
806 cJSON* root = json;
807 int ret = 0;
808 char* ptr = (char*)ptr_;
809
810 if (obj_index < 0)
811 return -1;
812
813 obj = &ctx->objs[obj_index];
814
815 DBG("handling obj: %s from %p[%d]\n", obj->name, ptr, obj->offset);
816
817 /* Handle simple string */
818 if (J2S_IS_SIMPLE_STRING(obj)) {
819 ptr += obj->offset;
820
821 if (query) {
822 if (obj->flags == J2S_FLAG_POINTER)
823 ptr = *(char**)ptr;
824
825 cJSON_SetValuestring(root, ptr ? ptr : "");
826 } else {
827 char* str = cJSON_GetStringValue(root);
828
829 if (obj->flags == J2S_FLAG_ARRAY) {
830 strncpy(ptr, str ? str : "", obj->num_elem);
831 } else {
832 char** buf = (char**)ptr;
833 if (*buf)
834 free(*buf);
835 *buf = strdup(str ? str : "");
836 }
837 }
838
839 return 0;
840 }
841
842 /* Handle array member */
843 if (J2S_IS_ARRAY(obj)) {
844 j2s_obj tmp_obj;
845 cJSON *item, *index_json;
846
847 index_json = j2s_get_index_json(ctx, parent, obj_index);
848 if (index_json && obj->type != J2S_TYPE_STRING && obj->flags != J2S_FLAG_ARRAY) {
849 cJSON_DetachItemViaPointer(parent, index_json);
850 index_json = NULL;
851 WARN("ignoring index for dep types %s\n", obj->name);
852 }
853
854 if (index_json)
855 return j2s_json_to_array_with_index(ctx, json, index_json, parent, obj,
856 ptr, query);
857
858 tmp_obj = *obj;
859
860 /* Walk into array */
861 j2s_extract_array(obj);
862
863 for (int i = 0; i < tmp_obj.num_elem; i++) {
864 DBG("handling array: %s %d/%d\n", obj->name, i, tmp_obj.num_elem);
865
866 item = cJSON_GetArrayItem(root, i);
867 if (!item)
868 continue;
869
870 ret = _j2s_json_to_obj(ctx, item, parent, obj_index, ptr, query);
871 if (ret < 0)
872 break;
873
874 obj->offset += tmp_obj.elem_size;
875 }
876
877 *obj = tmp_obj;
878 return ret;
879 }
880
881 /* Handle dynamic array */
882 if (J2S_IS_POINTER(obj)) {
883 j2s_obj tmp_obj;
884 cJSON *len_json, *index_json;
885 char* len_name;
886 int len, old_len;
887
888 DASSERT_MSG(obj->len_index >= 0, return -1,
889 "dynamic array %s missing len\n", obj->name);
890
891 len_name = ctx->objs[obj->len_index].name;
892
893 len_json = cJSON_GetObjectItemCaseSensitive(parent, len_name);
894 if (!len_json && !query)
895 WARN("missing len in json for dynamic array '%s'\n", obj->name);
896
897 index_json = j2s_get_index_json(ctx, parent, obj_index);
898
899 if (query && !index_json) {
900 /* Query dynamic array len */
901 if (len_json)
902 cJSON_DetachItemViaPointer(parent, len_json);
903
904 len_json = _j2s_obj_to_json(ctx, obj->len_index, ptr);
905 DASSERT_MSG(len_json, return -1, "failed to query %s\n", len_name);
906
907 cJSON_AddItemToObject(parent, len_name, len_json);
908
909 /* Force query the whole dynamic array */
910 cJSON_DetachItemViaPointer(parent, json);
911 cJSON_Delete(json);
912
913 json = _j2s_obj_to_json(ctx, obj_index, ptr);
914 DASSERT_MSG(json, return -1, "failed to query %s\n", obj->name);
915
916 cJSON_AddItemToObject(parent, obj->name, json);
917 return 0;
918 }
919
920 old_len = j2s_obj_get_value(ctx, obj->len_index, ptr);
921
922 if (len_json) {
923 len = cJSON_GetArraySize(json);
924 /* Fallback to array size */
925 cJSON_SetNumberValue(len_json, len);
926 } else if (index_json) {
927 len = old_len;
928 } else {
929 /* Fallback to array size */
930 len = cJSON_GetArraySize(json);
931 }
932
933 if (len != old_len) {
934 /* Dynamic array size changed, realloc it */
935 void** buf = (void**)(ptr + obj->offset);
936
937 if (old_len && *buf)
938 j2s_release_data(ctx, *buf);
939
940 *buf = j2s_alloc_data(ctx, len * obj->elem_size);
941
942 j2s_obj_set_value(ctx, obj->len_index, len, ptr);
943
944 DBG("re-alloc %s from %d*%d to %d*%d = %p\n", obj->name, old_len,
945 obj->elem_size, len, obj->elem_size, *buf);
946 }
947
948 if (!len)
949 return 0;
950
951 tmp_obj = *obj;
952
953 /* Walk into dynamic array */
954 ptr = (char*)j2s_extract_dynamic_array(obj, len, ptr);
955 DASSERT_MSG(ptr, return -1, "found null pointer at %s\n", obj->name);
956
957 DBG("handling dynamic array: %s %d*%d from %p\n", obj->name, obj->elem_size,
958 obj->num_elem, ptr);
959
960 ret = _j2s_json_to_obj(ctx, root, parent, obj_index, ptr, query);
961
962 *obj = tmp_obj;
963 return ret;
964 }
965
966 /* Handle struct member */
967 if (obj->type == J2S_TYPE_STRUCT)
968 return _j2s_json_to_struct(ctx, root, obj->struct_index, ptr + obj->offset,
969 query);
970
971 /* Handle basic member */
972 if (query) {
973 double value = j2s_obj_get_value(ctx, obj_index, ptr);
974
975 if (obj->enum_index >= 0) {
976 /* Convert enum value to name */
977 const char* name = j2s_enum_get_name(ctx, obj->enum_index, (int)value);
978 cJSON_SetValuestring(root, name);
979 return 0;
980 }
981
982 cJSON_SetNumberValue(root, value);
983 return 0;
984 } else {
985 double value;
986
987 if (obj->enum_index >= 0) {
988 /* Convert enum name to value */
989 char* name = cJSON_GetStringValue(root);
990
991 value = (double)j2s_enum_get_value(ctx, obj->enum_index, name);
992 } else {
993 value = cJSON_GetNumberValue(root);
994 }
995
996 j2s_obj_set_value(ctx, obj_index, value, ptr);
997 return 0;
998 }
999 }
1000
_j2s_json_to_struct(j2s_ctx * ctx,cJSON * json,int struct_index,void * ptr,bool query)1001 static int _j2s_json_to_struct(j2s_ctx* ctx, cJSON* json, int struct_index,
1002 void* ptr, bool query)
1003 {
1004 j2s_struct* struct_obj;
1005 j2s_obj* child;
1006 cJSON *item, *root = json;
1007 int child_index, ret = 0;
1008
1009 if (struct_index < 0)
1010 return -1;
1011
1012 struct_obj = &ctx->structs[struct_index];
1013
1014 DBG("start struct: %s from %p\n", struct_obj->name, ptr);
1015
1016 /* Walk child list */
1017 for (child_index = struct_obj->child_index; child_index >= 0;
1018 child_index = child->next_index) {
1019 child = &ctx->objs[child_index];
1020
1021 item = cJSON_GetObjectItemCaseSensitive(root, child->name);
1022 if (!item)
1023 continue;
1024
1025 DBG("start child: %s (%s) from %p\n", child->name, struct_obj->name, ptr);
1026 ret = _j2s_json_to_obj(ctx, item, root, child_index, ptr, query);
1027 DBG("finish child: %s (%s)\n", child->name, struct_obj->name);
1028 if (ret < 0)
1029 break;
1030 }
1031
1032 DBG("finish struct: %s\n", struct_obj->name);
1033 return ret;
1034 }
1035
j2s_restore_obj(j2s_ctx * ctx,j2s_obj * obj,int fd,void * ptr_)1036 static int j2s_restore_obj(j2s_ctx* ctx, j2s_obj* obj, int fd, void* ptr_)
1037 {
1038 char buf[MAX_NAME];
1039 void** data_ptr;
1040 int size;
1041 char* ptr = (char*)ptr_;
1042
1043 if (!J2S_IS_POINTER(obj))
1044 return 0;
1045
1046 data_ptr = (void**)(ptr + obj->offset);
1047
1048 if (read(fd, buf, MAX_NAME) != MAX_NAME)
1049 return -1;
1050
1051 if (strncmp(obj->name, buf, MAX_NAME) < 0)
1052 return -1;
1053
1054 if (read(fd, &size, sizeof(int)) != sizeof(int))
1055 return -1;
1056
1057 if (!size) {
1058 *data_ptr = NULL;
1059 return 0;
1060 }
1061
1062 *data_ptr = j2s_alloc_data(ctx, size);
1063 if (!*data_ptr)
1064 return -1;
1065
1066 if (read(fd, *data_ptr, size) != size) {
1067 j2s_release_data(ctx, *data_ptr);
1068 return -1;
1069 }
1070
1071 DBG("restore obj: %s to %p, size %d\n", obj->name, *data_ptr, size);
1072
1073 return size;
1074 }
1075
j2s_store_obj(j2s_obj * obj,int fd,void * ptr_)1076 static void j2s_store_obj(j2s_obj* obj, int fd, void* ptr_)
1077 {
1078 char buf[MAX_NAME] = { 0 };
1079 int size;
1080 ssize_t bytes_written = 0;
1081 char* ptr = (char*)ptr_;
1082
1083 if (!J2S_IS_POINTER(obj))
1084 return;
1085
1086 ptr = (char*)(*(void**)(ptr + obj->offset));
1087 if (!ptr)
1088 return;
1089
1090 if (J2S_IS_SIMPLE_STRING(obj)) {
1091 size = strlen(ptr) + 1;
1092 } else {
1093 size = obj->num_elem * obj->elem_size;
1094 }
1095
1096 DBG("store obj: %s from %p, size %d\n", obj->name, ptr, size);
1097
1098 strcpy(buf, obj->name);
1099 bytes_written = write(fd, buf, MAX_NAME);
1100 bytes_written = write(fd, &size, sizeof(int));
1101 bytes_written = write(fd, ptr, size);
1102 }
1103
_j2s_obj_from_cache(j2s_ctx * ctx,int obj_index,int fd,void * ptr)1104 static int _j2s_obj_from_cache(j2s_ctx* ctx, int obj_index, int fd, void* ptr)
1105 {
1106 j2s_obj* obj;
1107 int ret = 0;
1108
1109 if (obj_index < 0)
1110 return -1;
1111
1112 obj = &ctx->objs[obj_index];
1113
1114 DBG("handling obj: %s from %p[%d]\n", obj->name, ptr, obj->offset);
1115
1116 /* Handle simple string */
1117 if (J2S_IS_SIMPLE_STRING(obj))
1118 return j2s_restore_obj(ctx, obj, fd, ptr);
1119
1120 /* Handle array member */
1121 if (J2S_IS_ARRAY(obj)) {
1122 j2s_obj tmp_obj = *obj;
1123
1124 if (obj->type != J2S_TYPE_STRUCT && obj->type != J2S_TYPE_STRING)
1125 return 0;
1126
1127 /* Walk into array */
1128 j2s_extract_array(obj);
1129
1130 for (int i = 0; i < tmp_obj.num_elem; i++) {
1131 DBG("handling array: %s %d/%d\n", obj->name, i, tmp_obj.num_elem);
1132
1133 ret = _j2s_obj_from_cache(ctx, obj_index, fd, ptr);
1134 if (ret < 0)
1135 break;
1136
1137 obj->offset += tmp_obj.elem_size;
1138 }
1139
1140 *obj = tmp_obj;
1141 return ret;
1142 }
1143
1144 /* Handle dynamic array */
1145 if (J2S_IS_POINTER(obj)) {
1146 j2s_obj tmp_obj = *obj;
1147 int size;
1148
1149 size = j2s_restore_obj(ctx, obj, fd, ptr);
1150 if (size <= 0)
1151 return size;
1152
1153 /* Walk into dynamic array */
1154 ptr = j2s_extract_dynamic_array(obj, size / obj->elem_size, ptr);
1155
1156 DBG("handling dynamic array: %s %d*%d from %p\n", obj->name, obj->elem_size,
1157 obj->num_elem, ptr);
1158
1159 ret = _j2s_obj_from_cache(ctx, obj_index, fd, ptr);
1160
1161 *obj = tmp_obj;
1162 return ret;
1163 }
1164
1165 /* Handle struct member */
1166 if (obj->type == J2S_TYPE_STRUCT)
1167 return _j2s_struct_from_cache(ctx, obj->struct_index, fd,
1168 (char*)ptr + obj->offset);
1169
1170 return 0;
1171 }
1172
_j2s_struct_from_cache(j2s_ctx * ctx,int struct_index,int fd,void * ptr)1173 static int _j2s_struct_from_cache(j2s_ctx* ctx, int struct_index, int fd,
1174 void* ptr)
1175 {
1176 j2s_struct* struct_obj;
1177 j2s_obj* child;
1178 int child_index;
1179
1180 if (struct_index < 0)
1181 return -1;
1182
1183 if (struct_index == ctx->root_index) {
1184 int root_size = j2s_struct_size(ctx, ctx->root_index);
1185 if (read(fd, ptr, root_size) != root_size)
1186 return -1;
1187 }
1188
1189 struct_obj = &ctx->structs[struct_index];
1190
1191 /* Walk child list */
1192 for (child_index = struct_obj->child_index; child_index >= 0;
1193 child_index = child->next_index) {
1194 child = &ctx->objs[child_index];
1195 if (_j2s_obj_from_cache(ctx, child_index, fd, ptr) < 0)
1196 return -1;
1197 }
1198
1199 return 0;
1200 }
1201
_j2s_obj_to_cache(j2s_ctx * ctx,int obj_index,int fd,void * ptr)1202 static void _j2s_obj_to_cache(j2s_ctx* ctx, int obj_index, int fd, void* ptr)
1203 {
1204 j2s_obj* obj;
1205
1206 if (obj_index < 0)
1207 return;
1208
1209 obj = &ctx->objs[obj_index];
1210
1211 DBG("handling obj: %s from %p[%d]\n", obj->name, ptr, obj->offset);
1212
1213 /* Handle simple string */
1214 if (J2S_IS_SIMPLE_STRING(obj)) {
1215 j2s_store_obj(obj, fd, ptr);
1216 return;
1217 }
1218
1219 /* Handle array member */
1220 if (J2S_IS_ARRAY(obj)) {
1221 j2s_obj tmp_obj = *obj;
1222
1223 if (obj->type != J2S_TYPE_STRUCT && obj->type != J2S_TYPE_STRING)
1224 return;
1225
1226 /* Walk into array */
1227 j2s_extract_array(obj);
1228
1229 for (int i = 0; i < tmp_obj.num_elem; i++) {
1230 DBG("handling array: %s %d/%d\n", obj->name, i, tmp_obj.num_elem);
1231
1232 _j2s_obj_to_cache(ctx, obj_index, fd, ptr);
1233 obj->offset += tmp_obj.elem_size;
1234 }
1235
1236 *obj = tmp_obj;
1237 return;
1238 }
1239
1240 /* Handle dynamic array */
1241 if (J2S_IS_POINTER(obj)) {
1242 j2s_obj tmp_obj = *obj;
1243 int len;
1244
1245 if (obj->len_index < 0)
1246 return;
1247
1248 len = j2s_obj_get_value(ctx, obj->len_index, ptr);
1249 if (!len)
1250 return;
1251
1252 obj->num_elem = len;
1253 j2s_store_obj(obj, fd, ptr);
1254
1255 /* Walk into dynamic array */
1256 ptr = j2s_extract_dynamic_array(obj, len, ptr);
1257
1258 DBG("handling dynamic array: %s %d*%d from %p\n", obj->name, obj->elem_size,
1259 obj->num_elem, ptr);
1260
1261 _j2s_obj_to_cache(ctx, obj_index, fd, ptr);
1262
1263 *obj = tmp_obj;
1264 return;
1265 }
1266
1267 /* Handle struct member */
1268 if (obj->type == J2S_TYPE_STRUCT)
1269 _j2s_struct_to_cache(ctx, obj->struct_index, fd, (char*)ptr + obj->offset);
1270 }
1271
_j2s_struct_to_cache(j2s_ctx * ctx,int struct_index,int fd,void * ptr)1272 static void _j2s_struct_to_cache(j2s_ctx* ctx, int struct_index, int fd,
1273 void* ptr)
1274 {
1275 j2s_struct* struct_obj;
1276 j2s_obj* child;
1277 int child_index;
1278 ssize_t bytes_written = 0;
1279
1280 if (struct_index < 0)
1281 return;
1282
1283 if (struct_index == ctx->root_index)
1284 bytes_written = write(fd, ptr, j2s_struct_size(ctx, struct_index));
1285
1286 struct_obj = &ctx->structs[struct_index];
1287
1288 /* Walk child list */
1289 for (child_index = struct_obj->child_index; child_index >= 0;
1290 child_index = child->next_index) {
1291 child = &ctx->objs[child_index];
1292 _j2s_obj_to_cache(ctx, child_index, fd, ptr);
1293 }
1294 }
1295