// internal inplace reader for when it straddles the end of the buffer static const char* mpack_read_bytes_inplace_big(mpack_reader_t* reader, size_t count) { // we should only arrive here from inplace straddle; this should already be checked mpack_assert(mpack_reader_error(reader) == mpack_ok, "already in error state? %s", mpack_error_to_string(mpack_reader_error(reader))); mpack_assert(reader->left < count, "already enough bytes in buffer: %i left, %i count", (int)reader->left, (int)count); // we'll need a fill function to get more data. if there's no // fill function, the buffer should contain an entire MessagePack // object, so we raise mpack_error_invalid instead of mpack_error_io // on truncated data. if (reader->fill == NULL) { mpack_reader_flag_error(reader, mpack_error_invalid); return NULL; } // make sure the buffer is big enough to actually fit the data if (count > reader->size) { mpack_reader_flag_error(reader, mpack_error_too_big); return NULL; } // re-fill as much as possible mpack_partial_fill(reader); if (reader->left < count) { mpack_reader_flag_error(reader, mpack_error_io); return NULL; } reader->pos += count; reader->left -= count; return reader->buffer; }
bool mpack_reader_ensure_straddle(mpack_reader_t* reader, size_t count) { mpack_assert(count != 0, "cannot ensure zero bytes!"); mpack_assert(reader->error == mpack_ok, "reader cannot be in an error state!"); if (count <= reader->left) { mpack_assert(0, "big ensure requested for %i bytes, but there are %i bytes " "left in buffer. call mpack_reader_ensure() instead", (int)count, (int)reader->left); mpack_reader_flag_error(reader, mpack_error_bug); return false; } // we'll need a fill function to get more data. if there's no // fill function, the buffer should contain an entire MessagePack // object, so we raise mpack_error_invalid instead of mpack_error_io // on truncated data. if (reader->fill == NULL) { mpack_reader_flag_error(reader, mpack_error_invalid); return false; } mpack_assert(count <= reader->size, "cannot ensure byte count %i larger than buffer size %i", (int)count, (int)reader->size); // re-fill as much as possible mpack_partial_fill(reader); if (reader->left < count) { mpack_reader_flag_error(reader, mpack_error_io); return false; } return true; }
static void mpack_reader_skip_using_fill(mpack_reader_t* reader, size_t count) { mpack_assert(reader->fill != NULL, "missing fill function!"); mpack_assert(reader->left == 0, "there are bytes left in the buffer!"); mpack_assert(reader->error == mpack_ok, "should not have called this in an error state (%i)", reader->error); mpack_log("skip using fill for %i bytes\n", (int)count); // fill and discard multiples of the buffer size while (count > reader->size) { mpack_log("filling and discarding buffer of %i bytes\n", (int)reader->size); if (mpack_fill(reader, reader->buffer, reader->size) < reader->size) { mpack_reader_flag_error(reader, mpack_error_io); return; } count -= reader->size; } // fill the buffer as much as possible reader->pos = 0; reader->left = mpack_fill(reader, reader->buffer, reader->size); if (reader->left < count) { mpack_reader_flag_error(reader, mpack_error_io); return; } mpack_log("filled %i bytes into buffer; discarding %i bytes\n", (int)reader->left, (int)count); reader->pos += count; reader->left -= count; }
float mpack_expect_float_strict(mpack_reader_t* reader) { mpack_tag_t var = mpack_read_tag(reader); if (var.type == mpack_type_float) return var.v.f; mpack_reader_flag_error(reader, mpack_error_type); return 0.0f; }
char* mpack_read_bytes_alloc_impl(mpack_reader_t* reader, size_t count, bool null_terminated) { // track the bytes first in case it jumps mpack_reader_track_bytes(reader, count); if (mpack_reader_error(reader) != mpack_ok) return NULL; // cannot allocate zero bytes. this is not an error. if (count == 0 && null_terminated == false) return NULL; // allocate data char* data = (char*)MPACK_MALLOC(count + (null_terminated ? 1 : 0)); // TODO: can this overflow? if (data == NULL) { mpack_reader_flag_error(reader, mpack_error_memory); return NULL; } // read with error callback disabled so we don't leak our buffer mpack_read_native_noerrorfn(reader, data, count); // report flagged errors if (mpack_reader_error(reader) != mpack_ok) { MPACK_FREE(data); if (reader->error_fn) reader->error_fn(reader, mpack_reader_error(reader)); return NULL; } if (null_terminated) data[count] = '\0'; return data; }
uint32_t mpack_expect_bin(mpack_reader_t* reader) { mpack_tag_t var = mpack_read_tag(reader); if (var.type == mpack_type_bin) return var.v.l; mpack_reader_flag_error(reader, mpack_error_type); return 0; }
void* mpack_expect_array_alloc_impl(mpack_reader_t* reader, size_t element_size, uint32_t max_count, uint32_t* out_count, bool allow_nil) { *out_count = 0; uint32_t count; bool has_array = true; if (allow_nil) has_array = mpack_expect_array_max_or_nil(reader, max_count, &count); else count = mpack_expect_array_max(reader, max_count); if (mpack_reader_error(reader)) return NULL; // size 0 is not an error; we return NULL for no elements. if (count == 0) { // we call mpack_done_array() automatically ONLY if we are using // the _or_nil variant. this is the only way to allow nil and empty // to work the same way. if (allow_nil && has_array) mpack_done_array(reader); return NULL; } void* p = MPACK_MALLOC(element_size * count); if (p == NULL) { mpack_reader_flag_error(reader, mpack_error_memory); return NULL; } *out_count = count; return p; }
void mpack_expect_nil(mpack_reader_t* reader) { mpack_reader_track_element(reader); uint8_t type = mpack_read_native_u8(reader); if (reader->error != mpack_ok) return; if (type != 0xc0) mpack_reader_flag_error(reader, mpack_error_type); }
void mpack_read_utf8(mpack_reader_t* reader, char* p, size_t byte_count) { mpack_assert(p != NULL, "destination for read of %i bytes is NULL", (int)byte_count); mpack_reader_track_str_bytes_all(reader, byte_count); mpack_read_native(reader, p, byte_count); if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check(p, byte_count)) mpack_reader_flag_error(reader, mpack_error_type); }
void mpack_read_utf8_cstr(mpack_reader_t* reader, char* buf, size_t buffer_size, size_t byte_count) { mpack_read_cstr_unchecked(reader, buf, buffer_size, byte_count); // check encoding if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check_no_null(buf, byte_count)) { buf[0] = 0; mpack_reader_flag_error(reader, mpack_error_type); } }
void mpack_expect_utf8_cstr(mpack_reader_t* reader, char* buf, size_t bufsize) { size_t length = mpack_expect_cstr_unchecked(reader, buf, bufsize); // check encoding if (!mpack_utf8_check_no_null(buf, length)) { buf[0] = 0; mpack_reader_flag_error(reader, mpack_error_type); } }
bool mpack_expect_bool(mpack_reader_t* reader) { mpack_reader_track_element(reader); uint8_t type = mpack_read_native_u8(reader); if (reader->error != mpack_ok) return false; if ((type & ~1) != 0xc2) mpack_reader_flag_error(reader, mpack_error_type); return (bool)(type & 1); }
bool mpack_expect_array_max_or_nil(mpack_reader_t* reader, uint32_t max_count, uint32_t* count) { bool has_array = mpack_expect_array_or_nil(reader, count); if (has_array && *count > max_count) { *count = 0; mpack_reader_flag_error(reader, mpack_error_type); return false; } return has_array; }
double mpack_expect_double_strict(mpack_reader_t* reader) { mpack_tag_t var = mpack_read_tag(reader); if (var.type == mpack_type_float) return (double)var.v.f; else if (var.type == mpack_type_double) return var.v.d; mpack_reader_flag_error(reader, mpack_error_type); return 0.0; }
void mpack_reader_set_fill(mpack_reader_t* reader, mpack_reader_fill_t fill) { MPACK_STATIC_ASSERT(MPACK_READER_MINIMUM_BUFFER_SIZE >= MPACK_MAXIMUM_TAG_SIZE, "minimum buffer size must fit any tag!"); if (reader->size == 0) { mpack_break("cannot use fill function without a writeable buffer!"); mpack_reader_flag_error(reader, mpack_error_bug); return; } if (reader->size < MPACK_READER_MINIMUM_BUFFER_SIZE) { mpack_break("buffer size is %i, but minimum buffer size for fill is %i", (int)reader->size, MPACK_READER_MINIMUM_BUFFER_SIZE); mpack_reader_flag_error(reader, mpack_error_bug); return; } reader->fill = fill; }
size_t mpack_expect_utf8(mpack_reader_t* reader, char* buf, size_t size) { size_t length = mpack_expect_str_buf(reader, buf, size); if (!mpack_utf8_check(buf, length)) { mpack_reader_flag_error(reader, mpack_error_type); return 0; } return length; }
uint64_t mpack_expect_u64(mpack_reader_t* reader) { mpack_tag_t var = mpack_read_tag(reader); if (var.type == mpack_type_uint) { return var.v.u; } else if (var.type == mpack_type_int) { if (var.v.i >= 0) return (uint64_t)var.v.i; } mpack_reader_flag_error(reader, mpack_error_type); return 0; }
const char* mpack_read_utf8_inplace(mpack_reader_t* reader, size_t count) { mpack_reader_track_str_bytes_all(reader, count); const char* str = mpack_read_bytes_inplace_notrack(reader, count); if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check(str, count)) { mpack_reader_flag_error(reader, mpack_error_type); return NULL; } return str; }
void mpack_expect_str_match(mpack_reader_t* reader, const char* str, size_t len) { // expect a str the correct length if (len > UINT32_MAX) mpack_reader_flag_error(reader, mpack_error_type); mpack_expect_str_length(reader, (uint32_t)len); if (mpack_reader_error(reader)) return; // check each byte for (size_t i = 0; i < len; ++i) { mpack_reader_track_bytes(reader, 1); if (mpack_read_native_u8(reader) != *str++) { mpack_reader_flag_error(reader, mpack_error_type); return; } } mpack_done_str(reader); }
int16_t mpack_expect_i16(mpack_reader_t* reader) { mpack_tag_t var = mpack_read_tag(reader); if (var.type == mpack_type_uint) { if (var.v.u <= INT16_MAX) return (int16_t)var.v.u; } else if (var.type == mpack_type_int) { if (var.v.i >= INT16_MIN && var.v.i <= INT16_MAX) return (int16_t)var.v.i; } mpack_reader_flag_error(reader, mpack_error_type); return 0; }
uint32_t mpack_expect_u32(mpack_reader_t* reader) { mpack_tag_t var = mpack_read_tag(reader); if (var.type == mpack_type_uint) { if (var.v.u <= UINT32_MAX) return (uint32_t)var.v.u; } else if (var.type == mpack_type_int) { if (var.v.i >= 0 && var.v.i <= UINT32_MAX) return (uint32_t)var.v.i; } mpack_reader_flag_error(reader, mpack_error_type); return 0; }
char* mpack_expect_utf8_cstr_alloc(mpack_reader_t* reader, size_t maxsize) { size_t length; char* str = mpack_expect_cstr_alloc_unchecked(reader, maxsize, &length); if (str && !mpack_utf8_check_no_null(str, length)) { MPACK_FREE(str); mpack_reader_flag_error(reader, mpack_error_type); return NULL; } return str; }
char* mpack_expect_utf8_alloc(mpack_reader_t* reader, size_t maxsize, size_t* size) { char* str = mpack_expect_str_alloc(reader, maxsize, size); if (str && !mpack_utf8_check(str, *size)) { *size = 0; MPACK_FREE(str); mpack_reader_flag_error(reader, mpack_error_type); return NULL; } return str; }
float mpack_expect_float(mpack_reader_t* reader) { mpack_tag_t var = mpack_read_tag(reader); if (var.type == mpack_type_uint) return (float)var.v.u; else if (var.type == mpack_type_int) return (float)var.v.i; else if (var.type == mpack_type_float) return var.v.f; else if (var.type == mpack_type_double) return (float)var.v.d; mpack_reader_flag_error(reader, mpack_error_type); return 0.0f; }
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; }
bool mpack_expect_array_or_nil(mpack_reader_t* reader, uint32_t* count) { mpack_tag_t var = mpack_read_tag(reader); if (var.type == mpack_type_nil) { *count = 0; return false; } if (var.type == mpack_type_array) { *count = var.v.n; return true; } mpack_reader_flag_error(reader, mpack_error_type); *count = 0; return false; }
static void mpack_file_reader_teardown(mpack_reader_t* reader) { FILE* file = (FILE*)reader->context; if (file) { int ret = fclose(file); reader->context = NULL; if (ret != 0) mpack_reader_flag_error(reader, mpack_error_io); } MPACK_FREE(reader->buffer); reader->buffer = NULL; reader->size = 0; reader->fill = NULL; }
size_t mpack_expect_str_buf(mpack_reader_t* reader, char* buf, size_t bufsize) { size_t length = mpack_expect_str(reader); if (mpack_reader_error(reader)) return 0; if (length > bufsize) { mpack_reader_flag_error(reader, mpack_error_too_big); return 0; } mpack_read_bytes(reader, buf, length); if (mpack_reader_error(reader)) return 0; mpack_done_str(reader); return length; }
mpack_tag_t mpack_read_tag(mpack_reader_t* reader) { mpack_log("reading tag\n"); // make sure we can read a tag if (mpack_reader_error(reader) != mpack_ok) return mpack_tag_nil(); if (mpack_reader_track_element(reader) != mpack_ok) return mpack_tag_nil(); mpack_tag_t tag; mpack_memset(&tag, 0, sizeof(tag)); size_t count = mpack_parse_tag(reader, &tag); if (count == 0) return mpack_tag_nil(); #if MPACK_READ_TRACKING mpack_error_t track_error = mpack_ok; switch (tag.type) { case mpack_type_map: case mpack_type_array: track_error = mpack_track_push(&reader->track, tag.type, tag.v.l); break; case mpack_type_str: case mpack_type_bin: case mpack_type_ext: track_error = mpack_track_push(&reader->track, tag.type, tag.v.n); break; default: break; } if (track_error != mpack_ok) { mpack_reader_flag_error(reader, track_error); return mpack_tag_nil(); } #endif // the tag is guaranteed to have been read out of // the buffer, so we advance past it reader->pos += count; reader->left -= count; return tag; }
void mpack_skip_bytes(mpack_reader_t* reader, size_t count) { if (mpack_reader_error(reader) != mpack_ok) return; mpack_log("skip requested for %i bytes\n", (int)count); mpack_reader_track_bytes(reader, count); // check if we have enough in the buffer already if (reader->left >= count) { mpack_log("skipping %i bytes still in buffer\n", (int)count); reader->left -= count; reader->pos += count; return; } // we'll need at least a fill function to skip more data. if there's // no fill function, the buffer should contain an entire MessagePack // object, so we raise mpack_error_invalid instead of mpack_error_io // on truncated data. (see mpack_read_native_big()) if (reader->fill == NULL) { mpack_log("reader has no fill function!\n"); mpack_reader_flag_error(reader, mpack_error_invalid); return; } // discard whatever's left in the buffer mpack_log("discarding %i bytes still in buffer\n", (int)reader->left); count -= reader->left; reader->pos += reader->left; reader->left = 0; #if !MPACK_OPTIMIZE_FOR_SIZE // use the skip function if we've got one, and if we're trying // to skip a lot of data. if we only need to skip some tiny // fraction of the buffer size, it's probably better to just // fill the buffer and skip from it instead of trying to seek. if (reader->skip && count > reader->size / 16) { mpack_log("calling skip function for %i bytes\n", (int)count); reader->skip(reader, count); return; } #endif mpack_reader_skip_using_fill(reader, count); }