17 ) |
17 ) |
18 |
18 |
19 // UnmarshalOptions configures the unmarshaler. |
19 // UnmarshalOptions configures the unmarshaler. |
20 // |
20 // |
21 // Example usage: |
21 // Example usage: |
22 // err := UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, m) |
22 // |
|
23 // err := UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, m) |
23 type UnmarshalOptions struct { |
24 type UnmarshalOptions struct { |
24 pragma.NoUnkeyedLiterals |
25 pragma.NoUnkeyedLiterals |
25 |
26 |
26 // Merge merges the input into the destination message. |
27 // Merge merges the input into the destination message. |
27 // The default behavior is to always reset the message before unmarshaling, |
28 // The default behavior is to always reset the message before unmarshaling, |
40 // If nil, this defaults to using protoregistry.GlobalTypes. |
41 // If nil, this defaults to using protoregistry.GlobalTypes. |
41 Resolver interface { |
42 Resolver interface { |
42 FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) |
43 FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) |
43 FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) |
44 FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) |
44 } |
45 } |
|
46 |
|
47 // RecursionLimit limits how deeply messages may be nested. |
|
48 // If zero, a default limit is applied. |
|
49 RecursionLimit int |
45 } |
50 } |
46 |
51 |
47 // Unmarshal parses the wire-format message in b and places the result in m. |
52 // Unmarshal parses the wire-format message in b and places the result in m. |
48 // The provided message must be mutable (e.g., a non-nil pointer to a message). |
53 // The provided message must be mutable (e.g., a non-nil pointer to a message). |
49 func Unmarshal(b []byte, m Message) error { |
54 func Unmarshal(b []byte, m Message) error { |
50 _, err := UnmarshalOptions{}.unmarshal(b, m.ProtoReflect()) |
55 _, err := UnmarshalOptions{RecursionLimit: protowire.DefaultRecursionLimit}.unmarshal(b, m.ProtoReflect()) |
51 return err |
56 return err |
52 } |
57 } |
53 |
58 |
54 // Unmarshal parses the wire-format message in b and places the result in m. |
59 // Unmarshal parses the wire-format message in b and places the result in m. |
55 // The provided message must be mutable (e.g., a non-nil pointer to a message). |
60 // The provided message must be mutable (e.g., a non-nil pointer to a message). |
56 func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error { |
61 func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error { |
|
62 if o.RecursionLimit == 0 { |
|
63 o.RecursionLimit = protowire.DefaultRecursionLimit |
|
64 } |
57 _, err := o.unmarshal(b, m.ProtoReflect()) |
65 _, err := o.unmarshal(b, m.ProtoReflect()) |
58 return err |
66 return err |
59 } |
67 } |
60 |
68 |
61 // UnmarshalState parses a wire-format message and places the result in m. |
69 // UnmarshalState parses a wire-format message and places the result in m. |
62 // |
70 // |
63 // This method permits fine-grained control over the unmarshaler. |
71 // This method permits fine-grained control over the unmarshaler. |
64 // Most users should use Unmarshal instead. |
72 // Most users should use Unmarshal instead. |
65 func (o UnmarshalOptions) UnmarshalState(in protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { |
73 func (o UnmarshalOptions) UnmarshalState(in protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { |
|
74 if o.RecursionLimit == 0 { |
|
75 o.RecursionLimit = protowire.DefaultRecursionLimit |
|
76 } |
66 return o.unmarshal(in.Buf, in.Message) |
77 return o.unmarshal(in.Buf, in.Message) |
67 } |
78 } |
68 |
79 |
69 // unmarshal is a centralized function that all unmarshal operations go through. |
80 // unmarshal is a centralized function that all unmarshal operations go through. |
70 // For profiling purposes, avoid changing the name of this function or |
81 // For profiling purposes, avoid changing the name of this function or |
84 !(o.DiscardUnknown && methods.Flags&protoiface.SupportUnmarshalDiscardUnknown == 0) { |
95 !(o.DiscardUnknown && methods.Flags&protoiface.SupportUnmarshalDiscardUnknown == 0) { |
85 in := protoiface.UnmarshalInput{ |
96 in := protoiface.UnmarshalInput{ |
86 Message: m, |
97 Message: m, |
87 Buf: b, |
98 Buf: b, |
88 Resolver: o.Resolver, |
99 Resolver: o.Resolver, |
|
100 Depth: o.RecursionLimit, |
89 } |
101 } |
90 if o.DiscardUnknown { |
102 if o.DiscardUnknown { |
91 in.Flags |= protoiface.UnmarshalDiscardUnknown |
103 in.Flags |= protoiface.UnmarshalDiscardUnknown |
92 } |
104 } |
93 out, err = methods.Unmarshal(in) |
105 out, err = methods.Unmarshal(in) |
94 } else { |
106 } else { |
|
107 o.RecursionLimit-- |
|
108 if o.RecursionLimit < 0 { |
|
109 return out, errors.New("exceeded max recursion depth") |
|
110 } |
95 err = o.unmarshalMessageSlow(b, m) |
111 err = o.unmarshalMessageSlow(b, m) |
96 } |
112 } |
97 if err != nil { |
113 if err != nil { |
98 return out, err |
114 return out, err |
99 } |
115 } |