blob: 3e26223b03d0998e77087b55cc881fa1500ef1dd [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 {
27 preg.ExtensionTypeResolver
28 }
Damien Neile91877d2019-06-27 10:54:42 -070029}
30
31type unmarshalOptionFlags uint8
32
33const (
34 unmarshalDiscardUnknown unmarshalOptionFlags = 1 << iota
35)
36
37func newUnmarshalOptions(opts piface.UnmarshalOptions) unmarshalOptions {
38 o := unmarshalOptions{
39 resolver: opts.Resolver,
40 }
41 if opts.DiscardUnknown {
42 o.flags |= unmarshalDiscardUnknown
43 }
44 return o
45}
46
47func (o unmarshalOptions) Options() proto.UnmarshalOptions {
48 return proto.UnmarshalOptions{
Joe Tsai705acad2019-09-14 18:22:59 -070049 Merge: true,
Damien Neile91877d2019-06-27 10:54:42 -070050 AllowPartial: true,
51 DiscardUnknown: o.DiscardUnknown(),
52 Resolver: o.Resolver(),
53 }
54}
55
56func (o unmarshalOptions) DiscardUnknown() bool { return o.flags&unmarshalDiscardUnknown != 0 }
57func (o unmarshalOptions) Resolver() preg.ExtensionTypeResolver { return o.resolver }
58
59// unmarshal is protoreflect.Methods.Unmarshal.
Joe Tsai0f81b382019-07-10 23:14:31 -070060func (mi *MessageInfo) unmarshal(b []byte, m pref.Message, opts piface.UnmarshalOptions) error {
61 var p pointer
62 if ms, ok := m.(*messageState); ok {
63 p = ms.pointer()
64 } else {
65 p = m.(*messageReflectWrapper).pointer()
66 }
67 _, err := mi.unmarshalPointer(b, p, 0, newUnmarshalOptions(opts))
Damien Neile91877d2019-06-27 10:54:42 -070068 return err
69}
70
71// errUnknown is returned during unmarshaling to indicate a parse error that
72// should result in a field being placed in the unknown fields section (for example,
73// when the wire type doesn't match) as opposed to the entire unmarshal operation
74// failing (for example, when a field extends past the available input).
75//
76// This is a sentinel error which should never be visible to the user.
77var errUnknown = errors.New("unknown")
78
79func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag wire.Number, opts unmarshalOptions) (int, error) {
80 mi.init()
Damien Neilce3384c2019-11-06 13:18:28 -080081 if flags.ProtoLegacy && mi.isMessageSet {
82 return unmarshalMessageSet(mi, b, p, opts)
83 }
Damien Neile91877d2019-06-27 10:54:42 -070084 var exts *map[int32]ExtensionField
85 start := len(b)
86 for len(b) > 0 {
87 // Parse the tag (field number and wire type).
88 // TODO: inline 1 and 2 byte variants?
89 num, wtyp, n := wire.ConsumeTag(b)
90 if n < 0 {
91 return 0, wire.ParseError(n)
92 }
Damien Neilfe15dd42019-12-06 15:36:03 -080093 if num > wire.MaxValidNumber {
94 return 0, errors.New("invalid field number")
95 }
Damien Neile91877d2019-06-27 10:54:42 -070096 b = b[n:]
97
Damien Neil2ae60932020-01-14 11:12:21 -080098 if wtyp == wire.EndGroupType {
99 if num != groupTag {
100 return 0, errors.New("mismatching end group marker")
101 }
102 return start - len(b), nil
103 }
104
Damien Neile91877d2019-06-27 10:54:42 -0700105 var f *coderFieldInfo
106 if int(num) < len(mi.denseCoderFields) {
107 f = mi.denseCoderFields[num]
108 } else {
109 f = mi.coderFields[num]
110 }
111 err := errUnknown
112 switch {
113 case f != nil:
114 if f.funcs.unmarshal == nil {
115 break
116 }
117 n, err = f.funcs.unmarshal(b, p.Apply(f.offset), wtyp, opts)
Damien Neile91877d2019-06-27 10:54:42 -0700118 default:
119 // Possible extension.
120 if exts == nil && mi.extensionOffset.IsValid() {
121 exts = p.Apply(mi.extensionOffset).Extensions()
122 if *exts == nil {
123 *exts = make(map[int32]ExtensionField)
124 }
125 }
126 if exts == nil {
127 break
128 }
129 n, err = mi.unmarshalExtension(b, num, wtyp, *exts, opts)
130 }
131 if err != nil {
132 if err != errUnknown {
133 return 0, err
134 }
135 n = wire.ConsumeFieldValue(num, wtyp, b)
136 if n < 0 {
137 return 0, wire.ParseError(n)
138 }
139 if mi.unknownOffset.IsValid() {
140 u := p.Apply(mi.unknownOffset).Bytes()
141 *u = wire.AppendTag(*u, num, wtyp)
142 *u = append(*u, b[:n]...)
143 }
144 }
145 b = b[n:]
146 }
147 if groupTag != 0 {
148 return 0, errors.New("missing end group marker")
149 }
150 return start, nil
151}
152
153func (mi *MessageInfo) unmarshalExtension(b []byte, num wire.Number, wtyp wire.Type, exts map[int32]ExtensionField, opts unmarshalOptions) (n int, err error) {
154 x := exts[int32(num)]
Damien Neilef19a2a2019-11-01 12:00:37 -0700155 xt := x.Type()
Damien Neile91877d2019-06-27 10:54:42 -0700156 if xt == nil {
157 var err error
Damien Neil16163b42019-08-06 15:43:25 -0700158 xt, err = opts.Resolver().FindExtensionByNumber(mi.Desc.FullName(), num)
Damien Neile91877d2019-06-27 10:54:42 -0700159 if err != nil {
160 if err == preg.NotFound {
161 return 0, errUnknown
162 }
163 return 0, err
164 }
Damien Neile91877d2019-06-27 10:54:42 -0700165 }
Damien Neil79571e92019-12-09 10:24:36 -0800166 xi := getExtensionFieldInfo(xt)
Damien Neile91877d2019-06-27 10:54:42 -0700167 if xi.funcs.unmarshal == nil {
168 return 0, errUnknown
169 }
Damien Neil68b81c32019-08-22 11:41:32 -0700170 ival := x.Value()
171 if !ival.IsValid() && xi.unmarshalNeedsValue {
Damien Neile91877d2019-06-27 10:54:42 -0700172 // Create a new message, list, or map value to fill in.
173 // For enums, create a prototype value to let the unmarshal func know the
174 // concrete type.
Damien Neil68b81c32019-08-22 11:41:32 -0700175 ival = xt.New()
Damien Neile91877d2019-06-27 10:54:42 -0700176 }
177 v, n, err := xi.funcs.unmarshal(b, ival, num, wtyp, opts)
178 if err != nil {
179 return 0, err
180 }
Damien Neil68b81c32019-08-22 11:41:32 -0700181 x.Set(xt, v)
Damien Neile91877d2019-06-27 10:54:42 -0700182 exts[int32(num)] = x
183 return n, nil
184}