| 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; |
| 1124 return &cx_json_value_nothing; |
1110 return &cx_json_value_nothing; |
| 1125 } |
1111 } |
| 1126 return value->value.array.array[index]; |
1112 return value->value.array.array[index]; |
| 1127 } |
1113 } |
| 1128 |
1114 |
| |
1115 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { |
| |
1116 if (index >= value->value.array.array_size) { |
| |
1117 return NULL; |
| |
1118 } |
| |
1119 CxJsonValue *ret = value->value.array.array[index]; |
| |
1120 // TODO: replace with a low level cx_array_remove() |
| |
1121 size_t count = value->value.array.array_size - index - 1; |
| |
1122 if (count > 0) { |
| |
1123 memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*)); |
| |
1124 } |
| |
1125 value->value.array.array_size--; |
| |
1126 return ret; |
| |
1127 } |
| |
1128 |
| 1129 CxIterator cxJsonArrIter(const CxJsonValue *value) { |
1129 CxIterator cxJsonArrIter(const CxJsonValue *value) { |
| 1130 return cxIteratorPtr( |
1130 return cxIteratorPtr( |
| 1131 value->value.array.array, |
1131 value->value.array.array, |
| 1132 value->value.array.array_size |
1132 value->value.array.array_size |
| 1133 ); |
1133 ); |
| 1139 sizeof(CxJsonObjValue), |
1139 sizeof(CxJsonObjValue), |
| 1140 value->value.object.values_size |
1140 value->value.object.values_size |
| 1141 ); |
1141 ); |
| 1142 } |
1142 } |
| 1143 |
1143 |
| 1144 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) { |
1144 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) { |
| 1145 CxJsonObjValue *member = json_find_objvalue(value, name); |
1145 size_t index = json_find_objvalue(value, name); |
| 1146 if (member == NULL) { |
1146 if (index >= value->value.object.values_size) { |
| 1147 return &cx_json_value_nothing; |
1147 return &cx_json_value_nothing; |
| 1148 } else { |
1148 } else { |
| 1149 return member->value; |
1149 return value->value.object.values[index].value; |
| |
1150 } |
| |
1151 } |
| |
1152 |
| |
1153 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) { |
| |
1154 size_t index = json_find_objvalue(value, name); |
| |
1155 if (index >= value->value.object.values_size) { |
| |
1156 return NULL; |
| |
1157 } else { |
| |
1158 CxJsonObjValue kv = value->value.object.values[index]; |
| |
1159 cx_strfree_a(value->allocator, &kv.name); |
| |
1160 // TODO: replace with cx_array_remove() |
| |
1161 value->value.object.values_size--; |
| |
1162 memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue)); |
| |
1163 return kv.value; |
| 1150 } |
1164 } |
| 1151 } |
1165 } |
| 1152 |
1166 |
| 1153 CxJsonWriter cxJsonWriterCompact(void) { |
1167 CxJsonWriter cxJsonWriterCompact(void) { |
| 1154 return (CxJsonWriter) { |
1168 return (CxJsonWriter) { |