blob: f7b10ad788f76d5fad92a38b1d310581a3cd6a37 [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.
21// TODO: may want to describe when Unmarshal returns error.
22func Unmarshal(m proto.Message, b []byte) error {
23 return UnmarshalOptions{}.Unmarshal(m, b)
24}
25
26// UnmarshalOptions is a configurable textproto format parser.
27type UnmarshalOptions struct {
28 pragma.NoUnkeyedLiterals
Herbie Ongc525c972018-12-18 18:04:31 -080029
30 // Resolver is the registry used for type lookups when unmarshaling extensions
31 // and processing Any. If Resolver is not set, unmarshaling will default to
32 // using protoregistry.GlobalTypes.
33 Resolver *protoregistry.Types
Herbie Ong800c9902018-12-06 15:28:53 -080034}
35
36// Unmarshal reads the given []byte and populates the given proto.Message using options in
37// UnmarshalOptions object.
38func (o UnmarshalOptions) Unmarshal(m proto.Message, b []byte) error {
39 var nerr errors.NonFatal
40
41 mr := m.ProtoReflect()
42 // Clear all fields before populating it.
43 // TODO: Determine if this needs to be consistent with jsonpb and binary unmarshal where
44 // behavior is to merge values into existing message. If decision is to not clear the fields
45 // ahead, code will need to be updated properly when merging nested messages.
46 resetMessage(mr)
47
48 // Parse into text.Value of message type.
49 val, err := text.Unmarshal(b)
50 if !nerr.Merge(err) {
51 return err
52 }
53
Herbie Ongc525c972018-12-18 18:04:31 -080054 if o.Resolver == nil {
55 o.Resolver = protoregistry.GlobalTypes
56 }
Herbie Ong800c9902018-12-06 15:28:53 -080057 err = o.unmarshalMessage(val.Message(), mr)
58 if !nerr.Merge(err) {
59 return err
60 }
61
62 return nerr.E
63}
64
65// resetMessage clears all fields of given protoreflect.Message.
66// TODO: This should go into the proto package.
67func resetMessage(m pref.Message) {
68 knownFields := m.KnownFields()
69 knownFields.Range(func(num pref.FieldNumber, _ pref.Value) bool {
70 knownFields.Clear(num)
71 return true
72 })
73 unknownFields := m.UnknownFields()
74 unknownFields.Range(func(num pref.FieldNumber, _ pref.RawFields) bool {
75 unknownFields.Set(num, nil)
76 return true
77 })
Herbie Ong800c9902018-12-06 15:28:53 -080078 extTypes := knownFields.ExtensionTypes()
79 extTypes.Range(func(xt pref.ExtensionType) bool {
80 extTypes.Remove(xt)
81 return true
82 })
83}
84
85// unmarshalMessage unmarshals a [][2]text.Value message into the given protoreflect.Message.
86func (o UnmarshalOptions) unmarshalMessage(tmsg [][2]text.Value, m pref.Message) error {
87 var nerr errors.NonFatal
88
89 msgType := m.Type()
90 fieldDescs := msgType.Fields()
Herbie Ong7c624e22018-12-13 14:41:22 -080091 reservedNames := msgType.ReservedNames()
Herbie Ong800c9902018-12-06 15:28:53 -080092 knownFields := m.KnownFields()
Herbie Ongc525c972018-12-18 18:04:31 -080093 xtTypes := knownFields.ExtensionTypes()
Herbie Ong800c9902018-12-06 15:28:53 -080094 var reqNums set.Ints
95 var seenNums set.Ints
96
97 for _, tfield := range tmsg {
98 tkey := tfield[0]
99 tval := tfield[1]
100
101 var fd pref.FieldDescriptor
Herbie Ongc525c972018-12-18 18:04:31 -0800102 var name pref.Name
103 switch tkey.Type() {
104 case text.Name:
105 name, _ = tkey.Name()
Herbie Ong800c9902018-12-06 15:28:53 -0800106 fd = fieldDescs.ByName(name)
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800107 if fd == nil {
108 // Check if this is a group field.
109 fd = fieldDescs.ByName(pref.Name(strings.ToLower(string(name))))
110 }
Herbie Ongc525c972018-12-18 18:04:31 -0800111 case text.String:
112 // TODO: Handle Any expansions here as well.
113
114 // Handle extensions. Extensions have to be registered first in the message's
115 // ExtensionTypes before setting a value to it.
116 xtName := pref.FullName(tkey.String())
117 // Check first if it is already registered. This is the case for repeated fields.
118 xt := xtTypes.ByName(xtName)
119 if xt == nil {
120 var err error
121 xt, err = o.Resolver.FindExtensionByName(xtName)
122 if err != nil && err != protoregistry.NotFound {
123 return err
124 }
125 if xt != nil {
126 xtTypes.Register(xt)
127 }
128 }
129 fd = xt
Herbie Ong800c9902018-12-06 15:28:53 -0800130 }
Herbie Ongc525c972018-12-18 18:04:31 -0800131
Herbie Ong800c9902018-12-06 15:28:53 -0800132 if fd == nil {
Herbie Ong7c624e22018-12-13 14:41:22 -0800133 // Ignore reserved names.
134 if reservedNames.Has(name) {
135 continue
136 }
Herbie Ong800c9902018-12-06 15:28:53 -0800137 // TODO: Can provide option to ignore unknown message fields.
Herbie Ong800c9902018-12-06 15:28:53 -0800138 return errors.New("%v contains unknown field: %v", msgType.FullName(), tkey)
139 }
140
141 if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
142 // Map or list fields have cardinality of repeated.
143 if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
144 return err
145 }
146 } else {
147 // Required or optional fields.
148 num := uint64(fd.Number())
149 if seenNums.Has(num) {
150 return errors.New("non-repeated field %v is repeated", fd.FullName())
151 }
152 if err := o.unmarshalSingular(tval, fd, knownFields); !nerr.Merge(err) {
153 return err
154 }
155 if cardinality == pref.Required {
156 reqNums.Set(num)
157 }
158 seenNums.Set(num)
159 }
160 }
161
162 // Check for any missing required fields.
163 allReqNums := msgType.RequiredNumbers()
164 if reqNums.Len() != allReqNums.Len() {
165 for i := 0; i < allReqNums.Len(); i++ {
166 if num := allReqNums.Get(i); !reqNums.Has(uint64(num)) {
167 nerr.AppendRequiredNotSet(string(fieldDescs.ByNumber(num).FullName()))
168 }
169 }
170 }
171
172 return nerr.E
173}
174
175// unmarshalSingular unmarshals given text.Value into the non-repeated field.
176func (o UnmarshalOptions) unmarshalSingular(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
177 num := fd.Number()
178
179 var nerr errors.NonFatal
180 var val pref.Value
181 switch fd.Kind() {
182 case pref.MessageKind, pref.GroupKind:
183 if input.Type() != text.Message {
184 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
185 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800186 m := knownFields.NewMessage(num)
Herbie Ong800c9902018-12-06 15:28:53 -0800187 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
188 return err
189 }
190 val = pref.ValueOf(m)
191 default:
192 var err error
193 val, err = unmarshalScalar(input, fd)
194 if !nerr.Merge(err) {
195 return err
196 }
197 }
198 knownFields.Set(num, val)
199
200 return nerr.E
201}
202
203// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
204// call this for cardinality=repeated.
205func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
206 var items []text.Value
207 // If input is not a list, turn it into a list.
208 if input.Type() != text.List {
209 items = []text.Value{input}
210 } else {
211 items = input.List()
212 }
213
214 var nerr errors.NonFatal
215 num := fd.Number()
216 val := knownFields.Get(num)
217 if !fd.IsMap() {
218 if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
219 return err
220 }
221 } else {
222 if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
223 return err
224 }
225 }
226
227 return nerr.E
228}
229
230// unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
231// the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
232func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
233 const b32 = false
234 const b64 = true
235
236 switch kind := fd.Kind(); kind {
237 case pref.BoolKind:
238 if b, ok := input.Bool(); ok {
239 return pref.ValueOf(bool(b)), nil
240 }
241 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
242 if n, ok := input.Int(b32); ok {
243 return pref.ValueOf(int32(n)), nil
244 }
245 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
246 if n, ok := input.Int(b64); ok {
247 return pref.ValueOf(int64(n)), nil
248 }
249 case pref.Uint32Kind, pref.Fixed32Kind:
250 if n, ok := input.Uint(b32); ok {
251 return pref.ValueOf(uint32(n)), nil
252 }
253 case pref.Uint64Kind, pref.Fixed64Kind:
254 if n, ok := input.Uint(b64); ok {
255 return pref.ValueOf(uint64(n)), nil
256 }
257 case pref.FloatKind:
258 if n, ok := input.Float(b32); ok {
259 return pref.ValueOf(float32(n)), nil
260 }
261 case pref.DoubleKind:
262 if n, ok := input.Float(b64); ok {
263 return pref.ValueOf(float64(n)), nil
264 }
265 case pref.StringKind:
266 if input.Type() == text.String {
267 return pref.ValueOf(string(input.String())), nil
268 }
269 case pref.BytesKind:
270 if input.Type() == text.String {
271 return pref.ValueOf([]byte(input.String())), nil
272 }
273 case pref.EnumKind:
274 // If input is int32, use directly.
275 if n, ok := input.Int(b32); ok {
276 return pref.ValueOf(pref.EnumNumber(n)), nil
277 } else {
278 if name, ok := input.Name(); ok {
279 // Lookup EnumNumber based on name.
280 if enumVal := fd.EnumType().Values().ByName(name); enumVal != nil {
281 return pref.ValueOf(enumVal.Number()), nil
282 }
283 }
284 }
285 default:
286 panic(fmt.Sprintf("invalid scalar kind %v", kind))
287 }
288
289 return pref.Value{}, errors.New("%v contains invalid scalar value: %v", fd.FullName(), input)
290}
291
292// unmarshalList unmarshals given []text.Value into given protoreflect.List.
293func (o UnmarshalOptions) unmarshalList(inputList []text.Value, fd pref.FieldDescriptor, list pref.List) error {
294 var nerr errors.NonFatal
295
296 switch fd.Kind() {
297 case pref.MessageKind, pref.GroupKind:
298 for _, input := range inputList {
299 if input.Type() != text.Message {
300 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
301 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800302 m := list.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800303 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
304 return err
305 }
306 list.Append(pref.ValueOf(m))
307 }
308 default:
309 for _, input := range inputList {
310 val, err := unmarshalScalar(input, fd)
311 if !nerr.Merge(err) {
312 return err
313 }
314 list.Append(val)
315 }
316 }
317
318 return nerr.E
319}
320
321// unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
322func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
323 var nerr errors.NonFatal
324 fields := fd.MessageType().Fields()
325 keyDesc := fields.ByNumber(1)
326 valDesc := fields.ByNumber(2)
327
328 // Determine ahead whether map entry is a scalar type or a message type in order to call the
329 // appropriate unmarshalMapValue func inside the for loop below.
330 unmarshalMapValue := o.unmarshalMapScalarValue
331 switch valDesc.Kind() {
332 case pref.MessageKind, pref.GroupKind:
333 unmarshalMapValue = o.unmarshalMapMessageValue
334 }
335
336 for _, entry := range input {
337 if entry.Type() != text.Message {
338 return errors.New("%v contains invalid map entry: %v", fd.FullName(), entry)
339 }
340 tkey, tval, err := parseMapEntry(entry.Message(), fd.FullName())
341 if !nerr.Merge(err) {
342 return err
343 }
344 pkey, err := unmarshalMapKey(tkey, keyDesc)
345 if !nerr.Merge(err) {
346 return err
347 }
348 err = unmarshalMapValue(tval, pkey, valDesc, mmap)
349 if !nerr.Merge(err) {
350 return err
351 }
352 }
353
354 return nerr.E
355}
356
357// parseMapEntry parses [][2]text.Value for field names key and value, and return corresponding
358// field values. If there are duplicate field names, the value for the last field is returned. If
359// the field name does not exist, it will return the zero value of text.Value. It will return an
360// error if there are unknown field names.
361func parseMapEntry(mapEntry [][2]text.Value, name pref.FullName) (key text.Value, value text.Value, err error) {
362 for _, field := range mapEntry {
363 keyStr, ok := field[0].Name()
364 if ok {
365 switch keyStr {
366 case "key":
367 if key.Type() != 0 {
368 return key, value, errors.New("%v contains duplicate key field", name)
369 }
370 key = field[1]
371 case "value":
372 if value.Type() != 0 {
373 return key, value, errors.New("%v contains duplicate value field", name)
374 }
375 value = field[1]
376 default:
377 ok = false
378 }
379 }
380 if !ok {
381 // TODO: Do not return error if ignore unknown option is added and enabled.
382 return key, value, errors.New("%v contains unknown map entry name: %v", name, field[0])
383 }
384 }
385 return key, value, nil
386}
387
388// unmarshalMapKey converts given text.Value into a protoreflect.MapKey. A map key type is any
389// integral or string type.
390func unmarshalMapKey(input text.Value, fd pref.FieldDescriptor) (pref.MapKey, error) {
391 // If input is not set, use the zero value.
392 if input.Type() == 0 {
393 return fd.Default().MapKey(), nil
394 }
395
396 val, err := unmarshalScalar(input, fd)
397 if err != nil {
398 return pref.MapKey{}, errors.New("%v contains invalid key: %v", fd.FullName(), input)
399 }
400 return val.MapKey(), nil
401}
402
403// unmarshalMapMessageValue unmarshals given message-type text.Value into a protoreflect.Map for
404// the given MapKey.
405func (o UnmarshalOptions) unmarshalMapMessageValue(input text.Value, pkey pref.MapKey, _ pref.FieldDescriptor, mmap pref.Map) error {
406 var nerr errors.NonFatal
407 var value [][2]text.Value
408 if input.Type() != 0 {
409 value = input.Message()
410 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800411 m := mmap.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800412 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
413 return err
414 }
415 mmap.Set(pkey, pref.ValueOf(m))
416 return nerr.E
417}
418
419// unmarshalMapScalarValue unmarshals given scalar-type text.Value into a protoreflect.Map
420// for the given MapKey.
421func (o UnmarshalOptions) unmarshalMapScalarValue(input text.Value, pkey pref.MapKey, fd pref.FieldDescriptor, mmap pref.Map) error {
422 var val pref.Value
423 if input.Type() == 0 {
424 val = fd.Default()
425 } else {
426 var err error
427 val, err = unmarshalScalar(input, fd)
428 if err != nil {
429 return err
430 }
431 }
432 mmap.Set(pkey, val)
433 return nil
434}