You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

encode.go 11 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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 prototext
  5. import (
  6. "fmt"
  7. "sort"
  8. "strconv"
  9. "unicode/utf8"
  10. "google.golang.org/protobuf/encoding/protowire"
  11. "google.golang.org/protobuf/internal/encoding/messageset"
  12. "google.golang.org/protobuf/internal/encoding/text"
  13. "google.golang.org/protobuf/internal/errors"
  14. "google.golang.org/protobuf/internal/fieldnum"
  15. "google.golang.org/protobuf/internal/flags"
  16. "google.golang.org/protobuf/internal/mapsort"
  17. "google.golang.org/protobuf/internal/pragma"
  18. "google.golang.org/protobuf/proto"
  19. pref "google.golang.org/protobuf/reflect/protoreflect"
  20. "google.golang.org/protobuf/reflect/protoregistry"
  21. )
  22. const defaultIndent = " "
  23. // Format formats the message as a multiline string.
  24. // This function is only intended for human consumption and ignores errors.
  25. // Do not depend on the output being stable. It may change over time across
  26. // different versions of the program.
  27. func Format(m proto.Message) string {
  28. return MarshalOptions{Multiline: true}.Format(m)
  29. }
  30. // Marshal writes the given proto.Message in textproto format using default
  31. // options. Do not depend on the output being stable. It may change over time
  32. // across different versions of the program.
  33. func Marshal(m proto.Message) ([]byte, error) {
  34. return MarshalOptions{}.Marshal(m)
  35. }
  36. // MarshalOptions is a configurable text format marshaler.
  37. type MarshalOptions struct {
  38. pragma.NoUnkeyedLiterals
  39. // Multiline specifies whether the marshaler should format the output in
  40. // indented-form with every textual element on a new line.
  41. // If Indent is an empty string, then an arbitrary indent is chosen.
  42. Multiline bool
  43. // Indent specifies the set of indentation characters to use in a multiline
  44. // formatted output such that every entry is preceded by Indent and
  45. // terminated by a newline. If non-empty, then Multiline is treated as true.
  46. // Indent can only be composed of space or tab characters.
  47. Indent string
  48. // AllowPartial allows messages that have missing required fields to marshal
  49. // without returning an error. If AllowPartial is false (the default),
  50. // Marshal will return error if there are any missing required fields.
  51. AllowPartial bool
  52. // EmitUnknown specifies whether to emit unknown fields in the output.
  53. // If specified, the unmarshaler may be unable to parse the output.
  54. // The default is to exclude unknown fields.
  55. EmitUnknown bool
  56. // Resolver is used for looking up types when expanding google.protobuf.Any
  57. // messages. If nil, this defaults to using protoregistry.GlobalTypes.
  58. Resolver interface {
  59. protoregistry.ExtensionTypeResolver
  60. protoregistry.MessageTypeResolver
  61. }
  62. }
  63. // Format formats the message as a string.
  64. // This method is only intended for human consumption and ignores errors.
  65. // Do not depend on the output being stable. It may change over time across
  66. // different versions of the program.
  67. func (o MarshalOptions) Format(m proto.Message) string {
  68. if m == nil || !m.ProtoReflect().IsValid() {
  69. return "<nil>" // invalid syntax, but okay since this is for debugging
  70. }
  71. o.AllowPartial = true
  72. o.EmitUnknown = true
  73. b, _ := o.Marshal(m)
  74. return string(b)
  75. }
  76. // Marshal writes the given proto.Message in textproto format using options in
  77. // MarshalOptions object. Do not depend on the output being stable. It may
  78. // change over time across different versions of the program.
  79. func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
  80. const outputASCII = false
  81. var delims = [2]byte{'{', '}'}
  82. if o.Multiline && o.Indent == "" {
  83. o.Indent = defaultIndent
  84. }
  85. if o.Resolver == nil {
  86. o.Resolver = protoregistry.GlobalTypes
  87. }
  88. internalEnc, err := text.NewEncoder(o.Indent, delims, outputASCII)
  89. if err != nil {
  90. return nil, err
  91. }
  92. enc := encoder{internalEnc, o}
  93. err = enc.marshalMessage(m.ProtoReflect(), false)
  94. if err != nil {
  95. return nil, err
  96. }
  97. out := enc.Bytes()
  98. if len(o.Indent) > 0 && len(out) > 0 {
  99. out = append(out, '\n')
  100. }
  101. if o.AllowPartial {
  102. return out, nil
  103. }
  104. return out, proto.CheckInitialized(m)
  105. }
  106. type encoder struct {
  107. *text.Encoder
  108. opts MarshalOptions
  109. }
  110. // marshalMessage marshals the given protoreflect.Message.
  111. func (e encoder) marshalMessage(m pref.Message, inclDelims bool) error {
  112. messageDesc := m.Descriptor()
  113. if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
  114. return errors.New("no support for proto1 MessageSets")
  115. }
  116. if inclDelims {
  117. e.StartMessage()
  118. defer e.EndMessage()
  119. }
  120. // Handle Any expansion.
  121. if messageDesc.FullName() == "google.protobuf.Any" {
  122. if e.marshalAny(m) {
  123. return nil
  124. }
  125. // If unable to expand, continue on to marshal Any as a regular message.
  126. }
  127. // Marshal known fields.
  128. fieldDescs := messageDesc.Fields()
  129. size := fieldDescs.Len()
  130. for i := 0; i < size; {
  131. fd := fieldDescs.Get(i)
  132. if od := fd.ContainingOneof(); od != nil {
  133. fd = m.WhichOneof(od)
  134. i += od.Fields().Len()
  135. } else {
  136. i++
  137. }
  138. if fd == nil || !m.Has(fd) {
  139. continue
  140. }
  141. name := fd.Name()
  142. // Use type name for group field name.
  143. if fd.Kind() == pref.GroupKind {
  144. name = fd.Message().Name()
  145. }
  146. val := m.Get(fd)
  147. if err := e.marshalField(string(name), val, fd); err != nil {
  148. return err
  149. }
  150. }
  151. // Marshal extensions.
  152. if err := e.marshalExtensions(m); err != nil {
  153. return err
  154. }
  155. // Marshal unknown fields.
  156. if e.opts.EmitUnknown {
  157. e.marshalUnknown(m.GetUnknown())
  158. }
  159. return nil
  160. }
  161. // marshalField marshals the given field with protoreflect.Value.
  162. func (e encoder) marshalField(name string, val pref.Value, fd pref.FieldDescriptor) error {
  163. switch {
  164. case fd.IsList():
  165. return e.marshalList(name, val.List(), fd)
  166. case fd.IsMap():
  167. return e.marshalMap(name, val.Map(), fd)
  168. default:
  169. e.WriteName(name)
  170. return e.marshalSingular(val, fd)
  171. }
  172. }
  173. // marshalSingular marshals the given non-repeated field value. This includes
  174. // all scalar types, enums, messages, and groups.
  175. func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
  176. kind := fd.Kind()
  177. switch kind {
  178. case pref.BoolKind:
  179. e.WriteBool(val.Bool())
  180. case pref.StringKind:
  181. s := val.String()
  182. if !utf8.ValidString(s) {
  183. return errors.InvalidUTF8(string(fd.FullName()))
  184. }
  185. e.WriteString(s)
  186. case pref.Int32Kind, pref.Int64Kind,
  187. pref.Sint32Kind, pref.Sint64Kind,
  188. pref.Sfixed32Kind, pref.Sfixed64Kind:
  189. e.WriteInt(val.Int())
  190. case pref.Uint32Kind, pref.Uint64Kind,
  191. pref.Fixed32Kind, pref.Fixed64Kind:
  192. e.WriteUint(val.Uint())
  193. case pref.FloatKind:
  194. // Encoder.WriteFloat handles the special numbers NaN and infinites.
  195. e.WriteFloat(val.Float(), 32)
  196. case pref.DoubleKind:
  197. // Encoder.WriteFloat handles the special numbers NaN and infinites.
  198. e.WriteFloat(val.Float(), 64)
  199. case pref.BytesKind:
  200. e.WriteString(string(val.Bytes()))
  201. case pref.EnumKind:
  202. num := val.Enum()
  203. if desc := fd.Enum().Values().ByNumber(num); desc != nil {
  204. e.WriteLiteral(string(desc.Name()))
  205. } else {
  206. // Use numeric value if there is no enum description.
  207. e.WriteInt(int64(num))
  208. }
  209. case pref.MessageKind, pref.GroupKind:
  210. return e.marshalMessage(val.Message(), true)
  211. default:
  212. panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
  213. }
  214. return nil
  215. }
  216. // marshalList marshals the given protoreflect.List as multiple name-value fields.
  217. func (e encoder) marshalList(name string, list pref.List, fd pref.FieldDescriptor) error {
  218. size := list.Len()
  219. for i := 0; i < size; i++ {
  220. e.WriteName(name)
  221. if err := e.marshalSingular(list.Get(i), fd); err != nil {
  222. return err
  223. }
  224. }
  225. return nil
  226. }
  227. // marshalMap marshals the given protoreflect.Map as multiple name-value fields.
  228. func (e encoder) marshalMap(name string, mmap pref.Map, fd pref.FieldDescriptor) error {
  229. var err error
  230. mapsort.Range(mmap, fd.MapKey().Kind(), func(key pref.MapKey, val pref.Value) bool {
  231. e.WriteName(name)
  232. e.StartMessage()
  233. defer e.EndMessage()
  234. e.WriteName("key")
  235. err = e.marshalSingular(key.Value(), fd.MapKey())
  236. if err != nil {
  237. return false
  238. }
  239. e.WriteName("value")
  240. err = e.marshalSingular(val, fd.MapValue())
  241. if err != nil {
  242. return false
  243. }
  244. return true
  245. })
  246. return err
  247. }
  248. // marshalExtensions marshals extension fields.
  249. func (e encoder) marshalExtensions(m pref.Message) error {
  250. type entry struct {
  251. key string
  252. value pref.Value
  253. desc pref.FieldDescriptor
  254. }
  255. // Get a sorted list based on field key first.
  256. var entries []entry
  257. m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
  258. if !fd.IsExtension() {
  259. return true
  260. }
  261. // For MessageSet extensions, the name used is the parent message.
  262. name := fd.FullName()
  263. if messageset.IsMessageSetExtension(fd) {
  264. name = name.Parent()
  265. }
  266. entries = append(entries, entry{
  267. key: string(name),
  268. value: v,
  269. desc: fd,
  270. })
  271. return true
  272. })
  273. // Sort extensions lexicographically.
  274. sort.Slice(entries, func(i, j int) bool {
  275. return entries[i].key < entries[j].key
  276. })
  277. // Write out sorted list.
  278. for _, entry := range entries {
  279. // Extension field name is the proto field name enclosed in [].
  280. name := "[" + entry.key + "]"
  281. if err := e.marshalField(name, entry.value, entry.desc); err != nil {
  282. return err
  283. }
  284. }
  285. return nil
  286. }
  287. // marshalUnknown parses the given []byte and marshals fields out.
  288. // This function assumes proper encoding in the given []byte.
  289. func (e encoder) marshalUnknown(b []byte) {
  290. const dec = 10
  291. const hex = 16
  292. for len(b) > 0 {
  293. num, wtype, n := protowire.ConsumeTag(b)
  294. b = b[n:]
  295. e.WriteName(strconv.FormatInt(int64(num), dec))
  296. switch wtype {
  297. case protowire.VarintType:
  298. var v uint64
  299. v, n = protowire.ConsumeVarint(b)
  300. e.WriteUint(v)
  301. case protowire.Fixed32Type:
  302. var v uint32
  303. v, n = protowire.ConsumeFixed32(b)
  304. e.WriteLiteral("0x" + strconv.FormatUint(uint64(v), hex))
  305. case protowire.Fixed64Type:
  306. var v uint64
  307. v, n = protowire.ConsumeFixed64(b)
  308. e.WriteLiteral("0x" + strconv.FormatUint(v, hex))
  309. case protowire.BytesType:
  310. var v []byte
  311. v, n = protowire.ConsumeBytes(b)
  312. e.WriteString(string(v))
  313. case protowire.StartGroupType:
  314. e.StartMessage()
  315. var v []byte
  316. v, n = protowire.ConsumeGroup(num, b)
  317. e.marshalUnknown(v)
  318. e.EndMessage()
  319. default:
  320. panic(fmt.Sprintf("prototext: error parsing unknown field wire type: %v", wtype))
  321. }
  322. b = b[n:]
  323. }
  324. }
  325. // marshalAny marshals the given google.protobuf.Any message in expanded form.
  326. // It returns true if it was able to marshal, else false.
  327. func (e encoder) marshalAny(any pref.Message) bool {
  328. // Construct the embedded message.
  329. fds := any.Descriptor().Fields()
  330. fdType := fds.ByNumber(fieldnum.Any_TypeUrl)
  331. typeURL := any.Get(fdType).String()
  332. mt, err := e.opts.Resolver.FindMessageByURL(typeURL)
  333. if err != nil {
  334. return false
  335. }
  336. m := mt.New().Interface()
  337. // Unmarshal bytes into embedded message.
  338. fdValue := fds.ByNumber(fieldnum.Any_Value)
  339. value := any.Get(fdValue)
  340. err = proto.UnmarshalOptions{
  341. AllowPartial: true,
  342. Resolver: e.opts.Resolver,
  343. }.Unmarshal(value.Bytes(), m)
  344. if err != nil {
  345. return false
  346. }
  347. // Get current encoder position. If marshaling fails, reset encoder output
  348. // back to this position.
  349. pos := e.Snapshot()
  350. // Field name is the proto field name enclosed in [].
  351. e.WriteName("[" + typeURL + "]")
  352. err = e.marshalMessage(m.ProtoReflect(), true)
  353. if err != nil {
  354. e.Reset(pos)
  355. return false
  356. }
  357. return true
  358. }