blob: 5fdffe3a6e5fbffae7af2441e72e26b0b355f075 [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.
53func (mi *MessageInfo) unmarshal(b []byte, m pref.ProtoMessage, opts piface.UnmarshalOptions) error {
54 _, err := mi.unmarshalPointer(b, pointerOfIface(m), 0, newUnmarshalOptions(opts))
55 return err
56}
57
58// errUnknown is returned during unmarshaling to indicate a parse error that
59// should result in a field being placed in the unknown fields section (for example,
60// when the wire type doesn't match) as opposed to the entire unmarshal operation
61// failing (for example, when a field extends past the available input).
62//
63// This is a sentinel error which should never be visible to the user.
64var errUnknown = errors.New("unknown")
65
66func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag wire.Number, opts unmarshalOptions) (int, error) {
67 mi.init()
68 var exts *map[int32]ExtensionField
69 start := len(b)
70 for len(b) > 0 {
71 // Parse the tag (field number and wire type).
72 // TODO: inline 1 and 2 byte variants?
73 num, wtyp, n := wire.ConsumeTag(b)
74 if n < 0 {
75 return 0, wire.ParseError(n)
76 }
77 b = b[n:]
78
79 var f *coderFieldInfo
80 if int(num) < len(mi.denseCoderFields) {
81 f = mi.denseCoderFields[num]
82 } else {
83 f = mi.coderFields[num]
84 }
85 err := errUnknown
86 switch {
87 case f != nil:
88 if f.funcs.unmarshal == nil {
89 break
90 }
91 n, err = f.funcs.unmarshal(b, p.Apply(f.offset), wtyp, opts)
92 case num == groupTag && wtyp == wire.EndGroupType:
93 // End of group.
94 return start - len(b), nil
95 default:
96 // Possible extension.
97 if exts == nil && mi.extensionOffset.IsValid() {
98 exts = p.Apply(mi.extensionOffset).Extensions()
99 if *exts == nil {
100 *exts = make(map[int32]ExtensionField)
101 }
102 }
103 if exts == nil {
104 break
105 }
106 n, err = mi.unmarshalExtension(b, num, wtyp, *exts, opts)
107 }
108 if err != nil {
109 if err != errUnknown {
110 return 0, err
111 }
112 n = wire.ConsumeFieldValue(num, wtyp, b)
113 if n < 0 {
114 return 0, wire.ParseError(n)
115 }
116 if mi.unknownOffset.IsValid() {
117 u := p.Apply(mi.unknownOffset).Bytes()
118 *u = wire.AppendTag(*u, num, wtyp)
119 *u = append(*u, b[:n]...)
120 }
121 }
122 b = b[n:]
123 }
124 if groupTag != 0 {
125 return 0, errors.New("missing end group marker")
126 }
127 return start, nil
128}
129
130func (mi *MessageInfo) unmarshalExtension(b []byte, num wire.Number, wtyp wire.Type, exts map[int32]ExtensionField, opts unmarshalOptions) (n int, err error) {
131 x := exts[int32(num)]
132 xt := x.GetType()
133 if xt == nil {
134 var err error
135 xt, err = opts.Resolver().FindExtensionByNumber(mi.PBType.FullName(), num)
136 if err != nil {
137 if err == preg.NotFound {
138 return 0, errUnknown
139 }
140 return 0, err
141 }
142 x.SetType(xt)
143 }
144 xi := mi.extensionFieldInfo(xt)
145 if xi.funcs.unmarshal == nil {
146 return 0, errUnknown
147 }
148 ival := x.GetValue()
149 if ival == nil && xi.unmarshalNeedsValue {
150 // Create a new message, list, or map value to fill in.
151 // For enums, create a prototype value to let the unmarshal func know the
152 // concrete type.
153 ival = xt.InterfaceOf(xt.New())
154 }
155 v, n, err := xi.funcs.unmarshal(b, ival, num, wtyp, opts)
156 if err != nil {
157 return 0, err
158 }
159 x.SetEagerValue(v)
160 exts[int32(num)] = x
161 return n, nil
162}