diff --git a/msg_helpers.go b/msg_helpers.go index ec8cd9a8..e8c6b745 100644 --- a/msg_helpers.go +++ b/msg_helpers.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "net" "strconv" + "strings" ) // helper functions called from the generated zmsg.go @@ -267,29 +268,27 @@ func unpackString(msg []byte, off int) (string, int, error) { if off+l+1 > len(msg) { return "", off, &Error{err: "overflow unpacking txt"} } - s := make([]byte, 0, l) + var s strings.Builder + s.Grow(l) for _, b := range msg[off+1 : off+1+l] { - switch b { - case '"', '\\': - s = append(s, '\\', b) - default: - if b < 32 || b > 127 { // unprintable - var buf [3]byte - bufs := strconv.AppendInt(buf[:0], int64(b), 10) - s = append(s, '\\') - for i := 0; i < 3-len(bufs); i++ { - s = append(s, '0') - } - for _, r := range bufs { - s = append(s, r) - } - } else { - s = append(s, b) + switch { + case b == '"' || b == '\\': + s.WriteByte('\\') + s.WriteByte(b) + case b < 32 || b > 127: // unprintable + var buf [3]byte + bufs := strconv.AppendInt(buf[:0], int64(b), 10) + s.WriteByte('\\') + for i := len(bufs); i < 3; i++ { + s.WriteByte('0') } + s.Write(bufs) + default: + s.WriteByte(b) } } off += 1 + l - return string(s), off, nil + return s.String(), off, nil } func packString(s string, msg []byte, off int) (int, error) { diff --git a/msg_helpers_test.go b/msg_helpers_test.go index adceb882..df1fbfae 100644 --- a/msg_helpers_test.go +++ b/msg_helpers_test.go @@ -106,3 +106,33 @@ func TestPackDataNsec(t *testing.T) { }) } } + +func TestUnpackString(t *testing.T) { + msg := []byte("\x00abcdef\x0f\\\"ghi\x04mmm") + msg[0] = byte(len(msg) - 1) + + got, _, err := unpackString(msg, 0) + if err != nil { + t.Fatal(err) + } + + if want := `abcdef\015\\\"ghi\004mmm`; want != got { + t.Errorf("expected %q, got %q", want, got) + } +} + +func BenchmarkUnpackString(b *testing.B) { + msg := []byte("\x00abcdef\x0f\\\"ghi\x04mmm") + msg[0] = byte(len(msg) - 1) + + for n := 0; n < b.N; n++ { + got, _, err := unpackString(msg, 0) + if err != nil { + b.Fatal(err) + } + + if want := `abcdef\015\\\"ghi\004mmm`; want != got { + b.Errorf("expected %q, got %q", want, got) + } + } +}