| 699 | } |
| 700 | |
| 701 | static char *web_json_parse_string_at(const char *q, const char **endp) { |
| 702 | if (*q != '"') return NULL; |
| 703 | q++; |
| 704 | web_buf b = {0}; |
| 705 | while (*q && *q != '"') { |
| 706 | if (*q != '\\') { |
| 707 | web_buf_append(&b, q++, 1); |
| 708 | continue; |
| 709 | } |
| 710 | q++; |
| 711 | switch (*q) { |
| 712 | case '"': web_buf_append(&b, "\"", 1); q++; break; |
| 713 | case '\\': web_buf_append(&b, "\\", 1); q++; break; |
| 714 | case '/': web_buf_append(&b, "/", 1); q++; break; |
| 715 | case 'b': web_buf_append(&b, "\b", 1); q++; break; |
| 716 | case 'f': web_buf_append(&b, "\f", 1); q++; break; |
| 717 | case 'n': web_buf_append(&b, "\n", 1); q++; break; |
| 718 | case 'r': web_buf_append(&b, "\r", 1); q++; break; |
| 719 | case 't': web_buf_append(&b, "\t", 1); q++; break; |
| 720 | case 'u': { |
| 721 | int v = web_hex4(q + 1); |
| 722 | if (v < 0) { free(b.ptr); return NULL; } |
| 723 | q += 5; |
| 724 | if (v >= 0xd800 && v <= 0xdbff && q[0] == '\\' && q[1] == 'u') { |
| 725 | int lo = web_hex4(q + 2); |
| 726 | if (lo >= 0xdc00 && lo <= 0xdfff) { |
| 727 | unsigned code = 0x10000 + (((unsigned)v - 0xd800) << 10) + |
| 728 | ((unsigned)lo - 0xdc00); |
| 729 | web_utf8_append(&b, code); |
| 730 | q += 6; |
| 731 | break; |
| 732 | } |
| 733 | } |
| 734 | web_utf8_append(&b, (unsigned)v); |
| 735 | break; |
| 736 | } |
| 737 | default: |
| 738 | if (*q) web_buf_append(&b, q++, 1); |
| 739 | break; |
| 740 | } |
| 741 | } |
| 742 | if (*q != '"') { |
| 743 | free(b.ptr); |
| 744 | return NULL; |
| 745 | } |
| 746 | if (endp) *endp = q + 1; |
| 747 | return web_buf_take(&b); |
| 748 | } |
| 749 | |
| 750 | static char *web_json_get_string(const char *json, const char *key) { |
| 751 | char pat[128]; |
no test coverage detected