mirror of
https://github.com/neovim/neovim.git
synced 2025-09-09 04:48:18 +00:00
579 lines
17 KiB
C
579 lines
17 KiB
C
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
|
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
|
|
#include <string.h>
|
|
|
|
#include "mpack_core.h"
|
|
|
|
#define UNUSED(p) (void)p;
|
|
#define ADVANCE(buf, buflen) ((*buflen)--, (unsigned char)*((*buf)++))
|
|
#define TLEN(val, range_start) ((mpack_uint32_t)(1 << (val - range_start)))
|
|
#ifndef MIN
|
|
# define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
|
#endif
|
|
|
|
static int mpack_rtoken(const char **buf, size_t *buflen,
|
|
mpack_token_t *tok);
|
|
static int mpack_rpending(const char **b, size_t *nl, mpack_tokbuf_t *tb);
|
|
static int mpack_rvalue(mpack_token_type_t t, mpack_uint32_t l,
|
|
const char **b, size_t *bl, mpack_token_t *tok);
|
|
static int mpack_rblob(mpack_token_type_t t, mpack_uint32_t l,
|
|
const char **b, size_t *bl, mpack_token_t *tok);
|
|
static int mpack_wtoken(const mpack_token_t *tok, char **b, size_t *bl);
|
|
static int mpack_wpending(char **b, size_t *bl, mpack_tokbuf_t *tb);
|
|
static int mpack_wpint(char **b, size_t *bl, mpack_value_t v);
|
|
static int mpack_wnint(char **b, size_t *bl, mpack_value_t v);
|
|
static int mpack_wfloat(char **b, size_t *bl, const mpack_token_t *v);
|
|
static int mpack_wstr(char **buf, size_t *buflen, mpack_uint32_t len);
|
|
static int mpack_wbin(char **buf, size_t *buflen, mpack_uint32_t len);
|
|
static int mpack_wext(char **buf, size_t *buflen, int type,
|
|
mpack_uint32_t len);
|
|
static int mpack_warray(char **buf, size_t *buflen, mpack_uint32_t len);
|
|
static int mpack_wmap(char **buf, size_t *buflen, mpack_uint32_t len);
|
|
static int mpack_w1(char **b, size_t *bl, mpack_uint32_t v);
|
|
static int mpack_w2(char **b, size_t *bl, mpack_uint32_t v);
|
|
static int mpack_w4(char **b, size_t *bl, mpack_uint32_t v);
|
|
static mpack_value_t mpack_byte(unsigned char b);
|
|
static int mpack_value(mpack_token_type_t t, mpack_uint32_t l,
|
|
mpack_value_t v, mpack_token_t *tok);
|
|
static int mpack_blob(mpack_token_type_t t, mpack_uint32_t l, int et,
|
|
mpack_token_t *tok);
|
|
|
|
MPACK_API void mpack_tokbuf_init(mpack_tokbuf_t *tokbuf)
|
|
{
|
|
tokbuf->ppos = 0;
|
|
tokbuf->plen = 0;
|
|
tokbuf->passthrough = 0;
|
|
}
|
|
|
|
MPACK_API int mpack_read(mpack_tokbuf_t *tokbuf, const char **buf,
|
|
size_t *buflen, mpack_token_t *tok)
|
|
{
|
|
int status;
|
|
size_t initial_ppos, ptrlen, advanced;
|
|
const char *ptr, *ptr_save;
|
|
assert(*buf && *buflen);
|
|
|
|
if (tokbuf->passthrough) {
|
|
/* pass data from str/bin/ext directly as a MPACK_TOKEN_CHUNK, adjusting
|
|
* *buf and *buflen */
|
|
tok->type = MPACK_TOKEN_CHUNK;
|
|
tok->data.chunk_ptr = *buf;
|
|
tok->length = MIN((mpack_uint32_t)*buflen, tokbuf->passthrough);
|
|
tokbuf->passthrough -= tok->length;
|
|
*buf += tok->length;
|
|
*buflen -= tok->length;
|
|
goto done;
|
|
}
|
|
|
|
initial_ppos = tokbuf->ppos;
|
|
|
|
if (tokbuf->plen) {
|
|
if (!mpack_rpending(buf, buflen, tokbuf)) {
|
|
return MPACK_EOF;
|
|
}
|
|
ptr = tokbuf->pending;
|
|
ptrlen = tokbuf->ppos;
|
|
} else {
|
|
ptr = *buf;
|
|
ptrlen = *buflen;
|
|
}
|
|
|
|
ptr_save = ptr;
|
|
|
|
if ((status = mpack_rtoken(&ptr, &ptrlen, tok))) {
|
|
if (status != MPACK_EOF) return MPACK_ERROR;
|
|
/* need more data */
|
|
assert(!tokbuf->plen);
|
|
/* read the remainder of *buf to tokbuf->pending so it can be parsed
|
|
* later with more data. only required when tokbuf->plen == 0 or else
|
|
* it would have been done already. */
|
|
tokbuf->plen = tok->length + 1;
|
|
assert(tokbuf->plen <= sizeof(tokbuf->pending));
|
|
tokbuf->ppos = 0;
|
|
status = mpack_rpending(buf, buflen, tokbuf);
|
|
assert(!status);
|
|
return MPACK_EOF;
|
|
}
|
|
|
|
advanced = (size_t)(ptr - ptr_save) - initial_ppos;
|
|
tokbuf->plen = tokbuf->ppos = 0;
|
|
*buflen -= advanced;
|
|
*buf += advanced;
|
|
|
|
if (tok->type > MPACK_TOKEN_MAP) {
|
|
tokbuf->passthrough = tok->length;
|
|
}
|
|
|
|
done:
|
|
return MPACK_OK;
|
|
}
|
|
|
|
MPACK_API int mpack_write(mpack_tokbuf_t *tokbuf, char **buf, size_t *buflen,
|
|
const mpack_token_t *t)
|
|
{
|
|
int status;
|
|
char *ptr;
|
|
size_t ptrlen;
|
|
mpack_token_t tok = tokbuf->plen ? tokbuf->pending_tok : *t;
|
|
assert(*buf && *buflen);
|
|
|
|
if (tok.type == MPACK_TOKEN_CHUNK) {
|
|
size_t written, pending, count;
|
|
if (!tokbuf->plen) tokbuf->ppos = 0;
|
|
written = tokbuf->ppos;
|
|
pending = tok.length - written;
|
|
count = MIN(pending, *buflen);
|
|
memcpy(*buf, tok.data.chunk_ptr + written, count);
|
|
*buf += count;
|
|
*buflen -= count;
|
|
tokbuf->ppos += count;
|
|
tokbuf->plen = count == pending ? 0 : tok.length;
|
|
if (count == pending) {
|
|
return MPACK_OK;
|
|
} else {
|
|
tokbuf->pending_tok = tok;
|
|
return MPACK_EOF;
|
|
}
|
|
}
|
|
|
|
if (tokbuf->plen) return mpack_wpending(buf, buflen, tokbuf);
|
|
|
|
if (*buflen < MPACK_MAX_TOKEN_LEN) {
|
|
ptr = tokbuf->pending;
|
|
ptrlen = sizeof(tokbuf->pending);
|
|
} else {
|
|
ptr = *buf;
|
|
ptrlen = *buflen;
|
|
}
|
|
|
|
if ((status = mpack_wtoken(&tok, &ptr, &ptrlen))) return status;
|
|
|
|
if (*buflen < MPACK_MAX_TOKEN_LEN) {
|
|
size_t toklen = sizeof(tokbuf->pending) - ptrlen;
|
|
size_t write_cnt = MIN(toklen, *buflen);
|
|
memcpy(*buf, tokbuf->pending, write_cnt);
|
|
*buf += write_cnt;
|
|
*buflen -= write_cnt;
|
|
if (write_cnt < toklen) {
|
|
assert(!*buflen);
|
|
tokbuf->plen = toklen;
|
|
tokbuf->ppos = write_cnt;
|
|
tokbuf->pending_tok = tok;
|
|
return MPACK_EOF;
|
|
}
|
|
} else {
|
|
*buflen -= (size_t)(ptr - *buf);
|
|
*buf = ptr;
|
|
}
|
|
|
|
return MPACK_OK;
|
|
}
|
|
|
|
static int mpack_rtoken(const char **buf, size_t *buflen,
|
|
mpack_token_t *tok)
|
|
{
|
|
unsigned char t = ADVANCE(buf, buflen);
|
|
if (t < 0x80) {
|
|
/* positive fixint */
|
|
return mpack_value(MPACK_TOKEN_UINT, 1, mpack_byte(t), tok);
|
|
} else if (t < 0x90) {
|
|
/* fixmap */
|
|
return mpack_blob(MPACK_TOKEN_MAP, t & 0xf, 0, tok);
|
|
} else if (t < 0xa0) {
|
|
/* fixarray */
|
|
return mpack_blob(MPACK_TOKEN_ARRAY, t & 0xf, 0, tok);
|
|
} else if (t < 0xc0) {
|
|
/* fixstr */
|
|
return mpack_blob(MPACK_TOKEN_STR, t & 0x1f, 0, tok);
|
|
} else if (t < 0xe0) {
|
|
switch (t) {
|
|
case 0xc0: /* nil */
|
|
return mpack_value(MPACK_TOKEN_NIL, 0, mpack_byte(0), tok);
|
|
case 0xc2: /* false */
|
|
return mpack_value(MPACK_TOKEN_BOOLEAN, 1, mpack_byte(0), tok);
|
|
case 0xc3: /* true */
|
|
return mpack_value(MPACK_TOKEN_BOOLEAN, 1, mpack_byte(1), tok);
|
|
case 0xc4: /* bin 8 */
|
|
case 0xc5: /* bin 16 */
|
|
case 0xc6: /* bin 32 */
|
|
return mpack_rblob(MPACK_TOKEN_BIN, TLEN(t, 0xc4), buf, buflen, tok);
|
|
case 0xc7: /* ext 8 */
|
|
case 0xc8: /* ext 16 */
|
|
case 0xc9: /* ext 32 */
|
|
return mpack_rblob(MPACK_TOKEN_EXT, TLEN(t, 0xc7), buf, buflen, tok);
|
|
case 0xca: /* float 32 */
|
|
case 0xcb: /* float 64 */
|
|
return mpack_rvalue(MPACK_TOKEN_FLOAT, TLEN(t, 0xc8), buf, buflen, tok);
|
|
case 0xcc: /* uint 8 */
|
|
case 0xcd: /* uint 16 */
|
|
case 0xce: /* uint 32 */
|
|
case 0xcf: /* uint 64 */
|
|
return mpack_rvalue(MPACK_TOKEN_UINT, TLEN(t, 0xcc), buf, buflen, tok);
|
|
case 0xd0: /* int 8 */
|
|
case 0xd1: /* int 16 */
|
|
case 0xd2: /* int 32 */
|
|
case 0xd3: /* int 64 */
|
|
return mpack_rvalue(MPACK_TOKEN_SINT, TLEN(t, 0xd0), buf, buflen, tok);
|
|
case 0xd4: /* fixext 1 */
|
|
case 0xd5: /* fixext 2 */
|
|
case 0xd6: /* fixext 4 */
|
|
case 0xd7: /* fixext 8 */
|
|
case 0xd8: /* fixext 16 */
|
|
if (*buflen == 0) {
|
|
/* require only one extra byte for the type code */
|
|
tok->length = 1;
|
|
return MPACK_EOF;
|
|
}
|
|
tok->length = TLEN(t, 0xd4);
|
|
tok->type = MPACK_TOKEN_EXT;
|
|
tok->data.ext_type = ADVANCE(buf, buflen);
|
|
return MPACK_OK;
|
|
case 0xd9: /* str 8 */
|
|
case 0xda: /* str 16 */
|
|
case 0xdb: /* str 32 */
|
|
return mpack_rblob(MPACK_TOKEN_STR, TLEN(t, 0xd9), buf, buflen, tok);
|
|
case 0xdc: /* array 16 */
|
|
case 0xdd: /* array 32 */
|
|
return mpack_rblob(MPACK_TOKEN_ARRAY, TLEN(t, 0xdb), buf, buflen, tok);
|
|
case 0xde: /* map 16 */
|
|
case 0xdf: /* map 32 */
|
|
return mpack_rblob(MPACK_TOKEN_MAP, TLEN(t, 0xdd), buf, buflen, tok);
|
|
default:
|
|
return MPACK_ERROR;
|
|
}
|
|
} else {
|
|
/* negative fixint */
|
|
return mpack_value(MPACK_TOKEN_SINT, 1, mpack_byte(t), tok);
|
|
}
|
|
}
|
|
|
|
static int mpack_rpending(const char **buf, size_t *buflen,
|
|
mpack_tokbuf_t *state)
|
|
{
|
|
size_t count;
|
|
assert(state->ppos < state->plen);
|
|
count = MIN(state->plen - state->ppos, *buflen);
|
|
memcpy(state->pending + state->ppos, *buf, count);
|
|
state->ppos += count;
|
|
if (state->ppos < state->plen) {
|
|
/* consume buffer since no token will be parsed yet. */
|
|
*buf += *buflen;
|
|
*buflen = 0;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int mpack_rvalue(mpack_token_type_t type, mpack_uint32_t remaining,
|
|
const char **buf, size_t *buflen, mpack_token_t *tok)
|
|
{
|
|
if (*buflen < remaining) {
|
|
tok->length = remaining;
|
|
return MPACK_EOF;
|
|
}
|
|
|
|
mpack_value(type, remaining, mpack_byte(0), tok);
|
|
|
|
while (remaining) {
|
|
mpack_uint32_t byte = ADVANCE(buf, buflen), byte_idx, byte_shift;
|
|
byte_idx = (mpack_uint32_t)--remaining;
|
|
byte_shift = (byte_idx % 4) * 8;
|
|
tok->data.value.lo |= byte << byte_shift;
|
|
if (remaining == 4) {
|
|
/* unpacked the first half of a 8-byte value, shift what was parsed to the
|
|
* "hi" field and reset "lo" for the trailing 4 bytes. */
|
|
tok->data.value.hi = tok->data.value.lo;
|
|
tok->data.value.lo = 0;
|
|
}
|
|
}
|
|
|
|
if (type == MPACK_TOKEN_SINT) {
|
|
mpack_uint32_t hi = tok->data.value.hi;
|
|
mpack_uint32_t lo = tok->data.value.lo;
|
|
mpack_uint32_t msb = (tok->length == 8 && hi >> 31) ||
|
|
(tok->length == 4 && lo >> 31) ||
|
|
(tok->length == 2 && lo >> 15) ||
|
|
(tok->length == 1 && lo >> 7);
|
|
if (!msb) {
|
|
tok->type = MPACK_TOKEN_UINT;
|
|
}
|
|
}
|
|
|
|
return MPACK_OK;
|
|
}
|
|
|
|
static int mpack_rblob(mpack_token_type_t type, mpack_uint32_t tlen,
|
|
const char **buf, size_t *buflen, mpack_token_t *tok)
|
|
{
|
|
mpack_token_t l;
|
|
mpack_uint32_t required = tlen + (type == MPACK_TOKEN_EXT ? 1 : 0);
|
|
|
|
if (*buflen < required) {
|
|
tok->length = required;
|
|
return MPACK_EOF;
|
|
}
|
|
|
|
l.data.value.lo = 0;
|
|
mpack_rvalue(MPACK_TOKEN_UINT, tlen, buf, buflen, &l);
|
|
tok->type = type;
|
|
tok->length = l.data.value.lo;
|
|
|
|
if (type == MPACK_TOKEN_EXT) {
|
|
tok->data.ext_type = ADVANCE(buf, buflen);
|
|
}
|
|
|
|
return MPACK_OK;
|
|
}
|
|
|
|
static int mpack_wtoken(const mpack_token_t *tok, char **buf,
|
|
size_t *buflen)
|
|
{
|
|
switch (tok->type) {
|
|
case MPACK_TOKEN_NIL:
|
|
return mpack_w1(buf, buflen, 0xc0);
|
|
case MPACK_TOKEN_BOOLEAN:
|
|
return mpack_w1(buf, buflen, tok->data.value.lo ? 0xc3 : 0xc2);
|
|
case MPACK_TOKEN_UINT:
|
|
return mpack_wpint(buf, buflen, tok->data.value);
|
|
case MPACK_TOKEN_SINT:
|
|
return mpack_wnint(buf, buflen, tok->data.value);
|
|
case MPACK_TOKEN_FLOAT:
|
|
return mpack_wfloat(buf, buflen, tok);
|
|
case MPACK_TOKEN_BIN:
|
|
return mpack_wbin(buf, buflen, tok->length);
|
|
case MPACK_TOKEN_STR:
|
|
return mpack_wstr(buf, buflen, tok->length);
|
|
case MPACK_TOKEN_EXT:
|
|
return mpack_wext(buf, buflen, tok->data.ext_type, tok->length);
|
|
case MPACK_TOKEN_ARRAY:
|
|
return mpack_warray(buf, buflen, tok->length);
|
|
case MPACK_TOKEN_MAP:
|
|
return mpack_wmap(buf, buflen, tok->length);
|
|
default:
|
|
return MPACK_ERROR;
|
|
}
|
|
}
|
|
|
|
static int mpack_wpending(char **buf, size_t *buflen, mpack_tokbuf_t *state)
|
|
{
|
|
size_t count;
|
|
assert(state->ppos < state->plen);
|
|
count = MIN(state->plen - state->ppos, *buflen);
|
|
memcpy(*buf, state->pending + state->ppos, count);
|
|
state->ppos += count;
|
|
*buf += count;
|
|
*buflen -= count;
|
|
if (state->ppos == state->plen) {
|
|
state->plen = 0;
|
|
return MPACK_OK;
|
|
}
|
|
return MPACK_EOF;
|
|
}
|
|
|
|
static int mpack_wpint(char **buf, size_t *buflen, mpack_value_t val)
|
|
{
|
|
mpack_uint32_t hi = val.hi;
|
|
mpack_uint32_t lo = val.lo;
|
|
|
|
if (hi) {
|
|
/* uint 64 */
|
|
return mpack_w1(buf, buflen, 0xcf) ||
|
|
mpack_w4(buf, buflen, hi) ||
|
|
mpack_w4(buf, buflen, lo);
|
|
} else if (lo > 0xffff) {
|
|
/* uint 32 */
|
|
return mpack_w1(buf, buflen, 0xce) ||
|
|
mpack_w4(buf, buflen, lo);
|
|
} else if (lo > 0xff) {
|
|
/* uint 16 */
|
|
return mpack_w1(buf, buflen, 0xcd) ||
|
|
mpack_w2(buf, buflen, lo);
|
|
} else if (lo > 0x7f) {
|
|
/* uint 8 */
|
|
return mpack_w1(buf, buflen, 0xcc) ||
|
|
mpack_w1(buf, buflen, lo);
|
|
} else {
|
|
return mpack_w1(buf, buflen, lo);
|
|
}
|
|
}
|
|
|
|
static int mpack_wnint(char **buf, size_t *buflen, mpack_value_t val)
|
|
{
|
|
mpack_uint32_t hi = val.hi;
|
|
mpack_uint32_t lo = val.lo;
|
|
|
|
if (lo < 0x80000000) {
|
|
/* int 64 */
|
|
return mpack_w1(buf, buflen, 0xd3) ||
|
|
mpack_w4(buf, buflen, hi) ||
|
|
mpack_w4(buf, buflen, lo);
|
|
} else if (lo < 0xffff7fff) {
|
|
/* int 32 */
|
|
return mpack_w1(buf, buflen, 0xd2) ||
|
|
mpack_w4(buf, buflen, lo);
|
|
} else if (lo < 0xffffff7f) {
|
|
/* int 16 */
|
|
return mpack_w1(buf, buflen, 0xd1) ||
|
|
mpack_w2(buf, buflen, lo);
|
|
} else if (lo < 0xffffffe0) {
|
|
/* int 8 */
|
|
return mpack_w1(buf, buflen, 0xd0) ||
|
|
mpack_w1(buf, buflen, lo);
|
|
} else {
|
|
/* negative fixint */
|
|
return mpack_w1(buf, buflen, (mpack_uint32_t)(0x100 + lo));
|
|
}
|
|
}
|
|
|
|
static int mpack_wfloat(char **buf, size_t *buflen,
|
|
const mpack_token_t *tok)
|
|
{
|
|
if (tok->length == 4) {
|
|
return mpack_w1(buf, buflen, 0xca) ||
|
|
mpack_w4(buf, buflen, tok->data.value.lo);
|
|
} else if (tok->length == 8) {
|
|
return mpack_w1(buf, buflen, 0xcb) ||
|
|
mpack_w4(buf, buflen, tok->data.value.hi) ||
|
|
mpack_w4(buf, buflen, tok->data.value.lo);
|
|
} else {
|
|
return MPACK_ERROR;
|
|
}
|
|
}
|
|
|
|
static int mpack_wstr(char **buf, size_t *buflen, mpack_uint32_t len)
|
|
{
|
|
if (len < 0x20) {
|
|
return mpack_w1(buf, buflen, 0xa0 | len);
|
|
} else if (len < 0x100) {
|
|
return mpack_w1(buf, buflen, 0xd9) ||
|
|
mpack_w1(buf, buflen, len);
|
|
} else if (len < 0x10000) {
|
|
return mpack_w1(buf, buflen, 0xda) ||
|
|
mpack_w2(buf, buflen, len);
|
|
} else {
|
|
return mpack_w1(buf, buflen, 0xdb) ||
|
|
mpack_w4(buf, buflen, len);
|
|
}
|
|
}
|
|
|
|
static int mpack_wbin(char **buf, size_t *buflen, mpack_uint32_t len)
|
|
{
|
|
if (len < 0x100) {
|
|
return mpack_w1(buf, buflen, 0xc4) ||
|
|
mpack_w1(buf, buflen, len);
|
|
} else if (len < 0x10000) {
|
|
return mpack_w1(buf, buflen, 0xc5) ||
|
|
mpack_w2(buf, buflen, len);
|
|
} else {
|
|
return mpack_w1(buf, buflen, 0xc6) ||
|
|
mpack_w4(buf, buflen, len);
|
|
}
|
|
}
|
|
|
|
static int mpack_wext(char **buf, size_t *buflen, int type,
|
|
mpack_uint32_t len)
|
|
{
|
|
mpack_uint32_t t;
|
|
assert(type >= 0 && type < 0x80);
|
|
t = (mpack_uint32_t)type;
|
|
switch (len) {
|
|
case 1: mpack_w1(buf, buflen, 0xd4); return mpack_w1(buf, buflen, t);
|
|
case 2: mpack_w1(buf, buflen, 0xd5); return mpack_w1(buf, buflen, t);
|
|
case 4: mpack_w1(buf, buflen, 0xd6); return mpack_w1(buf, buflen, t);
|
|
case 8: mpack_w1(buf, buflen, 0xd7); return mpack_w1(buf, buflen, t);
|
|
case 16: mpack_w1(buf, buflen, 0xd8); return mpack_w1(buf, buflen, t);
|
|
default:
|
|
if (len < 0x100) {
|
|
return mpack_w1(buf, buflen, 0xc7) ||
|
|
mpack_w1(buf, buflen, len) ||
|
|
mpack_w1(buf, buflen, t);
|
|
} else if (len < 0x10000) {
|
|
return mpack_w1(buf, buflen, 0xc8) ||
|
|
mpack_w2(buf, buflen, len) ||
|
|
mpack_w1(buf, buflen, t);
|
|
} else {
|
|
return mpack_w1(buf, buflen, 0xc9) ||
|
|
mpack_w4(buf, buflen, len) ||
|
|
mpack_w1(buf, buflen, t);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int mpack_warray(char **buf, size_t *buflen, mpack_uint32_t len)
|
|
{
|
|
if (len < 0x10) {
|
|
return mpack_w1(buf, buflen, 0x90 | len);
|
|
} else if (len < 0x10000) {
|
|
return mpack_w1(buf, buflen, 0xdc) ||
|
|
mpack_w2(buf, buflen, len);
|
|
} else {
|
|
return mpack_w1(buf, buflen, 0xdd) ||
|
|
mpack_w4(buf, buflen, len);
|
|
}
|
|
}
|
|
|
|
static int mpack_wmap(char **buf, size_t *buflen, mpack_uint32_t len)
|
|
{
|
|
if (len < 0x10) {
|
|
return mpack_w1(buf, buflen, 0x80 | len);
|
|
} else if (len < 0x10000) {
|
|
return mpack_w1(buf, buflen, 0xde) ||
|
|
mpack_w2(buf, buflen, len);
|
|
} else {
|
|
return mpack_w1(buf, buflen, 0xdf) ||
|
|
mpack_w4(buf, buflen, len);
|
|
}
|
|
}
|
|
|
|
static int mpack_w1(char **b, size_t *bl, mpack_uint32_t v)
|
|
{
|
|
(*bl)--;
|
|
*(*b)++ = (char)(v & 0xff);
|
|
return MPACK_OK;
|
|
}
|
|
|
|
static int mpack_w2(char **b, size_t *bl, mpack_uint32_t v)
|
|
{
|
|
*bl -= 2;
|
|
*(*b)++ = (char)((v >> 8) & 0xff);
|
|
*(*b)++ = (char)(v & 0xff);
|
|
return MPACK_OK;
|
|
}
|
|
|
|
static int mpack_w4(char **b, size_t *bl, mpack_uint32_t v)
|
|
{
|
|
*bl -= 4;
|
|
*(*b)++ = (char)((v >> 24) & 0xff);
|
|
*(*b)++ = (char)((v >> 16) & 0xff);
|
|
*(*b)++ = (char)((v >> 8) & 0xff);
|
|
*(*b)++ = (char)(v & 0xff);
|
|
return MPACK_OK;
|
|
}
|
|
|
|
static int mpack_value(mpack_token_type_t type, mpack_uint32_t length,
|
|
mpack_value_t value, mpack_token_t *tok)
|
|
{
|
|
tok->type = type;
|
|
tok->length = length;
|
|
tok->data.value = value;
|
|
return MPACK_OK;
|
|
}
|
|
|
|
static int mpack_blob(mpack_token_type_t type, mpack_uint32_t length,
|
|
int ext_type, mpack_token_t *tok)
|
|
{
|
|
tok->type = type;
|
|
tok->length = length;
|
|
tok->data.ext_type = ext_type;
|
|
return MPACK_OK;
|
|
}
|
|
|
|
static mpack_value_t mpack_byte(unsigned char byte)
|
|
{
|
|
mpack_value_t rv;
|
|
rv.lo = byte;
|
|
rv.hi = 0;
|
|
return rv;
|
|
}
|