summaryrefslogtreecommitdiff
path: root/js/src/json.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/json.cpp')
-rw-r--r--js/src/json.cpp69
1 files changed, 55 insertions, 14 deletions
diff --git a/js/src/json.cpp b/js/src/json.cpp
index 73e37e2370..e32994e908 100644
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -66,26 +66,67 @@ InfallibleQuote(RangedPtr<const SrcCharT> srcBegin, RangedPtr<const SrcCharT> sr
/* Step 1. */
*dstPtr++ = '"';
+ // XXX: This is a rather ugly in-line definition. Move it somewhere better?
+ auto ToLowerHex = [](uint8_t u) {
+ MOZ_ASSERT(u <= 0xF);
+ return "0123456789abcdef"[u];
+ };
+
/* Step 2. */
while (srcBegin != srcEnd) {
- SrcCharT c = *srcBegin++;
- size_t escapeIndex = c % sizeof(escapeLookup);
- Latin1Char escaped = escapeLookup[escapeIndex];
- if (MOZ_LIKELY((escapeIndex != size_t(c)) || !escaped)) {
+ const SrcCharT c = *srcBegin++;
+
+ // Handle the Latin-1 cases.
+ if (MOZ_LIKELY(c < sizeof(escapeLookup))) {
+ Latin1Char escaped = escapeLookup[c];
+
+ // Directly copy non-escaped code points.
+ if (escaped == 0) {
+ *dstPtr++ = c;
+ continue;
+ }
+
+ // Escape the rest, elaborating Unicode escapes when needed.
+ *dstPtr++ = '\\';
+ *dstPtr++ = escaped;
+ if (escaped == 'u') {
+ *dstPtr++ = '0';
+ *dstPtr++ = '0';
+
+ uint8_t x = c >> 4;
+ MOZ_ASSERT(x < 10);
+ *dstPtr++ = '0' + x;
+
+ *dstPtr++ = ToLowerHex(c & 0xF);
+ }
+
+ continue;
+ }
+
+ // Non-ASCII non-surrogates are directly copied.
+ if (!unicode::IsSurrogate(c)) {
*dstPtr++ = c;
continue;
}
- *dstPtr++ = '\\';
- *dstPtr++ = escaped;
- if (escaped == 'u') {
- MOZ_ASSERT(c < ' ');
- MOZ_ASSERT((c >> 4) < 10);
- uint8_t x = c >> 4, y = c % 16;
- *dstPtr++ = '0';
- *dstPtr++ = '0';
- *dstPtr++ = '0' + x;
- *dstPtr++ = y < 10 ? '0' + y : 'a' + (y - 10);
+
+ // So too for complete surrogate pairs.
+ if (MOZ_LIKELY(unicode::IsLeadSurrogate(c) &&
+ srcBegin < srcEnd &&
+ unicode::IsTrailSurrogate(*srcBegin)))
+ {
+ *dstPtr++ = c;
+ *dstPtr++ = *srcBegin++;
+ continue;
}
+
+ // But lone surrogates are Unicode-escaped.
+ char32_t as32 = char32_t(c);
+ *dstPtr++ = '\\';
+ *dstPtr++ = 'u';
+ *dstPtr++ = ToLowerHex(as32 >> 12);
+ *dstPtr++ = ToLowerHex((as32 >> 8) & 0xF);
+ *dstPtr++ = ToLowerHex((as32 >> 4) & 0xF);
+ *dstPtr++ = ToLowerHex(as32 & 0xF);
}
/* Steps 3-4. */