android13/external/camera_engine_rkaiq/iq_parser_v2/j2s/j2s.cpp

1295 lines
33 KiB
C++

/*
* Copyright (c) 2020, Rockchip Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "j2s.h"
using namespace RkCam;
static bool j2s_template_dumping = false;
__attribute__((weak)) void* j2s_alloc_data(j2s_ctx* ctx, size_t size)
{
return malloc(size);
}
__attribute__((weak)) void j2s_release_data(j2s_ctx* ctx, void* ptr)
{
free(ptr);
}
static cJSON* _j2s_obj_to_json(j2s_ctx* ctx, int obj_index, void* ptr);
static cJSON* _j2s_struct_to_json(j2s_ctx* ctx, int struct_index, void* ptr);
static int _j2s_json_to_obj(j2s_ctx* ctx, cJSON* json, cJSON* parent,
int obj_index, void* ptr, bool query);
static int _j2s_json_to_struct(j2s_ctx* ctx, cJSON* json, int struct_index,
void* ptr, bool query);
static int _j2s_obj_from_cache(j2s_ctx* ctx, int obj_index, int fd, void* ptr);
static int _j2s_struct_from_cache(j2s_ctx* ctx, int struct_index, int fd,
void* ptr);
static void _j2s_obj_to_cache(j2s_ctx* ctx, int obj_index, int fd, void* ptr);
static void _j2s_struct_to_cache(j2s_ctx* ctx, int struct_index, int fd,
void* ptr);
static int _j2s_struct_free(j2s_ctx* ctx, int struct_index, void* ptr);
static inline int j2s_find_struct_index(j2s_ctx* ctx, const char* name)
{
if (!name)
return -1;
for (int i = 0; i < ctx->num_struct; i++) {
j2s_struct* struct_obj = &ctx->structs[i];
if (!strcmp(struct_obj->name, name))
return i;
}
return -1;
}
int j2s_struct_free(j2s_ctx* ctx, const char* name, void* ptr)
{
int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
return _j2s_struct_free(ctx, struct_index, ptr);
}
cJSON* j2s_struct_to_json(j2s_ctx* ctx, const char* name, void* ptr)
{
int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
return _j2s_struct_to_json(ctx, struct_index, ptr);
}
int j2s_json_to_struct(j2s_ctx* ctx, cJSON* json, const char* name, void* ptr)
{
int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
return _j2s_json_to_struct(ctx, json, struct_index, ptr, false);
}
int j2s_json_from_struct(j2s_ctx* ctx, cJSON* json, const char* name,
void* ptr)
{
int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
return _j2s_json_to_struct(ctx, json, struct_index, ptr, true);
}
void j2s_struct_to_cache(j2s_ctx* ctx, const char* name, int fd, void* ptr)
{
int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
_j2s_struct_to_cache(ctx, struct_index, fd, ptr);
}
int j2s_struct_from_cache(j2s_ctx* ctx, const char* name, int fd, void* ptr)
{
int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
return _j2s_struct_from_cache(ctx, struct_index, fd, ptr);
}
/* Enum name to value */
static inline int j2s_enum_get_value(j2s_ctx* ctx, int enum_index,
const char* name)
{
j2s_enum* enum_obj;
if (enum_index < 0 || !name)
return -1;
enum_obj = &ctx->enums[enum_index];
for (int i = 0; i < enum_obj->num_value; i++) {
j2s_enum_value* enum_value = &ctx->enum_values[enum_obj->value_index + i];
if (!strcmp(enum_value->name, name))
return enum_value->value;
}
WARN("unknown enum name: %s for %s\n", name, enum_obj->name);
return -1;
}
/* Enum value to name */
static inline const char* j2s_enum_get_name(j2s_ctx* ctx, int enum_index,
int value)
{
j2s_enum* enum_obj;
if (enum_index < 0)
goto out;
enum_obj = &ctx->enums[enum_index];
for (int i = 0; i < enum_obj->num_value; i++) {
j2s_enum_value* enum_value = &ctx->enum_values[enum_obj->value_index + i];
if (enum_value->value == value)
return enum_value->name;
}
WARN("unknown enum value: %d for %s\n", value, enum_obj->name);
out:
return "INVALID";
}
static cJSON* _j2s_enum_to_json(j2s_ctx* ctx, int enum_index)
{
j2s_enum* enum_obj;
cJSON *root, *item;
if (enum_index < 0)
return NULL;
enum_obj = &ctx->enums[enum_index];
root = RkCam::cJSON_CreateObject();
DASSERT(root, return NULL);
for (int i = 0; i < enum_obj->num_value; i++) {
j2s_enum_value* enum_value = &ctx->enum_values[enum_obj->value_index + i];
item = RkCam::cJSON_CreateNumber(enum_value->value);
if (item)
RkCam::cJSON_AddItemToObject(root, enum_value->name, item);
}
return root;
}
cJSON* j2s_enums_to_json(j2s_ctx* ctx)
{
cJSON *root, *item;
if (!ctx->num_enum)
return NULL;
root = cJSON_CreateObject();
DASSERT(root, return NULL);
for (int i = 0; i < ctx->num_enum; i++) {
j2s_enum* enum_obj = &ctx->enums[i];
item = _j2s_enum_to_json(ctx, i);
if (item)
cJSON_AddItemToObject(root, enum_obj->name, item);
}
return root;
}
static cJSON* _j2s_struct_to_template_json(j2s_ctx* ctx, int struct_index)
{
j2s_struct* struct_obj;
cJSON* json;
if (struct_index < 0)
return NULL;
struct_obj = &ctx->structs[struct_index];
if (struct_obj->child_index < 0)
return NULL;
DBG("start struct: %s\n", struct_obj->name);
j2s_template_dumping = true;
json = _j2s_struct_to_json(ctx, struct_index, NULL);
j2s_template_dumping = false;
DBG("finish struct: %s\n", struct_obj->name);
return json;
}
cJSON* j2s_struct_to_template_json(j2s_ctx* ctx, const char* name)
{
int struct_index = name ? j2s_find_struct_index(ctx, name) : ctx->root_index;
return _j2s_struct_to_template_json(ctx, struct_index);
}
int j2s_struct_size(j2s_ctx* ctx, int struct_index)
{
j2s_struct* struct_obj;
j2s_obj* child;
int child_index, child_size;
if (struct_index < 0)
return 0;
struct_obj = &ctx->structs[struct_index];
/* Find last child */
for (child = NULL, child_index = struct_obj->child_index; child_index >= 0;
child_index = child->next_index)
child = &ctx->objs[child_index];
if (!child)
return 0;
if (J2S_IS_POINTER(child)) {
child_size = (int)sizeof(void*);
} else if (J2S_IS_ARRAY(child)) {
child_size = child->elem_size * child->num_elem;
} else {
child_size = child->elem_size;
}
return child_size + child->offset;
}
const char* j2s_type_name(j2s_type type)
{
switch (type) {
case J2S_TYPE_INT_8:
return "int8_t";
case J2S_TYPE_UINT_8:
return "uint8_t";
case J2S_TYPE_INT_16:
return "int16_t";
case J2S_TYPE_UINT_16:
return "uint16_t";
case J2S_TYPE_INT_32:
return "int32_t";
case J2S_TYPE_UINT_32:
return "uint32_t";
case J2S_TYPE_INT_64:
return "int64_t";
case J2S_TYPE_UINT_64:
return "uint64_t";
case J2S_TYPE_FLOAT:
return "float";
case J2S_TYPE_DOUBLE:
return "double";
case J2S_TYPE_STRING:
return "char";
case J2S_TYPE_STRUCT:
return "struct";
default:
return "unknown";
}
}
/* Get number value from a obj */
static inline double j2s_obj_get_value(j2s_ctx* ctx, int obj_index, void* ptr_)
{
j2s_obj* obj;
double value;
char* ptr = (char*)ptr_;
if (!ptr || obj_index < 0)
return 0;
obj = &ctx->objs[obj_index];
ptr += obj->offset;
#define J2S_FETCH_NUM(type, ptr) \
value = (double)*((type*)ptr); \
return value;
switch (obj->type) {
case J2S_TYPE_INT_8:
J2S_FETCH_NUM(int8_t, ptr);
case J2S_TYPE_UINT_8:
J2S_FETCH_NUM(uint8_t, ptr);
case J2S_TYPE_INT_16:
J2S_FETCH_NUM(int16_t, ptr);
case J2S_TYPE_UINT_16:
J2S_FETCH_NUM(uint16_t, ptr);
case J2S_TYPE_INT_32:
J2S_FETCH_NUM(int32_t, ptr);
case J2S_TYPE_UINT_32:
J2S_FETCH_NUM(uint32_t, ptr);
case J2S_TYPE_INT_64:
J2S_FETCH_NUM(int64_t, ptr);
case J2S_TYPE_UINT_64:
J2S_FETCH_NUM(uint64_t, ptr);
case J2S_TYPE_FLOAT:
J2S_FETCH_NUM(float, ptr);
case J2S_TYPE_DOUBLE:
J2S_FETCH_NUM(double, ptr);
default:
return 0;
}
}
/* Set number value to a obj */
static inline int j2s_obj_set_value(j2s_ctx* ctx, int obj_index, double value,
void* ptr_)
{
j2s_obj* obj;
char* ptr = (char*)ptr_;
if (!ptr || obj_index < 0)
return 0;
obj = &ctx->objs[obj_index];
ptr += obj->offset;
#define J2S_STORE_NUM(type, value, ptr) \
*(type*)ptr = (type)value; \
return 0;
switch (obj->type) {
case J2S_TYPE_INT_8:
J2S_STORE_NUM(int8_t, value, ptr);
case J2S_TYPE_UINT_8:
J2S_STORE_NUM(uint8_t, value, ptr);
case J2S_TYPE_INT_16:
J2S_STORE_NUM(int16_t, value, ptr);
case J2S_TYPE_UINT_16:
J2S_STORE_NUM(uint16_t, value, ptr);
case J2S_TYPE_INT_32:
J2S_STORE_NUM(int32_t, value, ptr);
case J2S_TYPE_UINT_32:
J2S_STORE_NUM(uint32_t, value, ptr);
case J2S_TYPE_INT_64:
J2S_STORE_NUM(int64_t, value, ptr);
case J2S_TYPE_UINT_64:
J2S_STORE_NUM(uint64_t, value, ptr);
case J2S_TYPE_FLOAT:
J2S_STORE_NUM(float, value, ptr);
case J2S_TYPE_DOUBLE:
J2S_STORE_NUM(double, value, ptr);
default:
return 0;
}
}
/* Extract array to the first elem */
static inline void j2s_extract_array(j2s_obj* obj)
{
if (obj->flags & J2S_FLAG_DEP_ARRAY) {
obj->flags &= ~J2S_FLAG_DEP_ARRAY;
obj->num_elem = obj->elem_size / obj->base_elem_size;
} else {
obj->flags &= ~J2S_FLAG_ARRAY;
obj->num_elem = 1;
}
obj->elem_size = obj->base_elem_size;
}
/* Extract dynamic array to normal array */
static inline void* j2s_extract_dynamic_array(j2s_obj* obj, int len,
void* ptr_)
{
char* ptr = (char*)ptr_;
if (!j2s_template_dumping) {
ptr += obj->offset;
ptr = (char*)(*(void**)ptr);
if (!ptr)
return NULL;
}
obj->offset = 0;
obj->len_index = -1;
obj->num_elem = len;
if (obj->flags & J2S_FLAG_DEP_POINTER) {
obj->flags &= ~J2S_FLAG_DEP_POINTER;
} else {
obj->flags &= ~J2S_FLAG_ARRAY_POINTER;
obj->flags &= ~J2S_FLAG_POINTER;
}
if (obj->flags & J2S_FLAG_ARRAY) {
obj->flags |= J2S_FLAG_DEP_ARRAY;
} else {
obj->flags |= J2S_FLAG_ARRAY;
}
return ptr;
}
static cJSON* j2s_get_index_json(j2s_ctx* ctx, cJSON* parent, int obj_index)
{
j2s_obj* obj;
char index_name[MAX_NAME + 10];
if (obj_index < 0)
return NULL;
obj = &ctx->objs[obj_index];
/* Handle array with index obj @<name>_index */
snprintf(index_name, sizeof(index_name), "@%s_index", obj->name);
return cJSON_GetObjectItemCaseSensitive(parent, index_name);
}
static cJSON* _j2s_obj_to_json(j2s_ctx* ctx, int obj_index, void* ptr_)
{
j2s_obj* obj;
cJSON* root;
double value;
char* ptr = (char*)ptr_;
if (obj_index < 0)
return NULL;
obj = &ctx->objs[obj_index];
DBG("handling obj: %s from %p[%d]\n", obj->name, ptr, obj->offset);
/* Handle simple string */
if (J2S_IS_SIMPLE_STRING(obj)) {
if (j2s_template_dumping)
return cJSON_CreateString("");
ptr += obj->offset;
if (obj->flags & J2S_FLAG_POINTER)
ptr = *(char**)ptr;
return cJSON_CreateString(ptr ? ptr : "");
}
/* Handle array member */
if (J2S_IS_ARRAY(obj)) {
j2s_obj tmp_obj;
cJSON* item;
root = cJSON_CreateArray();
DASSERT(root, return NULL);
tmp_obj = *obj;
/* Walk into array */
j2s_extract_array(obj);
for (int i = 0; i < tmp_obj.num_elem; i++) {
DBG("handling array: %s %d/%d\n", obj->name, i, tmp_obj.num_elem);
item = _j2s_obj_to_json(ctx, obj_index, ptr);
if (item)
cJSON_AddItemToArray(root, item);
obj->offset += tmp_obj.elem_size;
}
*obj = tmp_obj;
return root;
}
/* Handle dynamic array */
if (J2S_IS_POINTER(obj)) {
j2s_obj tmp_obj;
int len;
DASSERT_MSG(obj->len_index >= 0, return NULL,
"dynamic array %s missing len\n", obj->name);
if (j2s_template_dumping) {
len = 1;
} else {
len = j2s_obj_get_value(ctx, obj->len_index, ptr);
}
if (!len)
return cJSON_CreateArray();
tmp_obj = *obj;
/* Walk into dynamic array */
ptr = (char*)j2s_extract_dynamic_array(obj, len, ptr);
DASSERT_MSG(j2s_template_dumping || ptr, return NULL,
"found null pointer at %s\n", obj->name);
DBG("handling dynamic array: %s %d*%d from %p\n", obj->name, obj->elem_size,
obj->num_elem, ptr);
root = _j2s_obj_to_json(ctx, obj_index, ptr);
*obj = tmp_obj;
return root;
}
/* Handle struct member */
if (obj->type == J2S_TYPE_STRUCT)
return _j2s_struct_to_json(ctx, obj->struct_index, ptr + obj->offset);
/* Handle basic member */
if (j2s_template_dumping) {
for (int i = 0; i < ctx->num_obj; i++) {
if (ctx->objs[i].len_index == obj_index)
return cJSON_CreateNumber(1);
}
if (obj->enum_index >= 0) {
/* Use first value as default */
j2s_enum* enum_obj = &ctx->enums[obj->enum_index];
j2s_enum_value* enum_value = &ctx->enum_values[enum_obj->value_index];
return cJSON_CreateString(enum_value->name);
}
return cJSON_CreateNumber(0);
}
value = j2s_obj_get_value(ctx, obj_index, ptr);
if (obj->enum_index >= 0) {
/* Convert enum value to name */
const char* name = j2s_enum_get_name(ctx, obj->enum_index, (int)value);
return cJSON_CreateString(name);
}
return cJSON_CreateNumber(value);
}
static cJSON* _j2s_struct_to_json(j2s_ctx* ctx, int struct_index, void* ptr)
{
j2s_struct* struct_obj;
j2s_obj* child;
cJSON *root, *item;
int child_index, ret = 0;
if (struct_index < 0)
return NULL;
struct_obj = &ctx->structs[struct_index];
if (struct_obj->child_index < 0)
return NULL;
root = cJSON_CreateObject();
DASSERT(root, return NULL);
DBG("start struct: %s from %p\n", struct_obj->name, ptr);
ret = -1;
/* Walk child list */
for (child_index = struct_obj->child_index; child_index >= 0;
child_index = child->next_index) {
child = &ctx->objs[child_index];
DBG("start child: %s (%s) from %p\n", child->name, struct_obj->name, ptr);
item = _j2s_obj_to_json(ctx, child_index, ptr);
DBG("finish child: %s (%s)\n", child->name, struct_obj->name);
if (item) {
if (ctx->dump_desc && child_index < ctx->num_desc) {
/* Dump desc to template JSON as @<member> */
char buf[MAX_NAME + 1] = "@";
const char* desc = ctx->descs[child_index];
if (desc) {
cJSON* json = cJSON_CreateString(desc);
DASSERT(json, goto out);
strcat(buf, child->name);
cJSON_AddItemToObject(root, buf, json);
}
}
cJSON_AddItemToObject(root, child->name, item);
}
}
ret = 0;
out:
DBG("finish struct: %s\n", struct_obj->name);
if (ret < 0) {
cJSON_Delete(root);
return NULL;
}
return root;
}
static int _j2s_obj_free(j2s_ctx* ctx, int obj_index, void* ptr_)
{
j2s_obj* obj;
char* ptr = (char*)ptr_;
if (obj_index < 0)
return -1;
obj = &ctx->objs[obj_index];
/* Handle simple string */
if (J2S_IS_SIMPLE_STRING(obj)) {
ptr += obj->offset;
if (obj->flags & J2S_FLAG_ARRAY) {
return 0;
}
if (obj->flags & J2S_FLAG_POINTER) {
ptr = *(char**)ptr;
}
if (ptr) {
free(ptr);
}
return 0;
}
/* Handle array member */
if (J2S_IS_ARRAY(obj)) {
j2s_obj tmp_obj;
tmp_obj = *obj;
/* Walk into array */
j2s_extract_array(obj);
for (int i = 0; i < tmp_obj.num_elem; i++) {
_j2s_obj_free(ctx, obj_index, ptr);
obj->offset += tmp_obj.elem_size;
}
*obj = tmp_obj;
return 0;
}
/* Handle dynamic array */
if (J2S_IS_POINTER(obj)) {
j2s_obj tmp_obj;
// void* root_ptr = *(void**)ptr;
int len;
if (obj->len_index < 0) {
DBG("dynamic array %s missing len\n", obj->name);
return -1;
}
len = j2s_obj_get_value(ctx, obj->len_index, ptr);
if (len <= 0) {
DBG("array size error: %s %d\n", obj->name, len);
return -1;
}
tmp_obj = *obj;
/* Walk into dynamic array */
ptr = (char*)j2s_extract_dynamic_array(obj, len, ptr);
_j2s_obj_free(ctx, obj_index, ptr);
if (ptr) {
free(ptr);
}
*obj = tmp_obj;
return 0;
}
/* Handle struct member */
if (obj->type == J2S_TYPE_STRUCT) {
return _j2s_struct_free(ctx, obj->struct_index, ptr + obj->offset);
}
return 0;
}
static int _j2s_struct_free(j2s_ctx* ctx, int struct_index, void* ptr)
{
j2s_struct* struct_obj = NULL;
j2s_obj* child = NULL;
int child_index, ret = 0;
if (struct_index < 0)
return -1;
struct_obj = &ctx->structs[struct_index];
if (struct_obj->child_index < 0)
return -1;
ret = -1;
/* Walk child list */
for (child_index = struct_obj->child_index; child_index >= 0;
child_index = child->next_index) {
child = &ctx->objs[child_index];
ret = _j2s_obj_free(ctx, child_index, ptr);
}
return ret;
}
static int j2s_json_to_array_with_index(j2s_ctx* ctx, cJSON* json,
cJSON* index_json, cJSON* parent,
j2s_obj* obj, void* ptr, bool query)
{
j2s_obj tmp_obj;
cJSON *index_item, *item;
int size, index, ret = -1;
size = cJSON_GetArraySize(index_json);
if (!size)
return 0;
tmp_obj = *obj;
/* Walk into array */
j2s_extract_array(obj);
if (query) {
cJSON* root;
/* Clear the original array */
root = cJSON_CreateArray();
cJSON_ReplaceItemInObjectCaseSensitive(parent, obj->name, root);
for (int i = 0; i < size; i++) {
index_item = cJSON_GetArrayItem(index_json, i);
index = cJSON_GetNumberValue(index_item);
obj->offset = tmp_obj.offset + index * tmp_obj.elem_size;
item = NULL;
DBG("handling index array: %s %d/%d\n", obj->name, index,
tmp_obj.num_elem);
/* Query item */
if (index < tmp_obj.num_elem)
item = _j2s_obj_to_json(ctx, obj - ctx->objs, ptr);
if (!item) {
item = cJSON_CreateObject();
if (!item) {
ret = -1;
break;
}
}
cJSON_AddItemToArray(root, item);
}
} else {
for (int i = 0; i < size; i++) {
index_item = cJSON_GetArrayItem(index_json, i);
index = cJSON_GetNumberValue(index_item);
obj->offset = tmp_obj.offset + index * tmp_obj.elem_size;
DBG("handling index array: %s %d/%d\n", obj->name, index,
tmp_obj.num_elem);
if (index >= tmp_obj.num_elem)
continue;
/* Apply item */
item = cJSON_GetArrayItem(json, i);
if (!item)
break;
ret = _j2s_json_to_obj(ctx, item, parent, obj - ctx->objs, ptr, false);
if (ret < 0)
break;
}
}
*obj = tmp_obj;
return ret;
}
static int _j2s_json_to_obj(j2s_ctx* ctx, cJSON* json, cJSON* parent,
int obj_index, void* ptr_, bool query)
{
j2s_obj* obj;
cJSON* root = json;
int ret = 0;
char* ptr = (char*)ptr_;
if (obj_index < 0)
return -1;
obj = &ctx->objs[obj_index];
DBG("handling obj: %s from %p[%d]\n", obj->name, ptr, obj->offset);
/* Handle simple string */
if (J2S_IS_SIMPLE_STRING(obj)) {
ptr += obj->offset;
if (query) {
if (obj->flags == J2S_FLAG_POINTER)
ptr = *(char**)ptr;
cJSON_SetValuestring(root, ptr ? ptr : "");
} else {
char* str = cJSON_GetStringValue(root);
if (obj->flags == J2S_FLAG_ARRAY) {
strncpy(ptr, str ? str : "", obj->num_elem);
} else {
char** buf = (char**)ptr;
if (*buf)
free(*buf);
*buf = strdup(str ? str : "");
}
}
return 0;
}
/* Handle array member */
if (J2S_IS_ARRAY(obj)) {
j2s_obj tmp_obj;
cJSON *item, *index_json;
index_json = j2s_get_index_json(ctx, parent, obj_index);
if (index_json && obj->type != J2S_TYPE_STRING && obj->flags != J2S_FLAG_ARRAY) {
cJSON_DetachItemViaPointer(parent, index_json);
index_json = NULL;
WARN("ignoring index for dep types %s\n", obj->name);
}
if (index_json)
return j2s_json_to_array_with_index(ctx, json, index_json, parent, obj,
ptr, query);
tmp_obj = *obj;
/* Walk into array */
j2s_extract_array(obj);
for (int i = 0; i < tmp_obj.num_elem; i++) {
DBG("handling array: %s %d/%d\n", obj->name, i, tmp_obj.num_elem);
item = cJSON_GetArrayItem(root, i);
if (!item)
continue;
ret = _j2s_json_to_obj(ctx, item, parent, obj_index, ptr, query);
if (ret < 0)
break;
obj->offset += tmp_obj.elem_size;
}
*obj = tmp_obj;
return ret;
}
/* Handle dynamic array */
if (J2S_IS_POINTER(obj)) {
j2s_obj tmp_obj;
cJSON *len_json, *index_json;
char* len_name;
int len, old_len;
DASSERT_MSG(obj->len_index >= 0, return -1,
"dynamic array %s missing len\n", obj->name);
len_name = ctx->objs[obj->len_index].name;
len_json = cJSON_GetObjectItemCaseSensitive(parent, len_name);
if (!len_json && !query)
WARN("missing len in json for dynamic array '%s'\n", obj->name);
index_json = j2s_get_index_json(ctx, parent, obj_index);
if (query && !index_json) {
/* Query dynamic array len */
if (len_json)
cJSON_DetachItemViaPointer(parent, len_json);
len_json = _j2s_obj_to_json(ctx, obj->len_index, ptr);
DASSERT_MSG(len_json, return -1, "failed to query %s\n", len_name);
cJSON_AddItemToObject(parent, len_name, len_json);
/* Force query the whole dynamic array */
cJSON_DetachItemViaPointer(parent, json);
cJSON_Delete(json);
json = _j2s_obj_to_json(ctx, obj_index, ptr);
DASSERT_MSG(json, return -1, "failed to query %s\n", obj->name);
cJSON_AddItemToObject(parent, obj->name, json);
return 0;
}
old_len = j2s_obj_get_value(ctx, obj->len_index, ptr);
if (len_json) {
len = cJSON_GetArraySize(json);
/* Fallback to array size */
cJSON_SetNumberValue(len_json, len);
} else if (index_json) {
len = old_len;
} else {
/* Fallback to array size */
len = cJSON_GetArraySize(json);
}
if (len != old_len) {
/* Dynamic array size changed, realloc it */
void** buf = (void**)(ptr + obj->offset);
if (old_len && *buf)
j2s_release_data(ctx, *buf);
*buf = j2s_alloc_data(ctx, len * obj->elem_size);
j2s_obj_set_value(ctx, obj->len_index, len, ptr);
DBG("re-alloc %s from %d*%d to %d*%d = %p\n", obj->name, old_len,
obj->elem_size, len, obj->elem_size, *buf);
}
if (!len)
return 0;
tmp_obj = *obj;
/* Walk into dynamic array */
ptr = (char*)j2s_extract_dynamic_array(obj, len, ptr);
DASSERT_MSG(ptr, return -1, "found null pointer at %s\n", obj->name);
DBG("handling dynamic array: %s %d*%d from %p\n", obj->name, obj->elem_size,
obj->num_elem, ptr);
ret = _j2s_json_to_obj(ctx, root, parent, obj_index, ptr, query);
*obj = tmp_obj;
return ret;
}
/* Handle struct member */
if (obj->type == J2S_TYPE_STRUCT)
return _j2s_json_to_struct(ctx, root, obj->struct_index, ptr + obj->offset,
query);
/* Handle basic member */
if (query) {
double value = j2s_obj_get_value(ctx, obj_index, ptr);
if (obj->enum_index >= 0) {
/* Convert enum value to name */
const char* name = j2s_enum_get_name(ctx, obj->enum_index, (int)value);
cJSON_SetValuestring(root, name);
return 0;
}
cJSON_SetNumberValue(root, value);
return 0;
} else {
double value;
if (obj->enum_index >= 0) {
/* Convert enum name to value */
char* name = cJSON_GetStringValue(root);
value = (double)j2s_enum_get_value(ctx, obj->enum_index, name);
} else {
value = cJSON_GetNumberValue(root);
}
j2s_obj_set_value(ctx, obj_index, value, ptr);
return 0;
}
}
static int _j2s_json_to_struct(j2s_ctx* ctx, cJSON* json, int struct_index,
void* ptr, bool query)
{
j2s_struct* struct_obj;
j2s_obj* child;
cJSON *item, *root = json;
int child_index, ret = 0;
if (struct_index < 0)
return -1;
struct_obj = &ctx->structs[struct_index];
DBG("start struct: %s from %p\n", struct_obj->name, ptr);
/* Walk child list */
for (child_index = struct_obj->child_index; child_index >= 0;
child_index = child->next_index) {
child = &ctx->objs[child_index];
item = cJSON_GetObjectItemCaseSensitive(root, child->name);
if (!item)
continue;
DBG("start child: %s (%s) from %p\n", child->name, struct_obj->name, ptr);
ret = _j2s_json_to_obj(ctx, item, root, child_index, ptr, query);
DBG("finish child: %s (%s)\n", child->name, struct_obj->name);
if (ret < 0)
break;
}
DBG("finish struct: %s\n", struct_obj->name);
return ret;
}
static int j2s_restore_obj(j2s_ctx* ctx, j2s_obj* obj, int fd, void* ptr_)
{
char buf[MAX_NAME];
void** data_ptr;
int size;
char* ptr = (char*)ptr_;
if (!J2S_IS_POINTER(obj))
return 0;
data_ptr = (void**)(ptr + obj->offset);
if (read(fd, buf, MAX_NAME) != MAX_NAME)
return -1;
if (strncmp(obj->name, buf, MAX_NAME) < 0)
return -1;
if (read(fd, &size, sizeof(int)) != sizeof(int))
return -1;
if (!size) {
*data_ptr = NULL;
return 0;
}
*data_ptr = j2s_alloc_data(ctx, size);
if (!*data_ptr)
return -1;
if (read(fd, *data_ptr, size) != size) {
j2s_release_data(ctx, *data_ptr);
return -1;
}
DBG("restore obj: %s to %p, size %d\n", obj->name, *data_ptr, size);
return size;
}
static void j2s_store_obj(j2s_obj* obj, int fd, void* ptr_)
{
char buf[MAX_NAME] = { 0 };
int size;
ssize_t bytes_written = 0;
char* ptr = (char*)ptr_;
if (!J2S_IS_POINTER(obj))
return;
ptr = (char*)(*(void**)(ptr + obj->offset));
if (!ptr)
return;
if (J2S_IS_SIMPLE_STRING(obj)) {
size = strlen(ptr) + 1;
} else {
size = obj->num_elem * obj->elem_size;
}
DBG("store obj: %s from %p, size %d\n", obj->name, ptr, size);
strcpy(buf, obj->name);
bytes_written = write(fd, buf, MAX_NAME);
bytes_written = write(fd, &size, sizeof(int));
bytes_written = write(fd, ptr, size);
}
static int _j2s_obj_from_cache(j2s_ctx* ctx, int obj_index, int fd, void* ptr)
{
j2s_obj* obj;
int ret = 0;
if (obj_index < 0)
return -1;
obj = &ctx->objs[obj_index];
DBG("handling obj: %s from %p[%d]\n", obj->name, ptr, obj->offset);
/* Handle simple string */
if (J2S_IS_SIMPLE_STRING(obj))
return j2s_restore_obj(ctx, obj, fd, ptr);
/* Handle array member */
if (J2S_IS_ARRAY(obj)) {
j2s_obj tmp_obj = *obj;
if (obj->type != J2S_TYPE_STRUCT && obj->type != J2S_TYPE_STRING)
return 0;
/* Walk into array */
j2s_extract_array(obj);
for (int i = 0; i < tmp_obj.num_elem; i++) {
DBG("handling array: %s %d/%d\n", obj->name, i, tmp_obj.num_elem);
ret = _j2s_obj_from_cache(ctx, obj_index, fd, ptr);
if (ret < 0)
break;
obj->offset += tmp_obj.elem_size;
}
*obj = tmp_obj;
return ret;
}
/* Handle dynamic array */
if (J2S_IS_POINTER(obj)) {
j2s_obj tmp_obj = *obj;
int size;
size = j2s_restore_obj(ctx, obj, fd, ptr);
if (size <= 0)
return size;
/* Walk into dynamic array */
ptr = j2s_extract_dynamic_array(obj, size / obj->elem_size, ptr);
DBG("handling dynamic array: %s %d*%d from %p\n", obj->name, obj->elem_size,
obj->num_elem, ptr);
ret = _j2s_obj_from_cache(ctx, obj_index, fd, ptr);
*obj = tmp_obj;
return ret;
}
/* Handle struct member */
if (obj->type == J2S_TYPE_STRUCT)
return _j2s_struct_from_cache(ctx, obj->struct_index, fd,
(char*)ptr + obj->offset);
return 0;
}
static int _j2s_struct_from_cache(j2s_ctx* ctx, int struct_index, int fd,
void* ptr)
{
j2s_struct* struct_obj;
j2s_obj* child;
int child_index;
if (struct_index < 0)
return -1;
if (struct_index == ctx->root_index) {
int root_size = j2s_struct_size(ctx, ctx->root_index);
if (read(fd, ptr, root_size) != root_size)
return -1;
}
struct_obj = &ctx->structs[struct_index];
/* Walk child list */
for (child_index = struct_obj->child_index; child_index >= 0;
child_index = child->next_index) {
child = &ctx->objs[child_index];
if (_j2s_obj_from_cache(ctx, child_index, fd, ptr) < 0)
return -1;
}
return 0;
}
static void _j2s_obj_to_cache(j2s_ctx* ctx, int obj_index, int fd, void* ptr)
{
j2s_obj* obj;
if (obj_index < 0)
return;
obj = &ctx->objs[obj_index];
DBG("handling obj: %s from %p[%d]\n", obj->name, ptr, obj->offset);
/* Handle simple string */
if (J2S_IS_SIMPLE_STRING(obj)) {
j2s_store_obj(obj, fd, ptr);
return;
}
/* Handle array member */
if (J2S_IS_ARRAY(obj)) {
j2s_obj tmp_obj = *obj;
if (obj->type != J2S_TYPE_STRUCT && obj->type != J2S_TYPE_STRING)
return;
/* Walk into array */
j2s_extract_array(obj);
for (int i = 0; i < tmp_obj.num_elem; i++) {
DBG("handling array: %s %d/%d\n", obj->name, i, tmp_obj.num_elem);
_j2s_obj_to_cache(ctx, obj_index, fd, ptr);
obj->offset += tmp_obj.elem_size;
}
*obj = tmp_obj;
return;
}
/* Handle dynamic array */
if (J2S_IS_POINTER(obj)) {
j2s_obj tmp_obj = *obj;
int len;
if (obj->len_index < 0)
return;
len = j2s_obj_get_value(ctx, obj->len_index, ptr);
if (!len)
return;
obj->num_elem = len;
j2s_store_obj(obj, fd, ptr);
/* Walk into dynamic array */
ptr = j2s_extract_dynamic_array(obj, len, ptr);
DBG("handling dynamic array: %s %d*%d from %p\n", obj->name, obj->elem_size,
obj->num_elem, ptr);
_j2s_obj_to_cache(ctx, obj_index, fd, ptr);
*obj = tmp_obj;
return;
}
/* Handle struct member */
if (obj->type == J2S_TYPE_STRUCT)
_j2s_struct_to_cache(ctx, obj->struct_index, fd, (char*)ptr + obj->offset);
}
static void _j2s_struct_to_cache(j2s_ctx* ctx, int struct_index, int fd,
void* ptr)
{
j2s_struct* struct_obj;
j2s_obj* child;
int child_index;
ssize_t bytes_written = 0;
if (struct_index < 0)
return;
if (struct_index == ctx->root_index)
bytes_written = write(fd, ptr, j2s_struct_size(ctx, struct_index));
struct_obj = &ctx->structs[struct_index];
/* Walk child list */
for (child_index = struct_obj->child_index; child_index >= 0;
child_index = child->next_index) {
child = &ctx->objs[child_index];
_j2s_obj_to_cache(ctx, child_index, fd, ptr);
}
}