Skip to content

Commit

Permalink
Parse Infinity and -Infinity if JSONSL_PARSE_NAN defined
Browse files Browse the repository at this point in the history
  • Loading branch information
ajdavis committed Apr 21, 2017
1 parent 9787ae5 commit 6977d68
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 13 deletions.
10 changes: 6 additions & 4 deletions README.pod
Expand Up @@ -355,12 +355,14 @@ instead of the good 'ole C<char>. Of course you would need to
handle processing the stream correctly to make sure the multibyte
stream was complete.

=head2 NaN
=head2 NaN, Infinity, -Infinity

By default, JSONSL does not consider an object like C<{"n": NaN}> to be valid
syntax. Compile with C<JSONSL_PARSE_NAN> defined to parse NaN as "not-a-number".
By default, JSONSL does not consider objects like C<{"n": NaN}>,
C<{"n": Infinity}>, or C<{"n": -Infinity}> to be valid.
Compile with C<JSONSL_PARSE_NAN> defined to parse these non-numbers.
JSONSL will then execute your POP callback with C<state-E<gt>special_flags> set
to C<JSONSL_SPECIALf_NUMNOINT | JSONSL_SPECIALf_NAN> when it parses a NaN.
to C<JSONSL_SPECIALf_NAN> when it parses NaN, C<JSONSL_SPECIALf_INF> for
Infinity, and C<JSONSL_SPECIALf_INF | JSONSL_SPECIALf_SIGNED> for -Infinity.

=head2 WINDOWS

Expand Down
Binary file modified json_samples.tgz
Binary file not shown.
38 changes: 31 additions & 7 deletions jsonsl.c
Expand Up @@ -287,6 +287,11 @@ jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes)
INVOKE_ERROR(SPECIAL_EXPECTED); \
}

#define VERIFY_SPECIAL_CI(lit) \
if (tolower(CUR_CHAR) != (lit)[jsn->pos - state->pos_begin]) { \
INVOKE_ERROR(SPECIAL_EXPECTED); \
}

#define STATE_SPECIAL_LENGTH \
(state)->nescapes

Expand Down Expand Up @@ -350,6 +355,14 @@ jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes)
goto GT_SPECIAL_NUMERIC;
}
} else if (state->special_flags == JSONSL_SPECIALf_DASH) {
#ifdef JSONSL_PARSE_NAN
if (CUR_CHAR == 'I' || CUR_CHAR == 'i') {
/* parsing -Infinity? */
state->special_flags = JSONSL_SPECIALf_NEG_INF;
CONTINUE_NEXT_CHAR();
}
#endif

if (!isdigit(CUR_CHAR)) {
INVOKE_ERROR(INVALID_NUMBER);
}
Expand Down Expand Up @@ -378,7 +391,8 @@ jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes)
goto GT_SPECIAL_NUMERIC;
}

if (state->special_flags & JSONSL_SPECIALf_NUMERIC) {
if ((state->special_flags & JSONSL_SPECIALf_NUMERIC) &&
!(state->special_flags & JSONSL_SPECIALf_INF)) {
GT_SPECIAL_NUMERIC:
switch (CUR_CHAR) {
CASE_DIGITS
Expand Down Expand Up @@ -430,11 +444,12 @@ jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes)
} else if (state->special_flags == JSONSL_SPECIALf_NULL) {
VERIFY_SPECIAL("null");
#ifdef JSONSL_PARSE_NAN
} else if (state->special_flags == JSONSL_SPECIALf_POS_INF) {
VERIFY_SPECIAL_CI("infinity");
} else if (state->special_flags == JSONSL_SPECIALf_NEG_INF) {
VERIFY_SPECIAL_CI("-infinity");
} else if (state->special_flags == JSONSL_SPECIALf_NAN) {
/* like VERIFY_SPECIAL but case-insensitive */
if (tolower(CUR_CHAR) != "nan"[jsn->pos - state->pos_begin]) {
INVOKE_ERROR(SPECIAL_EXPECTED);
}
VERIFY_SPECIAL_CI("nan");
} else if (state->special_flags & JSONSL_SPECIALf_NULL ||
state->special_flags & JSONSL_SPECIALf_NAN) {
/* previous char was "n", are we parsing null or nan? */
Expand Down Expand Up @@ -462,6 +477,11 @@ jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes)
} else if (state->special_flags == JSONSL_SPECIALf_DASH) {
/* Still in dash! */
INVOKE_ERROR(INVALID_NUMBER);
} else if (state->special_flags & JSONSL_SPECIALf_INF) {
if (STATE_SPECIAL_LENGTH != 8) {
INVOKE_ERROR(SPECIAL_INCOMPLETE);
}
state->nelem = 1;
} else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) {
/* Check that we're not at the end of a token */
if (STATE_NUM_LAST != '1') {
Expand Down Expand Up @@ -1446,11 +1466,15 @@ static unsigned short Special_Table[0x100] = {
/* 0x37 */ JSONSL_SPECIALf_UNSIGNED /* <7> */, /* 0x37 */
/* 0x38 */ JSONSL_SPECIALf_UNSIGNED /* <8> */, /* 0x38 */
/* 0x39 */ JSONSL_SPECIALf_UNSIGNED /* <9> */, /* 0x39 */
/* 0x3a */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4d */
/* 0x3a */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x48 */
/* 0x49 */ JSONSL__INF_PROXY /* <I> */, /* 0x49 */
/* 0x4a */ 0,0,0,0, /* 0x4d */
/* 0x4e */ JSONSL__NAN_PROXY /* <N> */, /* 0x4e */
/* 0x4f */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x65 */
/* 0x66 */ JSONSL_SPECIALf_FALSE /* <f> */, /* 0x66 */
/* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */
/* 0x67 */ 0,0, /* 0x68 */
/* 0x69 */ JSONSL__INF_PROXY /* <i> */, /* 0x69 */
/* 0x6a */ 0,0,0,0, /* 0x6d */
/* 0x6e */ JSONSL_SPECIALf_NULL|JSONSL__NAN_PROXY /* <n> */, /* 0x6e */
/* 0x6f */ 0,0,0,0,0, /* 0x73 */
/* 0x74 */ JSONSL_SPECIALf_TRUE /* <t> */, /* 0x74 */
Expand Down
11 changes: 9 additions & 2 deletions jsonsl.h
Expand Up @@ -33,8 +33,10 @@ typedef unsigned char jsonsl_uchar_t;

#ifdef JSONSL_PARSE_NAN
#define JSONSL__NAN_PROXY JSONSL_SPECIALf_NAN
#define JSONSL__INF_PROXY JSONSL_SPECIALf_INF
#else
#define JSONSL__NAN_PROXY 0
#define JSONSL__INF_PROXY 0
#endif

/* Stolen from http-parser.h, and possibly others */
Expand Down Expand Up @@ -150,7 +152,8 @@ typedef enum {
X(FLOAT, 1<<5) \
X(EXPONENT, 1<<6) \
X(NONASCII, 1<<7) \
X(NAN, 1<<8)
X(NAN, 1<<8) \
X(INF, 1<<9)
typedef enum {
#define X(o,b) \
JSONSL_SPECIALf_##o = b,
Expand All @@ -164,6 +167,9 @@ typedef enum {
JSONSL_SPECIALf_ZERO = 1 << 9 | JSONSL_SPECIALf_UNSIGNED,
/** @private */
JSONSL_SPECIALf_DASH = 1 << 10,
/** @private */
JSONSL_SPECIALf_POS_INF = (JSONSL_SPECIALf_INF),
JSONSL_SPECIALf_NEG_INF = (JSONSL_SPECIALf_INF|JSONSL_SPECIALf_SIGNED),

/** Type is numeric */
JSONSL_SPECIALf_NUMERIC = (JSONSL_SPECIALf_SIGNED| JSONSL_SPECIALf_UNSIGNED),
Expand All @@ -173,7 +179,8 @@ typedef enum {

/** Type is an "extended", not integral type (but numeric) */
JSONSL_SPECIALf_NUMNOINT =
(JSONSL_SPECIALf_FLOAT|JSONSL_SPECIALf_EXPONENT|JSONSL_SPECIALf_NAN)
(JSONSL_SPECIALf_FLOAT|JSONSL_SPECIALf_EXPONENT|JSONSL_SPECIALf_NAN
|JSONSL_SPECIALf_INF)
} jsonsl_special_t;


Expand Down
2 changes: 2 additions & 0 deletions srcutil/genchartables.pl
Expand Up @@ -12,6 +12,8 @@
################################################################################
my @special_begin;
$special_begin[ord('-')] = 'JSONSL_SPECIALf_DASH';
$special_begin[ord('i')] = 'JSONSL__INF_PROXY';
$special_begin[ord('I')] = 'JSONSL__INF_PROXY';
$special_begin[ord('t')] = 'JSONSL_SPECIALf_TRUE';
$special_begin[ord('f')] = 'JSONSL_SPECIALf_FALSE';
$special_begin[ord('n')] = 'JSONSL_SPECIALf_NULL|JSONSL__NAN_PROXY';
Expand Down

0 comments on commit 6977d68

Please sign in to comment.