blob: 59c98b199e933833f96d44eb98c92e5d8247f4e3 [file] [log] [blame]
Herbie Ong800c9902018-12-06 15:28:53 -08001// 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
5package textpb
6
7import (
8 "fmt"
Herbie Ong0dcfb9a2019-01-14 15:32:26 -08009 "strings"
Herbie Ong800c9902018-12-06 15:28:53 -080010
11 "github.com/golang/protobuf/v2/internal/encoding/text"
12 "github.com/golang/protobuf/v2/internal/errors"
Herbie Onge1e34932019-03-29 01:05:57 -070013 "github.com/golang/protobuf/v2/internal/fieldnum"
Herbie Ong800c9902018-12-06 15:28:53 -080014 "github.com/golang/protobuf/v2/internal/pragma"
15 "github.com/golang/protobuf/v2/internal/set"
16 "github.com/golang/protobuf/v2/proto"
17 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Herbie Ongc525c972018-12-18 18:04:31 -080018 "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ong800c9902018-12-06 15:28:53 -080019)
20
21// Unmarshal reads the given []byte into the given proto.Message.
Herbie Ong800c9902018-12-06 15:28:53 -080022func Unmarshal(m proto.Message, b []byte) error {
23 return UnmarshalOptions{}.Unmarshal(m, b)
24}
25
Herbie Ong42577ea2019-03-26 16:26:22 -070026// UnmarshalOptions is a configurable textproto format unmarshaler.
Herbie Ong800c9902018-12-06 15:28:53 -080027type UnmarshalOptions struct {
28 pragma.NoUnkeyedLiterals
Herbie Ongc525c972018-12-18 18:04:31 -080029
Herbie Ong42577ea2019-03-26 16:26:22 -070030 // AllowPartial accepts input for messages that will result in missing
31 // required fields. If AllowPartial is false (the default), Unmarshal will
32 // return error if there are any missing required fields.
33 AllowPartial bool
34
Herbie Ongc525c972018-12-18 18:04:31 -080035 // Resolver is the registry used for type lookups when unmarshaling extensions
36 // and processing Any. If Resolver is not set, unmarshaling will default to
37 // using protoregistry.GlobalTypes.
38 Resolver *protoregistry.Types
Herbie Ong800c9902018-12-06 15:28:53 -080039}
40
41// Unmarshal reads the given []byte and populates the given proto.Message using options in
42// UnmarshalOptions object.
43func (o UnmarshalOptions) Unmarshal(m proto.Message, b []byte) error {
44 var nerr errors.NonFatal
45
46 mr := m.ProtoReflect()
47 // Clear all fields before populating it.
48 // TODO: Determine if this needs to be consistent with jsonpb and binary unmarshal where
49 // behavior is to merge values into existing message. If decision is to not clear the fields
50 // ahead, code will need to be updated properly when merging nested messages.
51 resetMessage(mr)
52
53 // Parse into text.Value of message type.
54 val, err := text.Unmarshal(b)
55 if !nerr.Merge(err) {
56 return err
57 }
58
Herbie Ongc525c972018-12-18 18:04:31 -080059 if o.Resolver == nil {
60 o.Resolver = protoregistry.GlobalTypes
61 }
Herbie Ong800c9902018-12-06 15:28:53 -080062 err = o.unmarshalMessage(val.Message(), mr)
63 if !nerr.Merge(err) {
64 return err
65 }
66
Damien Neil4686e232019-04-05 13:31:40 -070067 if !o.AllowPartial {
68 nerr.Merge(proto.IsInitialized(m))
69 }
70
Herbie Ong800c9902018-12-06 15:28:53 -080071 return nerr.E
72}
73
74// resetMessage clears all fields of given protoreflect.Message.
75// TODO: This should go into the proto package.
76func resetMessage(m pref.Message) {
77 knownFields := m.KnownFields()
78 knownFields.Range(func(num pref.FieldNumber, _ pref.Value) bool {
79 knownFields.Clear(num)
80 return true
81 })
82 unknownFields := m.UnknownFields()
83 unknownFields.Range(func(num pref.FieldNumber, _ pref.RawFields) bool {
84 unknownFields.Set(num, nil)
85 return true
86 })
Herbie Ong800c9902018-12-06 15:28:53 -080087 extTypes := knownFields.ExtensionTypes()
88 extTypes.Range(func(xt pref.ExtensionType) bool {
89 extTypes.Remove(xt)
90 return true
91 })
92}
93
94// unmarshalMessage unmarshals a [][2]text.Value message into the given protoreflect.Message.
95func (o UnmarshalOptions) unmarshalMessage(tmsg [][2]text.Value, m pref.Message) error {
96 var nerr errors.NonFatal
97
98 msgType := m.Type()
Herbie Ong66c365c2019-01-04 14:08:41 -080099 knownFields := m.KnownFields()
100
101 // Handle expanded Any message.
102 if msgType.FullName() == "google.protobuf.Any" && isExpandedAny(tmsg) {
103 return o.unmarshalAny(tmsg[0], knownFields)
104 }
105
Herbie Ong800c9902018-12-06 15:28:53 -0800106 fieldDescs := msgType.Fields()
Herbie Ong7c624e22018-12-13 14:41:22 -0800107 reservedNames := msgType.ReservedNames()
Herbie Ongc525c972018-12-18 18:04:31 -0800108 xtTypes := knownFields.ExtensionTypes()
Herbie Ong800c9902018-12-06 15:28:53 -0800109 var seenNums set.Ints
Herbie Ong8a1d4602019-04-02 20:19:36 -0700110 var seenOneofs set.Ints
Herbie Ong800c9902018-12-06 15:28:53 -0800111
112 for _, tfield := range tmsg {
113 tkey := tfield[0]
114 tval := tfield[1]
115
116 var fd pref.FieldDescriptor
Herbie Ongc525c972018-12-18 18:04:31 -0800117 var name pref.Name
118 switch tkey.Type() {
119 case text.Name:
120 name, _ = tkey.Name()
Herbie Ong800c9902018-12-06 15:28:53 -0800121 fd = fieldDescs.ByName(name)
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800122 if fd == nil {
123 // Check if this is a group field.
124 fd = fieldDescs.ByName(pref.Name(strings.ToLower(string(name))))
125 }
Herbie Ongc525c972018-12-18 18:04:31 -0800126 case text.String:
Herbie Ong66c365c2019-01-04 14:08:41 -0800127 // Handle extensions only. This code path is not for Any.
128 if msgType.FullName() == "google.protobuf.Any" {
129 break
130 }
131 // Extensions have to be registered first in the message's
Herbie Ongc525c972018-12-18 18:04:31 -0800132 // ExtensionTypes before setting a value to it.
133 xtName := pref.FullName(tkey.String())
Herbie Ong66c365c2019-01-04 14:08:41 -0800134 // Check first if it is already registered. This is the case for
135 // repeated fields.
Herbie Ongc525c972018-12-18 18:04:31 -0800136 xt := xtTypes.ByName(xtName)
137 if xt == nil {
138 var err error
Herbie Ong6470ea62019-01-07 18:56:57 -0800139 xt, err = o.findExtension(xtName)
Herbie Ongc525c972018-12-18 18:04:31 -0800140 if err != nil && err != protoregistry.NotFound {
Herbie Ong66c365c2019-01-04 14:08:41 -0800141 return errors.New("unable to resolve [%v]: %v", xtName, err)
Herbie Ongc525c972018-12-18 18:04:31 -0800142 }
143 if xt != nil {
144 xtTypes.Register(xt)
145 }
146 }
147 fd = xt
Herbie Ong800c9902018-12-06 15:28:53 -0800148 }
Herbie Ongc525c972018-12-18 18:04:31 -0800149
Herbie Ong800c9902018-12-06 15:28:53 -0800150 if fd == nil {
Herbie Ong7c624e22018-12-13 14:41:22 -0800151 // Ignore reserved names.
152 if reservedNames.Has(name) {
153 continue
154 }
Herbie Ong800c9902018-12-06 15:28:53 -0800155 // TODO: Can provide option to ignore unknown message fields.
Herbie Ong800c9902018-12-06 15:28:53 -0800156 return errors.New("%v contains unknown field: %v", msgType.FullName(), tkey)
157 }
158
159 if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
160 // Map or list fields have cardinality of repeated.
161 if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
162 return err
163 }
164 } else {
Herbie Ong8a1d4602019-04-02 20:19:36 -0700165 // If field is a oneof, check if it has already been set.
166 if od := fd.OneofType(); od != nil {
167 idx := uint64(od.Index())
168 if seenOneofs.Has(idx) {
169 return errors.New("oneof %v is already set", od.FullName())
170 }
171 seenOneofs.Set(idx)
172 }
173
Herbie Ong800c9902018-12-06 15:28:53 -0800174 // Required or optional fields.
175 num := uint64(fd.Number())
176 if seenNums.Has(num) {
177 return errors.New("non-repeated field %v is repeated", fd.FullName())
178 }
179 if err := o.unmarshalSingular(tval, fd, knownFields); !nerr.Merge(err) {
180 return err
181 }
Herbie Ong800c9902018-12-06 15:28:53 -0800182 seenNums.Set(num)
183 }
184 }
185
Herbie Ong800c9902018-12-06 15:28:53 -0800186 return nerr.E
187}
188
Herbie Ong6470ea62019-01-07 18:56:57 -0800189// findExtension returns protoreflect.ExtensionType from the Resolver if found.
190func (o UnmarshalOptions) findExtension(xtName pref.FullName) (pref.ExtensionType, error) {
191 xt, err := o.Resolver.FindExtensionByName(xtName)
192 if err == nil {
193 return xt, nil
194 }
195
196 // Check if this is a MessageSet extension field.
197 xt, err = o.Resolver.FindExtensionByName(xtName + ".message_set_extension")
198 if err == nil && isMessageSetExtension(xt) {
199 return xt, nil
200 }
201 return nil, protoregistry.NotFound
202}
203
Herbie Ong800c9902018-12-06 15:28:53 -0800204// unmarshalSingular unmarshals given text.Value into the non-repeated field.
205func (o UnmarshalOptions) unmarshalSingular(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
206 num := fd.Number()
207
208 var nerr errors.NonFatal
209 var val pref.Value
210 switch fd.Kind() {
211 case pref.MessageKind, pref.GroupKind:
212 if input.Type() != text.Message {
213 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
214 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800215 m := knownFields.NewMessage(num)
Herbie Ong800c9902018-12-06 15:28:53 -0800216 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
217 return err
218 }
219 val = pref.ValueOf(m)
220 default:
221 var err error
222 val, err = unmarshalScalar(input, fd)
223 if !nerr.Merge(err) {
224 return err
225 }
226 }
227 knownFields.Set(num, val)
228
229 return nerr.E
230}
231
232// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
233// call this for cardinality=repeated.
234func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
235 var items []text.Value
236 // If input is not a list, turn it into a list.
237 if input.Type() != text.List {
238 items = []text.Value{input}
239 } else {
240 items = input.List()
241 }
242
243 var nerr errors.NonFatal
244 num := fd.Number()
245 val := knownFields.Get(num)
246 if !fd.IsMap() {
247 if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
248 return err
249 }
250 } else {
251 if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
252 return err
253 }
254 }
255
256 return nerr.E
257}
258
259// unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
260// the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
261func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
262 const b32 = false
263 const b64 = true
264
265 switch kind := fd.Kind(); kind {
266 case pref.BoolKind:
267 if b, ok := input.Bool(); ok {
268 return pref.ValueOf(bool(b)), nil
269 }
270 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
271 if n, ok := input.Int(b32); ok {
272 return pref.ValueOf(int32(n)), nil
273 }
274 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
275 if n, ok := input.Int(b64); ok {
276 return pref.ValueOf(int64(n)), nil
277 }
278 case pref.Uint32Kind, pref.Fixed32Kind:
279 if n, ok := input.Uint(b32); ok {
280 return pref.ValueOf(uint32(n)), nil
281 }
282 case pref.Uint64Kind, pref.Fixed64Kind:
283 if n, ok := input.Uint(b64); ok {
284 return pref.ValueOf(uint64(n)), nil
285 }
286 case pref.FloatKind:
Herbie Ong250c6ea2019-03-12 20:55:10 -0700287 if n, ok := input.Float(b32); ok {
Herbie Ong800c9902018-12-06 15:28:53 -0800288 return pref.ValueOf(float32(n)), nil
289 }
290 case pref.DoubleKind:
Herbie Ong250c6ea2019-03-12 20:55:10 -0700291 if n, ok := input.Float(b64); ok {
Herbie Ong800c9902018-12-06 15:28:53 -0800292 return pref.ValueOf(float64(n)), nil
293 }
294 case pref.StringKind:
295 if input.Type() == text.String {
296 return pref.ValueOf(string(input.String())), nil
297 }
298 case pref.BytesKind:
299 if input.Type() == text.String {
300 return pref.ValueOf([]byte(input.String())), nil
301 }
302 case pref.EnumKind:
303 // If input is int32, use directly.
304 if n, ok := input.Int(b32); ok {
305 return pref.ValueOf(pref.EnumNumber(n)), nil
Herbie Ong66c365c2019-01-04 14:08:41 -0800306 }
307 if name, ok := input.Name(); ok {
308 // Lookup EnumNumber based on name.
309 if enumVal := fd.EnumType().Values().ByName(name); enumVal != nil {
310 return pref.ValueOf(enumVal.Number()), nil
Herbie Ong800c9902018-12-06 15:28:53 -0800311 }
312 }
313 default:
314 panic(fmt.Sprintf("invalid scalar kind %v", kind))
315 }
316
317 return pref.Value{}, errors.New("%v contains invalid scalar value: %v", fd.FullName(), input)
318}
319
320// unmarshalList unmarshals given []text.Value into given protoreflect.List.
321func (o UnmarshalOptions) unmarshalList(inputList []text.Value, fd pref.FieldDescriptor, list pref.List) error {
322 var nerr errors.NonFatal
323
324 switch fd.Kind() {
325 case pref.MessageKind, pref.GroupKind:
326 for _, input := range inputList {
327 if input.Type() != text.Message {
328 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
329 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800330 m := list.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800331 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
332 return err
333 }
334 list.Append(pref.ValueOf(m))
335 }
336 default:
337 for _, input := range inputList {
338 val, err := unmarshalScalar(input, fd)
339 if !nerr.Merge(err) {
340 return err
341 }
342 list.Append(val)
343 }
344 }
345
346 return nerr.E
347}
348
349// unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
350func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
351 var nerr errors.NonFatal
352 fields := fd.MessageType().Fields()
353 keyDesc := fields.ByNumber(1)
354 valDesc := fields.ByNumber(2)
355
356 // Determine ahead whether map entry is a scalar type or a message type in order to call the
357 // appropriate unmarshalMapValue func inside the for loop below.
Herbie Ong66c365c2019-01-04 14:08:41 -0800358 unmarshalMapValue := unmarshalMapScalarValue
Herbie Ong800c9902018-12-06 15:28:53 -0800359 switch valDesc.Kind() {
360 case pref.MessageKind, pref.GroupKind:
361 unmarshalMapValue = o.unmarshalMapMessageValue
362 }
363
364 for _, entry := range input {
365 if entry.Type() != text.Message {
366 return errors.New("%v contains invalid map entry: %v", fd.FullName(), entry)
367 }
368 tkey, tval, err := parseMapEntry(entry.Message(), fd.FullName())
369 if !nerr.Merge(err) {
370 return err
371 }
372 pkey, err := unmarshalMapKey(tkey, keyDesc)
373 if !nerr.Merge(err) {
374 return err
375 }
376 err = unmarshalMapValue(tval, pkey, valDesc, mmap)
377 if !nerr.Merge(err) {
378 return err
379 }
380 }
381
382 return nerr.E
383}
384
385// parseMapEntry parses [][2]text.Value for field names key and value, and return corresponding
386// field values. If there are duplicate field names, the value for the last field is returned. If
387// the field name does not exist, it will return the zero value of text.Value. It will return an
388// error if there are unknown field names.
389func parseMapEntry(mapEntry [][2]text.Value, name pref.FullName) (key text.Value, value text.Value, err error) {
390 for _, field := range mapEntry {
391 keyStr, ok := field[0].Name()
392 if ok {
393 switch keyStr {
394 case "key":
395 if key.Type() != 0 {
396 return key, value, errors.New("%v contains duplicate key field", name)
397 }
398 key = field[1]
399 case "value":
400 if value.Type() != 0 {
401 return key, value, errors.New("%v contains duplicate value field", name)
402 }
403 value = field[1]
404 default:
405 ok = false
406 }
407 }
408 if !ok {
409 // TODO: Do not return error if ignore unknown option is added and enabled.
410 return key, value, errors.New("%v contains unknown map entry name: %v", name, field[0])
411 }
412 }
413 return key, value, nil
414}
415
416// unmarshalMapKey converts given text.Value into a protoreflect.MapKey. A map key type is any
417// integral or string type.
418func unmarshalMapKey(input text.Value, fd pref.FieldDescriptor) (pref.MapKey, error) {
419 // If input is not set, use the zero value.
420 if input.Type() == 0 {
421 return fd.Default().MapKey(), nil
422 }
423
424 val, err := unmarshalScalar(input, fd)
425 if err != nil {
426 return pref.MapKey{}, errors.New("%v contains invalid key: %v", fd.FullName(), input)
427 }
428 return val.MapKey(), nil
429}
430
431// unmarshalMapMessageValue unmarshals given message-type text.Value into a protoreflect.Map for
432// the given MapKey.
433func (o UnmarshalOptions) unmarshalMapMessageValue(input text.Value, pkey pref.MapKey, _ pref.FieldDescriptor, mmap pref.Map) error {
434 var nerr errors.NonFatal
435 var value [][2]text.Value
436 if input.Type() != 0 {
437 value = input.Message()
438 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800439 m := mmap.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800440 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
441 return err
442 }
443 mmap.Set(pkey, pref.ValueOf(m))
444 return nerr.E
445}
446
447// unmarshalMapScalarValue unmarshals given scalar-type text.Value into a protoreflect.Map
448// for the given MapKey.
Herbie Ong66c365c2019-01-04 14:08:41 -0800449func unmarshalMapScalarValue(input text.Value, pkey pref.MapKey, fd pref.FieldDescriptor, mmap pref.Map) error {
Herbie Ong800c9902018-12-06 15:28:53 -0800450 var val pref.Value
451 if input.Type() == 0 {
452 val = fd.Default()
453 } else {
454 var err error
455 val, err = unmarshalScalar(input, fd)
456 if err != nil {
457 return err
458 }
459 }
460 mmap.Set(pkey, val)
461 return nil
462}
Herbie Ong66c365c2019-01-04 14:08:41 -0800463
464// isExpandedAny returns true if given [][2]text.Value may be an expanded Any that contains only one
465// field with key type of text.String type and value type of text.Message.
466func isExpandedAny(tmsg [][2]text.Value) bool {
467 if len(tmsg) != 1 {
468 return false
469 }
470
471 field := tmsg[0]
472 return field[0].Type() == text.String && field[1].Type() == text.Message
473}
474
475// unmarshalAny unmarshals an expanded Any textproto. This method assumes that the given
476// tfield has key type of text.String and value type of text.Message.
477func (o UnmarshalOptions) unmarshalAny(tfield [2]text.Value, knownFields pref.KnownFields) error {
478 var nerr errors.NonFatal
479
480 typeURL := tfield[0].String()
481 value := tfield[1].Message()
482
483 mt, err := o.Resolver.FindMessageByURL(typeURL)
484 if !nerr.Merge(err) {
485 return errors.New("unable to resolve message [%v]: %v", typeURL, err)
486 }
487 // Create new message for the embedded message type and unmarshal the
488 // value into it.
489 m := mt.New()
490 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
491 return err
492 }
493 // Serialize the embedded message and assign the resulting bytes to the value field.
Damien Neil96c229a2019-04-03 12:17:24 -0700494 b, err := proto.MarshalOptions{
495 AllowPartial: o.AllowPartial,
496 Deterministic: true,
497 }.Marshal(m.Interface())
Herbie Ong66c365c2019-01-04 14:08:41 -0800498 if !nerr.Merge(err) {
499 return err
500 }
501
Herbie Onge1e34932019-03-29 01:05:57 -0700502 knownFields.Set(fieldnum.Any_TypeUrl, pref.ValueOf(typeURL))
503 knownFields.Set(fieldnum.Any_Value, pref.ValueOf(b))
Herbie Ong66c365c2019-01-04 14:08:41 -0800504
505 return nerr.E
506}