encoder: simplify quoted strings escaping

This commit is contained in:
Thomas Pelletier
2021-04-08 22:02:41 -04:00
parent 84f9e9bceb
commit e1f035461b
2 changed files with 53 additions and 26 deletions
+11 -26
View File
@@ -10,7 +10,6 @@ import (
"strconv"
"strings"
"time"
"unicode/utf8"
)
// Marshal serializes a Go value as a TOML document.
@@ -222,51 +221,37 @@ func (enc *Encoder) encodeLiteralString(b []byte, v string) []byte {
func (enc *Encoder) encodeQuotedString(b []byte, v string) []byte {
const stringQuote = '"'
const hextable = "0123456789ABCDEF"
b = append(b, stringQuote)
for _, r := range v {
for _, r := range []byte(v) {
switch r {
case '\\':
b = append(b, `\\`...)
continue
case '"':
b = append(b, `\"`...)
continue
case '\b':
b = append(b, `\b`...)
continue
case '\f':
b = append(b, `\f`...)
continue
case '\n':
b = append(b, `\n`...)
continue
case '\r':
b = append(b, `\r`...)
continue
case '\t':
b = append(b, `\t`...)
continue
}
if r == 0x20 || r == 0x09 || r == 0x21 || (r >= 0x23 && r <= 0x5B) || (r >= 0x5D && r <= 0x7E) {
b = append(b, byte(r))
} else if (r >= 0x80 && r <= 0xD7FF) || (r >= 0xE000 && r <= 0x10FFFF) {
l := utf8.RuneLen(r)
buf := make([]byte, l)
utf8.EncodeRune(buf, r)
b = append(b, buf...)
} else {
var h []byte
if r > 0xFFFF {
h = []byte(fmt.Sprintf("%08x", r))
} else {
h = []byte(fmt.Sprintf("%04x", r))
default:
switch {
case r >= 0x0 && r <= 0x8, r >= 0xA && r <= 0x1F, r == 0x7F:
b = append(b, `\u00`...)
b = append(b, hextable[r>>4])
b = append(b, hextable[r&0x0f])
default:
b = append(b, r)
}
b = append(b, `\u`...)
b = append(b, h...)
}
// U+0000 to U+0008, U+000A to U+001F, U+007F
}
b = append(b, stringQuote)
+42
View File
@@ -174,6 +174,48 @@ name = 'Bob'
name = 'Alice'
`,
},
{
desc: "string escapes",
v: map[string]interface{}{
"a": `'"\`,
},
expected: `a = "'\"\\"`,
},
{
desc: "string utf8 low",
v: map[string]interface{}{
"a": "'Ę",
},
expected: `a = "'Ę"`,
},
{
desc: "string utf8 low 2",
v: map[string]interface{}{
"a": "'\u10A85",
},
expected: "a = \"'\u10A85\"",
},
{
desc: "string utf8 low 2",
v: map[string]interface{}{
"a": "'\u10A85",
},
expected: "a = \"'\u10A85\"",
},
{
desc: "emoji",
v: map[string]interface{}{
"a": "'😀",
},
expected: "a = \"'😀\"",
},
{
desc: "control char",
v: map[string]interface{}{
"a": "'\u001A",
},
expected: `a = "'\u001A"`,
},
}
for _, e := range examples {