blob: 0b1aa3fe6d76cc3cea491aae72cb257148cd3d4d [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
28 pragma.NoUnkeyedLiterals
29}
30
Damien Neil0d3e8cc2019-04-01 13:31:55 -070031var _ = protoiface.UnmarshalOptions(UnmarshalOptions{})
32
Damien Neilba23aa52018-12-07 14:38:17 -080033// Unmarshal parses the wire-format message in b and places the result in m.
34func Unmarshal(b []byte, m Message) error {
35 return UnmarshalOptions{}.Unmarshal(b, m)
36}
37
38// Unmarshal parses the wire-format message in b and places the result in m.
39func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
40 // TODO: Reset m?
Damien Neil4686e232019-04-05 13:31:40 -070041 err := o.unmarshalMessageFast(b, m)
42 if err == errInternalNoFast {
43 err = o.unmarshalMessage(b, m.ProtoReflect())
44 }
45 var nerr errors.NonFatal
46 if !nerr.Merge(err) {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070047 return err
48 }
Damien Neil4686e232019-04-05 13:31:40 -070049 if !o.AllowPartial {
50 nerr.Merge(IsInitialized(m))
51 }
52 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -080053}
54
Damien Neil0d3e8cc2019-04-01 13:31:55 -070055func (o UnmarshalOptions) unmarshalMessageFast(b []byte, m Message) error {
Damien Neil0d3e8cc2019-04-01 13:31:55 -070056 methods := protoMethods(m)
57 if methods == nil || methods.Unmarshal == nil {
58 return errInternalNoFast
59 }
60 return methods.Unmarshal(b, m, protoiface.UnmarshalOptions(o))
61}
62
Damien Neilba23aa52018-12-07 14:38:17 -080063func (o UnmarshalOptions) unmarshalMessage(b []byte, m protoreflect.Message) error {
64 messageType := m.Type()
65 fieldTypes := messageType.Fields()
66 knownFields := m.KnownFields()
67 unknownFields := m.UnknownFields()
Damien Neil96c229a2019-04-03 12:17:24 -070068 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -080069 for len(b) > 0 {
70 // Parse the tag (field number and wire type).
71 num, wtyp, tagLen := wire.ConsumeTag(b)
72 if tagLen < 0 {
73 return wire.ParseError(tagLen)
74 }
75
76 // Parse the field value.
77 fieldType := fieldTypes.ByNumber(num)
Damien Neild068d302018-12-17 14:06:08 -080078 if fieldType == nil {
79 fieldType = knownFields.ExtensionTypes().ByNumber(num)
80 }
Damien Neilba23aa52018-12-07 14:38:17 -080081 var err error
82 var valLen int
83 switch {
84 case fieldType == nil:
85 err = errUnknown
86 case fieldType.Cardinality() != protoreflect.Repeated:
87 valLen, err = o.unmarshalScalarField(b[tagLen:], wtyp, num, knownFields, fieldType)
88 case !fieldType.IsMap():
Damien Neilbc310b52019-04-11 11:46:55 -070089 valLen, err = o.unmarshalList(b[tagLen:], wtyp, num, knownFields.Get(num).List(), fieldType)
Damien Neilba23aa52018-12-07 14:38:17 -080090 default:
91 valLen, err = o.unmarshalMap(b[tagLen:], wtyp, num, knownFields.Get(num).Map(), fieldType)
92 }
93 if err == errUnknown {
94 valLen = wire.ConsumeFieldValue(num, wtyp, b[tagLen:])
95 if valLen < 0 {
96 return wire.ParseError(valLen)
97 }
98 unknownFields.Set(num, append(unknownFields.Get(num), b[:tagLen+valLen]...))
Damien Neil96c229a2019-04-03 12:17:24 -070099 } else if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800100 return err
101 }
102 b = b[tagLen+valLen:]
103 }
Damien Neil96c229a2019-04-03 12:17:24 -0700104 return nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800105}
106
107func (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 -0700108 var nerr errors.NonFatal
109 v, n, err := o.unmarshalScalar(b, wtyp, num, field)
110 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800111 return 0, err
112 }
113 switch field.Kind() {
114 case protoreflect.GroupKind, protoreflect.MessageKind:
115 // Messages are merged with any existing message value,
116 // unless the message is part of a oneof.
117 //
118 // TODO: C++ merges into oneofs, while v1 does not.
119 // Evaluate which behavior to pick.
120 var m protoreflect.Message
121 if knownFields.Has(num) && field.OneofType() == nil {
122 m = knownFields.Get(num).Message()
123 } else {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800124 m = knownFields.NewMessage(num)
Damien Neilba23aa52018-12-07 14:38:17 -0800125 knownFields.Set(num, protoreflect.ValueOf(m))
126 }
Damien Neil96c229a2019-04-03 12:17:24 -0700127 // Pass up errors (fatal and otherwise).
Damien Neilbc310b52019-04-11 11:46:55 -0700128 if err := o.unmarshalMessage(v.Bytes(), m); !nerr.Merge(err) {
129 return n, err
130 }
Damien Neilba23aa52018-12-07 14:38:17 -0800131 default:
132 // Non-message scalars replace the previous value.
133 knownFields.Set(num, v)
134 }
Damien Neilbc310b52019-04-11 11:46:55 -0700135 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800136}
137
138func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp wire.Type, num wire.Number, mapv protoreflect.Map, field protoreflect.FieldDescriptor) (n int, err error) {
139 if wtyp != wire.BytesType {
140 return 0, errUnknown
141 }
142 b, n = wire.ConsumeBytes(b)
143 if n < 0 {
144 return 0, wire.ParseError(n)
145 }
146 var (
147 keyField = field.MessageType().Fields().ByNumber(1)
148 valField = field.MessageType().Fields().ByNumber(2)
149 key protoreflect.Value
150 val protoreflect.Value
151 haveKey bool
152 haveVal bool
153 )
154 switch valField.Kind() {
155 case protoreflect.GroupKind, protoreflect.MessageKind:
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800156 val = protoreflect.ValueOf(mapv.NewMessage())
Damien Neilba23aa52018-12-07 14:38:17 -0800157 }
158 // Map entries are represented as a two-element message with fields
159 // containing the key and value.
Damien Neil96c229a2019-04-03 12:17:24 -0700160 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -0800161 for len(b) > 0 {
162 num, wtyp, n := wire.ConsumeTag(b)
163 if n < 0 {
164 return 0, wire.ParseError(n)
165 }
166 b = b[n:]
167 err = errUnknown
168 switch num {
169 case 1:
Damien Neilbc310b52019-04-11 11:46:55 -0700170 key, n, err = o.unmarshalScalar(b, wtyp, num, keyField)
171 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800172 break
173 }
Damien Neilbc310b52019-04-11 11:46:55 -0700174 err = nil
Damien Neilba23aa52018-12-07 14:38:17 -0800175 haveKey = true
176 case 2:
177 var v protoreflect.Value
Damien Neilbc310b52019-04-11 11:46:55 -0700178 v, n, err = o.unmarshalScalar(b, wtyp, num, valField)
179 if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800180 break
181 }
Damien Neilbc310b52019-04-11 11:46:55 -0700182 err = nil
Damien Neilba23aa52018-12-07 14:38:17 -0800183 switch valField.Kind() {
184 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neil96c229a2019-04-03 12:17:24 -0700185 if err := o.unmarshalMessage(v.Bytes(), val.Message()); !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800186 return 0, err
187 }
188 default:
189 val = v
190 }
191 haveVal = true
192 }
193 if err == errUnknown {
194 n = wire.ConsumeFieldValue(num, wtyp, b)
195 if n < 0 {
196 return 0, wire.ParseError(n)
197 }
Damien Neilbc310b52019-04-11 11:46:55 -0700198 } else if err != nil {
Damien Neilba23aa52018-12-07 14:38:17 -0800199 return 0, err
200 }
201 b = b[n:]
202 }
203 // Every map entry should have entries for key and value, but this is not strictly required.
204 if !haveKey {
205 key = keyField.Default()
206 }
207 if !haveVal {
208 switch valField.Kind() {
209 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neilba23aa52018-12-07 14:38:17 -0800210 default:
211 val = valField.Default()
212 }
213 }
214 mapv.Set(key.MapKey(), val)
Damien Neil96c229a2019-04-03 12:17:24 -0700215 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800216}
217
218// errUnknown is used internally to indicate fields which should be added
219// to the unknown field set of a message. It is never returned from an exported
220// function.
Damien Neil96c229a2019-04-03 12:17:24 -0700221var errUnknown = errors.New("BUG: internal error (unknown)")