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 #ifdef __ANDROID__
17 #if defined(ISP_HW_V20)
18 #include "j2s_generated_v20.h"
19 #elif defined(ISP_HW_V21)
20 #include "j2s_generated_v21.h"
21 #elif defined(ISP_HW_V30)
22 #include "j2s_generated_v30.h"
23 #elif defined(ISP_HW_V32)
24 #include "j2s_generated_v32.h"
25 #elif defined(ISP_HW_V32_LITE)
26 #include "j2s_generated_v32_lite.h"
27 #else
28 #error "Please define supported ISP version!!!, eg: -DISP_HW_V21"
29 #endif
30 #else
31 #ifdef COMPILE_TEMPLATE
32 #include ".j2s_generated.h"
33 #else
34 #include "j2s_generated.h"
35 #endif
36 #endif
37
38 //#define J2S_USING_CACH
39
40 #include <sys/stat.h>
41
42 using namespace RkCam;
43
44 typedef struct {
45 void* ptr;
46 bool freeable;
47 } j2s_ptr;
48
49 typedef struct {
50 int num_data;
51 j2s_ptr* data;
52 } j2s_priv_data;
53
j2s_alloc_data(j2s_ctx * ctx,size_t size)54 void* j2s_alloc_data(j2s_ctx* ctx, size_t size)
55 {
56 void* ptr = calloc(size, 1);
57 if (!ptr)
58 return NULL;
59
60 if (j2s_add_data(ctx, ptr, false) < 0) {
61 free(ptr);
62 return NULL;
63 }
64
65 return ptr;
66 }
67
j2s_add_data(j2s_ctx * ctx,void * ptr,bool freeable)68 int j2s_add_data(j2s_ctx* ctx, void* ptr, bool freeable)
69 {
70 j2s_priv_data* priv;
71
72 if (!ctx->priv)
73 ctx->priv = calloc(1, sizeof(j2s_priv_data));
74
75 priv = (j2s_priv_data*)ctx->priv;
76 for (int i = 0; i < priv->num_data; i++) {
77 j2s_ptr* data = &priv->data[i];
78 if (data->ptr)
79 continue;
80
81 data->ptr = ptr;
82 data->freeable = freeable;
83 return 0;
84 }
85
86 priv->num_data++;
87 priv->data = (j2s_ptr*)realloc(priv->data, priv->num_data * sizeof(j2s_ptr));
88 if (!priv->data) {
89 ERR("failed to realloc\n");
90 priv->num_data = 0;
91 return -1;
92 }
93
94 priv->data[priv->num_data - 1].ptr = ptr;
95 priv->data[priv->num_data - 1].freeable = freeable;
96 return 0;
97 }
98
j2s_release_data(j2s_ctx * ctx,void * ptr)99 void j2s_release_data(j2s_ctx* ctx, void* ptr)
100 {
101 j2s_priv_data* priv = (j2s_priv_data*)ctx->priv;
102
103 void* free_ptr = ptr;
104 for (int i = 0; priv && i < priv->num_data; i++) {
105 j2s_ptr* data = &priv->data[i];
106 if (ptr != data->ptr)
107 continue;
108
109 if (data->ptr && data->freeable) {
110 free(data->ptr);
111 free_ptr = NULL;
112 }
113 data->ptr = NULL;
114 //return;
115 }
116
117 if (free_ptr)
118 free(ptr);
119 }
120
j2s_read_file(const char * file,size_t * size)121 void* j2s_read_file(const char* file, size_t* size)
122 {
123 struct stat st;
124 void* buf;
125 int fd;
126
127 DASSERT_MSG(file && !stat(file, &st), return NULL, "no such file: '%s'\n",
128 file ? file : "<null>");
129
130 fd = open(file, O_RDONLY);
131 DASSERT_MSG(fd >= 0, return NULL, "failed to open: '%s'\n", file);
132
133 buf = malloc(st.st_size + 1);
134 DASSERT(buf, return NULL);
135
136 DBG("Read file: '%s'\n", file);
137
138 if (read(fd, buf, st.st_size) != st.st_size) {
139 ERR("failed to read: '%s'\n", file);
140 free(buf);
141 close(fd);
142 return NULL;
143 }
144
145 ((char*)buf)[st.st_size] = '\0';
146 *size = st.st_size;
147
148 close(fd);
149 return buf;
150 }
151
j2s_cache_file(const char * file)152 static char* j2s_cache_file(const char* file)
153 {
154 #ifdef J2S_USING_CACH
155 char cache_file[256];
156
157 if (getenv("J2S_NO_CACHE")) {
158 DBG("Cache not allowed\n");
159 return NULL;
160 }
161
162 strcpy(cache_file, getenv("J2S_CACHE") ? getenv("J2S_CACHE") : "/var/cache/j2s-cache");
163
164 /* NULL for ctx cache file */
165 if (!file)
166 return strdup(cache_file);
167
168 strcat(cache_file, "-");
169 strcat(cache_file, strrchr(file, '/') ? strrchr(file, '/') + 1 : file);
170
171 for (int i = 0; cache_file[i]; i++) {
172 if (cache_file[i] == '.')
173 cache_file[i] = '-';
174 }
175
176 return strdup(cache_file);
177 #else
178 return NULL;
179 #endif
180 }
181
j2s_cache_file_valid(const char * cache_file)182 static int j2s_cache_file_valid(const char* cache_file)
183 {
184 struct stat st;
185
186 if (!cache_file || stat(cache_file, &st) < 0) {
187 DBG("invalid cache: '%s'\n", cache_file ?: "<NULL>");
188 return -1;
189 }
190
191 if (getuid() != st.st_uid) {
192 DBG("invalid cache: '%s'\n", cache_file);
193 return -1;
194 }
195
196 return 0;
197 }
198
j2s_load_ctx_cache(j2s_ctx * ctx,const char * cache_file)199 static __attribute__((unused)) int j2s_load_ctx_cache(j2s_ctx* ctx,
200 const char* cache_file)
201 {
202 void *buf;
203 char* ptr;
204 size_t size;
205
206 if (j2s_cache_file_valid(cache_file) < 0)
207 return -1;
208
209 buf = j2s_read_file(cache_file, &size);
210 if (!buf || size <= sizeof(*ctx)) {
211 DBG("invalid cache: %s\n", cache_file ? cache_file : "nullptr");
212 goto err;
213 }
214
215 DBG("Loading ctx cache: %s\n", cache_file ? cache_file : "nullptr");
216
217 ptr = (char*)buf;
218
219 *ctx = *(j2s_ctx*)ptr;
220 ctx->priv = NULL;
221 ptr += sizeof(*ctx);
222
223 if (ctx->magic != J2S_MAGIC || ctx->num_obj != J2S_NUM_OBJ || ctx->num_struct != J2S_NUM_STRUCT || ctx->num_enum != J2S_NUM_ENUM || ctx->num_enum_value != J2S_NUM_ENUM_VALUE) {
224 DBG("invalid cache: %s\n", cache_file ? cache_file : "nullptr");
225 goto err;
226 }
227
228 ctx->objs = (j2s_obj*)ptr;
229 ptr += ctx->num_obj * sizeof(*ctx->objs);
230
231 ctx->structs = (j2s_struct*)ptr;
232 ptr += ctx->num_struct * sizeof(*ctx->structs);
233
234 ctx->enums = (j2s_enum*)ptr;
235 ptr += ctx->num_enum * sizeof(*ctx->enums);
236
237 ctx->enum_values = (j2s_enum_value*)ptr;
238 ptr += ctx->num_enum_value * sizeof(*ctx->enum_values);
239
240 if (ptr != (char*)buf + size) {
241 DBG("invalid cache: %s\n", cache_file ? cache_file : "nullptr");
242 goto err;
243 }
244
245 if (j2s_add_data(ctx, buf, true) < 0)
246 goto err;
247
248 return 0;
249 err:
250 j2s_deinit(ctx);
251 free(buf);
252 return -1;
253 }
254
j2s_save_ctx_cache(j2s_ctx * ctx,const char * cache_file)255 static __attribute__((unused)) void j2s_save_ctx_cache(j2s_ctx* ctx,
256 const char* cache_file)
257 {
258 int fd;
259 ssize_t bytes_written = 0;
260
261 if (!cache_file)
262 return;
263
264 fd = creat(cache_file, S_IRUSR | S_IWUSR);
265 if (fd < 0) {
266 DBG("failed to create: '%s'\n", cache_file);
267 return;
268 }
269
270 DBG("Saving ctx cache: '%s'\n", cache_file);
271
272 ctx->num_desc = 0;
273
274 bytes_written = write(fd, ctx, sizeof(*ctx));
275 bytes_written = write(fd, ctx->objs, ctx->num_obj * sizeof(*ctx->objs));
276 bytes_written = write(fd, ctx->structs, ctx->num_struct * sizeof(*ctx->structs));
277 bytes_written = write(fd, ctx->enums, ctx->num_enum * sizeof(*ctx->enums));
278 bytes_written = write(fd, ctx->enum_values, ctx->num_enum_value * sizeof(*ctx->enum_values));
279
280 close(fd);
281 }
282
j2s_init(j2s_ctx * ctx)283 void j2s_init(j2s_ctx* ctx)
284 {
285 DBG("J2S version: %s\n", J2S_VERSION);
286
287 #ifdef J2S_ENABLE_DESC
288 _j2s_init(ctx);
289 #else
290 char* cache_file = j2s_cache_file(NULL);
291
292 if (j2s_load_ctx_cache(ctx, cache_file) < 0) {
293 _j2s_init(ctx);
294 #if 0
295 FILE* fp = NULL;
296 size_t total = 0;
297 size_t wr_size = 0;
298 fp = fopen("j2s_code2bin.bin","wb+");
299
300 size_t data_size = 0;
301 data_size = sizeof(j2s_obj) * ctx->num_obj;
302 wr_size = fwrite(ctx->objs, data_size , 1, fp);
303 total += data_size;
304 printf("write objs size: %zu, expected: %zu\n", wr_size * data_size, data_size);
305
306 data_size = sizeof(j2s_struct) * ctx->num_struct;
307 wr_size = fwrite(ctx->structs, data_size , 1, fp);
308 total += data_size;
309 printf("write structs size: %zu, expected: %zu\n", wr_size * data_size, data_size);
310
311 data_size = sizeof(j2s_enum) * ctx->num_enum;
312 wr_size = fwrite(ctx->enums, data_size , 1, fp);
313 total += data_size;
314 printf("write enums size: %zu, expected: %zu\n", wr_size * data_size, data_size);
315
316 data_size = sizeof(j2s_enum_value) * ctx->num_enum_value;
317 wr_size = fwrite(ctx->enum_values, data_size , 1, fp);
318 total += data_size;
319 printf("write enum_valuses size: %zu, expected: %zu\n", wr_size * data_size, data_size);
320
321 printf("write total size: %zu\n", total);
322
323 fclose(fp);
324 #endif
325 j2s_save_ctx_cache(ctx, cache_file);
326 }
327
328 if (cache_file)
329 free(cache_file);
330 #endif
331
332 ctx->manage_data = true;
333 }
334
j2s_camgroup_init(j2s_ctx * ctx)335 void j2s_camgroup_init(j2s_ctx* ctx)
336 {
337 DBG("J2S version: %s\n", J2S_VERSION);
338
339 _j2s_init(ctx);
340 // CamCalibDbProj_t always be followed by CamCalibDbGroup_t,
341 // this was decided by the definition sequence in RkAiqCalibDbTypesV2
342 ctx->root_index += 1;
343
344 ctx->manage_data = true;
345 }
346
j2s_deinit(j2s_ctx * ctx)347 void j2s_deinit(j2s_ctx* ctx)
348 {
349 j2s_priv_data* priv = (j2s_priv_data*)ctx->priv;
350
351 for (int i = 0; priv && i < priv->num_data; i++) {
352 j2s_ptr* data = &priv->data[i];
353 if (!data->ptr || !data->freeable)
354 continue;
355
356 /* Always free the cache file buf */
357 if (ctx->manage_data || (char*)data->ptr + sizeof(*ctx) == (char*)ctx->objs)
358 free(data->ptr);
359 }
360
361 if (priv) {
362 if (priv->data)
363 free(priv->data);
364 free(priv);
365 }
366 }
367
j2s_load_struct_cache(j2s_ctx * ctx,const char * cache_file,void * ptr,void * auth_data,int auth_size)368 int j2s_load_struct_cache(j2s_ctx* ctx, const char* cache_file, void* ptr,
369 void* auth_data, int auth_size)
370 {
371 int fd, ret = -1;
372
373 if (j2s_cache_file_valid(cache_file) < 0)
374 return -1;
375
376 fd = open(cache_file, O_RDONLY);
377 if (fd < 0) {
378 DBG("failed to open: '%s'\n", cache_file);
379 return -1;
380 }
381
382 DBG("Loading struct cache: '%s'\n", cache_file);
383
384 /* The cache file should start with auth data */
385 if (auth_data && auth_size) {
386 void* buf = malloc(auth_size);
387 if (!buf)
388 goto out;
389
390 if (read(fd, buf, auth_size) != auth_size) {
391 free(buf);
392 goto out;
393 }
394
395 if (memcmp(buf, auth_data, auth_size)) {
396 free(buf);
397 goto out;
398 }
399
400 free(buf);
401 }
402
403 if (j2s_root_struct_from_cache(ctx, fd, ptr) < 0)
404 goto out;
405
406 /* Check end of file */
407 if (read(fd, &ret, 1) > 0)
408 goto out;
409
410 DBG("Loaded struct cache: '%s'\n", cache_file);
411
412 ret = 0;
413 out:
414 close(fd);
415 return ret;
416 }
417
j2s_save_struct_cache(j2s_ctx * ctx,const char * cache_file,void * ptr,void * auth_data,int auth_size)418 void j2s_save_struct_cache(j2s_ctx* ctx, const char* cache_file, void* ptr,
419 void* auth_data, int auth_size)
420 {
421 int fd;
422 ssize_t bytes_written = 0;
423
424 fd = creat(cache_file, S_IRUSR | S_IWUSR);
425 if (fd < 0) {
426 DBG("failed to create: '%s'\n", cache_file);
427 return;
428 }
429
430 DBG("Saving struct cache: '%s'\n", cache_file);
431
432 if (auth_data && auth_size)
433 bytes_written = write(fd, auth_data, auth_size);
434
435 j2s_root_struct_to_cache(ctx, fd, ptr);
436
437 close(fd);
438 }
439
j2s_json_file_to_struct(j2s_ctx * ctx,const char * file,const char * name,void * ptr)440 int j2s_json_file_to_struct(j2s_ctx* ctx, const char* file, const char* name,
441 void* ptr)
442 {
443 char* cache_file = NULL;
444 struct stat st;
445 size_t size;
446 char* buf;
447 int ret = -1;
448
449 DASSERT_MSG(file && !stat(file, &st), return -1, "no such file: '%s'\n",
450 file ? file : "<null>");
451
452 #ifdef J2S_USING_CACH
453 cache_file = j2s_cache_file(file);
454
455 /* Using the file stat as auth data */
456 if (!j2s_load_struct_cache(ctx, cache_file, ptr, &st, sizeof(st))) {
457 free(cache_file);
458 return 0;
459 }
460 #endif
461
462 memset(ptr, 0, j2s_struct_size(ctx, ctx->root_index));
463
464 buf = (char*)j2s_read_file(file, &size);
465 if (!buf)
466 goto out;
467
468 DBG("Parse file: '%s', content:\n%s\n", file, buf);
469
470 if (j2s_modify_struct(ctx, buf, name, ptr) < 0)
471 goto out;
472
473 #ifdef J2S_USING_CACH
474 j2s_save_struct_cache(ctx, cache_file, ptr, &st, sizeof(st));
475 #endif
476 ret = 0;
477 out:
478 if (cache_file)
479 free(cache_file);
480 if (buf)
481 free(buf);
482 return ret;
483 }
484
j2s_dump_struct(j2s_ctx * ctx,const char * name,void * ptr)485 char* j2s_dump_struct(j2s_ctx* ctx, const char* name, void* ptr)
486 {
487 cJSON *json, *item;
488 char* buf;
489
490 DBG("Dump: %s\n", name ? name : "root struct");
491
492 if (!name) {
493 json = j2s_root_struct_to_json(ctx, ptr);
494 } else {
495 json = j2s_struct_to_json(ctx, name, ptr);
496 }
497
498 DASSERT(json, return NULL);
499
500 if (ctx->dump_enums) {
501 item = j2s_enums_to_json(ctx);
502 if (item)
503 cJSON_AddItemToObject(json, "@enum", item);
504 }
505
506 if (ctx->format_json) {
507 buf = cJSON_Print(json);
508 } else {
509 buf = cJSON_PrintUnformatted(json);
510 }
511
512 cJSON_Delete(json);
513 return buf;
514 }
515
j2s_modify_struct(j2s_ctx * ctx,const char * str,const char * name,void * ptr)516 int j2s_modify_struct(j2s_ctx* ctx, const char* str, const char* name,
517 void* ptr)
518 {
519 cJSON* json;
520 int ret = -1;
521
522 json = cJSON_Parse(str);
523 DASSERT_MSG(json, return -1, "failed to parse: '%s'\n", str);
524
525 DBG("Modify:\n%s\n", str);
526
527 ret = j2s_json_to_struct(ctx, json, name, ptr);
528
529 cJSON_Delete(json);
530 return ret;
531 }
532
j2s_query_struct(j2s_ctx * ctx,const char * str,void * ptr)533 char* j2s_query_struct(j2s_ctx* ctx, const char* str, void* ptr)
534 {
535 cJSON* json;
536 char* buf;
537
538 json = cJSON_Parse(str);
539 DASSERT_MSG(json, return NULL, "failed to parse: '%s'\n", str);
540
541 DBG("Query:\n%s\n", str);
542
543 if (j2s_json_from_root_struct(ctx, json, ptr) < 0) {
544 cJSON_Delete(json);
545 return NULL;
546 }
547
548 if (ctx->format_json) {
549 buf = cJSON_Print(json);
550 } else {
551 buf = cJSON_PrintUnformatted(json);
552 }
553
554 cJSON_Delete(json);
555 return buf;
556 }
557
j2s_dump_template_struct(j2s_ctx * ctx,const char * name)558 char* j2s_dump_template_struct(j2s_ctx* ctx, const char* name)
559 {
560 cJSON *json, *item;
561 char* buf;
562
563 DBG("Dump template: %s\n", name ? name : "root struct");
564
565 if (!name) {
566 json = j2s_root_struct_to_template_json(ctx);
567 } else {
568 json = j2s_struct_to_template_json(ctx, name);
569 }
570
571 DASSERT(json, return NULL);
572
573 if (ctx->dump_enums) {
574 item = j2s_enums_to_json(ctx);
575 if (item)
576 cJSON_AddItemToObject(json, "@enum", item);
577 }
578
579 if (ctx->format_json) {
580 buf = cJSON_Print(json);
581 } else {
582 buf = cJSON_PrintUnformatted(json);
583 }
584
585 cJSON_Delete(json);
586 return buf;
587 }
588
j2s_dump_structs(j2s_ctx * ctx,j2s_struct_info * info)589 char* j2s_dump_structs(j2s_ctx* ctx, j2s_struct_info* info)
590 {
591 cJSON *json, *item;
592 char* buf;
593
594 if (!info || !info->name)
595 return NULL;
596
597 DBG("Dump structs\n");
598
599 json = cJSON_CreateObject();
600 DASSERT(json, return NULL);
601
602 for (; info->name; info++) {
603 item = j2s_struct_to_json(ctx, info->name, info->ptr);
604 if (!item)
605 continue;
606
607 cJSON_AddItemToObject(json, info->name, item);
608 }
609
610 if (ctx->dump_enums) {
611 item = j2s_enums_to_json(ctx);
612 if (item)
613 cJSON_AddItemToObject(json, "@enum", item);
614 }
615
616 if (ctx->format_json) {
617 buf = cJSON_Print(json);
618 } else {
619 buf = cJSON_PrintUnformatted(json);
620 }
621
622 cJSON_Delete(json);
623 return buf;
624 }
625