src/json.c

changeset 1119
ff4d7e76f85a
parent 1117
54df904472b0
equal deleted inserted replaced
1118:9fa87f9882ba 1119:ff4d7e76f85a
343 return CX_JSON_INCOMPLETE_DATA; 343 return CX_JSON_INCOMPLETE_DATA;
344 } 344 }
345 345
346 static cxmutstr unescape_string(const CxAllocator *a, cxmutstr str) { 346 static cxmutstr unescape_string(const CxAllocator *a, cxmutstr str) {
347 // TODO: support more escape sequences 347 // TODO: support more escape sequences
348 // we know that the unescaped string will be shorter by at least 2 chars 348 // TODO: to be consistent with escape_string() we might want to expect that the enclosing quotes were already removed
349 cxmutstr result; 349 cxmutstr result;
350 result.length = 0; 350 result.length = 0;
351 result.ptr = cxMalloc(a, str.length - 1); 351 result.ptr = cxMalloc(a, str.length - 1);
352 if (result.ptr == NULL) return result; // LCOV_EXCL_LINE 352 if (result.ptr == NULL) return result; // LCOV_EXCL_LINE
353 353
371 } 371 }
372 } 372 }
373 result.ptr[result.length] = 0; 373 result.ptr[result.length] = 0;
374 374
375 return result; 375 return result;
376 }
377
378 static cxmutstr escape_string(cxmutstr str) {
379 CxBuffer buf = {0};
380
381 bool all_printable = true;
382 for (size_t i = 0; i < str.length; i++) {
383 bool escape = !isprint(str.ptr[i])
384 || str.ptr[i] == '\\'
385 || str.ptr[i] == '"'
386 // TODO: make escaping slash optional
387 || str.ptr[i] == '/';
388
389 if (all_printable && escape) {
390 size_t capa = str.length + 32;
391 char *space = malloc(capa);
392 if (space == NULL) return cx_mutstrn(NULL, 0);
393 cxBufferInit(&buf, space, capa, NULL, CX_BUFFER_AUTO_EXTEND);
394 cxBufferWrite(str.ptr, 1, i, &buf);
395 all_printable = false;
396 }
397 if (escape) {
398 cxBufferPut(&buf, '\\');
399 if (str.ptr[i] == '\"') {
400 cxBufferPut(&buf, '\"');
401 } else if (str.ptr[i] == '\n') {
402 cxBufferPut(&buf, 'n');
403 } else if (str.ptr[i] == '\t') {
404 cxBufferPut(&buf, 't');
405 } else if (str.ptr[i] == '\r') {
406 cxBufferPut(&buf, 'r');
407 } else if (str.ptr[i] == '\\') {
408 cxBufferPut(&buf, '\\');
409 } else if (str.ptr[i] == '/') {
410 cxBufferPut(&buf, '/');
411 } else if (str.ptr[i] == '\f') {
412 cxBufferPut(&buf, 'f');
413 } else if (str.ptr[i] == '\b') {
414 cxBufferPut(&buf, 'b');
415 } else {
416 char code[6];
417 snprintf(code, sizeof(code), "u%04x",
418 (unsigned int)(0xff & str.ptr[i]));
419 cxBufferPutString(&buf, code);
420 }
421 } else if (!all_printable) {
422 cxBufferPut(&buf, str.ptr[i]);
423 }
424 }
425 if (!all_printable) {
426 str = cx_mutstrn(buf.space, buf.size);
427 }
428 cxBufferDestroy(&buf);
429 return str;
376 } 430 }
377 431
378 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) { 432 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) {
379 CxJsonValue *v = cxCalloc(json->allocator, 1, sizeof(CxJsonValue)); 433 CxJsonValue *v = cxCalloc(json->allocator, 1, sizeof(CxJsonValue));
380 if (v == NULL) return NULL; // LCOV_EXCL_LINE 434 if (v == NULL) return NULL; // LCOV_EXCL_LINE
1082 } 1136 }
1083 } 1137 }
1084 1138
1085 // the name 1139 // the name
1086 actual += wfunc("\"", 1, 1, target); 1140 actual += wfunc("\"", 1, 1, target);
1087 // TODO: escape the string 1141 cxmutstr name = escape_string(member->name);
1088 actual += wfunc(member->name.ptr, 1, 1142 actual += wfunc(name.ptr, 1, name.length, target);
1089 member->name.length, target); 1143 if (name.ptr != member->name.ptr) {
1144 cx_strfree(&name);
1145 }
1090 actual += wfunc("\"", 1, 1, target); 1146 actual += wfunc("\"", 1, 1, target);
1091 const char *obj_name_sep = ": "; 1147 const char *obj_name_sep = ": ";
1092 if (settings->pretty) { 1148 if (settings->pretty) {
1093 actual += wfunc(obj_name_sep, 1, 2, target); 1149 actual += wfunc(obj_name_sep, 1, 2, target);
1094 expected += 4 + member->name.length; 1150 expected += 4 + member->name.length;
1150 expected++; 1206 expected++;
1151 break; 1207 break;
1152 } 1208 }
1153 case CX_JSON_STRING: { 1209 case CX_JSON_STRING: {
1154 actual += wfunc("\"", 1, 1, target); 1210 actual += wfunc("\"", 1, 1, target);
1155 // TODO: escape the string 1211 cxmutstr str = escape_string(value->value.string);
1156 actual += wfunc(value->value.string.ptr, 1, 1212 actual += wfunc(str.ptr, 1, str.length, target);
1157 value->value.string.length, target); 1213 if (str.ptr != value->value.string.ptr) {
1214 cx_strfree(&str);
1215 }
1158 actual += wfunc("\"", 1, 1, target); 1216 actual += wfunc("\"", 1, 1, target);
1159 expected += 2 + value->value.string.length; 1217 expected += 2 + value->value.string.length;
1160 break; 1218 break;
1161 } 1219 }
1162 case CX_JSON_NUMBER: { 1220 case CX_JSON_NUMBER: {

mercurial