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 12 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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. // Treat nil message interface as an empty message,
  93. // in which case there is nothing to output.
  94. if m == nil {
  95. return []byte{}, nil
  96. }
  97. enc := encoder{internalEnc, o}
  98. err = enc.marshalMessage(m.ProtoReflect(), false)
  99. if err != nil {
  100. return nil, err
  101. }
  102. out := enc.Bytes()
  103. if len(o.Indent) > 0 && len(out) > 0 {
  104. out = append(out, '\n')
  105. }
  106. if o.AllowPartial {
  107. return out, nil
  108. }
  109. return out, proto.CheckInitialized(m)
  110. }
  111. type encoder struct {
  112. *text.Encoder
  113. opts MarshalOptions
  114. }
  115. // marshalMessage marshals the given protoreflect.Message.
  116. func (e encoder) marshalMessage(m pref.Message, inclDelims bool) error {
  117. messageDesc := m.Descriptor()
  118. if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
  119. return errors.New("no support for proto1 MessageSets")
  120. }
  121. if inclDelims {
  122. e.StartMessage()
  123. defer e.EndMessage()
  124. }
  125. // Handle Any expansion.
  126. if messageDesc.FullName() == "google.protobuf.Any" {
  127. if e.marshalAny(m) {
  128. return nil
  129. }
  130. // If unable to expand, continue on to marshal Any as a regular message.
  131. }
  132. // Marshal known fields.
  133. fieldDescs := messageDesc.Fields()
  134. size := fieldDescs.Len()
  135. for i := 0; i < size; {
  136. fd := fieldDescs.Get(i)
  137. if od := fd.ContainingOneof(); od != nil {
  138. fd = m.WhichOneof(od)
  139. i += od.Fields().Len()
  140. } else {
  141. i++
  142. }
  143. if fd == nil || !m.Has(fd) {
  144. continue
  145. }
  146. name := fd.Name()
  147. // Use type name for group field name.
  148. if fd.Kind() == pref.GroupKind {
  149. name = fd.Message().Name()
  150. }
  151. val := m.Get(fd)
  152. if err := e.marshalField(string(name), val, fd); err != nil {
  153. return err
  154. }
  155. }
  156. // Marshal extensions.
  157. if err := e.marshalExtensions(m); err != nil {
  158. return err
  159. }
  160. // Marshal unknown fields.
  161. if e.opts.EmitUnknown {
  162. e.marshalUnknown(m.GetUnknown())
  163. }
  164. return nil
  165. }
  166. // marshalField marshals the given field with protoreflect.Value.
  167. func (e encoder) marshalField(name string, val pref.Value, fd pref.FieldDescriptor) error {
  168. switch {
  169. case fd.IsList():
  170. return e.marshalList(name, val.List(), fd)
  171. case fd.IsMap():
  172. return e.marshalMap(name, val.Map(), fd)
  173. default:
  174. e.WriteName(name)
  175. return e.marshalSingular(val, fd)
  176. }
  177. }
  178. // marshalSingular marshals the given non-repeated field value. This includes
  179. // all scalar types, enums, messages, and groups.
  180. func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
  181. kind := fd.Kind()
  182. switch kind {
  183. case pref.BoolKind:
  184. e.WriteBool(val.Bool())
  185. case pref.StringKind:
  186. s := val.String()
  187. if !utf8.ValidString(s) {
  188. return errors.InvalidUTF8(string(fd.FullName()))
  189. }
  190. e.WriteString(s)
  191. case pref.Int32Kind, pref.Int64Kind,
  192. pref.Sint32Kind, pref.Sint64Kind,
  193. pref.Sfixed32Kind, pref.Sfixed64Kind:
  194. e.WriteInt(val.Int())
  195. case pref.Uint32Kind, pref.Uint64Kind,
  196. pref.Fixed32Kind, pref.Fixed64Kind:
  197. e.WriteUint(val.Uint())
  198. case pref.FloatKind:
  199. // Encoder.WriteFloat handles the special numbers NaN and infinites.
  200. e.WriteFloat(val.Float(), 32)
  201. case pref.DoubleKind:
  202. // Encoder.WriteFloat handles the special numbers NaN and infinites.
  203. e.WriteFloat(val.Float(), 64)
  204. case pref.BytesKind:
  205. e.WriteString(string(val.Bytes()))
  206. case pref.EnumKind:
  207. num := val.Enum()
  208. if desc := fd.Enum().Values().ByNumber(num); desc != nil {
  209. e.WriteLiteral(string(desc.Name()))
  210. } else {
  211. // Use numeric value if there is no enum description.
  212. e.WriteInt(int64(num))
  213. }
  214. case pref.MessageKind, pref.GroupKind:
  215. return e.marshalMessage(val.Message(), true)
  216. default:
  217. panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
  218. }
  219. return nil
  220. }
  221. // marshalList marshals the given protoreflect.List as multiple name-value fields.
  222. func (e encoder) marshalList(name string, list pref.List, fd pref.FieldDescriptor) error {
  223. size := list.Len()
  224. for i := 0; i < size; i++ {
  225. e.WriteName(name)
  226. if err := e.marshalSingular(list.Get(i), fd); err != nil {
  227. return err
  228. }
  229. }
  230. return nil
  231. }
  232. // marshalMap marshals the given protoreflect.Map as multiple name-value fields.
  233. func (e encoder) marshalMap(name string, mmap pref.Map, fd pref.FieldDescriptor) error {
  234. var err error
  235. mapsort.Range(mmap, fd.MapKey().Kind(), func(key pref.MapKey, val pref.Value) bool {
  236. e.WriteName(name)
  237. e.StartMessage()
  238. defer e.EndMessage()
  239. e.WriteName("key")
  240. err = e.marshalSingular(key.Value(), fd.MapKey())
  241. if err != nil {
  242. return false
  243. }
  244. e.WriteName("value")
  245. err = e.marshalSingular(val, fd.MapValue())
  246. if err != nil {
  247. return false
  248. }
  249. return true
  250. })
  251. return err
  252. }
  253. // marshalExtensions marshals extension fields.
  254. func (e encoder) marshalExtensions(m pref.Message) error {
  255. type entry struct {
  256. key string
  257. value pref.Value
  258. desc pref.FieldDescriptor
  259. }
  260. // Get a sorted list based on field key first.
  261. var entries []entry
  262. m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
  263. if !fd.IsExtension() {
  264. return true
  265. }
  266. // For MessageSet extensions, the name used is the parent message.
  267. name := fd.FullName()
  268. if messageset.IsMessageSetExtension(fd) {
  269. name = name.Parent()
  270. }
  271. entries = append(entries, entry{
  272. key: string(name),
  273. value: v,
  274. desc: fd,
  275. })
  276. return true
  277. })
  278. // Sort extensions lexicographically.
  279. sort.Slice(entries, func(i, j int) bool {
  280. return entries[i].key < entries[j].key
  281. })
  282. // Write out sorted list.
  283. for _, entry := range entries {
  284. // Extension field name is the proto field name enclosed in [].
  285. name := "[" + entry.key + "]"
  286. if err := e.marshalField(name, entry.value, entry.desc); err != nil {
  287. return err
  288. }
  289. }
  290. return nil
  291. }
  292. // marshalUnknown parses the given []byte and marshals fields out.
  293. // This function assumes proper encoding in the given []byte.
  294. func (e encoder) marshalUnknown(b []byte) {
  295. const dec = 10
  296. const hex = 16
  297. for len(b) > 0 {
  298. num, wtype, n := protowire.ConsumeTag(b)
  299. b = b[n:]
  300. e.WriteName(strconv.FormatInt(int64(num), dec))
  301. switch wtype {
  302. case protowire.VarintType:
  303. var v uint64
  304. v, n = protowire.ConsumeVarint(b)
  305. e.WriteUint(v)
  306. case protowire.Fixed32Type:
  307. var v uint32
  308. v, n = protowire.ConsumeFixed32(b)
  309. e.WriteLiteral("0x" + strconv.FormatUint(uint64(v), hex))
  310. case protowire.Fixed64Type:
  311. var v uint64
  312. v, n = protowire.ConsumeFixed64(b)
  313. e.WriteLiteral("0x" + strconv.FormatUint(v, hex))
  314. case protowire.BytesType:
  315. var v []byte
  316. v, n = protowire.ConsumeBytes(b)
  317. e.WriteString(string(v))
  318. case protowire.StartGroupType:
  319. e.StartMessage()
  320. var v []byte
  321. v, n = protowire.ConsumeGroup(num, b)
  322. e.marshalUnknown(v)
  323. e.EndMessage()
  324. default:
  325. panic(fmt.Sprintf("prototext: error parsing unknown field wire type: %v", wtype))
  326. }
  327. b = b[n:]
  328. }
  329. }
  330. // marshalAny marshals the given google.protobuf.Any message in expanded form.
  331. // It returns true if it was able to marshal, else false.
  332. func (e encoder) marshalAny(any pref.Message) bool {
  333. // Construct the embedded message.
  334. fds := any.Descriptor().Fields()
  335. fdType := fds.ByNumber(fieldnum.Any_TypeUrl)
  336. typeURL := any.Get(fdType).String()
  337. mt, err := e.opts.Resolver.FindMessageByURL(typeURL)
  338. if err != nil {
  339. return false
  340. }
  341. m := mt.New().Interface()
  342. // Unmarshal bytes into embedded message.
  343. fdValue := fds.ByNumber(fieldnum.Any_Value)
  344. value := any.Get(fdValue)
  345. err = proto.UnmarshalOptions{
  346. AllowPartial: true,
  347. Resolver: e.opts.Resolver,
  348. }.Unmarshal(value.Bytes(), m)
  349. if err != nil {
  350. return false
  351. }
  352. // Get current encoder position. If marshaling fails, reset encoder output
  353. // back to this position.
  354. pos := e.Snapshot()
  355. // Field name is the proto field name enclosed in [].
  356. e.WriteName("[" + typeURL + "]")
  357. err = e.marshalMessage(m.ProtoReflect(), true)
  358. if err != nil {
  359. e.Reset(pos)
  360. return false
  361. }
  362. return true
  363. }