@@ -10,6 +10,8 @@ import (
10
10
"reflect"
11
11
"sort"
12
12
"strings"
13
+ "unicode"
14
+ "unicode/utf8"
13
15
14
16
"github.com/golang/protobuf/proto"
15
17
"github.com/golang/protobuf/protoc-gen-go/descriptor"
@@ -1656,7 +1658,7 @@ func (p *Printer) printOption(name string, optVal interface{}, w *writer, indent
1656
1658
case string :
1657
1659
fmt .Fprintf (w , "%s" , quotedString (optVal ))
1658
1660
case []byte :
1659
- fmt .Fprintf (w , "%s" , quotedString (string (optVal )))
1661
+ fmt .Fprintf (w , "%s" , quotedBytes (string (optVal )))
1660
1662
case bool :
1661
1663
fmt .Fprintf (w , "%v" , optVal )
1662
1664
case ident :
@@ -1978,12 +1980,12 @@ func optionsAsElementAddrs(optionsTag int32, order int, opts map[int32][]option)
1978
1980
return optAddrs
1979
1981
}
1980
1982
1981
- // quotedString implements the text format for string literals for protocol
1982
- // buffers. This form is also acceptable for string literals in option values
1983
- // by the protocol buffer compiler, protoc.
1984
- func quotedString (s string ) string {
1983
+ // quotedBytes implements the text format for string literals for protocol
1984
+ // buffers. Since the underlying data is a bytes field, this encodes all
1985
+ // bytes outside the 7-bit ASCII printable range. To preserve unicode strings
1986
+ // without byte escapes, use quotedString.
1987
+ func quotedBytes (s string ) string {
1985
1988
var b bytes.Buffer
1986
- // use WriteByte here to get any needed indent
1987
1989
b .WriteByte ('"' )
1988
1990
// Loop over the bytes, not the runes.
1989
1991
for i := 0 ; i < len (s ); i ++ {
@@ -2014,6 +2016,62 @@ func quotedString(s string) string {
2014
2016
return b .String ()
2015
2017
}
2016
2018
2019
+ // quotedString implements the text format for string literals for protocol
2020
+ // buffers. This form is also acceptable for string literals in option values
2021
+ // by the protocol buffer compiler, protoc.
2022
+ func quotedString (s string ) string {
2023
+ var b bytes.Buffer
2024
+ b .WriteByte ('"' )
2025
+ // Loop over the bytes, not the runes.
2026
+ for {
2027
+ r , n := utf8 .DecodeRuneInString (s )
2028
+ if n == 0 {
2029
+ break // end of string
2030
+ }
2031
+ if r == utf8 .RuneError && n == 1 {
2032
+ // Invalid UTF8! Use an octal byte escape to encode the bad byte.
2033
+ fmt .Fprintf (& b , "\\ %03o" , s [0 ])
2034
+ s = s [1 :]
2035
+ continue
2036
+ }
2037
+
2038
+ // Divergence from C++: we don't escape apostrophes.
2039
+ // There's no need to escape them, and the C++ parser
2040
+ // copes with a naked apostrophe.
2041
+ switch r {
2042
+ case '\n' :
2043
+ b .WriteString ("\\ n" )
2044
+ case '\r' :
2045
+ b .WriteString ("\\ r" )
2046
+ case '\t' :
2047
+ b .WriteString ("\\ t" )
2048
+ case '"' :
2049
+ b .WriteString ("\\ " )
2050
+ case '\\' :
2051
+ b .WriteString ("\\ \\ " )
2052
+ default :
2053
+ if unicode .IsPrint (r ) {
2054
+ b .WriteRune (r )
2055
+ } else {
2056
+ // if it's not printable, use a unicode escape
2057
+ if r > 0xffff {
2058
+ fmt .Fprintf (& b , "\\ U%08X" , r )
2059
+ } else if r > 0x7F {
2060
+ fmt .Fprintf (& b , "\\ u%04X" , r )
2061
+ } else {
2062
+ fmt .Fprintf (& b , "\\ %03o" , byte (r ))
2063
+ }
2064
+ }
2065
+ }
2066
+
2067
+ s = s [n :]
2068
+ }
2069
+
2070
+ b .WriteByte ('"' )
2071
+
2072
+ return b .String ()
2073
+ }
2074
+
2017
2075
type elementAddr struct {
2018
2076
elementType int32
2019
2077
elementIndex int
0 commit comments