blob: 949dc49a65b3cf4f9892292d9a556a66fe33d42d [file] [log] [blame]
Damien Neile91877d2019-06-27 10:54:42 -07001// Copyright 2019 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 impl
6
7import (
Damien Neilc600d6c2020-01-21 15:00:33 -08008 "math/bits"
9
Joe Tsaicd108d02020-02-14 18:08:02 -080010 "google.golang.org/protobuf/encoding/protowire"
Damien Neile91877d2019-06-27 10:54:42 -070011 "google.golang.org/protobuf/internal/errors"
Damien Neilce3384c2019-11-06 13:18:28 -080012 "google.golang.org/protobuf/internal/flags"
Damien Neile91877d2019-06-27 10:54:42 -070013 "google.golang.org/protobuf/proto"
Damien Neil466dd772020-02-14 14:49:35 -080014 "google.golang.org/protobuf/reflect/protoreflect"
Damien Neile91877d2019-06-27 10:54:42 -070015 preg "google.golang.org/protobuf/reflect/protoregistry"
Damien Neil466dd772020-02-14 14:49:35 -080016 "google.golang.org/protobuf/runtime/protoiface"
Damien Neile91877d2019-06-27 10:54:42 -070017 piface "google.golang.org/protobuf/runtime/protoiface"
18)
19
Damien Neilb5523e32020-07-22 09:10:20 -070020var errDecode = errors.New("cannot parse invalid wire-format data")
21
Damien Neil466dd772020-02-14 14:49:35 -080022type unmarshalOptions struct {
23 flags protoiface.UnmarshalInputFlags
24 resolver interface {
25 FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error)
26 FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error)
27 }
28}
Damien Neile91877d2019-06-27 10:54:42 -070029
30func (o unmarshalOptions) Options() proto.UnmarshalOptions {
31 return proto.UnmarshalOptions{
Joe Tsai705acad2019-09-14 18:22:59 -070032 Merge: true,
Damien Neile91877d2019-06-27 10:54:42 -070033 AllowPartial: true,
34 DiscardUnknown: o.DiscardUnknown(),
Damien Neil466dd772020-02-14 14:49:35 -080035 Resolver: o.resolver,
Damien Neile91877d2019-06-27 10:54:42 -070036 }
37}
38
Damien Neil466dd772020-02-14 14:49:35 -080039func (o unmarshalOptions) DiscardUnknown() bool { return o.flags&piface.UnmarshalDiscardUnknown != 0 }
Damien Neile91877d2019-06-27 10:54:42 -070040
Damien Neil0ae1c972020-01-28 14:53:44 -080041func (o unmarshalOptions) IsDefault() bool {
Damien Neil466dd772020-02-14 14:49:35 -080042 return o.flags == 0 && o.resolver == preg.GlobalTypes
Damien Neil6fb29942020-02-05 16:26:45 -080043}
44
45var lazyUnmarshalOptions = unmarshalOptions{
Damien Neil466dd772020-02-14 14:49:35 -080046 resolver: preg.GlobalTypes,
Damien Neil0ae1c972020-01-28 14:53:44 -080047}
48
Damien Neilf0831e82020-01-21 14:25:12 -080049type unmarshalOutput struct {
Damien Neilc600d6c2020-01-21 15:00:33 -080050 n int // number of bytes consumed
51 initialized bool
Damien Neilf0831e82020-01-21 14:25:12 -080052}
53
Damien Neile91877d2019-06-27 10:54:42 -070054// unmarshal is protoreflect.Methods.Unmarshal.
Damien Neil466dd772020-02-14 14:49:35 -080055func (mi *MessageInfo) unmarshal(in piface.UnmarshalInput) (piface.UnmarshalOutput, error) {
Joe Tsai0f81b382019-07-10 23:14:31 -070056 var p pointer
Damien Neil466dd772020-02-14 14:49:35 -080057 if ms, ok := in.Message.(*messageState); ok {
Joe Tsai0f81b382019-07-10 23:14:31 -070058 p = ms.pointer()
59 } else {
Damien Neil466dd772020-02-14 14:49:35 -080060 p = in.Message.(*messageReflectWrapper).pointer()
Joe Tsai0f81b382019-07-10 23:14:31 -070061 }
Damien Neil466dd772020-02-14 14:49:35 -080062 out, err := mi.unmarshalPointer(in.Buf, p, 0, unmarshalOptions{
63 flags: in.Flags,
64 resolver: in.Resolver,
65 })
66 var flags piface.UnmarshalOutputFlags
67 if out.initialized {
68 flags |= piface.UnmarshalInitialized
69 }
Damien Neilc600d6c2020-01-21 15:00:33 -080070 return piface.UnmarshalOutput{
Damien Neil466dd772020-02-14 14:49:35 -080071 Flags: flags,
Damien Neilc600d6c2020-01-21 15:00:33 -080072 }, err
Damien Neile91877d2019-06-27 10:54:42 -070073}
74
75// errUnknown is returned during unmarshaling to indicate a parse error that
76// should result in a field being placed in the unknown fields section (for example,
77// when the wire type doesn't match) as opposed to the entire unmarshal operation
78// failing (for example, when a field extends past the available input).
79//
80// This is a sentinel error which should never be visible to the user.
81var errUnknown = errors.New("unknown")
82
Joe Tsaicd108d02020-02-14 18:08:02 -080083func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag protowire.Number, opts unmarshalOptions) (out unmarshalOutput, err error) {
Damien Neile91877d2019-06-27 10:54:42 -070084 mi.init()
Damien Neilce3384c2019-11-06 13:18:28 -080085 if flags.ProtoLegacy && mi.isMessageSet {
86 return unmarshalMessageSet(mi, b, p, opts)
87 }
Damien Neilc600d6c2020-01-21 15:00:33 -080088 initialized := true
89 var requiredMask uint64
Damien Neile91877d2019-06-27 10:54:42 -070090 var exts *map[int32]ExtensionField
91 start := len(b)
92 for len(b) > 0 {
93 // Parse the tag (field number and wire type).
Damien Neilce8f7f62020-01-24 16:00:20 -080094 var tag uint64
95 if b[0] < 0x80 {
96 tag = uint64(b[0])
97 b = b[1:]
98 } else if len(b) >= 2 && b[1] < 128 {
99 tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
100 b = b[2:]
101 } else {
102 var n int
Joe Tsaicd108d02020-02-14 18:08:02 -0800103 tag, n = protowire.ConsumeVarint(b)
Damien Neilce8f7f62020-01-24 16:00:20 -0800104 if n < 0 {
Damien Neilb5523e32020-07-22 09:10:20 -0700105 return out, errDecode
Damien Neilce8f7f62020-01-24 16:00:20 -0800106 }
107 b = b[n:]
Damien Neile91877d2019-06-27 10:54:42 -0700108 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800109 var num protowire.Number
110 if n := tag >> 3; n < uint64(protowire.MinValidNumber) || n > uint64(protowire.MaxValidNumber) {
Damien Neilb5523e32020-07-22 09:10:20 -0700111 return out, errDecode
Damien Neila522d5f2020-01-27 21:50:47 -0800112 } else {
Joe Tsaicd108d02020-02-14 18:08:02 -0800113 num = protowire.Number(n)
Damien Neilfe15dd42019-12-06 15:36:03 -0800114 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800115 wtyp := protowire.Type(tag & 7)
Damien Neile91877d2019-06-27 10:54:42 -0700116
Joe Tsaicd108d02020-02-14 18:08:02 -0800117 if wtyp == protowire.EndGroupType {
Damien Neil2ae60932020-01-14 11:12:21 -0800118 if num != groupTag {
Damien Neilb5523e32020-07-22 09:10:20 -0700119 return out, errDecode
Damien Neil2ae60932020-01-14 11:12:21 -0800120 }
Damien Neilc600d6c2020-01-21 15:00:33 -0800121 groupTag = 0
122 break
Damien Neil2ae60932020-01-14 11:12:21 -0800123 }
124
Damien Neile91877d2019-06-27 10:54:42 -0700125 var f *coderFieldInfo
126 if int(num) < len(mi.denseCoderFields) {
127 f = mi.denseCoderFields[num]
128 } else {
129 f = mi.coderFields[num]
130 }
Damien Neilce8f7f62020-01-24 16:00:20 -0800131 var n int
Damien Neile91877d2019-06-27 10:54:42 -0700132 err := errUnknown
133 switch {
134 case f != nil:
135 if f.funcs.unmarshal == nil {
136 break
137 }
Damien Neilf0831e82020-01-21 14:25:12 -0800138 var o unmarshalOutput
Damien Neil316febd2020-02-09 12:26:50 -0800139 o, err = f.funcs.unmarshal(b, p.Apply(f.offset), wtyp, f, opts)
Damien Neilf0831e82020-01-21 14:25:12 -0800140 n = o.n
Damien Neil170b2bf2020-01-24 16:42:42 -0800141 if err != nil {
142 break
Damien Neilc600d6c2020-01-21 15:00:33 -0800143 }
Damien Neil170b2bf2020-01-24 16:42:42 -0800144 requiredMask |= f.validation.requiredBit
Damien Neilc600d6c2020-01-21 15:00:33 -0800145 if f.funcs.isInit != nil && !o.initialized {
146 initialized = false
147 }
Damien Neile91877d2019-06-27 10:54:42 -0700148 default:
149 // Possible extension.
150 if exts == nil && mi.extensionOffset.IsValid() {
151 exts = p.Apply(mi.extensionOffset).Extensions()
152 if *exts == nil {
153 *exts = make(map[int32]ExtensionField)
154 }
155 }
156 if exts == nil {
157 break
158 }
Damien Neilf0831e82020-01-21 14:25:12 -0800159 var o unmarshalOutput
160 o, err = mi.unmarshalExtension(b, num, wtyp, *exts, opts)
Damien Neil1887ff72020-01-29 16:40:05 -0800161 if err != nil {
162 break
163 }
Damien Neilf0831e82020-01-21 14:25:12 -0800164 n = o.n
Damien Neilc600d6c2020-01-21 15:00:33 -0800165 if !o.initialized {
166 initialized = false
167 }
Damien Neile91877d2019-06-27 10:54:42 -0700168 }
169 if err != nil {
170 if err != errUnknown {
Damien Neilf0831e82020-01-21 14:25:12 -0800171 return out, err
Damien Neile91877d2019-06-27 10:54:42 -0700172 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800173 n = protowire.ConsumeFieldValue(num, wtyp, b)
Damien Neile91877d2019-06-27 10:54:42 -0700174 if n < 0 {
Damien Neilb5523e32020-07-22 09:10:20 -0700175 return out, errDecode
Damien Neile91877d2019-06-27 10:54:42 -0700176 }
Damien Neila60e7092020-01-28 14:53:44 -0800177 if !opts.DiscardUnknown() && mi.unknownOffset.IsValid() {
Joe Tsai5d634732020-07-26 22:37:47 -0700178 u := mi.mutableUnknownBytes(p)
Joe Tsaicd108d02020-02-14 18:08:02 -0800179 *u = protowire.AppendTag(*u, num, wtyp)
Damien Neile91877d2019-06-27 10:54:42 -0700180 *u = append(*u, b[:n]...)
181 }
182 }
183 b = b[n:]
184 }
185 if groupTag != 0 {
Damien Neilb5523e32020-07-22 09:10:20 -0700186 return out, errDecode
Damien Neile91877d2019-06-27 10:54:42 -0700187 }
Damien Neilc600d6c2020-01-21 15:00:33 -0800188 if mi.numRequiredFields > 0 && bits.OnesCount64(requiredMask) != int(mi.numRequiredFields) {
189 initialized = false
190 }
191 if initialized {
192 out.initialized = true
193 }
194 out.n = start - len(b)
Damien Neilf0831e82020-01-21 14:25:12 -0800195 return out, nil
Damien Neile91877d2019-06-27 10:54:42 -0700196}
197
Joe Tsaicd108d02020-02-14 18:08:02 -0800198func (mi *MessageInfo) unmarshalExtension(b []byte, num protowire.Number, wtyp protowire.Type, exts map[int32]ExtensionField, opts unmarshalOptions) (out unmarshalOutput, err error) {
Damien Neile91877d2019-06-27 10:54:42 -0700199 x := exts[int32(num)]
Damien Neilef19a2a2019-11-01 12:00:37 -0700200 xt := x.Type()
Damien Neile91877d2019-06-27 10:54:42 -0700201 if xt == nil {
202 var err error
Damien Neil466dd772020-02-14 14:49:35 -0800203 xt, err = opts.resolver.FindExtensionByNumber(mi.Desc.FullName(), num)
Damien Neile91877d2019-06-27 10:54:42 -0700204 if err != nil {
205 if err == preg.NotFound {
Damien Neilf0831e82020-01-21 14:25:12 -0800206 return out, errUnknown
Damien Neile91877d2019-06-27 10:54:42 -0700207 }
Damien Neil01b51b42020-01-17 13:40:51 -0800208 return out, errors.New("%v: unable to resolve extension %v: %v", mi.Desc.FullName(), num, err)
Damien Neile91877d2019-06-27 10:54:42 -0700209 }
Damien Neile91877d2019-06-27 10:54:42 -0700210 }
Damien Neil79571e92019-12-09 10:24:36 -0800211 xi := getExtensionFieldInfo(xt)
Damien Neile91877d2019-06-27 10:54:42 -0700212 if xi.funcs.unmarshal == nil {
Damien Neilf0831e82020-01-21 14:25:12 -0800213 return out, errUnknown
Damien Neile91877d2019-06-27 10:54:42 -0700214 }
Damien Neil0ae1c972020-01-28 14:53:44 -0800215 if flags.LazyUnmarshalExtensions {
216 if opts.IsDefault() && x.canLazy(xt) {
Damien Neil40cba142020-02-05 10:12:40 -0800217 out, valid := skipExtension(b, xi, num, wtyp, opts)
218 switch valid {
219 case ValidationValid:
220 if out.initialized {
221 x.appendLazyBytes(xt, xi, num, wtyp, b[:out.n])
222 exts[int32(num)] = x
223 return out, nil
224 }
225 case ValidationInvalid:
Damien Neilb5523e32020-07-22 09:10:20 -0700226 return out, errDecode
Damien Neil40cba142020-02-05 10:12:40 -0800227 case ValidationUnknown:
Damien Neil0ae1c972020-01-28 14:53:44 -0800228 }
229 }
230 }
Damien Neil68b81c32019-08-22 11:41:32 -0700231 ival := x.Value()
232 if !ival.IsValid() && xi.unmarshalNeedsValue {
Damien Neile91877d2019-06-27 10:54:42 -0700233 // Create a new message, list, or map value to fill in.
234 // For enums, create a prototype value to let the unmarshal func know the
235 // concrete type.
Damien Neil68b81c32019-08-22 11:41:32 -0700236 ival = xt.New()
Damien Neile91877d2019-06-27 10:54:42 -0700237 }
Damien Neilf0831e82020-01-21 14:25:12 -0800238 v, out, err := xi.funcs.unmarshal(b, ival, num, wtyp, opts)
Damien Neile91877d2019-06-27 10:54:42 -0700239 if err != nil {
Damien Neilf0831e82020-01-21 14:25:12 -0800240 return out, err
Damien Neile91877d2019-06-27 10:54:42 -0700241 }
Damien Neil1887ff72020-01-29 16:40:05 -0800242 if xi.funcs.isInit == nil {
243 out.initialized = true
244 }
Damien Neil68b81c32019-08-22 11:41:32 -0700245 x.Set(xt, v)
Damien Neile91877d2019-06-27 10:54:42 -0700246 exts[int32(num)] = x
Damien Neilf0831e82020-01-21 14:25:12 -0800247 return out, nil
Damien Neile91877d2019-06-27 10:54:42 -0700248}
Damien Neil0ae1c972020-01-28 14:53:44 -0800249
Joe Tsaicd108d02020-02-14 18:08:02 -0800250func skipExtension(b []byte, xi *extensionFieldInfo, num protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (out unmarshalOutput, _ ValidationStatus) {
Damien Neil0ae1c972020-01-28 14:53:44 -0800251 if xi.validation.mi == nil {
Damien Neil40cba142020-02-05 10:12:40 -0800252 return out, ValidationUnknown
Damien Neil0ae1c972020-01-28 14:53:44 -0800253 }
254 xi.validation.mi.init()
Damien Neil0ae1c972020-01-28 14:53:44 -0800255 switch xi.validation.typ {
256 case validationTypeMessage:
Joe Tsaicd108d02020-02-14 18:08:02 -0800257 if wtyp != protowire.BytesType {
Damien Neil40cba142020-02-05 10:12:40 -0800258 return out, ValidationUnknown
Damien Neil0ae1c972020-01-28 14:53:44 -0800259 }
Joe Tsaicd108d02020-02-14 18:08:02 -0800260 v, n := protowire.ConsumeBytes(b)
Damien Neil0ae1c972020-01-28 14:53:44 -0800261 if n < 0 {
Damien Neil40cba142020-02-05 10:12:40 -0800262 return out, ValidationUnknown
Damien Neil0ae1c972020-01-28 14:53:44 -0800263 }
Damien Neilcadb4ab2020-02-03 16:17:31 -0800264 out, st := xi.validation.mi.validate(v, 0, opts)
265 out.n = n
Damien Neil40cba142020-02-05 10:12:40 -0800266 return out, st
Damien Neil0ae1c972020-01-28 14:53:44 -0800267 case validationTypeGroup:
Joe Tsaicd108d02020-02-14 18:08:02 -0800268 if wtyp != protowire.StartGroupType {
Damien Neil40cba142020-02-05 10:12:40 -0800269 return out, ValidationUnknown
Damien Neil0ae1c972020-01-28 14:53:44 -0800270 }
Damien Neil40cba142020-02-05 10:12:40 -0800271 out, st := xi.validation.mi.validate(b, num, opts)
272 return out, st
Damien Neil0ae1c972020-01-28 14:53:44 -0800273 default:
Damien Neil40cba142020-02-05 10:12:40 -0800274 return out, ValidationUnknown
Damien Neil0ae1c972020-01-28 14:53:44 -0800275 }
Damien Neil0ae1c972020-01-28 14:53:44 -0800276}