1ffe3c632Sopenharmony_ci#region Copyright notice and license 2ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format 3ffe3c632Sopenharmony_ci// Copyright 2008 Google Inc. All rights reserved. 4ffe3c632Sopenharmony_ci// https://developers.google.com/protocol-buffers/ 5ffe3c632Sopenharmony_ci// 6ffe3c632Sopenharmony_ci// Redistribution and use in source and binary forms, with or without 7ffe3c632Sopenharmony_ci// modification, are permitted provided that the following conditions are 8ffe3c632Sopenharmony_ci// met: 9ffe3c632Sopenharmony_ci// 10ffe3c632Sopenharmony_ci// * Redistributions of source code must retain the above copyright 11ffe3c632Sopenharmony_ci// notice, this list of conditions and the following disclaimer. 12ffe3c632Sopenharmony_ci// * Redistributions in binary form must reproduce the above 13ffe3c632Sopenharmony_ci// copyright notice, this list of conditions and the following disclaimer 14ffe3c632Sopenharmony_ci// in the documentation and/or other materials provided with the 15ffe3c632Sopenharmony_ci// distribution. 16ffe3c632Sopenharmony_ci// * Neither the name of Google Inc. nor the names of its 17ffe3c632Sopenharmony_ci// contributors may be used to endorse or promote products derived from 18ffe3c632Sopenharmony_ci// this software without specific prior written permission. 19ffe3c632Sopenharmony_ci// 20ffe3c632Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21ffe3c632Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22ffe3c632Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23ffe3c632Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24ffe3c632Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25ffe3c632Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26ffe3c632Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27ffe3c632Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28ffe3c632Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29ffe3c632Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30ffe3c632Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31ffe3c632Sopenharmony_ci#endregion 32ffe3c632Sopenharmony_ci 33ffe3c632Sopenharmony_ciusing Google.Protobuf.Collections; 34ffe3c632Sopenharmony_ciusing Google.Protobuf.WellKnownTypes; 35ffe3c632Sopenharmony_ciusing System; 36ffe3c632Sopenharmony_ciusing System.Collections.Generic; 37ffe3c632Sopenharmony_ciusing System.Collections.ObjectModel; 38ffe3c632Sopenharmony_ciusing System.Diagnostics; 39ffe3c632Sopenharmony_ciusing System.Linq; 40ffe3c632Sopenharmony_ciusing System.Threading; 41ffe3c632Sopenharmony_ciusing static Google.Protobuf.Reflection.SourceCodeInfo.Types; 42ffe3c632Sopenharmony_ci 43ffe3c632Sopenharmony_cinamespace Google.Protobuf.Reflection 44ffe3c632Sopenharmony_ci{ 45ffe3c632Sopenharmony_ci /// <summary> 46ffe3c632Sopenharmony_ci /// The syntax of a .proto file 47ffe3c632Sopenharmony_ci /// </summary> 48ffe3c632Sopenharmony_ci public enum Syntax 49ffe3c632Sopenharmony_ci { 50ffe3c632Sopenharmony_ci /// <summary> 51ffe3c632Sopenharmony_ci /// Proto2 syntax 52ffe3c632Sopenharmony_ci /// </summary> 53ffe3c632Sopenharmony_ci Proto2, 54ffe3c632Sopenharmony_ci /// <summary> 55ffe3c632Sopenharmony_ci /// Proto3 syntax 56ffe3c632Sopenharmony_ci /// </summary> 57ffe3c632Sopenharmony_ci Proto3, 58ffe3c632Sopenharmony_ci /// <summary> 59ffe3c632Sopenharmony_ci /// An unknown declared syntax 60ffe3c632Sopenharmony_ci /// </summary> 61ffe3c632Sopenharmony_ci Unknown 62ffe3c632Sopenharmony_ci } 63ffe3c632Sopenharmony_ci 64ffe3c632Sopenharmony_ci /// <summary> 65ffe3c632Sopenharmony_ci /// Describes a .proto file, including everything defined within. 66ffe3c632Sopenharmony_ci /// IDescriptor is implemented such that the File property returns this descriptor, 67ffe3c632Sopenharmony_ci /// and the FullName is the same as the Name. 68ffe3c632Sopenharmony_ci /// </summary> 69ffe3c632Sopenharmony_ci public sealed class FileDescriptor : IDescriptor 70ffe3c632Sopenharmony_ci { 71ffe3c632Sopenharmony_ci // Prevent linker failures when using IL2CPP with the well-known types. 72ffe3c632Sopenharmony_ci static FileDescriptor() 73ffe3c632Sopenharmony_ci { 74ffe3c632Sopenharmony_ci ForceReflectionInitialization<Syntax>(); 75ffe3c632Sopenharmony_ci ForceReflectionInitialization<NullValue>(); 76ffe3c632Sopenharmony_ci ForceReflectionInitialization<Field.Types.Cardinality>(); 77ffe3c632Sopenharmony_ci ForceReflectionInitialization<Field.Types.Kind>(); 78ffe3c632Sopenharmony_ci ForceReflectionInitialization<Value.KindOneofCase>(); 79ffe3c632Sopenharmony_ci } 80ffe3c632Sopenharmony_ci 81ffe3c632Sopenharmony_ci private readonly Lazy<Dictionary<IDescriptor, DescriptorDeclaration>> declarations; 82ffe3c632Sopenharmony_ci 83ffe3c632Sopenharmony_ci private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, IEnumerable<FileDescriptor> dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo) 84ffe3c632Sopenharmony_ci { 85ffe3c632Sopenharmony_ci SerializedData = descriptorData; 86ffe3c632Sopenharmony_ci DescriptorPool = pool; 87ffe3c632Sopenharmony_ci Proto = proto; 88ffe3c632Sopenharmony_ci Dependencies = new ReadOnlyCollection<FileDescriptor>(dependencies.ToList()); 89ffe3c632Sopenharmony_ci 90ffe3c632Sopenharmony_ci PublicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies); 91ffe3c632Sopenharmony_ci 92ffe3c632Sopenharmony_ci pool.AddPackage(Package, this); 93ffe3c632Sopenharmony_ci 94ffe3c632Sopenharmony_ci MessageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType, 95ffe3c632Sopenharmony_ci (message, index) => 96ffe3c632Sopenharmony_ci new MessageDescriptor(message, this, null, index, generatedCodeInfo?.NestedTypes[index])); 97ffe3c632Sopenharmony_ci 98ffe3c632Sopenharmony_ci EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType, 99ffe3c632Sopenharmony_ci (enumType, index) => 100ffe3c632Sopenharmony_ci new EnumDescriptor(enumType, this, null, index, generatedCodeInfo?.NestedEnums[index])); 101ffe3c632Sopenharmony_ci 102ffe3c632Sopenharmony_ci Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service, 103ffe3c632Sopenharmony_ci (service, index) => 104ffe3c632Sopenharmony_ci new ServiceDescriptor(service, this, index)); 105ffe3c632Sopenharmony_ci 106ffe3c632Sopenharmony_ci Extensions = new ExtensionCollection(this, generatedCodeInfo?.Extensions); 107ffe3c632Sopenharmony_ci 108ffe3c632Sopenharmony_ci declarations = new Lazy<Dictionary<IDescriptor, DescriptorDeclaration>>(CreateDeclarationMap, LazyThreadSafetyMode.ExecutionAndPublication); 109ffe3c632Sopenharmony_ci 110ffe3c632Sopenharmony_ci if (!proto.HasSyntax || proto.Syntax == "proto2") 111ffe3c632Sopenharmony_ci { 112ffe3c632Sopenharmony_ci Syntax = Syntax.Proto2; 113ffe3c632Sopenharmony_ci } 114ffe3c632Sopenharmony_ci else if (proto.Syntax == "proto3") 115ffe3c632Sopenharmony_ci { 116ffe3c632Sopenharmony_ci Syntax = Syntax.Proto3; 117ffe3c632Sopenharmony_ci } 118ffe3c632Sopenharmony_ci else 119ffe3c632Sopenharmony_ci { 120ffe3c632Sopenharmony_ci Syntax = Syntax.Unknown; 121ffe3c632Sopenharmony_ci } 122ffe3c632Sopenharmony_ci } 123ffe3c632Sopenharmony_ci 124ffe3c632Sopenharmony_ci private Dictionary<IDescriptor, DescriptorDeclaration> CreateDeclarationMap() 125ffe3c632Sopenharmony_ci { 126ffe3c632Sopenharmony_ci var dictionary = new Dictionary<IDescriptor, DescriptorDeclaration>(); 127ffe3c632Sopenharmony_ci foreach (var location in Proto.SourceCodeInfo?.Location ?? Enumerable.Empty<Location>()) 128ffe3c632Sopenharmony_ci { 129ffe3c632Sopenharmony_ci var descriptor = FindDescriptorForPath(location.Path); 130ffe3c632Sopenharmony_ci if (descriptor != null) 131ffe3c632Sopenharmony_ci { 132ffe3c632Sopenharmony_ci dictionary[descriptor] = DescriptorDeclaration.FromProto(descriptor, location); 133ffe3c632Sopenharmony_ci } 134ffe3c632Sopenharmony_ci } 135ffe3c632Sopenharmony_ci return dictionary; 136ffe3c632Sopenharmony_ci } 137ffe3c632Sopenharmony_ci 138ffe3c632Sopenharmony_ci private IDescriptor FindDescriptorForPath(IList<int> path) 139ffe3c632Sopenharmony_ci { 140ffe3c632Sopenharmony_ci // All complete declarations have an even, non-empty path length 141ffe3c632Sopenharmony_ci // (There can be an empty path for a descriptor declaration, but that can't have any comments, 142ffe3c632Sopenharmony_ci // so we currently ignore it.) 143ffe3c632Sopenharmony_ci if (path.Count == 0 || (path.Count & 1) != 0) 144ffe3c632Sopenharmony_ci { 145ffe3c632Sopenharmony_ci return null; 146ffe3c632Sopenharmony_ci } 147ffe3c632Sopenharmony_ci IReadOnlyList<DescriptorBase> topLevelList = GetNestedDescriptorListForField(path[0]); 148ffe3c632Sopenharmony_ci DescriptorBase current = GetDescriptorFromList(topLevelList, path[1]); 149ffe3c632Sopenharmony_ci 150ffe3c632Sopenharmony_ci for (int i = 2; current != null && i < path.Count; i += 2) 151ffe3c632Sopenharmony_ci { 152ffe3c632Sopenharmony_ci var list = current.GetNestedDescriptorListForField(path[i]); 153ffe3c632Sopenharmony_ci current = GetDescriptorFromList(list, path[i + 1]); 154ffe3c632Sopenharmony_ci } 155ffe3c632Sopenharmony_ci return current; 156ffe3c632Sopenharmony_ci } 157ffe3c632Sopenharmony_ci 158ffe3c632Sopenharmony_ci private DescriptorBase GetDescriptorFromList(IReadOnlyList<DescriptorBase> list, int index) 159ffe3c632Sopenharmony_ci { 160ffe3c632Sopenharmony_ci // This is fine: it may be a newer version of protobuf than we understand, with a new descriptor 161ffe3c632Sopenharmony_ci // field. 162ffe3c632Sopenharmony_ci if (list == null) 163ffe3c632Sopenharmony_ci { 164ffe3c632Sopenharmony_ci return null; 165ffe3c632Sopenharmony_ci } 166ffe3c632Sopenharmony_ci // We *could* return null to silently continue, but this is basically data corruption. 167ffe3c632Sopenharmony_ci if (index < 0 || index >= list.Count) 168ffe3c632Sopenharmony_ci { 169ffe3c632Sopenharmony_ci // We don't have much extra information to give at this point unfortunately. If this becomes a problem, 170ffe3c632Sopenharmony_ci // we can pass in the complete path and report that and the file name. 171ffe3c632Sopenharmony_ci throw new InvalidProtocolBufferException($"Invalid descriptor location path: index out of range"); 172ffe3c632Sopenharmony_ci } 173ffe3c632Sopenharmony_ci return list[index]; 174ffe3c632Sopenharmony_ci } 175ffe3c632Sopenharmony_ci 176ffe3c632Sopenharmony_ci private IReadOnlyList<DescriptorBase> GetNestedDescriptorListForField(int fieldNumber) 177ffe3c632Sopenharmony_ci { 178ffe3c632Sopenharmony_ci switch (fieldNumber) 179ffe3c632Sopenharmony_ci { 180ffe3c632Sopenharmony_ci case FileDescriptorProto.ServiceFieldNumber: 181ffe3c632Sopenharmony_ci return (IReadOnlyList<DescriptorBase>) Services; 182ffe3c632Sopenharmony_ci case FileDescriptorProto.MessageTypeFieldNumber: 183ffe3c632Sopenharmony_ci return (IReadOnlyList<DescriptorBase>) MessageTypes; 184ffe3c632Sopenharmony_ci case FileDescriptorProto.EnumTypeFieldNumber: 185ffe3c632Sopenharmony_ci return (IReadOnlyList<DescriptorBase>) EnumTypes; 186ffe3c632Sopenharmony_ci default: 187ffe3c632Sopenharmony_ci return null; 188ffe3c632Sopenharmony_ci } 189ffe3c632Sopenharmony_ci } 190ffe3c632Sopenharmony_ci 191ffe3c632Sopenharmony_ci internal DescriptorDeclaration GetDeclaration(IDescriptor descriptor) 192ffe3c632Sopenharmony_ci { 193ffe3c632Sopenharmony_ci DescriptorDeclaration declaration; 194ffe3c632Sopenharmony_ci declarations.Value.TryGetValue(descriptor, out declaration); 195ffe3c632Sopenharmony_ci return declaration; 196ffe3c632Sopenharmony_ci } 197ffe3c632Sopenharmony_ci 198ffe3c632Sopenharmony_ci /// <summary> 199ffe3c632Sopenharmony_ci /// Computes the full name of a descriptor within this file, with an optional parent message. 200ffe3c632Sopenharmony_ci /// </summary> 201ffe3c632Sopenharmony_ci internal string ComputeFullName(MessageDescriptor parent, string name) 202ffe3c632Sopenharmony_ci { 203ffe3c632Sopenharmony_ci if (parent != null) 204ffe3c632Sopenharmony_ci { 205ffe3c632Sopenharmony_ci return parent.FullName + "." + name; 206ffe3c632Sopenharmony_ci } 207ffe3c632Sopenharmony_ci if (Package.Length > 0) 208ffe3c632Sopenharmony_ci { 209ffe3c632Sopenharmony_ci return Package + "." + name; 210ffe3c632Sopenharmony_ci } 211ffe3c632Sopenharmony_ci return name; 212ffe3c632Sopenharmony_ci } 213ffe3c632Sopenharmony_ci 214ffe3c632Sopenharmony_ci /// <summary> 215ffe3c632Sopenharmony_ci /// Extracts public dependencies from direct dependencies. This is a static method despite its 216ffe3c632Sopenharmony_ci /// first parameter, as the value we're in the middle of constructing is only used for exceptions. 217ffe3c632Sopenharmony_ci /// </summary> 218ffe3c632Sopenharmony_ci private static IList<FileDescriptor> DeterminePublicDependencies(FileDescriptor @this, FileDescriptorProto proto, IEnumerable<FileDescriptor> dependencies, bool allowUnknownDependencies) 219ffe3c632Sopenharmony_ci { 220ffe3c632Sopenharmony_ci var nameToFileMap = dependencies.ToDictionary(file => file.Name); 221ffe3c632Sopenharmony_ci var publicDependencies = new List<FileDescriptor>(); 222ffe3c632Sopenharmony_ci for (int i = 0; i < proto.PublicDependency.Count; i++) 223ffe3c632Sopenharmony_ci { 224ffe3c632Sopenharmony_ci int index = proto.PublicDependency[i]; 225ffe3c632Sopenharmony_ci if (index < 0 || index >= proto.Dependency.Count) 226ffe3c632Sopenharmony_ci { 227ffe3c632Sopenharmony_ci throw new DescriptorValidationException(@this, "Invalid public dependency index."); 228ffe3c632Sopenharmony_ci } 229ffe3c632Sopenharmony_ci string name = proto.Dependency[index]; 230ffe3c632Sopenharmony_ci FileDescriptor file; 231ffe3c632Sopenharmony_ci if (!nameToFileMap.TryGetValue(name, out file)) 232ffe3c632Sopenharmony_ci { 233ffe3c632Sopenharmony_ci if (!allowUnknownDependencies) 234ffe3c632Sopenharmony_ci { 235ffe3c632Sopenharmony_ci throw new DescriptorValidationException(@this, "Invalid public dependency: " + name); 236ffe3c632Sopenharmony_ci } 237ffe3c632Sopenharmony_ci // Ignore unknown dependencies. 238ffe3c632Sopenharmony_ci } 239ffe3c632Sopenharmony_ci else 240ffe3c632Sopenharmony_ci { 241ffe3c632Sopenharmony_ci publicDependencies.Add(file); 242ffe3c632Sopenharmony_ci } 243ffe3c632Sopenharmony_ci } 244ffe3c632Sopenharmony_ci return new ReadOnlyCollection<FileDescriptor>(publicDependencies); 245ffe3c632Sopenharmony_ci } 246ffe3c632Sopenharmony_ci 247ffe3c632Sopenharmony_ci /// <value> 248ffe3c632Sopenharmony_ci /// The descriptor in its protocol message representation. 249ffe3c632Sopenharmony_ci /// </value> 250ffe3c632Sopenharmony_ci internal FileDescriptorProto Proto { get; } 251ffe3c632Sopenharmony_ci 252ffe3c632Sopenharmony_ci /// <summary> 253ffe3c632Sopenharmony_ci /// The syntax of the file 254ffe3c632Sopenharmony_ci /// </summary> 255ffe3c632Sopenharmony_ci public Syntax Syntax { get; } 256ffe3c632Sopenharmony_ci 257ffe3c632Sopenharmony_ci /// <value> 258ffe3c632Sopenharmony_ci /// The file name. 259ffe3c632Sopenharmony_ci /// </value> 260ffe3c632Sopenharmony_ci public string Name => Proto.Name; 261ffe3c632Sopenharmony_ci 262ffe3c632Sopenharmony_ci /// <summary> 263ffe3c632Sopenharmony_ci /// The package as declared in the .proto file. This may or may not 264ffe3c632Sopenharmony_ci /// be equivalent to the .NET namespace of the generated classes. 265ffe3c632Sopenharmony_ci /// </summary> 266ffe3c632Sopenharmony_ci public string Package => Proto.Package; 267ffe3c632Sopenharmony_ci 268ffe3c632Sopenharmony_ci /// <value> 269ffe3c632Sopenharmony_ci /// Unmodifiable list of top-level message types declared in this file. 270ffe3c632Sopenharmony_ci /// </value> 271ffe3c632Sopenharmony_ci public IList<MessageDescriptor> MessageTypes { get; } 272ffe3c632Sopenharmony_ci 273ffe3c632Sopenharmony_ci /// <value> 274ffe3c632Sopenharmony_ci /// Unmodifiable list of top-level enum types declared in this file. 275ffe3c632Sopenharmony_ci /// </value> 276ffe3c632Sopenharmony_ci public IList<EnumDescriptor> EnumTypes { get; } 277ffe3c632Sopenharmony_ci 278ffe3c632Sopenharmony_ci /// <value> 279ffe3c632Sopenharmony_ci /// Unmodifiable list of top-level services declared in this file. 280ffe3c632Sopenharmony_ci /// </value> 281ffe3c632Sopenharmony_ci public IList<ServiceDescriptor> Services { get; } 282ffe3c632Sopenharmony_ci 283ffe3c632Sopenharmony_ci /// <summary> 284ffe3c632Sopenharmony_ci /// Unmodifiable list of top-level extensions declared in this file. 285ffe3c632Sopenharmony_ci /// Note that some extensions may be incomplete (FieldDescriptor.Extension may be null) 286ffe3c632Sopenharmony_ci /// if this descriptor was generated using a version of protoc that did not fully 287ffe3c632Sopenharmony_ci /// support extensions in C#. 288ffe3c632Sopenharmony_ci /// </summary> 289ffe3c632Sopenharmony_ci public ExtensionCollection Extensions { get; } 290ffe3c632Sopenharmony_ci 291ffe3c632Sopenharmony_ci /// <value> 292ffe3c632Sopenharmony_ci /// Unmodifiable list of this file's dependencies (imports). 293ffe3c632Sopenharmony_ci /// </value> 294ffe3c632Sopenharmony_ci public IList<FileDescriptor> Dependencies { get; } 295ffe3c632Sopenharmony_ci 296ffe3c632Sopenharmony_ci /// <value> 297ffe3c632Sopenharmony_ci /// Unmodifiable list of this file's public dependencies (public imports). 298ffe3c632Sopenharmony_ci /// </value> 299ffe3c632Sopenharmony_ci public IList<FileDescriptor> PublicDependencies { get; } 300ffe3c632Sopenharmony_ci 301ffe3c632Sopenharmony_ci /// <value> 302ffe3c632Sopenharmony_ci /// The original serialized binary form of this descriptor. 303ffe3c632Sopenharmony_ci /// </value> 304ffe3c632Sopenharmony_ci public ByteString SerializedData { get; } 305ffe3c632Sopenharmony_ci 306ffe3c632Sopenharmony_ci /// <value> 307ffe3c632Sopenharmony_ci /// Implementation of IDescriptor.FullName - just returns the same as Name. 308ffe3c632Sopenharmony_ci /// </value> 309ffe3c632Sopenharmony_ci string IDescriptor.FullName => Name; 310ffe3c632Sopenharmony_ci 311ffe3c632Sopenharmony_ci /// <value> 312ffe3c632Sopenharmony_ci /// Implementation of IDescriptor.File - just returns this descriptor. 313ffe3c632Sopenharmony_ci /// </value> 314ffe3c632Sopenharmony_ci FileDescriptor IDescriptor.File => this; 315ffe3c632Sopenharmony_ci 316ffe3c632Sopenharmony_ci /// <value> 317ffe3c632Sopenharmony_ci /// Pool containing symbol descriptors. 318ffe3c632Sopenharmony_ci /// </value> 319ffe3c632Sopenharmony_ci internal DescriptorPool DescriptorPool { get; } 320ffe3c632Sopenharmony_ci 321ffe3c632Sopenharmony_ci /// <summary> 322ffe3c632Sopenharmony_ci /// Finds a type (message, enum, service or extension) in the file by name. Does not find nested types. 323ffe3c632Sopenharmony_ci /// </summary> 324ffe3c632Sopenharmony_ci /// <param name="name">The unqualified type name to look for.</param> 325ffe3c632Sopenharmony_ci /// <typeparam name="T">The type of descriptor to look for</typeparam> 326ffe3c632Sopenharmony_ci /// <returns>The type's descriptor, or null if not found.</returns> 327ffe3c632Sopenharmony_ci public T FindTypeByName<T>(String name) 328ffe3c632Sopenharmony_ci where T : class, IDescriptor 329ffe3c632Sopenharmony_ci { 330ffe3c632Sopenharmony_ci // Don't allow looking up nested types. This will make optimization 331ffe3c632Sopenharmony_ci // easier later. 332ffe3c632Sopenharmony_ci if (name.IndexOf('.') != -1) 333ffe3c632Sopenharmony_ci { 334ffe3c632Sopenharmony_ci return null; 335ffe3c632Sopenharmony_ci } 336ffe3c632Sopenharmony_ci if (Package.Length > 0) 337ffe3c632Sopenharmony_ci { 338ffe3c632Sopenharmony_ci name = Package + "." + name; 339ffe3c632Sopenharmony_ci } 340ffe3c632Sopenharmony_ci T result = DescriptorPool.FindSymbol<T>(name); 341ffe3c632Sopenharmony_ci if (result != null && result.File == this) 342ffe3c632Sopenharmony_ci { 343ffe3c632Sopenharmony_ci return result; 344ffe3c632Sopenharmony_ci } 345ffe3c632Sopenharmony_ci return null; 346ffe3c632Sopenharmony_ci } 347ffe3c632Sopenharmony_ci 348ffe3c632Sopenharmony_ci /// <summary> 349ffe3c632Sopenharmony_ci /// Builds a FileDescriptor from its protocol buffer representation. 350ffe3c632Sopenharmony_ci /// </summary> 351ffe3c632Sopenharmony_ci /// <param name="descriptorData">The original serialized descriptor data. 352ffe3c632Sopenharmony_ci /// We have only limited proto2 support, so serializing FileDescriptorProto 353ffe3c632Sopenharmony_ci /// would not necessarily give us this.</param> 354ffe3c632Sopenharmony_ci /// <param name="proto">The protocol message form of the FileDescriptor.</param> 355ffe3c632Sopenharmony_ci /// <param name="dependencies">FileDescriptors corresponding to all of the 356ffe3c632Sopenharmony_ci /// file's dependencies, in the exact order listed in the .proto file. May be null, 357ffe3c632Sopenharmony_ci /// in which case it is treated as an empty array.</param> 358ffe3c632Sopenharmony_ci /// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param> 359ffe3c632Sopenharmony_ci /// <param name="generatedCodeInfo">Details about generated code, for the purposes of reflection.</param> 360ffe3c632Sopenharmony_ci /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not 361ffe3c632Sopenharmony_ci /// a valid descriptor. This can occur for a number of reasons, such as a field 362ffe3c632Sopenharmony_ci /// having an undefined type or because two messages were defined with the same name.</exception> 363ffe3c632Sopenharmony_ci private static FileDescriptor BuildFrom(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo) 364ffe3c632Sopenharmony_ci { 365ffe3c632Sopenharmony_ci // Building descriptors involves two steps: translating and linking. 366ffe3c632Sopenharmony_ci // In the translation step (implemented by FileDescriptor's 367ffe3c632Sopenharmony_ci // constructor), we build an object tree mirroring the 368ffe3c632Sopenharmony_ci // FileDescriptorProto's tree and put all of the descriptors into the 369ffe3c632Sopenharmony_ci // DescriptorPool's lookup tables. In the linking step, we look up all 370ffe3c632Sopenharmony_ci // type references in the DescriptorPool, so that, for example, a 371ffe3c632Sopenharmony_ci // FieldDescriptor for an embedded message contains a pointer directly 372ffe3c632Sopenharmony_ci // to the Descriptor for that message's type. We also detect undefined 373ffe3c632Sopenharmony_ci // types in the linking step. 374ffe3c632Sopenharmony_ci if (dependencies == null) 375ffe3c632Sopenharmony_ci { 376ffe3c632Sopenharmony_ci dependencies = new FileDescriptor[0]; 377ffe3c632Sopenharmony_ci } 378ffe3c632Sopenharmony_ci 379ffe3c632Sopenharmony_ci DescriptorPool pool = new DescriptorPool(dependencies); 380ffe3c632Sopenharmony_ci FileDescriptor result = new FileDescriptor(descriptorData, proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo); 381ffe3c632Sopenharmony_ci 382ffe3c632Sopenharmony_ci // Validate that the dependencies we've been passed (as FileDescriptors) are actually the ones we 383ffe3c632Sopenharmony_ci // need. 384ffe3c632Sopenharmony_ci if (dependencies.Length != proto.Dependency.Count) 385ffe3c632Sopenharmony_ci { 386ffe3c632Sopenharmony_ci throw new DescriptorValidationException( 387ffe3c632Sopenharmony_ci result, 388ffe3c632Sopenharmony_ci "Dependencies passed to FileDescriptor.BuildFrom() don't match " + 389ffe3c632Sopenharmony_ci "those listed in the FileDescriptorProto."); 390ffe3c632Sopenharmony_ci } 391ffe3c632Sopenharmony_ci 392ffe3c632Sopenharmony_ci result.CrossLink(); 393ffe3c632Sopenharmony_ci return result; 394ffe3c632Sopenharmony_ci } 395ffe3c632Sopenharmony_ci 396ffe3c632Sopenharmony_ci private void CrossLink() 397ffe3c632Sopenharmony_ci { 398ffe3c632Sopenharmony_ci foreach (MessageDescriptor message in MessageTypes) 399ffe3c632Sopenharmony_ci { 400ffe3c632Sopenharmony_ci message.CrossLink(); 401ffe3c632Sopenharmony_ci } 402ffe3c632Sopenharmony_ci 403ffe3c632Sopenharmony_ci foreach (ServiceDescriptor service in Services) 404ffe3c632Sopenharmony_ci { 405ffe3c632Sopenharmony_ci service.CrossLink(); 406ffe3c632Sopenharmony_ci } 407ffe3c632Sopenharmony_ci 408ffe3c632Sopenharmony_ci Extensions.CrossLink(); 409ffe3c632Sopenharmony_ci } 410ffe3c632Sopenharmony_ci 411ffe3c632Sopenharmony_ci /// <summary> 412ffe3c632Sopenharmony_ci /// Creates a descriptor for generated code. 413ffe3c632Sopenharmony_ci /// </summary> 414ffe3c632Sopenharmony_ci /// <remarks> 415ffe3c632Sopenharmony_ci /// This method is only designed to be used by the results of generating code with protoc, 416ffe3c632Sopenharmony_ci /// which creates the appropriate dependencies etc. It has to be public because the generated 417ffe3c632Sopenharmony_ci /// code is "external", but should not be called directly by end users. 418ffe3c632Sopenharmony_ci /// </remarks> 419ffe3c632Sopenharmony_ci public static FileDescriptor FromGeneratedCode( 420ffe3c632Sopenharmony_ci byte[] descriptorData, 421ffe3c632Sopenharmony_ci FileDescriptor[] dependencies, 422ffe3c632Sopenharmony_ci GeneratedClrTypeInfo generatedCodeInfo) 423ffe3c632Sopenharmony_ci { 424ffe3c632Sopenharmony_ci ExtensionRegistry registry = new ExtensionRegistry(); 425ffe3c632Sopenharmony_ci registry.AddRange(GetAllExtensions(dependencies, generatedCodeInfo)); 426ffe3c632Sopenharmony_ci 427ffe3c632Sopenharmony_ci FileDescriptorProto proto; 428ffe3c632Sopenharmony_ci try 429ffe3c632Sopenharmony_ci { 430ffe3c632Sopenharmony_ci proto = FileDescriptorProto.Parser.WithExtensionRegistry(registry).ParseFrom(descriptorData); 431ffe3c632Sopenharmony_ci } 432ffe3c632Sopenharmony_ci catch (InvalidProtocolBufferException e) 433ffe3c632Sopenharmony_ci { 434ffe3c632Sopenharmony_ci throw new ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e); 435ffe3c632Sopenharmony_ci } 436ffe3c632Sopenharmony_ci 437ffe3c632Sopenharmony_ci try 438ffe3c632Sopenharmony_ci { 439ffe3c632Sopenharmony_ci // When building descriptors for generated code, we allow unknown 440ffe3c632Sopenharmony_ci // dependencies by default. 441ffe3c632Sopenharmony_ci return BuildFrom(ByteString.CopyFrom(descriptorData), proto, dependencies, true, generatedCodeInfo); 442ffe3c632Sopenharmony_ci } 443ffe3c632Sopenharmony_ci catch (DescriptorValidationException e) 444ffe3c632Sopenharmony_ci { 445ffe3c632Sopenharmony_ci throw new ArgumentException($"Invalid embedded descriptor for \"{proto.Name}\".", e); 446ffe3c632Sopenharmony_ci } 447ffe3c632Sopenharmony_ci } 448ffe3c632Sopenharmony_ci 449ffe3c632Sopenharmony_ci private static IEnumerable<Extension> GetAllExtensions(FileDescriptor[] dependencies, GeneratedClrTypeInfo generatedInfo) 450ffe3c632Sopenharmony_ci { 451ffe3c632Sopenharmony_ci return dependencies.SelectMany(GetAllDependedExtensions).Distinct(ExtensionRegistry.ExtensionComparer.Instance).Concat(GetAllGeneratedExtensions(generatedInfo)); 452ffe3c632Sopenharmony_ci } 453ffe3c632Sopenharmony_ci 454ffe3c632Sopenharmony_ci private static IEnumerable<Extension> GetAllGeneratedExtensions(GeneratedClrTypeInfo generated) 455ffe3c632Sopenharmony_ci { 456ffe3c632Sopenharmony_ci return generated.Extensions.Concat(generated.NestedTypes.Where(t => t != null).SelectMany(GetAllGeneratedExtensions)); 457ffe3c632Sopenharmony_ci } 458ffe3c632Sopenharmony_ci 459ffe3c632Sopenharmony_ci private static IEnumerable<Extension> GetAllDependedExtensions(FileDescriptor descriptor) 460ffe3c632Sopenharmony_ci { 461ffe3c632Sopenharmony_ci return descriptor.Extensions.UnorderedExtensions 462ffe3c632Sopenharmony_ci .Select(s => s.Extension) 463ffe3c632Sopenharmony_ci .Where(e => e != null) 464ffe3c632Sopenharmony_ci .Concat(descriptor.Dependencies.Concat(descriptor.PublicDependencies).SelectMany(GetAllDependedExtensions)) 465ffe3c632Sopenharmony_ci .Concat(descriptor.MessageTypes.SelectMany(GetAllDependedExtensionsFromMessage)); 466ffe3c632Sopenharmony_ci } 467ffe3c632Sopenharmony_ci 468ffe3c632Sopenharmony_ci private static IEnumerable<Extension> GetAllDependedExtensionsFromMessage(MessageDescriptor descriptor) 469ffe3c632Sopenharmony_ci { 470ffe3c632Sopenharmony_ci return descriptor.Extensions.UnorderedExtensions 471ffe3c632Sopenharmony_ci .Select(s => s.Extension) 472ffe3c632Sopenharmony_ci .Where(e => e != null) 473ffe3c632Sopenharmony_ci .Concat(descriptor.NestedTypes.SelectMany(GetAllDependedExtensionsFromMessage)); 474ffe3c632Sopenharmony_ci } 475ffe3c632Sopenharmony_ci 476ffe3c632Sopenharmony_ci /// <summary> 477ffe3c632Sopenharmony_ci /// Converts the given descriptor binary data into FileDescriptor objects. 478ffe3c632Sopenharmony_ci /// Note: reflection using the returned FileDescriptors is not currently supported. 479ffe3c632Sopenharmony_ci /// </summary> 480ffe3c632Sopenharmony_ci /// <param name="descriptorData">The binary file descriptor proto data. Must not be null, and any 481ffe3c632Sopenharmony_ci /// dependencies must come before the descriptor which depends on them. (If A depends on B, and B 482ffe3c632Sopenharmony_ci /// depends on C, then the descriptors must be presented in the order C, B, A.) This is compatible 483ffe3c632Sopenharmony_ci /// with the order in which protoc provides descriptors to plugins.</param> 484ffe3c632Sopenharmony_ci /// <returns>The file descriptors corresponding to <paramref name="descriptorData"/>.</returns> 485ffe3c632Sopenharmony_ci public static IReadOnlyList<FileDescriptor> BuildFromByteStrings(IEnumerable<ByteString> descriptorData) 486ffe3c632Sopenharmony_ci { 487ffe3c632Sopenharmony_ci ProtoPreconditions.CheckNotNull(descriptorData, nameof(descriptorData)); 488ffe3c632Sopenharmony_ci 489ffe3c632Sopenharmony_ci // TODO: See if we can build a single DescriptorPool instead of building lots of them. 490ffe3c632Sopenharmony_ci // This will all behave correctly, but it's less efficient than we'd like. 491ffe3c632Sopenharmony_ci var descriptors = new List<FileDescriptor>(); 492ffe3c632Sopenharmony_ci var descriptorsByName = new Dictionary<string, FileDescriptor>(); 493ffe3c632Sopenharmony_ci foreach (var data in descriptorData) 494ffe3c632Sopenharmony_ci { 495ffe3c632Sopenharmony_ci var proto = FileDescriptorProto.Parser.ParseFrom(data); 496ffe3c632Sopenharmony_ci var dependencies = new List<FileDescriptor>(); 497ffe3c632Sopenharmony_ci foreach (var dependencyName in proto.Dependency) 498ffe3c632Sopenharmony_ci { 499ffe3c632Sopenharmony_ci FileDescriptor dependency; 500ffe3c632Sopenharmony_ci if (!descriptorsByName.TryGetValue(dependencyName, out dependency)) 501ffe3c632Sopenharmony_ci { 502ffe3c632Sopenharmony_ci throw new ArgumentException($"Dependency missing: {dependencyName}"); 503ffe3c632Sopenharmony_ci } 504ffe3c632Sopenharmony_ci dependencies.Add(dependency); 505ffe3c632Sopenharmony_ci } 506ffe3c632Sopenharmony_ci var pool = new DescriptorPool(dependencies); 507ffe3c632Sopenharmony_ci FileDescriptor descriptor = new FileDescriptor( 508ffe3c632Sopenharmony_ci data, proto, dependencies, pool, 509ffe3c632Sopenharmony_ci allowUnknownDependencies: false, generatedCodeInfo: null); 510ffe3c632Sopenharmony_ci descriptor.CrossLink(); 511ffe3c632Sopenharmony_ci descriptors.Add(descriptor); 512ffe3c632Sopenharmony_ci if (descriptorsByName.ContainsKey(descriptor.Name)) 513ffe3c632Sopenharmony_ci { 514ffe3c632Sopenharmony_ci throw new ArgumentException($"Duplicate descriptor name: {descriptor.Name}"); 515ffe3c632Sopenharmony_ci } 516ffe3c632Sopenharmony_ci descriptorsByName.Add(descriptor.Name, descriptor); 517ffe3c632Sopenharmony_ci } 518ffe3c632Sopenharmony_ci return new ReadOnlyCollection<FileDescriptor>(descriptors); 519ffe3c632Sopenharmony_ci } 520ffe3c632Sopenharmony_ci 521ffe3c632Sopenharmony_ci /// <summary> 522ffe3c632Sopenharmony_ci /// Returns a <see cref="System.String" /> that represents this instance. 523ffe3c632Sopenharmony_ci /// </summary> 524ffe3c632Sopenharmony_ci /// <returns> 525ffe3c632Sopenharmony_ci /// A <see cref="System.String" /> that represents this instance. 526ffe3c632Sopenharmony_ci /// </returns> 527ffe3c632Sopenharmony_ci public override string ToString() 528ffe3c632Sopenharmony_ci { 529ffe3c632Sopenharmony_ci return $"FileDescriptor for {Name}"; 530ffe3c632Sopenharmony_ci } 531ffe3c632Sopenharmony_ci 532ffe3c632Sopenharmony_ci /// <summary> 533ffe3c632Sopenharmony_ci /// Returns the file descriptor for descriptor.proto. 534ffe3c632Sopenharmony_ci /// </summary> 535ffe3c632Sopenharmony_ci /// <remarks> 536ffe3c632Sopenharmony_ci /// This is used for protos which take a direct dependency on <c>descriptor.proto</c>, typically for 537ffe3c632Sopenharmony_ci /// annotations. While <c>descriptor.proto</c> is a proto2 file, it is built into the Google.Protobuf 538ffe3c632Sopenharmony_ci /// runtime for reflection purposes. The messages are internal to the runtime as they would require 539ffe3c632Sopenharmony_ci /// proto2 semantics for full support, but the file descriptor is available via this property. The 540ffe3c632Sopenharmony_ci /// C# codegen in protoc automatically uses this property when it detects a dependency on <c>descriptor.proto</c>. 541ffe3c632Sopenharmony_ci /// </remarks> 542ffe3c632Sopenharmony_ci /// <value> 543ffe3c632Sopenharmony_ci /// The file descriptor for <c>descriptor.proto</c>. 544ffe3c632Sopenharmony_ci /// </value> 545ffe3c632Sopenharmony_ci public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorReflection.Descriptor; } } 546ffe3c632Sopenharmony_ci 547ffe3c632Sopenharmony_ci /// <summary> 548ffe3c632Sopenharmony_ci /// The (possibly empty) set of custom options for this file. 549ffe3c632Sopenharmony_ci /// </summary> 550ffe3c632Sopenharmony_ci [Obsolete("CustomOptions are obsolete. Use the GetOptions() method.")] 551ffe3c632Sopenharmony_ci public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber); 552ffe3c632Sopenharmony_ci 553ffe3c632Sopenharmony_ci /// <summary> 554ffe3c632Sopenharmony_ci /// The <c>FileOptions</c>, defined in <c>descriptor.proto</c>. 555ffe3c632Sopenharmony_ci /// If the options message is not present (i.e. there are no options), <c>null</c> is returned. 556ffe3c632Sopenharmony_ci /// Custom options can be retrieved as extensions of the returned message. 557ffe3c632Sopenharmony_ci /// NOTE: A defensive copy is created each time this property is retrieved. 558ffe3c632Sopenharmony_ci /// </summary> 559ffe3c632Sopenharmony_ci public FileOptions GetOptions() => Proto.Options?.Clone(); 560ffe3c632Sopenharmony_ci 561ffe3c632Sopenharmony_ci /// <summary> 562ffe3c632Sopenharmony_ci /// Gets a single value file option for this descriptor 563ffe3c632Sopenharmony_ci /// </summary> 564ffe3c632Sopenharmony_ci [Obsolete("GetOption is obsolete. Use the GetOptions() method.")] 565ffe3c632Sopenharmony_ci public T GetOption<T>(Extension<FileOptions, T> extension) 566ffe3c632Sopenharmony_ci { 567ffe3c632Sopenharmony_ci var value = Proto.Options.GetExtension(extension); 568ffe3c632Sopenharmony_ci return value is IDeepCloneable<T> ? (value as IDeepCloneable<T>).Clone() : value; 569ffe3c632Sopenharmony_ci } 570ffe3c632Sopenharmony_ci 571ffe3c632Sopenharmony_ci /// <summary> 572ffe3c632Sopenharmony_ci /// Gets a repeated value file option for this descriptor 573ffe3c632Sopenharmony_ci /// </summary> 574ffe3c632Sopenharmony_ci [Obsolete("GetOption is obsolete. Use the GetOptions() method.")] 575ffe3c632Sopenharmony_ci public RepeatedField<T> GetOption<T>(RepeatedExtension<FileOptions, T> extension) 576ffe3c632Sopenharmony_ci { 577ffe3c632Sopenharmony_ci return Proto.Options.GetExtension(extension).Clone(); 578ffe3c632Sopenharmony_ci } 579ffe3c632Sopenharmony_ci 580ffe3c632Sopenharmony_ci /// <summary> 581ffe3c632Sopenharmony_ci /// Performs initialization for the given generic type argument. 582ffe3c632Sopenharmony_ci /// </summary> 583ffe3c632Sopenharmony_ci /// <remarks> 584ffe3c632Sopenharmony_ci /// This method is present for the sake of AOT compilers. It allows code (whether handwritten or generated) 585ffe3c632Sopenharmony_ci /// to make calls into the reflection machinery of this library to express an intention to use that type 586ffe3c632Sopenharmony_ci /// reflectively (e.g. for JSON parsing and formatting). The call itself does almost nothing, but AOT compilers 587ffe3c632Sopenharmony_ci /// attempting to determine which generic type arguments need to be handled will spot the code path and act 588ffe3c632Sopenharmony_ci /// accordingly. 589ffe3c632Sopenharmony_ci /// </remarks> 590ffe3c632Sopenharmony_ci /// <typeparam name="T">The type to force initialization for.</typeparam> 591ffe3c632Sopenharmony_ci public static void ForceReflectionInitialization<T>() => ReflectionUtil.ForceInitialize<T>(); 592ffe3c632Sopenharmony_ci } 593ffe3c632Sopenharmony_ci} 594