blob: b37668569cdc297c5fe80666cf7cf41771071db7 [file] [log] [blame]
Damien Neilba23aa52018-12-07 14:38:17 -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 proto
6
7import (
Damien Neile89e6242019-05-13 23:55:40 -07008 "google.golang.org/protobuf/internal/encoding/wire"
9 "google.golang.org/protobuf/internal/errors"
10 "google.golang.org/protobuf/internal/pragma"
11 "google.golang.org/protobuf/reflect/protoreflect"
12 "google.golang.org/protobuf/reflect/protoregistry"
13 "google.golang.org/protobuf/runtime/protoiface"
Damien Neilba23aa52018-12-07 14:38:17 -080014)
15
16// UnmarshalOptions configures the unmarshaler.
17//
18// Example usage:
19// err := UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, m)
20type UnmarshalOptions struct {
Damien Neil96c229a2019-04-03 12:17:24 -070021 // AllowPartial accepts input for messages that will result in missing
22 // required fields. If AllowPartial is false (the default), Unmarshal will
23 // return an error if there are any missing required fields.
24 AllowPartial bool
25
Damien Neilba23aa52018-12-07 14:38:17 -080026 // If DiscardUnknown is set, unknown fields are ignored.
27 DiscardUnknown bool
28
Joe Tsaidb38ddd2019-05-07 15:14:40 -070029 // Resolver is used for looking up types when unmarshaling extension fields.
30 // If nil, this defaults to using protoregistry.GlobalTypes.
Joe Tsai1c283042019-05-14 14:28:19 -070031 Resolver interface {
32 protoregistry.ExtensionTypeResolver
33 }
Joe Tsaidb38ddd2019-05-07 15:14:40 -070034
Damien Neilba23aa52018-12-07 14:38:17 -080035 pragma.NoUnkeyedLiterals
36}
37
Damien Neil0d3e8cc2019-04-01 13:31:55 -070038var _ = protoiface.UnmarshalOptions(UnmarshalOptions{})
39
Damien Neilba23aa52018-12-07 14:38:17 -080040// Unmarshal parses the wire-format message in b and places the result in m.
41func Unmarshal(b []byte, m Message) error {
42 return UnmarshalOptions{}.Unmarshal(b, m)
43}
44
45// Unmarshal parses the wire-format message in b and places the result in m.
46func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
Joe Tsaidb38ddd2019-05-07 15:14:40 -070047 if o.Resolver == nil {
48 o.Resolver = protoregistry.GlobalTypes
49 }
50
Damien Neilba23aa52018-12-07 14:38:17 -080051 // TODO: Reset m?
Damien Neil4686e232019-04-05 13:31:40 -070052 err := o.unmarshalMessageFast(b, m)
53 if err == errInternalNoFast {
54 err = o.unmarshalMessage(b, m.ProtoReflect())
55 }
56 var nerr errors.NonFatal
57 if !nerr.Merge(err) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070058 return err
59 }
Damien Neil4686e232019-04-05 13:31:40 -070060 if !o.AllowPartial {
61 nerr.Merge(IsInitialized(m))
62 }
63 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -080064}
65
Damien Neil0d3e8cc2019-04-01 13:31:55 -070066func (o UnmarshalOptions) unmarshalMessageFast(b []byte, m Message) error {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070067 methods := protoMethods(m)
68 if methods == nil || methods.Unmarshal == nil {
69 return errInternalNoFast
70 }
71 return methods.Unmarshal(b, m, protoiface.UnmarshalOptions(o))
72}
73
Damien Neilba23aa52018-12-07 14:38:17 -080074func (o UnmarshalOptions) unmarshalMessage(b []byte, m protoreflect.Message) error {
Joe Tsai0fc49f82019-05-01 12:29:25 -070075 messageDesc := m.Descriptor()
76 fieldDescs := messageDesc.Fields()
Damien Neilba23aa52018-12-07 14:38:17 -080077 knownFields := m.KnownFields()
78 unknownFields := m.UnknownFields()
Damien Neil96c229a2019-04-03 12:17:24 -070079 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -080080 for len(b) > 0 {
81 // Parse the tag (field number and wire type).
82 num, wtyp, tagLen := wire.ConsumeTag(b)
83 if tagLen < 0 {
84 return wire.ParseError(tagLen)
85 }
86
87 // Parse the field value.
Joe Tsai0fc49f82019-05-01 12:29:25 -070088 fieldDesc := fieldDescs.ByNumber(num)
89 if fieldDesc == nil {
90 extType := knownFields.ExtensionTypes().ByNumber(num)
91 if extType == nil && messageDesc.ExtensionRanges().Has(num) {
92 var err error
93 extType, err = o.Resolver.FindExtensionByNumber(messageDesc.FullName(), num)
Joe Tsaidb38ddd2019-05-07 15:14:40 -070094 if err != nil && err != protoregistry.NotFound {
95 return err
96 }
97 if extType != nil {
98 knownFields.ExtensionTypes().Register(extType)
Joe Tsaidb38ddd2019-05-07 15:14:40 -070099 }
100 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700101 if extType != nil {
102 fieldDesc = extType.Descriptor()
103 }
Damien Neild068d302018-12-17 14:06:08 -0800104 }
Damien Neilba23aa52018-12-07 14:38:17 -0800105 var err error
106 var valLen int
107 switch {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700108 case fieldDesc == nil:
Damien Neilba23aa52018-12-07 14:38:17 -0800109 err = errUnknown
Joe Tsaiac31a352019-05-13 14:32:56 -0700110 case fieldDesc.IsList():
Joe Tsai0fc49f82019-05-01 12:29:25 -0700111 valLen, err = o.unmarshalList(b[tagLen:], wtyp, num, knownFields.Get(num).List(), fieldDesc)
Joe Tsaiac31a352019-05-13 14:32:56 -0700112 case fieldDesc.IsMap():
Joe Tsai0fc49f82019-05-01 12:29:25 -0700113 valLen, err = o.unmarshalMap(b[tagLen:], wtyp, num, knownFields.Get(num).Map(), fieldDesc)
Joe Tsaiac31a352019-05-13 14:32:56 -0700114 default:
115 valLen, err = o.unmarshalScalarField(b[tagLen:], wtyp, num, knownFields, fieldDesc)
Damien Neilba23aa52018-12-07 14:38:17 -0800116 }
117 if err == errUnknown {
118 valLen = wire.ConsumeFieldValue(num, wtyp, b[tagLen:])
119 if valLen < 0 {
120 return wire.ParseError(valLen)
121 }
122 unknownFields.Set(num, append(unknownFields.Get(num), b[:tagLen+valLen]...))
Damien Neil96c229a2019-04-03 12:17:24 -0700123 } else if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800124 return err
125 }
126 b = b[tagLen+valLen:]
127 }
Damien Neil96c229a2019-04-03 12:17:24 -0700128 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800129}
130
131func (o UnmarshalOptions) unmarshalScalarField(b []byte, wtyp wire.Type, num wire.Number, knownFields protoreflect.KnownFields, field protoreflect.FieldDescriptor) (n int, err error) {
Damien Neilbc310b52019-04-11 11:46:55 -0700132 var nerr errors.NonFatal
133 v, n, err := o.unmarshalScalar(b, wtyp, num, field)
134 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800135 return 0, err
136 }
137 switch field.Kind() {
138 case protoreflect.GroupKind, protoreflect.MessageKind:
139 // Messages are merged with any existing message value,
140 // unless the message is part of a oneof.
141 //
142 // TODO: C++ merges into oneofs, while v1 does not.
143 // Evaluate which behavior to pick.
144 var m protoreflect.Message
Joe Tsaiac31a352019-05-13 14:32:56 -0700145 if knownFields.Has(num) && field.ContainingOneof() == nil {
Damien Neilba23aa52018-12-07 14:38:17 -0800146 m = knownFields.Get(num).Message()
147 } else {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800148 m = knownFields.NewMessage(num)
Damien Neilba23aa52018-12-07 14:38:17 -0800149 knownFields.Set(num, protoreflect.ValueOf(m))
150 }
Damien Neil96c229a2019-04-03 12:17:24 -0700151 // Pass up errors (fatal and otherwise).
Damien Neilbc310b52019-04-11 11:46:55 -0700152 if err := o.unmarshalMessage(v.Bytes(), m); !nerr.Merge(err) {
153 return n, err
154 }
Damien Neilba23aa52018-12-07 14:38:17 -0800155 default:
156 // Non-message scalars replace the previous value.
157 knownFields.Set(num, v)
158 }
Damien Neilbc310b52019-04-11 11:46:55 -0700159 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800160}
161
162func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp wire.Type, num wire.Number, mapv protoreflect.Map, field protoreflect.FieldDescriptor) (n int, err error) {
163 if wtyp != wire.BytesType {
164 return 0, errUnknown
165 }
166 b, n = wire.ConsumeBytes(b)
167 if n < 0 {
168 return 0, wire.ParseError(n)
169 }
170 var (
Joe Tsaiac31a352019-05-13 14:32:56 -0700171 keyField = field.MapKey()
172 valField = field.MapValue()
Damien Neilba23aa52018-12-07 14:38:17 -0800173 key protoreflect.Value
174 val protoreflect.Value
175 haveKey bool
176 haveVal bool
177 )
178 switch valField.Kind() {
179 case protoreflect.GroupKind, protoreflect.MessageKind:
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800180 val = protoreflect.ValueOf(mapv.NewMessage())
Damien Neilba23aa52018-12-07 14:38:17 -0800181 }
182 // Map entries are represented as a two-element message with fields
183 // containing the key and value.
Damien Neil96c229a2019-04-03 12:17:24 -0700184 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -0800185 for len(b) > 0 {
186 num, wtyp, n := wire.ConsumeTag(b)
187 if n < 0 {
188 return 0, wire.ParseError(n)
189 }
190 b = b[n:]
191 err = errUnknown
192 switch num {
193 case 1:
Damien Neilbc310b52019-04-11 11:46:55 -0700194 key, n, err = o.unmarshalScalar(b, wtyp, num, keyField)
195 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800196 break
197 }
Damien Neilbc310b52019-04-11 11:46:55 -0700198 err = nil
Damien Neilba23aa52018-12-07 14:38:17 -0800199 haveKey = true
200 case 2:
201 var v protoreflect.Value
Damien Neilbc310b52019-04-11 11:46:55 -0700202 v, n, err = o.unmarshalScalar(b, wtyp, num, valField)
203 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800204 break
205 }
Damien Neilbc310b52019-04-11 11:46:55 -0700206 err = nil
Damien Neilba23aa52018-12-07 14:38:17 -0800207 switch valField.Kind() {
208 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neil96c229a2019-04-03 12:17:24 -0700209 if err := o.unmarshalMessage(v.Bytes(), val.Message()); !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800210 return 0, err
211 }
212 default:
213 val = v
214 }
215 haveVal = true
216 }
217 if err == errUnknown {
218 n = wire.ConsumeFieldValue(num, wtyp, b)
219 if n < 0 {
220 return 0, wire.ParseError(n)
221 }
Damien Neilbc310b52019-04-11 11:46:55 -0700222 } else if err != nil {
Damien Neilba23aa52018-12-07 14:38:17 -0800223 return 0, err
224 }
225 b = b[n:]
226 }
227 // Every map entry should have entries for key and value, but this is not strictly required.
228 if !haveKey {
229 key = keyField.Default()
230 }
231 if !haveVal {
232 switch valField.Kind() {
233 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neilba23aa52018-12-07 14:38:17 -0800234 default:
235 val = valField.Default()
236 }
237 }
238 mapv.Set(key.MapKey(), val)
Damien Neil96c229a2019-04-03 12:17:24 -0700239 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800240}
241
242// errUnknown is used internally to indicate fields which should be added
243// to the unknown field set of a message. It is never returned from an exported
244// function.
Damien Neil96c229a2019-04-03 12:17:24 -0700245var errUnknown = errors.New("BUG: internal error (unknown)")