lib/encoder: fix decoding a trailing character after an escaped quote

This commit is contained in:
kevin9327 authored and Nick Craig-Wood committed 2026-10-13 11:30:54 +01:00
1 parent 81d7b6f299
commit f91c9d2d11
2 files changed
+59 -6

No files matched your search

+21 -6
View File
@@ -682,6 +682,21 @@ func (mask MultiEncoder) Encode(in string) string {
return out.String()
}
// quoteLen is the length in bytes of QuoteRune
var quoteLen = utf8.RuneLen(QuoteRune)
// endsWithQuote returns true if in ends with a QuoteRune which quotes
// the following character, rather than one which is part of an
// escaped QuoteRune (QuoteRune QuoteRune).
func endsWithQuote(in string) bool {
n := 0
for strings.HasSuffix(in, string(QuoteRune)) {
in = in[:len(in)-quoteLen]
n++
}
return n%2 == 1
}
// Decode takes a name and undoes any substitutions made by Encode
func (mask MultiEncoder) Decode(in string) string {
if mask == EncodeRaw {
@@ -727,22 +742,22 @@ func (mask MultiEncoder) Decode(in string) string {
suffix := ""
if r, l := utf8.DecodeLastRuneInString(in); mask.Has(EncodeRightSpace) && r == '␠' { // SYMBOL FOR SPACE
in = in[:len(in)-l]
if q, l2 := utf8.DecodeLastRuneInString(in); q == QuoteRune {
suffix, in = "␠", in[:len(in)-l2]
if endsWithQuote(in) {
suffix, in = "␠", in[:len(in)-quoteLen]
} else {
suffix = " "
}
} else if mask.Has(EncodeRightPeriod) && r == '.' { // FULLWIDTH FULL STOP
in = in[:len(in)-l]
if q, l2 := utf8.DecodeLastRuneInString(in); q == QuoteRune {
suffix, in = ".", in[:len(in)-l2]
if endsWithQuote(in) {
suffix, in = ".", in[:len(in)-quoteLen]
} else {
suffix = "."
}
} else if mask.Has(EncodeRightCrLfHtVt) && (r == '␀'+'\t' || r == '␀'+'\n' || r == '␀'+'\v' || r == '␀'+'\r') {
in = in[:len(in)-l]
if q, l2 := utf8.DecodeLastRuneInString(in); q == QuoteRune {
suffix, in = string(r), in[:len(in)-l2]
if endsWithQuote(in) {
suffix, in = string(r), in[:len(in)-quoteLen]
} else {
suffix = string(r - '␀')
}
+38
View File
@@ -255,6 +255,44 @@ func TestDecodeHalf(t *testing.T) {
}
}
func TestEncodeQuoteBeforeRightEdge(t *testing.T) {
for i, tc := range []testCase{
{
mask: EncodeRightSpace,
in: "a‛ ",
out: "a‛‛␠",
}, {
mask: EncodeRightSpace,
in: "‛‛ ",
out: "‛‛‛‛␠",
}, {
mask: EncodeRightSpace,
in: "a‛␠",
out: "a‛‛‛␠",
}, {
mask: EncodeRightPeriod,
in: "a‛.",
out: "a‛‛.",
}, {
mask: EncodeRightCrLfHtVt,
in: "a‛\t",
out: "a‛‛␉",
},
} {
e := tc.mask
t.Run(strconv.FormatInt(int64(i), 10), func(t *testing.T) {
got := e.Encode(tc.in)
if got != tc.out {
t.Errorf("Encode(%q) want %q got %q", tc.in, tc.out, got)
}
got2 := e.Decode(got)
if got2 != tc.in {
t.Errorf("Decode(%q) want %q got %q", got, tc.in, got2)
}
})
}
}
const oneDrive = (Standard |
EncodeWin |
EncodeBackSlash |