json_t *bunser(const char *buf, const char *end, int *needed, json_error_t *jerr) { json_int_t ival; switch (buf[0]) { case BSER_INT8: case BSER_INT16: case BSER_INT32: case BSER_INT64: if (!bunser_int(buf, end - buf, needed, &ival)) { snprintf(jerr->text, sizeof(jerr->text), "invalid integer encoding"); return NULL; } return json_integer(ival); case BSER_STRING: { const char *start; json_int_t len; if (!bunser_string(buf, end - buf, needed, &start, &len)) { snprintf(jerr->text, sizeof(jerr->text), "invalid string encoding"); return NULL; } return json_string_binary(start, len); } case BSER_REAL: *needed = sizeof(double) + 1; return json_real(*(double*)(buf+1)); case BSER_TRUE: *needed = 1; return json_true(); case BSER_FALSE: *needed = 1; return json_false(); case BSER_NULL: *needed = 1; return json_null(); case BSER_ARRAY: return bunser_array(buf, end, needed, jerr); case BSER_TEMPLATE: return bunser_template(buf, end, needed, jerr); case BSER_OBJECT: return bunser_object(buf, end, needed, jerr); default: snprintf(jerr->text, sizeof(jerr->text), "invalid bser encoding type %02x", (int)buf[0]); return NULL; } return NULL; }
static json_t *bunser_array(const char *buf, const char *end, json_int_t *used, json_error_t *jerr) { json_int_t needed; json_int_t total = 0; json_int_t i, nelems; json_t *arrval; buf++; total++; if (!bunser_int(buf, end - buf, &needed, &nelems)) { if (needed == -1) { snprintf(jerr->text, sizeof(jerr->text), "invalid integer encoding 0x%02x for array length. buf=%p\n", (int)buf[0], buf); return NULL; } *used = needed + total; snprintf(jerr->text, sizeof(jerr->text), "invalid array length encoding 0x%02x (needed %d but have %d)", (int)buf[0], (int)needed, (int)(end - buf)); return NULL; } total += needed; buf += needed; arrval = json_array(); for (i = 0; i < nelems; i++) { json_t *item; needed = 0; item = bunser(buf, end, &needed, jerr); total += needed; buf += needed; if (!item) { json_decref(arrval); *used = total; return NULL; } if (json_array_append_new(arrval, item)) { json_decref(arrval); *used = total; snprintf(jerr->text, sizeof(jerr->text), "failed to append array item"); return NULL; } } *used = total; return arrval; }
bool w_bser_decode_pdu_info(w_jbuffer_t *jr, w_stm_t stm, uint32_t bser_version, json_int_t *len, json_int_t *bser_capabilities, json_error_t *jerr) { json_int_t needed; if (bser_version == 2) { while (!bunser_int(jr->buf + jr->rpos, jr->wpos - jr->rpos, &needed, bser_capabilities)) { if (needed == -1) { snprintf(jerr->text, sizeof(jerr->text), "failed to read BSER capabilities"); return false; } if (!fill_buffer(jr, stm)) { snprintf(jerr->text, sizeof(jerr->text), "unable to fill buffer"); return false; } } jr->rpos += (uint32_t)needed; } while (!bunser_int(jr->buf + jr->rpos, jr->wpos - jr->rpos, &needed, len)) { if (needed == -1) { snprintf(jerr->text, sizeof(jerr->text), "failed to read PDU size"); return false; } if (!fill_buffer(jr, stm)) { snprintf(jerr->text, sizeof(jerr->text), "unable to fill buffer"); return false; } } jr->rpos += (uint32_t)needed; return true; }
bool bunser_bytestring(const char *buf, json_int_t avail, json_int_t *needed, const char **start, json_int_t *len) { json_int_t ineed; if (!bunser_int(buf + 1, avail - 1, &ineed, len)) { *needed = ineed; return false; } buf += ineed + 1; avail -= ineed + 1; *needed = ineed + 1 + *len; if (*len > avail) { return false; } *start = buf; return true; }
bool w_bser_decode_pdu_len(w_jbuffer_t *jr, w_stm_t stm, json_int_t *len, json_error_t *jerr) { json_int_t needed; while (!bunser_int(jr->buf + jr->rpos, jr->wpos - jr->rpos, &needed, len)) { if (needed == -1) { snprintf(jerr->text, sizeof(jerr->text), "failed to read PDU size"); return false; } if (!fill_buffer(jr, stm)) { snprintf(jerr->text, sizeof(jerr->text), "unable to fill buffer"); return false; } } jr->rpos += (uint32_t)needed; return true; }
json_t *bunser(const char *buf, const char *end, json_int_t *needed, json_error_t *jerr) { json_int_t ival; switch (buf[0]) { case BSER_INT8: case BSER_INT16: case BSER_INT32: case BSER_INT64: if (!bunser_int(buf, end - buf, needed, &ival)) { snprintf(jerr->text, sizeof(jerr->text), "invalid integer encoding"); return NULL; } return json_integer(ival); case BSER_BYTESTRING: { const char *start; json_int_t len; if (!bunser_bytestring(buf, end - buf, needed, &start, &len)) { snprintf(jerr->text, sizeof(jerr->text), "invalid bytestring encoding"); return NULL; } return json_stringn_nocheck(start, len); } case BSER_REAL: { double dval; *needed = sizeof(double) + 1; memcpy(&dval, buf + 1, sizeof(dval)); return json_real(dval); } case BSER_TRUE: *needed = 1; return json_true(); case BSER_FALSE: *needed = 1; return json_false(); case BSER_NULL: *needed = 1; return json_null(); case BSER_ARRAY: return bunser_array(buf, end, needed, jerr); case BSER_TEMPLATE: return bunser_template(buf, end, needed, jerr); case BSER_OBJECT: return bunser_object(buf, end, needed, jerr); default: snprintf(jerr->text, sizeof(jerr->text), "invalid bser encoding type %02x", (int)buf[0]); return NULL; } #ifndef _WIN32 // It knows this is unreachable return NULL; #endif }
static json_t *bunser_object(const char *buf, const char *end, json_int_t *used, json_error_t *jerr) { json_int_t needed; json_int_t total = 0; json_int_t i, nelems; json_t *objval; char keybuf[128]; total = 1; buf++; if (!bunser_int(buf, end - buf, &needed, &nelems)) { *used = needed + total; snprintf(jerr->text, sizeof(jerr->text), "invalid object property count encoding"); return NULL; } total += needed; buf += needed; objval = json_object(); for (i = 0; i < nelems; i++) { const char *start; json_int_t slen; json_t *item; // Read key if (!bunser_bytestring(buf, end - buf, &needed, &start, &slen)) { *used = total + needed; json_decref(objval); snprintf(jerr->text, sizeof(jerr->text), "invalid bytestring for object key"); return NULL; } total += needed; buf += needed; // Saves us allocating a string when the library is going to // do that anyway if ((uint16_t)slen > sizeof(keybuf) - 1) { json_decref(objval); snprintf(jerr->text, sizeof(jerr->text), "object key is too long"); return NULL; } memcpy(keybuf, start, (size_t)slen); keybuf[slen] = '\0'; // Read value item = bunser(buf, end, &needed, jerr); total += needed; buf += needed; if (!item) { json_decref(objval); *used = total; return NULL; } if (json_object_set_new_nocheck(objval, keybuf, item)) { json_decref(item); json_decref(objval); *used = total; snprintf(jerr->text, sizeof(jerr->text), "failed to add object property"); return NULL; } } *used = total; return objval; }
static json_t *bunser_template(const char *buf, const char *end, json_int_t *used, json_error_t *jerr) { json_int_t needed = 0; json_int_t total = 0; json_int_t i, nelems; json_int_t ip, np; json_t *templ = NULL, *arrval, *ret = NULL; buf++; total++; if (*buf != BSER_ARRAY) { snprintf(jerr->text, sizeof(jerr->text), "Expected array encoding, but found 0x%02x", *buf); *used = total; return NULL; } // Load in the property names template templ = bunser_array(buf, end, &needed, jerr); if (!templ) { *used = needed + total; goto bail; } total += needed; buf += needed; // And the number of objects needed = 0; if (!bunser_int(buf, end - buf, &needed, &nelems)) { *used = needed + total; snprintf(jerr->text, sizeof(jerr->text), "invalid object number encoding (needed %d but have %d)", (int)needed, (int)(end - buf)); goto bail; } total += needed; buf += needed; np = json_array_size(templ); // Now load up the array with object values arrval = json_array_of_size((size_t)nelems); for (i = 0; i < nelems; i++) { json_t *item, *val; item = json_object_of_size((size_t)np); for (ip = 0; ip < np; ip++) { if (*buf == BSER_SKIP) { buf++; total++; continue; } needed = 0; val = bunser(buf, end, &needed, jerr); if (!val) { *used = needed + total; goto bail; } buf += needed; total += needed; json_object_set_new_nocheck(item, json_string_value(json_array_get(templ, (size_t)ip)), val); } json_array_append_new(arrval, item); } *used = total; ret = arrval; bail: json_decref(templ); return ret; }