blob: b40b05ed012527bf859cd856b211e3fa136fed3d [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"
13 "github.com/golang/protobuf/v2/internal/pragma"
14 "github.com/golang/protobuf/v2/internal/set"
15 "github.com/golang/protobuf/v2/proto"
16 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Herbie Ongc525c972018-12-18 18:04:31 -080017 "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ong800c9902018-12-06 15:28:53 -080018)
19
20// Unmarshal reads the given []byte into the given proto.Message.
Herbie Ong800c9902018-12-06 15:28:53 -080021func Unmarshal(m proto.Message, b []byte) error {
22 return UnmarshalOptions{}.Unmarshal(m, b)
23}
24
Herbie Ong42577ea2019-03-26 16:26:22 -070025// UnmarshalOptions is a configurable textproto format unmarshaler.
Herbie Ong800c9902018-12-06 15:28:53 -080026type UnmarshalOptions struct {
27 pragma.NoUnkeyedLiterals
Herbie Ongc525c972018-12-18 18:04:31 -080028
Herbie Ong42577ea2019-03-26 16:26:22 -070029 // AllowPartial accepts input for messages that will result in missing
30 // required fields. If AllowPartial is false (the default), Unmarshal will
31 // return error if there are any missing required fields.
32 AllowPartial bool
33
Herbie Ongc525c972018-12-18 18:04:31 -080034 // Resolver is the registry used for type lookups when unmarshaling extensions
35 // and processing Any. If Resolver is not set, unmarshaling will default to
36 // using protoregistry.GlobalTypes.
37 Resolver *protoregistry.Types
Herbie Ong800c9902018-12-06 15:28:53 -080038}
39
40// Unmarshal reads the given []byte and populates the given proto.Message using options in
41// UnmarshalOptions object.
42func (o UnmarshalOptions) Unmarshal(m proto.Message, b []byte) error {
43 var nerr errors.NonFatal
44
45 mr := m.ProtoReflect()
46 // Clear all fields before populating it.
47 // TODO: Determine if this needs to be consistent with jsonpb and binary unmarshal where
48 // behavior is to merge values into existing message. If decision is to not clear the fields
49 // ahead, code will need to be updated properly when merging nested messages.
50 resetMessage(mr)
51
52 // Parse into text.Value of message type.
53 val, err := text.Unmarshal(b)
54 if !nerr.Merge(err) {
55 return err
56 }
57
Herbie Ongc525c972018-12-18 18:04:31 -080058 if o.Resolver == nil {
59 o.Resolver = protoregistry.GlobalTypes
60 }
Herbie Ong800c9902018-12-06 15:28:53 -080061 err = o.unmarshalMessage(val.Message(), mr)
62 if !nerr.Merge(err) {
63 return err
64 }
65
66 return nerr.E
67}
68
69// resetMessage clears all fields of given protoreflect.Message.
70// TODO: This should go into the proto package.
71func resetMessage(m pref.Message) {
72 knownFields := m.KnownFields()
73 knownFields.Range(func(num pref.FieldNumber, _ pref.Value) bool {
74 knownFields.Clear(num)
75 return true
76 })
77 unknownFields := m.UnknownFields()
78 unknownFields.Range(func(num pref.FieldNumber, _ pref.RawFields) bool {
79 unknownFields.Set(num, nil)
80 return true
81 })
Herbie Ong800c9902018-12-06 15:28:53 -080082 extTypes := knownFields.ExtensionTypes()
83 extTypes.Range(func(xt pref.ExtensionType) bool {
84 extTypes.Remove(xt)
85 return true
86 })
87}
88
89// unmarshalMessage unmarshals a [][2]text.Value message into the given protoreflect.Message.
90func (o UnmarshalOptions) unmarshalMessage(tmsg [][2]text.Value, m pref.Message) error {
91 var nerr errors.NonFatal
92
93 msgType := m.Type()
Herbie Ong66c365c2019-01-04 14:08:41 -080094 knownFields := m.KnownFields()
95
96 // Handle expanded Any message.
97 if msgType.FullName() == "google.protobuf.Any" && isExpandedAny(tmsg) {
98 return o.unmarshalAny(tmsg[0], knownFields)
99 }
100
Herbie Ong800c9902018-12-06 15:28:53 -0800101 fieldDescs := msgType.Fields()
Herbie Ong7c624e22018-12-13 14:41:22 -0800102 reservedNames := msgType.ReservedNames()
Herbie Ongc525c972018-12-18 18:04:31 -0800103 xtTypes := knownFields.ExtensionTypes()
Herbie Ong800c9902018-12-06 15:28:53 -0800104 var reqNums set.Ints
105 var seenNums set.Ints
106
107 for _, tfield := range tmsg {
108 tkey := tfield[0]
109 tval := tfield[1]
110
111 var fd pref.FieldDescriptor
Herbie Ongc525c972018-12-18 18:04:31 -0800112 var name pref.Name
113 switch tkey.Type() {
114 case text.Name:
115 name, _ = tkey.Name()
Herbie Ong800c9902018-12-06 15:28:53 -0800116 fd = fieldDescs.ByName(name)
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800117 if fd == nil {
118 // Check if this is a group field.
119 fd = fieldDescs.ByName(pref.Name(strings.ToLower(string(name))))
120 }
Herbie Ongc525c972018-12-18 18:04:31 -0800121 case text.String:
Herbie Ong66c365c2019-01-04 14:08:41 -0800122 // Handle extensions only. This code path is not for Any.
123 if msgType.FullName() == "google.protobuf.Any" {
124 break
125 }
126 // Extensions have to be registered first in the message's
Herbie Ongc525c972018-12-18 18:04:31 -0800127 // ExtensionTypes before setting a value to it.
128 xtName := pref.FullName(tkey.String())
Herbie Ong66c365c2019-01-04 14:08:41 -0800129 // Check first if it is already registered. This is the case for
130 // repeated fields.
Herbie Ongc525c972018-12-18 18:04:31 -0800131 xt := xtTypes.ByName(xtName)
132 if xt == nil {
133 var err error
Herbie Ong6470ea62019-01-07 18:56:57 -0800134 xt, err = o.findExtension(xtName)
Herbie Ongc525c972018-12-18 18:04:31 -0800135 if err != nil && err != protoregistry.NotFound {
Herbie Ong66c365c2019-01-04 14:08:41 -0800136 return errors.New("unable to resolve [%v]: %v", xtName, err)
Herbie Ongc525c972018-12-18 18:04:31 -0800137 }
138 if xt != nil {
139 xtTypes.Register(xt)
140 }
141 }
142 fd = xt
Herbie Ong800c9902018-12-06 15:28:53 -0800143 }
Herbie Ongc525c972018-12-18 18:04:31 -0800144
Herbie Ong800c9902018-12-06 15:28:53 -0800145 if fd == nil {
Herbie Ong7c624e22018-12-13 14:41:22 -0800146 // Ignore reserved names.
147 if reservedNames.Has(name) {
148 continue
149 }
Herbie Ong800c9902018-12-06 15:28:53 -0800150 // TODO: Can provide option to ignore unknown message fields.
Herbie Ong800c9902018-12-06 15:28:53 -0800151 return errors.New("%v contains unknown field: %v", msgType.FullName(), tkey)
152 }
153
154 if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
155 // Map or list fields have cardinality of repeated.
156 if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
157 return err
158 }
159 } else {
160 // Required or optional fields.
161 num := uint64(fd.Number())
162 if seenNums.Has(num) {
163 return errors.New("non-repeated field %v is repeated", fd.FullName())
164 }
165 if err := o.unmarshalSingular(tval, fd, knownFields); !nerr.Merge(err) {
166 return err
167 }
Herbie Ong42577ea2019-03-26 16:26:22 -0700168 if !o.AllowPartial && cardinality == pref.Required {
Herbie Ong800c9902018-12-06 15:28:53 -0800169 reqNums.Set(num)
170 }
171 seenNums.Set(num)
172 }
173 }
174
Herbie Ong42577ea2019-03-26 16:26:22 -0700175 if !o.AllowPartial {
176 // Check for any missing required fields.
177 allReqNums := msgType.RequiredNumbers()
178 if reqNums.Len() != allReqNums.Len() {
179 for i := 0; i < allReqNums.Len(); i++ {
180 if num := allReqNums.Get(i); !reqNums.Has(uint64(num)) {
181 nerr.AppendRequiredNotSet(string(fieldDescs.ByNumber(num).FullName()))
182 }
Herbie Ong800c9902018-12-06 15:28:53 -0800183 }
184 }
185 }
186
187 return nerr.E
188}
189
Herbie Ong6470ea62019-01-07 18:56:57 -0800190// findExtension returns protoreflect.ExtensionType from the Resolver if found.
191func (o UnmarshalOptions) findExtension(xtName pref.FullName) (pref.ExtensionType, error) {
192 xt, err := o.Resolver.FindExtensionByName(xtName)
193 if err == nil {
194 return xt, nil
195 }
196
197 // Check if this is a MessageSet extension field.
198 xt, err = o.Resolver.FindExtensionByName(xtName + ".message_set_extension")
199 if err == nil && isMessageSetExtension(xt) {
200 return xt, nil
201 }
202 return nil, protoregistry.NotFound
203}
204
Herbie Ong800c9902018-12-06 15:28:53 -0800205// unmarshalSingular unmarshals given text.Value into the non-repeated field.
206func (o UnmarshalOptions) unmarshalSingular(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
207 num := fd.Number()
208
209 var nerr errors.NonFatal
210 var val pref.Value
211 switch fd.Kind() {
212 case pref.MessageKind, pref.GroupKind:
213 if input.Type() != text.Message {
214 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
215 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800216 m := knownFields.NewMessage(num)
Herbie Ong800c9902018-12-06 15:28:53 -0800217 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
218 return err
219 }
220 val = pref.ValueOf(m)
221 default:
222 var err error
223 val, err = unmarshalScalar(input, fd)
224 if !nerr.Merge(err) {
225 return err
226 }
227 }
228 knownFields.Set(num, val)
229
230 return nerr.E
231}
232
233// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
234// call this for cardinality=repeated.
235func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
236 var items []text.Value
237 // If input is not a list, turn it into a list.
238 if input.Type() != text.List {
239 items = []text.Value{input}
240 } else {
241 items = input.List()
242 }
243
244 var nerr errors.NonFatal
245 num := fd.Number()
246 val := knownFields.Get(num)
247 if !fd.IsMap() {
248 if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
249 return err
250 }
251 } else {
252 if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
253 return err
254 }
255 }
256
257 return nerr.E
258}
259
260// unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
261// the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
262func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
263 const b32 = false
264 const b64 = true
265
266 switch kind := fd.Kind(); kind {
267 case pref.BoolKind:
268 if b, ok := input.Bool(); ok {
269 return pref.ValueOf(bool(b)), nil
270 }
271 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
272 if n, ok := input.Int(b32); ok {
273 return pref.ValueOf(int32(n)), nil
274 }
275 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
276 if n, ok := input.Int(b64); ok {
277 return pref.ValueOf(int64(n)), nil
278 }
279 case pref.Uint32Kind, pref.Fixed32Kind:
280 if n, ok := input.Uint(b32); ok {
281 return pref.ValueOf(uint32(n)), nil
282 }
283 case pref.Uint64Kind, pref.Fixed64Kind:
284 if n, ok := input.Uint(b64); ok {
285 return pref.ValueOf(uint64(n)), nil
286 }
287 case pref.FloatKind:
Herbie Ong250c6ea2019-03-12 20:55:10 -0700288 if n, ok := input.Float(b32); ok {
Herbie Ong800c9902018-12-06 15:28:53 -0800289 return pref.ValueOf(float32(n)), nil
290 }
291 case pref.DoubleKind:
Herbie Ong250c6ea2019-03-12 20:55:10 -0700292 if n, ok := input.Float(b64); ok {
Herbie Ong800c9902018-12-06 15:28:53 -0800293 return pref.ValueOf(float64(n)), nil
294 }
295 case pref.StringKind:
296 if input.Type() == text.String {
297 return pref.ValueOf(string(input.String())), nil
298 }
299 case pref.BytesKind:
300 if input.Type() == text.String {
301 return pref.ValueOf([]byte(input.String())), nil
302 }
303 case pref.EnumKind:
304 // If input is int32, use directly.
305 if n, ok := input.Int(b32); ok {
306 return pref.ValueOf(pref.EnumNumber(n)), nil
Herbie Ong66c365c2019-01-04 14:08:41 -0800307 }
308 if name, ok := input.Name(); ok {
309 // Lookup EnumNumber based on name.
310 if enumVal := fd.EnumType().Values().ByName(name); enumVal != nil {
311 return pref.ValueOf(enumVal.Number()), nil
Herbie Ong800c9902018-12-06 15:28:53 -0800312 }
313 }
314 default:
315 panic(fmt.Sprintf("invalid scalar kind %v", kind))
316 }
317
318 return pref.Value{}, errors.New("%v contains invalid scalar value: %v", fd.FullName(), input)
319}
320
321// unmarshalList unmarshals given []text.Value into given protoreflect.List.
322func (o UnmarshalOptions) unmarshalList(inputList []text.Value, fd pref.FieldDescriptor, list pref.List) error {
323 var nerr errors.NonFatal
324
325 switch fd.Kind() {
326 case pref.MessageKind, pref.GroupKind:
327 for _, input := range inputList {
328 if input.Type() != text.Message {
329 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
330 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800331 m := list.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800332 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
333 return err
334 }
335 list.Append(pref.ValueOf(m))
336 }
337 default:
338 for _, input := range inputList {
339 val, err := unmarshalScalar(input, fd)
340 if !nerr.Merge(err) {
341 return err
342 }
343 list.Append(val)
344 }
345 }
346
347 return nerr.E
348}
349
350// unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
351func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
352 var nerr errors.NonFatal
353 fields := fd.MessageType().Fields()
354 keyDesc := fields.ByNumber(1)
355 valDesc := fields.ByNumber(2)
356
357 // Determine ahead whether map entry is a scalar type or a message type in order to call the
358 // appropriate unmarshalMapValue func inside the for loop below.
Herbie Ong66c365c2019-01-04 14:08:41 -0800359 unmarshalMapValue := unmarshalMapScalarValue
Herbie Ong800c9902018-12-06 15:28:53 -0800360 switch valDesc.Kind() {
361 case pref.MessageKind, pref.GroupKind:
362 unmarshalMapValue = o.unmarshalMapMessageValue
363 }
364
365 for _, entry := range input {
366 if entry.Type() != text.Message {
367 return errors.New("%v contains invalid map entry: %v", fd.FullName(), entry)
368 }
369 tkey, tval, err := parseMapEntry(entry.Message(), fd.FullName())
370 if !nerr.Merge(err) {
371 return err
372 }
373 pkey, err := unmarshalMapKey(tkey, keyDesc)
374 if !nerr.Merge(err) {
375 return err
376 }
377 err = unmarshalMapValue(tval, pkey, valDesc, mmap)
378 if !nerr.Merge(err) {
379 return err
380 }
381 }
382
383 return nerr.E
384}
385
386// parseMapEntry parses [][2]text.Value for field names key and value, and return corresponding
387// field values. If there are duplicate field names, the value for the last field is returned. If
388// the field name does not exist, it will return the zero value of text.Value. It will return an
389// error if there are unknown field names.
390func parseMapEntry(mapEntry [][2]text.Value, name pref.FullName) (key text.Value, value text.Value, err error) {
391 for _, field := range mapEntry {
392 keyStr, ok := field[0].Name()
393 if ok {
394 switch keyStr {
395 case "key":
396 if key.Type() != 0 {
397 return key, value, errors.New("%v contains duplicate key field", name)
398 }
399 key = field[1]
400 case "value":
401 if value.Type() != 0 {
402 return key, value, errors.New("%v contains duplicate value field", name)
403 }
404 value = field[1]
405 default:
406 ok = false
407 }
408 }
409 if !ok {
410 // TODO: Do not return error if ignore unknown option is added and enabled.
411 return key, value, errors.New("%v contains unknown map entry name: %v", name, field[0])
412 }
413 }
414 return key, value, nil
415}
416
417// unmarshalMapKey converts given text.Value into a protoreflect.MapKey. A map key type is any
418// integral or string type.
419func unmarshalMapKey(input text.Value, fd pref.FieldDescriptor) (pref.MapKey, error) {
420 // If input is not set, use the zero value.
421 if input.Type() == 0 {
422 return fd.Default().MapKey(), nil
423 }
424
425 val, err := unmarshalScalar(input, fd)
426 if err != nil {
427 return pref.MapKey{}, errors.New("%v contains invalid key: %v", fd.FullName(), input)
428 }
429 return val.MapKey(), nil
430}
431
432// unmarshalMapMessageValue unmarshals given message-type text.Value into a protoreflect.Map for
433// the given MapKey.
434func (o UnmarshalOptions) unmarshalMapMessageValue(input text.Value, pkey pref.MapKey, _ pref.FieldDescriptor, mmap pref.Map) error {
435 var nerr errors.NonFatal
436 var value [][2]text.Value
437 if input.Type() != 0 {
438 value = input.Message()
439 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800440 m := mmap.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800441 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
442 return err
443 }
444 mmap.Set(pkey, pref.ValueOf(m))
445 return nerr.E
446}
447
448// unmarshalMapScalarValue unmarshals given scalar-type text.Value into a protoreflect.Map
449// for the given MapKey.
Herbie Ong66c365c2019-01-04 14:08:41 -0800450func unmarshalMapScalarValue(input text.Value, pkey pref.MapKey, fd pref.FieldDescriptor, mmap pref.Map) error {
Herbie Ong800c9902018-12-06 15:28:53 -0800451 var val pref.Value
452 if input.Type() == 0 {
453 val = fd.Default()
454 } else {
455 var err error
456 val, err = unmarshalScalar(input, fd)
457 if err != nil {
458 return err
459 }
460 }
461 mmap.Set(pkey, val)
462 return nil
463}
Herbie Ong66c365c2019-01-04 14:08:41 -0800464
465// isExpandedAny returns true if given [][2]text.Value may be an expanded Any that contains only one
466// field with key type of text.String type and value type of text.Message.
467func isExpandedAny(tmsg [][2]text.Value) bool {
468 if len(tmsg) != 1 {
469 return false
470 }
471
472 field := tmsg[0]
473 return field[0].Type() == text.String && field[1].Type() == text.Message
474}
475
476// unmarshalAny unmarshals an expanded Any textproto. This method assumes that the given
477// tfield has key type of text.String and value type of text.Message.
478func (o UnmarshalOptions) unmarshalAny(tfield [2]text.Value, knownFields pref.KnownFields) error {
479 var nerr errors.NonFatal
480
481 typeURL := tfield[0].String()
482 value := tfield[1].Message()
483
484 mt, err := o.Resolver.FindMessageByURL(typeURL)
485 if !nerr.Merge(err) {
486 return errors.New("unable to resolve message [%v]: %v", typeURL, err)
487 }
488 // Create new message for the embedded message type and unmarshal the
489 // value into it.
490 m := mt.New()
491 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
492 return err
493 }
494 // Serialize the embedded message and assign the resulting bytes to the value field.
Herbie Onge0cf15b2019-03-15 19:32:38 -0700495 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m.Interface())
Herbie Ong66c365c2019-01-04 14:08:41 -0800496 if !nerr.Merge(err) {
497 return err
498 }
499
500 knownFields.Set(pref.FieldNumber(1), pref.ValueOf(typeURL))
501 knownFields.Set(pref.FieldNumber(2), pref.ValueOf(b))
502
503 return nerr.E
504}