summaryrefslogtreecommitdiff
path: root/misc.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-08-14 10:55:02 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-14 17:06:28 -0600
commitc8a79cbfde0e42ac3d677bb986e4dbfc9e5cfa85 (patch)
tree10294f06b9d1143644dbdfb7a2e895acd8504efd /misc.go
parent076ca46bad3e18ea7f4c3b3320ab410c3ebea747 (diff)
reencode: Rethink the string backslash encoder
Diffstat (limited to 'misc.go')
-rw-r--r--misc.go81
1 files changed, 53 insertions, 28 deletions
diff --git a/misc.go b/misc.go
index a567cc7..4d8b136 100644
--- a/misc.go
+++ b/misc.go
@@ -68,34 +68,42 @@ func writeRune(w io.Writer, c rune) (int, error) {
// JSON string encoding ////////////////////////////////////////////////////////
-func UnicodeEscapeJSSafe(c rune, _ bool) bool {
+type BackslashEscapeMode uint8
+
+const (
+ BackslashEscapeNone = BackslashEscapeMode(iota)
+ BackslashEscapeShort
+ BackslashEscapeUnicode
+)
+
+func EscapeJSSafe(c rune, _ BackslashEscapeMode) BackslashEscapeMode {
// JSON is notionally a JS subset, but that's not actually
// true.
//
// http://timelessrepo.com/json-isnt-a-javascript-subset
switch c {
case '\u2028', '\u2029':
- return true
+ return BackslashEscapeUnicode
default:
- return false
+ return BackslashEscapeNone
}
}
-func UnicodeEscapeHTMLSafe(c rune, wasEscaped bool) bool {
+func EscapeHTMLSafe(c rune, wasEscaped BackslashEscapeMode) BackslashEscapeMode {
switch c {
case '&', '<', '>':
- return true
+ return BackslashEscapeUnicode
default:
- return UnicodeEscapeJSSafe(c, wasEscaped)
+ return EscapeJSSafe(c, wasEscaped)
}
}
-func UnicodeEscapeDefault(c rune, wasEscaped bool) bool {
+func EscapeDefault(c rune, wasEscaped BackslashEscapeMode) BackslashEscapeMode {
switch c {
case '\b', '\f', utf8.RuneError:
- return true
+ return BackslashEscapeUnicode
default:
- return UnicodeEscapeHTMLSafe(c, wasEscaped)
+ return EscapeHTMLSafe(c, wasEscaped)
}
}
@@ -114,31 +122,48 @@ func writeStringShortEscape(w io.Writer, c byte) (int, error) {
buf := [2]byte{'\\', c}
return w.Write(buf[:])
}
-func writeStringChar(w io.Writer, c rune, wasEscaped bool, escaper func(rune, bool) bool) (int, error) {
+func writeStringChar(w io.Writer, c rune, wasEscaped BackslashEscapeMode, escaper func(rune, BackslashEscapeMode) BackslashEscapeMode) (int, error) {
if escaper == nil {
- escaper = UnicodeEscapeDefault
+ escaper = EscapeDefault
}
- switch {
- case c <= 0xFFFF && escaper(c, wasEscaped):
- return writeStringUnicodeEscape(w, c)
- case c == '"' || c == '\\':
- return writeStringShortEscape(w, byte(c))
- case c < 0x0020:
+ switch escaper(c, wasEscaped) {
+ case BackslashEscapeNone:
+ switch {
+ case c < 0x0020:
+ switch c {
+ case '\b':
+ return writeStringShortEscape(w, 'b')
+ case '\f':
+ return writeStringShortEscape(w, 'f')
+ case '\n':
+ return writeStringShortEscape(w, 'n')
+ case '\r':
+ return writeStringShortEscape(w, 'r')
+ case '\t':
+ return writeStringShortEscape(w, 't')
+ default:
+ return writeStringUnicodeEscape(w, c)
+ }
+ case c == '"' || c == '\\':
+ return writeStringShortEscape(w, byte(c))
+ default:
+ return writeRune(w, c)
+ }
+ case BackslashEscapeShort:
switch c {
- case '\b':
- return writeStringShortEscape(w, 'b')
- case '\f':
- return writeStringShortEscape(w, 'f')
- case '\n':
- return writeStringShortEscape(w, 'n')
- case '\r':
- return writeStringShortEscape(w, 'r')
- case '\t':
- return writeStringShortEscape(w, 't')
+ case '"', '\\', '/', '\b', '\f', '\n', '\r', '\t':
+ return writeStringShortEscape(w, byte(c))
+ default:
+ return writeRune(w, c)
+ }
+ case BackslashEscapeUnicode:
+ switch {
+ case c > 0xFFFF:
+ return writeRune(w, c)
default:
return writeStringUnicodeEscape(w, c)
}
default:
- return writeRune(w, c)
+ panic("escaper returned an invalid escape mode")
}
}