src/ucx/json.c

changeset 621
956c03c25edd
parent 582
82b60a8dd55c
child 645
0c85c4cd0dd8
equal deleted inserted replaced
620:a202cb1ee175 621:956c03c25edd
30 30
31 #include <string.h> 31 #include <string.h>
32 #include <assert.h> 32 #include <assert.h>
33 #include <stdio.h> 33 #include <stdio.h>
34 #include <inttypes.h> 34 #include <inttypes.h>
35 #include <ctype.h>
35 36
36 /* 37 /*
37 * RFC 8259 38 * RFC 8259
38 * https://tools.ietf.org/html/rfc8259 39 * https://tools.ietf.org/html/rfc8259
39 */ 40 */
44 const CxJsonObjValue *left = l; 45 const CxJsonObjValue *left = l;
45 const CxJsonObjValue *right = r; 46 const CxJsonObjValue *right = r;
46 return cx_strcmp(cx_strcast(left->name), cx_strcast(right->name)); 47 return cx_strcmp(cx_strcast(left->name), cx_strcast(right->name));
47 } 48 }
48 49
49 static CxJsonObjValue *json_find_objvalue(const CxJsonValue *obj, cxstring name) { 50 static size_t json_find_objvalue(const CxJsonValue *obj, cxstring name) {
50 assert(obj->type == CX_JSON_OBJECT); 51 assert(obj->type == CX_JSON_OBJECT);
51 CxJsonObjValue kv_dummy; 52 CxJsonObjValue kv_dummy;
52 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length); 53 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length);
53 size_t index = cx_array_binary_search( 54 return cx_array_binary_search(
54 obj->value.object.values, 55 obj->value.object.values,
55 obj->value.object.values_size, 56 obj->value.object.values_size,
56 sizeof(CxJsonObjValue), 57 sizeof(CxJsonObjValue),
57 &kv_dummy, 58 &kv_dummy,
58 json_cmp_objvalue 59 json_cmp_objvalue
59 ); 60 );
60 if (index == obj->value.object.values_size) {
61 return NULL;
62 } else {
63 return &obj->value.object.values[index];
64 }
65 } 61 }
66 62
67 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) { 63 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) {
68 assert(objv->type == CX_JSON_OBJECT); 64 assert(objv->type == CX_JSON_OBJECT);
69 const CxAllocator * const al = objv->allocator; 65 const CxAllocator * const al = objv->allocator;
130 if (token->allocated) { 126 if (token->allocated) {
131 cx_strfree(&token->content); 127 cx_strfree(&token->content);
132 } 128 }
133 } 129 }
134 130
135 static bool json_isdigit(char c) {
136 // TODO: remove once UCX has public API for this
137 return c >= '0' && c <= '9';
138 }
139
140 static bool json_isspace(char c) {
141 // TODO: remove once UCX has public API for this
142 return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f';
143 }
144
145 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) {
146 if (pos >= length) { 132 if (pos >= length) {
147 return 0; 133 return 0;
148 } 134 }
149 135
150 int ok = 0; 136 int ok = 0;
151 for (size_t i = pos; i < length; i++) { 137 for (size_t i = pos; i < length; i++) {
152 char c = content[i]; 138 char c = content[i];
153 if (json_isdigit(c)) { 139 if (isdigit((unsigned char)c)) {
154 ok = 1; 140 ok = 1;
155 } else if (i == pos) { 141 } else if (i == pos) {
156 if (!(c == '+' || c == '-')) { 142 if (!(c == '+' || c == '-')) {
157 return 0; 143 return 0;
158 } 144 }
165 } 151 }
166 152
167 static CxJsonTokenType token_numbertype(const char *content, size_t length) { 153 static CxJsonTokenType token_numbertype(const char *content, size_t length) {
168 if (length == 0) return CX_JSON_TOKEN_ERROR; 154 if (length == 0) return CX_JSON_TOKEN_ERROR;
169 155
170 if (content[0] != '-' && !json_isdigit(content[0])) { 156 if (content[0] != '-' && !isdigit((unsigned char)content[0])) {
171 return CX_JSON_TOKEN_ERROR; 157 return CX_JSON_TOKEN_ERROR;
172 } 158 }
173 159
174 CxJsonTokenType type = CX_JSON_TOKEN_INTEGER; 160 CxJsonTokenType type = CX_JSON_TOKEN_INTEGER;
175 for (size_t i = 1; i < length; i++) { 161 for (size_t i = 1; i < length; i++) {
178 return CX_JSON_TOKEN_ERROR; // more than one decimal separator 164 return CX_JSON_TOKEN_ERROR; // more than one decimal separator
179 } 165 }
180 type = CX_JSON_TOKEN_NUMBER; 166 type = CX_JSON_TOKEN_NUMBER;
181 } else if (content[i] == 'e' || content[i] == 'E') { 167 } else if (content[i] == 'e' || content[i] == 'E') {
182 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;
183 } else if (!json_isdigit(content[i])) { 169 } else if (!isdigit((unsigned char)content[i])) {
184 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
185 } 171 }
186 } 172 }
187 173
188 return type; 174 return type;
242 } 228 }
243 case '"': { 229 case '"': {
244 return CX_JSON_TOKEN_STRING; 230 return CX_JSON_TOKEN_STRING;
245 } 231 }
246 default: { 232 default: {
247 if (json_isspace(c)) { 233 if (isspace((unsigned char)c)) {
248 return CX_JSON_TOKEN_SPACE; 234 return CX_JSON_TOKEN_SPACE;
249 } 235 }
250 } 236 }
251 } 237 }
252 return CX_JSON_NO_TOKEN; 238 return CX_JSON_NO_TOKEN;
642 cx_strfree_a(json->allocator, &json->uncompleted_member.name); 628 cx_strfree_a(json->allocator, &json->uncompleted_member.name);
643 json->uncompleted_member = (CxJsonObjValue){{NULL, 0}, NULL}; 629 json->uncompleted_member = (CxJsonObjValue){{NULL, 0}, NULL};
644 } 630 }
645 } 631 }
646 632
633 void cxJsonReset(CxJson *json) {
634 const CxAllocator *allocator = json->allocator;
635 cxJsonDestroy(json);
636 cxJsonInit(json, allocator);
637 }
638
647 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { 639 int cxJsonFilln(CxJson *json, const char *buf, size_t size) {
648 if (cxBufferEof(&json->buffer)) { 640 if (cxBufferEof(&json->buffer)) {
649 // reinitialize the buffer 641 // reinitialize the buffer
650 cxBufferDestroy(&json->buffer); 642 cxBufferDestroy(&json->buffer);
651 cxBufferInit(&json->buffer, (char*) buf, size, 643 cxBufferInit(&json->buffer, (char*) buf, size,
1124 return &cx_json_value_nothing; 1116 return &cx_json_value_nothing;
1125 } 1117 }
1126 return value->value.array.array[index]; 1118 return value->value.array.array[index];
1127 } 1119 }
1128 1120
1121 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
1122 if (index >= value->value.array.array_size) {
1123 return NULL;
1124 }
1125 CxJsonValue *ret = value->value.array.array[index];
1126 // TODO: replace with a low level cx_array_remove()
1127 size_t count = value->value.array.array_size - index - 1;
1128 if (count > 0) {
1129 memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*));
1130 }
1131 value->value.array.array_size--;
1132 return ret;
1133 }
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
1129 CxIterator cxJsonArrIter(const CxJsonValue *value) { 1163 CxIterator cxJsonArrIter(const CxJsonValue *value) {
1130 return cxIteratorPtr( 1164 return cxIteratorPtr(
1131 value->value.array.array, 1165 value->value.array.array,
1132 value->value.array.array_size 1166 value->value.array.array_size,
1167 true // arrays need to keep order
1133 ); 1168 );
1134 } 1169 }
1135 1170
1136 CxIterator cxJsonObjIter(const CxJsonValue *value) { 1171 CxIterator cxJsonObjIter(const CxJsonValue *value) {
1137 return cxIterator( 1172 return cxIterator(
1138 value->value.object.values, 1173 value->value.object.values,
1139 sizeof(CxJsonObjValue), 1174 sizeof(CxJsonObjValue),
1140 value->value.object.values_size 1175 value->value.object.values_size,
1176 true // TODO: objects do not always need to keep order
1141 ); 1177 );
1142 } 1178 }
1143 1179
1144 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) { 1180 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) {
1145 CxJsonObjValue *member = json_find_objvalue(value, name); 1181 size_t index = json_find_objvalue(value, name);
1146 if (member == NULL) { 1182 if (index >= value->value.object.values_size) {
1147 return &cx_json_value_nothing; 1183 return &cx_json_value_nothing;
1148 } else { 1184 } else {
1149 return member->value; 1185 return value->value.object.values[index].value;
1186 }
1187 }
1188
1189 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) {
1190 size_t index = json_find_objvalue(value, name);
1191 if (index >= value->value.object.values_size) {
1192 return NULL;
1193 } else {
1194 CxJsonObjValue kv = value->value.object.values[index];
1195 cx_strfree_a(value->allocator, &kv.name);
1196 // TODO: replace with cx_array_remove() / cx_array_remove_fast()
1197 value->value.object.values_size--;
1198 memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue));
1199 return kv.value;
1150 } 1200 }
1151 } 1201 }
1152 1202
1153 CxJsonWriter cxJsonWriterCompact(void) { 1203 CxJsonWriter cxJsonWriterCompact(void) {
1154 return (CxJsonWriter) { 1204 return (CxJsonWriter) {

mercurial