// Reads MessagePack bin bytes and outputs a JSON base64 string static bool base64_bin(mpack_reader_t* reader, yajl_gen gen, options_t* options, uint32_t len, bool prefix) { uint32_t new_len = base64_len(len) + (prefix ? strlen(b64_str) : 0); char* output = (char*)malloc(new_len); bool ret = base64(reader, gen, options, len, output, output, prefix); mpack_done_bin(reader); free(output); return ret; }
char* mpack_expect_bin_alloc(mpack_reader_t* reader, size_t maxsize, size_t* size) { *size = 0; if (maxsize > UINT32_MAX) maxsize = UINT32_MAX; size_t length = mpack_expect_bin_max(reader, (uint32_t)maxsize); char* data = mpack_read_bytes_alloc(reader, length); mpack_done_bin(reader); if (data) *size = length; return data; }
size_t mpack_expect_bin_buf(mpack_reader_t* reader, char* buf, size_t bufsize) { size_t binsize = mpack_expect_bin(reader); if (mpack_reader_error(reader)) return 0; if (binsize > bufsize) { mpack_reader_flag_error(reader, mpack_error_too_big); return 0; } mpack_read_bytes(reader, buf, binsize); if (mpack_reader_error(reader)) return 0; mpack_done_bin(reader); return binsize; }
void mpack_discard(mpack_reader_t* reader) { mpack_tag_t var = mpack_read_tag(reader); if (mpack_reader_error(reader)) return; switch (var.type) { case mpack_type_str: mpack_skip_bytes(reader, var.v.l); mpack_done_str(reader); break; case mpack_type_bin: mpack_skip_bytes(reader, var.v.l); mpack_done_bin(reader); break; case mpack_type_ext: mpack_skip_bytes(reader, var.v.l); mpack_done_ext(reader); break; case mpack_type_array: { for (; var.v.n > 0; --var.v.n) { mpack_discard(reader); if (mpack_reader_error(reader)) break; } mpack_done_array(reader); break; } case mpack_type_map: { for (; var.v.n > 0; --var.v.n) { mpack_discard(reader); mpack_discard(reader); if (mpack_reader_error(reader)) break; } mpack_done_map(reader); break; } default: break; } }
static bool element(mpack_reader_t* reader, yajl_gen gen, options_t* options, int depth) { const mpack_tag_t tag = mpack_read_tag(reader); if (mpack_reader_error(reader) != mpack_ok) return false; if (!options->debug && depth == 0 && (tag.type != mpack_type_map && tag.type != mpack_type_array)) { fprintf(stderr, "%s: Top-level object must be a map or array. Try debug viewing mode (-d)\n", options->command); return false; } // TODO check not depth zero switch (tag.type) { case mpack_type_bool: return yajl_gen_bool(gen, tag.v.b) == yajl_gen_status_ok; case mpack_type_nil: return yajl_gen_null(gen) == yajl_gen_status_ok; case mpack_type_int: return yajl_gen_integer(gen, tag.v.i) == yajl_gen_status_ok; case mpack_type_float: return yajl_gen_double(gen, tag.v.f) == yajl_gen_status_ok; case mpack_type_double: return yajl_gen_double(gen, tag.v.d) == yajl_gen_status_ok; case mpack_type_uint: if (tag.v.u > (uint64_t)INT64_MAX) { char buf[32]; snprintf(buf, sizeof(buf), "%" PRIu64, tag.v.u); return yajl_gen_string(gen, (const unsigned char*)buf, strlen(buf)) == yajl_gen_status_ok; } return yajl_gen_integer(gen, (int64_t)tag.v.u) == yajl_gen_status_ok; case mpack_type_str: return string(reader, gen, options, tag.v.l); case mpack_type_bin: if (options->base64) { return base64_bin(reader, gen, options, tag.v.l, options->base64_prefix); } else if (options->debug) { mpack_skip_bytes(reader, tag.v.l); mpack_done_bin(reader); // output nothing to allow us to print our debug string skip_quotes = true; if (yajl_gen_string(gen, (const unsigned char*)"", 0) != yajl_gen_status_ok) return false; skip_quotes = false; char buf[64]; snprintf(buf, sizeof(buf), "<bin of size %u>", tag.v.l); print(out_file, buf, strlen(buf)); return true; } else { fprintf(stderr, "%s: bin unencodable in JSON. Try debug viewing mode (-d)\n", options->command); return false; } case mpack_type_ext: if (options->base64) { return base64_ext(reader, gen, options, tag.exttype, tag.v.l); } else if (options->debug) { mpack_skip_bytes(reader, tag.v.l); mpack_done_ext(reader); // output nothing to allow us to print our debug string skip_quotes = true; if (yajl_gen_string(gen, (const unsigned char*)"", 0) != yajl_gen_status_ok) return false; skip_quotes = false; char buf[64]; snprintf(buf, sizeof(buf), "<ext of type %i size %u>", tag.exttype, tag.v.l); print(out_file, buf, strlen(buf)); return true; } else { fprintf(stderr, "%s: ext type %i unencodable in JSON. Try debug viewing mode (-d)\n", options->command, tag.exttype); return false; } case mpack_type_array: if (yajl_gen_array_open(gen) != yajl_gen_status_ok) return false; for (size_t i = 0; i < tag.v.l; ++i) if (!element(reader, gen, options, depth + 1)) return false; mpack_done_array(reader); return yajl_gen_array_close(gen) == yajl_gen_status_ok; case mpack_type_map: if (yajl_gen_map_open(gen) != yajl_gen_status_ok) return false; for (size_t i = 0; i < tag.v.l; ++i) { if (options->debug) { element(reader, gen, options, depth + 1); } else { uint32_t len = mpack_expect_str(reader); if (mpack_reader_error(reader) != mpack_ok) { fprintf(stderr, "%s: map key is not a string. Try debug viewing mode (-d)\n", options->command); return false; } if (!string(reader, gen, options, len)) return false; } if (!element(reader, gen, options, depth + 1)) return false; } mpack_done_map(reader); return yajl_gen_map_close(gen) == yajl_gen_status_ok; } return true; }
static void mpack_print_element(mpack_reader_t* reader, size_t depth, FILE* file) { mpack_tag_t val = mpack_read_tag(reader); if (mpack_reader_error(reader) != mpack_ok) return; switch (val.type) { case mpack_type_nil: fprintf(file, "null"); break; case mpack_type_bool: fprintf(file, val.v.b ? "true" : "false"); break; case mpack_type_float: fprintf(file, "%f", val.v.f); break; case mpack_type_double: fprintf(file, "%f", val.v.d); break; case mpack_type_int: fprintf(file, "%" PRIi64, val.v.i); break; case mpack_type_uint: fprintf(file, "%" PRIu64, val.v.u); break; case mpack_type_bin: fprintf(file, "<binary data of length %u>", val.v.l); mpack_skip_bytes(reader, val.v.l); mpack_done_bin(reader); break; case mpack_type_ext: fprintf(file, "<ext data of type %i and length %u>", val.exttype, val.v.l); mpack_skip_bytes(reader, val.v.l); mpack_done_ext(reader); break; case mpack_type_str: putc('"', file); for (size_t i = 0; i < val.v.l; ++i) { char c; mpack_read_bytes(reader, &c, 1); if (mpack_reader_error(reader) != mpack_ok) return; switch (c) { case '\n': fprintf(file, "\\n"); break; case '\\': fprintf(file, "\\\\"); break; case '"': fprintf(file, "\\\""); break; default: putc(c, file); break; } } putc('"', file); mpack_done_str(reader); break; case mpack_type_array: fprintf(file, "[\n"); for (size_t i = 0; i < val.v.n; ++i) { for (size_t j = 0; j < depth + 1; ++j) fprintf(file, " "); mpack_print_element(reader, depth + 1, file); if (mpack_reader_error(reader) != mpack_ok) return; if (i != val.v.n - 1) putc(',', file); putc('\n', file); } for (size_t i = 0; i < depth; ++i) fprintf(file, " "); putc(']', file); mpack_done_array(reader); break; case mpack_type_map: fprintf(file, "{\n"); for (size_t i = 0; i < val.v.n; ++i) { for (size_t j = 0; j < depth + 1; ++j) fprintf(file, " "); mpack_print_element(reader, depth + 1, file); if (mpack_reader_error(reader) != mpack_ok) return; fprintf(file, ": "); mpack_print_element(reader, depth + 1, file); if (mpack_reader_error(reader) != mpack_ok) return; if (i != val.v.n - 1) putc(',', file); putc('\n', file); } for (size_t i = 0; i < depth; ++i) fprintf(file, " "); putc('}', file); mpack_done_map(reader); break; } }