blob: 11fed46b2710bb092f5be20cf5840fe0efae8486 [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"
Damien Neil0d3e8cc2019-04-01 13:31:55 -070012 "github.com/golang/protobuf/v2/runtime/protoiface"
Damien Neilba23aa52018-12-07 14:38:17 -080013)
14
15// UnmarshalOptions configures the unmarshaler.
16//
17// Example usage:
18// err := UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, m)
19type UnmarshalOptions struct {
Damien Neil96c229a2019-04-03 12:17:24 -070020 // AllowPartial accepts input for messages that will result in missing
21 // required fields. If AllowPartial is false (the default), Unmarshal will
22 // return an error if there are any missing required fields.
23 AllowPartial bool
24
Damien Neilba23aa52018-12-07 14:38:17 -080025 // If DiscardUnknown is set, unknown fields are ignored.
26 DiscardUnknown bool
27
Damien Neil0d3e8cc2019-04-01 13:31:55 -070028 // Reflection forces use of the reflection-based decoder, even for
29 // messages which implement fast-path deserialization.
30 Reflection bool
31
Damien Neilba23aa52018-12-07 14:38:17 -080032 pragma.NoUnkeyedLiterals
33}
34
Damien Neil0d3e8cc2019-04-01 13:31:55 -070035var _ = protoiface.UnmarshalOptions(UnmarshalOptions{})
36
Damien Neilba23aa52018-12-07 14:38:17 -080037// Unmarshal parses the wire-format message in b and places the result in m.
38func Unmarshal(b []byte, m Message) error {
39 return UnmarshalOptions{}.Unmarshal(b, m)
40}
41
42// Unmarshal parses the wire-format message in b and places the result in m.
43func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
44 // TODO: Reset m?
Damien Neil4686e232019-04-05 13:31:40 -070045 err := o.unmarshalMessageFast(b, m)
46 if err == errInternalNoFast {
47 err = o.unmarshalMessage(b, m.ProtoReflect())
48 }
49 var nerr errors.NonFatal
50 if !nerr.Merge(err) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070051 return err
52 }
Damien Neil4686e232019-04-05 13:31:40 -070053 if !o.AllowPartial {
54 nerr.Merge(IsInitialized(m))
55 }
56 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -080057}
58
Damien Neil0d3e8cc2019-04-01 13:31:55 -070059func (o UnmarshalOptions) unmarshalMessageFast(b []byte, m Message) error {
60 if o.Reflection {
61 return errInternalNoFast
62 }
63 methods := protoMethods(m)
64 if methods == nil || methods.Unmarshal == nil {
65 return errInternalNoFast
66 }
67 return methods.Unmarshal(b, m, protoiface.UnmarshalOptions(o))
68}
69
Damien Neilba23aa52018-12-07 14:38:17 -080070func (o UnmarshalOptions) unmarshalMessage(b []byte, m protoreflect.Message) error {
71 messageType := m.Type()
72 fieldTypes := messageType.Fields()
73 knownFields := m.KnownFields()
74 unknownFields := m.UnknownFields()
Damien Neil96c229a2019-04-03 12:17:24 -070075 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -080076 for len(b) > 0 {
77 // Parse the tag (field number and wire type).
78 num, wtyp, tagLen := wire.ConsumeTag(b)
79 if tagLen < 0 {
80 return wire.ParseError(tagLen)
81 }
82
83 // Parse the field value.
84 fieldType := fieldTypes.ByNumber(num)
Damien Neild068d302018-12-17 14:06:08 -080085 if fieldType == nil {
86 fieldType = knownFields.ExtensionTypes().ByNumber(num)
87 }
Damien Neilba23aa52018-12-07 14:38:17 -080088 var err error
89 var valLen int
90 switch {
91 case fieldType == nil:
92 err = errUnknown
93 case fieldType.Cardinality() != protoreflect.Repeated:
94 valLen, err = o.unmarshalScalarField(b[tagLen:], wtyp, num, knownFields, fieldType)
95 case !fieldType.IsMap():
96 valLen, err = o.unmarshalList(b[tagLen:], wtyp, num, knownFields.Get(num).List(), fieldType.Kind())
97 default:
98 valLen, err = o.unmarshalMap(b[tagLen:], wtyp, num, knownFields.Get(num).Map(), fieldType)
99 }
100 if err == errUnknown {
101 valLen = wire.ConsumeFieldValue(num, wtyp, b[tagLen:])
102 if valLen < 0 {
103 return wire.ParseError(valLen)
104 }
105 unknownFields.Set(num, append(unknownFields.Get(num), b[:tagLen+valLen]...))
Damien Neil96c229a2019-04-03 12:17:24 -0700106 } else if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800107 return err
108 }
109 b = b[tagLen+valLen:]
110 }
Damien Neil96c229a2019-04-03 12:17:24 -0700111 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800112}
113
114func (o UnmarshalOptions) unmarshalScalarField(b []byte, wtyp wire.Type, num wire.Number, knownFields protoreflect.KnownFields, field protoreflect.FieldDescriptor) (n int, err error) {
115 v, n, err := o.unmarshalScalar(b, wtyp, num, field.Kind())
116 if err != nil {
117 return 0, err
118 }
119 switch field.Kind() {
120 case protoreflect.GroupKind, protoreflect.MessageKind:
121 // Messages are merged with any existing message value,
122 // unless the message is part of a oneof.
123 //
124 // TODO: C++ merges into oneofs, while v1 does not.
125 // Evaluate which behavior to pick.
126 var m protoreflect.Message
127 if knownFields.Has(num) && field.OneofType() == nil {
128 m = knownFields.Get(num).Message()
129 } else {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800130 m = knownFields.NewMessage(num)
Damien Neilba23aa52018-12-07 14:38:17 -0800131 knownFields.Set(num, protoreflect.ValueOf(m))
132 }
Damien Neil96c229a2019-04-03 12:17:24 -0700133 // Pass up errors (fatal and otherwise).
134 err = o.unmarshalMessage(v.Bytes(), m)
Damien Neilba23aa52018-12-07 14:38:17 -0800135 default:
136 // Non-message scalars replace the previous value.
137 knownFields.Set(num, v)
138 }
Damien Neil96c229a2019-04-03 12:17:24 -0700139 return n, err
Damien Neilba23aa52018-12-07 14:38:17 -0800140}
141
142func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp wire.Type, num wire.Number, mapv protoreflect.Map, field protoreflect.FieldDescriptor) (n int, err error) {
143 if wtyp != wire.BytesType {
144 return 0, errUnknown
145 }
146 b, n = wire.ConsumeBytes(b)
147 if n < 0 {
148 return 0, wire.ParseError(n)
149 }
150 var (
151 keyField = field.MessageType().Fields().ByNumber(1)
152 valField = field.MessageType().Fields().ByNumber(2)
153 key protoreflect.Value
154 val protoreflect.Value
155 haveKey bool
156 haveVal bool
157 )
158 switch valField.Kind() {
159 case protoreflect.GroupKind, protoreflect.MessageKind:
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800160 val = protoreflect.ValueOf(mapv.NewMessage())
Damien Neilba23aa52018-12-07 14:38:17 -0800161 }
162 // Map entries are represented as a two-element message with fields
163 // containing the key and value.
Damien Neil96c229a2019-04-03 12:17:24 -0700164 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -0800165 for len(b) > 0 {
166 num, wtyp, n := wire.ConsumeTag(b)
167 if n < 0 {
168 return 0, wire.ParseError(n)
169 }
170 b = b[n:]
171 err = errUnknown
172 switch num {
173 case 1:
174 key, n, err = o.unmarshalScalar(b, wtyp, num, keyField.Kind())
175 if err != nil {
176 break
177 }
178 haveKey = true
179 case 2:
180 var v protoreflect.Value
181 v, n, err = o.unmarshalScalar(b, wtyp, num, valField.Kind())
182 if err != nil {
183 break
184 }
185 switch valField.Kind() {
186 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neil96c229a2019-04-03 12:17:24 -0700187 if err := o.unmarshalMessage(v.Bytes(), val.Message()); !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800188 return 0, err
189 }
190 default:
191 val = v
192 }
193 haveVal = true
194 }
195 if err == errUnknown {
196 n = wire.ConsumeFieldValue(num, wtyp, b)
197 if n < 0 {
198 return 0, wire.ParseError(n)
199 }
Damien Neil96c229a2019-04-03 12:17:24 -0700200 } else if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800201 return 0, err
202 }
203 b = b[n:]
204 }
205 // Every map entry should have entries for key and value, but this is not strictly required.
206 if !haveKey {
207 key = keyField.Default()
208 }
209 if !haveVal {
210 switch valField.Kind() {
211 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neilba23aa52018-12-07 14:38:17 -0800212 default:
213 val = valField.Default()
214 }
215 }
216 mapv.Set(key.MapKey(), val)
Damien Neil96c229a2019-04-03 12:17:24 -0700217 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800218}
219
220// errUnknown is used internally to indicate fields which should be added
221// to the unknown field set of a message. It is never returned from an exported
222// function.
Damien Neil96c229a2019-04-03 12:17:24 -0700223var errUnknown = errors.New("BUG: internal error (unknown)")