/** Get the next token. \a value points to the token and the return value
* is the length. Returns -1 on parse error, 0 on end of input. */
SPA_API_JSON int spa_json_next(struct spa_json * iter, constchar **value)
{ int utf8_remain = 0, err = 0; enum {
__NONE, __STRUCT, __BARE, __STRING, __UTF8, __ESC, __COMMENT,
__ARRAY_FLAG = 0x10, /* in array context */
__PREV_ARRAY_FLAG = 0x20, /* depth=0 array context flag */
__KEY_FLAG = 0x40, /* inside object key */
__SUB_FLAG = 0x80, /* not at top-level */
__FLAGS = 0xff0,
__ERROR_SYSTEM = SPA_JSON_ERROR_FLAG,
__ERROR_INVALID_ARRAY_SEPARATOR,
__ERROR_EXPECTED_OBJECT_KEY,
__ERROR_EXPECTED_OBJECT_VALUE,
__ERROR_TOO_DEEP_NESTING,
__ERROR_EXPECTED_ARRAY_CLOSE,
__ERROR_EXPECTED_OBJECT_CLOSE,
__ERROR_MISMATCHED_BRACKET,
__ERROR_ESCAPE_NOT_ALLOWED,
__ERROR_CHARACTERS_NOT_ALLOWED,
__ERROR_INVALID_ESCAPE,
__ERROR_INVALID_STATE,
__ERROR_UNFINISHED_STRING,
};
uint64_t array_stack[8] = {0}; /* array context flags of depths 1...512 */
*value = iter->cur;
if (iter->state & SPA_JSON_ERROR_FLAG) return -1;
for (; iter->cur < iter->end; iter->cur++) { unsignedchar cur = (unsignedchar)*iter->cur;
uint32_t flag;
#define _SPA_ERROR(reason) { err = __ERROR_ ## reason; goto error; }
again:
flag = iter->state & __FLAGS; switch (iter->state & ~__FLAGS) { case __NONE:
flag &= ~(__KEY_FLAG | __PREV_ARRAY_FLAG);
iter->state = __STRUCT | flag;
iter->depth = 0; goto again; case __STRUCT: switch (cur) { case'\0': case'\t': case' ': case'\r': case'\n': case',': continue; case':': case'=': if (flag & __ARRAY_FLAG)
_SPA_ERROR(INVALID_ARRAY_SEPARATOR); if (!(flag & __KEY_FLAG))
_SPA_ERROR(EXPECTED_OBJECT_KEY);
iter->state |= __SUB_FLAG; continue; case'#':
iter->state = __COMMENT | flag; continue; case'"': if (flag & __KEY_FLAG)
flag |= __SUB_FLAG; if (!(flag & __ARRAY_FLAG))
SPA_FLAG_UPDATE(flag, __KEY_FLAG, !(flag & __KEY_FLAG));
*value = iter->cur;
iter->state = __STRING | flag; continue; case'[': case'{': if (!(flag & __ARRAY_FLAG)) { /* At top-level we may be either in object context *orinsingle-itemcontext,andthenweneedto *acceptarray/objecthere.
*/ if ((iter->state & __SUB_FLAG) && !(flag & __KEY_FLAG))
_SPA_ERROR(EXPECTED_OBJECT_KEY);
SPA_FLAG_CLEAR(flag, __KEY_FLAG);
}
iter->state = __STRUCT | __SUB_FLAG | flag;
SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG, cur == '[');
/* We need to remember previous array state across calls *fordepth=0,sostorethatinstate.Othersbitsgoto *temporarystack.
*/ if (iter->depth == 0) {
SPA_FLAG_UPDATE(iter->state, __PREV_ARRAY_FLAG, flag & __ARRAY_FLAG);
} elseif (((iter->depth-1) >> 6) < SPA_N_ELEMENTS(array_stack)) {
uint64_t mask = 1ULL << ((iter->depth-1) & 0x3f);
SPA_FLAG_UPDATE(array_stack[(iter->depth-1) >> 6], mask, flag & __ARRAY_FLAG);
} else { /* too deep */
_SPA_ERROR(TOO_DEEP_NESTING);
}
*value = iter->cur; if (++iter->depth > 1) continue;
iter->cur++; return1; case'}': case']': if ((flag & __ARRAY_FLAG) && cur != ']')
_SPA_ERROR(EXPECTED_ARRAY_CLOSE); if (!(flag & __ARRAY_FLAG) && cur != '}')
_SPA_ERROR(EXPECTED_OBJECT_CLOSE); if (flag & __KEY_FLAG) { /* incomplete key-value pair */
_SPA_ERROR(EXPECTED_OBJECT_VALUE);
}
iter->state = __STRUCT | __SUB_FLAG | flag; if (iter->depth == 0) { if (iter->parent)
iter->parent->cur = iter->cur; else
_SPA_ERROR(MISMATCHED_BRACKET); return0;
}
--iter->depth; if (iter->depth == 0) {
SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG, flag & __PREV_ARRAY_FLAG);
} elseif (((iter->depth-1) >> 6) < SPA_N_ELEMENTS(array_stack)) {
uint64_t mask = 1ULL << ((iter->depth-1) & 0x3f);
SPA_FLAG_UPDATE(iter->state, __ARRAY_FLAG,
SPA_FLAG_IS_SET(array_stack[(iter->depth-1) >> 6], mask));
} else { /* too deep */
_SPA_ERROR(TOO_DEEP_NESTING);
} continue; case'\\': /* disallow bare escape */
_SPA_ERROR(ESCAPE_NOT_ALLOWED); default: /* allow bare ascii */ if (!(cur >= 32 && cur <= 126))
_SPA_ERROR(CHARACTERS_NOT_ALLOWED); if (flag & __KEY_FLAG)
flag |= __SUB_FLAG; if (!(flag & __ARRAY_FLAG))
SPA_FLAG_UPDATE(flag, __KEY_FLAG, !(flag & __KEY_FLAG));
*value = iter->cur;
iter->state = __BARE | flag;
} continue; case __BARE: switch (cur) { case'\0': case'\t': case' ': case'\r': case'\n': case'"': case'#': case':': case',': case'=': case']': case'}':
iter->state = __STRUCT | flag; if (iter->depth > 0) goto again; return iter->cur - *value; case'\\': /* disallow bare escape */
_SPA_ERROR(ESCAPE_NOT_ALLOWED); default: /* allow bare ascii */ if (cur >= 32 && cur <= 126) continue;
}
_SPA_ERROR(CHARACTERS_NOT_ALLOWED); case __STRING: switch (cur) { case'\\':
iter->state = __ESC | flag; continue; case'"':
iter->state = __STRUCT | flag; if (iter->depth > 0) continue; return ++iter->cur - *value; case240 ... 247:
utf8_remain++;
SPA_FALLTHROUGH; case224 ... 239:
utf8_remain++;
SPA_FALLTHROUGH; case192 ... 223:
utf8_remain++;
iter->state = __UTF8 | flag; continue; default: if (cur >= 32 && cur <= 127) continue;
}
_SPA_ERROR(CHARACTERS_NOT_ALLOWED); case __UTF8: switch (cur) { case128 ... 191: if (--utf8_remain == 0)
iter->state = __STRING | flag; continue;
}
_SPA_ERROR(CHARACTERS_NOT_ALLOWED); case __ESC: switch (cur) { case'"': case'\\': case'/': case'b': case'f': case'n': case'r': case't': case'u':
iter->state = __STRING | flag; continue;
}
_SPA_ERROR(INVALID_ESCAPE); case __COMMENT: switch (cur) { case'\n': case'\r':
iter->state = __STRUCT | flag;
} break; default:
_SPA_ERROR(INVALID_STATE);
}
} if (iter->depth != 0 || iter->parent)
_SPA_ERROR(MISMATCHED_BRACKET);
switch (iter->state & ~__FLAGS) { case __STRING: case __UTF8: case __ESC: /* string/escape not closed */
_SPA_ERROR(UNFINISHED_STRING); case __COMMENT: /* trailing comment */ return0;
}
SPA_API_JSON int spa_json_parse_bool(constchar *val, int len, bool *result)
{ if ((*result = spa_json_is_true(val, len))) return1; if (!(*result = !spa_json_is_false(val, len))) return1; return -1;
}
/* string */
SPA_API_JSON bool spa_json_is_string(constchar *val, int len)
{ return len > 1 && *val == '"';
}
SPA_API_JSON int spa_json_parse_hex(constchar *p, int num, uint32_t *res)
{ int i;
*res = 0; for (i = 0; i < num; i++) { char v = p[i]; if (v >= '0' && v <= '9')
v = v - '0'; elseif (v >= 'a' && v <= 'f')
v = v - 'a' + 10; elseif (v >= 'A' && v <= 'F')
v = v - 'A' + 10; else return -1;
*res = (*res << 4) | v;
} return1;
}
SPA_API_JSON int spa_json_parse_stringn(constchar *val, int len, char *result, int maxlen)
{ constchar *p; if (maxlen <= len) return -ENOSPC; if (!spa_json_is_string(val, len)) { if (result != val)
memmove(result, val, len);
result += len;
} else { for (p = val+1; p < val + len; p++) { if (*p == '\\') {
p++; if (*p == 'n')
*result++ = '\n'; elseif (*p == 'r')
*result++ = '\r'; elseif (*p == 'b')
*result++ = '\b'; elseif (*p == 't')
*result++ = '\t'; elseif (*p == 'f')
*result++ = '\f'; elseif (*p == 'u') {
uint8_t prefix[] = { 0, 0xc0, 0xe0, 0xf0 };
uint32_t idx, n, v, cp, enc[] = { 0x80, 0x800, 0x10000 }; if (val + len - p < 5 ||
spa_json_parse_hex(p+1, 4, &cp) < 0) {
*result++ = *p; continue;
}
p += 4;
if (cp >= 0xd800 && cp <= 0xdbff) { if (val + len - p < 7 ||
p[1] != '\\' || p[2] != 'u' ||
spa_json_parse_hex(p+3, 4, &v) < 0 ||
v < 0xdc00 || v > 0xdfff) continue;
p += 6;
cp = 0x010000 + (((cp & 0x3ff) << 10) | (v & 0x3ff));
} elseif (cp >= 0xdc00 && cp <= 0xdfff) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.