blob: fa6d4432dc667ecb26e09a71d7a8427164ff1d75 [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 {
73 messageType := m.Type()
74 fieldTypes := messageType.Fields()
75 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.
86 fieldType := fieldTypes.ByNumber(num)
Damien Neild068d302018-12-17 14:06:08 -080087 if fieldType == nil {
88 fieldType = knownFields.ExtensionTypes().ByNumber(num)
Joe Tsaidb38ddd2019-05-07 15:14:40 -070089 if fieldType == nil && messageType.ExtensionRanges().Has(num) {
90 extType, err := o.Resolver.FindExtensionByNumber(messageType.FullName(), num)
91 if err != nil && err != protoregistry.NotFound {
92 return err
93 }
94 if extType != nil {
95 knownFields.ExtensionTypes().Register(extType)
96 fieldType = extType
97 }
98 }
Damien Neild068d302018-12-17 14:06:08 -080099 }
Damien Neilba23aa52018-12-07 14:38:17 -0800100 var err error
101 var valLen int
102 switch {
103 case fieldType == nil:
104 err = errUnknown
105 case fieldType.Cardinality() != protoreflect.Repeated:
106 valLen, err = o.unmarshalScalarField(b[tagLen:], wtyp, num, knownFields, fieldType)
107 case !fieldType.IsMap():
Damien Neilbc310b52019-04-11 11:46:55 -0700108 valLen, err = o.unmarshalList(b[tagLen:], wtyp, num, knownFields.Get(num).List(), fieldType)
Damien Neilba23aa52018-12-07 14:38:17 -0800109 default:
110 valLen, err = o.unmarshalMap(b[tagLen:], wtyp, num, knownFields.Get(num).Map(), fieldType)
111 }
112 if err == errUnknown {
113 valLen = wire.ConsumeFieldValue(num, wtyp, b[tagLen:])
114 if valLen < 0 {
115 return wire.ParseError(valLen)
116 }
117 unknownFields.Set(num, append(unknownFields.Get(num), b[:tagLen+valLen]...))
Damien Neil96c229a2019-04-03 12:17:24 -0700118 } else if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800119 return err
120 }
121 b = b[tagLen+valLen:]
122 }
Damien Neil96c229a2019-04-03 12:17:24 -0700123 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800124}
125
126func (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 -0700127 var nerr errors.NonFatal
128 v, n, err := o.unmarshalScalar(b, wtyp, num, field)
129 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800130 return 0, err
131 }
132 switch field.Kind() {
133 case protoreflect.GroupKind, protoreflect.MessageKind:
134 // Messages are merged with any existing message value,
135 // unless the message is part of a oneof.
136 //
137 // TODO: C++ merges into oneofs, while v1 does not.
138 // Evaluate which behavior to pick.
139 var m protoreflect.Message
Joe Tsaid24bc722019-04-15 23:39:09 -0700140 if knownFields.Has(num) && field.Oneof() == nil {
Damien Neilba23aa52018-12-07 14:38:17 -0800141 m = knownFields.Get(num).Message()
142 } else {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800143 m = knownFields.NewMessage(num)
Damien Neilba23aa52018-12-07 14:38:17 -0800144 knownFields.Set(num, protoreflect.ValueOf(m))
145 }
Damien Neil96c229a2019-04-03 12:17:24 -0700146 // Pass up errors (fatal and otherwise).
Damien Neilbc310b52019-04-11 11:46:55 -0700147 if err := o.unmarshalMessage(v.Bytes(), m); !nerr.Merge(err) {
148 return n, err
149 }
Damien Neilba23aa52018-12-07 14:38:17 -0800150 default:
151 // Non-message scalars replace the previous value.
152 knownFields.Set(num, v)
153 }
Damien Neilbc310b52019-04-11 11:46:55 -0700154 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800155}
156
157func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp wire.Type, num wire.Number, mapv protoreflect.Map, field protoreflect.FieldDescriptor) (n int, err error) {
158 if wtyp != wire.BytesType {
159 return 0, errUnknown
160 }
161 b, n = wire.ConsumeBytes(b)
162 if n < 0 {
163 return 0, wire.ParseError(n)
164 }
165 var (
Joe Tsaid24bc722019-04-15 23:39:09 -0700166 keyField = field.Message().Fields().ByNumber(1)
167 valField = field.Message().Fields().ByNumber(2)
Damien Neilba23aa52018-12-07 14:38:17 -0800168 key protoreflect.Value
169 val protoreflect.Value
170 haveKey bool
171 haveVal bool
172 )
173 switch valField.Kind() {
174 case protoreflect.GroupKind, protoreflect.MessageKind:
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800175 val = protoreflect.ValueOf(mapv.NewMessage())
Damien Neilba23aa52018-12-07 14:38:17 -0800176 }
177 // Map entries are represented as a two-element message with fields
178 // containing the key and value.
Damien Neil96c229a2019-04-03 12:17:24 -0700179 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -0800180 for len(b) > 0 {
181 num, wtyp, n := wire.ConsumeTag(b)
182 if n < 0 {
183 return 0, wire.ParseError(n)
184 }
185 b = b[n:]
186 err = errUnknown
187 switch num {
188 case 1:
Damien Neilbc310b52019-04-11 11:46:55 -0700189 key, n, err = o.unmarshalScalar(b, wtyp, num, keyField)
190 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800191 break
192 }
Damien Neilbc310b52019-04-11 11:46:55 -0700193 err = nil
Damien Neilba23aa52018-12-07 14:38:17 -0800194 haveKey = true
195 case 2:
196 var v protoreflect.Value
Damien Neilbc310b52019-04-11 11:46:55 -0700197 v, n, err = o.unmarshalScalar(b, wtyp, num, valField)
198 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800199 break
200 }
Damien Neilbc310b52019-04-11 11:46:55 -0700201 err = nil
Damien Neilba23aa52018-12-07 14:38:17 -0800202 switch valField.Kind() {
203 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neil96c229a2019-04-03 12:17:24 -0700204 if err := o.unmarshalMessage(v.Bytes(), val.Message()); !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800205 return 0, err
206 }
207 default:
208 val = v
209 }
210 haveVal = true
211 }
212 if err == errUnknown {
213 n = wire.ConsumeFieldValue(num, wtyp, b)
214 if n < 0 {
215 return 0, wire.ParseError(n)
216 }
Damien Neilbc310b52019-04-11 11:46:55 -0700217 } else if err != nil {
Damien Neilba23aa52018-12-07 14:38:17 -0800218 return 0, err
219 }
220 b = b[n:]
221 }
222 // Every map entry should have entries for key and value, but this is not strictly required.
223 if !haveKey {
224 key = keyField.Default()
225 }
226 if !haveVal {
227 switch valField.Kind() {
228 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neilba23aa52018-12-07 14:38:17 -0800229 default:
230 val = valField.Default()
231 }
232 }
233 mapv.Set(key.MapKey(), val)
Damien Neil96c229a2019-04-03 12:17:24 -0700234 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800235}
236
237// errUnknown is used internally to indicate fields which should be added
238// to the unknown field set of a message. It is never returned from an exported
239// function.
Damien Neil96c229a2019-04-03 12:17:24 -0700240var errUnknown = errors.New("BUG: internal error (unknown)")