encode.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. "strings"
  8. "github.com/golang/protobuf/v2/internal/detrand"
  9. "github.com/golang/protobuf/v2/internal/errors"
  10. )
  11. // Marshal serializes v as the proto text format, where v must be a Message.
  12. // In the proto text format, the top-level value is always a message where the
  13. // delimiters are elided.
  14. //
  15. // If indent is a non-empty string, it causes every entry in a List or Message
  16. // to be preceded by the indent and trailed by a newline.
  17. //
  18. // If delims is not the zero value, it controls the delimiter characters used
  19. // for messages (e.g., "{}" vs "<>").
  20. //
  21. // If outputASCII is true, strings will be serialized in such a way that
  22. // multi-byte UTF-8 sequences are escaped. This property ensures that the
  23. // overall output is ASCII (as opposed to UTF-8).
  24. func Marshal(v Value, indent string, delims [2]byte, outputASCII bool) ([]byte, error) {
  25. p := encoder{}
  26. if len(indent) > 0 {
  27. if strings.Trim(indent, " \t") != "" {
  28. return nil, errors.New("indent may only be composed of space and tab characters")
  29. }
  30. p.indent = indent
  31. p.newline = "\n"
  32. }
  33. switch delims {
  34. case [2]byte{0, 0}:
  35. p.delims = [2]byte{'{', '}'}
  36. case [2]byte{'{', '}'}, [2]byte{'<', '>'}:
  37. p.delims = delims
  38. default:
  39. return nil, errors.New("delimiters may only be \"{}\" or \"<>\"")
  40. }
  41. p.outputASCII = outputASCII
  42. err := p.marshalMessage(v, false)
  43. if !p.nerr.Merge(err) {
  44. return nil, err
  45. }
  46. if len(indent) > 0 {
  47. return append(bytes.TrimRight(p.out, "\n"), '\n'), p.nerr.E
  48. }
  49. return p.out, p.nerr.E
  50. }
  51. type encoder struct {
  52. nerr errors.NonFatal
  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); !p.nerr.Merge(err) {
  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]); !p.nerr.Merge(err) {
  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]); !p.nerr.Merge(err) {
  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. func (p *encoder) marshalKey(v Value) error {
  136. switch v.Type() {
  137. case String:
  138. var err error
  139. p.out = append(p.out, '[')
  140. if len(urlRegexp.FindString(v.str)) == len(v.str) {
  141. p.out = append(p.out, v.str...)
  142. } else {
  143. err = p.marshalString(v)
  144. }
  145. p.out = append(p.out, ']')
  146. return err
  147. case Uint:
  148. return p.marshalNumber(v)
  149. case Name:
  150. s, _ := v.Name()
  151. p.out = append(p.out, s...)
  152. return nil
  153. default:
  154. return errors.New("invalid type %v to encode key", v.Type())
  155. }
  156. }
  157. func (p *encoder) marshalValue(v Value) error {
  158. switch v.Type() {
  159. case Bool, Int, Uint, Float:
  160. return p.marshalNumber(v)
  161. case String:
  162. return p.marshalString(v)
  163. case List:
  164. return p.marshalList(v)
  165. case Message:
  166. return p.marshalMessage(v, true)
  167. case Name:
  168. s, _ := v.Name()
  169. p.out = append(p.out, s...)
  170. return nil
  171. default:
  172. return errors.New("invalid type %v to encode value", v.Type())
  173. }
  174. }