blob: 8518cd108341de7cb83a8e6c52e118887c8b4454 [file] [log] [blame]
csharptestc07571a2010-11-04 14:25:56 -05001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
6// http://code.google.com/p/protobuf/
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11//
12// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
21//
22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33#endregion
34
35using System.Collections.Generic;
csharptestc07571a2010-11-04 14:25:56 -050036using System;
37
38namespace Google.ProtocolBuffers {
csharptestd9c59e62010-11-04 19:36:28 -050039
40
csharptestc07571a2010-11-04 14:25:56 -050041 /// <summary>
42 /// A table of known extensions, searchable by name or field number. When
43 /// parsing a protocol message that might have extensions, you must provide
csharptestd9c59e62010-11-04 19:36:28 -050044 /// an <see cref="ExtensionRegistryLite"/> in which you have registered any extensions
csharptestc07571a2010-11-04 14:25:56 -050045 /// that you want to be able to parse. Otherwise, those extensions will just
46 /// be treated like unknown fields.
47 /// </summary>
48 /// <example>
49 /// For example, if you had the <c>.proto</c> file:
50 /// <code>
51 /// option java_class = "MyProto";
52 ///
53 /// message Foo {
54 /// extensions 1000 to max;
55 /// }
56 ///
57 /// extend Foo {
58 /// optional int32 bar;
59 /// }
60 /// </code>
61 ///
62 /// Then you might write code like:
63 ///
64 /// <code>
csharptestd9c59e62010-11-04 19:36:28 -050065 /// ExtensionRegistryLite registry = ExtensionRegistryLite.CreateInstance();
csharptestc07571a2010-11-04 14:25:56 -050066 /// registry.Add(MyProto.Bar);
67 /// MyProto.Foo message = MyProto.Foo.ParseFrom(input, registry);
68 /// </code>
69 /// </example>
70 ///
71 /// <remarks>
72 /// <para>You might wonder why this is necessary. Two alternatives might come to
73 /// mind. First, you might imagine a system where generated extensions are
74 /// automatically registered when their containing classes are loaded. This
75 /// is a popular technique, but is bad design; among other things, it creates a
76 /// situation where behavior can change depending on what classes happen to be
77 /// loaded. It also introduces a security vulnerability, because an
78 /// unprivileged class could cause its code to be called unexpectedly from a
79 /// privileged class by registering itself as an extension of the right type.
80 /// </para>
81 /// <para>Another option you might consider is lazy parsing: do not parse an
82 /// extension until it is first requested, at which point the caller must
83 /// provide a type to use. This introduces a different set of problems. First,
84 /// it would require a mutex lock any time an extension was accessed, which
85 /// would be slow. Second, corrupt data would not be detected until first
86 /// access, at which point it would be much harder to deal with it. Third, it
87 /// could violate the expectation that message objects are immutable, since the
88 /// type provided could be any arbitrary message class. An unprivileged user
89 /// could take advantage of this to inject a mutable object into a message
90 /// belonging to privileged code and create mischief.</para>
91 /// </remarks>
csharptestd9c59e62010-11-04 19:36:28 -050092 public class ExtensionRegistryLite {
csharptestc07571a2010-11-04 14:25:56 -050093
csharptestd9c59e62010-11-04 19:36:28 -050094 private static readonly ExtensionRegistryLite empty = new ExtensionRegistryLite(
95 new Dictionary<ExtensionIntPair, IGeneratedExtensionLite>(),
csharptestc07571a2010-11-04 14:25:56 -050096 true);
97
csharptestd9c59e62010-11-04 19:36:28 -050098 protected readonly IDictionary<ExtensionIntPair, IGeneratedExtensionLite> extensionsByNumber;
99 protected readonly bool readOnly;
csharptestc07571a2010-11-04 14:25:56 -0500100
csharptestd9c59e62010-11-04 19:36:28 -0500101 protected ExtensionRegistryLite(IDictionary<ExtensionIntPair, IGeneratedExtensionLite> extensionsByNumber,
csharptestc07571a2010-11-04 14:25:56 -0500102 bool readOnly) {
csharptestc07571a2010-11-04 14:25:56 -0500103 this.extensionsByNumber = extensionsByNumber;
104 this.readOnly = readOnly;
105 }
csharptest6b812f82010-11-05 11:06:13 -0500106#if LITE
csharptestc07571a2010-11-04 14:25:56 -0500107 /// <summary>
108 /// Construct a new, empty instance.
109 /// </summary>
csharptestd9c59e62010-11-04 19:36:28 -0500110 public static ExtensionRegistryLite CreateInstance() {
111 return new ExtensionRegistryLite(
112 new Dictionary<ExtensionIntPair, IGeneratedExtensionLite>(), false);
csharptestc07571a2010-11-04 14:25:56 -0500113 }
114
115 /// <summary>
116 /// Get the unmodifiable singleton empty instance.
117 /// </summary>
csharptestd9c59e62010-11-04 19:36:28 -0500118 public static ExtensionRegistryLite Empty {
csharptestc07571a2010-11-04 14:25:56 -0500119 get { return empty; }
120 }
csharptest6b812f82010-11-05 11:06:13 -0500121#endif
csharptestdce2b9d2010-11-04 19:57:23 -0500122 public ExtensionRegistryLite AsReadOnly() {
123 return MakeReadOnly();
124 }
125
126 protected virtual ExtensionRegistryLite MakeReadOnly() {
csharptestd9c59e62010-11-04 19:36:28 -0500127 return new ExtensionRegistryLite(extensionsByNumber, true);
csharptestc07571a2010-11-04 14:25:56 -0500128 }
129
130 /// <summary>
131 /// Finds an extension by containing type and field number.
132 /// A null reference is returned if the extension can't be found.
133 /// </summary>
csharptestd9c59e62010-11-04 19:36:28 -0500134 public IGeneratedExtensionLite this[IMessageLite containingType, int fieldNumber] {
csharptestc07571a2010-11-04 14:25:56 -0500135 get {
csharptestd9c59e62010-11-04 19:36:28 -0500136 IGeneratedExtensionLite ret;
137 extensionsByNumber.TryGetValue(new ExtensionIntPair(containingType, fieldNumber), out ret);
csharptestc07571a2010-11-04 14:25:56 -0500138 return ret;
139 }
140 }
141
142 /// <summary>
143 /// Add an extension from a generated file to the registry.
144 /// </summary>
csharptestd9c59e62010-11-04 19:36:28 -0500145 public virtual void Add(IGeneratedExtensionLite extension) {
csharptestc07571a2010-11-04 14:25:56 -0500146 if (readOnly) {
147 throw new InvalidOperationException("Cannot add entries to a read-only extension registry");
148 }
csharptestd9c59e62010-11-04 19:36:28 -0500149 extensionsByNumber.Add(
150 new ExtensionIntPair(extension.ContainingType, extension.Number),
151 extension);
csharptestc07571a2010-11-04 14:25:56 -0500152 }
153
154 /// <summary>
155 /// Nested type just used to represent a pair of MessageDescriptor and int, as
156 /// the key into the "by number" map.
157 /// </summary>
csharptestd9c59e62010-11-04 19:36:28 -0500158 protected struct ExtensionIntPair : IEquatable<ExtensionIntPair> {
159 readonly object msgType;
csharptestc07571a2010-11-04 14:25:56 -0500160 readonly int number;
161
csharptestd9c59e62010-11-04 19:36:28 -0500162 internal ExtensionIntPair(object msgType, int number) {
163 this.msgType = msgType;
csharptestc07571a2010-11-04 14:25:56 -0500164 this.number = number;
165 }
166
167 public override int GetHashCode() {
csharptestd9c59e62010-11-04 19:36:28 -0500168 return msgType.GetHashCode() * ((1 << 16) - 1) + number;
csharptestc07571a2010-11-04 14:25:56 -0500169 }
170
171 public override bool Equals(object obj) {
csharptestd9c59e62010-11-04 19:36:28 -0500172 if (!(obj is ExtensionIntPair)) {
csharptestc07571a2010-11-04 14:25:56 -0500173 return false;
174 }
csharptestd9c59e62010-11-04 19:36:28 -0500175 return Equals((ExtensionIntPair)obj);
csharptestc07571a2010-11-04 14:25:56 -0500176 }
177
csharptestd9c59e62010-11-04 19:36:28 -0500178 public bool Equals(ExtensionIntPair other) {
179 return msgType.Equals(other.msgType) && number == other.number;
csharptestc07571a2010-11-04 14:25:56 -0500180 }
181 }
182 }
183}