Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ProtobufCS/0.9.1/ProtobufCS/src/ProtocolBuffers/ExtensionRegistry.cs @ 4068

Last change on this file since 4068 was 4068, checked in by swagner, 14 years ago

Sorted usings and removed unused usings in entire solution (#1094)

File size: 10.0 KB
Line 
1#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;
36using System.Collections.Generic;
37using Google.ProtocolBuffers.Descriptors;
38
39namespace Google.ProtocolBuffers {
40  /// <summary>
41  /// A table of known extensions, searchable by name or field number.  When
42  /// parsing a protocol message that might have extensions, you must provide
43  /// an <see cref="ExtensionRegistry"/> in which you have registered any extensions
44  /// that you want to be able to parse.  Otherwise, those extensions will just
45  /// be treated like unknown fields.
46  /// </summary>
47  /// <example>
48  /// For example, if you had the <c>.proto</c> file:
49  /// <code>
50  /// option java_class = "MyProto";
51  ///
52  /// message Foo {
53  ///   extensions 1000 to max;
54  /// }
55  ///
56  /// extend Foo {
57  ///   optional int32 bar;
58  /// }
59  /// </code>
60  ///
61  /// Then you might write code like:
62  ///
63  /// <code>
64  /// ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
65  /// registry.Add(MyProto.Bar);
66  /// MyProto.Foo message = MyProto.Foo.ParseFrom(input, registry);
67  /// </code>
68  /// </example>
69  ///
70  /// <remarks>
71  /// <para>You might wonder why this is necessary. Two alternatives might come to
72  /// mind. First, you might imagine a system where generated extensions are
73  /// automatically registered when their containing classes are loaded. This
74  /// is a popular technique, but is bad design; among other things, it creates a
75  /// situation where behavior can change depending on what classes happen to be
76  /// loaded. It also introduces a security vulnerability, because an
77  /// unprivileged class could cause its code to be called unexpectedly from a
78  /// privileged class by registering itself as an extension of the right type.
79  /// </para>
80  /// <para>Another option you might consider is lazy parsing: do not parse an
81  /// extension until it is first requested, at which point the caller must
82  /// provide a type to use. This introduces a different set of problems. First,
83  /// it would require a mutex lock any time an extension was accessed, which
84  /// would be slow. Second, corrupt data would not be detected until first
85  /// access, at which point it would be much harder to deal with it. Third, it
86  /// could violate the expectation that message objects are immutable, since the
87  /// type provided could be any arbitrary message class. An unprivileged user
88  /// could take advantage of this to inject a mutable object into a message
89  /// belonging to privileged code and create mischief.</para>
90  /// </remarks>
91  public sealed class ExtensionRegistry {
92
93    private static readonly ExtensionRegistry empty = new ExtensionRegistry(
94        new Dictionary<string, ExtensionInfo>(),
95        new Dictionary<DescriptorIntPair, ExtensionInfo>(),
96        true);
97
98    private readonly IDictionary<string, ExtensionInfo> extensionsByName;
99    private readonly IDictionary<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
100    private readonly bool readOnly;
101
102    private ExtensionRegistry(IDictionary<String, ExtensionInfo> extensionsByName,
103        IDictionary<DescriptorIntPair, ExtensionInfo> extensionsByNumber,
104        bool readOnly) {
105      this.extensionsByName = extensionsByName;
106      this.extensionsByNumber = extensionsByNumber;
107      this.readOnly = readOnly;
108    }
109
110    /// <summary>
111    /// Construct a new, empty instance.
112    /// </summary>
113    public static ExtensionRegistry CreateInstance() {
114      return new ExtensionRegistry(new Dictionary<string, ExtensionInfo>(),
115        new Dictionary<DescriptorIntPair, ExtensionInfo>(), false);
116    }
117
118    /// <summary>
119    /// Get the unmodifiable singleton empty instance.
120    /// </summary>
121    public static ExtensionRegistry Empty {
122      get { return empty; }
123    }
124
125    public ExtensionRegistry AsReadOnly() {
126      return new ExtensionRegistry(extensionsByName, extensionsByNumber, true);
127    }
128
129    /// <summary>
130    /// Finds an extension by fully-qualified field name, in the
131    /// proto namespace, i.e. result.Descriptor.FullName will match
132    /// <paramref name="fullName"/> if a match is found. A null
133    /// reference is returned if the extension can't be found.
134    /// </summary>
135    public ExtensionInfo this[string fullName] {
136      get {
137        ExtensionInfo ret;
138        extensionsByName.TryGetValue(fullName, out ret);
139        return ret;
140      }
141    }
142
143    /// <summary>
144    /// Finds an extension by containing type and field number.
145    /// A null reference is returned if the extension can't be found.
146    /// </summary>
147    public ExtensionInfo this[MessageDescriptor containingType, int fieldNumber] {
148      get {
149        ExtensionInfo ret;
150        extensionsByNumber.TryGetValue(new DescriptorIntPair(containingType, fieldNumber), out ret);
151        return ret;
152      }
153    }
154
155    /// <summary>
156    /// Add an extension from a generated file to the registry.
157    /// </summary>
158    public void Add<TExtension>(GeneratedExtensionBase<TExtension> extension) {
159      if (extension.Descriptor.MappedType == MappedType.Message) {
160        Add(new ExtensionInfo(extension.Descriptor, extension.MessageDefaultInstance));
161      } else {
162        Add(new ExtensionInfo(extension.Descriptor, null));
163      }
164    }
165
166    /// <summary>
167    /// Adds a non-message-type extension to the registry by descriptor.
168    /// </summary>
169    /// <param name="type"></param>
170    public void Add(FieldDescriptor type) {
171      if (type.MappedType == MappedType.Message) {
172        throw new ArgumentException("ExtensionRegistry.Add() must be provided a default instance "
173            + "when adding an embedded message extension.");
174      }
175      Add(new ExtensionInfo(type, null));
176    }
177
178    /// <summary>
179    /// Adds a message-type-extension to the registry by descriptor.
180    /// </summary>
181    /// <param name="type"></param>
182    /// <param name="defaultInstance"></param>
183    public void Add(FieldDescriptor type, IMessage defaultInstance) {
184      if (type.MappedType != MappedType.Message) {
185        throw new ArgumentException("ExtensionRegistry.Add() provided a default instance for a "
186            + "non-message extension.");
187      }
188      Add(new ExtensionInfo(type, defaultInstance));
189    }
190
191    private void Add(ExtensionInfo extension) {
192      if (readOnly) {
193        throw new InvalidOperationException("Cannot add entries to a read-only extension registry");
194      }
195      if (!extension.Descriptor.IsExtension) {
196        throw new ArgumentException("ExtensionRegistry.add() was given a FieldDescriptor for a "
197            + "regular (non-extension) field.");
198      }
199
200      extensionsByName[extension.Descriptor.FullName] = extension;
201      extensionsByNumber[new DescriptorIntPair(extension.Descriptor.ContainingType,
202          extension.Descriptor.FieldNumber)] = extension;
203
204      FieldDescriptor field = extension.Descriptor;
205      if (field.ContainingType.Options.MessageSetWireFormat
206          && field.FieldType == FieldType.Message
207          && field.IsOptional
208          && field.ExtensionScope == field.MessageType) {
209        // This is an extension of a MessageSet type defined within the extension
210        // type's own scope. For backwards-compatibility, allow it to be looked
211        // up by type name.
212        extensionsByName[field.MessageType.FullName] = extension;
213      }
214    }
215
216    /// <summary>
217    /// Nested type just used to represent a pair of MessageDescriptor and int, as
218    /// the key into the "by number" map.
219    /// </summary>
220    private struct DescriptorIntPair : IEquatable<DescriptorIntPair> {
221      readonly MessageDescriptor descriptor;
222      readonly int number;
223
224      internal DescriptorIntPair(MessageDescriptor descriptor, int number) {
225        this.descriptor = descriptor;
226        this.number = number;
227      }
228
229      public override int GetHashCode() {
230        return descriptor.GetHashCode() * ((1 << 16) - 1) + number;
231      }
232
233      public override bool Equals(object obj) {
234        if (!(obj is DescriptorIntPair)) {
235          return false;
236        }
237        return Equals((DescriptorIntPair)obj);
238      }
239
240      public bool Equals(DescriptorIntPair other) {
241        return descriptor == other.descriptor && number == other.number;
242      }
243    }
244  }
245}
Note: See TracBrowser for help on using the repository browser.