encode.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package text
  5. import (
  6. "bytes"
  7. "regexp"
  8. "strings"
  9. "google.golang.org/protobuf/internal/detrand"
  10. "google.golang.org/protobuf/internal/errors"
  11. )
  12. // Marshal serializes v as the proto text format, where v must be a Message.
  13. // In the proto text format, the top-level value is always a message where the
  14. // delimiters are elided.
  15. //
  16. // If indent is a non-empty string, it causes every entry in a List or Message
  17. // to be preceded by the indent and trailed by a newline.
  18. //
  19. // If delims is not the zero value, it controls the delimiter characters used
  20. // for messages (e.g., "{}" vs "<>").
  21. //
  22. // If outputASCII is true, strings will be serialized in such a way that
  23. // multi-byte UTF-8 sequences are escaped. This property ensures that the
  24. // overall output is ASCII (as opposed to UTF-8).
  25. func Marshal(v Value, indent string, delims [2]byte, outputASCII bool) ([]byte, error) {
  26. p := encoder{}
  27. if len(indent) > 0 {
  28. if strings.Trim(indent, " \t") != "" {
  29. return nil, errors.New("indent may only be composed of space and tab characters")
  30. }
  31. p.indent = indent
  32. p.newline = "\n"
  33. }
  34. switch delims {
  35. case [2]byte{0, 0}:
  36. p.delims = [2]byte{'{', '}'}
  37. case [2]byte{'{', '}'}, [2]byte{'<', '>'}:
  38. p.delims = delims
  39. default:
  40. return nil, errors.New("delimiters may only be \"{}\" or \"<>\"")
  41. }
  42. p.outputASCII = outputASCII
  43. err := p.marshalMessage(v, false)
  44. if err != nil {
  45. return nil, err
  46. }
  47. if len(indent) > 0 {
  48. return append(bytes.TrimRight(p.out, "\n"), '\n'), nil
  49. }
  50. return p.out, nil
  51. }
  52. type encoder struct {
  53. out []byte
  54. indent string
  55. indents []byte
  56. newline string // set to "\n" if len(indent) > 0
  57. delims [2]byte
  58. outputASCII bool
  59. }
  60. func (p *encoder) marshalList(v Value) error {
  61. if v.Type() != List {
  62. return errors.New("invalid type %v, expected list", v.Type())
  63. }
  64. elems := v.List()
  65. p.out = append(p.out, '[')
  66. p.indents = append(p.indents, p.indent...)
  67. if len(elems) > 0 {
  68. p.out = append(p.out, p.newline...)
  69. }
  70. for i, elem := range elems {
  71. p.out = append(p.out, p.indents...)
  72. if err := p.marshalValue(elem); err != nil {
  73. return err
  74. }
  75. if i < len(elems)-1 {
  76. p.out = append(p.out, ',')
  77. }
  78. p.out = append(p.out, p.newline...)
  79. }
  80. p.indents = p.indents[:len(p.indents)-len(p.indent)]
  81. if len(elems) > 0 {
  82. p.out = append(p.out, p.indents...)
  83. }
  84. p.out = append(p.out, ']')
  85. return nil
  86. }
  87. func (p *encoder) marshalMessage(v Value, emitDelims bool) error {
  88. if v.Type() != Message {
  89. return errors.New("invalid type %v, expected message", v.Type())
  90. }
  91. items := v.Message()
  92. if emitDelims {
  93. p.out = append(p.out, p.delims[0])
  94. p.indents = append(p.indents, p.indent...)
  95. if len(items) > 0 {
  96. p.out = append(p.out, p.newline...)
  97. }
  98. }
  99. for i, item := range items {
  100. p.out = append(p.out, p.indents...)
  101. if err := p.marshalKey(item[0]); err != nil {
  102. return err
  103. }
  104. p.out = append(p.out, ':')
  105. if len(p.indent) > 0 {
  106. p.out = append(p.out, ' ')
  107. }
  108. // For multi-line output, add a random extra space after key: per message to
  109. // make output unstable.
  110. if len(p.indent) > 0 && detrand.Bool() {
  111. p.out = append(p.out, ' ')
  112. }
  113. if err := p.marshalValue(item[1]); err != nil {
  114. return err
  115. }
  116. if i < len(items)-1 && len(p.indent) == 0 {
  117. p.out = append(p.out, ' ')
  118. }
  119. // For single-line output, add a random extra space after a field per message to
  120. // make output unstable.
  121. if len(p.indent) == 0 && detrand.Bool() && i != len(items)-1 {
  122. p.out = append(p.out, ' ')
  123. }
  124. p.out = append(p.out, p.newline...)
  125. }
  126. if emitDelims {
  127. p.indents = p.indents[:len(p.indents)-len(p.indent)]
  128. if len(items) > 0 {
  129. p.out = append(p.out, p.indents...)
  130. }
  131. p.out = append(p.out, p.delims[1])
  132. }
  133. return nil
  134. }
  135. // This expression is more liberal than ConsumeAnyTypeUrl in C++.
  136. // However, the C++ parser does not handle many legal URL strings.
  137. // The Go implementation is more liberal to be backwards compatible with
  138. // the historical Go implementation which was overly liberal (and buggy).
  139. var urlRegexp = regexp.MustCompile(`^[-_a-zA-Z0-9]+([./][-_a-zA-Z0-9]+)*`)
  140. func (p *encoder) marshalKey(v Value) error {
  141. switch v.Type() {
  142. case String:
  143. var err error
  144. p.out = append(p.out, '[')
  145. if len(urlRegexp.FindString(v.str)) == len(v.str) {
  146. p.out = append(p.out, v.str...)
  147. } else {
  148. err = p.marshalString(v)
  149. }
  150. p.out = append(p.out, ']')
  151. return err
  152. case Uint:
  153. return p.marshalNumber(v)
  154. case Name:
  155. s, _ := v.Name()
  156. p.out = append(p.out, s...)
  157. return nil
  158. default:
  159. return errors.New("invalid type %v to encode key", v.Type())
  160. }
  161. }
  162. func (p *encoder) marshalValue(v Value) error {
  163. switch v.Type() {
  164. case Bool, Int, Uint, Float32, Float64:
  165. return p.marshalNumber(v)
  166. case String:
  167. return p.marshalString(v)
  168. case List:
  169. return p.marshalList(v)
  170. case Message:
  171. return p.marshalMessage(v, true)
  172. case Name:
  173. s, _ := v.Name()
  174. p.out = append(p.out, s...)
  175. return nil
  176. default:
  177. return errors.New("invalid type %v to encode value", v.Type())
  178. }
  179. }