in c/src/core/codec.c [845:1229]
int pn_data_vscan(pn_data_t *data, const char *fmt, va_list ap)
{
pn_data_rewind(data);
bool *scanarg = NULL;
bool at = false;
int level = 0;
int count_level = -1;
int resume_count = 0;
while (*fmt) {
char code = *(fmt++);
bool found = false;
pn_type_t type;
bool scanned = false;
bool suspend = resume_count > 0;
switch (code) {
case 'n':
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_NULL) {
scanned = true;
} else {
scanned = false;
}
if (resume_count && level == count_level) resume_count--;
break;
case 'o':
{
bool *value = va_arg(ap, bool *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_BOOL) {
*value = pn_data_get_bool(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'B':
{
uint8_t *value = va_arg(ap, uint8_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_UBYTE) {
*value = pn_data_get_ubyte(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'b':
{
int8_t *value = va_arg(ap, int8_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_BYTE) {
*value = pn_data_get_byte(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'H':
{
uint16_t *value = va_arg(ap, uint16_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_USHORT) {
*value = pn_data_get_ushort(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'h':
{
int16_t *value = va_arg(ap, int16_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_SHORT) {
*value = pn_data_get_short(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'I':
{
uint32_t *value = va_arg(ap, uint32_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_UINT) {
*value = pn_data_get_uint(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'i':
{
int32_t *value = va_arg(ap, int32_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_INT) {
*value = pn_data_get_int(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'c':
{
pn_char_t *value = va_arg(ap, pn_char_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_CHAR) {
*value = pn_data_get_char(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'L':
{
uint64_t *value = va_arg(ap, uint64_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_ULONG) {
*value = pn_data_get_ulong(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'l':
{
int64_t *value = va_arg(ap, int64_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_LONG) {
*value = pn_data_get_long(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 't':
{
pn_timestamp_t *value = va_arg(ap, pn_timestamp_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_TIMESTAMP) {
*value = pn_data_get_timestamp(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'f':
{
float *value = va_arg(ap, float *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_FLOAT) {
*value = pn_data_get_float(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'd':
{
double *value = va_arg(ap, double *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_DOUBLE) {
*value = pn_data_get_double(data);
scanned = true;
} else {
*value = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'z':
{
pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_BINARY) {
*bytes = pn_data_get_binary(data);
scanned = true;
} else {
bytes->start = 0;
bytes->size = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'S':
{
pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_STRING) {
*bytes = pn_data_get_string(data);
scanned = true;
} else {
bytes->start = 0;
bytes->size = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 's':
{
pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_SYMBOL) {
*bytes = pn_data_get_symbol(data);
scanned = true;
} else {
bytes->start = 0;
bytes->size = 0;
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'D':
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_DESCRIBED) {
pn_data_enter(data);
scanned = true;
} else {
if (!suspend) {
resume_count = 3;
count_level = level;
}
scanned = false;
}
if (resume_count && level == count_level) resume_count--;
break;
case '@':
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_ARRAY) {
pn_data_enter(data);
scanned = true;
at = true;
} else {
if (!suspend) {
resume_count = 3;
count_level = level;
}
scanned = false;
}
if (resume_count && level == count_level) resume_count--;
break;
case '[':
if (at) {
scanned = true;
at = false;
} else {
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_LIST) {
pn_data_enter(data);
scanned = true;
} else {
if (!suspend) {
resume_count = 1;
count_level = level;
}
scanned = false;
}
}
level++;
break;
case '{':
found = pn_scan_next(data, &type, suspend);
if (found && type == PN_MAP) {
pn_data_enter(data);
scanned = true;
} else {
if (resume_count) {
resume_count = 1;
count_level = level;
}
scanned = false;
}
level++;
break;
case ']':
case '}':
level--;
if (!suspend && !pn_data_exit(data))
return pn_error_format(pni_data_error(data), PN_ERR, "exit failed");
if (resume_count && level == count_level) resume_count--;
break;
case '.':
found = pn_scan_next(data, &type, suspend);
scanned = found;
if (resume_count && level == count_level) resume_count--;
break;
case '?':
if (!*fmt || *fmt == '?')
return pn_error_format(pni_data_error(data), PN_ARG_ERR, "codes must follow a ?");
scanarg = va_arg(ap, bool *);
break;
case 'C':
{
pn_data_t *dst = va_arg(ap, pn_data_t *);
if (!suspend) {
size_t old = pn_data_size(dst);
pni_node_t *next = pni_data_peek(data);
if (next && next->atom.type != PN_NULL) {
pn_data_narrow(data);
int err = pn_data_appendn(dst, data, 1);
pn_data_widen(data);
if (err) return err;
scanned = pn_data_size(dst) > old;
} else {
scanned = false;
}
pn_data_next(data);
} else {
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
case 'a':
{
pn_atom_t *dst = va_arg(ap, pn_atom_t *);
if (!suspend) {
pni_node_t *next = pni_data_peek(data);
if (next && next->atom.type != PN_NULL) {
*dst = next->atom;
} else {
scanned = false;
}
pn_data_next(data);
} else {
scanned = false;
}
}
if (resume_count && level == count_level) resume_count--;
break;
default:
return pn_error_format(pni_data_error(data), PN_ARG_ERR, "unrecognized scan code: 0x%.2X '%c'", code, code);
}
if (scanarg && code != '?') {
*scanarg = scanned;
scanarg = NULL;
}
}
return 0;
}