| 68 | } |
| 69 | |
| 70 | Value parseString() { |
| 71 | next(); // opening " |
| 72 | Value v; |
| 73 | v.type = Type::String; |
| 74 | while (pos < len && s[pos] != '"') { |
| 75 | if (s[pos] == '\\' && pos + 1 < len) { |
| 76 | ++pos; |
| 77 | switch (s[pos]) { |
| 78 | case '"': v.strVal += '"'; break; |
| 79 | case '\\': v.strVal += '\\'; break; |
| 80 | case '/': v.strVal += '/'; break; |
| 81 | case 'n': v.strVal += '\n'; break; |
| 82 | case 'r': v.strVal += '\r'; break; |
| 83 | case 't': v.strVal += '\t'; break; |
| 84 | case 'u': { |
| 85 | if (pos + 4 < len) { |
| 86 | char hex[5] = {s[pos+1],s[pos+2],s[pos+3],s[pos+4],0}; |
| 87 | unsigned cp = strtoul(hex, nullptr, 16); |
| 88 | pos += 4; |
| 89 | // handle UTF-16 surrogate pairs (\uD800-\uDBFF \uDC00-\uDFFF) |
| 90 | if (cp >= 0xD800 && cp <= 0xDBFF && pos + 2 < len |
| 91 | && s[pos+1] == '\\' && s[pos+2] == 'u' && pos + 6 < len) { |
| 92 | char hex2[5] = {s[pos+3],s[pos+4],s[pos+5],s[pos+6],0}; |
| 93 | unsigned lo = strtoul(hex2, nullptr, 16); |
| 94 | if (lo >= 0xDC00 && lo <= 0xDFFF) { |
| 95 | cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00); |
| 96 | pos += 6; // skip \uXXXX |
| 97 | } |
| 98 | } |
| 99 | // Lone surrogates (high without low, or bare low) are invalid |
| 100 | // in UTF-8. Replace with U+FFFD (replacement character). |
| 101 | if (cp >= 0xD800 && cp <= 0xDFFF) { |
| 102 | cp = 0xFFFD; |
| 103 | } |
| 104 | if (cp < 0x80) { |
| 105 | v.strVal += (char)cp; |
| 106 | } else if (cp < 0x800) { |
| 107 | v.strVal += (char)(0xC0 | (cp >> 6)); |
| 108 | v.strVal += (char)(0x80 | (cp & 0x3F)); |
| 109 | } else if (cp < 0x10000) { |
| 110 | v.strVal += (char)(0xE0 | (cp >> 12)); |
| 111 | v.strVal += (char)(0x80 | ((cp >> 6) & 0x3F)); |
| 112 | v.strVal += (char)(0x80 | (cp & 0x3F)); |
| 113 | } else { |
| 114 | v.strVal += (char)(0xF0 | (cp >> 18)); |
| 115 | v.strVal += (char)(0x80 | ((cp >> 12) & 0x3F)); |
| 116 | v.strVal += (char)(0x80 | ((cp >> 6) & 0x3F)); |
| 117 | v.strVal += (char)(0x80 | (cp & 0x3F)); |
| 118 | } |
| 119 | } |
| 120 | break; |
| 121 | } |
| 122 | default: v.strVal += s[pos]; break; |
| 123 | } |
| 124 | } else { |
| 125 | v.strVal += s[pos]; |
| 126 | } |
| 127 | ++pos; |
nothing calls this directly
no outgoing calls
no test coverage detected