blob: 50b0cf1c2a9b49226759a800786addd28ecf8064 [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 (
8 "google.golang.org/protobuf/internal/encoding/wire"
9 "google.golang.org/protobuf/internal/errors"
Damien Neilce3384c2019-11-06 13:18:28 -080010 "google.golang.org/protobuf/internal/flags"
Damien Neile91877d2019-06-27 10:54:42 -070011 "google.golang.org/protobuf/proto"
12 pref "google.golang.org/protobuf/reflect/protoreflect"
13 preg "google.golang.org/protobuf/reflect/protoregistry"
14 piface "google.golang.org/protobuf/runtime/protoiface"
15)
16
17// unmarshalOptions is a more efficient representation of UnmarshalOptions.
18//
19// We don't preserve the AllowPartial flag, because fast-path (un)marshal
20// operations always allow partial messages.
21type unmarshalOptions struct {
Damien Neil2f643a92020-01-21 09:56:01 -080022 flags unmarshalOptionFlags
23
24 // Keep this field's type identical to (proto.UnmarshalOptions).Resolver
25 // to avoid a type conversion on assignment.
26 resolver interface {
Damien Neilf12fb452020-01-21 11:27:51 -080027 FindExtensionByName(field pref.FullName) (pref.ExtensionType, error)
28 FindExtensionByNumber(message pref.FullName, field pref.FieldNumber) (pref.ExtensionType, error)
Damien Neil2f643a92020-01-21 09:56:01 -080029 }
Damien Neile91877d2019-06-27 10:54:42 -070030}
31
32type unmarshalOptionFlags uint8
33
34const (
35 unmarshalDiscardUnknown unmarshalOptionFlags = 1 << iota
36)
37
38func newUnmarshalOptions(opts piface.UnmarshalOptions) unmarshalOptions {
39 o := unmarshalOptions{
40 resolver: opts.Resolver,
41 }
42 if opts.DiscardUnknown {
43 o.flags |= unmarshalDiscardUnknown
44 }
45 return o
46}
47
48func (o unmarshalOptions) Options() proto.UnmarshalOptions {
49 return proto.UnmarshalOptions{
Joe Tsai705acad2019-09-14 18:22:59 -070050 Merge: true,
Damien Neile91877d2019-06-27 10:54:42 -070051 AllowPartial: true,
52 DiscardUnknown: o.DiscardUnknown(),
53 Resolver: o.Resolver(),
54 }
55}
56
57func (o unmarshalOptions) DiscardUnknown() bool { return o.flags&unmarshalDiscardUnknown != 0 }
58func (o unmarshalOptions) Resolver() preg.ExtensionTypeResolver { return o.resolver }
59
60// unmarshal is protoreflect.Methods.Unmarshal.
Joe Tsai0f81b382019-07-10 23:14:31 -070061func (mi *MessageInfo) unmarshal(b []byte, m pref.Message, opts piface.UnmarshalOptions) error {
62 var p pointer
63 if ms, ok := m.(*messageState); ok {
64 p = ms.pointer()
65 } else {
66 p = m.(*messageReflectWrapper).pointer()
67 }
68 _, err := mi.unmarshalPointer(b, p, 0, newUnmarshalOptions(opts))
Damien Neile91877d2019-06-27 10:54:42 -070069 return err
70}
71
72// errUnknown is returned during unmarshaling to indicate a parse error that
73// should result in a field being placed in the unknown fields section (for example,
74// when the wire type doesn't match) as opposed to the entire unmarshal operation
75// failing (for example, when a field extends past the available input).
76//
77// This is a sentinel error which should never be visible to the user.
78var errUnknown = errors.New("unknown")
79
80func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag wire.Number, opts unmarshalOptions) (int, error) {
81 mi.init()
Damien Neilce3384c2019-11-06 13:18:28 -080082 if flags.ProtoLegacy && mi.isMessageSet {
83 return unmarshalMessageSet(mi, b, p, opts)
84 }
Damien Neile91877d2019-06-27 10:54:42 -070085 var exts *map[int32]ExtensionField
86 start := len(b)
87 for len(b) > 0 {
88 // Parse the tag (field number and wire type).
89 // TODO: inline 1 and 2 byte variants?
90 num, wtyp, n := wire.ConsumeTag(b)
91 if n < 0 {
92 return 0, wire.ParseError(n)
93 }
Damien Neilfe15dd42019-12-06 15:36:03 -080094 if num > wire.MaxValidNumber {
95 return 0, errors.New("invalid field number")
96 }
Damien Neile91877d2019-06-27 10:54:42 -070097 b = b[n:]
98
Damien Neil2ae60932020-01-14 11:12:21 -080099 if wtyp == wire.EndGroupType {
100 if num != groupTag {
101 return 0, errors.New("mismatching end group marker")
102 }
103 return start - len(b), nil
104 }
105
Damien Neile91877d2019-06-27 10:54:42 -0700106 var f *coderFieldInfo
107 if int(num) < len(mi.denseCoderFields) {
108 f = mi.denseCoderFields[num]
109 } else {
110 f = mi.coderFields[num]
111 }
112 err := errUnknown
113 switch {
114 case f != nil:
115 if f.funcs.unmarshal == nil {
116 break
117 }
118 n, err = f.funcs.unmarshal(b, p.Apply(f.offset), wtyp, opts)
Damien Neile91877d2019-06-27 10:54:42 -0700119 default:
120 // Possible extension.
121 if exts == nil && mi.extensionOffset.IsValid() {
122 exts = p.Apply(mi.extensionOffset).Extensions()
123 if *exts == nil {
124 *exts = make(map[int32]ExtensionField)
125 }
126 }
127 if exts == nil {
128 break
129 }
130 n, err = mi.unmarshalExtension(b, num, wtyp, *exts, opts)
131 }
132 if err != nil {
133 if err != errUnknown {
134 return 0, err
135 }
136 n = wire.ConsumeFieldValue(num, wtyp, b)
137 if n < 0 {
138 return 0, wire.ParseError(n)
139 }
140 if mi.unknownOffset.IsValid() {
141 u := p.Apply(mi.unknownOffset).Bytes()
142 *u = wire.AppendTag(*u, num, wtyp)
143 *u = append(*u, b[:n]...)
144 }
145 }
146 b = b[n:]
147 }
148 if groupTag != 0 {
149 return 0, errors.New("missing end group marker")
150 }
151 return start, nil
152}
153
154func (mi *MessageInfo) unmarshalExtension(b []byte, num wire.Number, wtyp wire.Type, exts map[int32]ExtensionField, opts unmarshalOptions) (n int, err error) {
155 x := exts[int32(num)]
Damien Neilef19a2a2019-11-01 12:00:37 -0700156 xt := x.Type()
Damien Neile91877d2019-06-27 10:54:42 -0700157 if xt == nil {
158 var err error
Damien Neil16163b42019-08-06 15:43:25 -0700159 xt, err = opts.Resolver().FindExtensionByNumber(mi.Desc.FullName(), num)
Damien Neile91877d2019-06-27 10:54:42 -0700160 if err != nil {
161 if err == preg.NotFound {
162 return 0, errUnknown
163 }
164 return 0, err
165 }
Damien Neile91877d2019-06-27 10:54:42 -0700166 }
Damien Neil79571e92019-12-09 10:24:36 -0800167 xi := getExtensionFieldInfo(xt)
Damien Neile91877d2019-06-27 10:54:42 -0700168 if xi.funcs.unmarshal == nil {
169 return 0, errUnknown
170 }
Damien Neil68b81c32019-08-22 11:41:32 -0700171 ival := x.Value()
172 if !ival.IsValid() && xi.unmarshalNeedsValue {
Damien Neile91877d2019-06-27 10:54:42 -0700173 // Create a new message, list, or map value to fill in.
174 // For enums, create a prototype value to let the unmarshal func know the
175 // concrete type.
Damien Neil68b81c32019-08-22 11:41:32 -0700176 ival = xt.New()
Damien Neile91877d2019-06-27 10:54:42 -0700177 }
178 v, n, err := xi.funcs.unmarshal(b, ival, num, wtyp, opts)
179 if err != nil {
180 return 0, err
181 }
Damien Neil68b81c32019-08-22 11:41:32 -0700182 x.Set(xt, v)
Damien Neile91877d2019-06-27 10:54:42 -0700183 exts[int32(num)] = x
184 return n, nil
185}