diff options
| author | Björn Linse <bjorn.linse@gmail.com> | 2021-09-04 16:59:26 +0200 | 
|---|---|---|
| committer | Björn Linse <bjorn.linse@gmail.com> | 2021-09-09 16:06:43 +0200 | 
| commit | c8f46480bc0bfd07c8a69d61e365706e3184abc9 (patch) | |
| tree | ed0f91460fc3988bb7efd5aea24c9a037c418f07 /src/mpack/core.c | |
| parent | d8339be6915b3640f12a1827cee652b604b1a0d7 (diff) | |
| download | rneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.tar.gz rneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.tar.bz2 rneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.zip | |
build: vendor libmpack source from libmpack/libmpack 22b1fd90285117c995728511f9525d29520a8c82
Diffstat (limited to 'src/mpack/core.c')
| -rw-r--r-- | src/mpack/core.c | 575 | 
1 files changed, 575 insertions, 0 deletions
| diff --git a/src/mpack/core.c b/src/mpack/core.c new file mode 100644 index 0000000000..ce529f0dca --- /dev/null +++ b/src/mpack/core.c @@ -0,0 +1,575 @@ +#include <string.h> + +#include "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; +} | 
