| 234 | } |
| 235 | |
| 236 | sds writeJsonValue(sds output, const char *valIn, size_t cchIn) { |
| 237 | const char *val = valIn; |
| 238 | size_t cch = cchIn; |
| 239 | int cchEscapeExtra = 0; |
| 240 | |
| 241 | // First scan for escaped chars |
| 242 | for (size_t ich = 0; ich < cchIn; ++ich) { |
| 243 | if (FSimpleJsonEscapeCh(valIn[ich])) { |
| 244 | ++cchEscapeExtra; |
| 245 | } else if (FExtendedJsonEscapeCh(valIn[ich])) { |
| 246 | cchEscapeExtra += 5; |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | if (cchEscapeExtra > 0) { |
| 251 | size_t ichDst = 0; |
| 252 | sds dst = sdsnewlen(SDS_NOINIT, cchIn+cchEscapeExtra); |
| 253 | for (size_t ich = 0; ich < cchIn; ++ich) { |
| 254 | switch (valIn[ich]) { |
| 255 | case '"': |
| 256 | dst[ichDst++] = '\\'; dst[ichDst++] = '"'; |
| 257 | break; |
| 258 | case '\\': |
| 259 | dst[ichDst++] = '\\'; dst[ichDst++] = '\\'; |
| 260 | break; |
| 261 | |
| 262 | default: |
| 263 | serverAssert(!FSimpleJsonEscapeCh(valIn[ich])); |
| 264 | if (FExtendedJsonEscapeCh(valIn[ich])) { |
| 265 | dst[ichDst++] = '\\'; dst[ichDst++] = 'u'; |
| 266 | snprintf(dst + ichDst, cchIn+cchEscapeExtra-ichDst, "%4x", valIn[ich]); |
| 267 | ichDst += 4; |
| 268 | } else { |
| 269 | dst[ichDst++] = valIn[ich]; |
| 270 | } |
| 271 | break; |
| 272 | } |
| 273 | } |
| 274 | val = (const char*)dst; |
| 275 | serverAssert(ichDst == (cchIn+cchEscapeExtra)); |
| 276 | cch = ichDst; |
| 277 | } |
| 278 | |
| 279 | output = sdscat(output, "\""); |
| 280 | output = sdscatlen(output, val, cch); |
| 281 | output = sdscat(output, "\""); |
| 282 | |
| 283 | if (val != valIn) |
| 284 | sdsfree(val); |
| 285 | |
| 286 | return output; |
| 287 | } |
| 288 | sds writeJsonValue(sds output, sds val) { |
| 289 | return writeJsonValue(output, (const char*)val, sdslen(val)); |
| 290 | } |
no test coverage detected