blob: 3e00074dffed6dba72baced8129f98f325cf1d7b [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():
89 valLen, err = o.unmarshalList(b[tagLen:], wtyp, num, knownFields.Get(num).List(), fieldType.Kind())
90 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) {
108 v, n, err := o.unmarshalScalar(b, wtyp, num, field.Kind())
109 if err != nil {
110 return 0, err
111 }
112 switch field.Kind() {
113 case protoreflect.GroupKind, protoreflect.MessageKind:
114 // Messages are merged with any existing message value,
115 // unless the message is part of a oneof.
116 //
117 // TODO: C++ merges into oneofs, while v1 does not.
118 // Evaluate which behavior to pick.
119 var m protoreflect.Message
120 if knownFields.Has(num) && field.OneofType() == nil {
121 m = knownFields.Get(num).Message()
122 } else {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800123 m = knownFields.NewMessage(num)
Damien Neilba23aa52018-12-07 14:38:17 -0800124 knownFields.Set(num, protoreflect.ValueOf(m))
125 }
Damien Neil96c229a2019-04-03 12:17:24 -0700126 // Pass up errors (fatal and otherwise).
127 err = o.unmarshalMessage(v.Bytes(), m)
Damien Neilba23aa52018-12-07 14:38:17 -0800128 default:
129 // Non-message scalars replace the previous value.
130 knownFields.Set(num, v)
131 }
Damien Neil96c229a2019-04-03 12:17:24 -0700132 return n, err
Damien Neilba23aa52018-12-07 14:38:17 -0800133}
134
135func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp wire.Type, num wire.Number, mapv protoreflect.Map, field protoreflect.FieldDescriptor) (n int, err error) {
136 if wtyp != wire.BytesType {
137 return 0, errUnknown
138 }
139 b, n = wire.ConsumeBytes(b)
140 if n < 0 {
141 return 0, wire.ParseError(n)
142 }
143 var (
144 keyField = field.MessageType().Fields().ByNumber(1)
145 valField = field.MessageType().Fields().ByNumber(2)
146 key protoreflect.Value
147 val protoreflect.Value
148 haveKey bool
149 haveVal bool
150 )
151 switch valField.Kind() {
152 case protoreflect.GroupKind, protoreflect.MessageKind:
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800153 val = protoreflect.ValueOf(mapv.NewMessage())
Damien Neilba23aa52018-12-07 14:38:17 -0800154 }
155 // Map entries are represented as a two-element message with fields
156 // containing the key and value.
Damien Neil96c229a2019-04-03 12:17:24 -0700157 var nerr errors.NonFatal
Damien Neilba23aa52018-12-07 14:38:17 -0800158 for len(b) > 0 {
159 num, wtyp, n := wire.ConsumeTag(b)
160 if n < 0 {
161 return 0, wire.ParseError(n)
162 }
163 b = b[n:]
164 err = errUnknown
165 switch num {
166 case 1:
167 key, n, err = o.unmarshalScalar(b, wtyp, num, keyField.Kind())
168 if err != nil {
169 break
170 }
171 haveKey = true
172 case 2:
173 var v protoreflect.Value
174 v, n, err = o.unmarshalScalar(b, wtyp, num, valField.Kind())
175 if err != nil {
176 break
177 }
178 switch valField.Kind() {
179 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neil96c229a2019-04-03 12:17:24 -0700180 if err := o.unmarshalMessage(v.Bytes(), val.Message()); !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800181 return 0, err
182 }
183 default:
184 val = v
185 }
186 haveVal = true
187 }
188 if err == errUnknown {
189 n = wire.ConsumeFieldValue(num, wtyp, b)
190 if n < 0 {
191 return 0, wire.ParseError(n)
192 }
Damien Neil96c229a2019-04-03 12:17:24 -0700193 } else if !nerr.Merge(err) {
Damien Neilba23aa52018-12-07 14:38:17 -0800194 return 0, err
195 }
196 b = b[n:]
197 }
198 // Every map entry should have entries for key and value, but this is not strictly required.
199 if !haveKey {
200 key = keyField.Default()
201 }
202 if !haveVal {
203 switch valField.Kind() {
204 case protoreflect.GroupKind, protoreflect.MessageKind:
Damien Neilba23aa52018-12-07 14:38:17 -0800205 default:
206 val = valField.Default()
207 }
208 }
209 mapv.Set(key.MapKey(), val)
Damien Neil96c229a2019-04-03 12:17:24 -0700210 return n, nerr.E
Damien Neilba23aa52018-12-07 14:38:17 -0800211}
212
213// errUnknown is used internally to indicate fields which should be added
214// to the unknown field set of a message. It is never returned from an exported
215// function.
Damien Neil96c229a2019-04-03 12:17:24 -0700216var errUnknown = errors.New("BUG: internal error (unknown)")