blob: 85cc6b0cbf82c1a9aaf860a57cb8db4a608c47f5 [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 {
22 flags unmarshalOptionFlags
23 resolver preg.ExtensionTypeResolver
24}
25
26type unmarshalOptionFlags uint8
27
28const (
29 unmarshalDiscardUnknown unmarshalOptionFlags = 1 << iota
30)
31
32func newUnmarshalOptions(opts piface.UnmarshalOptions) unmarshalOptions {
33 o := unmarshalOptions{
34 resolver: opts.Resolver,
35 }
36 if opts.DiscardUnknown {
37 o.flags |= unmarshalDiscardUnknown
38 }
39 return o
40}
41
42func (o unmarshalOptions) Options() proto.UnmarshalOptions {
43 return proto.UnmarshalOptions{
Joe Tsai705acad2019-09-14 18:22:59 -070044 Merge: true,
Damien Neile91877d2019-06-27 10:54:42 -070045 AllowPartial: true,
46 DiscardUnknown: o.DiscardUnknown(),
47 Resolver: o.Resolver(),
48 }
49}
50
51func (o unmarshalOptions) DiscardUnknown() bool { return o.flags&unmarshalDiscardUnknown != 0 }
52func (o unmarshalOptions) Resolver() preg.ExtensionTypeResolver { return o.resolver }
53
54// unmarshal is protoreflect.Methods.Unmarshal.
Joe Tsai0f81b382019-07-10 23:14:31 -070055func (mi *MessageInfo) unmarshal(b []byte, m pref.Message, opts piface.UnmarshalOptions) error {
56 var p pointer
57 if ms, ok := m.(*messageState); ok {
58 p = ms.pointer()
59 } else {
60 p = m.(*messageReflectWrapper).pointer()
61 }
62 _, err := mi.unmarshalPointer(b, p, 0, newUnmarshalOptions(opts))
Damien Neile91877d2019-06-27 10:54:42 -070063 return err
64}
65
66// errUnknown is returned during unmarshaling to indicate a parse error that
67// should result in a field being placed in the unknown fields section (for example,
68// when the wire type doesn't match) as opposed to the entire unmarshal operation
69// failing (for example, when a field extends past the available input).
70//
71// This is a sentinel error which should never be visible to the user.
72var errUnknown = errors.New("unknown")
73
74func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag wire.Number, opts unmarshalOptions) (int, error) {
75 mi.init()
Damien Neilce3384c2019-11-06 13:18:28 -080076 if flags.ProtoLegacy && mi.isMessageSet {
77 return unmarshalMessageSet(mi, b, p, opts)
78 }
Damien Neile91877d2019-06-27 10:54:42 -070079 var exts *map[int32]ExtensionField
80 start := len(b)
81 for len(b) > 0 {
82 // Parse the tag (field number and wire type).
83 // TODO: inline 1 and 2 byte variants?
84 num, wtyp, n := wire.ConsumeTag(b)
85 if n < 0 {
86 return 0, wire.ParseError(n)
87 }
88 b = b[n:]
89
90 var f *coderFieldInfo
91 if int(num) < len(mi.denseCoderFields) {
92 f = mi.denseCoderFields[num]
93 } else {
94 f = mi.coderFields[num]
95 }
96 err := errUnknown
97 switch {
98 case f != nil:
99 if f.funcs.unmarshal == nil {
100 break
101 }
102 n, err = f.funcs.unmarshal(b, p.Apply(f.offset), wtyp, opts)
103 case num == groupTag && wtyp == wire.EndGroupType:
104 // End of group.
105 return start - len(b), nil
106 default:
107 // Possible extension.
108 if exts == nil && mi.extensionOffset.IsValid() {
109 exts = p.Apply(mi.extensionOffset).Extensions()
110 if *exts == nil {
111 *exts = make(map[int32]ExtensionField)
112 }
113 }
114 if exts == nil {
115 break
116 }
117 n, err = mi.unmarshalExtension(b, num, wtyp, *exts, opts)
118 }
119 if err != nil {
120 if err != errUnknown {
121 return 0, err
122 }
123 n = wire.ConsumeFieldValue(num, wtyp, b)
124 if n < 0 {
125 return 0, wire.ParseError(n)
126 }
127 if mi.unknownOffset.IsValid() {
128 u := p.Apply(mi.unknownOffset).Bytes()
129 *u = wire.AppendTag(*u, num, wtyp)
130 *u = append(*u, b[:n]...)
131 }
132 }
133 b = b[n:]
134 }
135 if groupTag != 0 {
136 return 0, errors.New("missing end group marker")
137 }
138 return start, nil
139}
140
141func (mi *MessageInfo) unmarshalExtension(b []byte, num wire.Number, wtyp wire.Type, exts map[int32]ExtensionField, opts unmarshalOptions) (n int, err error) {
142 x := exts[int32(num)]
Damien Neilef19a2a2019-11-01 12:00:37 -0700143 xt := x.Type()
Damien Neile91877d2019-06-27 10:54:42 -0700144 if xt == nil {
145 var err error
Damien Neil16163b42019-08-06 15:43:25 -0700146 xt, err = opts.Resolver().FindExtensionByNumber(mi.Desc.FullName(), num)
Damien Neile91877d2019-06-27 10:54:42 -0700147 if err != nil {
148 if err == preg.NotFound {
149 return 0, errUnknown
150 }
151 return 0, err
152 }
Damien Neile91877d2019-06-27 10:54:42 -0700153 }
154 xi := mi.extensionFieldInfo(xt)
155 if xi.funcs.unmarshal == nil {
156 return 0, errUnknown
157 }
Damien Neil68b81c32019-08-22 11:41:32 -0700158 ival := x.Value()
159 if !ival.IsValid() && xi.unmarshalNeedsValue {
Damien Neile91877d2019-06-27 10:54:42 -0700160 // Create a new message, list, or map value to fill in.
161 // For enums, create a prototype value to let the unmarshal func know the
162 // concrete type.
Damien Neil68b81c32019-08-22 11:41:32 -0700163 ival = xt.New()
Damien Neile91877d2019-06-27 10:54:42 -0700164 }
165 v, n, err := xi.funcs.unmarshal(b, ival, num, wtyp, opts)
166 if err != nil {
167 return 0, err
168 }
Damien Neil68b81c32019-08-22 11:41:32 -0700169 x.Set(xt, v)
Damien Neile91877d2019-06-27 10:54:42 -0700170 exts[int32(num)] = x
171 return n, nil
172}