Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
97b663a8
Commit
97b663a8
authored
Jan 10, 2015
by
Chris Fallin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update upb amalgamation.
parent
4c922897
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
756 additions
and
409 deletions
+756
-409
upb.c
ruby/ext/google/protobuf_c/upb.c
+738
-402
upb.h
ruby/ext/google/protobuf_c/upb.h
+18
-7
No files found.
ruby/ext/google/protobuf_c/upb.c
View file @
97b663a8
...
...
@@ -3416,6 +3416,8 @@ char *upb_strdup(const char *s) {
}
char
*
upb_strdup2
(
const
char
*
s
,
size_t
len
)
{
// Prevent overflow errors.
if
(
len
==
SIZE_MAX
)
return
NULL
;
// Always null-terminate, even if binary data; but don't rely on the input to
// have a null-terminating byte since it may be a raw binary buffer.
size_t
n
=
len
+
1
;
...
...
@@ -4230,8 +4232,10 @@ static void nullz(upb_status *status) {
}
void
upb_status_clear
(
upb_status
*
status
)
{
upb_status
blank
=
UPB_STATUS_INIT
;
upb_status_copy
(
status
,
&
blank
);
if
(
!
status
)
return
;
status
->
ok_
=
true
;
status
->
code_
=
0
;
status
->
msg
[
0
]
=
'\0'
;
}
bool
upb_ok
(
const
upb_status
*
status
)
{
return
status
->
ok_
;
}
...
...
@@ -5998,6 +6002,7 @@ static void putop(compiler *c, opcode op, ...) {
case
OP_SETDELIM
:
case
OP_HALT
:
case
OP_RET
:
case
OP_DISPATCH
:
put32
(
c
,
op
);
break
;
case
OP_PARSE_DOUBLE
:
...
...
@@ -6078,7 +6083,7 @@ const char *upb_pbdecoder_getopname(unsigned int op) {
OP
(
ENDSUBMSG
),
OP
(
STARTSTR
),
OP
(
STRING
),
OP
(
ENDSTR
),
OP
(
CALL
),
OP
(
RET
),
OP
(
PUSHLENDELIM
),
OP
(
PUSHTAGDELIM
),
OP
(
SETDELIM
),
OP
(
CHECKDELIM
),
OP
(
BRANCH
),
OP
(
TAG1
),
OP
(
TAG2
),
OP
(
TAGN
),
OP
(
SETDISPATCH
),
OP
(
POP
),
OP
(
SETBIGGROUPNUM
),
OP
(
HALT
),
OP
(
SETBIGGROUPNUM
),
OP
(
DISPATCH
),
OP
(
HALT
),
};
return
op
>
OP_HALT
?
names
[
0
]
:
names
[
op
];
#undef OP
...
...
@@ -6110,6 +6115,7 @@ static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) {
upb_handlers_msgdef
(
method
->
dest_handlers_
)));
break
;
}
case
OP_DISPATCH
:
case
OP_STARTMSG
:
case
OP_ENDMSG
:
case
OP_PUSHLENDELIM
:
...
...
@@ -6455,6 +6461,7 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) {
putop
(
c
,
OP_SETDISPATCH
,
&
method
->
dispatch
);
putsel
(
c
,
OP_STARTMSG
,
UPB_STARTMSG_SELECTOR
,
h
);
label
(
c
,
LABEL_FIELD
);
uint32_t
*
start_pc
=
c
->
pc
;
upb_msg_iter
i
;
for
(
upb_msg_begin
(
&
i
,
md
);
!
upb_msg_done
(
&
i
);
upb_msg_next
(
&
i
))
{
const
upb_fielddef
*
f
=
upb_msg_iter_field
(
&
i
);
...
...
@@ -6470,8 +6477,18 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) {
}
}
// If there were no fields, or if no handlers were defined, we need to
// generate a non-empty loop body so that we can at least dispatch for unknown
// fields and check for the end of the message.
if
(
c
->
pc
==
start_pc
)
{
// Check for end-of-message.
putop
(
c
,
OP_CHECKDELIM
,
LABEL_ENDMSG
);
// Unconditionally dispatch.
putop
(
c
,
OP_DISPATCH
,
0
);
}
// For now we just loop back to the last field of the message (or if none,
// the DISPATCH opcode for the message.
// the DISPATCH opcode for the message
)
.
putop
(
c
,
OP_BRANCH
,
-
LABEL_FIELD
);
// Insert both a label and a dispatch table entry for this end-of-msg.
...
...
@@ -7455,6 +7472,9 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
if
(
result
==
DECODE_MISMATCH
)
goto
badtag
;
if
(
result
>=
0
)
return
result
;
})
VMCASE
(
OP_DISPATCH
,
{
CHECK_RETURN
(
dispatch
(
d
));
})
VMCASE
(
OP_HALT
,
{
return
size
;
})
...
...
@@ -7513,7 +7533,8 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) {
// Rewind from OP_TAG* to OP_CHECKDELIM.
assert
(
getop
(
*
d
->
pc
)
==
OP_TAG1
||
getop
(
*
d
->
pc
)
==
OP_TAG2
||
getop
(
*
d
->
pc
)
==
OP_TAGN
);
getop
(
*
d
->
pc
)
==
OP_TAGN
||
getop
(
*
d
->
pc
==
OP_DISPATCH
));
d
->
pc
=
p
;
}
upb_pbdecoder_decode
(
closure
,
handler_data
,
&
dummy
,
0
,
NULL
);
...
...
@@ -8648,6 +8669,9 @@ upb_decoderet upb_vdecode_max8_wright(upb_decoderet r) {
#define PARSER_CHECK_RETURN(x) if (!(x)) return false
// Used to signal that a capture has been suspended.
static
char
suspend_capture
;
static
upb_selector_t
getsel_for_handlertype
(
upb_json_parser
*
p
,
upb_handlertype_t
type
)
{
upb_selector_t
sel
;
...
...
@@ -8661,41 +8685,6 @@ static upb_selector_t parser_getsel(upb_json_parser *p) {
p
,
upb_handlers_getprimitivehandlertype
(
p
->
top
->
f
));
}
static
void
start_member
(
upb_json_parser
*
p
)
{
assert
(
!
p
->
top
->
f
);
assert
(
!
p
->
accumulated
);
p
->
accumulated_len
=
0
;
}
static
bool
end_member
(
upb_json_parser
*
p
)
{
// TODO(haberman): support keys that span buffers or have escape sequences.
assert
(
!
p
->
top
->
f
);
assert
(
p
->
accumulated
);
const
upb_fielddef
*
f
=
upb_msgdef_ntof
(
p
->
top
->
m
,
p
->
accumulated
,
p
->
accumulated_len
);
if
(
!
f
)
{
// TODO(haberman): Ignore unknown fields if requested/configured to do so.
upb_status_seterrf
(
p
->
status
,
"No such field: %.*s
\n
"
,
(
int
)
p
->
accumulated_len
,
p
->
accumulated
);
return
false
;
}
p
->
top
->
f
=
f
;
p
->
accumulated
=
NULL
;
return
true
;
}
static
void
start_object
(
upb_json_parser
*
p
)
{
upb_sink_startmsg
(
&
p
->
top
->
sink
);
}
static
void
end_object
(
upb_json_parser
*
p
)
{
upb_status
status
;
upb_sink_endmsg
(
&
p
->
top
->
sink
,
&
status
);
}
static
bool
check_stack
(
upb_json_parser
*
p
)
{
if
((
p
->
top
+
1
)
==
p
->
limit
)
{
upb_status_seterrmsg
(
p
->
status
,
"Nesting too deep"
);
...
...
@@ -8705,83 +8694,28 @@ static bool check_stack(upb_json_parser *p) {
return
true
;
}
static
bool
start_subobject
(
upb_json_parser
*
p
)
{
assert
(
p
->
top
->
f
);
if
(
!
upb_fielddef_issubmsg
(
p
->
top
->
f
))
{
upb_status_seterrf
(
p
->
status
,
"Object specified for non-message/group field: %s"
,
upb_fielddef_name
(
p
->
top
->
f
));
return
false
;
}
if
(
!
check_stack
(
p
))
return
false
;
upb_jsonparser_frame
*
inner
=
p
->
top
+
1
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STARTSUBMSG
);
upb_sink_startsubmsg
(
&
p
->
top
->
sink
,
sel
,
&
inner
->
sink
);
inner
->
m
=
upb_fielddef_msgsubdef
(
p
->
top
->
f
);
inner
->
f
=
NULL
;
p
->
top
=
inner
;
// There are GCC/Clang built-ins for overflow checking which we could start
// using if there was any performance benefit to it.
static
bool
checked_add
(
size_t
a
,
size_t
b
,
size_t
*
c
)
{
if
(
SIZE_MAX
-
a
<
b
)
return
false
;
*
c
=
a
+
b
;
return
true
;
}
static
void
end_subobject
(
upb_json_parser
*
p
)
{
p
->
top
--
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_ENDSUBMSG
);
upb_sink_endsubmsg
(
&
p
->
top
->
sink
,
sel
);
}
static
bool
start_array
(
upb_json_parser
*
p
)
{
assert
(
p
->
top
->
f
);
if
(
!
upb_fielddef_isseq
(
p
->
top
->
f
))
{
upb_status_seterrf
(
p
->
status
,
"Array specified for non-repeated field: %s"
,
upb_fielddef_name
(
p
->
top
->
f
));
return
false
;
static
size_t
saturating_multiply
(
size_t
a
,
size_t
b
)
{
// size_t is unsigned, so this is defined behavior even on overflow.
size_t
ret
=
a
*
b
;
if
(
b
!=
0
&&
ret
/
b
!=
a
)
{
ret
=
SIZE_MAX
;
}
if
(
!
check_stack
(
p
))
return
false
;
upb_jsonparser_frame
*
inner
=
p
->
top
+
1
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STARTSEQ
);
upb_sink_startseq
(
&
p
->
top
->
sink
,
sel
,
&
inner
->
sink
);
inner
->
m
=
p
->
top
->
m
;
inner
->
f
=
p
->
top
->
f
;
p
->
top
=
inner
;
return
true
;
}
static
void
end_array
(
upb_json_parser
*
p
)
{
assert
(
p
->
top
>
p
->
stack
);
p
->
top
--
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_ENDSEQ
);
upb_sink_endseq
(
&
p
->
top
->
sink
,
sel
);
return
ret
;
}
static
void
clear_member
(
upb_json_parser
*
p
)
{
p
->
top
->
f
=
NULL
;
}
static
bool
parser_putbool
(
upb_json_parser
*
p
,
bool
val
)
{
if
(
upb_fielddef_type
(
p
->
top
->
f
)
!=
UPB_TYPE_BOOL
)
{
upb_status_seterrf
(
p
->
status
,
"Boolean value specified for non-bool field: %s"
,
upb_fielddef_name
(
p
->
top
->
f
));
return
false
;
}
bool
ok
=
upb_sink_putbool
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
UPB_ASSERT_VAR
(
ok
,
ok
);
return
true
;
}
/* Base64 decoding ************************************************************/
static
void
start_text
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
p
->
text_begin
=
ptr
;
}
// TODO(haberman): make this streaming.
static
const
signed
char
b64table
[]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
...
...
@@ -8901,148 +8835,231 @@ badpadding:
return
false
;
}
static
bool
end_text
(
upb_json_parser
*
p
,
const
char
*
ptr
,
bool
is_num
)
{
assert
(
!
p
->
accumulated
);
// TODO: handle this case.
p
->
accumulated
=
p
->
text_begin
;
p
->
accumulated_len
=
ptr
-
p
->
text_begin
;
if
(
p
->
top
->
f
&&
upb_fielddef_isstring
(
p
->
top
->
f
))
{
// This is a string field (as opposed to a member name).
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STRING
);
if
(
upb_fielddef_type
(
p
->
top
->
f
)
==
UPB_TYPE_BYTES
)
{
PARSER_CHECK_RETURN
(
base64_push
(
p
,
sel
,
p
->
accumulated
,
p
->
accumulated_len
));
}
else
{
upb_sink_putstring
(
&
p
->
top
->
sink
,
sel
,
p
->
accumulated
,
p
->
accumulated_len
,
NULL
);
}
/* Accumulate buffer **********************************************************/
// Functionality for accumulating a buffer.
//
// Some parts of the parser need an entire value as a contiguous string. For
// example, to look up a member name in a hash table, or to turn a string into
// a number, the relevant library routines need the input string to be in
// contiguous memory, even if the value spanned two or more buffers in the
// input. These routines handle that.
//
// In the common case we can just point to the input buffer to get this
// contiguous string and avoid any actual copy. So we optimistically begin
// this way. But there are a few cases where we must instead copy into a
// separate buffer:
//
// 1. The string was not contiguous in the input (it spanned buffers).
//
// 2. The string included escape sequences that need to be interpreted to get
// the true value in a contiguous buffer.
static
void
assert_accumulate_empty
(
upb_json_parser
*
p
)
{
assert
(
p
->
accumulated
==
NULL
);
assert
(
p
->
accumulated_len
==
0
);
}
static
void
accumulate_clear
(
upb_json_parser
*
p
)
{
p
->
accumulated
=
NULL
;
}
else
if
(
p
->
top
->
f
&&
upb_fielddef_type
(
p
->
top
->
f
)
==
UPB_TYPE_ENUM
&&
!
is_num
)
{
p
->
accumulated_len
=
0
;
}
// Enum case: resolve enum symbolic name to integer value.
const
upb_enumdef
*
enumdef
=
(
const
upb_enumdef
*
)
upb_fielddef_subdef
(
p
->
top
->
f
);
// Used internally by accumulate_append().
static
bool
accumulate_realloc
(
upb_json_parser
*
p
,
size_t
need
)
{
size_t
new_size
=
UPB_MAX
(
p
->
accumulate_buf_size
,
128
);
while
(
new_size
<
need
)
{
new_size
=
saturating_multiply
(
new_size
,
2
);
}
int32_t
int_val
=
0
;
if
(
upb_enumdef_ntoi
(
enumdef
,
p
->
accumulated
,
p
->
accumulated_len
,
&
int_val
))
{
upb_selector_t
sel
=
parser_getsel
(
p
);
upb_sink_putint32
(
&
p
->
top
->
sink
,
sel
,
int_val
);
}
else
{
upb_status_seterrmsg
(
p
->
status
,
"Enum value name unknown"
);
void
*
mem
=
realloc
(
p
->
accumulate_buf
,
new_size
);
if
(
!
mem
)
{
upb_status_seterrmsg
(
p
->
status
,
"Out of memory allocating buffer."
);
return
false
;
}
p
->
accumulated
=
NULL
;
}
p
->
accumulate_buf
=
mem
;
p
->
accumulate_buf_size
=
new_size
;
return
true
;
}
static
bool
start_stringval
(
upb_json_parser
*
p
)
{
assert
(
p
->
top
->
f
);
if
(
upb_fielddef_isstring
(
p
->
top
->
f
))
{
if
(
!
check_stack
(
p
))
return
false
;
// Logically appends the given data to the append buffer.
// If "can_alias" is true, we will try to avoid actually copying, but the buffer
// must be valid until the next accumulate_append() call (if any).
static
bool
accumulate_append
(
upb_json_parser
*
p
,
const
char
*
buf
,
size_t
len
,
bool
can_alias
)
{
if
(
!
p
->
accumulated
&&
can_alias
)
{
p
->
accumulated
=
buf
;
p
->
accumulated_len
=
len
;
return
true
;
}
// Start a new parser frame: parser frames correspond one-to-one with
// handler frames, and string events occur in a sub-frame.
upb_jsonparser_frame
*
inner
=
p
->
top
+
1
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STARTSTR
);
upb_sink_startstr
(
&
p
->
top
->
sink
,
sel
,
0
,
&
inner
->
sink
);
inner
->
m
=
p
->
top
->
m
;
inner
->
f
=
p
->
top
->
f
;
p
->
top
=
inner
;
size_t
need
;
if
(
!
checked_add
(
p
->
accumulated_len
,
len
,
&
need
))
{
upb_status_seterrmsg
(
p
->
status
,
"Integer overflow."
);
return
false
;
}
return
true
;
}
else
if
(
upb_fielddef_type
(
p
->
top
->
f
)
==
UPB_TYPE_ENUM
)
{
// Do nothing -- symbolic enum names in quotes remain in the
// current parser frame.
return
true
;
}
else
{
upb_status_seterrf
(
p
->
status
,
"String specified for non-string/non-enum field: %s"
,
upb_fielddef_name
(
p
->
top
->
f
));
if
(
need
>
p
->
accumulate_buf_size
&&
!
accumulate_realloc
(
p
,
need
))
{
return
false
;
}
if
(
p
->
accumulated
!=
p
->
accumulate_buf
)
{
memcpy
(
p
->
accumulate_buf
,
p
->
accumulated
,
p
->
accumulated_len
);
p
->
accumulated
=
p
->
accumulate_buf
;
}
memcpy
(
p
->
accumulate_buf
+
p
->
accumulated_len
,
buf
,
len
);
p
->
accumulated_len
+=
len
;
return
true
;
}
static
void
end_stringval
(
upb_json_parser
*
p
)
{
if
(
upb_fielddef_isstring
(
p
->
top
->
f
))
{
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_ENDSTR
);
upb_sink_endstr
(
&
p
->
top
->
sink
,
sel
);
p
->
top
--
;
}
// Returns a pointer to the data accumulated since the last accumulate_clear()
// call, and writes the length to *len. This with point either to the input
// buffer or a temporary accumulate buffer.
static
const
char
*
accumulate_getptr
(
upb_json_parser
*
p
,
size_t
*
len
)
{
assert
(
p
->
accumulated
);
*
len
=
p
->
accumulated_len
;
return
p
->
accumulated
;
}
static
void
start_number
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
start_text
(
p
,
ptr
);
assert
(
p
->
accumulated
==
NULL
);
/* Mult-part text data ********************************************************/
// When we have text data in the input, it can often come in multiple segments.
// For example, there may be some raw string data followed by an escape
// sequence. The two segments are processed with different logic. Also buffer
// seams in the input can cause multiple segments.
//
// As we see segments, there are two main cases for how we want to process them:
//
// 1. we want to push the captured input directly to string handlers.
//
// 2. we need to accumulate all the parts into a contiguous buffer for further
// processing (field name lookup, string->number conversion, etc).
// This is the set of states for p->multipart_state.
enum
{
// We are not currently processing multipart data.
MULTIPART_INACTIVE
=
0
,
// We are processing multipart data by accumulating it into a contiguous
// buffer.
MULTIPART_ACCUMULATE
=
1
,
// We are processing multipart data by pushing each part directly to the
// current string handlers.
MULTIPART_PUSHEAGERLY
=
2
};
// Start a multi-part text value where we accumulate the data for processing at
// the end.
static
void
multipart_startaccum
(
upb_json_parser
*
p
)
{
assert_accumulate_empty
(
p
);
assert
(
p
->
multipart_state
==
MULTIPART_INACTIVE
);
p
->
multipart_state
=
MULTIPART_ACCUMULATE
;
}
static
void
end_number
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
end_text
(
p
,
ptr
,
true
);
const
char
*
myend
=
p
->
accumulated
+
p
->
accumulated_len
;
char
*
end
;
// Start a multi-part text value where we immediately push text data to a string
// value with the given selector.
static
void
multipart_start
(
upb_json_parser
*
p
,
upb_selector_t
sel
)
{
assert_accumulate_empty
(
p
);
assert
(
p
->
multipart_state
==
MULTIPART_INACTIVE
);
p
->
multipart_state
=
MULTIPART_PUSHEAGERLY
;
p
->
string_selector
=
sel
;
}
switch
(
upb_fielddef_type
(
p
->
top
->
f
))
{
case
UPB_TYPE_ENUM
:
case
UPB_TYPE_INT32
:
{
long
val
=
strtol
(
p
->
accumulated
,
&
end
,
0
);
if
(
val
>
INT32_MAX
||
val
<
INT32_MIN
||
errno
==
ERANGE
||
end
!=
myend
)
assert
(
false
);
else
upb_sink_putint32
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
case
UPB_TYPE_INT64
:
{
long
long
val
=
strtoll
(
p
->
accumulated
,
&
end
,
0
);
if
(
val
>
INT64_MAX
||
val
<
INT64_MIN
||
errno
==
ERANGE
||
end
!=
myend
)
assert
(
false
);
else
upb_sink_putint64
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
static
bool
multipart_text
(
upb_json_parser
*
p
,
const
char
*
buf
,
size_t
len
,
bool
can_alias
)
{
switch
(
p
->
multipart_state
)
{
case
MULTIPART_INACTIVE
:
upb_status_seterrmsg
(
p
->
status
,
"Internal error: unexpected state MULTIPART_INACTIVE"
);
return
false
;
case
MULTIPART_ACCUMULATE
:
if
(
!
accumulate_append
(
p
,
buf
,
len
,
can_alias
))
{
return
false
;
}
case
UPB_TYPE_UINT32
:
{
unsigned
long
val
=
strtoul
(
p
->
accumulated
,
&
end
,
0
);
if
(
val
>
UINT32_MAX
||
errno
==
ERANGE
||
end
!=
myend
)
assert
(
false
);
else
upb_sink_putuint32
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
case
UPB_TYPE_UINT64
:
{
unsigned
long
long
val
=
strtoull
(
p
->
accumulated
,
&
end
,
0
);
if
(
val
>
UINT64_MAX
||
errno
==
ERANGE
||
end
!=
myend
)
assert
(
false
);
else
upb_sink_putuint64
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
case
MULTIPART_PUSHEAGERLY
:
{
const
upb_bufhandle
*
handle
=
can_alias
?
p
->
handle
:
NULL
;
upb_sink_putstring
(
&
p
->
top
->
sink
,
p
->
string_selector
,
buf
,
len
,
handle
);
break
;
}
case
UPB_TYPE_DOUBLE
:
{
double
val
=
strtod
(
p
->
accumulated
,
&
end
);
if
(
errno
==
ERANGE
||
end
!=
myend
)
assert
(
false
);
else
upb_sink_putdouble
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
case
UPB_TYPE_FLOAT
:
{
float
val
=
strtof
(
p
->
accumulated
,
&
end
);
if
(
errno
==
ERANGE
||
end
!=
myend
)
assert
(
false
);
else
upb_sink_putfloat
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
return
true
;
}
// Note: this invalidates the accumulate buffer! Call only after reading its
// contents.
static
void
multipart_end
(
upb_json_parser
*
p
)
{
assert
(
p
->
multipart_state
!=
MULTIPART_INACTIVE
);
p
->
multipart_state
=
MULTIPART_INACTIVE
;
accumulate_clear
(
p
);
}
/* Input capture **************************************************************/
// Functionality for capturing a region of the input as text. Gracefully
// handles the case where a buffer seam occurs in the middle of the captured
// region.
static
void
capture_begin
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
assert
(
p
->
multipart_state
!=
MULTIPART_INACTIVE
);
assert
(
p
->
capture
==
NULL
);
p
->
capture
=
ptr
;
}
static
bool
capture_end
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
assert
(
p
->
capture
);
if
(
multipart_text
(
p
,
p
->
capture
,
ptr
-
p
->
capture
,
true
))
{
p
->
capture
=
NULL
;
return
true
;
}
else
{
return
false
;
}
default:
assert
(
false
);
}
// This is called at the end of each input buffer (ie. when we have hit a
// buffer seam). If we are in the middle of capturing the input, this
// processes the unprocessed capture region.
static
void
capture_suspend
(
upb_json_parser
*
p
,
const
char
**
ptr
)
{
if
(
!
p
->
capture
)
return
;
if
(
multipart_text
(
p
,
p
->
capture
,
*
ptr
-
p
->
capture
,
false
))
{
// We use this as a signal that we were in the middle of capturing, and
// that capturing should resume at the beginning of the next buffer.
//
// We can't use *ptr here, because we have no guarantee that this pointer
// will be valid when we resume (if the underlying memory is freed, then
// using the pointer at all, even to compare to NULL, is likely undefined
// behavior).
p
->
capture
=
&
suspend_capture
;
}
else
{
// Need to back up the pointer to the beginning of the capture, since
// we were not able to actually preserve it.
*
ptr
=
p
->
capture
;
}
}
p
->
accumulated
=
NULL
;
static
void
capture_resume
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
if
(
p
->
capture
)
{
assert
(
p
->
capture
==
&
suspend_capture
);
p
->
capture
=
ptr
;
}
}
/* Callbacks from the parser **************************************************/
// These are the functions called directly from the parser itself.
// We define these in the same order as their declarations in the parser.
static
char
escape_char
(
char
in
)
{
switch
(
in
)
{
case
'r'
:
return
'\r'
;
...
...
@@ -9059,35 +9076,33 @@ static char escape_char(char in) {
}
}
static
void
escape
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
static
bool
escape
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
char
ch
=
escape_char
(
*
ptr
);
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STRING
);
upb_sink_putstring
(
&
p
->
top
->
sink
,
sel
,
&
ch
,
1
,
NULL
);
return
multipart_text
(
p
,
&
ch
,
1
,
false
);
}
static
void
start_hex
(
upb_json_parser
*
p
)
{
p
->
digit
=
0
;
}
static
uint8_t
hexdigit
(
char
ch
)
{
static
void
hexdigit
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
char
ch
=
*
ptr
;
p
->
digit
<<=
4
;
if
(
ch
>=
'0'
&&
ch
<=
'9'
)
{
return
ch
-
'0'
;
p
->
digit
+=
(
ch
-
'0'
)
;
}
else
if
(
ch
>=
'a'
&&
ch
<=
'f'
)
{
return
ch
-
'a'
+
10
;
p
->
digit
+=
((
ch
-
'a'
)
+
10
)
;
}
else
{
assert
(
ch
>=
'A'
&&
ch
<=
'F'
);
return
ch
-
'A'
+
10
;
p
->
digit
+=
((
ch
-
'A'
)
+
10
)
;
}
}
static
void
start_hex
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
start_text
(
p
,
ptr
);
}
static
bool
end_hex
(
upb_json_parser
*
p
)
{
uint32_t
codepoint
=
p
->
digit
;
static
void
hex
(
upb_json_parser
*
p
,
const
char
*
end
)
{
const
char
*
start
=
p
->
text_begin
;
UPB_ASSERT_VAR
(
end
,
end
-
start
==
4
);
uint16_t
codepoint
=
(
hexdigit
(
start
[
0
])
<<
12
)
|
(
hexdigit
(
start
[
1
])
<<
8
)
|
(
hexdigit
(
start
[
2
])
<<
4
)
|
hexdigit
(
start
[
3
]);
// emit the codepoint as UTF-8.
char
utf8
[
3
];
// support \u0000 -- \uFFFF -- need only three bytes.
int
length
=
0
;
...
...
@@ -9110,160 +9125,466 @@ static void hex(upb_json_parser *p, const char *end) {
// TODO(haberman): Handle high surrogates: if codepoint is a high surrogate
// we have to wait for the next escape to get the full code point).
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STRING
);
upb_sink_putstring
(
&
p
->
top
->
sink
,
sel
,
utf8
,
length
,
NULL
);
return
multipart_text
(
p
,
utf8
,
length
,
false
);
}
#define CHECK_RETURN_TOP(x) if (!(x)) goto error
static
void
start_text
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
capture_begin
(
p
,
ptr
);
}
static
bool
end_text
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
return
capture_end
(
p
,
ptr
);
}
static
void
start_number
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
multipart_startaccum
(
p
);
capture_begin
(
p
,
ptr
);
}
static
bool
end_number
(
upb_json_parser
*
p
,
const
char
*
ptr
)
{
if
(
!
capture_end
(
p
,
ptr
))
{
return
false
;
}
// strtol() and friends unfortunately do not support specifying the length of
// the input string, so we need to force a copy into a NULL-terminated buffer.
if
(
!
multipart_text
(
p
,
"
\0
"
,
1
,
false
))
{
return
false
;
}
size_t
len
;
const
char
*
buf
=
accumulate_getptr
(
p
,
&
len
);
const
char
*
myend
=
buf
+
len
-
1
;
// One for NULL.
char
*
end
;
switch
(
upb_fielddef_type
(
p
->
top
->
f
))
{
case
UPB_TYPE_ENUM
:
case
UPB_TYPE_INT32
:
{
long
val
=
strtol
(
p
->
accumulated
,
&
end
,
0
);
if
(
val
>
INT32_MAX
||
val
<
INT32_MIN
||
errno
==
ERANGE
||
end
!=
myend
)
goto
err
;
else
upb_sink_putint32
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
case
UPB_TYPE_INT64
:
{
long
long
val
=
strtoll
(
p
->
accumulated
,
&
end
,
0
);
if
(
val
>
INT64_MAX
||
val
<
INT64_MIN
||
errno
==
ERANGE
||
end
!=
myend
)
goto
err
;
else
upb_sink_putint64
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
case
UPB_TYPE_UINT32
:
{
unsigned
long
val
=
strtoul
(
p
->
accumulated
,
&
end
,
0
);
if
(
val
>
UINT32_MAX
||
errno
==
ERANGE
||
end
!=
myend
)
goto
err
;
else
upb_sink_putuint32
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
case
UPB_TYPE_UINT64
:
{
unsigned
long
long
val
=
strtoull
(
p
->
accumulated
,
&
end
,
0
);
if
(
val
>
UINT64_MAX
||
errno
==
ERANGE
||
end
!=
myend
)
goto
err
;
else
upb_sink_putuint64
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
case
UPB_TYPE_DOUBLE
:
{
double
val
=
strtod
(
p
->
accumulated
,
&
end
);
if
(
errno
==
ERANGE
||
end
!=
myend
)
goto
err
;
else
upb_sink_putdouble
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
case
UPB_TYPE_FLOAT
:
{
float
val
=
strtof
(
p
->
accumulated
,
&
end
);
if
(
errno
==
ERANGE
||
end
!=
myend
)
goto
err
;
else
upb_sink_putfloat
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
break
;
}
default:
assert
(
false
);
}
multipart_end
(
p
);
return
true
;
err:
upb_status_seterrf
(
p
->
status
,
"error parsing number: %s"
,
buf
);
multipart_end
(
p
);
return
false
;
}
static
bool
parser_putbool
(
upb_json_parser
*
p
,
bool
val
)
{
if
(
upb_fielddef_type
(
p
->
top
->
f
)
!=
UPB_TYPE_BOOL
)
{
upb_status_seterrf
(
p
->
status
,
"Boolean value specified for non-bool field: %s"
,
upb_fielddef_name
(
p
->
top
->
f
));
return
false
;
}
bool
ok
=
upb_sink_putbool
(
&
p
->
top
->
sink
,
parser_getsel
(
p
),
val
);
UPB_ASSERT_VAR
(
ok
,
ok
);
return
true
;
}
static
bool
start_stringval
(
upb_json_parser
*
p
)
{
assert
(
p
->
top
->
f
);
if
(
upb_fielddef_isstring
(
p
->
top
->
f
))
{
if
(
!
check_stack
(
p
))
return
false
;
// Start a new parser frame: parser frames correspond one-to-one with
// handler frames, and string events occur in a sub-frame.
upb_jsonparser_frame
*
inner
=
p
->
top
+
1
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STARTSTR
);
upb_sink_startstr
(
&
p
->
top
->
sink
,
sel
,
0
,
&
inner
->
sink
);
inner
->
m
=
p
->
top
->
m
;
inner
->
f
=
p
->
top
->
f
;
p
->
top
=
inner
;
if
(
upb_fielddef_type
(
p
->
top
->
f
)
==
UPB_TYPE_STRING
)
{
// For STRING fields we push data directly to the handlers as it is
// parsed. We don't do this yet for BYTES fields, because our base64
// decoder is not streaming.
//
// TODO(haberman): make base64 decoding streaming also.
multipart_start
(
p
,
getsel_for_handlertype
(
p
,
UPB_HANDLER_STRING
));
return
true
;
}
else
{
multipart_startaccum
(
p
);
return
true
;
}
}
else
if
(
upb_fielddef_type
(
p
->
top
->
f
)
==
UPB_TYPE_ENUM
)
{
// No need to push a frame -- symbolic enum names in quotes remain in the
// current parser frame.
//
// Enum string values must accumulate so we can look up the value in a table
// once it is complete.
multipart_startaccum
(
p
);
return
true
;
}
else
{
upb_status_seterrf
(
p
->
status
,
"String specified for non-string/non-enum field: %s"
,
upb_fielddef_name
(
p
->
top
->
f
));
return
false
;
}
}
static
bool
end_stringval
(
upb_json_parser
*
p
)
{
bool
ok
=
true
;
switch
(
upb_fielddef_type
(
p
->
top
->
f
))
{
case
UPB_TYPE_BYTES
:
if
(
!
base64_push
(
p
,
getsel_for_handlertype
(
p
,
UPB_HANDLER_STRING
),
p
->
accumulated
,
p
->
accumulated_len
))
{
return
false
;
}
// Fall through.
case
UPB_TYPE_STRING
:
{
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_ENDSTR
);
upb_sink_endstr
(
&
p
->
top
->
sink
,
sel
);
p
->
top
--
;
break
;
}
case
UPB_TYPE_ENUM
:
{
// Resolve enum symbolic name to integer value.
const
upb_enumdef
*
enumdef
=
(
const
upb_enumdef
*
)
upb_fielddef_subdef
(
p
->
top
->
f
);
size_t
len
;
const
char
*
buf
=
accumulate_getptr
(
p
,
&
len
);
int32_t
int_val
=
0
;
ok
=
upb_enumdef_ntoi
(
enumdef
,
buf
,
len
,
&
int_val
);
if
(
ok
)
{
upb_selector_t
sel
=
parser_getsel
(
p
);
upb_sink_putint32
(
&
p
->
top
->
sink
,
sel
,
int_val
);
}
else
{
upb_status_seterrf
(
p
->
status
,
"Enum value unknown: '%.*s'"
,
len
,
buf
);
}
break
;
}
default:
assert
(
false
);
upb_status_seterrmsg
(
p
->
status
,
"Internal error in JSON decoder"
);
ok
=
false
;
break
;
}
multipart_end
(
p
);
return
ok
;
}
static
void
start_member
(
upb_json_parser
*
p
)
{
assert
(
!
p
->
top
->
f
);
multipart_startaccum
(
p
);
}
static
bool
end_member
(
upb_json_parser
*
p
)
{
assert
(
!
p
->
top
->
f
);
size_t
len
;
const
char
*
buf
=
accumulate_getptr
(
p
,
&
len
);
const
upb_fielddef
*
f
=
upb_msgdef_ntof
(
p
->
top
->
m
,
buf
,
len
);
if
(
!
f
)
{
// TODO(haberman): Ignore unknown fields if requested/configured to do so.
upb_status_seterrf
(
p
->
status
,
"No such field: %.*s
\n
"
,
(
int
)
len
,
buf
);
return
false
;
}
p
->
top
->
f
=
f
;
multipart_end
(
p
);
return
true
;
}
static
void
clear_member
(
upb_json_parser
*
p
)
{
p
->
top
->
f
=
NULL
;
}
static
bool
start_subobject
(
upb_json_parser
*
p
)
{
assert
(
p
->
top
->
f
);
if
(
!
upb_fielddef_issubmsg
(
p
->
top
->
f
))
{
upb_status_seterrf
(
p
->
status
,
"Object specified for non-message/group field: %s"
,
upb_fielddef_name
(
p
->
top
->
f
));
return
false
;
}
if
(
!
check_stack
(
p
))
return
false
;
upb_jsonparser_frame
*
inner
=
p
->
top
+
1
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STARTSUBMSG
);
upb_sink_startsubmsg
(
&
p
->
top
->
sink
,
sel
,
&
inner
->
sink
);
inner
->
m
=
upb_fielddef_msgsubdef
(
p
->
top
->
f
);
inner
->
f
=
NULL
;
p
->
top
=
inner
;
return
true
;
}
static
void
end_subobject
(
upb_json_parser
*
p
)
{
p
->
top
--
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_ENDSUBMSG
);
upb_sink_endsubmsg
(
&
p
->
top
->
sink
,
sel
);
}
static
bool
start_array
(
upb_json_parser
*
p
)
{
assert
(
p
->
top
->
f
);
if
(
!
upb_fielddef_isseq
(
p
->
top
->
f
))
{
upb_status_seterrf
(
p
->
status
,
"Array specified for non-repeated field: %s"
,
upb_fielddef_name
(
p
->
top
->
f
));
return
false
;
}
if
(
!
check_stack
(
p
))
return
false
;
upb_jsonparser_frame
*
inner
=
p
->
top
+
1
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_STARTSEQ
);
upb_sink_startseq
(
&
p
->
top
->
sink
,
sel
,
&
inner
->
sink
);
inner
->
m
=
p
->
top
->
m
;
inner
->
f
=
p
->
top
->
f
;
p
->
top
=
inner
;
return
true
;
}
static
void
end_array
(
upb_json_parser
*
p
)
{
assert
(
p
->
top
>
p
->
stack
);
p
->
top
--
;
upb_selector_t
sel
=
getsel_for_handlertype
(
p
,
UPB_HANDLER_ENDSEQ
);
upb_sink_endseq
(
&
p
->
top
->
sink
,
sel
);
}
static
void
start_object
(
upb_json_parser
*
p
)
{
upb_sink_startmsg
(
&
p
->
top
->
sink
);
}
static
void
end_object
(
upb_json_parser
*
p
)
{
upb_status
status
;
upb_sink_endmsg
(
&
p
->
top
->
sink
,
&
status
);
}
#define CHECK_RETURN_TOP(x) if (!(x)) goto error
/* The actual parser **********************************************************/
// What follows is the Ragel parser itself. The language is specified in Ragel
// and the actions call our C functions above.
//
// Ragel has an extensive set of functionality, and we use only a small part of
// it. There are many action types but we only use a few:
//
// ">" -- transition into a machine
// "%" -- transition out of a machine
// "@" -- transition into a final state of a machine.
//
// "@" transitions are tricky because a machine can transition into a final
// state repeatedly. But in some cases we know this can't happen, for example
// a string which is delimited by a final '"' can only transition into its
// final state once, when the closing '"' is seen.
#line
596
"upb/json/parser.rl"
#line
904
"upb/json/parser.rl"
#line
514
"upb/json/parser.c"
#line
816
"upb/json/parser.c"
static
const
char
_json_actions
[]
=
{
0
,
1
,
0
,
1
,
2
,
1
,
3
,
1
,
4
,
1
,
5
,
1
,
6
,
1
,
7
,
1
,
9
,
1
,
11
,
1
,
12
,
1
,
13
,
1
,
14
,
1
,
15
,
1
,
16
,
1
,
24
,
1
,
26
,
2
,
3
,
7
,
2
,
5
,
2
,
2
,
5
,
7
,
2
,
10
,
8
,
2
,
12
,
14
,
2
,
13
,
14
,
2
,
17
,
1
,
2
,
18
,
26
,
2
,
19
,
8
,
2
,
20
,
26
,
2
,
21
,
26
,
2
,
22
,
26
,
2
,
23
,
26
,
2
,
25
,
26
,
3
,
13
,
10
,
8
5
,
1
,
6
,
1
,
7
,
1
,
8
,
1
,
10
,
1
,
12
,
1
,
13
,
1
,
14
,
1
,
15
,
1
,
16
,
1
,
17
,
1
,
21
,
1
,
25
,
1
,
27
,
2
,
3
,
8
,
2
,
4
,
5
,
2
,
6
,
2
,
2
,
6
,
8
,
2
,
11
,
9
,
2
,
13
,
15
,
2
,
14
,
15
,
2
,
18
,
1
,
2
,
19
,
27
,
2
,
20
,
9
,
2
,
22
,
27
,
2
,
23
,
27
,
2
,
24
,
27
,
2
,
26
,
27
,
3
,
14
,
11
,
9
};
static
const
unsigned
char
_json_key_offsets
[]
=
{
0
,
0
,
4
,
9
,
14
,
1
8
,
22
,
27
,
32
,
37
,
41
,
45
,
48
,
51
,
53
,
57
,
61
,
63
,
65
,
70
,
72
,
74
,
83
,
89
,
9
5
,
101
,
107
,
109
,
118
,
118
,
118
,
123
,
12
8
,
133
,
133
,
134
,
135
,
136
,
137
,
137
,
13
8
,
139
,
140
,
140
,
141
,
142
,
143
,
143
,
14
8
,
153
,
157
,
161
,
166
,
171
,
176
,
180
,
1
80
,
183
,
183
,
183
0
,
0
,
4
,
9
,
14
,
1
5
,
19
,
24
,
29
,
34
,
38
,
42
,
45
,
48
,
50
,
54
,
58
,
60
,
62
,
67
,
69
,
71
,
80
,
86
,
9
2
,
98
,
104
,
106
,
115
,
116
,
116
,
116
,
12
1
,
126
,
131
,
132
,
133
,
134
,
135
,
135
,
13
6
,
137
,
138
,
138
,
139
,
140
,
141
,
141
,
14
6
,
151
,
152
,
156
,
161
,
166
,
171
,
175
,
1
75
,
178
,
178
,
178
};
static
const
char
_json_trans_keys
[]
=
{
32
,
123
,
9
,
13
,
32
,
34
,
125
,
9
,
13
,
32
,
34
,
125
,
9
,
13
,
3
2
,
58
,
9
,
13
,
32
,
58
,
9
,
13
,
32
,
9
3
,
125
,
9
,
13
,
32
,
44
,
125
,
9
,
13
,
32
,
44
,
125
,
9
,
13
,
32
,
34
,
9
,
13
,
45
,
48
,
49
,
57
,
48
,
49
,
57
,
4
6
,
69
,
101
,
48
,
57
,
69
,
101
,
48
,
57
,
43
,
45
,
48
,
57
,
48
,
57
,
48
,
57
,
46
,
69
,
101
,
48
,
57
,
34
,
92
,
34
,
92
,
34
,
47
,
92
,
98
,
102
,
110
,
114
,
116
,
117
,
48
,
57
,
65
,
70
,
9
7
,
102
,
48
,
57
,
65
,
70
,
97
,
102
,
48
,
57
,
65
,
70
,
97
,
102
,
48
,
57
,
65
,
70
,
97
,
102
,
34
,
92
,
34
,
45
,
91
,
1
02
,
110
,
116
,
123
,
48
,
57
,
32
,
93
,
1
25
,
9
,
13
,
32
,
44
,
93
,
9
,
1
3
,
32
,
93
,
125
,
9
,
13
,
97
,
108
,
115
,
10
1
,
117
,
108
,
108
,
114
,
117
,
101
,
32
,
34
,
125
,
9
,
13
,
32
,
34
,
125
,
9
,
13
,
32
,
58
,
9
,
13
,
32
,
58
,
9
,
13
,
32
,
93
,
125
,
9
,
13
,
32
,
44
,
125
,
9
,
13
,
32
,
44
,
125
,
9
,
13
,
32
,
34
,
9
,
13
,
32
,
9
,
13
,
0
13
,
32
,
34
,
125
,
9
,
13
,
3
4
,
32
,
58
,
9
,
13
,
32
,
93
,
125
,
9
,
1
3
,
32
,
44
,
125
,
9
,
13
,
32
,
44
,
125
,
9
,
13
,
32
,
34
,
9
,
13
,
45
,
48
,
49
,
57
,
48
,
49
,
57
,
46
,
69
,
101
,
4
8
,
57
,
69
,
101
,
48
,
57
,
43
,
45
,
48
,
57
,
48
,
57
,
48
,
57
,
46
,
69
,
101
,
48
,
57
,
34
,
92
,
34
,
92
,
34
,
47
,
92
,
98
,
102
,
110
,
114
,
116
,
117
,
48
,
57
,
65
,
70
,
97
,
102
,
48
,
5
7
,
65
,
70
,
97
,
102
,
48
,
57
,
65
,
70
,
97
,
102
,
48
,
57
,
65
,
70
,
97
,
102
,
34
,
92
,
34
,
45
,
91
,
102
,
110
,
116
,
1
23
,
48
,
57
,
34
,
32
,
93
,
125
,
9
,
1
3
,
32
,
44
,
93
,
9
,
13
,
32
,
9
3
,
125
,
9
,
13
,
97
,
108
,
115
,
101
,
117
,
10
8
,
108
,
114
,
117
,
101
,
32
,
34
,
125
,
9
,
13
,
32
,
34
,
125
,
9
,
13
,
34
,
32
,
58
,
9
,
13
,
32
,
93
,
125
,
9
,
13
,
32
,
44
,
125
,
9
,
13
,
32
,
44
,
125
,
9
,
13
,
32
,
34
,
9
,
13
,
32
,
9
,
13
,
0
};
static
const
char
_json_single_lengths
[]
=
{
0
,
2
,
3
,
3
,
2
,
2
,
3
,
3
,
0
,
2
,
3
,
3
,
1
,
2
,
3
,
3
,
3
,
2
,
2
,
1
,
3
,
0
,
2
,
2
,
0
,
0
,
3
,
2
,
2
,
9
,
0
,
0
,
0
,
0
,
2
,
7
,
0
,
0
,
3
,
3
,
3
,
0
,
1
,
1
,
1
,
1
,
0
,
1
,
0
,
0
,
2
,
7
,
1
,
0
,
0
,
3
,
3
,
3
,
1
,
1
,
1
,
1
,
0
,
1
,
1
,
1
,
0
,
1
,
1
,
1
,
0
,
3
,
3
,
2
,
2
,
3
,
3
,
3
,
2
,
0
,
3
,
1
,
2
,
3
,
3
,
3
,
2
,
0
,
1
,
0
,
0
,
0
};
static
const
char
_json_range_lengths
[]
=
{
0
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
1
,
1
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
,
0
,
3
,
3
,
3
,
3
,
0
,
1
,
0
,
0
,
1
,
1
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
3
,
3
,
0
,
1
,
0
,
0
,
0
,
1
,
1
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
0
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
0
,
0
,
0
};
static
const
short
_json_index_offsets
[]
=
{
0
,
0
,
4
,
9
,
14
,
1
8
,
22
,
27
,
3
2
,
37
,
41
,
45
,
48
,
52
,
54
,
58
,
6
2
,
64
,
66
,
71
,
74
,
77
,
87
,
91
,
9
5
,
99
,
103
,
106
,
115
,
116
,
117
,
122
,
12
7
,
132
,
133
,
135
,
137
,
139
,
141
,
142
,
14
4
,
146
,
148
,
149
,
151
,
153
,
155
,
156
,
16
1
,
166
,
170
,
174
,
179
,
184
,
189
,
193
,
19
4
,
197
,
198
,
199
0
,
0
,
4
,
9
,
14
,
1
6
,
20
,
25
,
3
0
,
35
,
39
,
43
,
46
,
50
,
52
,
56
,
6
0
,
62
,
64
,
69
,
72
,
75
,
85
,
89
,
9
3
,
97
,
101
,
104
,
113
,
115
,
116
,
117
,
12
2
,
127
,
132
,
134
,
136
,
138
,
140
,
141
,
14
3
,
145
,
147
,
148
,
150
,
152
,
154
,
155
,
16
0
,
165
,
167
,
171
,
176
,
181
,
186
,
190
,
19
1
,
194
,
195
,
196
};
static
const
char
_json_indicies
[]
=
{
0
,
2
,
0
,
1
,
3
,
4
,
5
,
3
,
1
,
6
,
7
,
8
,
6
,
1
,
9
,
1
0
,
9
,
1
,
11
,
12
,
11
,
1
,
12
,
1
,
1
,
12
,
13
,
14
,
15
,
16
,
14
,
1
,
17
,
18
,
8
,
17
,
1
,
18
,
7
,
18
,
1
,
19
,
20
,
21
,
1
,
20
,
21
,
1
,
23
,
2
4
,
24
,
22
,
25
,
1
,
24
,
24
,
25
,
2
2
,
26
,
26
,
27
,
1
,
27
,
1
,
2
7
,
22
,
23
,
24
,
24
,
21
,
22
,
29
,
3
0
,
28
,
32
,
33
,
31
,
34
,
34
,
34
,
3
4
,
34
,
34
,
34
,
34
,
35
,
1
,
36
,
36
,
36
,
1
,
37
,
37
,
37
,
1
,
38
,
38
,
38
,
1
,
39
,
39
,
39
,
1
,
41
,
42
,
4
0
,
43
,
44
,
45
,
46
,
47
,
48
,
49
,
44
,
1
,
50
,
51
,
53
,
54
,
1
,
1
,
6
,
7
,
8
,
6
,
1
,
9
,
1
,
10
,
11
,
10
,
1
,
11
,
1
,
1
,
1
1
,
1
2
,
13
,
14
,
15
,
13
,
1
,
16
,
17
,
8
,
16
,
1
,
17
,
7
,
17
,
1
,
18
,
1
9
,
20
,
1
,
19
,
20
,
1
,
22
,
23
,
23
,
2
1
,
24
,
1
,
23
,
23
,
24
,
21
,
25
,
2
5
,
26
,
1
,
26
,
1
,
26
,
2
1
,
2
2
,
23
,
23
,
20
,
21
,
28
,
29
,
27
,
3
1
,
32
,
30
,
33
,
33
,
33
,
33
,
33
,
3
3
,
33
,
33
,
34
,
1
,
35
,
35
,
35
,
1
,
36
,
36
,
36
,
1
,
37
,
37
,
37
,
1
,
38
,
38
,
38
,
1
,
40
,
41
,
39
,
42
,
4
3
,
44
,
45
,
46
,
47
,
48
,
43
,
1
,
49
,
1
,
50
,
51
,
53
,
54
,
1
,
53
,
52
,
55
,
56
,
54
,
55
,
1
,
56
,
1
,
1
,
56
,
52
,
57
,
58
,
1
,
59
,
1
,
60
,
1
,
61
,
1
,
62
,
63
,
1
,
64
,
1
,
65
,
1
,
66
,
67
,
1
,
68
,
1
,
69
,
1
,
70
,
71
,
72
,
73
,
71
,
1
,
74
,
75
,
76
,
74
,
1
,
77
,
78
,
77
,
1
,
79
,
80
,
79
,
1
,
80
,
1
,
1
,
80
,
81
,
82
,
83
,
84
,
82
,
1
,
85
,
86
,
76
,
85
,
1
,
86
,
75
,
86
,
1
,
87
,
88
,
88
,
1
,
1
,
1
,
1
,
0
1
,
1
,
56
,
52
,
57
,
1
,
58
,
1
,
59
,
1
,
60
,
1
,
61
,
62
,
1
,
63
,
1
,
64
,
1
,
65
,
66
,
1
,
67
,
1
,
68
,
1
,
69
,
70
,
71
,
72
,
70
,
1
,
73
,
74
,
75
,
73
,
1
,
76
,
1
,
77
,
78
,
77
,
1
,
78
,
1
,
1
,
78
,
79
,
80
,
81
,
82
,
80
,
1
,
83
,
84
,
75
,
83
,
1
,
84
,
74
,
84
,
1
,
85
,
86
,
86
,
1
,
1
,
1
,
1
,
0
};
static
const
char
_json_trans_targs
[]
=
{
1
,
0
,
2
,
3
,
4
,
56
,
3
,
4
,
56
,
5
,
6
,
5
,
6
,
7
,
8
,
9
,
56
,
8
,
9
,
11
,
12
,
18
,
57
,
13
,
15
,
14
,
16
,
17
,
20
,
58
,
21
,
20
,
58
,
21
,
19
,
22
,
23
,
24
,
25
,
26
,
20
,
58
,
21
,
28
,
29
,
30
,
34
,
39
,
43
,
47
,
59
,
59
,
31
,
30
,
33
,
31
,
32
,
59
,
35
,
36
,
37
,
38
,
59
,
40
,
41
,
42
,
59
,
44
,
45
,
46
,
59
,
48
,
49
,
55
,
48
,
49
,
55
,
50
,
51
,
50
,
51
,
52
,
53
,
54
,
55
,
53
,
54
,
59
,
56
56
,
5
,
5
,
6
,
7
,
8
,
9
,
56
,
8
,
9
,
11
,
12
,
18
,
57
,
13
,
15
,
14
,
16
,
17
,
20
,
58
,
21
,
20
,
58
,
21
,
19
,
22
,
23
,
24
,
25
,
26
,
20
,
58
,
21
,
28
,
30
,
31
,
34
,
39
,
43
,
47
,
29
,
59
,
59
,
32
,
31
,
29
,
32
,
33
,
35
,
36
,
37
,
38
,
59
,
40
,
41
,
42
,
59
,
44
,
45
,
46
,
59
,
48
,
49
,
55
,
48
,
49
,
55
,
50
,
50
,
51
,
52
,
53
,
54
,
55
,
53
,
54
,
59
,
56
};
static
const
char
_json_trans_actions
[]
=
{
0
,
0
,
0
,
21
,
75
,
48
,
0
,
42
,
23
,
17
,
17
,
0
,
0
,
15
,
19
,
19
,
45
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
,
3
,
13
,
0
,
0
,
33
,
5
,
11
,
0
,
7
,
0
,
0
,
0
,
36
,
39
,
9
,
57
,
51
,
25
,
0
,
0
,
0
,
29
,
60
,
54
,
15
,
0
,
27
,
0
,
0
,
31
,
0
,
0
,
0
,
0
,
66
,
0
,
0
,
0
,
69
,
0
,
0
,
0
,
63
,
21
,
75
,
48
,
0
,
42
,
23
,
17
,
17
,
0
,
0
,
15
,
19
,
19
,
45
,
0
,
0
,
72
,
0
0
,
0
,
0
,
21
,
77
,
53
,
0
,
47
,
23
,
17
,
0
,
0
,
15
,
19
,
19
,
50
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
,
3
,
13
,
0
,
0
,
35
,
5
,
11
,
0
,
38
,
7
,
7
,
7
,
41
,
44
,
9
,
62
,
56
,
25
,
0
,
0
,
0
,
31
,
29
,
33
,
59
,
15
,
0
,
27
,
0
,
0
,
0
,
0
,
0
,
0
,
68
,
0
,
0
,
0
,
71
,
0
,
0
,
0
,
65
,
21
,
77
,
53
,
0
,
47
,
23
,
17
,
0
,
0
,
15
,
19
,
19
,
50
,
0
,
0
,
74
,
0
};
static
const
int
json_start
=
1
;
...
...
@@ -9276,13 +9597,14 @@ static const int json_en_value_machine = 27;
static
const
int
json_en_main
=
1
;
#line
599
"upb/json/parser.rl"
#line
907
"upb/json/parser.rl"
size_t
parse
(
void
*
closure
,
const
void
*
hd
,
const
char
*
buf
,
size_t
size
,
const
upb_bufhandle
*
handle
)
{
UPB_UNUSED
(
hd
);
UPB_UNUSED
(
handle
);
upb_json_parser
*
parser
=
closure
;
parser
->
handle
=
handle
;
// Variables used by Ragel's generated code.
int
cs
=
parser
->
current_state
;
...
...
@@ -9292,8 +9614,10 @@ size_t parse(void *closure, const void *hd, const char *buf, size_t size,
const
char
*
p
=
buf
;
const
char
*
pe
=
buf
+
size
;
capture_resume
(
parser
,
buf
);
#line 684 "upb/json/parser.c"
#line 987 "upb/json/parser.c"
{
int
_klen
;
unsigned
int
_trans
;
...
...
@@ -9368,114 +9692,118 @@ _match:
switch
(
*
_acts
++
)
{
case
0
:
#line
517
"upb/json/parser.rl"
#line
819
"upb/json/parser.rl"
{
p
--
;
{
cs
=
stack
[
--
top
];
goto
_again
;}
}
break
;
case
1
:
#line
518
"upb/json/parser.rl"
#line
820
"upb/json/parser.rl"
{
p
--
;
{
stack
[
top
++
]
=
cs
;
cs
=
10
;
goto
_again
;}
}
break
;
case
2
:
#line
522
"upb/json/parser.rl"
#line
824
"upb/json/parser.rl"
{
start_text
(
parser
,
p
);
}
break
;
case
3
:
#line
523
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
end_text
(
parser
,
p
,
false
));
}
#line
825
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
end_text
(
parser
,
p
));
}
break
;
case
4
:
#line
529
"upb/json/parser.rl"
{
start_hex
(
parser
,
p
);
}
#line
831
"upb/json/parser.rl"
{
start_hex
(
parser
);
}
break
;
case
5
:
#line
530
"upb/json/parser.rl"
{
hex
(
parser
,
p
);
}
#line
832
"upb/json/parser.rl"
{
hex
digit
(
parser
,
p
);
}
break
;
case
6
:
#line
536
"upb/json/parser.rl"
{
escape
(
parser
,
p
);
}
#line
833
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
end_hex
(
parser
)
);
}
break
;
case
7
:
#line
5
39 "upb/json/parser.rl"
{
{
cs
=
stack
[
--
top
];
goto
_again
;}
}
#line
8
39 "upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
escape
(
parser
,
p
));
}
break
;
case
8
:
#line
540
"upb/json/parser.rl"
{
{
stack
[
top
++
]
=
cs
;
cs
=
19
;
goto
_again
;}
}
#line
845
"upb/json/parser.rl"
{
p
--
;
{
cs
=
stack
[
--
top
]
;
goto
_again
;}
}
break
;
case
9
:
#line
542
"upb/json/parser.rl"
{
p
--
;
{
stack
[
top
++
]
=
cs
;
cs
=
27
;
goto
_again
;}
}
#line
848
"upb/json/parser.rl"
{
{
stack
[
top
++
]
=
cs
;
cs
=
19
;
goto
_again
;}
}
break
;
case
10
:
#line
547
"upb/json/parser.rl"
{
start_member
(
parser
);
}
#line
850
"upb/json/parser.rl"
{
p
--
;
{
stack
[
top
++
]
=
cs
;
cs
=
27
;
goto
_again
;}
}
break
;
case
11
:
#line
548
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
end_member
(
parser
)
);
}
#line
855
"upb/json/parser.rl"
{
start_member
(
parser
);
}
break
;
case
12
:
#line
551
"upb/json/parser.rl"
{
clear_member
(
parser
);
}
#line
856
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
end_member
(
parser
)
);
}
break
;
case
13
:
#line
557
"upb/json/parser.rl"
{
start_object
(
parser
);
}
#line
859
"upb/json/parser.rl"
{
clear_member
(
parser
);
}
break
;
case
14
:
#line
560
"upb/json/parser.rl"
{
end
_object
(
parser
);
}
#line
865
"upb/json/parser.rl"
{
start
_object
(
parser
);
}
break
;
case
15
:
#line
566
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
start_array
(
parser
)
);
}
#line
868
"upb/json/parser.rl"
{
end_object
(
parser
);
}
break
;
case
16
:
#line
570
"upb/json/parser.rl"
{
end_array
(
parser
);
}
#line
874
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
start_array
(
parser
)
);
}
break
;
case
17
:
#line
575
"upb/json/parser.rl"
{
start_number
(
parser
,
p
);
}
#line
878
"upb/json/parser.rl"
{
end_array
(
parser
);
}
break
;
case
18
:
#line
576
"upb/json/parser.rl"
{
end
_number
(
parser
,
p
);
}
#line
883
"upb/json/parser.rl"
{
start
_number
(
parser
,
p
);
}
break
;
case
19
:
#line
578
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
start_stringval
(
parser
));
}
#line
884
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
end_number
(
parser
,
p
));
}
break
;
case
20
:
#line
579
"upb/json/parser.rl"
{
end_stringval
(
parser
);
}
#line
886
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
start_stringval
(
parser
)
);
}
break
;
case
21
:
#line
581
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
parser_putbool
(
parser
,
true
));
}
#line
887
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
end_stringval
(
parser
));
}
break
;
case
22
:
#line
583
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
parser_putbool
(
parser
,
fals
e
));
}
#line
889
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
parser_putbool
(
parser
,
tru
e
));
}
break
;
case
23
:
#line
585
"upb/json/parser.rl"
{
/* null value */
}
#line
891
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
parser_putbool
(
parser
,
false
));
}
break
;
case
24
:
#line
587
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
start_subobject
(
parser
));
}
#line
893
"upb/json/parser.rl"
{
/* null value */
}
break
;
case
25
:
#line
588
"upb/json/parser.rl"
{
end_subobject
(
parser
);
}
#line
895
"upb/json/parser.rl"
{
CHECK_RETURN_TOP
(
start_subobject
(
parser
)
);
}
break
;
case
26
:
#line 593 "upb/json/parser.rl"
#line 896 "upb/json/parser.rl"
{
end_subobject
(
parser
);
}
break
;
case
27
:
#line 901 "upb/json/parser.rl"
{
p
--
;
{
cs
=
stack
[
--
top
];
goto
_again
;}
}
break
;
#line
866
"upb/json/parser.c"
#line
1173
"upb/json/parser.c"
}
}
...
...
@@ -9488,10 +9816,12 @@ _again:
_out:
{}
}
#line
615
"upb/json/parser.rl"
#line
926
"upb/json/parser.rl"
if
(
p
!=
pe
)
{
upb_status_seterrf
(
parser
->
status
,
"Parse error at %s
\n
"
,
p
);
}
else
{
capture_suspend
(
parser
,
&
p
);
}
error:
...
...
@@ -9508,8 +9838,13 @@ bool end(void *closure, const void *hd) {
return
true
;
}
/* Public API *****************************************************************/
void
upb_json_parser_init
(
upb_json_parser
*
p
,
upb_status
*
status
)
{
p
->
limit
=
p
->
stack
+
UPB_JSON_MAX_DEPTH
;
p
->
accumulate_buf
=
NULL
;
p
->
accumulate_buf_size
=
0
;
upb_byteshandler_init
(
&
p
->
input_handler_
);
upb_byteshandler_setstring
(
&
p
->
input_handler_
,
parse
,
NULL
);
upb_byteshandler_setendstr
(
&
p
->
input_handler_
,
end
,
NULL
);
...
...
@@ -9519,6 +9854,7 @@ void upb_json_parser_init(upb_json_parser *p, upb_status *status) {
void
upb_json_parser_uninit
(
upb_json_parser
*
p
)
{
upb_byteshandler_uninit
(
&
p
->
input_handler_
);
free
(
p
->
accumulate_buf
);
}
void
upb_json_parser_reset
(
upb_json_parser
*
p
)
{
...
...
@@ -9529,18 +9865,18 @@ void upb_json_parser_reset(upb_json_parser *p) {
int
top
;
// Emit Ragel initialization of the parser.
#line
920
"upb/json/parser.c"
#line
1235
"upb/json/parser.c"
{
cs
=
json_start
;
top
=
0
;
}
#line
655
"upb/json/parser.rl"
#line
974
"upb/json/parser.rl"
p
->
current_state
=
cs
;
p
->
parser_top
=
top
;
p
->
text_begin
=
NULL
;
p
->
accumulated
=
NULL
;
p
->
accumulated_len
=
0
;
accumulate_clear
(
p
)
;
p
->
multipart_state
=
MULTIPART_INACTIVE
;
p
->
capture
=
NULL
;
}
void
upb_json_parser_resetoutput
(
upb_json_parser
*
p
,
upb_sink
*
sink
)
{
...
...
ruby/ext/google/protobuf_c/upb.h
View file @
97b663a8
...
...
@@ -6662,7 +6662,9 @@ typedef enum {
// | unused (24) | opc |
// | upb_inttable* (32 or 64) |
OP_HALT
=
36
,
// No arg.
OP_DISPATCH
=
36
,
// No arg.
OP_HALT
=
37
,
// No arg.
}
opcode
;
#define OP_MAX OP_HALT
...
...
@@ -7339,15 +7341,24 @@ UPB_DEFINE_STRUCT0(upb_json_parser,
int
parser_stack
[
UPB_JSON_MAX_DEPTH
];
int
parser_top
;
//
A pointer to the beginning of whatever text we are currently parsing
.
const
char
*
text_begin
;
//
The handle for the current buffer
.
const
upb_bufhandle
*
handle
;
// We have to accumulate text for member names, integers, unicode escapes, and
// base64 partial results.
// Accumulate buffer. See details in parser.rl.
const
char
*
accumulated
;
size_t
accumulated_len
;
// TODO: add members and code for allocating a buffer when necessary (when the
// member spans input buffers or contains escapes).
char
*
accumulate_buf
;
size_t
accumulate_buf_size
;
// Multi-part text data. See details in parser.rl.
int
multipart_state
;
upb_selector_t
string_selector
;
// Input capture. See details in parser.rl.
const
char
*
capture
;
// Intermediate result of parsing a unicode escape sequence.
uint32_t
digit
;
));
UPB_BEGIN_EXTERN_C
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment