bool unsafe_yyjson_mut_ptr_putx()

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;
}