diff --git a/bbfdmd/ubus/plugin.c b/bbfdmd/ubus/plugin.c index b050202b..529814d0 100644 --- a/bbfdmd/ubus/plugin.c +++ b/bbfdmd/ubus/plugin.c @@ -88,14 +88,15 @@ int load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, save_loaded_json_files(json_plugin, json_obj); json_object_object_foreach(json_obj, key, jobj) { + char node_obj[1024] = {0}; if (strcmp(key, "json_plugin_version") == 0) { json_plugin_version = json_object_get_int(jobj); continue; } - char *node_obj = replace_str(key, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX); - if (node_obj == NULL) { + replace_str(key, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX, node_obj, sizeof(node_obj)); + if (strlen(node_obj) == 0) { ERR("ERROR: Can't get the node object\n"); return -1; } @@ -133,7 +134,6 @@ int load_json_plugin(struct list_head *json_plugin, struct list_head *json_list, dm_entryobj[0].bbfdm_type = BBFDM_BOTH; parse_obj(node_obj, jobj, dm_entryobj[0].nextobj, 0, json_plugin_version, json_list); - FREE(node_obj); break; } diff --git a/libbbfdm-api/dmcommon.c b/libbbfdm-api/dmcommon.c index 55485cb3..2bcff5b8 100644 --- a/libbbfdm-api/dmcommon.c +++ b/libbbfdm-api/dmcommon.c @@ -2062,44 +2062,93 @@ char *replace_char(char *str, char find, char replace) return str; } -char *replace_str(const char *str, const char *substr, const char *replacement) +/** + * Replace all occurrences of a substring in a given string with another substring. + * + * @param input_str The input string where replacements will be performed. + * @param old_substr The substring to be replaced. + * @param new_substr The substring to replace `old_substr`. + * @param result_str The buffer to store the result. If NULL, memory will be allocated. + * @param buffer_len The length of the buffer. If `result_str` is not NULL, this should be the size of the buffer. + * @return A pointer to the result string. If `result_str` is provided, it will point to `result_str`, otherwise, it will be dynamically allocated. + */ +char *replace_str(const char *input_str, const char *old_substr, const char *new_substr, char *result_str, size_t buffer_len) { - if (!str || !substr || !replacement) + if (result_str && buffer_len > 0) + result_str[0] = 0; + + if (!input_str || !old_substr || !new_substr || (result_str && buffer_len == 0)) return NULL; - int str_len = strlen(str); - int substr_len = strlen(substr); - int replacement_len = strlen(replacement); - int cnt = 0; + size_t input_str_len = strlen(input_str); + size_t old_substr_len = strlen(old_substr); + size_t new_substr_len = strlen(new_substr); + size_t occurrences = 0; - if (str_len == 0) - return strdup(""); - - if (substr_len == 0) - return strdup(str); - - for (int i = 0; str[i] != '\0'; i++) { - if (DM_STRSTR(&str[i], substr) == &str[i]) { - cnt++; - i += substr_len - 1; + if (input_str_len == 0) { + // Handle case where the input string is empty + if (result_str && buffer_len > 0) { + return result_str; + } else { + return strdup(""); } } - size_t new_str_len = str_len + cnt * (replacement_len - substr_len) + 1; - char *value = (char *)malloc(new_str_len * sizeof(char)); - - int i = 0; - while (*str) { - if (strstr(str, substr) == str) { - i += snprintf(&value[i], new_str_len - i, "%s", replacement); - str += substr_len; + if (old_substr_len == 0) { + // Handle case where the input substring is empty + if (result_str && buffer_len > 0) { + snprintf(result_str, buffer_len, "%s", input_str); + return result_str; + } else { + return strdup(input_str); } - else - value[i++] = *str++; } - value[i] = '\0'; - return value; + // Count occurrences of old_substr in input_str + for (size_t i = 0; input_str[i] != '\0'; i++) { + if (strstr(&input_str[i], old_substr) == &input_str[i]) { + occurrences++; + i += old_substr_len; + } + } + + size_t new_str_len = input_str_len + occurrences * (new_substr_len - old_substr_len) + 1; + + if (result_str && buffer_len > 0 && new_str_len > buffer_len) { + // Buffer size is too small + return NULL; + } + + // Allocate memory only if result_str is not provided + char *result = result_str ? result_str : (char *)malloc(new_str_len * sizeof(char)); + + if (!result) { + // Memory allocation failed + return NULL; + } + + size_t i = 0; + while (*input_str) { + char *match = strstr(input_str, old_substr); + if (match == input_str) { + // Replace old_substr with new_substr + strncpy(&result[i], new_substr, new_substr_len); + i += new_substr_len; + input_str += old_substr_len; + } else if (match) { + // Copy characters from input_str to result until the match + size_t len = match - input_str; + strncpy(&result[i], input_str, len); + i += len; + input_str += len; + } else { + // No more occurrences, copy the remaining characters + result[i++] = *input_str++; + } + } + result[i] = '\0'; + + return result; } void strip_lead_trail_whitespace(char *str) diff --git a/libbbfdm-api/dmcommon.h b/libbbfdm-api/dmcommon.h index bab04c8d..5b5976d4 100644 --- a/libbbfdm-api/dmcommon.h +++ b/libbbfdm-api/dmcommon.h @@ -322,7 +322,7 @@ bool is_regular_file(const char *path); unsigned long file_system_size(const char *path, const enum fs_size_type_enum type); void remove_char(char *str, const char c); char *replace_char(char *str, char find, char replace); -char *replace_str(const char *str, const char *substr, const char *replacement); +char *replace_str(const char *input_str, const char *old_substr, const char *new_substr, char *result_str, size_t buffer_len); int dm_file_to_buf(const char *filename, void *buf, size_t buf_size); int dm_file_copy(char *src, char *dst); int check_browse_section(struct uci_section *s, void *data); diff --git a/libbbfdm-api/dmplugin.c b/libbbfdm-api/dmplugin.c index 55001776..c5e4dd48 100644 --- a/libbbfdm-api/dmplugin.c +++ b/libbbfdm-api/dmplugin.c @@ -320,12 +320,12 @@ DMOBJ *find_entry_obj(DMOBJ *entryobj, char *obj_path) DMNODE node = {.current_object = ""}; DMOBJ *obj = NULL; - char *in_obj = replace_str(obj_path, ".{i}.", "."); - if (in_obj == NULL) + char in_obj[1024] = {0}; + replace_str(obj_path, ".{i}.", ".", in_obj, sizeof(in_obj)); + if (strlen(in_obj) == 0) return NULL; dm_check_dynamic_obj(&node, entryobj, in_obj, &obj); - FREE(in_obj); return obj; } diff --git a/libbbfdm-api/plugin/json_plugin.c b/libbbfdm-api/plugin/json_plugin.c index 955a11ec..bdd33cf9 100644 --- a/libbbfdm-api/plugin/json_plugin.c +++ b/libbbfdm-api/plugin/json_plugin.c @@ -114,14 +114,15 @@ static void free_loaded_json_files(struct list_head *json_list) void json_plugin_find_prefix_obj(const char *full_obj, char *prefix_obj, size_t len) { int last_occurent = 0, occur = 0; + char full_object[MAX_DM_LENGTH] = {0}; if (!full_obj || !prefix_obj || len == 0) return; *prefix_obj = 0; - char *full_object = replace_str(full_obj, ".{i}.", "."); - if (full_object == NULL) + replace_str(full_obj, ".{i}.", ".", full_object, sizeof(full_object)); + if (strlen(full_object) == 0) return; unsigned int full_object_dot_num = count_occurrences(full_object, '.'); @@ -138,20 +139,20 @@ void json_plugin_find_prefix_obj(const char *full_obj, char *prefix_obj, size_t *(full_object + last_occurent + 1) = 0; snprintf(prefix_obj, len, "%s", full_object); - FREE(full_object); } static void json_plugin_find_current_obj(const char *full_obj, char *curr_obj, size_t len) { int last_occurent = 0, occur = 0; + char full_object[MAX_DM_LENGTH] = {0}; if (!full_obj || !curr_obj || len == 0) return; *curr_obj = 0; - char *full_object = replace_str(full_obj, ".{i}.", "."); - if (full_object == NULL) + replace_str(full_obj, ".{i}.", ".", full_object, sizeof(full_object)); + if (strlen(full_object) == 0) return; unsigned int full_object_dot_num = count_occurrences(full_object, '.'); @@ -168,7 +169,6 @@ static void json_plugin_find_current_obj(const char *full_obj, char *curr_obj, s full_object[occur] = 0; snprintf(curr_obj, len, "%s", full_object + last_occurent + 1); - FREE(full_object); } static void generate_path_without_instance(char *full_obj, bool is_obj, char *obj_path, size_t len) @@ -688,7 +688,7 @@ static char *uci_get_value(json_object *mapping_obj, int json_version, char *ref if (linker_jobj) { char *link = json_object_get_string(linker_jobj); - linker = replace_str(link, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX); + linker = replace_str(link, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX, NULL, 0); } if (file && type && opt_temp && strstr(refparam, "NumberOfEntries")) { @@ -1600,7 +1600,8 @@ static void parse_param(char *object, char *param, json_object *jobj, DMLEAF *pl { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type(6)*/ struct json_object *type = NULL, *protocols = NULL, *write = NULL, *async = NULL, *flags = NULL; - char full_param[512] = {0}; + char full_param[1024] = {0}; + char param_ext[256] = {0}; size_t n_flags; // cppcheck-suppress nullPointerRedundantCheck char **in_p = NULL, **out_p = NULL, **ev_arg = NULL, **tmp = NULL; @@ -1608,8 +1609,8 @@ static void parse_param(char *object, char *param, json_object *jobj, DMLEAF *pl if (!jobj || !pleaf) return; - char *param_ext = replace_str(param, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX); - if (!param_ext) + replace_str(param, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX, param_ext, sizeof(param_ext)); + if (strlen(param_ext) == 0) return; //PARAM @@ -1739,7 +1740,6 @@ static void parse_param(char *object, char *param, json_object *jobj, DMLEAF *pl } snprintf(full_param, sizeof(full_param), "%s%s", object, param_ext); - FREE(param_ext); save_json_data(list, full_param, jobj, json_version, (const char**)in_p, (const char**)out_p, (const char**)ev_arg); } @@ -1768,22 +1768,21 @@ void parse_obj(char *object, json_object *jobj, DMOBJ *pobj, int index, int json DMOBJ *next_obj = NULL; DMLEAF *next_leaf = NULL; char **keys_p = NULL; - char curr_obj[128] = {0}; count_obj_param_under_jsonobj(jobj, &obj_number, ¶m_number); - char *obj_path = replace_str(object, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX); - if (!obj_path) + char obj_path[MAX_DM_LENGTH] = {0}; + replace_str(object, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX, obj_path, sizeof(obj_path)); + if (strlen(obj_path) == 0) return; - char *full_obj = replace_str(obj_path, ".{i}.", "."); - if (!full_obj) { - FREE(obj_path); + char full_obj[MAX_DM_LENGTH] = {0}; + replace_str(obj_path, ".{i}.", ".", full_obj, sizeof(full_obj)); + if (strlen(full_obj) == 0) return; - } - json_plugin_find_current_obj(full_obj, curr_obj, sizeof(curr_obj)); - FREE(obj_path); + char curr_obj[256] = {0}; + json_plugin_find_current_obj(full_obj, curr_obj, sizeof(curr_obj));; if (!pobj || strlen(curr_obj) == 0) return; @@ -1862,8 +1861,6 @@ void parse_obj(char *object, json_object *jobj, DMOBJ *pobj, int index, int json i++; } } - - FREE(full_obj); } int load_json_plugins(DMOBJ *entryobj, const char *plugin_path) @@ -1877,21 +1874,21 @@ int load_json_plugins(DMOBJ *entryobj, const char *plugin_path) } json_object_object_foreach(json, key, jobj) { + char obj_path[MAX_DM_LENGTH] = {0}; if (strcmp(key, "json_plugin_version") == 0) { json_plugin_version = json_object_get_int(jobj); continue; } - char *obj_path = replace_str(key, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX); - if (obj_path == NULL) { + replace_str(key, "{BBF_VENDOR_PREFIX}", BBF_VENDOR_PREFIX, obj_path, sizeof(obj_path)); + if (strlen(obj_path) == 0) { BBF_DEBUG("ERROR: Can't get the node object"); continue; } if (strncmp(obj_path, "Device.", strlen("Device.")) != 0 || obj_path[strlen(obj_path) - 1] != '.') { BBF_DEBUG("ERROR: Object (%s) not valid", obj_path); - FREE(obj_path); continue; } @@ -1899,7 +1896,6 @@ int load_json_plugins(DMOBJ *entryobj, const char *plugin_path) json_plugin_find_prefix_obj(obj_path, obj_prefix, MAX_DM_LENGTH); if (strlen(obj_prefix) == 0) { BBF_DEBUG("ERROR: Obj prefix is empty for (%s) Object", obj_path); - FREE(obj_path); continue; } @@ -1907,14 +1903,12 @@ int load_json_plugins(DMOBJ *entryobj, const char *plugin_path) json_plugin_find_current_obj(obj_path, curr_obj, sizeof(curr_obj)); if (strlen(curr_obj) == 0) { BBF_DEBUG("ERROR: Can't get the current object from (%s) parent object", obj_path); - FREE(obj_path); continue; } DMOBJ *dm_entryobj = find_entry_obj(entryobj, obj_prefix); if (!dm_entryobj) { BBF_DEBUG("ERROR: entry obj doesn't exist for (%s) Object", obj_prefix); - FREE(obj_path); continue; } @@ -1940,8 +1934,6 @@ int load_json_plugins(DMOBJ *entryobj, const char *plugin_path) memset(dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0] + (idx + 1), 0, sizeof(struct dm_obj_s)); parse_obj(obj_path, jobj, dm_entryobj->nextdynamicobj[INDX_JSON_MOUNT].nextobj[0], idx, json_plugin_version, &json_list); } - - FREE(obj_path); } save_loaded_json_files(&loaded_json_files, json); diff --git a/test/cmocka/functional_api_test_bbfd.c b/test/cmocka/functional_api_test_bbfd.c index 8568060e..db82fade 100644 --- a/test/cmocka/functional_api_test_bbfd.c +++ b/test/cmocka/functional_api_test_bbfd.c @@ -964,13 +964,13 @@ static void test_bbf_api_common(void **state) // replace_str: test DM_STRNCPY(buf, "Device.IEEE1905.AL.NetworkTopology.IEEE1905Device.{i}.IPv4Address.{i}.", sizeof(buf)); - value = replace_str(buf, ".{i}.", "."); + value = replace_str(buf, ".{i}.", ".", NULL, 0); assert_string_equal(value, "Device.IEEE1905.AL.NetworkTopology.IEEE1905Device.IPv4Address."); FREE(value); // replace_str: test DM_STRNCPY(buf, "Device.IEEE1905.AL.NetworkTopology.IEEE1905Device.{i}.IPv4Address.{i}.", sizeof(buf)); - value = replace_str(buf, ".{i}.", ".*."); + value = replace_str(buf, ".{i}.", ".*.", NULL, 0); assert_string_equal(value, "Device.IEEE1905.AL.NetworkTopology.IEEE1905Device.*.IPv4Address.*."); FREE(value);