blob: 51b2068f5a9d8c99b84cdea4bac0136383381f7f [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 Neilba23aa52018-12-07 14:38:17 -08008 "github.com/golang/protobuf/v2/internal/encoding/wire"
Damien Neil96c229a2019-04-03 12:17:24 -07009 "github.com/golang/protobuf/v2/internal/errors"
Damien Neilba23aa52018-12-07 14:38:17 -080010 "github.com/golang/protobuf/v2/internal/pragma"
11 "github.com/golang/protobuf/v2/reflect/protoreflect"
Joe Tsaidb38ddd2019-05-07 15:14:40 -070012 "github.com/golang/protobuf/v2/reflect/protoregistry"
Damien Neil0d3e8cc2019-04-01 13:31:55 -070013 "github.com/golang/protobuf/v2/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.
31 Resolver *protoregistry.Types
32
Damien Neilba23aa52018-12-07 14:38:17 -080033 pragma.NoUnkeyedLiterals
34}
35
Damien Neil0d3e8cc2019-04-01 13:31:55 -070036var _ = protoiface.UnmarshalOptions(UnmarshalOptions{})
37
Damien Neilba23aa52018-12-07 14:38:17 -080038// Unmarshal parses the wire-format message in b and places the result in m.
39func Unmarshal(b []byte, m Message) error {
40 return UnmarshalOptions{}.Unmarshal(b, m)
41}
42
43// Unmarshal parses the wire-format message in b and places the result in m.
44func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
Joe Tsaidb38ddd2019-05-07 15:14:40 -070045 if o.Resolver == nil {
46 o.Resolver = protoregistry.GlobalTypes
47 }
48
Damien Neilba23aa52018-12-07 14:38:17 -080049 // TODO: Reset m?
Damien Neil4686e232019-04-05 13:31:40 -070050 err := o.unmarshalMessageFast(b, m)
51 if err == errInternalNoFast {
52 err = o.unmarshalMessage(b, m.ProtoReflect())
53 }
54 var nerr errors.NonFatal
55 if !nerr.Merge(err) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070056 return err
57 }
Damien Neil4686e232019-04-05 13:31:40 -070058 if !o.AllowPartial {
59 nerr.Merge(IsInitialized(m))
60 }
61 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -080062}
63
Damien Neil0d3e8cc2019-04-01 13:31:55 -070064func (o UnmarshalOptions) unmarshalMessageFast(b []byte, m Message) error {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070065 methods := protoMethods(m)
66 if methods == nil || methods.Unmarshal == nil {
67 return errInternalNoFast
68 }
69 return methods.Unmarshal(b, m, protoiface.UnmarshalOptions(o))
70}
71
Damien Neilba23aa52018-12-07 14:38:17 -080072func (o UnmarshalOptions) unmarshalMessage(b []byte, m protoreflect.Message) error {
Joe Tsai0fc49f82019-05-01 12:29:25 -070073 messageDesc := m.Descriptor()
74 fieldDescs := messageDesc.Fields()
Damien Neilba23aa52018-12-07 14:38:17 -080075 knownFields := m.KnownFields()
76 unknownFields := m.UnknownFields()
Damien Neil96c229a2019-04-03 12:17:24 -070077 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -080078 for len(b) > 0 {
79 // Parse the tag (field number and wire type).
80 num, wtyp, tagLen := wire.ConsumeTag(b)
81 if tagLen < 0 {
82 return wire.ParseError(tagLen)
83 }
84
85 // Parse the field value.
Joe Tsai0fc49f82019-05-01 12:29:25 -070086 fieldDesc := fieldDescs.ByNumber(num)
87 if fieldDesc == nil {
88 extType := knownFields.ExtensionTypes().ByNumber(num)
89 if extType == nil && messageDesc.ExtensionRanges().Has(num) {
90 var err error
91 extType, err = o.Resolver.FindExtensionByNumber(messageDesc.FullName(), num)
Joe Tsaidb38ddd2019-05-07 15:14:40 -070092 if err != nil && err != protoregistry.NotFound {
93 return err
94 }
95 if extType != nil {
96 knownFields.ExtensionTypes().Register(extType)
Joe Tsaidb38ddd2019-05-07 15:14:40 -070097 }
98 }
Joe Tsai0fc49f82019-05-01 12:29:25 -070099 if extType != nil {
100 fieldDesc = extType.Descriptor()
101 }
Damien Neild068d302018-12-17 14:06:08 -0800102 }
Damien Neilba23aa52018-12-07 14:38:17 -0800103 var err error
104 var valLen int
105 switch {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700106 case fieldDesc == nil:
Damien Neilba23aa52018-12-07 14:38:17 -0800107 err = errUnknown
Joe Tsai0fc49f82019-05-01 12:29:25 -0700108 case fieldDesc.Cardinality() != protoreflect.Repeated:
109 valLen, err = o.unmarshalScalarField(b[tagLen:], wtyp, num, knownFields, fieldDesc)
110 case !fieldDesc.IsMap():
111 valLen, err = o.unmarshalList(b[tagLen:], wtyp, num, knownFields.Get(num).List(), fieldDesc)
Damien Neilba23aa52018-12-07 14:38:17 -0800112 default:
Joe Tsai0fc49f82019-05-01 12:29:25 -0700113 valLen, err = o.unmarshalMap(b[tagLen:], wtyp, num, knownFields.Get(num).Map(), fieldDesc)
Damien Neilba23aa52018-12-07 14:38:17 -0800114 }
115 if err == errUnknown {
116 valLen = wire.ConsumeFieldValue(num, wtyp, b[tagLen:])
117 if valLen < 0 {
118 return wire.ParseError(valLen)
119 }
120 unknownFields.Set(num, append(unknownFields.Get(num), b[:tagLen+valLen]...))
Damien Neil96c229a2019-04-03 12:17:24 -0700121 } else if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800122 return err
123 }
124 b = b[tagLen+valLen:]
125 }
Damien Neil96c229a2019-04-03 12:17:24 -0700126 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800127}
128
129func (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 -0700130 var nerr errors.NonFatal
131 v, n, err := o.unmarshalScalar(b, wtyp, num, field)
132 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800133 return 0, err
134 }
135 switch field.Kind() {
136 case protoreflect.GroupKind, protoreflect.MessageKind:
137 // Messages are merged with any existing message value,
138 // unless the message is part of a oneof.
139 //
140 // TODO: C++ merges into oneofs, while v1 does not.
141 // Evaluate which behavior to pick.
142 var m protoreflect.Message
Joe Tsaid24bc722019-04-15 23:39:09 -0700143 if knownFields.Has(num) && field.Oneof() == nil {
Damien Neilba23aa52018-12-07 14:38:17 -0800144 m = knownFields.Get(num).Message()
145 } else {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800146 m = knownFields.NewMessage(num)
Damien Neilba23aa52018-12-07 14:38:17 -0800147 knownFields.Set(num, protoreflect.ValueOf(m))
148 }
Damien Neil96c229a2019-04-03 12:17:24 -0700149 // Pass up errors (fatal and otherwise).
Damien Neilbc310b52019-04-11 11:46:55 -0700150 if err := o.unmarshalMessage(v.Bytes(), m); !nerr.Merge(err) {
151 return n, err
152 }
Damien Neilba23aa52018-12-07 14:38:17 -0800153 default:
154 // Non-message scalars replace the previous value.
155 knownFields.Set(num, v)
156 }
Damien Neilbc310b52019-04-11 11:46:55 -0700157 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800158}
159
160func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp wire.Type, num wire.Number, mapv protoreflect.Map, field protoreflect.FieldDescriptor) (n int, err error) {
161 if wtyp != wire.BytesType {
162 return 0, errUnknown
163 }
164 b, n = wire.ConsumeBytes(b)
165 if n < 0 {
166 return 0, wire.ParseError(n)
167 }
168 var (
Joe Tsaid24bc722019-04-15 23:39:09 -0700169 keyField = field.Message().Fields().ByNumber(1)
170 valField = field.Message().Fields().ByNumber(2)
Damien Neilba23aa52018-12-07 14:38:17 -0800171 key protoreflect.Value
172 val protoreflect.Value
173 haveKey bool
174 haveVal bool
175 )
176 switch valField.Kind() {
177 case protoreflect.GroupKind, protoreflect.MessageKind:
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800178 val = protoreflect.ValueOf(mapv.NewMessage())
Damien Neilba23aa52018-12-07 14:38:17 -0800179 }
180 // Map entries are represented as a two-element message with fields
181 // containing the key and value.
Damien Neil96c229a2019-04-03 12:17:24 -0700182 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -0800183 for len(b) > 0 {
184 num, wtyp, n := wire.ConsumeTag(b)
185 if n < 0 {
186 return 0, wire.ParseError(n)
187 }
188 b = b[n:]
189 err = errUnknown
190 switch num {
191 case 1:
Damien Neilbc310b52019-04-11 11:46:55 -0700192 key, n, err = o.unmarshalScalar(b, wtyp, num, keyField)
193 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800194 break
195 }
Damien Neilbc310b52019-04-11 11:46:55 -0700196 err = nil
Damien Neilba23aa52018-12-07 14:38:17 -0800197 haveKey = true
198 case 2:
199 var v protoreflect.Value
Damien Neilbc310b52019-04-11 11:46:55 -0700200 v, n, err = o.unmarshalScalar(b, wtyp, num, valField)
201 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800202 break
203 }
Damien Neilbc310b52019-04-11 11:46:55 -0700204 err = nil
Damien Neilba23aa52018-12-07 14:38:17 -0800205 switch valField.Kind() {
206 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neil96c229a2019-04-03 12:17:24 -0700207 if err := o.unmarshalMessage(v.Bytes(), val.Message()); !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800208 return 0, err
209 }
210 default:
211 val = v
212 }
213 haveVal = true
214 }
215 if err == errUnknown {
216 n = wire.ConsumeFieldValue(num, wtyp, b)
217 if n < 0 {
218 return 0, wire.ParseError(n)
219 }
Damien Neilbc310b52019-04-11 11:46:55 -0700220 } else if err != nil {
Damien Neilba23aa52018-12-07 14:38:17 -0800221 return 0, err
222 }
223 b = b[n:]
224 }
225 // Every map entry should have entries for key and value, but this is not strictly required.
226 if !haveKey {
227 key = keyField.Default()
228 }
229 if !haveVal {
230 switch valField.Kind() {
231 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neilba23aa52018-12-07 14:38:17 -0800232 default:
233 val = valField.Default()
234 }
235 }
236 mapv.Set(key.MapKey(), val)
Damien Neil96c229a2019-04-03 12:17:24 -0700237 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800238}
239
240// errUnknown is used internally to indicate fields which should be added
241// to the unknown field set of a message. It is never returned from an exported
242// function.
Damien Neil96c229a2019-04-03 12:17:24 -0700243var errUnknown = errors.New("BUG: internal error (unknown)")