json_setf doesn's works as expected!
Anricx opened this issue · 3 comments
Anricx commented
char *payload = "{\"a\":1}";
struct json_out out = JSON_OUT_BUF(output, output_len);
json_setf(input, input_len, &out, ".sign", "%Q", "5738263BEFF11EC874D99623AC22A3B1");
output:
{"a":1,"sign":"5738263BEFF11EC874D99623AC22A3B1"}
Works grate
char *payload = "{\"service\":\"service.parking.detail\",\"a\":1}";
struct json_out out = JSON_OUT_BUF(output, output_len);
json_setf(input, input_len, &out, ".sign", "%Q", "5738263BEFF11EC874D99623AC22A3B1");
outpu:
{"service":"service.parking.detail","a":1,"59DEE02F6A5CBA08F66FA862BF88EF76"}
Not Working!
cpq commented
PR please :)
zdila commented
In my case input JSON is {"ignore": "me"}
(because of #26) and I am calling char *json = "{\"ignore\": \"me\"}"; json_setf(json, strlen(json), &out, ".foo", "{from: %ld, to: %ld, energy: %ld}", rec_start_ts, rec_finish_ts, rec_energy)
.
The result is: {"ignore": "me,"foo":{"from": 1587467683, "to": 1587558755, "energy":
59}"}
rtrue983 commented
I have a fix for this (at least with how I was using it) but don't have the time ATM to do a PR...
Here are the two functions that need to be modified:
static void json_vsetf_cb(void *userdata, const char *name, size_t name_len,
const char *path, const struct json_token *t) {
struct json_setf_data *data = (struct json_setf_data *) userdata;
int off, len = get_matched_prefix_len(path, data->json_path);
int matched = 0;
if (t->ptr == NULL) return;
off = t->ptr - data->base;
// only check matched later on if deliminator or end are found
if (len > data->matched &&
(data->json_path[len] == '.' || data->json_path[len] == '\0')) {
matched = len;
}
/*
* If there is no exact path match, set the mutation position to be end
* of the object or array
*/
if (matched > data->matched && data->pos == 0 &&
(t->type == JSON_TYPE_OBJECT_END || t->type == JSON_TYPE_ARRAY_END))
{
// only save off matched value if it is a new and larger match
data->matched = matched;
// account for a the previous item being a string
if (data->base[data->prev] == '"') {
data->pos = data->end = data->prev + 1;
}
else {
data->pos = data->end = data->prev;
}
}
/* Exact path match. Set mutation position to the value of this token */
if (strcmp(path, data->json_path) == 0 && t->type != JSON_TYPE_OBJECT_START &&
t->type != JSON_TYPE_ARRAY_START) {
// need to set pos and end differently to account for '"' around string
if (t->type == JSON_TYPE_TRUE || t->type == JSON_TYPE_FALSE || t->type == JSON_TYPE_NUMBER) {
data->pos = off;
data->end = off + t->len + 1;
}
else {
data->pos = off - 1;
data->end = off + t->len + 2;
}
data->matched = matched;
}
/*
* For deletion, we need to know where the previous value ends, because
* we don't know where matched value key starts.
* When the mutation position is not yet set, remember each value end.
* When the mutation position is already set, but it is at the beginning
* of the object/array, we catch the end of the object/array and see
* whether the object/array start is closer then previously stored prev.
*/
if (data->pos == 0) {
data->prev = off + t->len; /* pos is not yet set */
} else if ((t->ptr[0] == '[' || t->ptr[0] == '{') && off + 1 < data->pos &&
off + 1 > data->prev) {
data->prev = off + 1;
}
(void) name;
(void) name_len;
}
int json_vsetf(const char *s, int len, struct json_out *out,
const char *json_path, const char *json_fmt, va_list ap) WEAK;
int json_vsetf(const char *s, int len, struct json_out *out,
const char *json_path, const char *json_fmt, va_list ap) {
struct json_setf_data data;
memset(&data, 0, sizeof(data));
data.json_path = json_path;
data.base = s;
data.end = len;
json_walk(s, len, json_vsetf_cb, &data);
if (json_fmt == NULL) {
/* Deletion codepath */
json_printf(out, "%.*s", data.prev, s);
/* Trim comma after the value that begins at object/array start */
if (s[data.prev - 1] == '{' || s[data.prev - 1] == '[') {
int i = data.end;
while (i < len && json_isspace(s[i])) i++;
if (s[i] == ',') data.end = i + 1; /* Point after comma */
}
json_printf(out, "%.*s", len - data.end, s + data.end);
} else {
/* Modification codepath */
int n, off = data.matched+1, depth = 0;
bool empty_base = false;
// if a partial or exact match isn't found, adjust a few items
if (data.matched == 0 && data.pos == 0) {
data.pos = data.prev - 1;
data.end--;
// a completely empty base requres additional correction
if (data.base[0] == '{' && data.base[1] == '}') {
empty_base = true;
data.pos = 1;
data.prev = 1;
data.end = 1;
}
}
/* Print the unchanged beginning */
json_printf(out, "%.*s", data.pos, s);
/* Add missing keys */
while ((n = strcspn(&json_path[off], ".[")) > 0) {
// don't add a comma if it is a completely empty base
if (s[data.prev - 1] != '{' && s[data.prev - 1] != '[' && depth == 0 && !empty_base) {
json_printf(out, ",");
}
if (off > 0 && json_path[off - 1] != '.') break;
json_printf(out, "%.*Q:", n, json_path + off);
off += n;
if (json_path[off] != '\0') {
json_printf(out, "%c", json_path[off] == '.' ? '{' : '[');
depth++;
off++;
}
}
/* Print the new value */
json_vprintf(out, json_fmt, ap);
/* Close brackets/braces of the added missing keys */
for (; off > data.matched; off--) {
int ch = json_path[off];
const char *p = ch == '.' ? "}" : ch == '[' ? "]" : "";
json_printf(out, "%s", p);
}
/* Print the rest of the unchanged string */
json_printf(out, "%.*s", len - data.end, s + data.end);
}
return data.end > data.pos ? 1 : 0;
}