in include/yyjson/yyjson.c [2144:2281]
bool unsafe_yyjson_mut_ptr_putx(yyjson_mut_val *val,
const char *ptr, size_t ptr_len,
yyjson_mut_val *new_val,
yyjson_mut_doc *doc,
bool create_parent, bool insert_new,
yyjson_ptr_ctx *ctx,
yyjson_ptr_err *err) {
const char *hdr = ptr, *end = ptr + ptr_len, *token;
usize token_len, esc, ctn_len;
yyjson_mut_val *ctn, *key, *pre = NULL;
yyjson_mut_val *sep_ctn = NULL, *sep_key = NULL, *sep_val = NULL;
yyjson_type ctn_type;
bool idx_is_last = false;
/* skip exist parent nodes */
while (true) {
token = ptr_next_token(&ptr, end, &token_len, &esc);
if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
ctn = val;
ctn_type = unsafe_yyjson_get_type(ctn);
if (ctn_type == YYJSON_TYPE_OBJ) {
val = ptr_mut_obj_get(ctn, token, token_len, esc, &pre);
} else if (ctn_type == YYJSON_TYPE_ARR) {
val = ptr_mut_arr_get(ctn, token, token_len, esc, &pre,
&idx_is_last);
} else return_err_resolve(false, token - hdr);
if (!val) break;
if (ptr == end) break; /* is last token */
}
/* create parent nodes if not exist */
if (unlikely(ptr != end)) { /* not last token */
if (!create_parent) return_err_resolve(false, token - hdr);
/* add value at last index if container is array */
if (ctn_type == YYJSON_TYPE_ARR) {
if (!idx_is_last || !insert_new) {
return_err_resolve(false, token - hdr);
}
val = yyjson_mut_obj(doc);
if (!val) return_err_alloc(false);
/* delay attaching until all operations are completed */
sep_ctn = ctn;
sep_key = NULL;
sep_val = val;
/* move to next token */
ctn = val;
val = NULL;
ctn_type = YYJSON_TYPE_OBJ;
token = ptr_next_token(&ptr, end, &token_len, &esc);
if (unlikely(!token)) return_err_resolve(false, token - hdr);
}
/* container is object, create parent nodes */
while (ptr != end) { /* not last token */
key = ptr_new_key(token, token_len, esc, doc);
if (!key) return_err_alloc(false);
val = yyjson_mut_obj(doc);
if (!val) return_err_alloc(false);
/* delay attaching until all operations are completed */
if (!sep_ctn) {
sep_ctn = ctn;
sep_key = key;
sep_val = val;
} else {
yyjson_mut_obj_add(ctn, key, val);
}
/* move to next token */
ctn = val;
val = NULL;
token = ptr_next_token(&ptr, end, &token_len, &esc);
if (unlikely(!token)) return_err_syntax(false, ptr - hdr);
}
}
/* JSON pointer is resolved, insert or replace target value */
ctn_len = unsafe_yyjson_get_len(ctn);
if (ctn_type == YYJSON_TYPE_OBJ) {
if (ctx) ctx->ctn = ctn;
if (!val || insert_new) {
/* insert new key-value pair */
key = ptr_new_key(token, token_len, esc, doc);
if (unlikely(!key)) return_err_alloc(false);
if (ctx) ctx->pre = ctn_len ? (yyjson_mut_val *)ctn->uni.ptr : key;
unsafe_yyjson_mut_obj_add(ctn, key, new_val, ctn_len);
} else {
/* replace exist value */
key = pre->next->next;
if (ctx) ctx->pre = pre;
if (ctx) ctx->old = val;
yyjson_mut_obj_put(ctn, key, new_val);
}
} else {
/* array */
if (ctx && (val || idx_is_last)) ctx->ctn = ctn;
if (insert_new) {
/* append new value */
if (val) {
pre->next = new_val;
new_val->next = val;
if (ctx) ctx->pre = pre;
unsafe_yyjson_set_len(ctn, ctn_len + 1);
} else if (idx_is_last) {
if (ctx) ctx->pre = ctn_len ?
(yyjson_mut_val *)ctn->uni.ptr : new_val;
yyjson_mut_arr_append(ctn, new_val);
} else {
return_err_resolve(false, token - hdr);
}
} else {
/* replace exist value */
if (!val) return_err_resolve(false, token - hdr);
if (ctn_len > 1) {
new_val->next = val->next;
pre->next = new_val;
if (ctn->uni.ptr == val) ctn->uni.ptr = new_val;
} else {
new_val->next = new_val;
ctn->uni.ptr = new_val;
pre = new_val;
}
if (ctx) ctx->pre = pre;
if (ctx) ctx->old = val;
}
}
/* all operations are completed, attach the new components to the target */
if (unlikely(sep_ctn)) {
if (sep_key) yyjson_mut_obj_add(sep_ctn, sep_key, sep_val);
else yyjson_mut_arr_append(sep_ctn, sep_val);
}
return true;
}