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