Add support for JSON sequence MIME type

Per draft-ietf-json-text-sequence-07 (which soon will be published as an
RFC).
This commit is contained in:
Nicolas Williams committed 2014-10-12 08:44:40 -05:00
1 parent 3411167c03
commit 89791a000b
5 files changed
+141 -21

No files matched your search

+63 -9
View File
@@ -24,6 +24,8 @@ struct jv_parser {
int curr_buf_is_partial;
unsigned bom_strip_position;
int flags;
jv* stack;
int stackpos;
int stacklen;
@@ -40,12 +42,15 @@ struct jv_parser {
enum {
JV_PARSER_NORMAL,
JV_PARSER_STRING,
JV_PARSER_STRING_ESCAPE
JV_PARSER_STRING_ESCAPE,
JV_PARSER_WAITING_FOR_RS // parse error, waiting for RS
} st;
unsigned int last_ch_was_ws:1;
};
static void parser_init(struct jv_parser* p) {
p->flags = 0;
p->stack = 0;
p->stacklen = p->stackpos = 0;
p->next = jv_invalid();
@@ -60,10 +65,18 @@ static void parser_init(struct jv_parser* p) {
jvp_dtoa_context_init(&p->dtoa);
}
static void parser_free(struct jv_parser* p) {
static void parser_reset(struct jv_parser* p) {
jv_free(p->next);
p->next = jv_invalid();
for (int i=0; i<p->stackpos; i++)
jv_free(p->stack[i]);
p->stackpos = 0;
p->tokenpos = 0;
p->st = JV_PARSER_NORMAL;
}
static void parser_free(struct jv_parser* p) {
parser_reset(p);
jv_mem_free(p->stack);
jv_mem_free(p->tokenbuf);
jvp_dtoa_context_free(&p->dtoa);
@@ -330,9 +343,26 @@ static pfunc scan(struct jv_parser* p, char ch, jv* out) {
p->line++;
p->column = 0;
}
if (ch == '\036' /* ASCII RS; see draft-ietf-json-sequence-07 */) {
TRY(check_literal(p));
if (p->st == JV_PARSER_NORMAL && check_done(p, out)) {
if ((p->flags & JV_PARSE_SEQ) && !p->last_ch_was_ws && jv_get_kind(*out) == JV_KIND_NUMBER) {
jv_free(*out);
*out = jv_invalid();
return "Potentially truncated top-level numeric value";
}
return OK;
}
parser_reset(p);
*out = jv_invalid();
return "Truncated value";
}
presult answer = 0;
p->last_ch_was_ws = 0;
if (p->st == JV_PARSER_NORMAL) {
chclass cls = classify(ch);
if (cls == WHITESPACE)
p->last_ch_was_ws = 1;
if (cls != LITERAL) {
TRY(check_literal(p));
if (check_done(p, out)) answer = OK;
@@ -373,6 +403,7 @@ static pfunc scan(struct jv_parser* p, char ch, jv* out) {
struct jv_parser* jv_parser_new(int flags) {
struct jv_parser* p = jv_mem_alloc(sizeof(struct jv_parser));
parser_init(p);
p->flags = flags;
return p;
}
@@ -412,14 +443,22 @@ jv jv_parser_next(struct jv_parser* p) {
assert(p->curr_buf && "a buffer must be provided");
if (p->bom_strip_position == 0xff) return jv_invalid_with_msg(jv_string("Malformed BOM"));
jv value;
char ch;
presult msg = 0;
while (!msg && p->curr_buf_pos < p->curr_buf_length) {
char ch = p->curr_buf[p->curr_buf_pos++];
ch = p->curr_buf[p->curr_buf_pos++];
if (ch != '\036' && p->st == JV_PARSER_WAITING_FOR_RS)
continue; // need to resync, wait for RS
msg = scan(p, ch, &value);
}
if (msg == OK) {
return value;
} else if (msg) {
parser_reset(p);
if (ch != '\036' && (p->flags & JV_PARSE_SEQ)) {
p->st = JV_PARSER_WAITING_FOR_RS;
return jv_invalid_with_msg(jv_string_fmt("%s at line %d, column %d (need RS to resync)", msg, p->line, p->column));
}
return jv_invalid_with_msg(jv_string_fmt("%s at line %d, column %d", msg, p->line, p->column));
} else if (p->curr_buf_is_partial) {
assert(p->curr_buf_pos == p->curr_buf_length);
@@ -428,16 +467,31 @@ jv jv_parser_next(struct jv_parser* p) {
} else {
assert(p->curr_buf_pos == p->curr_buf_length);
// at EOF
if (p->st != JV_PARSER_NORMAL)
return jv_invalid_with_msg(jv_string("Unfinished string"));
if ((msg = check_literal(p)))
return jv_invalid_with_msg(jv_string(msg));
if (p->stackpos != 0)
return jv_invalid_with_msg(jv_string("Unfinished JSON term"));
if (p->st != JV_PARSER_WAITING_FOR_RS) {
if (p->st != JV_PARSER_NORMAL) {
parser_reset(p);
p->st = JV_PARSER_WAITING_FOR_RS;
return jv_invalid_with_msg(jv_string("Unfinished string"));
}
if ((msg = check_literal(p))) {
parser_reset(p);
p->st = JV_PARSER_WAITING_FOR_RS;
return jv_invalid_with_msg(jv_string(msg));
}
if (p->stackpos != 0) {
parser_reset(p);
p->st = JV_PARSER_WAITING_FOR_RS;
return jv_invalid_with_msg(jv_string("Unfinished JSON term"));
}
}
// p->next is either invalid (nothing here but no syntax error)
// or valid (this is the value). either way it's the thing to return
value = p->next;
p->next = jv_invalid();
if ((p->flags & JV_PARSE_SEQ) && !p->last_ch_was_ws && jv_get_kind(value) == JV_KIND_NUMBER) {
jv_free(value);
return jv_invalid_with_msg(jv_string("Potentially truncated top-level numeric value"));
}
return value;
}
}