| OLD | NEW |
| (Empty) | |
| 1 #region Copyright notice and license |
| 2 // Protocol Buffers - Google's data interchange format |
| 3 // Copyright 2008 Google Inc. All rights reserved. |
| 4 // https://developers.google.com/protocol-buffers/ |
| 5 // |
| 6 // Redistribution and use in source and binary forms, with or without |
| 7 // modification, are permitted provided that the following conditions are |
| 8 // met: |
| 9 // |
| 10 // * Redistributions of source code must retain the above copyright |
| 11 // notice, this list of conditions and the following disclaimer. |
| 12 // * Redistributions in binary form must reproduce the above |
| 13 // copyright notice, this list of conditions and the following disclaimer |
| 14 // in the documentation and/or other materials provided with the |
| 15 // distribution. |
| 16 // * Neither the name of Google Inc. nor the names of its |
| 17 // contributors may be used to endorse or promote products derived from |
| 18 // this software without specific prior written permission. |
| 19 // |
| 20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 #endregion |
| 32 |
| 33 using System; |
| 34 using System.Collections.Generic; |
| 35 using System.Collections.ObjectModel; |
| 36 |
| 37 namespace Google.Protobuf.Reflection |
| 38 { |
| 39 /// <summary> |
| 40 /// Describes a .proto file, including everything defined within. |
| 41 /// IDescriptor is implemented such that the File property returns this desc
riptor, |
| 42 /// and the FullName is the same as the Name. |
| 43 /// </summary> |
| 44 public sealed class FileDescriptor : IDescriptor |
| 45 { |
| 46 private readonly ByteString descriptorData; |
| 47 private readonly FileDescriptorProto proto; |
| 48 private readonly IList<MessageDescriptor> messageTypes; |
| 49 private readonly IList<EnumDescriptor> enumTypes; |
| 50 private readonly IList<ServiceDescriptor> services; |
| 51 private readonly IList<FileDescriptor> dependencies; |
| 52 private readonly IList<FileDescriptor> publicDependencies; |
| 53 private readonly DescriptorPool pool; |
| 54 |
| 55 private FileDescriptor(ByteString descriptorData, FileDescriptorProto pr
oto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDepend
encies, GeneratedCodeInfo generatedCodeInfo) |
| 56 { |
| 57 this.descriptorData = descriptorData; |
| 58 this.pool = pool; |
| 59 this.proto = proto; |
| 60 this.dependencies = new ReadOnlyCollection<FileDescriptor>((FileDesc
riptor[]) dependencies.Clone()); |
| 61 |
| 62 publicDependencies = DeterminePublicDependencies(this, proto, depend
encies, allowUnknownDependencies); |
| 63 |
| 64 pool.AddPackage(Package, this); |
| 65 |
| 66 messageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageTy
pe, |
| 67 (message, index
) => |
| 68 new MessageDesc
riptor(message, this, null, index, generatedCodeInfo == null ? null : generatedC
odeInfo.NestedTypes[index])); |
| 69 |
| 70 enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType, |
| 71 (enumType, index)
=> |
| 72 new EnumDescriptor
(enumType, this, null, index, generatedCodeInfo == null ? null : generatedCodeIn
fo.NestedEnums[index])); |
| 73 |
| 74 services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service, |
| 75 (service, index) => |
| 76 new ServiceDescript
or(service, this, index)); |
| 77 } |
| 78 |
| 79 /// <summary> |
| 80 /// Computes the full name of a descriptor within this file, with an opt
ional parent message. |
| 81 /// </summary> |
| 82 internal string ComputeFullName(MessageDescriptor parent, string name) |
| 83 { |
| 84 if (parent != null) |
| 85 { |
| 86 return parent.FullName + "." + name; |
| 87 } |
| 88 if (Package.Length > 0) |
| 89 { |
| 90 return Package + "." + name; |
| 91 } |
| 92 return name; |
| 93 } |
| 94 |
| 95 /// <summary> |
| 96 /// Extracts public dependencies from direct dependencies. This is a sta
tic method despite its |
| 97 /// first parameter, as the value we're in the middle of constructing is
only used for exceptions. |
| 98 /// </summary> |
| 99 private static IList<FileDescriptor> DeterminePublicDependencies(FileDes
criptor @this, FileDescriptorProto proto, FileDescriptor[] dependencies, bool al
lowUnknownDependencies) |
| 100 { |
| 101 var nameToFileMap = new Dictionary<string, FileDescriptor>(); |
| 102 foreach (var file in dependencies) |
| 103 { |
| 104 nameToFileMap[file.Name] = file; |
| 105 } |
| 106 var publicDependencies = new List<FileDescriptor>(); |
| 107 for (int i = 0; i < proto.PublicDependency.Count; i++) |
| 108 { |
| 109 int index = proto.PublicDependency[i]; |
| 110 if (index < 0 || index >= proto.Dependency.Count) |
| 111 { |
| 112 throw new DescriptorValidationException(@this, "Invalid publ
ic dependency index."); |
| 113 } |
| 114 string name = proto.Dependency[index]; |
| 115 FileDescriptor file = nameToFileMap[name]; |
| 116 if (file == null) |
| 117 { |
| 118 if (!allowUnknownDependencies) |
| 119 { |
| 120 throw new DescriptorValidationException(@this, "Invalid
public dependency: " + name); |
| 121 } |
| 122 // Ignore unknown dependencies. |
| 123 } |
| 124 else |
| 125 { |
| 126 publicDependencies.Add(file); |
| 127 } |
| 128 } |
| 129 return new ReadOnlyCollection<FileDescriptor>(publicDependencies); |
| 130 } |
| 131 |
| 132 /// <value> |
| 133 /// The descriptor in its protocol message representation. |
| 134 /// </value> |
| 135 internal FileDescriptorProto Proto |
| 136 { |
| 137 get { return proto; } |
| 138 } |
| 139 |
| 140 /// <value> |
| 141 /// The file name. |
| 142 /// </value> |
| 143 public string Name |
| 144 { |
| 145 get { return proto.Name; } |
| 146 } |
| 147 |
| 148 /// <summary> |
| 149 /// The package as declared in the .proto file. This may or may not |
| 150 /// be equivalent to the .NET namespace of the generated classes. |
| 151 /// </summary> |
| 152 public string Package |
| 153 { |
| 154 get { return proto.Package; } |
| 155 } |
| 156 |
| 157 /// <value> |
| 158 /// Unmodifiable list of top-level message types declared in this file. |
| 159 /// </value> |
| 160 public IList<MessageDescriptor> MessageTypes |
| 161 { |
| 162 get { return messageTypes; } |
| 163 } |
| 164 |
| 165 /// <value> |
| 166 /// Unmodifiable list of top-level enum types declared in this file. |
| 167 /// </value> |
| 168 public IList<EnumDescriptor> EnumTypes |
| 169 { |
| 170 get { return enumTypes; } |
| 171 } |
| 172 |
| 173 /// <value> |
| 174 /// Unmodifiable list of top-level services declared in this file. |
| 175 /// </value> |
| 176 public IList<ServiceDescriptor> Services |
| 177 { |
| 178 get { return services; } |
| 179 } |
| 180 |
| 181 /// <value> |
| 182 /// Unmodifiable list of this file's dependencies (imports). |
| 183 /// </value> |
| 184 public IList<FileDescriptor> Dependencies |
| 185 { |
| 186 get { return dependencies; } |
| 187 } |
| 188 |
| 189 /// <value> |
| 190 /// Unmodifiable list of this file's public dependencies (public imports
). |
| 191 /// </value> |
| 192 public IList<FileDescriptor> PublicDependencies |
| 193 { |
| 194 get { return publicDependencies; } |
| 195 } |
| 196 |
| 197 /// <value> |
| 198 /// The original serialized binary form of this descriptor. |
| 199 /// </value> |
| 200 public ByteString SerializedData |
| 201 { |
| 202 get { return descriptorData; } |
| 203 } |
| 204 |
| 205 /// <value> |
| 206 /// Implementation of IDescriptor.FullName - just returns the same as Na
me. |
| 207 /// </value> |
| 208 string IDescriptor.FullName |
| 209 { |
| 210 get { return Name; } |
| 211 } |
| 212 |
| 213 /// <value> |
| 214 /// Implementation of IDescriptor.File - just returns this descriptor. |
| 215 /// </value> |
| 216 FileDescriptor IDescriptor.File |
| 217 { |
| 218 get { return this; } |
| 219 } |
| 220 |
| 221 /// <value> |
| 222 /// Pool containing symbol descriptors. |
| 223 /// </value> |
| 224 internal DescriptorPool DescriptorPool |
| 225 { |
| 226 get { return pool; } |
| 227 } |
| 228 |
| 229 /// <summary> |
| 230 /// Finds a type (message, enum, service or extension) in the file by na
me. Does not find nested types. |
| 231 /// </summary> |
| 232 /// <param name="name">The unqualified type name to look for.</param> |
| 233 /// <typeparam name="T">The type of descriptor to look for</typeparam> |
| 234 /// <returns>The type's descriptor, or null if not found.</returns> |
| 235 public T FindTypeByName<T>(String name) |
| 236 where T : class, IDescriptor |
| 237 { |
| 238 // Don't allow looking up nested types. This will make optimization |
| 239 // easier later. |
| 240 if (name.IndexOf('.') != -1) |
| 241 { |
| 242 return null; |
| 243 } |
| 244 if (Package.Length > 0) |
| 245 { |
| 246 name = Package + "." + name; |
| 247 } |
| 248 T result = pool.FindSymbol<T>(name); |
| 249 if (result != null && result.File == this) |
| 250 { |
| 251 return result; |
| 252 } |
| 253 return null; |
| 254 } |
| 255 |
| 256 /// <summary> |
| 257 /// Builds a FileDescriptor from its protocol buffer representation. |
| 258 /// </summary> |
| 259 /// <param name="descriptorData">The original serialized descriptor data
. |
| 260 /// We have only limited proto2 support, so serializing FileDescriptorPr
oto |
| 261 /// would not necessarily give us this.</param> |
| 262 /// <param name="proto">The protocol message form of the FileDescriptor.
</param> |
| 263 /// <param name="dependencies">FileDescriptors corresponding to all of t
he |
| 264 /// file's dependencies, in the exact order listed in the .proto file. M
ay be null, |
| 265 /// in which case it is treated as an empty array.</param> |
| 266 /// <param name="allowUnknownDependencies">Whether unknown dependencies
are ignored (true) or cause an exception to be thrown (false).</param> |
| 267 /// <param name="generatedCodeInfo">Reflection information, if any. May
be null, specifically for non-generated code.</param> |
| 268 /// <exception cref="DescriptorValidationException">If <paramref name="p
roto"/> is not |
| 269 /// a valid descriptor. This can occur for a number of reasons, such as
a field |
| 270 /// having an undefined type or because two messages were defined with t
he same name.</exception> |
| 271 private static FileDescriptor BuildFrom(ByteString descriptorData, FileD
escriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependenci
es, GeneratedCodeInfo generatedCodeInfo) |
| 272 { |
| 273 // Building descriptors involves two steps: translating and linking. |
| 274 // In the translation step (implemented by FileDescriptor's |
| 275 // constructor), we build an object tree mirroring the |
| 276 // FileDescriptorProto's tree and put all of the descriptors into th
e |
| 277 // DescriptorPool's lookup tables. In the linking step, we look up
all |
| 278 // type references in the DescriptorPool, so that, for example, a |
| 279 // FieldDescriptor for an embedded message contains a pointer direct
ly |
| 280 // to the Descriptor for that message's type. We also detect undefi
ned |
| 281 // types in the linking step. |
| 282 if (dependencies == null) |
| 283 { |
| 284 dependencies = new FileDescriptor[0]; |
| 285 } |
| 286 |
| 287 DescriptorPool pool = new DescriptorPool(dependencies); |
| 288 FileDescriptor result = new FileDescriptor(descriptorData, proto, de
pendencies, pool, allowUnknownDependencies, generatedCodeInfo); |
| 289 |
| 290 // Validate that the dependencies we've been passed (as FileDescript
ors) are actually the ones we |
| 291 // need. |
| 292 if (dependencies.Length != proto.Dependency.Count) |
| 293 { |
| 294 throw new DescriptorValidationException(result, |
| 295 "Dependencies passed to
FileDescriptor.BuildFrom() don't match " + |
| 296 "those listed in the Fil
eDescriptorProto."); |
| 297 } |
| 298 for (int i = 0; i < proto.Dependency.Count; i++) |
| 299 { |
| 300 if (dependencies[i].Name != proto.Dependency[i]) |
| 301 { |
| 302 throw new DescriptorValidationException(result, |
| 303 "Dependencies passed
to FileDescriptor.BuildFrom() don't match " + |
| 304 "those listed in the
FileDescriptorProto."); |
| 305 } |
| 306 } |
| 307 |
| 308 result.CrossLink(); |
| 309 return result; |
| 310 } |
| 311 |
| 312 private void CrossLink() |
| 313 { |
| 314 foreach (MessageDescriptor message in messageTypes) |
| 315 { |
| 316 message.CrossLink(); |
| 317 } |
| 318 |
| 319 foreach (ServiceDescriptor service in services) |
| 320 { |
| 321 service.CrossLink(); |
| 322 } |
| 323 } |
| 324 |
| 325 /// <summary> |
| 326 /// Creates an instance for generated code. |
| 327 /// </summary> |
| 328 /// <remarks> |
| 329 /// The <paramref name="generatedCodeInfo"/> parameter should be null fo
r descriptors which don't correspond to |
| 330 /// generated types. Otherwise, it should be a <see cref="GeneratedCodeI
nfo"/> with nested types and nested |
| 331 /// enums corresponding to the types and enums contained within the file
descriptor. |
| 332 /// </remarks> |
| 333 public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descr
iptorData, |
| 334 FileDescript
or[] dependencies, |
| 335 GeneratedCod
eInfo generatedCodeInfo) |
| 336 { |
| 337 FileDescriptorProto proto; |
| 338 try |
| 339 { |
| 340 proto = FileDescriptorProto.Parser.ParseFrom(descriptorData); |
| 341 } |
| 342 catch (InvalidProtocolBufferException e) |
| 343 { |
| 344 throw new ArgumentException("Failed to parse protocol buffer des
criptor for generated code.", e); |
| 345 } |
| 346 |
| 347 |
| 348 |
| 349 try |
| 350 { |
| 351 // When building descriptors for generated code, we allow unknow
n |
| 352 // dependencies by default. |
| 353 return BuildFrom(ByteString.CopyFrom(descriptorData), proto, dep
endencies, true, generatedCodeInfo); |
| 354 } |
| 355 catch (DescriptorValidationException e) |
| 356 { |
| 357 throw new ArgumentException("Invalid embedded descriptor for \""
+ proto.Name + "\".", e); |
| 358 } |
| 359 } |
| 360 |
| 361 /// <summary> |
| 362 /// Returns a <see cref="System.String" /> that represents this instance
. |
| 363 /// </summary> |
| 364 /// <returns> |
| 365 /// A <see cref="System.String" /> that represents this instance. |
| 366 /// </returns> |
| 367 public override string ToString() |
| 368 { |
| 369 return "FileDescriptor for " + proto.Name; |
| 370 } |
| 371 } |
| 372 } |
| OLD | NEW |