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