1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
Index: yajl_parse.h
===================================================================
--- yajl_parse.h (revision 767861)
+++ yajl_parse.h (revision 767862)
@@ -75,6 +75,7 @@
int (* yajl_null)(void * ctx);
int (* yajl_boolean)(void * ctx, int boolVal);
int (* yajl_integer)(void * ctx, long long integerVal);
+ int (* yajl_uinteger)(void * ctx, unsigned long long uintegerVal);
int (* yajl_double)(void * ctx, double doubleVal);
/** A callback which passes the string representation of the number
* back to the client. Will be used for all numbers when present */
Index: yajl_parser.c
===================================================================
--- yajl_parser.c (revision 767861)
+++ yajl_parser.c (revision 767862)
@@ -30,6 +30,7 @@
#include <math.h>
#define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10))
+#define MAX_UVALUE_TO_MULTIPLY ((ULLONG_MAX / 10) + (ULLONG_MAX % 10))
/* same semantics as strtol */
long long
@@ -57,6 +58,35 @@
return sign * ret;
}
+unsigned long long
+yajl_parse_uinteger(const unsigned char *number, unsigned int length)
+{
+ unsigned long long ret = 0;
+ const unsigned char *pos = number;
+ if (*pos == '-') {
+ errno = ERANGE;
+ return 0;
+ }
+
+ if (*pos == '+') { pos++; }
+
+ while (pos < number + length) {
+ if ( ret > MAX_UVALUE_TO_MULTIPLY ) {
+ errno = ERANGE;
+ return ULLONG_MAX;
+ }
+ ret *= 10ull;
+ if (ULLONG_MAX - ret < (unsigned long long)(*pos - '0')) {
+ errno = ERANGE;
+ return ULLONG_MAX;
+ }
+ ret += (unsigned long long)(*pos++ - '0');
+ }
+
+ return ret;
+}
+
+
unsigned char *
yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
size_t jsonTextLen, int verbose)
@@ -283,6 +313,37 @@
if ((i == LLONG_MIN || i == LLONG_MAX) &&
errno == ERANGE)
{
+ unsigned long long ui = 0;
+ int parsing_failed = 1;
+ if (hand->callbacks->yajl_uinteger) {
+ errno = 0;
+ ui = yajl_parse_uinteger(buf, bufLen);
+ if ((ui == 0 || ui == ULLONG_MAX) && errno == ERANGE)
+ parsing_failed = 1;
+ else
+ parsing_failed = 0;
+ }
+
+ if (parsing_failed) {
+ yajl_bs_set(hand->stateStack,
+ yajl_state_parse_error);
+ hand->parseError = "integer overflow" ;
+ /* try to restore error offset */
+ if (*offset >= bufLen) *offset -= bufLen;
+ else *offset = 0;
+ goto around_again;
+ } else {
+ _CC_CHK(hand->callbacks->yajl_uinteger(hand->ctx,
+ ui));
+ }
+ } else {
+ _CC_CHK(hand->callbacks->yajl_integer(hand->ctx,
+ i));
+ }
+ } else if (hand->callbacks->yajl_uinteger) {
+ unsigned long long ui = 0;
+ ui = yajl_parse_uinteger(buf, bufLen);
+ if ((ui == 0 || ui == ULLONG_MAX) && errno == ERANGE) {
yajl_bs_set(hand->stateStack,
yajl_state_parse_error);
hand->parseError = "integer overflow" ;
@@ -291,8 +352,8 @@
else *offset = 0;
goto around_again;
}
- _CC_CHK(hand->callbacks->yajl_integer(hand->ctx,
- i));
+ _CC_CHK(hand->callbacks->yajl_uinteger(hand->ctx,
+ ui));
}
}
break;
Index: yajl_tree.c
===================================================================
--- yajl_tree.c (revision 767861)
+++ yajl_tree.c (revision 767862)
@@ -318,6 +318,14 @@
endptr = NULL;
errno = 0;
+ v->u.number.ui = yajl_parse_uinteger((const unsigned char *) v->u.number.r,
+ strlen(v->u.number.r));
+
+ if ((errno == 0) && (endptr != NULL) && (*endptr == 0))
+ v->u.number.flags |= YAJL_NUMBER_UINT_VALID;
+
+ endptr = NULL;
+ errno = 0;
v->u.number.d = strtod(v->u.number.r, &endptr);
if ((errno == 0) && (endptr != NULL) && (*endptr == 0))
v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID;
@@ -409,6 +417,7 @@
/* null = */ handle_null,
/* boolean = */ handle_boolean,
/* integer = */ NULL,
+ /* unsigned integer = */ NULL,
/* double = */ NULL,
/* number = */ handle_number,
/* string = */ handle_string,
Index: yajl_parser.h
===================================================================
--- yajl_parser.h (revision 767861)
+++ yajl_parser.h (revision 767862)
@@ -74,5 +74,8 @@
long long
yajl_parse_integer(const unsigned char *number, unsigned int length);
+unsigned long long
+yajl_parse_uinteger(const unsigned char *number, unsigned int length);
+
#endif
Index: yajl_tree.h
===================================================================
--- yajl_tree.h (revision 767861)
+++ yajl_tree.h (revision 767862)
@@ -50,6 +50,7 @@
#define YAJL_NUMBER_INT_VALID 0x01
#define YAJL_NUMBER_DOUBLE_VALID 0x02
+#define YAJL_NUMBER_UINT_VALID 0x04
/** A pointer to a node in the parse tree */
typedef struct yajl_val_s * yajl_val;
@@ -73,6 +74,7 @@
char * string;
struct {
long long i; /*< integer value, if representable. */
+ unsigned long long ui; /*< unsigned integer value, if representable. */
double d; /*< double value, if representable. */
/** Signals whether the \em i and \em d members are
* valid. See \c YAJL_NUMBER_INT_VALID and
@@ -145,6 +147,7 @@
#define YAJL_IS_STRING(v) (((v) != NULL) && ((v)->type == yajl_t_string))
#define YAJL_IS_NUMBER(v) (((v) != NULL) && ((v)->type == yajl_t_number))
#define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_INT_VALID))
+#define YAJL_IS_UINTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_UINT_VALID))
#define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_DOUBLE_VALID))
#define YAJL_IS_OBJECT(v) (((v) != NULL) && ((v)->type == yajl_t_object))
#define YAJL_IS_ARRAY(v) (((v) != NULL) && ((v)->type == yajl_t_array ))
@@ -168,6 +171,10 @@
* check type first, perhaps using YAJL_IS_INTEGER */
#define YAJL_GET_INTEGER(v) ((v)->u.number.i)
+/** Get the 64bit (unsigned long long) unsigned integer representation of a number. You should
+ * check type first, perhaps using YAJL_IS_UINTEGER */
+#define YAJL_GET_UINTEGER(v) ((v)->u.number.ui)
+
/** Get a pointer to a yajl_val_object or NULL if the value is not an object. */
#define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->u.object : NULL)
Index: yajl_gen.c
===================================================================
--- yajl_gen.c (revision 767861)
+++ yajl_gen.c (revision 767862)
@@ -208,6 +208,19 @@
return yajl_gen_status_ok;
}
+yajl_gen_status
+yajl_gen_uinteger(yajl_gen g, unsigned long long number)
+{
+ char i[32];
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ sprintf(i, "%llu", number);
+ g->print(g->ctx, i, (unsigned int)strlen(i));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+
#ifdef WIN32
#include <float.h>
#define isnan _isnan
Index: yajl_gen.h
===================================================================
--- yajl_gen.h (revision 767861)
+++ yajl_gen.h (revision 767862)
@@ -121,6 +121,7 @@
YAJL_API void yajl_gen_free(yajl_gen handle);
YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long long int number);
+ YAJL_API yajl_gen_status yajl_gen_uinteger(yajl_gen hand, unsigned long long number);
/** generate a floating point number. number may not be infinity or
* NaN, as these have no representation in JSON. In these cases the
* generator will return 'yajl_gen_invalid_number' */
|