/* * 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" 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 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; } 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 = 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 = cJSON_CreateNumber(enum_value->value); if (item) 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; 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; 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) { if (!j2s_template_dumping) { ptr += obj->offset; ptr = *(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 @_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; 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 ?: ""); } /* 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 = 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 @ */ 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_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; ret = 0; /* 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; 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 ?: ""); } else { char* str = cJSON_GetStringValue(root); if (obj->flags == J2S_FLAG_ARRAY) { strncpy(ptr, str ?: "", obj->num_elem); } else { char** buf = (char**)ptr; if (*buf) free(*buf); *buf = strdup(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 = 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; 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; if (!J2S_IS_POINTER(obj)) return; ptr = *(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, 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, 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); } }