| 125 if (token->allocated) { |
126 if (token->allocated) { |
| 126 cx_strfree(&token->content); |
127 cx_strfree(&token->content); |
| 127 } |
128 } |
| 128 } |
129 } |
| 129 |
130 |
| 130 static bool json_isdigit(char c) { |
|
| 131 // TODO: remove once UCX has public API for this |
|
| 132 return c >= '0' && c <= '9'; |
|
| 133 } |
|
| 134 |
|
| 135 static bool json_isspace(char c) { |
|
| 136 // TODO: remove once UCX has public API for this |
|
| 137 return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f'; |
|
| 138 } |
|
| 139 |
|
| 140 static int num_isexp(const char *content, size_t length, size_t pos) { |
131 static int num_isexp(const char *content, size_t length, size_t pos) { |
| 141 if (pos >= length) { |
132 if (pos >= length) { |
| 142 return 0; |
133 return 0; |
| 143 } |
134 } |
| 144 |
135 |
| 145 int ok = 0; |
136 int ok = 0; |
| 146 for (size_t i = pos; i < length; i++) { |
137 for (size_t i = pos; i < length; i++) { |
| 147 char c = content[i]; |
138 char c = content[i]; |
| 148 if (json_isdigit(c)) { |
139 if (isdigit((unsigned char)c)) { |
| 149 ok = 1; |
140 ok = 1; |
| 150 } else if (i == pos) { |
141 } else if (i == pos) { |
| 151 if (!(c == '+' || c == '-')) { |
142 if (!(c == '+' || c == '-')) { |
| 152 return 0; |
143 return 0; |
| 153 } |
144 } |
| 173 return CX_JSON_TOKEN_ERROR; // more than one decimal separator |
164 return CX_JSON_TOKEN_ERROR; // more than one decimal separator |
| 174 } |
165 } |
| 175 type = CX_JSON_TOKEN_NUMBER; |
166 type = CX_JSON_TOKEN_NUMBER; |
| 176 } else if (content[i] == 'e' || content[i] == 'E') { |
167 } else if (content[i] == 'e' || content[i] == 'E') { |
| 177 return num_isexp(content, length, i + 1) ? CX_JSON_TOKEN_NUMBER : CX_JSON_TOKEN_ERROR; |
168 return num_isexp(content, length, i + 1) ? CX_JSON_TOKEN_NUMBER : CX_JSON_TOKEN_ERROR; |
| 178 } else if (!json_isdigit(content[i])) { |
169 } else if (!isdigit((unsigned char)content[i])) { |
| 179 return CX_JSON_TOKEN_ERROR; // char is not a digit, decimal separator or exponent sep |
170 return CX_JSON_TOKEN_ERROR; // char is not a digit, decimal separator or exponent sep |
| 180 } |
171 } |
| 181 } |
172 } |
| 182 |
173 |
| 183 return type; |
174 return type; |
| 637 cx_strfree_a(json->allocator, &json->uncompleted_member.name); |
628 cx_strfree_a(json->allocator, &json->uncompleted_member.name); |
| 638 json->uncompleted_member = (CxJsonObjValue){{NULL, 0}, NULL}; |
629 json->uncompleted_member = (CxJsonObjValue){{NULL, 0}, NULL}; |
| 639 } |
630 } |
| 640 } |
631 } |
| 641 |
632 |
| |
633 void cxJsonReset(CxJson *json) { |
| |
634 const CxAllocator *allocator = json->allocator; |
| |
635 cxJsonDestroy(json); |
| |
636 cxJsonInit(json, allocator); |
| |
637 } |
| |
638 |
| 642 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { |
639 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { |
| 643 if (cxBufferEof(&json->buffer)) { |
640 if (cxBufferEof(&json->buffer)) { |
| 644 // reinitialize the buffer |
641 // reinitialize the buffer |
| 645 cxBufferDestroy(&json->buffer); |
642 cxBufferDestroy(&json->buffer); |
| 646 cxBufferInit(&json->buffer, (char*) buf, size, |
643 cxBufferInit(&json->buffer, (char*) buf, size, |
| 1133 } |
1130 } |
| 1134 value->value.array.array_size--; |
1131 value->value.array.array_size--; |
| 1135 return ret; |
1132 return ret; |
| 1136 } |
1133 } |
| 1137 |
1134 |
| |
1135 char *cxJsonAsString(const CxJsonValue *value) { |
| |
1136 return value->value.string.ptr; |
| |
1137 } |
| |
1138 |
| |
1139 cxstring cxJsonAsCxString(const CxJsonValue *value) { |
| |
1140 return cx_strcast(value->value.string); |
| |
1141 } |
| |
1142 |
| |
1143 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) { |
| |
1144 return value->value.string; |
| |
1145 } |
| |
1146 |
| |
1147 double cxJsonAsDouble(const CxJsonValue *value) { |
| |
1148 if (value->type == CX_JSON_INTEGER) { |
| |
1149 return (double) value->value.integer; |
| |
1150 } else { |
| |
1151 return value->value.number; |
| |
1152 } |
| |
1153 } |
| |
1154 |
| |
1155 int64_t cxJsonAsInteger(const CxJsonValue *value) { |
| |
1156 if (value->type == CX_JSON_INTEGER) { |
| |
1157 return value->value.integer; |
| |
1158 } else { |
| |
1159 return (int64_t) value->value.number; |
| |
1160 } |
| |
1161 } |
| |
1162 |
| 1138 CxIterator cxJsonArrIter(const CxJsonValue *value) { |
1163 CxIterator cxJsonArrIter(const CxJsonValue *value) { |
| 1139 return cxIteratorPtr( |
1164 return cxIteratorPtr( |
| 1140 value->value.array.array, |
1165 value->value.array.array, |
| 1141 value->value.array.array_size |
1166 value->value.array.array_size, |
| |
1167 true // arrays need to keep order |
| 1142 ); |
1168 ); |
| 1143 } |
1169 } |
| 1144 |
1170 |
| 1145 CxIterator cxJsonObjIter(const CxJsonValue *value) { |
1171 CxIterator cxJsonObjIter(const CxJsonValue *value) { |
| 1146 return cxIterator( |
1172 return cxIterator( |
| 1147 value->value.object.values, |
1173 value->value.object.values, |
| 1148 sizeof(CxJsonObjValue), |
1174 sizeof(CxJsonObjValue), |
| 1149 value->value.object.values_size |
1175 value->value.object.values_size, |
| |
1176 true // TODO: objects do not always need to keep order |
| 1150 ); |
1177 ); |
| 1151 } |
1178 } |
| 1152 |
1179 |
| 1153 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) { |
1180 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) { |
| 1154 size_t index = json_find_objvalue(value, name); |
1181 size_t index = json_find_objvalue(value, name); |
| 1155 if (index >= value->value.object.values_size) { |
1182 if (index >= value->value.object.values_size) { |
| 1156 return &cx_json_value_nothing; |
1183 return &cx_json_value_nothing; |
| 1157 } else { |
1184 } else { |
| 1158 return value->value.object.values[index].value; |
1185 return value->value.object.values[index].value; |
| 1159 } |
1186 } |
| 1160 } |
1187 } |
| 1161 |
1188 |
| 1162 CxJsonValue *cx_json_obj_remove_cxstr(CxJsonValue *value, cxstring name) { |
1189 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) { |
| 1163 size_t index = json_find_objvalue(value, name); |
1190 size_t index = json_find_objvalue(value, name); |
| 1164 if (index >= value->value.object.values_size) { |
1191 if (index >= value->value.object.values_size) { |
| 1165 return NULL; |
1192 return NULL; |
| 1166 } else { |
1193 } else { |
| 1167 CxJsonObjValue kv = value->value.object.values[index]; |
1194 CxJsonObjValue kv = value->value.object.values[index]; |
| 1168 cx_strfree_a(value->allocator, &kv.name); |
1195 cx_strfree_a(value->allocator, &kv.name); |
| 1169 // TODO: replace with cx_array_remove() |
1196 // TODO: replace with cx_array_remove() / cx_array_remove_fast() |
| 1170 value->value.object.values_size--; |
1197 value->value.object.values_size--; |
| 1171 memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue)); |
1198 memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue)); |
| 1172 return kv.value; |
1199 return kv.value; |
| 1173 } |
1200 } |
| 1174 } |
1201 } |