static int pni_decoder_decode_value()

in c/src/core/decoder.c [184:439]


static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code)
{
  int err;
  conv_t conv;
  pn_decimal128_t dec128;
  pn_uuid_t uuid;
  size_t size;
  size_t count;

  switch (code)
  {
  case PNE_NULL:
    err = pn_data_put_null(data);
    break;
  case PNE_TRUE:
    err = pn_data_put_bool(data, true);
    break;
  case PNE_FALSE:
    err = pn_data_put_bool(data, false);
    break;
  case PNE_BOOLEAN:
    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
    err = pn_data_put_bool(data, pn_decoder_readf8(decoder) != 0);
    break;
  case PNE_UBYTE:
    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
    err = pn_data_put_ubyte(data, pn_decoder_readf8(decoder));
    break;
  case PNE_BYTE:
    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
    err = pn_data_put_byte(data, pn_decoder_readf8(decoder));
    break;
  case PNE_USHORT:
    if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
    err = pn_data_put_ushort(data, pn_decoder_readf16(decoder));
    break;
  case PNE_SHORT:
    if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
    err = pn_data_put_short(data, pn_decoder_readf16(decoder));
    break;
  case PNE_UINT:
    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
    err = pn_data_put_uint(data, pn_decoder_readf32(decoder));
    break;
  case PNE_UINT0:
    err = pn_data_put_uint(data, 0);
    break;
  case PNE_SMALLUINT:
    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
    err = pn_data_put_uint(data, pn_decoder_readf8(decoder));
    break;
  case PNE_SMALLINT:
    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
    err = pn_data_put_int(data, (int8_t)pn_decoder_readf8(decoder));
    break;
  case PNE_INT:
    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
    err = pn_data_put_int(data, pn_decoder_readf32(decoder));
    break;
  case PNE_UTF32:
    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
    err = pn_data_put_char(data, pn_decoder_readf32(decoder));
    break;
  case PNE_FLOAT:
    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
    // XXX: this assumes the platform uses IEEE floats
    conv.i = pn_decoder_readf32(decoder);
    err = pn_data_put_float(data, conv.f);
    break;
  case PNE_DECIMAL32:
    if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
    err = pn_data_put_decimal32(data, pn_decoder_readf32(decoder));
    break;
  case PNE_ULONG:
    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
    err = pn_data_put_ulong(data, pn_decoder_readf64(decoder));
    break;
  case PNE_LONG:
    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
    err = pn_data_put_long(data, pn_decoder_readf64(decoder));
    break;
  case PNE_MS64:
    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
    err = pn_data_put_timestamp(data, pn_decoder_readf64(decoder));
    break;
  case PNE_DOUBLE:
    // XXX: this assumes the platform uses IEEE floats
    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
    conv.l = pn_decoder_readf64(decoder);
    err = pn_data_put_double(data, conv.d);
    break;
  case PNE_DECIMAL64:
    if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
    err = pn_data_put_decimal64(data, pn_decoder_readf64(decoder));
    break;
  case PNE_ULONG0:
    err = pn_data_put_ulong(data, 0);
    break;
  case PNE_SMALLULONG:
    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
    err = pn_data_put_ulong(data, pn_decoder_readf8(decoder));
    break;
  case PNE_SMALLLONG:
    if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
    err = pn_data_put_long(data, (int8_t)pn_decoder_readf8(decoder));
    break;
  case PNE_DECIMAL128:
    if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
    pn_decoder_readf128(decoder, &dec128);
    err = pn_data_put_decimal128(data, dec128);
    break;
  case PNE_UUID:
    if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
    pn_decoder_readf128(decoder, &uuid);
    err = pn_data_put_uuid(data, uuid);
    break;
  case PNE_VBIN8:
  case PNE_STR8_UTF8:
  case PNE_SYM8:
  case PNE_VBIN32:
  case PNE_STR32_UTF8:
  case PNE_SYM32:
    switch (code & 0xF0)
    {
    case 0xA0:
      if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
      size = pn_decoder_readf8(decoder);
      break;
    case 0xB0:
      if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
      size = pn_decoder_readf32(decoder);
      break;
    default:
      return PN_ARG_ERR;
    }

    if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;

    {
      char *start = (char *) decoder->position;
      pn_bytes_t bytes = {size, start};
      switch (code & 0x0F)
      {
      case 0x0:
        err = pn_data_put_binary(data, bytes);
        break;
      case 0x1:
        err = pn_data_put_string(data, bytes);
        break;
      case 0x3:
        err = pn_data_put_symbol(data, bytes);
        break;
      default:
        return PN_ARG_ERR;
      }
    }

    decoder->position += size;
    break;
  case PNE_LIST0:
    err = pn_data_put_list(data);
    break;
  case PNE_ARRAY8:
  case PNE_ARRAY32:
  case PNE_LIST8:
  case PNE_LIST32:
  case PNE_MAP8:
  case PNE_MAP32: {
    size_t min_expected_size = 0;
    switch (code)
    {
    case PNE_ARRAY8:
      min_expected_size += 1; // Array has a constructor of at least 1 byte
      PN_FALLTHROUGH;
    case PNE_LIST8:
    case PNE_MAP8:
      min_expected_size += 1; // All these types have a count
      if (pn_decoder_remaining(decoder) < min_expected_size+1) return PN_UNDERFLOW;
      size = pn_decoder_readf8(decoder);
      // size must be at least big enough for count or count+constructor
      if (size < min_expected_size) return PN_ARG_ERR;
      if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
      count = pn_decoder_readf8(decoder);
      break;
    case PNE_ARRAY32:
      min_expected_size += 1; // Array has a constructor of at least 1 byte
      PN_FALLTHROUGH;
    case PNE_LIST32:
    case PNE_MAP32:
      min_expected_size += 4; // All these types have a count
      if (pn_decoder_remaining(decoder) < min_expected_size+4) return PN_UNDERFLOW;
      size = pn_decoder_readf32(decoder);
      // size must be at least big enough for count or count+constructor
      if (size < min_expected_size) return PN_ARG_ERR;
      if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
      count = pn_decoder_readf32(decoder);
      break;
    default:
      return PN_ARG_ERR;
    }

    switch (code)
    {
    case PNE_ARRAY8:
    case PNE_ARRAY32:
      {
        uint8_t next = *decoder->position;
        bool described = (next == PNE_DESCRIPTOR);
        err = pn_data_put_array(data, described, (pn_type_t) 0);
        if (err) return err;

        pn_data_enter(data);
        uint8_t acode;
        int e = pni_decoder_decode_type(decoder, data, &acode);
        if (e) return e;
        pn_type_t type = pn_code2type(acode);
        if ((int)type < 0) return (int)type;
        for (size_t i = 0; i < count; i++)
        {
          e = pni_decoder_decode_value(decoder, data, acode);
          if (e) return e;
        }
        pn_data_exit(data);

        pni_data_set_array_type(data, type);
      }
      return 0;
    case PNE_LIST8:
    case PNE_LIST32:
      err = pn_data_put_list(data);
      if (err) return err;
      break;
    case PNE_MAP8:
    case PNE_MAP32:
      err = pn_data_put_map(data);
      if (err) return err;
      break;
    default:
      return PN_ARG_ERR;
    }
    pn_data_enter(data);
    for (size_t i = 0; i < count; i++)
    {
      int e = pni_decoder_single(decoder, data);
      if (e) return e;
    }
    pn_data_exit(data);

    return 0;
  }
  default:
    return pn_error_format(pni_decoder_error(decoder), PN_ARG_ERR, "unrecognized typecode: %u", code);
  }

  return err;
}