Use a table lookup for escaping unprintable bytes (#846)

This commit is contained in:
Tom Thorogood 2018-11-30 06:27:48 +10:30 committed by Miek Gieben
parent c0747f060e
commit 2c039114d2
3 changed files with 35 additions and 14 deletions

5
msg.go
View File

@ -416,10 +416,7 @@ Loop:
s = append(s, '\\', b)
default:
if b < ' ' || b > '~' { // unprintable, use \DDD
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s = append(s, '\\', '0', '0', '0')
copy(s[len(s)-len(bufs):], bufs)
s = append(s, escapeByte(b)...)
} else {
s = append(s, b)
}

View File

@ -275,7 +275,7 @@ func unpackString(msg []byte, off int) (string, int, error) {
s.WriteByte('\\')
s.WriteByte(b)
case b < ' ' || b > '~': // unprintable
writeEscapedByte(&s, b)
s.WriteString(escapeByte(b))
default:
s.WriteByte(b)
}

View File

@ -460,7 +460,7 @@ func sprintTxtOctet(s string) string {
case b == '.':
dst.WriteByte('.')
case b < ' ' || b > '~':
writeEscapedByte(&dst, b)
dst.WriteString(escapeByte(b))
default:
dst.WriteByte(b)
}
@ -508,20 +508,44 @@ func writeTXTStringByte(s *strings.Builder, b byte) {
s.WriteByte('\\')
s.WriteByte(b)
case b < ' ' || b > '~':
writeEscapedByte(s, b)
s.WriteString(escapeByte(b))
default:
s.WriteByte(b)
}
}
func writeEscapedByte(s *strings.Builder, b byte) {
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s.WriteByte('\\')
for i := len(bufs); i < 3; i++ {
s.WriteByte('0')
const (
escapedByteSmall = "" +
`\000\001\002\003\004\005\006\007\008\009` +
`\010\011\012\013\014\015\016\017\018\019` +
`\020\021\022\023\024\025\026\027\028\029` +
`\030\031`
escapedByteLarge = `\127\128\129` +
`\130\131\132\133\134\135\136\137\138\139` +
`\140\141\142\143\144\145\146\147\148\149` +
`\150\151\152\153\154\155\156\157\158\159` +
`\160\161\162\163\164\165\166\167\168\169` +
`\170\171\172\173\174\175\176\177\178\179` +
`\180\181\182\183\184\185\186\187\188\189` +
`\190\191\192\193\194\195\196\197\198\199` +
`\200\201\202\203\204\205\206\207\208\209` +
`\210\211\212\213\214\215\216\217\218\219` +
`\220\221\222\223\224\225\226\227\228\229` +
`\230\231\232\233\234\235\236\237\238\239` +
`\240\241\242\243\244\245\246\247\248\249` +
`\250\251\252\253\254\255`
)
// escapeByte returns the \DDD escaping of b which must
// satisfy b < ' ' || b > '~'.
func escapeByte(b byte) string {
if b < ' ' {
return escapedByteSmall[b*4 : b*4+4]
}
s.Write(bufs)
b -= '~' + 1
// The cast here is needed as b*4 may overflow byte.
return escapedByteLarge[int(b)*4 : int(b)*4+4]
}
func nextByte(s string, offset int) (byte, int) {