|
|
@ -19,8 +19,56 @@ using System; |
|
|
|
|
|
|
|
|
|
|
|
namespace Google.ProtocolBuffers { |
|
|
|
namespace Google.ProtocolBuffers { |
|
|
|
/// <summary> |
|
|
|
/// <summary> |
|
|
|
/// TODO(jonskeet): Copy docs from Java |
|
|
|
/// A table of known extensions, searchable by name or field number. When |
|
|
|
|
|
|
|
/// parsing a protocol message that might have extensions, you must provide |
|
|
|
|
|
|
|
/// an <see cref="ExtensionRegistry"/> in which you have registered any extensions |
|
|
|
|
|
|
|
/// that you want to be able to parse. Otherwise, those extensions will just |
|
|
|
|
|
|
|
/// be treated like unknown fields. |
|
|
|
/// </summary> |
|
|
|
/// </summary> |
|
|
|
|
|
|
|
/// <example> |
|
|
|
|
|
|
|
/// For example, if you had the <c>.proto</c> file: |
|
|
|
|
|
|
|
/// <code> |
|
|
|
|
|
|
|
/// option java_class = "MyProto"; |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// message Foo { |
|
|
|
|
|
|
|
/// extensions 1000 to max; |
|
|
|
|
|
|
|
/// } |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// extend Foo { |
|
|
|
|
|
|
|
/// optional int32 bar; |
|
|
|
|
|
|
|
/// } |
|
|
|
|
|
|
|
/// </code> |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// Then you might write code like: |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// <code> |
|
|
|
|
|
|
|
/// ExtensionRegistry registry = ExtensionRegistry.CreateInstance(); |
|
|
|
|
|
|
|
/// registry.Add(MyProto.Bar); |
|
|
|
|
|
|
|
/// MyProto.Foo message = MyProto.Foo.ParseFrom(input, registry); |
|
|
|
|
|
|
|
/// </code> |
|
|
|
|
|
|
|
/// </example> |
|
|
|
|
|
|
|
/// |
|
|
|
|
|
|
|
/// <remarks> |
|
|
|
|
|
|
|
/// <para>You might wonder why this is necessary. Two alternatives might come to |
|
|
|
|
|
|
|
/// mind. First, you might imagine a system where generated extensions are |
|
|
|
|
|
|
|
/// automatically registered when their containing classes are loaded. This |
|
|
|
|
|
|
|
/// is a popular technique, but is bad design; among other things, it creates a |
|
|
|
|
|
|
|
/// situation where behavior can change depending on what classes happen to be |
|
|
|
|
|
|
|
/// loaded. It also introduces a security vulnerability, because an |
|
|
|
|
|
|
|
/// unprivileged class could cause its code to be called unexpectedly from a |
|
|
|
|
|
|
|
/// privileged class by registering itself as an extension of the right type. |
|
|
|
|
|
|
|
/// </para> |
|
|
|
|
|
|
|
/// <para>Another option you might consider is lazy parsing: do not parse an |
|
|
|
|
|
|
|
/// extension until it is first requested, at which point the caller must |
|
|
|
|
|
|
|
/// provide a type to use. This introduces a different set of problems. First, |
|
|
|
|
|
|
|
/// it would require a mutex lock any time an extension was accessed, which |
|
|
|
|
|
|
|
/// would be slow. Second, corrupt data would not be detected until first |
|
|
|
|
|
|
|
/// access, at which point it would be much harder to deal with it. Third, it |
|
|
|
|
|
|
|
/// could violate the expectation that message objects are immutable, since the |
|
|
|
|
|
|
|
/// type provided could be any arbitrary message class. An unprivileged user |
|
|
|
|
|
|
|
/// could take advantage of this to inject a mutable object into a message |
|
|
|
|
|
|
|
/// belonging to privileged code and create mischief.</para> |
|
|
|
|
|
|
|
/// </remarks> |
|
|
|
public sealed class ExtensionRegistry { |
|
|
|
public sealed class ExtensionRegistry { |
|
|
|
|
|
|
|
|
|
|
|
private static readonly ExtensionRegistry empty = new ExtensionRegistry( |
|
|
|
private static readonly ExtensionRegistry empty = new ExtensionRegistry( |
|
|
@ -140,7 +188,7 @@ namespace Google.ProtocolBuffers { |
|
|
|
&& field.IsOptional |
|
|
|
&& field.IsOptional |
|
|
|
&& field.ExtensionScope == field.MessageType) { |
|
|
|
&& field.ExtensionScope == field.MessageType) { |
|
|
|
// This is an extension of a MessageSet type defined within the extension |
|
|
|
// This is an extension of a MessageSet type defined within the extension |
|
|
|
// type's own scope. For backwards-compatibility, allow it to be looked |
|
|
|
// type's own scope. For backwards-compatibility, allow it to be looked |
|
|
|
// up by type name. |
|
|
|
// up by type name. |
|
|
|
extensionsByName[field.MessageType.FullName] = extension; |
|
|
|
extensionsByName[field.MessageType.FullName] = extension; |
|
|
|
} |
|
|
|
} |
|
|
|