blob: f906e186821d22d7d7c64e3c5a3b517c3e3660be [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
Herbie Ong66c365c2019-01-04 14:08:41 -080011 protoV1 "github.com/golang/protobuf/proto"
Herbie Ong800c9902018-12-06 15:28:53 -080012 "github.com/golang/protobuf/v2/internal/encoding/text"
13 "github.com/golang/protobuf/v2/internal/errors"
14 "github.com/golang/protobuf/v2/internal/pragma"
15 "github.com/golang/protobuf/v2/internal/set"
Herbie Ong66c365c2019-01-04 14:08:41 -080016 pvalue "github.com/golang/protobuf/v2/internal/value"
Herbie Ong800c9902018-12-06 15:28:53 -080017 "github.com/golang/protobuf/v2/proto"
18 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Herbie Ongc525c972018-12-18 18:04:31 -080019 "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ong800c9902018-12-06 15:28:53 -080020)
21
22// Unmarshal reads the given []byte into the given proto.Message.
23// TODO: may want to describe when Unmarshal returns error.
24func Unmarshal(m proto.Message, b []byte) error {
25 return UnmarshalOptions{}.Unmarshal(m, b)
26}
27
28// UnmarshalOptions is a configurable textproto format parser.
29type UnmarshalOptions struct {
30 pragma.NoUnkeyedLiterals
Herbie Ongc525c972018-12-18 18:04:31 -080031
32 // Resolver is the registry used for type lookups when unmarshaling extensions
33 // and processing Any. If Resolver is not set, unmarshaling will default to
34 // using protoregistry.GlobalTypes.
35 Resolver *protoregistry.Types
Herbie Ong800c9902018-12-06 15:28:53 -080036}
37
38// Unmarshal reads the given []byte and populates the given proto.Message using options in
39// UnmarshalOptions object.
40func (o UnmarshalOptions) Unmarshal(m proto.Message, b []byte) error {
41 var nerr errors.NonFatal
42
43 mr := m.ProtoReflect()
44 // Clear all fields before populating it.
45 // TODO: Determine if this needs to be consistent with jsonpb and binary unmarshal where
46 // behavior is to merge values into existing message. If decision is to not clear the fields
47 // ahead, code will need to be updated properly when merging nested messages.
48 resetMessage(mr)
49
50 // Parse into text.Value of message type.
51 val, err := text.Unmarshal(b)
52 if !nerr.Merge(err) {
53 return err
54 }
55
Herbie Ongc525c972018-12-18 18:04:31 -080056 if o.Resolver == nil {
57 o.Resolver = protoregistry.GlobalTypes
58 }
Herbie Ong800c9902018-12-06 15:28:53 -080059 err = o.unmarshalMessage(val.Message(), mr)
60 if !nerr.Merge(err) {
61 return err
62 }
63
64 return nerr.E
65}
66
67// resetMessage clears all fields of given protoreflect.Message.
68// TODO: This should go into the proto package.
69func resetMessage(m pref.Message) {
70 knownFields := m.KnownFields()
71 knownFields.Range(func(num pref.FieldNumber, _ pref.Value) bool {
72 knownFields.Clear(num)
73 return true
74 })
75 unknownFields := m.UnknownFields()
76 unknownFields.Range(func(num pref.FieldNumber, _ pref.RawFields) bool {
77 unknownFields.Set(num, nil)
78 return true
79 })
Herbie Ong800c9902018-12-06 15:28:53 -080080 extTypes := knownFields.ExtensionTypes()
81 extTypes.Range(func(xt pref.ExtensionType) bool {
82 extTypes.Remove(xt)
83 return true
84 })
85}
86
87// unmarshalMessage unmarshals a [][2]text.Value message into the given protoreflect.Message.
88func (o UnmarshalOptions) unmarshalMessage(tmsg [][2]text.Value, m pref.Message) error {
89 var nerr errors.NonFatal
90
91 msgType := m.Type()
Herbie Ong66c365c2019-01-04 14:08:41 -080092 knownFields := m.KnownFields()
93
94 // Handle expanded Any message.
95 if msgType.FullName() == "google.protobuf.Any" && isExpandedAny(tmsg) {
96 return o.unmarshalAny(tmsg[0], knownFields)
97 }
98
Herbie Ong800c9902018-12-06 15:28:53 -080099 fieldDescs := msgType.Fields()
Herbie Ong7c624e22018-12-13 14:41:22 -0800100 reservedNames := msgType.ReservedNames()
Herbie Ongc525c972018-12-18 18:04:31 -0800101 xtTypes := knownFields.ExtensionTypes()
Herbie Ong800c9902018-12-06 15:28:53 -0800102 var reqNums set.Ints
103 var seenNums set.Ints
104
105 for _, tfield := range tmsg {
106 tkey := tfield[0]
107 tval := tfield[1]
108
109 var fd pref.FieldDescriptor
Herbie Ongc525c972018-12-18 18:04:31 -0800110 var name pref.Name
111 switch tkey.Type() {
112 case text.Name:
113 name, _ = tkey.Name()
Herbie Ong800c9902018-12-06 15:28:53 -0800114 fd = fieldDescs.ByName(name)
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800115 if fd == nil {
116 // Check if this is a group field.
117 fd = fieldDescs.ByName(pref.Name(strings.ToLower(string(name))))
118 }
Herbie Ongc525c972018-12-18 18:04:31 -0800119 case text.String:
Herbie Ong66c365c2019-01-04 14:08:41 -0800120 // Handle extensions only. This code path is not for Any.
121 if msgType.FullName() == "google.protobuf.Any" {
122 break
123 }
124 // Extensions have to be registered first in the message's
Herbie Ongc525c972018-12-18 18:04:31 -0800125 // ExtensionTypes before setting a value to it.
126 xtName := pref.FullName(tkey.String())
Herbie Ong66c365c2019-01-04 14:08:41 -0800127 // Check first if it is already registered. This is the case for
128 // repeated fields.
Herbie Ongc525c972018-12-18 18:04:31 -0800129 xt := xtTypes.ByName(xtName)
130 if xt == nil {
131 var err error
132 xt, err = o.Resolver.FindExtensionByName(xtName)
133 if err != nil && err != protoregistry.NotFound {
Herbie Ong66c365c2019-01-04 14:08:41 -0800134 return errors.New("unable to resolve [%v]: %v", xtName, err)
Herbie Ongc525c972018-12-18 18:04:31 -0800135 }
136 if xt != nil {
137 xtTypes.Register(xt)
138 }
139 }
140 fd = xt
Herbie Ong800c9902018-12-06 15:28:53 -0800141 }
Herbie Ongc525c972018-12-18 18:04:31 -0800142
Herbie Ong800c9902018-12-06 15:28:53 -0800143 if fd == nil {
Herbie Ong7c624e22018-12-13 14:41:22 -0800144 // Ignore reserved names.
145 if reservedNames.Has(name) {
146 continue
147 }
Herbie Ong800c9902018-12-06 15:28:53 -0800148 // TODO: Can provide option to ignore unknown message fields.
Herbie Ong800c9902018-12-06 15:28:53 -0800149 return errors.New("%v contains unknown field: %v", msgType.FullName(), tkey)
150 }
151
152 if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
153 // Map or list fields have cardinality of repeated.
154 if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
155 return err
156 }
157 } else {
158 // Required or optional fields.
159 num := uint64(fd.Number())
160 if seenNums.Has(num) {
161 return errors.New("non-repeated field %v is repeated", fd.FullName())
162 }
163 if err := o.unmarshalSingular(tval, fd, knownFields); !nerr.Merge(err) {
164 return err
165 }
166 if cardinality == pref.Required {
167 reqNums.Set(num)
168 }
169 seenNums.Set(num)
170 }
171 }
172
173 // Check for any missing required fields.
174 allReqNums := msgType.RequiredNumbers()
175 if reqNums.Len() != allReqNums.Len() {
176 for i := 0; i < allReqNums.Len(); i++ {
177 if num := allReqNums.Get(i); !reqNums.Has(uint64(num)) {
178 nerr.AppendRequiredNotSet(string(fieldDescs.ByNumber(num).FullName()))
179 }
180 }
181 }
182
183 return nerr.E
184}
185
186// unmarshalSingular unmarshals given text.Value into the non-repeated field.
187func (o UnmarshalOptions) unmarshalSingular(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
188 num := fd.Number()
189
190 var nerr errors.NonFatal
191 var val pref.Value
192 switch fd.Kind() {
193 case pref.MessageKind, pref.GroupKind:
194 if input.Type() != text.Message {
195 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
196 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800197 m := knownFields.NewMessage(num)
Herbie Ong800c9902018-12-06 15:28:53 -0800198 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
199 return err
200 }
201 val = pref.ValueOf(m)
202 default:
203 var err error
204 val, err = unmarshalScalar(input, fd)
205 if !nerr.Merge(err) {
206 return err
207 }
208 }
209 knownFields.Set(num, val)
210
211 return nerr.E
212}
213
214// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
215// call this for cardinality=repeated.
216func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
217 var items []text.Value
218 // If input is not a list, turn it into a list.
219 if input.Type() != text.List {
220 items = []text.Value{input}
221 } else {
222 items = input.List()
223 }
224
225 var nerr errors.NonFatal
226 num := fd.Number()
227 val := knownFields.Get(num)
228 if !fd.IsMap() {
229 if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
230 return err
231 }
232 } else {
233 if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
234 return err
235 }
236 }
237
238 return nerr.E
239}
240
241// unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
242// the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
243func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
244 const b32 = false
245 const b64 = true
246
247 switch kind := fd.Kind(); kind {
248 case pref.BoolKind:
249 if b, ok := input.Bool(); ok {
250 return pref.ValueOf(bool(b)), nil
251 }
252 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
253 if n, ok := input.Int(b32); ok {
254 return pref.ValueOf(int32(n)), nil
255 }
256 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
257 if n, ok := input.Int(b64); ok {
258 return pref.ValueOf(int64(n)), nil
259 }
260 case pref.Uint32Kind, pref.Fixed32Kind:
261 if n, ok := input.Uint(b32); ok {
262 return pref.ValueOf(uint32(n)), nil
263 }
264 case pref.Uint64Kind, pref.Fixed64Kind:
265 if n, ok := input.Uint(b64); ok {
266 return pref.ValueOf(uint64(n)), nil
267 }
268 case pref.FloatKind:
269 if n, ok := input.Float(b32); ok {
270 return pref.ValueOf(float32(n)), nil
271 }
272 case pref.DoubleKind:
273 if n, ok := input.Float(b64); ok {
274 return pref.ValueOf(float64(n)), nil
275 }
276 case pref.StringKind:
277 if input.Type() == text.String {
278 return pref.ValueOf(string(input.String())), nil
279 }
280 case pref.BytesKind:
281 if input.Type() == text.String {
282 return pref.ValueOf([]byte(input.String())), nil
283 }
284 case pref.EnumKind:
285 // If input is int32, use directly.
286 if n, ok := input.Int(b32); ok {
287 return pref.ValueOf(pref.EnumNumber(n)), nil
Herbie Ong66c365c2019-01-04 14:08:41 -0800288 }
289 if name, ok := input.Name(); ok {
290 // Lookup EnumNumber based on name.
291 if enumVal := fd.EnumType().Values().ByName(name); enumVal != nil {
292 return pref.ValueOf(enumVal.Number()), nil
Herbie Ong800c9902018-12-06 15:28:53 -0800293 }
294 }
295 default:
296 panic(fmt.Sprintf("invalid scalar kind %v", kind))
297 }
298
299 return pref.Value{}, errors.New("%v contains invalid scalar value: %v", fd.FullName(), input)
300}
301
302// unmarshalList unmarshals given []text.Value into given protoreflect.List.
303func (o UnmarshalOptions) unmarshalList(inputList []text.Value, fd pref.FieldDescriptor, list pref.List) error {
304 var nerr errors.NonFatal
305
306 switch fd.Kind() {
307 case pref.MessageKind, pref.GroupKind:
308 for _, input := range inputList {
309 if input.Type() != text.Message {
310 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
311 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800312 m := list.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800313 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
314 return err
315 }
316 list.Append(pref.ValueOf(m))
317 }
318 default:
319 for _, input := range inputList {
320 val, err := unmarshalScalar(input, fd)
321 if !nerr.Merge(err) {
322 return err
323 }
324 list.Append(val)
325 }
326 }
327
328 return nerr.E
329}
330
331// unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
332func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
333 var nerr errors.NonFatal
334 fields := fd.MessageType().Fields()
335 keyDesc := fields.ByNumber(1)
336 valDesc := fields.ByNumber(2)
337
338 // Determine ahead whether map entry is a scalar type or a message type in order to call the
339 // appropriate unmarshalMapValue func inside the for loop below.
Herbie Ong66c365c2019-01-04 14:08:41 -0800340 unmarshalMapValue := unmarshalMapScalarValue
Herbie Ong800c9902018-12-06 15:28:53 -0800341 switch valDesc.Kind() {
342 case pref.MessageKind, pref.GroupKind:
343 unmarshalMapValue = o.unmarshalMapMessageValue
344 }
345
346 for _, entry := range input {
347 if entry.Type() != text.Message {
348 return errors.New("%v contains invalid map entry: %v", fd.FullName(), entry)
349 }
350 tkey, tval, err := parseMapEntry(entry.Message(), fd.FullName())
351 if !nerr.Merge(err) {
352 return err
353 }
354 pkey, err := unmarshalMapKey(tkey, keyDesc)
355 if !nerr.Merge(err) {
356 return err
357 }
358 err = unmarshalMapValue(tval, pkey, valDesc, mmap)
359 if !nerr.Merge(err) {
360 return err
361 }
362 }
363
364 return nerr.E
365}
366
367// parseMapEntry parses [][2]text.Value for field names key and value, and return corresponding
368// field values. If there are duplicate field names, the value for the last field is returned. If
369// the field name does not exist, it will return the zero value of text.Value. It will return an
370// error if there are unknown field names.
371func parseMapEntry(mapEntry [][2]text.Value, name pref.FullName) (key text.Value, value text.Value, err error) {
372 for _, field := range mapEntry {
373 keyStr, ok := field[0].Name()
374 if ok {
375 switch keyStr {
376 case "key":
377 if key.Type() != 0 {
378 return key, value, errors.New("%v contains duplicate key field", name)
379 }
380 key = field[1]
381 case "value":
382 if value.Type() != 0 {
383 return key, value, errors.New("%v contains duplicate value field", name)
384 }
385 value = field[1]
386 default:
387 ok = false
388 }
389 }
390 if !ok {
391 // TODO: Do not return error if ignore unknown option is added and enabled.
392 return key, value, errors.New("%v contains unknown map entry name: %v", name, field[0])
393 }
394 }
395 return key, value, nil
396}
397
398// unmarshalMapKey converts given text.Value into a protoreflect.MapKey. A map key type is any
399// integral or string type.
400func unmarshalMapKey(input text.Value, fd pref.FieldDescriptor) (pref.MapKey, error) {
401 // If input is not set, use the zero value.
402 if input.Type() == 0 {
403 return fd.Default().MapKey(), nil
404 }
405
406 val, err := unmarshalScalar(input, fd)
407 if err != nil {
408 return pref.MapKey{}, errors.New("%v contains invalid key: %v", fd.FullName(), input)
409 }
410 return val.MapKey(), nil
411}
412
413// unmarshalMapMessageValue unmarshals given message-type text.Value into a protoreflect.Map for
414// the given MapKey.
415func (o UnmarshalOptions) unmarshalMapMessageValue(input text.Value, pkey pref.MapKey, _ pref.FieldDescriptor, mmap pref.Map) error {
416 var nerr errors.NonFatal
417 var value [][2]text.Value
418 if input.Type() != 0 {
419 value = input.Message()
420 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800421 m := mmap.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800422 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
423 return err
424 }
425 mmap.Set(pkey, pref.ValueOf(m))
426 return nerr.E
427}
428
429// unmarshalMapScalarValue unmarshals given scalar-type text.Value into a protoreflect.Map
430// for the given MapKey.
Herbie Ong66c365c2019-01-04 14:08:41 -0800431func unmarshalMapScalarValue(input text.Value, pkey pref.MapKey, fd pref.FieldDescriptor, mmap pref.Map) error {
Herbie Ong800c9902018-12-06 15:28:53 -0800432 var val pref.Value
433 if input.Type() == 0 {
434 val = fd.Default()
435 } else {
436 var err error
437 val, err = unmarshalScalar(input, fd)
438 if err != nil {
439 return err
440 }
441 }
442 mmap.Set(pkey, val)
443 return nil
444}
Herbie Ong66c365c2019-01-04 14:08:41 -0800445
446// isExpandedAny returns true if given [][2]text.Value may be an expanded Any that contains only one
447// field with key type of text.String type and value type of text.Message.
448func isExpandedAny(tmsg [][2]text.Value) bool {
449 if len(tmsg) != 1 {
450 return false
451 }
452
453 field := tmsg[0]
454 return field[0].Type() == text.String && field[1].Type() == text.Message
455}
456
457// unmarshalAny unmarshals an expanded Any textproto. This method assumes that the given
458// tfield has key type of text.String and value type of text.Message.
459func (o UnmarshalOptions) unmarshalAny(tfield [2]text.Value, knownFields pref.KnownFields) error {
460 var nerr errors.NonFatal
461
462 typeURL := tfield[0].String()
463 value := tfield[1].Message()
464
465 mt, err := o.Resolver.FindMessageByURL(typeURL)
466 if !nerr.Merge(err) {
467 return errors.New("unable to resolve message [%v]: %v", typeURL, err)
468 }
469 // Create new message for the embedded message type and unmarshal the
470 // value into it.
471 m := mt.New()
472 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
473 return err
474 }
475 // Serialize the embedded message and assign the resulting bytes to the value field.
476 // TODO: Switch to V2 marshal and enable deterministic option when ready.
477 var mv1 protoV1.Message
478 if mtmp, ok := m.(pvalue.Unwrapper); ok {
479 mv1 = mtmp.ProtoUnwrap().(protoV1.Message)
480 } else {
481 mv1 = m.Interface().(protoV1.Message)
482 }
483 b, err := protoV1.Marshal(mv1)
484 if !nerr.Merge(err) {
485 return err
486 }
487
488 knownFields.Set(pref.FieldNumber(1), pref.ValueOf(typeURL))
489 knownFields.Set(pref.FieldNumber(2), pref.ValueOf(b))
490
491 return nerr.E
492}