1fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Protocol Buffers - Google's data interchange format
2fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Copyright 2008 Google Inc.  All rights reserved.
3fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// http://code.google.com/p/protobuf/
4fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
5fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Redistribution and use in source and binary forms, with or without
6fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// modification, are permitted provided that the following conditions are
7fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// met:
8fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
9fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions of source code must retain the above copyright
10fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// notice, this list of conditions and the following disclaimer.
11fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions in binary form must reproduce the above
12fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// copyright notice, this list of conditions and the following disclaimer
13fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// in the documentation and/or other materials provided with the
14fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// distribution.
15fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Neither the name of Google Inc. nor the names of its
16fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// contributors may be used to endorse or promote products derived from
17fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// this software without specific prior written permission.
18fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
19fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
31fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillepackage com.google.protobuf;
32fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
33fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport com.google.protobuf.DescriptorProtos.*;
34fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
35fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.util.Arrays;
36fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.util.Collections;
37fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.util.HashMap;
38fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.util.List;
39fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.util.Map;
40fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.io.UnsupportedEncodingException;
41fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
42fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville/**
43fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Contains a collection of classes which describe protocol message types.
44fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville *
45fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Every message type has a {@link Descriptor}, which lists all
46fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * its fields and other information about a type.  You can get a message
47fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * type's descriptor by calling {@code MessageType.getDescriptor()}, or
48fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * (given a message object of the type) {@code message.getDescriptorForType()}.
49fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville *
50fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Descriptors are built from DescriptorProtos, as defined in
51d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * {@code google/protobuf/descriptor.proto}.
52fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville *
53fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @author kenton@google.com Kenton Varda
54fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */
55fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillepublic final class Descriptors {
56fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /**
57fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * Describes a {@code .proto} file, including everything defined within.
58fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   */
59fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  public static final class FileDescriptor {
60fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Convert the descriptor to its protocol message representation. */
61fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FileDescriptorProto toProto() { return proto; }
62fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
63fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the file name. */
64fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getName() { return proto.getName(); }
65fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
66fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
67fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the proto package name.  This is the package name given by the
68fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@code package} statement in the {@code .proto} file, which differs
69fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * from the Java package.
70fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
71fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getPackage() { return proto.getPackage(); }
72fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
73fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@code FileOptions}, defined in {@code descriptor.proto}. */
74fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FileOptions getOptions() { return proto.getOptions(); }
75fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
76fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of top-level message types declared in this file. */
77fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<Descriptor> getMessageTypes() {
78fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(messageTypes));
79fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
80fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
81fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of top-level enum types declared in this file. */
82fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<EnumDescriptor> getEnumTypes() {
83fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(enumTypes));
84fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
85fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
86fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of top-level services declared in this file. */
87fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<ServiceDescriptor> getServices() {
88fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(services));
89fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
90fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
91fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of top-level extensions declared in this file. */
92fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<FieldDescriptor> getExtensions() {
93fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(extensions));
94fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
95fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
96fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of this file's dependencies (imports). */
97fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<FileDescriptor> getDependencies() {
98fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(dependencies));
99fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
100fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
101fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
102fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Find a message type in the file by name.  Does not find nested types.
103fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *
104fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified type name to look for.
105fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return The message type's descriptor, or {@code null} if not found.
106fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
107fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor findMessageTypeByName(String name) {
108fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Don't allow looking up nested types.  This will make optimization
109fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // easier later.
110fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (name.indexOf('.') != -1) {
111fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
112fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
113fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (getPackage().length() > 0) {
114fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        name = getPackage() + '.' + name;
115fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
116fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result = pool.findSymbol(name);
117fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof Descriptor &&
118fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          result.getFile() == this) {
119fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (Descriptor)result;
120fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
121fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
122fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
123fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
124fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
125fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
126fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Find an enum type in the file by name.  Does not find nested types.
127fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *
128fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified type name to look for.
129fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return The enum type's descriptor, or {@code null} if not found.
130fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
131fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumDescriptor findEnumTypeByName(String name) {
132fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Don't allow looking up nested types.  This will make optimization
133fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // easier later.
134fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (name.indexOf('.') != -1) {
135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
137fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (getPackage().length() > 0) {
138fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        name = getPackage() + '.' + name;
139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
140fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result = pool.findSymbol(name);
141fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof EnumDescriptor &&
142fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          result.getFile() == this) {
143fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (EnumDescriptor)result;
144fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
145fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
147fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
148fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
149fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
150fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Find a service type in the file by name.
151fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *
152fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified type name to look for.
153fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return The service type's descriptor, or {@code null} if not found.
154fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
155fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public ServiceDescriptor findServiceByName(String name) {
156fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Don't allow looking up nested types.  This will make optimization
157fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // easier later.
158fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (name.indexOf('.') != -1) {
159fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
160fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
161fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (getPackage().length() > 0) {
162fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        name = getPackage() + '.' + name;
163fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
164fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result = pool.findSymbol(name);
165fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof ServiceDescriptor &&
166fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          result.getFile() == this) {
167fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (ServiceDescriptor)result;
168fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
169fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
170fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
171fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
172fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
173fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
174fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Find an extension in the file by name.  Does not find extensions nested
175fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * inside message types.
176fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *
177fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified extension name to look for.
178fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return The extension's descriptor, or {@code null} if not found.
179fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
180fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FieldDescriptor findExtensionByName(String name) {
181fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (name.indexOf('.') != -1) {
182fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
183fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (getPackage().length() > 0) {
185fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        name = getPackage() + '.' + name;
186fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
187fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result = pool.findSymbol(name);
188fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof FieldDescriptor &&
189fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          result.getFile() == this) {
190fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (FieldDescriptor)result;
191fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
192fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
193fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
194fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
195fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
196fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
197fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Construct a {@code FileDescriptor}.
198fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *
199fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param proto The protocol message form of the FileDescriptor.
200fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param dependencies {@code FileDescriptor}s corresponding to all of
201fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *                     the file's dependencies, in the exact order listed
202fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *                     in {@code proto}.
203fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @throws DescriptorValidationException {@code proto} is not a valid
204fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *           descriptor.  This can occur for a number of reasons, e.g.
205fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *           because a field has an undefined type or because two messages
206fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *           were defined with the same name.
207fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
208fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public static FileDescriptor buildFrom(final FileDescriptorProto proto,
209fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                           final FileDescriptor[] dependencies)
210fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                    throws DescriptorValidationException {
211fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Building decsriptors involves two steps:  translating and linking.
212fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // In the translation step (implemented by FileDescriptor's
213fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // constructor), we build an object tree mirroring the
214fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // FileDescriptorProto's tree and put all of the descriptors into the
215fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // DescriptorPool's lookup tables.  In the linking step, we look up all
216fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // type references in the DescriptorPool, so that, for example, a
217fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // FieldDescriptor for an embedded message contains a pointer directly
218fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // to the Descriptor for that message's type.  We also detect undefined
219fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // types in the linking step.
220fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final DescriptorPool pool = new DescriptorPool(dependencies);
221fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final FileDescriptor result =
222fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          new FileDescriptor(proto, dependencies, pool);
223fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
224fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (dependencies.length != proto.getDependencyCount()) {
225fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new DescriptorValidationException(result,
226fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "Dependencies passed to FileDescriptor.buildFrom() don't match " +
227fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "those listed in the FileDescriptorProto.");
228fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
229fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getDependencyCount(); i++) {
230fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (!dependencies[i].getName().equals(proto.getDependency(i))) {
231fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(result,
232fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "Dependencies passed to FileDescriptor.buildFrom() don't match " +
233fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "those listed in the FileDescriptorProto.");
234fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
235fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
236fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
237fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      result.crossLink();
238fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return result;
239fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
240fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
241fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
242fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * This method is to be called by generated code only.  It is equivalent
243fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * to {@code buildFrom} except that the {@code FileDescriptorProto} is
244fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * encoded in protocol buffer wire format.
245fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
246fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public static void internalBuildGeneratedFileFrom(
247fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final String[] descriptorDataParts,
248fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final FileDescriptor[] dependencies,
249fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final InternalDescriptorAssigner descriptorAssigner) {
250fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Hack:  We can't embed a raw byte array inside generated Java code
251fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      //   (at least, not efficiently), but we can embed Strings.  So, the
252fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      //   protocol compiler embeds the FileDescriptorProto as a giant
253fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      //   string literal which is passed to this function to construct the
254fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      //   file's FileDescriptor.  The string literal contains only 8-bit
255fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      //   characters, each one representing a byte of the FileDescriptorProto's
256fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      //   serialized form.  So, if we convert it to bytes in ISO-8859-1, we
257fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      //   should get the original bytes that we want.
258fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
259fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // descriptorData may contain multiple strings in order to get around the
260fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Java 64k string literal limit.
261fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      StringBuilder descriptorData = new StringBuilder();
262fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (String part : descriptorDataParts) {
263fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        descriptorData.append(part);
264fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
265fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
266fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final byte[] descriptorBytes;
267fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      try {
268fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        descriptorBytes = descriptorData.toString().getBytes("ISO-8859-1");
269fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } catch (UnsupportedEncodingException e) {
270fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new RuntimeException(
271fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "Standard encoding ISO-8859-1 not supported by JVM.", e);
272fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
273fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
274fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      FileDescriptorProto proto;
275fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      try {
276fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        proto = FileDescriptorProto.parseFrom(descriptorBytes);
277fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } catch (InvalidProtocolBufferException e) {
278fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new IllegalArgumentException(
279fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "Failed to parse protocol buffer descriptor for generated code.", e);
280fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
281fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
282fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final FileDescriptor result;
283fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      try {
284fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        result = buildFrom(proto, dependencies);
285fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } catch (DescriptorValidationException e) {
286fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new IllegalArgumentException(
287fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
288fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
289fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
290fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final ExtensionRegistry registry =
291fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          descriptorAssigner.assignDescriptors(result);
292fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
293fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (registry != null) {
294fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // We must re-parse the proto using the registry.
295fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        try {
296fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto = FileDescriptorProto.parseFrom(descriptorBytes, registry);
297fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } catch (InvalidProtocolBufferException e) {
298fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new IllegalArgumentException(
299fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "Failed to parse protocol buffer descriptor for generated code.",
300fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            e);
301fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
302fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
303fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        result.setProto(proto);
304fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
305fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
306fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
307fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
308fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * This class should be used by generated code only.  When calling
309fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
310fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * provides a callback implementing this interface.  The callback is called
311fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * after the FileDescriptor has been constructed, in order to assign all
312fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * the global variales defined in the generated code which point at parts
313fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * of the FileDescriptor.  The callback returns an ExtensionRegistry which
314fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * contains any extensions which might be used in the descriptor -- that
315fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * is, extensions of the various "Options" messages defined in
316fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * descriptor.proto.  The callback may also return null to indicate that
317fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * no extensions are used in the decsriptor.
318fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
319fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public interface InternalDescriptorAssigner {
320fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ExtensionRegistry assignDescriptors(FileDescriptor root);
321fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
322fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
323fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private FileDescriptorProto proto;
324fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Descriptor[] messageTypes;
325fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final EnumDescriptor[] enumTypes;
326fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final ServiceDescriptor[] services;
327fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FieldDescriptor[] extensions;
328fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FileDescriptor[] dependencies;
329fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final DescriptorPool pool;
330fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
331fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private FileDescriptor(final FileDescriptorProto proto,
332fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                           final FileDescriptor[] dependencies,
333fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                           final DescriptorPool pool)
334fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                    throws DescriptorValidationException {
335fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.pool = pool;
336fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
337fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.dependencies = dependencies.clone();
338fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
339fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      pool.addPackage(getPackage(), this);
340fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
341fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      messageTypes = new Descriptor[proto.getMessageTypeCount()];
342fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getMessageTypeCount(); i++) {
343fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        messageTypes[i] =
344fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          new Descriptor(proto.getMessageType(i), this, null, i);
345fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
346fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
347fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
348fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getEnumTypeCount(); i++) {
349fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        enumTypes[i] = new EnumDescriptor(proto.getEnumType(i), this, null, i);
350fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
351fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
352fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      services = new ServiceDescriptor[proto.getServiceCount()];
353fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getServiceCount(); i++) {
354fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        services[i] = new ServiceDescriptor(proto.getService(i), this, i);
355fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
356fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
357fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      extensions = new FieldDescriptor[proto.getExtensionCount()];
358fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getExtensionCount(); i++) {
359fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        extensions[i] = new FieldDescriptor(
360fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto.getExtension(i), this, null, i, true);
361fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
362fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
363fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
364fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Look up and cross-link all field types, etc. */
365fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void crossLink() throws DescriptorValidationException {
366fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final Descriptor messageType : messageTypes) {
367fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        messageType.crossLink();
368fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
369fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
370fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final ServiceDescriptor service : services) {
371fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        service.crossLink();
372fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
373fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
374fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final FieldDescriptor extension : extensions) {
375fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        extension.crossLink();
376fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
377fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
378fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
379fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
380fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Replace our {@link FileDescriptorProto} with the given one, which is
381fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * identical except that it might contain extensions that weren't present
382fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * in the original.  This method is needed for bootstrapping when a file
383fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * defines custom options.  The options may be defined in the file itself,
384fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * so we can't actually parse them until we've constructed the descriptors,
385fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * but to construct the decsriptors we have to have parsed the descriptor
386fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * protos.  So, we have to parse the descriptor protos a second time after
387fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * constructing the descriptors.
388fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
389fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void setProto(final FileDescriptorProto proto) {
390fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
391fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
392fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < messageTypes.length; i++) {
393fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        messageTypes[i].setProto(proto.getMessageType(i));
394fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
395fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
396fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < enumTypes.length; i++) {
397fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        enumTypes[i].setProto(proto.getEnumType(i));
398fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
399fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
400fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < services.length; i++) {
401fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        services[i].setProto(proto.getService(i));
402fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
403fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
404fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < extensions.length; i++) {
405fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        extensions[i].setProto(proto.getExtension(i));
406fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
407fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
408fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
409fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
410fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
411fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
412fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /** Describes a message type. */
413fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  public static final class Descriptor implements GenericDescriptor {
414fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
415fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the index of this descriptor within its parent.  In other words,
416fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * given a {@link FileDescriptor} {@code file}, the following is true:
417fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * <pre>
418fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   for all i in [0, file.getMessageTypeCount()):
419fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *     file.getMessageType(i).getIndex() == i
420fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * </pre>
421fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Similarly, for a {@link Descriptor} {@code messageType}:
422fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * <pre>
423fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   for all i in [0, messageType.getNestedTypeCount()):
424fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *     messageType.getNestedType(i).getIndex() == i
425fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * </pre>
426fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
427fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int getIndex() { return index; }
428fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
429fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Convert the descriptor to its protocol message representation. */
430fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public DescriptorProto toProto() { return proto; }
431fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
432fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the type's unqualified name. */
433fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getName() { return proto.getName(); }
434fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
435fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
436fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the type's fully-qualified name, within the proto language's
437fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * namespace.  This differs from the Java name.  For example, given this
438fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@code .proto}:
439fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * <pre>
440fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   package foo.bar;
441fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   option java_package = "com.example.protos"
442fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   message Baz {}
443fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * </pre>
444fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@code Baz}'s full name is "foo.bar.Baz".
445fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
446fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getFullName() { return fullName; }
447fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
448fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@link FileDescriptor} containing this descriptor. */
449fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FileDescriptor getFile() { return file; }
450fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
451fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** If this is a nested type, get the outer descriptor, otherwise null. */
452fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor getContainingType() { return containingType; }
453fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
454fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@code MessageOptions}, defined in {@code descriptor.proto}. */
455fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public MessageOptions getOptions() { return proto.getOptions(); }
456fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
457fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of this message type's fields. */
458fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<FieldDescriptor> getFields() {
459fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(fields));
460fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
461fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
462fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of this message type's extensions. */
463fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<FieldDescriptor> getExtensions() {
464fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(extensions));
465fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
466fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
467fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of message types nested within this one. */
468fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<Descriptor> getNestedTypes() {
469fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(nestedTypes));
470fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
471fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
472fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of enum types nested within this one. */
473fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<EnumDescriptor> getEnumTypes() {
474fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(enumTypes));
475fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
476fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
477fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Determines if the given field number is an extension. */
478fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public boolean isExtensionNumber(final int number) {
479fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final DescriptorProto.ExtensionRange range :
480fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto.getExtensionRangeList()) {
481fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (range.getStart() <= number && number < range.getEnd()) {
482fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          return true;
483fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
484fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
485fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return false;
486fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
487fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
488fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
489fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Finds a field by name.
490fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified name of the field (e.g. "foo").
491fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return The field's descriptor, or {@code null} if not found.
492fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
493fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FieldDescriptor findFieldByName(final String name) {
494fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result =
495fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          file.pool.findSymbol(fullName + '.' + name);
496fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof FieldDescriptor) {
497fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (FieldDescriptor)result;
498fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
499fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
500fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
501fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
502fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
503fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
504fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Finds a field by field number.
505fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param number The field number within this message type.
506fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return The field's descriptor, or {@code null} if not found.
507fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
508fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FieldDescriptor findFieldByNumber(final int number) {
509fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return file.pool.fieldsByNumber.get(
510fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        new DescriptorPool.DescriptorIntPair(this, number));
511fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
512fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
513fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
514fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Finds a nested message type by name.
515fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified name of the nested type (e.g. "Foo").
516fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return The types's descriptor, or {@code null} if not found.
517fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
518fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor findNestedTypeByName(final String name) {
519fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result =
520fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          file.pool.findSymbol(fullName + '.' + name);
521fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof Descriptor) {
522fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (Descriptor)result;
523fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
524fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
525fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
526fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
527fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
528fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
529fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Finds a nested enum type by name.
530fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified name of the nested type (e.g. "Foo").
531fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return The types's descriptor, or {@code null} if not found.
532fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
533fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumDescriptor findEnumTypeByName(final String name) {
534fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result =
535fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          file.pool.findSymbol(fullName + '.' + name);
536fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof EnumDescriptor) {
537fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (EnumDescriptor)result;
538fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
539fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
540fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
541fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
542fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
543fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final int index;
544fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private DescriptorProto proto;
545fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final String fullName;
546fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FileDescriptor file;
547fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Descriptor containingType;
548fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Descriptor[] nestedTypes;
549fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final EnumDescriptor[] enumTypes;
550fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FieldDescriptor[] fields;
551fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FieldDescriptor[] extensions;
552fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
553fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private Descriptor(final DescriptorProto proto,
554fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                       final FileDescriptor file,
555fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                       final Descriptor parent,
556fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                       final int index)
557fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                throws DescriptorValidationException {
558fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.index = index;
559fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
560fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      fullName = computeFullName(file, parent, proto.getName());
561fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.file = file;
562fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      containingType = parent;
563fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
564fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      nestedTypes = new Descriptor[proto.getNestedTypeCount()];
565fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getNestedTypeCount(); i++) {
566fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        nestedTypes[i] = new Descriptor(
567fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto.getNestedType(i), file, this, i);
568fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
569fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
570fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
571fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getEnumTypeCount(); i++) {
572fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        enumTypes[i] = new EnumDescriptor(
573fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto.getEnumType(i), file, this, i);
574fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
575fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
576fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      fields = new FieldDescriptor[proto.getFieldCount()];
577fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getFieldCount(); i++) {
578fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        fields[i] = new FieldDescriptor(
579fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto.getField(i), file, this, i, false);
580fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
581fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
582fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      extensions = new FieldDescriptor[proto.getExtensionCount()];
583fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getExtensionCount(); i++) {
584fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        extensions[i] = new FieldDescriptor(
585fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto.getExtension(i), file, this, i, true);
586fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
587fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
588fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      file.pool.addSymbol(this);
589fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
590fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
591fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Look up and cross-link all field types, etc. */
592fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void crossLink() throws DescriptorValidationException {
593fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final Descriptor nestedType : nestedTypes) {
594fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        nestedType.crossLink();
595fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
596fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
597fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final FieldDescriptor field : fields) {
598fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        field.crossLink();
599fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
600fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
601fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final FieldDescriptor extension : extensions) {
602fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        extension.crossLink();
603fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
604fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
605fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
606fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** See {@link FileDescriptor#setProto}. */
607fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void setProto(final DescriptorProto proto) {
608fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
609fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
610fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < nestedTypes.length; i++) {
611fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        nestedTypes[i].setProto(proto.getNestedType(i));
612fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
613fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
614fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < enumTypes.length; i++) {
615fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        enumTypes[i].setProto(proto.getEnumType(i));
616fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
617fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
618fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < fields.length; i++) {
619fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        fields[i].setProto(proto.getField(i));
620fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
621fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
622fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < extensions.length; i++) {
623fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        extensions[i].setProto(proto.getExtension(i));
624fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
625fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
626fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
627fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
628fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
629fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
630fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /** Describes a field of a message type. */
631fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  public static final class FieldDescriptor
632fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      implements GenericDescriptor, Comparable<FieldDescriptor>,
633fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                 FieldSet.FieldDescriptorLite<FieldDescriptor> {
634fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
635fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the index of this descriptor within its parent.
636fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @see Descriptor#getIndex()
637fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
638fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int getIndex() { return index; }
639fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
640fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Convert the descriptor to its protocol message representation. */
641fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FieldDescriptorProto toProto() { return proto; }
642fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
643fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the field's unqualified name. */
644fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getName() { return proto.getName(); }
645fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
646fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the field's number. */
647fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int getNumber() { return proto.getNumber(); }
648fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
649fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
650fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the field's fully-qualified name.
651fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @see Descriptor#getFullName()
652fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
653fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getFullName() { return fullName; }
654fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
655fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
656fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the field's java type.  This is just for convenience.  Every
657fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
658fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
659fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public JavaType getJavaType() { return type.getJavaType(); }
660fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
661fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** For internal use only. */
662fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public WireFormat.JavaType getLiteJavaType() {
663fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return getLiteType().getJavaType();
664fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
665fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
666fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@code FileDescriptor} containing this descriptor. */
667fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FileDescriptor getFile() { return file; }
668fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
669fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the field's declared type. */
670fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Type getType() { return type; }
671fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
672fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** For internal use only. */
673fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public WireFormat.FieldType getLiteType() {
674fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return table[type.ordinal()];
675fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
676fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // I'm pretty sure values() constructs a new array every time, since there
677fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // is nothing stopping the caller from mutating the array.  Therefore we
678fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // make a static copy here.
679fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private static final WireFormat.FieldType[] table =
680fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        WireFormat.FieldType.values();
681fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
682fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Is this field declared required? */
683fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public boolean isRequired() {
684fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
685fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
686fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
687fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Is this field declared optional? */
688fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public boolean isOptional() {
689fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL;
690fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
691fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
692fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Is this field declared repeated? */
693fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public boolean isRepeated() {
694fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
695fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
696fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
697fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Does this field have the {@code [packed = true]} option? */
698fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public boolean isPacked() {
699fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return getOptions().getPacked();
700fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
701fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
702d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    /** Can this field be packed? i.e. is it a repeated primitive field? */
703d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    public boolean isPackable() {
704d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      return isRepeated() && getLiteType().isPackable();
705d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    }
706d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
707fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Returns true if the field had an explicitly-defined default value. */
708fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public boolean hasDefaultValue() { return proto.hasDefaultValue(); }
709fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
710fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
711fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Returns the field's default value.  Valid for all types except for
712fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * messages and groups.  For all other types, the object returned is of
713fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * the same class that would returned by Message.getField(this).
714fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
715fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Object getDefaultValue() {
716fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (getJavaType() == JavaType.MESSAGE) {
717fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new UnsupportedOperationException(
718fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "FieldDescriptor.getDefaultValue() called on an embedded message " +
719fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "field.");
720fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
721fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return defaultValue;
722fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
723fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
724fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@code FieldOptions}, defined in {@code descriptor.proto}. */
725fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FieldOptions getOptions() { return proto.getOptions(); }
726fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
727fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Is this field an extension? */
728fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public boolean isExtension() { return proto.hasExtendee(); }
729fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
730fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
731fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the field's containing type. For extensions, this is the type being
732fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * extended, not the location where the extension was defined.  See
733fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@link #getExtensionScope()}.
734fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
735fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor getContainingType() { return containingType; }
736fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
737fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
738fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * For extensions defined nested within message types, gets the outer
739fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * type.  Not valid for non-extension fields.  For example, consider
740fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * this {@code .proto} file:
741fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * <pre>
742fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   message Foo {
743fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *     extensions 1000 to max;
744fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   }
745fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   extend Foo {
746fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *     optional int32 baz = 1234;
747fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   }
748fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   message Bar {
749fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *     extend Foo {
750fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *       optional int32 qux = 4321;
751fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *     }
752fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *   }
753fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * </pre>
754fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Both {@code baz}'s and {@code qux}'s containing type is {@code Foo}.
755fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * However, {@code baz}'s extension scope is {@code null} while
756fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@code qux}'s extension scope is {@code Bar}.
757fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
758fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor getExtensionScope() {
759fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (!isExtension()) {
760fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new UnsupportedOperationException(
761fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "This field is not an extension.");
762fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
763fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return extensionScope;
764fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
765fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
766fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** For embedded message and group fields, gets the field's type. */
767fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor getMessageType() {
768fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (getJavaType() != JavaType.MESSAGE) {
769fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new UnsupportedOperationException(
770fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "This field is not of message type.");
771fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
772fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return messageType;
773fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
774fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
775fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** For enum fields, gets the field's type. */
776fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumDescriptor getEnumType() {
777fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (getJavaType() != JavaType.ENUM) {
778fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new UnsupportedOperationException(
779fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "This field is not of enum type.");
780fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
781fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return enumType;
782fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
783fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
784fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
785fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Compare with another {@code FieldDescriptor}.  This orders fields in
786fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * "canonical" order, which simply means ascending order by field number.
787fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@code other} must be a field of the same type -- i.e.
788fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * {@code getContainingType()} must return the same {@code Descriptor} for
789fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * both fields.
790fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *
791fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return negative, zero, or positive if {@code this} is less than,
792fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     *         equal to, or greater than {@code other}, respectively.
793fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
794fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int compareTo(final FieldDescriptor other) {
795fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (other.containingType != containingType) {
796fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new IllegalArgumentException(
797fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "FieldDescriptors can only be compared to other FieldDescriptors " +
798fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "for fields of the same message type.");
799fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
800fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return getNumber() - other.getNumber();
801fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
802fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
803fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final int index;
804fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
805fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private FieldDescriptorProto proto;
806fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final String fullName;
807fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FileDescriptor file;
808fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Descriptor extensionScope;
809fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
810fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // Possibly initialized during cross-linking.
811fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private Type type;
812fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private Descriptor containingType;
813fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private Descriptor messageType;
814fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private EnumDescriptor enumType;
815fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private Object defaultValue;
816fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
817fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public enum Type {
818d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      DOUBLE  (JavaType.DOUBLE     ),
819d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      FLOAT   (JavaType.FLOAT      ),
820d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      INT64   (JavaType.LONG       ),
821d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      UINT64  (JavaType.LONG       ),
822d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      INT32   (JavaType.INT        ),
823d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      FIXED64 (JavaType.LONG       ),
824d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      FIXED32 (JavaType.INT        ),
825d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      BOOL    (JavaType.BOOLEAN    ),
826d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      STRING  (JavaType.STRING     ),
827d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      GROUP   (JavaType.MESSAGE    ),
828d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      MESSAGE (JavaType.MESSAGE    ),
829d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      BYTES   (JavaType.BYTE_STRING),
830d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      UINT32  (JavaType.INT        ),
831d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      ENUM    (JavaType.ENUM       ),
832d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      SFIXED32(JavaType.INT        ),
833d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      SFIXED64(JavaType.LONG       ),
834d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      SINT32  (JavaType.INT        ),
835d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      SINT64  (JavaType.LONG       );
836d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
837d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      Type(final JavaType javaType) {
838fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        this.javaType = javaType;
839fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
840fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
841fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      private JavaType javaType;
842fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
843d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      public FieldDescriptorProto.Type toProto() {
844d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        return FieldDescriptorProto.Type.valueOf(ordinal() + 1);
845d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      }
846fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      public JavaType getJavaType() { return javaType; }
847fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
848fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      public static Type valueOf(final FieldDescriptorProto.Type type) {
849fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return values()[type.getNumber() - 1];
850fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
851fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
852fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
853fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    static {
854fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Refuse to init if someone added a new declared type.
855fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (Type.values().length != FieldDescriptorProto.Type.values().length) {
856fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new RuntimeException(
857fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "descriptor.proto has a new declared type but Desrciptors.java " +
858fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "wasn't updated.");
859fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
860fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
861fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
862fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public enum JavaType {
863fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      INT(0),
864fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      LONG(0L),
865fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      FLOAT(0F),
866fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      DOUBLE(0D),
867fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      BOOLEAN(false),
868fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      STRING(""),
869fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      BYTE_STRING(ByteString.EMPTY),
870fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ENUM(null),
871fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      MESSAGE(null);
872fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
873fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      JavaType(final Object defaultDefault) {
874fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        this.defaultDefault = defaultDefault;
875fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
876fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
877fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      /**
878fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville       * The default default value for fields of this type, if it's a primitive
879fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville       * type.  This is meant for use inside this file only, hence is private.
880fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville       */
881fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      private final Object defaultDefault;
882fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
883fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
884fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private FieldDescriptor(final FieldDescriptorProto proto,
885fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                            final FileDescriptor file,
886fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                            final Descriptor parent,
887fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                            final int index,
888fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                            final boolean isExtension)
889fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                     throws DescriptorValidationException {
890fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.index = index;
891fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
892fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      fullName = computeFullName(file, parent, proto.getName());
893fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.file = file;
894fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
895fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (proto.hasType()) {
896fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        type = Type.valueOf(proto.getType());
897fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
898fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
899fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (getNumber() <= 0) {
900fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new DescriptorValidationException(this,
901fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "Field numbers must be positive integers.");
902fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
903fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
904fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Only repeated primitive fields may be packed.
905d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      if (proto.getOptions().getPacked() && !isPackable()) {
906d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        throw new DescriptorValidationException(this,
907d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          "[packed = true] can only be specified for repeated primitive " +
908d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          "fields.");
909fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
910fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
911fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (isExtension) {
912fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (!proto.hasExtendee()) {
913fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(this,
914fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "FieldDescriptorProto.extendee not set for extension field.");
915fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
916fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        containingType = null;  // Will be filled in when cross-linking
917fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (parent != null) {
918fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          extensionScope = parent;
919fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } else {
920fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          extensionScope = null;
921fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
922fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
923fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (proto.hasExtendee()) {
924fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(this,
925fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "FieldDescriptorProto.extendee set for non-extension field.");
926fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
927fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        containingType = parent;
928fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        extensionScope = null;
929fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
930fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
931fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      file.pool.addSymbol(this);
932fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
933fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
934fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Look up and cross-link all field types, etc. */
935fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void crossLink() throws DescriptorValidationException {
936fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (proto.hasExtendee()) {
937fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final GenericDescriptor extendee =
938fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          file.pool.lookupSymbol(proto.getExtendee(), this);
939fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (!(extendee instanceof Descriptor)) {
940fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(this,
941fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              '\"' + proto.getExtendee() + "\" is not a message type.");
942fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
943fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        containingType = (Descriptor)extendee;
944fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
945fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (!getContainingType().isExtensionNumber(getNumber())) {
946fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(this,
947fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              '\"' + getContainingType().getFullName() +
948fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              "\" does not declare " + getNumber() +
949fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              " as an extension number.");
950fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
951fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
952fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
953fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (proto.hasTypeName()) {
954fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final GenericDescriptor typeDescriptor =
955fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          file.pool.lookupSymbol(proto.getTypeName(), this);
956fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
957fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (!proto.hasType()) {
958fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // Choose field type based on symbol.
959fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (typeDescriptor instanceof Descriptor) {
960fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            type = Type.MESSAGE;
961fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          } else if (typeDescriptor instanceof EnumDescriptor) {
962fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            type = Type.ENUM;
963fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          } else {
964fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            throw new DescriptorValidationException(this,
965fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                '\"' + proto.getTypeName() + "\" is not a type.");
966fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
967fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
968fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
969fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (getJavaType() == JavaType.MESSAGE) {
970fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (!(typeDescriptor instanceof Descriptor)) {
971fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            throw new DescriptorValidationException(this,
972fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                '\"' + proto.getTypeName() + "\" is not a message type.");
973fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
974fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          messageType = (Descriptor)typeDescriptor;
975fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
976fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (proto.hasDefaultValue()) {
977fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            throw new DescriptorValidationException(this,
978fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              "Messages can't have default values.");
979fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
980fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } else if (getJavaType() == JavaType.ENUM) {
981fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (!(typeDescriptor instanceof EnumDescriptor)) {
982fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            throw new DescriptorValidationException(this,
983fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                '\"' + proto.getTypeName() + "\" is not an enum type.");
984fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
985fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          enumType = (EnumDescriptor)typeDescriptor;
986fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } else {
987fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(this,
988fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "Field with primitive type has type_name.");
989fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
990fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
991fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (getJavaType() == JavaType.MESSAGE ||
992fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            getJavaType() == JavaType.ENUM) {
993fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(this,
994fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "Field with message or enum type missing type_name.");
995fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
996fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
997fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
998fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // We don't attempt to parse the default value until here because for
999fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // enums we need the enum type's descriptor.
1000fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (proto.hasDefaultValue()) {
1001fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (isRepeated()) {
1002fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(this,
1003fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "Repeated fields cannot have default values.");
1004fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1005fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1006fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        try {
1007fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          switch (getType()) {
1008fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case INT32:
1009fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case SINT32:
1010fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case SFIXED32:
1011fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = TextFormat.parseInt32(proto.getDefaultValue());
1012fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1013fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case UINT32:
1014fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case FIXED32:
1015fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = TextFormat.parseUInt32(proto.getDefaultValue());
1016fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1017fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case INT64:
1018fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case SINT64:
1019fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case SFIXED64:
1020fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = TextFormat.parseInt64(proto.getDefaultValue());
1021fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1022fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case UINT64:
1023fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case FIXED64:
1024fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = TextFormat.parseUInt64(proto.getDefaultValue());
1025fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1026fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case FLOAT:
1027d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              if (proto.getDefaultValue().equals("inf")) {
1028d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                defaultValue = Float.POSITIVE_INFINITY;
1029d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              } else if (proto.getDefaultValue().equals("-inf")) {
1030d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                defaultValue = Float.NEGATIVE_INFINITY;
1031d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              } else if (proto.getDefaultValue().equals("nan")) {
1032d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                defaultValue = Float.NaN;
1033d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              } else {
1034d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                defaultValue = Float.valueOf(proto.getDefaultValue());
1035d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              }
1036fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1037fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case DOUBLE:
1038d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              if (proto.getDefaultValue().equals("inf")) {
1039d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                defaultValue = Double.POSITIVE_INFINITY;
1040d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              } else if (proto.getDefaultValue().equals("-inf")) {
1041d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                defaultValue = Double.NEGATIVE_INFINITY;
1042d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              } else if (proto.getDefaultValue().equals("nan")) {
1043d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                defaultValue = Double.NaN;
1044d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              } else {
1045d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville                defaultValue = Double.valueOf(proto.getDefaultValue());
1046d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              }
1047fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1048fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case BOOL:
1049fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = Boolean.valueOf(proto.getDefaultValue());
1050fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1051fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case STRING:
1052fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = proto.getDefaultValue();
1053fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1054fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case BYTES:
1055fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              try {
1056fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                defaultValue =
1057fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                  TextFormat.unescapeBytes(proto.getDefaultValue());
1058fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              } catch (TextFormat.InvalidEscapeSequenceException e) {
1059fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                throw new DescriptorValidationException(this,
1060fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                  "Couldn't parse default value: " + e.getMessage(), e);
1061fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              }
1062fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1063fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case ENUM:
1064fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = enumType.findValueByName(proto.getDefaultValue());
1065fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              if (defaultValue == null) {
1066fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                throw new DescriptorValidationException(this,
1067fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                  "Unknown enum default value: \"" +
1068fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                  proto.getDefaultValue() + '\"');
1069fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              }
1070fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1071fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case MESSAGE:
1072fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case GROUP:
1073fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              throw new DescriptorValidationException(this,
1074fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                "Message type had default value.");
1075fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
1076fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } catch (NumberFormatException e) {
1077d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          throw new DescriptorValidationException(this,
1078d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              "Could not parse default value: \"" +
1079d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville              proto.getDefaultValue() + '\"', e);
1080fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1081fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
1082fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // Determine the default default for this field.
1083fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (isRepeated()) {
1084fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          defaultValue = Collections.emptyList();
1085fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } else {
1086fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          switch (getJavaType()) {
1087fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case ENUM:
1088fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              // We guarantee elsewhere that an enum type always has at least
1089fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              // one possible value.
1090fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = enumType.getValues().get(0);
1091fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1092fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            case MESSAGE:
1093fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = null;
1094fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1095fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            default:
1096fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              defaultValue = getJavaType().defaultDefault;
1097fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1098fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
1099fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1100fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1101fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1102fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (!isExtension()) {
1103fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        file.pool.addFieldByNumber(this);
1104fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1105fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1106fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (containingType != null &&
1107fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          containingType.getOptions().getMessageSetWireFormat()) {
1108fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (isExtension()) {
1109fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (!isOptional() || getType() != Type.MESSAGE) {
1110fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            throw new DescriptorValidationException(this,
1111fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              "Extensions of MessageSets must be optional messages.");
1112fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
1113fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } else {
1114fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(this,
1115fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            "MessageSets cannot have fields, only extensions.");
1116fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1117fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1118fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1119fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1120fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** See {@link FileDescriptor#setProto}. */
1121fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void setProto(final FieldDescriptorProto proto) {
1122fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1123fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1124fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1125fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1126fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * For internal use only.  This is to satisfy the FieldDescriptorLite
1127fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * interface.
1128fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1129fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public MessageLite.Builder internalMergeFrom(
1130fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        MessageLite.Builder to, MessageLite from) {
1131fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // FieldDescriptors are only used with non-lite messages so we can just
1132fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // down-cast and call mergeFrom directly.
1133fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return ((Message.Builder) to).mergeFrom((Message) from);
1134fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1137fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
1138fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /** Describes an enum type. */
1140fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  public static final class EnumDescriptor
1141fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      implements GenericDescriptor, Internal.EnumLiteMap<EnumValueDescriptor> {
1142fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1143fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the index of this descriptor within its parent.
1144fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @see Descriptor#getIndex()
1145fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int getIndex() { return index; }
1147fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1148fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Convert the descriptor to its protocol message representation. */
1149fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumDescriptorProto toProto() { return proto; }
1150fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1151fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the type's unqualified name. */
1152fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getName() { return proto.getName(); }
1153fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1154fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1155fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the type's fully-qualified name.
1156fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @see Descriptor#getFullName()
1157fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1158fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getFullName() { return fullName; }
1159fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1160fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@link FileDescriptor} containing this descriptor. */
1161fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FileDescriptor getFile() { return file; }
1162fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1163fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** If this is a nested type, get the outer descriptor, otherwise null. */
1164fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor getContainingType() { return containingType; }
1165fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1166fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@code EnumOptions}, defined in {@code descriptor.proto}. */
1167fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumOptions getOptions() { return proto.getOptions(); }
1168fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1169fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of defined values for this enum. */
1170fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<EnumValueDescriptor> getValues() {
1171fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(values));
1172fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1173fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1174fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1175fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Find an enum value by name.
1176fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified name of the value (e.g. "FOO").
1177fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return the value's decsriptor, or {@code null} if not found.
1178fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1179fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumValueDescriptor findValueByName(final String name) {
1180fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result =
1181fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          file.pool.findSymbol(fullName + '.' + name);
1182fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof EnumValueDescriptor) {
1183fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (EnumValueDescriptor)result;
1184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
1185fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
1186fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1187fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1188fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1189fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1190fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Find an enum value by number.  If multiple enum values have the same
1191fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * number, this returns the first defined value with that number.
1192fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param number The value's number.
1193fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return the value's decsriptor, or {@code null} if not found.
1194fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1195fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumValueDescriptor findValueByNumber(final int number) {
1196fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return file.pool.enumValuesByNumber.get(
1197fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        new DescriptorPool.DescriptorIntPair(this, number));
1198fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1199fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1200fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final int index;
1201fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private EnumDescriptorProto proto;
1202fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final String fullName;
1203fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FileDescriptor file;
1204fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Descriptor containingType;
1205fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private EnumValueDescriptor[] values;
1206fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1207fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private EnumDescriptor(final EnumDescriptorProto proto,
1208fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                           final FileDescriptor file,
1209fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                           final Descriptor parent,
1210fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                           final int index)
1211fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                    throws DescriptorValidationException {
1212fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.index = index;
1213fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1214fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      fullName = computeFullName(file, parent, proto.getName());
1215fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.file = file;
1216fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      containingType = parent;
1217fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1218fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (proto.getValueCount() == 0) {
1219fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // We cannot allow enums with no values because this would mean there
1220fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // would be no valid default value for fields of this type.
1221fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new DescriptorValidationException(this,
1222fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "Enums must contain at least one value.");
1223fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1224fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1225fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      values = new EnumValueDescriptor[proto.getValueCount()];
1226fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getValueCount(); i++) {
1227fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        values[i] = new EnumValueDescriptor(
1228fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto.getValue(i), file, this, i);
1229fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1230fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1231fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      file.pool.addSymbol(this);
1232fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1233fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1234fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** See {@link FileDescriptor#setProto}. */
1235fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void setProto(final EnumDescriptorProto proto) {
1236fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1237fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1238fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < values.length; i++) {
1239fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        values[i].setProto(proto.getValue(i));
1240fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1241fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1242fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1243fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1244fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
1245fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1246fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /**
1247fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * Describes one value within an enum type.  Note that multiple defined
1248fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * values may have the same number.  In generated Java code, all values
1249fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * with the same number after the first become aliases of the first.
1250fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * However, they still have independent EnumValueDescriptors.
1251fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   */
1252fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  public static final class EnumValueDescriptor
1253fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      implements GenericDescriptor, Internal.EnumLite {
1254fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1255fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the index of this descriptor within its parent.
1256fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @see Descriptor#getIndex()
1257fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1258fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int getIndex() { return index; }
1259fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1260fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Convert the descriptor to its protocol message representation. */
1261fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumValueDescriptorProto toProto() { return proto; }
1262fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1263fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the value's unqualified name. */
1264fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getName() { return proto.getName(); }
1265fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1266fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the value's number. */
1267fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int getNumber() { return proto.getNumber(); }
1268fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1269fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1270fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the value's fully-qualified name.
1271fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @see Descriptor#getFullName()
1272fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1273fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getFullName() { return fullName; }
1274fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1275fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@link FileDescriptor} containing this descriptor. */
1276fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FileDescriptor getFile() { return file; }
1277fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1278fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the value's enum type. */
1279fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumDescriptor getType() { return type; }
1280fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1281fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1282fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the {@code EnumValueOptions}, defined in {@code descriptor.proto}.
1283fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1284fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public EnumValueOptions getOptions() { return proto.getOptions(); }
1285fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1286fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final int index;
1287fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private EnumValueDescriptorProto proto;
1288fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final String fullName;
1289fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FileDescriptor file;
1290fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final EnumDescriptor type;
1291fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1292fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private EnumValueDescriptor(final EnumValueDescriptorProto proto,
1293fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                final FileDescriptor file,
1294fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                final EnumDescriptor parent,
1295fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                final int index)
1296fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                         throws DescriptorValidationException {
1297fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.index = index;
1298fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1299fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.file = file;
1300fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      type = parent;
1301fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1302fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      fullName = parent.getFullName() + '.' + proto.getName();
1303fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1304fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      file.pool.addSymbol(this);
1305fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      file.pool.addEnumValueByNumber(this);
1306fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1307fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1308fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** See {@link FileDescriptor#setProto}. */
1309fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void setProto(final EnumValueDescriptorProto proto) {
1310fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1311fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1312fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1313fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1314fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
1315fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1316fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /** Describes a service type. */
1317fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  public static final class ServiceDescriptor implements GenericDescriptor {
1318fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1319fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the index of this descriptor within its parent.
1320fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * * @see Descriptors.Descriptor#getIndex()
1321fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1322fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int getIndex() { return index; }
1323fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1324fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Convert the descriptor to its protocol message representation. */
1325fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public ServiceDescriptorProto toProto() { return proto; }
1326fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1327fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the type's unqualified name. */
1328fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getName() { return proto.getName(); }
1329fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1330fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1331fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the type's fully-qualified name.
1332fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @see Descriptor#getFullName()
1333fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1334fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getFullName() { return fullName; }
1335fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1336fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@link FileDescriptor} containing this descriptor. */
1337fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FileDescriptor getFile() { return file; }
1338fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1339fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
1340fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public ServiceOptions getOptions() { return proto.getOptions(); }
1341fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1342fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get a list of methods for this service. */
1343fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public List<MethodDescriptor> getMethods() {
1344fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return Collections.unmodifiableList(Arrays.asList(methods));
1345fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1346fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1347fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1348fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Find a method by name.
1349fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @param name The unqualified name of the method (e.g. "Foo").
1350fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @return the method's decsriptor, or {@code null} if not found.
1351fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1352fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public MethodDescriptor findMethodByName(final String name) {
1353fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor result =
1354fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          file.pool.findSymbol(fullName + '.' + name);
1355fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null && result instanceof MethodDescriptor) {
1356fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return (MethodDescriptor)result;
1357fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
1358fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return null;
1359fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1360fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1361fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1362fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final int index;
1363fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private ServiceDescriptorProto proto;
1364fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final String fullName;
1365fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FileDescriptor file;
1366fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private MethodDescriptor[] methods;
1367fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1368fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private ServiceDescriptor(final ServiceDescriptorProto proto,
1369fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                              final FileDescriptor file,
1370fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                              final int index)
1371fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                       throws DescriptorValidationException {
1372fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.index = index;
1373fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1374fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      fullName = computeFullName(file, null, proto.getName());
1375fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.file = file;
1376fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1377fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      methods = new MethodDescriptor[proto.getMethodCount()];
1378fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < proto.getMethodCount(); i++) {
1379fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        methods[i] = new MethodDescriptor(
1380fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          proto.getMethod(i), file, this, i);
1381fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1382fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1383fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      file.pool.addSymbol(this);
1384fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1385fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1386fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void crossLink() throws DescriptorValidationException {
1387fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final MethodDescriptor method : methods) {
1388fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        method.crossLink();
1389fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1390fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1391fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1392fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** See {@link FileDescriptor#setProto}. */
1393fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void setProto(final ServiceDescriptorProto proto) {
1394fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1395fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1396fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < methods.length; i++) {
1397fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        methods[i].setProto(proto.getMethod(i));
1398fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1399fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1400fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1401fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1402fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
1403fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1404fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /**
1405fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * Describes one method within a service type.
1406fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   */
1407fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  public static final class MethodDescriptor implements GenericDescriptor {
1408fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1409fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the index of this descriptor within its parent.
1410fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * * @see Descriptors.Descriptor#getIndex()
1411fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1412fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public int getIndex() { return index; }
1413fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1414fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Convert the descriptor to its protocol message representation. */
1415fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public MethodDescriptorProto toProto() { return proto; }
1416fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1417fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the method's unqualified name. */
1418fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getName() { return proto.getName(); }
1419fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1420fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1421fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the method's fully-qualified name.
1422fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * @see Descriptor#getFullName()
1423fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1424fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getFullName() { return fullName; }
1425fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1426fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the {@link FileDescriptor} containing this descriptor. */
1427fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public FileDescriptor getFile() { return file; }
1428fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1429fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the method's service type. */
1430fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public ServiceDescriptor getService() { return service; }
1431fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1432fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the method's input type. */
1433fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor getInputType() { return inputType; }
1434fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1435fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Get the method's output type. */
1436fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Descriptor getOutputType() { return outputType; }
1437fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1438fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1439fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Get the {@code MethodOptions}, defined in {@code descriptor.proto}.
1440fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1441fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public MethodOptions getOptions() { return proto.getOptions(); }
1442fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1443fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final int index;
1444fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private MethodDescriptorProto proto;
1445fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final String fullName;
1446fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final FileDescriptor file;
1447fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final ServiceDescriptor service;
1448fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1449fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // Initialized during cross-linking.
1450fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private Descriptor inputType;
1451fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private Descriptor outputType;
1452fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1453fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private MethodDescriptor(final MethodDescriptorProto proto,
1454fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                             final FileDescriptor file,
1455fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                             final ServiceDescriptor parent,
1456fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                             final int index)
1457fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                      throws DescriptorValidationException {
1458fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.index = index;
1459fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1460fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.file = file;
1461fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      service = parent;
1462fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1463fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      fullName = parent.getFullName() + '.' + proto.getName();
1464fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1465fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      file.pool.addSymbol(this);
1466fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1467fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1468fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void crossLink() throws DescriptorValidationException {
1469fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor input =
1470fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        file.pool.lookupSymbol(proto.getInputType(), this);
1471fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (!(input instanceof Descriptor)) {
1472fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new DescriptorValidationException(this,
1473fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            '\"' + proto.getInputType() + "\" is not a message type.");
1474fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1475fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      inputType = (Descriptor)input;
1476fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1477fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor output =
1478fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        file.pool.lookupSymbol(proto.getOutputType(), this);
1479fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (!(output instanceof Descriptor)) {
1480fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new DescriptorValidationException(this,
1481fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            '\"' + proto.getOutputType() + "\" is not a message type.");
1482fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1483fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      outputType = (Descriptor)output;
1484fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1485fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1486fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** See {@link FileDescriptor#setProto}. */
1487fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private void setProto(final MethodDescriptorProto proto) {
1488fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.proto = proto;
1489fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1490fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1491fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1492fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
1493fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1494fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  private static String computeFullName(final FileDescriptor file,
1495fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                        final Descriptor parent,
1496fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                        final String name) {
1497fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (parent != null) {
1498fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return parent.getFullName() + '.' + name;
1499fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    } else if (file.getPackage().length() > 0) {
1500fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return file.getPackage() + '.' + name;
1501fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    } else {
1502fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return name;
1503fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1504fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1505fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1506fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
1507fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1508fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /**
1509fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * All descriptors except {@code FileDescriptor} implement this to make
1510fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * {@code DescriptorPool}'s life easier.
1511fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   */
1512fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  private interface GenericDescriptor {
1513fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Message toProto();
1514fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    String getName();
1515fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    String getFullName();
1516fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    FileDescriptor getFile();
1517fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1518fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1519fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /**
1520fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * Thrown when building descriptors fails because the source DescriptorProtos
1521fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * are not valid.
1522fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   */
1523fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  public static class DescriptorValidationException extends Exception {
1524fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private static final long serialVersionUID = 5750205775490483148L;
1525fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1526fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Gets the full name of the descriptor where the error occurred. */
1527fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getProblemSymbolName() { return name; }
1528fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1529fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1530fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Gets the the protocol message representation of the invalid descriptor.
1531fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1532fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public Message getProblemProto() { return proto; }
1533fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1534fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1535fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Gets a human-readable description of the error.
1536fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1537fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    public String getDescription() { return description; }
1538fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1539fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final String name;
1540fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Message proto;
1541fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final String description;
1542fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1543fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private DescriptorValidationException(
1544fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final GenericDescriptor problemDescriptor,
1545fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final String description) {
1546d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      super(problemDescriptor.getFullName() + ": " + description);
1547fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1548fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Note that problemDescriptor may be partially uninitialized, so we
1549fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // don't want to expose it directly to the user.  So, we only provide
1550fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // the name and the original proto.
1551fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      name = problemDescriptor.getFullName();
1552fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      proto = problemDescriptor.toProto();
1553fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.description = description;
1554fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1555fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1556fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private DescriptorValidationException(
1557d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        final GenericDescriptor problemDescriptor,
1558d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        final String description,
1559d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        final Throwable cause) {
1560d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      this(problemDescriptor, description);
1561d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      initCause(cause);
1562d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    }
1563d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
1564d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    private DescriptorValidationException(
1565fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final FileDescriptor problemDescriptor,
1566fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final String description) {
1567fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      super(problemDescriptor.getName() + ": " + description);
1568fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1569fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Note that problemDescriptor may be partially uninitialized, so we
1570fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // don't want to expose it directly to the user.  So, we only provide
1571fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // the name and the original proto.
1572fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      name = problemDescriptor.getName();
1573fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      proto = problemDescriptor.toProto();
1574fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.description = description;
1575fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1576fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1577fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1578fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // =================================================================
1579fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1580fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  /**
1581fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * A private helper class which contains lookup tables containing all the
1582fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   * descriptors defined in a particular file.
1583fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville   */
1584fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  private static final class DescriptorPool {
1585fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    DescriptorPool(final FileDescriptor[] dependencies) {
1586fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      this.dependencies = new DescriptorPool[dependencies.length];
1587fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1588fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (int i = 0; i < dependencies.length; i++)  {
1589fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        this.dependencies[i] = dependencies[i].pool;
1590fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1591fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1592fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final FileDescriptor dependency : dependencies) {
1593fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        try {
1594fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          addPackage(dependency.getPackage(), dependency);
1595fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } catch (DescriptorValidationException e) {
1596fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // Can't happen, because addPackage() only fails when the name
1597fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // conflicts with a non-package, but we have not yet added any
1598fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // non-packages at this point.
1599fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          assert false;
1600fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1601fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1602fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1603fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1604fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final DescriptorPool[] dependencies;
1605fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1606fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Map<String, GenericDescriptor> descriptorsByName =
1607fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      new HashMap<String, GenericDescriptor>();
1608fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
1609fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      new HashMap<DescriptorIntPair, FieldDescriptor>();
1610fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber
1611fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        = new HashMap<DescriptorIntPair, EnumValueDescriptor>();
1612fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1613fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** Find a generic descriptor by fully-qualified name. */
1614fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    GenericDescriptor findSymbol(final String fullName) {
1615fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      GenericDescriptor result = descriptorsByName.get(fullName);
1616fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result != null) {
1617fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return result;
1618fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1619fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1620fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for (final DescriptorPool dependency : dependencies) {
1621fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        result = dependency.descriptorsByName.get(fullName);
1622fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (result != null) {
1623fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          return result;
1624fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1625fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1626fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1627fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return null;
1628fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1629fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1630fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1631fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Look up a descriptor by name, relative to some other descriptor.
1632fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * The name may be fully-qualified (with a leading '.'),
1633fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * partially-qualified, or unqualified.  C++-like name lookup semantics
1634fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * are used to search for the matching descriptor.
1635fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1636fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    GenericDescriptor lookupSymbol(final String name,
1637fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                   final GenericDescriptor relativeTo)
1638fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                            throws DescriptorValidationException {
1639fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // TODO(kenton):  This could be optimized in a number of ways.
1640fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1641fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      GenericDescriptor result;
1642fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (name.startsWith(".")) {
1643fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // Fully-qualified name.
1644fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        result = findSymbol(name.substring(1));
1645fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
1646fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // If "name" is a compound identifier, we want to search for the
1647fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // first component of it, then search within it for the rest.
1648fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final int firstPartLength = name.indexOf('.');
1649fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final String firstPart;
1650fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (firstPartLength == -1) {
1651fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          firstPart = name;
1652fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } else {
1653fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          firstPart = name.substring(0, firstPartLength);
1654fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1655fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1656fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // We will search each parent scope of "relativeTo" looking for the
1657fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // symbol.
1658fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final StringBuilder scopeToTry =
1659fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            new StringBuilder(relativeTo.getFullName());
1660fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1661fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        while (true) {
1662fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // Chop off the last component of the scope.
1663fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          final int dotpos = scopeToTry.lastIndexOf(".");
1664fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (dotpos == -1) {
1665fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            result = findSymbol(name);
1666fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            break;
1667fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          } else {
1668fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            scopeToTry.setLength(dotpos + 1);
1669fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1670fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            // Append firstPart and try to find.
1671fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            scopeToTry.append(firstPart);
1672fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            result = findSymbol(scopeToTry.toString());
1673fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1674fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            if (result != null) {
1675fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              if (firstPartLength != -1) {
1676fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                // We only found the first part of the symbol.  Now look for
1677fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                // the whole thing.  If this fails, we *don't* want to keep
1678fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                // searching parent scopes.
1679fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                scopeToTry.setLength(dotpos + 1);
1680fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                scopeToTry.append(name);
1681fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                result = findSymbol(scopeToTry.toString());
1682fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              }
1683fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              break;
1684fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            }
1685fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1686fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            // Not found.  Remove the name so we can try again.
1687fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            scopeToTry.setLength(dotpos);
1688fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
1689fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1690fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1691fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1692fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (result == null) {
1693fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new DescriptorValidationException(relativeTo,
1694fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            '\"' + name + "\" is not defined.");
1695fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
1696fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return result;
1697fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1698fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1699fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1700fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1701fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Adds a symbol to the symbol table.  If a symbol with the same name
1702fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * already exists, throws an error.
1703fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1704fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    void addSymbol(final GenericDescriptor descriptor)
1705fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            throws DescriptorValidationException {
1706fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      validateSymbolName(descriptor);
1707fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1708fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final String fullName = descriptor.getFullName();
1709fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final int dotpos = fullName.lastIndexOf('.');
1710fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1711fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
1712fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (old != null) {
1713fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        descriptorsByName.put(fullName, old);
1714fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1715fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (descriptor.getFile() == old.getFile()) {
1716fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (dotpos == -1) {
1717fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            throw new DescriptorValidationException(descriptor,
1718fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                '\"' + fullName + "\" is already defined.");
1719fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          } else {
1720fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            throw new DescriptorValidationException(descriptor,
1721fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                '\"' + fullName.substring(dotpos + 1) +
1722fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              "\" is already defined in \"" +
1723fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              fullName.substring(0, dotpos) + "\".");
1724fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
1725fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } else {
1726fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(descriptor,
1727fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              '\"' + fullName + "\" is already defined in file \"" +
1728fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            old.getFile().getName() + "\".");
1729fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1730fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1731fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1732fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1733fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1734fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Represents a package in the symbol table.  We use PackageDescriptors
1735fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * just as placeholders so that someone cannot define, say, a message type
1736fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * that has the same name as an existing package.
1737fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1738fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private static final class PackageDescriptor implements GenericDescriptor {
1739fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      public Message toProto()        { return file.toProto(); }
1740fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      public String getName()         { return name;           }
1741fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      public String getFullName()     { return fullName;       }
1742fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      public FileDescriptor getFile() { return file;           }
1743fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1744fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      PackageDescriptor(final String name, final String fullName,
1745fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                        final FileDescriptor file) {
1746fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        this.file = file;
1747fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        this.fullName = fullName;
1748fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        this.name = name;
1749fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1750fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1751fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      private final String name;
1752fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      private final String fullName;
1753fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      private final FileDescriptor file;
1754fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1755fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1756fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1757fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Adds a package to the symbol tables.  If a package by the same name
1758fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * already exists, that is fine, but if some other kind of symbol exists
1759fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * under the same name, an exception is thrown.  If the package has
1760fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * multiple components, this also adds the parent package(s).
1761fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1762fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    void addPackage(final String fullName, final FileDescriptor file)
1763fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville             throws DescriptorValidationException {
1764fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final int dotpos = fullName.lastIndexOf('.');
1765fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final String name;
1766fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (dotpos == -1) {
1767fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        name = fullName;
1768fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
1769fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        addPackage(fullName.substring(0, dotpos), file);
1770fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        name = fullName.substring(dotpos + 1);
1771fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1772fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1773fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final GenericDescriptor old =
1774fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        descriptorsByName.put(fullName,
1775fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          new PackageDescriptor(name, fullName, file));
1776fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (old != null) {
1777fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        descriptorsByName.put(fullName, old);
1778fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (!(old instanceof PackageDescriptor)) {
1779fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(file,
1780fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              '\"' + name + "\" is already defined (as something other than a "
1781fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              + "package) in file \"" + old.getFile().getName() + "\".");
1782fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1783fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1784fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1785fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1786fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /** A (GenericDescriptor, int) pair, used as a map key. */
1787fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    private static final class DescriptorIntPair {
1788fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      private final GenericDescriptor descriptor;
1789fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      private final int number;
1790fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1791fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      DescriptorIntPair(final GenericDescriptor descriptor, final int number) {
1792fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        this.descriptor = descriptor;
1793fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        this.number = number;
1794fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1795fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1796fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      @Override
1797fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      public int hashCode() {
1798fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return descriptor.hashCode() * ((1 << 16) - 1) + number;
1799fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1800fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      @Override
1801fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      public boolean equals(final Object obj) {
1802fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (!(obj instanceof DescriptorIntPair)) {
1803fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          return false;
1804fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1805fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        final DescriptorIntPair other = (DescriptorIntPair)obj;
1806fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return descriptor == other.descriptor && number == other.number;
1807fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1808fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1809fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1810fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1811fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Adds a field to the fieldsByNumber table.  Throws an exception if a
1812fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * field with hte same containing type and number already exists.
1813fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1814fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    void addFieldByNumber(final FieldDescriptor field)
1815fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                   throws DescriptorValidationException {
1816fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final DescriptorIntPair key =
1817fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        new DescriptorIntPair(field.getContainingType(), field.getNumber());
1818fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final FieldDescriptor old = fieldsByNumber.put(key, field);
1819fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (old != null) {
1820fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        fieldsByNumber.put(key, old);
1821fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new DescriptorValidationException(field,
1822fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "Field number " + field.getNumber() +
1823fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "has already been used in \"" +
1824fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          field.getContainingType().getFullName() +
1825fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          "\" by field \"" + old.getName() + "\".");
1826fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1827fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1828fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1829fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1830fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Adds an enum value to the enumValuesByNumber table.  If an enum value
1831fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * with the same type and number already exists, does nothing.  (This is
1832fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * allowed; the first value define with the number takes precedence.)
1833fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1834fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    void addEnumValueByNumber(final EnumValueDescriptor value) {
1835fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final DescriptorIntPair key =
1836fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        new DescriptorIntPair(value.getType(), value.getNumber());
1837fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final EnumValueDescriptor old = enumValuesByNumber.put(key, value);
1838fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (old != null) {
1839fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        enumValuesByNumber.put(key, old);
1840fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // Not an error:  Multiple enum values may have the same number, but
1841fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // we only want the first one in the map.
1842fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1843fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1844fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
1845fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    /**
1846fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * Verifies that the descriptor's name is valid (i.e. it contains only
1847fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     * letters, digits, and underscores, and does not start with a digit).
1848fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville     */
1849fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    static void validateSymbolName(final GenericDescriptor descriptor)
1850fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                                   throws DescriptorValidationException {
1851fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      final String name = descriptor.getName();
1852fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (name.length() == 0) {
1853fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        throw new DescriptorValidationException(descriptor, "Missing name.");
1854fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
1855fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        boolean valid = true;
1856fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        for (int i = 0; i < name.length(); i++) {
1857fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          final char c = name.charAt(i);
1858fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // Non-ASCII characters are not valid in protobuf identifiers, even
1859fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // if they are letters or digits.
1860fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (c >= 128) {
1861fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            valid = false;
1862fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
1863fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // First character must be letter or _.  Subsequent characters may
1864fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          // be letters, numbers, or digits.
1865fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          if (Character.isLetter(c) || c == '_' ||
1866fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              (Character.isDigit(c) && i > 0)) {
1867fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            // Valid
1868fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          } else {
1869fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville            valid = false;
1870fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          }
1871fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1872fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (!valid) {
1873fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          throw new DescriptorValidationException(descriptor,
1874fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              '\"' + name + "\" is not a valid identifier.");
1875fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
1876fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
1877fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
1878fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
1879fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
1880