xref: /aosp_15_r20/external/protobuf/objectivec/GPBDescriptor.m (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker// Protocol Buffers - Google's data interchange format
2*1b3f573fSAndroid Build Coastguard Worker// Copyright 2008 Google Inc.  All rights reserved.
3*1b3f573fSAndroid Build Coastguard Worker// https://developers.google.com/protocol-buffers/
4*1b3f573fSAndroid Build Coastguard Worker//
5*1b3f573fSAndroid Build Coastguard Worker// Redistribution and use in source and binary forms, with or without
6*1b3f573fSAndroid Build Coastguard Worker// modification, are permitted provided that the following conditions are
7*1b3f573fSAndroid Build Coastguard Worker// met:
8*1b3f573fSAndroid Build Coastguard Worker//
9*1b3f573fSAndroid Build Coastguard Worker//     * Redistributions of source code must retain the above copyright
10*1b3f573fSAndroid Build Coastguard Worker// notice, this list of conditions and the following disclaimer.
11*1b3f573fSAndroid Build Coastguard Worker//     * Redistributions in binary form must reproduce the above
12*1b3f573fSAndroid Build Coastguard Worker// copyright notice, this list of conditions and the following disclaimer
13*1b3f573fSAndroid Build Coastguard Worker// in the documentation and/or other materials provided with the
14*1b3f573fSAndroid Build Coastguard Worker// distribution.
15*1b3f573fSAndroid Build Coastguard Worker//     * Neither the name of Google Inc. nor the names of its
16*1b3f573fSAndroid Build Coastguard Worker// contributors may be used to endorse or promote products derived from
17*1b3f573fSAndroid Build Coastguard Worker// this software without specific prior written permission.
18*1b3f573fSAndroid Build Coastguard Worker//
19*1b3f573fSAndroid Build Coastguard Worker// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*1b3f573fSAndroid Build Coastguard Worker// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*1b3f573fSAndroid Build Coastguard Worker// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*1b3f573fSAndroid Build Coastguard Worker// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*1b3f573fSAndroid Build Coastguard Worker// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*1b3f573fSAndroid Build Coastguard Worker// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*1b3f573fSAndroid Build Coastguard Worker// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*1b3f573fSAndroid Build Coastguard Worker// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*1b3f573fSAndroid Build Coastguard Worker// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*1b3f573fSAndroid Build Coastguard Worker// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*1b3f573fSAndroid Build Coastguard Worker// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*1b3f573fSAndroid Build Coastguard Worker
31*1b3f573fSAndroid Build Coastguard Worker#import "GPBDescriptor_PackagePrivate.h"
32*1b3f573fSAndroid Build Coastguard Worker
33*1b3f573fSAndroid Build Coastguard Worker#import <objc/runtime.h>
34*1b3f573fSAndroid Build Coastguard Worker
35*1b3f573fSAndroid Build Coastguard Worker#import "GPBUtilities_PackagePrivate.h"
36*1b3f573fSAndroid Build Coastguard Worker#import "GPBWireFormat.h"
37*1b3f573fSAndroid Build Coastguard Worker#import "GPBMessage_PackagePrivate.h"
38*1b3f573fSAndroid Build Coastguard Worker
39*1b3f573fSAndroid Build Coastguard Worker// Direct access is use for speed, to avoid even internally declaring things
40*1b3f573fSAndroid Build Coastguard Worker// read/write, etc. The warning is enabled in the project to ensure code calling
41*1b3f573fSAndroid Build Coastguard Worker// protos can turn on -Wdirect-ivar-access without issues.
42*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic push
43*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Wdirect-ivar-access"
44*1b3f573fSAndroid Build Coastguard Worker
45*1b3f573fSAndroid Build Coastguard Worker// The addresses of these variables are used as keys for objc_getAssociatedObject.
46*1b3f573fSAndroid Build Coastguard Workerstatic const char kTextFormatExtraValueKey = 0;
47*1b3f573fSAndroid Build Coastguard Workerstatic const char kParentClassValueKey = 0;
48*1b3f573fSAndroid Build Coastguard Workerstatic const char kClassNameSuffixKey = 0;
49*1b3f573fSAndroid Build Coastguard Worker
50*1b3f573fSAndroid Build Coastguard Worker// Utility function to generate selectors on the fly.
51*1b3f573fSAndroid Build Coastguard Workerstatic SEL SelFromStrings(const char *prefix, const char *middle,
52*1b3f573fSAndroid Build Coastguard Worker                          const char *suffix, BOOL takesArg) {
53*1b3f573fSAndroid Build Coastguard Worker  if (prefix == NULL && suffix == NULL && !takesArg) {
54*1b3f573fSAndroid Build Coastguard Worker    return sel_getUid(middle);
55*1b3f573fSAndroid Build Coastguard Worker  }
56*1b3f573fSAndroid Build Coastguard Worker  const size_t prefixLen = prefix != NULL ? strlen(prefix) : 0;
57*1b3f573fSAndroid Build Coastguard Worker  const size_t middleLen = strlen(middle);
58*1b3f573fSAndroid Build Coastguard Worker  const size_t suffixLen = suffix != NULL ? strlen(suffix) : 0;
59*1b3f573fSAndroid Build Coastguard Worker  size_t totalLen =
60*1b3f573fSAndroid Build Coastguard Worker      prefixLen + middleLen + suffixLen + 1;  // include space for null on end.
61*1b3f573fSAndroid Build Coastguard Worker  if (takesArg) {
62*1b3f573fSAndroid Build Coastguard Worker    totalLen += 1;
63*1b3f573fSAndroid Build Coastguard Worker  }
64*1b3f573fSAndroid Build Coastguard Worker  char buffer[totalLen];
65*1b3f573fSAndroid Build Coastguard Worker  if (prefix != NULL) {
66*1b3f573fSAndroid Build Coastguard Worker    memcpy(buffer, prefix, prefixLen);
67*1b3f573fSAndroid Build Coastguard Worker    memcpy(buffer + prefixLen, middle, middleLen);
68*1b3f573fSAndroid Build Coastguard Worker    buffer[prefixLen] = (char)toupper(buffer[prefixLen]);
69*1b3f573fSAndroid Build Coastguard Worker  } else {
70*1b3f573fSAndroid Build Coastguard Worker    memcpy(buffer, middle, middleLen);
71*1b3f573fSAndroid Build Coastguard Worker  }
72*1b3f573fSAndroid Build Coastguard Worker  if (suffix != NULL) {
73*1b3f573fSAndroid Build Coastguard Worker    memcpy(buffer + prefixLen + middleLen, suffix, suffixLen);
74*1b3f573fSAndroid Build Coastguard Worker  }
75*1b3f573fSAndroid Build Coastguard Worker  if (takesArg) {
76*1b3f573fSAndroid Build Coastguard Worker    buffer[totalLen - 2] = ':';
77*1b3f573fSAndroid Build Coastguard Worker  }
78*1b3f573fSAndroid Build Coastguard Worker  // Always null terminate it.
79*1b3f573fSAndroid Build Coastguard Worker  buffer[totalLen - 1] = 0;
80*1b3f573fSAndroid Build Coastguard Worker
81*1b3f573fSAndroid Build Coastguard Worker  SEL result = sel_getUid(buffer);
82*1b3f573fSAndroid Build Coastguard Worker  return result;
83*1b3f573fSAndroid Build Coastguard Worker}
84*1b3f573fSAndroid Build Coastguard Worker
85*1b3f573fSAndroid Build Coastguard Workerstatic NSArray *NewFieldsArrayForHasIndex(int hasIndex,
86*1b3f573fSAndroid Build Coastguard Worker                                          NSArray *allMessageFields)
87*1b3f573fSAndroid Build Coastguard Worker    __attribute__((ns_returns_retained));
88*1b3f573fSAndroid Build Coastguard Worker
89*1b3f573fSAndroid Build Coastguard Workerstatic NSArray *NewFieldsArrayForHasIndex(int hasIndex,
90*1b3f573fSAndroid Build Coastguard Worker                                          NSArray *allMessageFields) {
91*1b3f573fSAndroid Build Coastguard Worker  NSMutableArray *result = [[NSMutableArray alloc] init];
92*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *fieldDesc in allMessageFields) {
93*1b3f573fSAndroid Build Coastguard Worker    if (fieldDesc->description_->hasIndex == hasIndex) {
94*1b3f573fSAndroid Build Coastguard Worker      [result addObject:fieldDesc];
95*1b3f573fSAndroid Build Coastguard Worker    }
96*1b3f573fSAndroid Build Coastguard Worker  }
97*1b3f573fSAndroid Build Coastguard Worker  return result;
98*1b3f573fSAndroid Build Coastguard Worker}
99*1b3f573fSAndroid Build Coastguard Worker
100*1b3f573fSAndroid Build Coastguard Worker@implementation GPBDescriptor {
101*1b3f573fSAndroid Build Coastguard Worker  Class messageClass_;
102*1b3f573fSAndroid Build Coastguard Worker  GPBFileDescriptor *file_;
103*1b3f573fSAndroid Build Coastguard Worker  BOOL wireFormat_;
104*1b3f573fSAndroid Build Coastguard Worker}
105*1b3f573fSAndroid Build Coastguard Worker
106*1b3f573fSAndroid Build Coastguard Worker@synthesize messageClass = messageClass_;
107*1b3f573fSAndroid Build Coastguard Worker@synthesize fields = fields_;
108*1b3f573fSAndroid Build Coastguard Worker@synthesize oneofs = oneofs_;
109*1b3f573fSAndroid Build Coastguard Worker@synthesize extensionRanges = extensionRanges_;
110*1b3f573fSAndroid Build Coastguard Worker@synthesize extensionRangesCount = extensionRangesCount_;
111*1b3f573fSAndroid Build Coastguard Worker@synthesize file = file_;
112*1b3f573fSAndroid Build Coastguard Worker@synthesize wireFormat = wireFormat_;
113*1b3f573fSAndroid Build Coastguard Worker
114*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)
115*1b3f573fSAndroid Build Coastguard Worker    allocDescriptorForClass:(Class)messageClass
116*1b3f573fSAndroid Build Coastguard Worker                  rootClass:(Class)rootClass
117*1b3f573fSAndroid Build Coastguard Worker                       file:(GPBFileDescriptor *)file
118*1b3f573fSAndroid Build Coastguard Worker                     fields:(void *)fieldDescriptions
119*1b3f573fSAndroid Build Coastguard Worker                 fieldCount:(uint32_t)fieldCount
120*1b3f573fSAndroid Build Coastguard Worker                storageSize:(uint32_t)storageSize
121*1b3f573fSAndroid Build Coastguard Worker                      flags:(GPBDescriptorInitializationFlags)flags {
122*1b3f573fSAndroid Build Coastguard Worker  // The rootClass is no longer used, but it is passed in to ensure it
123*1b3f573fSAndroid Build Coastguard Worker  // was started up during initialization also.
124*1b3f573fSAndroid Build Coastguard Worker  (void)rootClass;
125*1b3f573fSAndroid Build Coastguard Worker  NSMutableArray *fields = nil;
126*1b3f573fSAndroid Build Coastguard Worker  GPBFileSyntax syntax = file.syntax;
127*1b3f573fSAndroid Build Coastguard Worker  BOOL fieldsIncludeDefault =
128*1b3f573fSAndroid Build Coastguard Worker      (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
129*1b3f573fSAndroid Build Coastguard Worker  BOOL usesClassRefs =
130*1b3f573fSAndroid Build Coastguard Worker      (flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0;
131*1b3f573fSAndroid Build Coastguard Worker  BOOL proto3OptionalKnown =
132*1b3f573fSAndroid Build Coastguard Worker      (flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) != 0;
133*1b3f573fSAndroid Build Coastguard Worker
134*1b3f573fSAndroid Build Coastguard Worker  void *desc;
135*1b3f573fSAndroid Build Coastguard Worker  for (uint32_t i = 0; i < fieldCount; ++i) {
136*1b3f573fSAndroid Build Coastguard Worker    if (fields == nil) {
137*1b3f573fSAndroid Build Coastguard Worker      fields = [[NSMutableArray alloc] initWithCapacity:fieldCount];
138*1b3f573fSAndroid Build Coastguard Worker    }
139*1b3f573fSAndroid Build Coastguard Worker    // Need correctly typed pointer for array indexing below to work.
140*1b3f573fSAndroid Build Coastguard Worker    if (fieldsIncludeDefault) {
141*1b3f573fSAndroid Build Coastguard Worker      GPBMessageFieldDescriptionWithDefault *fieldDescWithDefault = fieldDescriptions;
142*1b3f573fSAndroid Build Coastguard Worker      desc = &(fieldDescWithDefault[i]);
143*1b3f573fSAndroid Build Coastguard Worker    } else {
144*1b3f573fSAndroid Build Coastguard Worker      GPBMessageFieldDescription *fieldDesc = fieldDescriptions;
145*1b3f573fSAndroid Build Coastguard Worker      desc = &(fieldDesc[i]);
146*1b3f573fSAndroid Build Coastguard Worker    }
147*1b3f573fSAndroid Build Coastguard Worker    GPBFieldDescriptor *fieldDescriptor =
148*1b3f573fSAndroid Build Coastguard Worker        [[GPBFieldDescriptor alloc] initWithFieldDescription:desc
149*1b3f573fSAndroid Build Coastguard Worker                                             includesDefault:fieldsIncludeDefault
150*1b3f573fSAndroid Build Coastguard Worker                                               usesClassRefs:usesClassRefs
151*1b3f573fSAndroid Build Coastguard Worker                                         proto3OptionalKnown:proto3OptionalKnown
152*1b3f573fSAndroid Build Coastguard Worker                                                      syntax:syntax];
153*1b3f573fSAndroid Build Coastguard Worker    [fields addObject:fieldDescriptor];
154*1b3f573fSAndroid Build Coastguard Worker    [fieldDescriptor release];
155*1b3f573fSAndroid Build Coastguard Worker  }
156*1b3f573fSAndroid Build Coastguard Worker
157*1b3f573fSAndroid Build Coastguard Worker  BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0;
158*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
159*1b3f573fSAndroid Build Coastguard Worker                                                     file:file
160*1b3f573fSAndroid Build Coastguard Worker                                                   fields:fields
161*1b3f573fSAndroid Build Coastguard Worker                                              storageSize:storageSize
162*1b3f573fSAndroid Build Coastguard Worker                                               wireFormat:wireFormat];
163*1b3f573fSAndroid Build Coastguard Worker  [fields release];
164*1b3f573fSAndroid Build Coastguard Worker  return descriptor;
165*1b3f573fSAndroid Build Coastguard Worker}
166*1b3f573fSAndroid Build Coastguard Worker
167*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithClass:(Class)messageClass
168*1b3f573fSAndroid Build Coastguard Worker                         file:(GPBFileDescriptor *)file
169*1b3f573fSAndroid Build Coastguard Worker                       fields:(NSArray *)fields
170*1b3f573fSAndroid Build Coastguard Worker                  storageSize:(uint32_t)storageSize
171*1b3f573fSAndroid Build Coastguard Worker                   wireFormat:(BOOL)wireFormat {
172*1b3f573fSAndroid Build Coastguard Worker  if ((self = [super init])) {
173*1b3f573fSAndroid Build Coastguard Worker    messageClass_ = messageClass;
174*1b3f573fSAndroid Build Coastguard Worker    file_ = file;
175*1b3f573fSAndroid Build Coastguard Worker    fields_ = [fields retain];
176*1b3f573fSAndroid Build Coastguard Worker    storageSize_ = storageSize;
177*1b3f573fSAndroid Build Coastguard Worker    wireFormat_ = wireFormat;
178*1b3f573fSAndroid Build Coastguard Worker  }
179*1b3f573fSAndroid Build Coastguard Worker  return self;
180*1b3f573fSAndroid Build Coastguard Worker}
181*1b3f573fSAndroid Build Coastguard Worker
182*1b3f573fSAndroid Build Coastguard Worker- (void)dealloc {
183*1b3f573fSAndroid Build Coastguard Worker  [fields_ release];
184*1b3f573fSAndroid Build Coastguard Worker  [oneofs_ release];
185*1b3f573fSAndroid Build Coastguard Worker  [super dealloc];
186*1b3f573fSAndroid Build Coastguard Worker}
187*1b3f573fSAndroid Build Coastguard Worker
188*1b3f573fSAndroid Build Coastguard Worker- (void)setupOneofs:(const char **)oneofNames
189*1b3f573fSAndroid Build Coastguard Worker              count:(uint32_t)count
190*1b3f573fSAndroid Build Coastguard Worker      firstHasIndex:(int32_t)firstHasIndex {
191*1b3f573fSAndroid Build Coastguard Worker  NSCAssert(firstHasIndex < 0, @"Should always be <0");
192*1b3f573fSAndroid Build Coastguard Worker  NSMutableArray *oneofs = [[NSMutableArray alloc] initWithCapacity:count];
193*1b3f573fSAndroid Build Coastguard Worker  for (uint32_t i = 0, hasIndex = firstHasIndex; i < count; ++i, --hasIndex) {
194*1b3f573fSAndroid Build Coastguard Worker    const char *name = oneofNames[i];
195*1b3f573fSAndroid Build Coastguard Worker    NSArray *fieldsForOneof = NewFieldsArrayForHasIndex(hasIndex, fields_);
196*1b3f573fSAndroid Build Coastguard Worker    NSCAssert(fieldsForOneof.count > 0,
197*1b3f573fSAndroid Build Coastguard Worker              @"No fields for this oneof? (%s:%d)", name, hasIndex);
198*1b3f573fSAndroid Build Coastguard Worker    GPBOneofDescriptor *oneofDescriptor =
199*1b3f573fSAndroid Build Coastguard Worker        [[GPBOneofDescriptor alloc] initWithName:name fields:fieldsForOneof];
200*1b3f573fSAndroid Build Coastguard Worker    [oneofs addObject:oneofDescriptor];
201*1b3f573fSAndroid Build Coastguard Worker    [oneofDescriptor release];
202*1b3f573fSAndroid Build Coastguard Worker    [fieldsForOneof release];
203*1b3f573fSAndroid Build Coastguard Worker  }
204*1b3f573fSAndroid Build Coastguard Worker  oneofs_ = oneofs;
205*1b3f573fSAndroid Build Coastguard Worker}
206*1b3f573fSAndroid Build Coastguard Worker
207*1b3f573fSAndroid Build Coastguard Worker- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo {
208*1b3f573fSAndroid Build Coastguard Worker  // Extra info is a compile time option, so skip the work if not needed.
209*1b3f573fSAndroid Build Coastguard Worker  if (extraTextFormatInfo) {
210*1b3f573fSAndroid Build Coastguard Worker    NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo];
211*1b3f573fSAndroid Build Coastguard Worker    for (GPBFieldDescriptor *fieldDescriptor in fields_) {
212*1b3f573fSAndroid Build Coastguard Worker      if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) {
213*1b3f573fSAndroid Build Coastguard Worker        objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey,
214*1b3f573fSAndroid Build Coastguard Worker                                 extraInfoValue,
215*1b3f573fSAndroid Build Coastguard Worker                                 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
216*1b3f573fSAndroid Build Coastguard Worker      }
217*1b3f573fSAndroid Build Coastguard Worker    }
218*1b3f573fSAndroid Build Coastguard Worker  }
219*1b3f573fSAndroid Build Coastguard Worker}
220*1b3f573fSAndroid Build Coastguard Worker
221*1b3f573fSAndroid Build Coastguard Worker- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count {
222*1b3f573fSAndroid Build Coastguard Worker  extensionRanges_ = ranges;
223*1b3f573fSAndroid Build Coastguard Worker  extensionRangesCount_ = count;
224*1b3f573fSAndroid Build Coastguard Worker}
225*1b3f573fSAndroid Build Coastguard Worker
226*1b3f573fSAndroid Build Coastguard Worker- (void)setupContainingMessageClass:(Class)messageClass {
227*1b3f573fSAndroid Build Coastguard Worker  objc_setAssociatedObject(self, &kParentClassValueKey,
228*1b3f573fSAndroid Build Coastguard Worker                           messageClass,
229*1b3f573fSAndroid Build Coastguard Worker                           OBJC_ASSOCIATION_ASSIGN);
230*1b3f573fSAndroid Build Coastguard Worker}
231*1b3f573fSAndroid Build Coastguard Worker
232*1b3f573fSAndroid Build Coastguard Worker- (void)setupContainingMessageClassName:(const char *)msgClassName {
233*1b3f573fSAndroid Build Coastguard Worker  // Note: Only fetch the class here, can't send messages to it because
234*1b3f573fSAndroid Build Coastguard Worker  // that could cause cycles back to this class within +initialize if
235*1b3f573fSAndroid Build Coastguard Worker  // two messages have each other in fields (i.e. - they build a graph).
236*1b3f573fSAndroid Build Coastguard Worker  Class clazz = objc_getClass(msgClassName);
237*1b3f573fSAndroid Build Coastguard Worker  NSAssert(clazz, @"Class %s not defined", msgClassName);
238*1b3f573fSAndroid Build Coastguard Worker  [self setupContainingMessageClass:clazz];
239*1b3f573fSAndroid Build Coastguard Worker}
240*1b3f573fSAndroid Build Coastguard Worker
241*1b3f573fSAndroid Build Coastguard Worker- (void)setupMessageClassNameSuffix:(NSString *)suffix {
242*1b3f573fSAndroid Build Coastguard Worker  if (suffix.length) {
243*1b3f573fSAndroid Build Coastguard Worker    objc_setAssociatedObject(self, &kClassNameSuffixKey,
244*1b3f573fSAndroid Build Coastguard Worker                             suffix,
245*1b3f573fSAndroid Build Coastguard Worker                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
246*1b3f573fSAndroid Build Coastguard Worker  }
247*1b3f573fSAndroid Build Coastguard Worker}
248*1b3f573fSAndroid Build Coastguard Worker
249*1b3f573fSAndroid Build Coastguard Worker- (NSString *)name {
250*1b3f573fSAndroid Build Coastguard Worker  return NSStringFromClass(messageClass_);
251*1b3f573fSAndroid Build Coastguard Worker}
252*1b3f573fSAndroid Build Coastguard Worker
253*1b3f573fSAndroid Build Coastguard Worker- (GPBDescriptor *)containingType {
254*1b3f573fSAndroid Build Coastguard Worker  Class parentClass = objc_getAssociatedObject(self, &kParentClassValueKey);
255*1b3f573fSAndroid Build Coastguard Worker  return [parentClass descriptor];
256*1b3f573fSAndroid Build Coastguard Worker}
257*1b3f573fSAndroid Build Coastguard Worker
258*1b3f573fSAndroid Build Coastguard Worker- (NSString *)fullName {
259*1b3f573fSAndroid Build Coastguard Worker  NSString *className = NSStringFromClass(self.messageClass);
260*1b3f573fSAndroid Build Coastguard Worker  GPBFileDescriptor *file = self.file;
261*1b3f573fSAndroid Build Coastguard Worker  NSString *objcPrefix = file.objcPrefix;
262*1b3f573fSAndroid Build Coastguard Worker  if (objcPrefix && ![className hasPrefix:objcPrefix]) {
263*1b3f573fSAndroid Build Coastguard Worker    NSAssert(0,
264*1b3f573fSAndroid Build Coastguard Worker             @"Class didn't have correct prefix? (%@ - %@)",
265*1b3f573fSAndroid Build Coastguard Worker             className, objcPrefix);
266*1b3f573fSAndroid Build Coastguard Worker    return nil;
267*1b3f573fSAndroid Build Coastguard Worker  }
268*1b3f573fSAndroid Build Coastguard Worker  GPBDescriptor *parent = self.containingType;
269*1b3f573fSAndroid Build Coastguard Worker
270*1b3f573fSAndroid Build Coastguard Worker  NSString *name = nil;
271*1b3f573fSAndroid Build Coastguard Worker  if (parent) {
272*1b3f573fSAndroid Build Coastguard Worker    NSString *parentClassName = NSStringFromClass(parent.messageClass);
273*1b3f573fSAndroid Build Coastguard Worker    // The generator will add _Class to avoid reserved words, drop it.
274*1b3f573fSAndroid Build Coastguard Worker    NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
275*1b3f573fSAndroid Build Coastguard Worker    if (suffix) {
276*1b3f573fSAndroid Build Coastguard Worker      if (![parentClassName hasSuffix:suffix]) {
277*1b3f573fSAndroid Build Coastguard Worker        NSAssert(0,
278*1b3f573fSAndroid Build Coastguard Worker                 @"ParentMessage class didn't have correct suffix? (%@ - %@)",
279*1b3f573fSAndroid Build Coastguard Worker                 className, suffix);
280*1b3f573fSAndroid Build Coastguard Worker        return nil;
281*1b3f573fSAndroid Build Coastguard Worker      }
282*1b3f573fSAndroid Build Coastguard Worker      parentClassName =
283*1b3f573fSAndroid Build Coastguard Worker          [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
284*1b3f573fSAndroid Build Coastguard Worker    }
285*1b3f573fSAndroid Build Coastguard Worker    NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
286*1b3f573fSAndroid Build Coastguard Worker    if (![className hasPrefix:parentPrefix]) {
287*1b3f573fSAndroid Build Coastguard Worker      NSAssert(0,
288*1b3f573fSAndroid Build Coastguard Worker               @"Class didn't have the correct parent name prefix? (%@ - %@)",
289*1b3f573fSAndroid Build Coastguard Worker               parentPrefix, className);
290*1b3f573fSAndroid Build Coastguard Worker      return nil;
291*1b3f573fSAndroid Build Coastguard Worker    }
292*1b3f573fSAndroid Build Coastguard Worker    name = [className substringFromIndex:parentPrefix.length];
293*1b3f573fSAndroid Build Coastguard Worker  } else {
294*1b3f573fSAndroid Build Coastguard Worker    name = [className substringFromIndex:objcPrefix.length];
295*1b3f573fSAndroid Build Coastguard Worker  }
296*1b3f573fSAndroid Build Coastguard Worker
297*1b3f573fSAndroid Build Coastguard Worker  // The generator will add _Class to avoid reserved words, drop it.
298*1b3f573fSAndroid Build Coastguard Worker  NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
299*1b3f573fSAndroid Build Coastguard Worker  if (suffix) {
300*1b3f573fSAndroid Build Coastguard Worker    if (![name hasSuffix:suffix]) {
301*1b3f573fSAndroid Build Coastguard Worker      NSAssert(0,
302*1b3f573fSAndroid Build Coastguard Worker               @"Message class didn't have correct suffix? (%@ - %@)",
303*1b3f573fSAndroid Build Coastguard Worker               name, suffix);
304*1b3f573fSAndroid Build Coastguard Worker      return nil;
305*1b3f573fSAndroid Build Coastguard Worker    }
306*1b3f573fSAndroid Build Coastguard Worker    name = [name substringToIndex:(name.length - suffix.length)];
307*1b3f573fSAndroid Build Coastguard Worker  }
308*1b3f573fSAndroid Build Coastguard Worker
309*1b3f573fSAndroid Build Coastguard Worker  NSString *prefix = (parent != nil ? parent.fullName : file.package);
310*1b3f573fSAndroid Build Coastguard Worker  NSString *result;
311*1b3f573fSAndroid Build Coastguard Worker  if (prefix.length > 0) {
312*1b3f573fSAndroid Build Coastguard Worker    result = [NSString stringWithFormat:@"%@.%@", prefix, name];
313*1b3f573fSAndroid Build Coastguard Worker  } else {
314*1b3f573fSAndroid Build Coastguard Worker    result = name;
315*1b3f573fSAndroid Build Coastguard Worker  }
316*1b3f573fSAndroid Build Coastguard Worker  return result;
317*1b3f573fSAndroid Build Coastguard Worker}
318*1b3f573fSAndroid Build Coastguard Worker
319*1b3f573fSAndroid Build Coastguard Worker- (id)copyWithZone:(NSZone *)zone {
320*1b3f573fSAndroid Build Coastguard Worker#pragma unused(zone)
321*1b3f573fSAndroid Build Coastguard Worker  return [self retain];
322*1b3f573fSAndroid Build Coastguard Worker}
323*1b3f573fSAndroid Build Coastguard Worker
324*1b3f573fSAndroid Build Coastguard Worker- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
325*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *descriptor in fields_) {
326*1b3f573fSAndroid Build Coastguard Worker    if (GPBFieldNumber(descriptor) == fieldNumber) {
327*1b3f573fSAndroid Build Coastguard Worker      return descriptor;
328*1b3f573fSAndroid Build Coastguard Worker    }
329*1b3f573fSAndroid Build Coastguard Worker  }
330*1b3f573fSAndroid Build Coastguard Worker  return nil;
331*1b3f573fSAndroid Build Coastguard Worker}
332*1b3f573fSAndroid Build Coastguard Worker
333*1b3f573fSAndroid Build Coastguard Worker- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
334*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *descriptor in fields_) {
335*1b3f573fSAndroid Build Coastguard Worker    if ([descriptor.name isEqual:name]) {
336*1b3f573fSAndroid Build Coastguard Worker      return descriptor;
337*1b3f573fSAndroid Build Coastguard Worker    }
338*1b3f573fSAndroid Build Coastguard Worker  }
339*1b3f573fSAndroid Build Coastguard Worker  return nil;
340*1b3f573fSAndroid Build Coastguard Worker}
341*1b3f573fSAndroid Build Coastguard Worker
342*1b3f573fSAndroid Build Coastguard Worker- (GPBOneofDescriptor *)oneofWithName:(NSString *)name {
343*1b3f573fSAndroid Build Coastguard Worker  for (GPBOneofDescriptor *descriptor in oneofs_) {
344*1b3f573fSAndroid Build Coastguard Worker    if ([descriptor.name isEqual:name]) {
345*1b3f573fSAndroid Build Coastguard Worker      return descriptor;
346*1b3f573fSAndroid Build Coastguard Worker    }
347*1b3f573fSAndroid Build Coastguard Worker  }
348*1b3f573fSAndroid Build Coastguard Worker  return nil;
349*1b3f573fSAndroid Build Coastguard Worker}
350*1b3f573fSAndroid Build Coastguard Worker
351*1b3f573fSAndroid Build Coastguard Worker@end
352*1b3f573fSAndroid Build Coastguard Worker
353*1b3f573fSAndroid Build Coastguard Worker@implementation GPBFileDescriptor {
354*1b3f573fSAndroid Build Coastguard Worker  NSString *package_;
355*1b3f573fSAndroid Build Coastguard Worker  NSString *objcPrefix_;
356*1b3f573fSAndroid Build Coastguard Worker  GPBFileSyntax syntax_;
357*1b3f573fSAndroid Build Coastguard Worker}
358*1b3f573fSAndroid Build Coastguard Worker
359*1b3f573fSAndroid Build Coastguard Worker@synthesize package = package_;
360*1b3f573fSAndroid Build Coastguard Worker@synthesize objcPrefix = objcPrefix_;
361*1b3f573fSAndroid Build Coastguard Worker@synthesize syntax = syntax_;
362*1b3f573fSAndroid Build Coastguard Worker
363*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithPackage:(NSString *)package
364*1b3f573fSAndroid Build Coastguard Worker                     objcPrefix:(NSString *)objcPrefix
365*1b3f573fSAndroid Build Coastguard Worker                         syntax:(GPBFileSyntax)syntax {
366*1b3f573fSAndroid Build Coastguard Worker  self = [super init];
367*1b3f573fSAndroid Build Coastguard Worker  if (self) {
368*1b3f573fSAndroid Build Coastguard Worker    package_ = [package copy];
369*1b3f573fSAndroid Build Coastguard Worker    objcPrefix_ = [objcPrefix copy];
370*1b3f573fSAndroid Build Coastguard Worker    syntax_ = syntax;
371*1b3f573fSAndroid Build Coastguard Worker  }
372*1b3f573fSAndroid Build Coastguard Worker  return self;
373*1b3f573fSAndroid Build Coastguard Worker}
374*1b3f573fSAndroid Build Coastguard Worker
375*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithPackage:(NSString *)package
376*1b3f573fSAndroid Build Coastguard Worker                         syntax:(GPBFileSyntax)syntax {
377*1b3f573fSAndroid Build Coastguard Worker  self = [super init];
378*1b3f573fSAndroid Build Coastguard Worker  if (self) {
379*1b3f573fSAndroid Build Coastguard Worker    package_ = [package copy];
380*1b3f573fSAndroid Build Coastguard Worker    syntax_ = syntax;
381*1b3f573fSAndroid Build Coastguard Worker  }
382*1b3f573fSAndroid Build Coastguard Worker  return self;
383*1b3f573fSAndroid Build Coastguard Worker}
384*1b3f573fSAndroid Build Coastguard Worker
385*1b3f573fSAndroid Build Coastguard Worker- (void)dealloc {
386*1b3f573fSAndroid Build Coastguard Worker  [package_ release];
387*1b3f573fSAndroid Build Coastguard Worker  [objcPrefix_ release];
388*1b3f573fSAndroid Build Coastguard Worker  [super dealloc];
389*1b3f573fSAndroid Build Coastguard Worker}
390*1b3f573fSAndroid Build Coastguard Worker
391*1b3f573fSAndroid Build Coastguard Worker@end
392*1b3f573fSAndroid Build Coastguard Worker
393*1b3f573fSAndroid Build Coastguard Worker@implementation GPBOneofDescriptor
394*1b3f573fSAndroid Build Coastguard Worker
395*1b3f573fSAndroid Build Coastguard Worker@synthesize fields = fields_;
396*1b3f573fSAndroid Build Coastguard Worker
397*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields {
398*1b3f573fSAndroid Build Coastguard Worker  self = [super init];
399*1b3f573fSAndroid Build Coastguard Worker  if (self) {
400*1b3f573fSAndroid Build Coastguard Worker    name_ = name;
401*1b3f573fSAndroid Build Coastguard Worker    fields_ = [fields retain];
402*1b3f573fSAndroid Build Coastguard Worker    for (GPBFieldDescriptor *fieldDesc in fields) {
403*1b3f573fSAndroid Build Coastguard Worker      fieldDesc->containingOneof_ = self;
404*1b3f573fSAndroid Build Coastguard Worker    }
405*1b3f573fSAndroid Build Coastguard Worker
406*1b3f573fSAndroid Build Coastguard Worker    caseSel_ = SelFromStrings(NULL, name, "OneOfCase", NO);
407*1b3f573fSAndroid Build Coastguard Worker  }
408*1b3f573fSAndroid Build Coastguard Worker  return self;
409*1b3f573fSAndroid Build Coastguard Worker}
410*1b3f573fSAndroid Build Coastguard Worker
411*1b3f573fSAndroid Build Coastguard Worker- (void)dealloc {
412*1b3f573fSAndroid Build Coastguard Worker  [fields_ release];
413*1b3f573fSAndroid Build Coastguard Worker  [super dealloc];
414*1b3f573fSAndroid Build Coastguard Worker}
415*1b3f573fSAndroid Build Coastguard Worker
416*1b3f573fSAndroid Build Coastguard Worker- (NSString *)name {
417*1b3f573fSAndroid Build Coastguard Worker  return (NSString * _Nonnull)@(name_);
418*1b3f573fSAndroid Build Coastguard Worker}
419*1b3f573fSAndroid Build Coastguard Worker
420*1b3f573fSAndroid Build Coastguard Worker- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
421*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *descriptor in fields_) {
422*1b3f573fSAndroid Build Coastguard Worker    if (GPBFieldNumber(descriptor) == fieldNumber) {
423*1b3f573fSAndroid Build Coastguard Worker      return descriptor;
424*1b3f573fSAndroid Build Coastguard Worker    }
425*1b3f573fSAndroid Build Coastguard Worker  }
426*1b3f573fSAndroid Build Coastguard Worker  return nil;
427*1b3f573fSAndroid Build Coastguard Worker}
428*1b3f573fSAndroid Build Coastguard Worker
429*1b3f573fSAndroid Build Coastguard Worker- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
430*1b3f573fSAndroid Build Coastguard Worker  for (GPBFieldDescriptor *descriptor in fields_) {
431*1b3f573fSAndroid Build Coastguard Worker    if ([descriptor.name isEqual:name]) {
432*1b3f573fSAndroid Build Coastguard Worker      return descriptor;
433*1b3f573fSAndroid Build Coastguard Worker    }
434*1b3f573fSAndroid Build Coastguard Worker  }
435*1b3f573fSAndroid Build Coastguard Worker  return nil;
436*1b3f573fSAndroid Build Coastguard Worker}
437*1b3f573fSAndroid Build Coastguard Worker
438*1b3f573fSAndroid Build Coastguard Worker@end
439*1b3f573fSAndroid Build Coastguard Worker
440*1b3f573fSAndroid Build Coastguard Workeruint32_t GPBFieldTag(GPBFieldDescriptor *self) {
441*1b3f573fSAndroid Build Coastguard Worker  GPBMessageFieldDescription *description = self->description_;
442*1b3f573fSAndroid Build Coastguard Worker  GPBWireFormat format;
443*1b3f573fSAndroid Build Coastguard Worker  if ((description->flags & GPBFieldMapKeyMask) != 0) {
444*1b3f573fSAndroid Build Coastguard Worker    // Maps are repeated messages on the wire.
445*1b3f573fSAndroid Build Coastguard Worker    format = GPBWireFormatForType(GPBDataTypeMessage, NO);
446*1b3f573fSAndroid Build Coastguard Worker  } else {
447*1b3f573fSAndroid Build Coastguard Worker    format = GPBWireFormatForType(description->dataType,
448*1b3f573fSAndroid Build Coastguard Worker                                  ((description->flags & GPBFieldPacked) != 0));
449*1b3f573fSAndroid Build Coastguard Worker  }
450*1b3f573fSAndroid Build Coastguard Worker  return GPBWireFormatMakeTag(description->number, format);
451*1b3f573fSAndroid Build Coastguard Worker}
452*1b3f573fSAndroid Build Coastguard Worker
453*1b3f573fSAndroid Build Coastguard Workeruint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
454*1b3f573fSAndroid Build Coastguard Worker  GPBMessageFieldDescription *description = self->description_;
455*1b3f573fSAndroid Build Coastguard Worker  NSCAssert((description->flags & GPBFieldRepeated) != 0,
456*1b3f573fSAndroid Build Coastguard Worker            @"Only valid on repeated fields");
457*1b3f573fSAndroid Build Coastguard Worker  GPBWireFormat format =
458*1b3f573fSAndroid Build Coastguard Worker      GPBWireFormatForType(description->dataType,
459*1b3f573fSAndroid Build Coastguard Worker                           ((description->flags & GPBFieldPacked) == 0));
460*1b3f573fSAndroid Build Coastguard Worker  return GPBWireFormatMakeTag(description->number, format);
461*1b3f573fSAndroid Build Coastguard Worker}
462*1b3f573fSAndroid Build Coastguard Worker
463*1b3f573fSAndroid Build Coastguard Worker@implementation GPBFieldDescriptor {
464*1b3f573fSAndroid Build Coastguard Worker  GPBGenericValue defaultValue_;
465*1b3f573fSAndroid Build Coastguard Worker
466*1b3f573fSAndroid Build Coastguard Worker  // Message ivars
467*1b3f573fSAndroid Build Coastguard Worker  Class msgClass_;
468*1b3f573fSAndroid Build Coastguard Worker
469*1b3f573fSAndroid Build Coastguard Worker  // Enum ivars.
470*1b3f573fSAndroid Build Coastguard Worker  // If protos are generated with GenerateEnumDescriptors on then it will
471*1b3f573fSAndroid Build Coastguard Worker  // be a enumDescriptor, otherwise it will be a enumVerifier.
472*1b3f573fSAndroid Build Coastguard Worker  union {
473*1b3f573fSAndroid Build Coastguard Worker    GPBEnumDescriptor *enumDescriptor_;
474*1b3f573fSAndroid Build Coastguard Worker    GPBEnumValidationFunc enumVerifier_;
475*1b3f573fSAndroid Build Coastguard Worker  } enumHandling_;
476*1b3f573fSAndroid Build Coastguard Worker}
477*1b3f573fSAndroid Build Coastguard Worker
478*1b3f573fSAndroid Build Coastguard Worker@synthesize msgClass = msgClass_;
479*1b3f573fSAndroid Build Coastguard Worker@synthesize containingOneof = containingOneof_;
480*1b3f573fSAndroid Build Coastguard Worker
481*1b3f573fSAndroid Build Coastguard Worker- (instancetype)init {
482*1b3f573fSAndroid Build Coastguard Worker  // Throw an exception if people attempt to not use the designated initializer.
483*1b3f573fSAndroid Build Coastguard Worker  self = [super init];
484*1b3f573fSAndroid Build Coastguard Worker  if (self != nil) {
485*1b3f573fSAndroid Build Coastguard Worker    [self doesNotRecognizeSelector:_cmd];
486*1b3f573fSAndroid Build Coastguard Worker    self = nil;
487*1b3f573fSAndroid Build Coastguard Worker  }
488*1b3f573fSAndroid Build Coastguard Worker  return self;
489*1b3f573fSAndroid Build Coastguard Worker}
490*1b3f573fSAndroid Build Coastguard Worker
491*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithFieldDescription:(void *)description
492*1b3f573fSAndroid Build Coastguard Worker                         includesDefault:(BOOL)includesDefault
493*1b3f573fSAndroid Build Coastguard Worker                           usesClassRefs:(BOOL)usesClassRefs
494*1b3f573fSAndroid Build Coastguard Worker                     proto3OptionalKnown:(BOOL)proto3OptionalKnown
495*1b3f573fSAndroid Build Coastguard Worker                                  syntax:(GPBFileSyntax)syntax {
496*1b3f573fSAndroid Build Coastguard Worker  if ((self = [super init])) {
497*1b3f573fSAndroid Build Coastguard Worker    GPBMessageFieldDescription *coreDesc;
498*1b3f573fSAndroid Build Coastguard Worker    if (includesDefault) {
499*1b3f573fSAndroid Build Coastguard Worker      coreDesc = &(((GPBMessageFieldDescriptionWithDefault *)description)->core);
500*1b3f573fSAndroid Build Coastguard Worker    } else {
501*1b3f573fSAndroid Build Coastguard Worker      coreDesc = description;
502*1b3f573fSAndroid Build Coastguard Worker    }
503*1b3f573fSAndroid Build Coastguard Worker    description_ = coreDesc;
504*1b3f573fSAndroid Build Coastguard Worker    getSel_ = sel_getUid(coreDesc->name);
505*1b3f573fSAndroid Build Coastguard Worker    setSel_ = SelFromStrings("set", coreDesc->name, NULL, YES);
506*1b3f573fSAndroid Build Coastguard Worker
507*1b3f573fSAndroid Build Coastguard Worker    GPBDataType dataType = coreDesc->dataType;
508*1b3f573fSAndroid Build Coastguard Worker    BOOL isMessage = GPBDataTypeIsMessage(dataType);
509*1b3f573fSAndroid Build Coastguard Worker    BOOL isMapOrArray = GPBFieldIsMapOrArray(self);
510*1b3f573fSAndroid Build Coastguard Worker
511*1b3f573fSAndroid Build Coastguard Worker    // If proto3 optionals weren't known (i.e. generated code from an
512*1b3f573fSAndroid Build Coastguard Worker    // older version), compute the flag for the rest of the runtime.
513*1b3f573fSAndroid Build Coastguard Worker    if (!proto3OptionalKnown) {
514*1b3f573fSAndroid Build Coastguard Worker      // If it was...
515*1b3f573fSAndroid Build Coastguard Worker      //  - proto3 syntax
516*1b3f573fSAndroid Build Coastguard Worker      //  - not repeated/map
517*1b3f573fSAndroid Build Coastguard Worker      //  - not in a oneof (negative has index)
518*1b3f573fSAndroid Build Coastguard Worker      //  - not a message (the flag doesn't make sense for messages)
519*1b3f573fSAndroid Build Coastguard Worker      BOOL clearOnZero = ((syntax == GPBFileSyntaxProto3) &&
520*1b3f573fSAndroid Build Coastguard Worker                          !isMapOrArray &&
521*1b3f573fSAndroid Build Coastguard Worker                          (coreDesc->hasIndex >= 0) &&
522*1b3f573fSAndroid Build Coastguard Worker                          !isMessage);
523*1b3f573fSAndroid Build Coastguard Worker      if (clearOnZero) {
524*1b3f573fSAndroid Build Coastguard Worker        coreDesc->flags |= GPBFieldClearHasIvarOnZero;
525*1b3f573fSAndroid Build Coastguard Worker      }
526*1b3f573fSAndroid Build Coastguard Worker    }
527*1b3f573fSAndroid Build Coastguard Worker
528*1b3f573fSAndroid Build Coastguard Worker    if (isMapOrArray) {
529*1b3f573fSAndroid Build Coastguard Worker      // map<>/repeated fields get a *Count property (inplace of a has*) to
530*1b3f573fSAndroid Build Coastguard Worker      // support checking if there are any entries without triggering
531*1b3f573fSAndroid Build Coastguard Worker      // autocreation.
532*1b3f573fSAndroid Build Coastguard Worker      hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO);
533*1b3f573fSAndroid Build Coastguard Worker    } else {
534*1b3f573fSAndroid Build Coastguard Worker      // It is a single field; it gets has/setHas selectors if...
535*1b3f573fSAndroid Build Coastguard Worker      //  - not in a oneof (negative has index)
536*1b3f573fSAndroid Build Coastguard Worker      //  - not clearing on zero
537*1b3f573fSAndroid Build Coastguard Worker      if ((coreDesc->hasIndex >= 0) &&
538*1b3f573fSAndroid Build Coastguard Worker          ((coreDesc->flags & GPBFieldClearHasIvarOnZero) == 0)) {
539*1b3f573fSAndroid Build Coastguard Worker        hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO);
540*1b3f573fSAndroid Build Coastguard Worker        setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES);
541*1b3f573fSAndroid Build Coastguard Worker      }
542*1b3f573fSAndroid Build Coastguard Worker    }
543*1b3f573fSAndroid Build Coastguard Worker
544*1b3f573fSAndroid Build Coastguard Worker    // Extra type specific data.
545*1b3f573fSAndroid Build Coastguard Worker    if (isMessage) {
546*1b3f573fSAndroid Build Coastguard Worker      // Note: Only fetch the class here, can't send messages to it because
547*1b3f573fSAndroid Build Coastguard Worker      // that could cause cycles back to this class within +initialize if
548*1b3f573fSAndroid Build Coastguard Worker      // two messages have each other in fields (i.e. - they build a graph).
549*1b3f573fSAndroid Build Coastguard Worker      if (usesClassRefs) {
550*1b3f573fSAndroid Build Coastguard Worker        msgClass_ = coreDesc->dataTypeSpecific.clazz;
551*1b3f573fSAndroid Build Coastguard Worker      } else {
552*1b3f573fSAndroid Build Coastguard Worker        // Backwards compatibility for sources generated with older protoc.
553*1b3f573fSAndroid Build Coastguard Worker        const char *className = coreDesc->dataTypeSpecific.className;
554*1b3f573fSAndroid Build Coastguard Worker        msgClass_ = objc_getClass(className);
555*1b3f573fSAndroid Build Coastguard Worker        NSAssert(msgClass_, @"Class %s not defined", className);
556*1b3f573fSAndroid Build Coastguard Worker      }
557*1b3f573fSAndroid Build Coastguard Worker    } else if (dataType == GPBDataTypeEnum) {
558*1b3f573fSAndroid Build Coastguard Worker      if ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0) {
559*1b3f573fSAndroid Build Coastguard Worker        enumHandling_.enumDescriptor_ =
560*1b3f573fSAndroid Build Coastguard Worker            coreDesc->dataTypeSpecific.enumDescFunc();
561*1b3f573fSAndroid Build Coastguard Worker      } else {
562*1b3f573fSAndroid Build Coastguard Worker        enumHandling_.enumVerifier_ =
563*1b3f573fSAndroid Build Coastguard Worker            coreDesc->dataTypeSpecific.enumVerifier;
564*1b3f573fSAndroid Build Coastguard Worker      }
565*1b3f573fSAndroid Build Coastguard Worker    }
566*1b3f573fSAndroid Build Coastguard Worker
567*1b3f573fSAndroid Build Coastguard Worker    // Non map<>/repeated fields can have defaults in proto2 syntax.
568*1b3f573fSAndroid Build Coastguard Worker    if (!isMapOrArray && includesDefault) {
569*1b3f573fSAndroid Build Coastguard Worker      defaultValue_ = ((GPBMessageFieldDescriptionWithDefault *)description)->defaultValue;
570*1b3f573fSAndroid Build Coastguard Worker      if (dataType == GPBDataTypeBytes) {
571*1b3f573fSAndroid Build Coastguard Worker        // Data stored as a length prefixed (network byte order) c-string in
572*1b3f573fSAndroid Build Coastguard Worker        // descriptor structure.
573*1b3f573fSAndroid Build Coastguard Worker        const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData;
574*1b3f573fSAndroid Build Coastguard Worker        if (bytes) {
575*1b3f573fSAndroid Build Coastguard Worker          uint32_t length;
576*1b3f573fSAndroid Build Coastguard Worker          memcpy(&length, bytes, sizeof(length));
577*1b3f573fSAndroid Build Coastguard Worker          length = ntohl(length);
578*1b3f573fSAndroid Build Coastguard Worker          bytes += sizeof(length);
579*1b3f573fSAndroid Build Coastguard Worker          defaultValue_.valueData =
580*1b3f573fSAndroid Build Coastguard Worker              [[NSData alloc] initWithBytes:bytes length:length];
581*1b3f573fSAndroid Build Coastguard Worker        }
582*1b3f573fSAndroid Build Coastguard Worker      }
583*1b3f573fSAndroid Build Coastguard Worker    }
584*1b3f573fSAndroid Build Coastguard Worker  }
585*1b3f573fSAndroid Build Coastguard Worker  return self;
586*1b3f573fSAndroid Build Coastguard Worker}
587*1b3f573fSAndroid Build Coastguard Worker
588*1b3f573fSAndroid Build Coastguard Worker- (void)dealloc {
589*1b3f573fSAndroid Build Coastguard Worker  if (description_->dataType == GPBDataTypeBytes &&
590*1b3f573fSAndroid Build Coastguard Worker      !(description_->flags & GPBFieldRepeated)) {
591*1b3f573fSAndroid Build Coastguard Worker    [defaultValue_.valueData release];
592*1b3f573fSAndroid Build Coastguard Worker  }
593*1b3f573fSAndroid Build Coastguard Worker  [super dealloc];
594*1b3f573fSAndroid Build Coastguard Worker}
595*1b3f573fSAndroid Build Coastguard Worker
596*1b3f573fSAndroid Build Coastguard Worker- (GPBDataType)dataType {
597*1b3f573fSAndroid Build Coastguard Worker  return description_->dataType;
598*1b3f573fSAndroid Build Coastguard Worker}
599*1b3f573fSAndroid Build Coastguard Worker
600*1b3f573fSAndroid Build Coastguard Worker- (BOOL)hasDefaultValue {
601*1b3f573fSAndroid Build Coastguard Worker  return (description_->flags & GPBFieldHasDefaultValue) != 0;
602*1b3f573fSAndroid Build Coastguard Worker}
603*1b3f573fSAndroid Build Coastguard Worker
604*1b3f573fSAndroid Build Coastguard Worker- (uint32_t)number {
605*1b3f573fSAndroid Build Coastguard Worker  return description_->number;
606*1b3f573fSAndroid Build Coastguard Worker}
607*1b3f573fSAndroid Build Coastguard Worker
608*1b3f573fSAndroid Build Coastguard Worker- (NSString *)name {
609*1b3f573fSAndroid Build Coastguard Worker  return (NSString * _Nonnull)@(description_->name);
610*1b3f573fSAndroid Build Coastguard Worker}
611*1b3f573fSAndroid Build Coastguard Worker
612*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isRequired {
613*1b3f573fSAndroid Build Coastguard Worker  return (description_->flags & GPBFieldRequired) != 0;
614*1b3f573fSAndroid Build Coastguard Worker}
615*1b3f573fSAndroid Build Coastguard Worker
616*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isOptional {
617*1b3f573fSAndroid Build Coastguard Worker  return (description_->flags & GPBFieldOptional) != 0;
618*1b3f573fSAndroid Build Coastguard Worker}
619*1b3f573fSAndroid Build Coastguard Worker
620*1b3f573fSAndroid Build Coastguard Worker- (GPBFieldType)fieldType {
621*1b3f573fSAndroid Build Coastguard Worker  GPBFieldFlags flags = description_->flags;
622*1b3f573fSAndroid Build Coastguard Worker  if ((flags & GPBFieldRepeated) != 0) {
623*1b3f573fSAndroid Build Coastguard Worker    return GPBFieldTypeRepeated;
624*1b3f573fSAndroid Build Coastguard Worker  } else if ((flags & GPBFieldMapKeyMask) != 0) {
625*1b3f573fSAndroid Build Coastguard Worker    return GPBFieldTypeMap;
626*1b3f573fSAndroid Build Coastguard Worker  } else {
627*1b3f573fSAndroid Build Coastguard Worker    return GPBFieldTypeSingle;
628*1b3f573fSAndroid Build Coastguard Worker  }
629*1b3f573fSAndroid Build Coastguard Worker}
630*1b3f573fSAndroid Build Coastguard Worker
631*1b3f573fSAndroid Build Coastguard Worker- (GPBDataType)mapKeyDataType {
632*1b3f573fSAndroid Build Coastguard Worker  switch (description_->flags & GPBFieldMapKeyMask) {
633*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeyInt32:
634*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeInt32;
635*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeyInt64:
636*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeInt64;
637*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeyUInt32:
638*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeUInt32;
639*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeyUInt64:
640*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeUInt64;
641*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeySInt32:
642*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeSInt32;
643*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeySInt64:
644*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeSInt64;
645*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeyFixed32:
646*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeFixed32;
647*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeyFixed64:
648*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeFixed64;
649*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeySFixed32:
650*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeSFixed32;
651*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeySFixed64:
652*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeSFixed64;
653*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeyBool:
654*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeBool;
655*1b3f573fSAndroid Build Coastguard Worker    case GPBFieldMapKeyString:
656*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeString;
657*1b3f573fSAndroid Build Coastguard Worker
658*1b3f573fSAndroid Build Coastguard Worker    default:
659*1b3f573fSAndroid Build Coastguard Worker      NSAssert(0, @"Not a map type");
660*1b3f573fSAndroid Build Coastguard Worker      return GPBDataTypeInt32;  // For lack of anything better.
661*1b3f573fSAndroid Build Coastguard Worker  }
662*1b3f573fSAndroid Build Coastguard Worker}
663*1b3f573fSAndroid Build Coastguard Worker
664*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isPackable {
665*1b3f573fSAndroid Build Coastguard Worker  return (description_->flags & GPBFieldPacked) != 0;
666*1b3f573fSAndroid Build Coastguard Worker}
667*1b3f573fSAndroid Build Coastguard Worker
668*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isValidEnumValue:(int32_t)value {
669*1b3f573fSAndroid Build Coastguard Worker  NSAssert(description_->dataType == GPBDataTypeEnum,
670*1b3f573fSAndroid Build Coastguard Worker           @"Field Must be of type GPBDataTypeEnum");
671*1b3f573fSAndroid Build Coastguard Worker  if (description_->flags & GPBFieldHasEnumDescriptor) {
672*1b3f573fSAndroid Build Coastguard Worker    return enumHandling_.enumDescriptor_.enumVerifier(value);
673*1b3f573fSAndroid Build Coastguard Worker  } else {
674*1b3f573fSAndroid Build Coastguard Worker    return enumHandling_.enumVerifier_(value);
675*1b3f573fSAndroid Build Coastguard Worker  }
676*1b3f573fSAndroid Build Coastguard Worker}
677*1b3f573fSAndroid Build Coastguard Worker
678*1b3f573fSAndroid Build Coastguard Worker- (GPBEnumDescriptor *)enumDescriptor {
679*1b3f573fSAndroid Build Coastguard Worker  if (description_->flags & GPBFieldHasEnumDescriptor) {
680*1b3f573fSAndroid Build Coastguard Worker    return enumHandling_.enumDescriptor_;
681*1b3f573fSAndroid Build Coastguard Worker  } else {
682*1b3f573fSAndroid Build Coastguard Worker    return nil;
683*1b3f573fSAndroid Build Coastguard Worker  }
684*1b3f573fSAndroid Build Coastguard Worker}
685*1b3f573fSAndroid Build Coastguard Worker
686*1b3f573fSAndroid Build Coastguard Worker- (GPBGenericValue)defaultValue {
687*1b3f573fSAndroid Build Coastguard Worker  // Depends on the fact that defaultValue_ is initialized either to "0/nil" or
688*1b3f573fSAndroid Build Coastguard Worker  // to an actual defaultValue in our initializer.
689*1b3f573fSAndroid Build Coastguard Worker  GPBGenericValue value = defaultValue_;
690*1b3f573fSAndroid Build Coastguard Worker
691*1b3f573fSAndroid Build Coastguard Worker  if (!(description_->flags & GPBFieldRepeated)) {
692*1b3f573fSAndroid Build Coastguard Worker    // We special handle data and strings. If they are nil, we replace them
693*1b3f573fSAndroid Build Coastguard Worker    // with empty string/empty data.
694*1b3f573fSAndroid Build Coastguard Worker    GPBDataType type = description_->dataType;
695*1b3f573fSAndroid Build Coastguard Worker    if (type == GPBDataTypeBytes && value.valueData == nil) {
696*1b3f573fSAndroid Build Coastguard Worker      value.valueData = GPBEmptyNSData();
697*1b3f573fSAndroid Build Coastguard Worker    } else if (type == GPBDataTypeString && value.valueString == nil) {
698*1b3f573fSAndroid Build Coastguard Worker      value.valueString = @"";
699*1b3f573fSAndroid Build Coastguard Worker    }
700*1b3f573fSAndroid Build Coastguard Worker  }
701*1b3f573fSAndroid Build Coastguard Worker  return value;
702*1b3f573fSAndroid Build Coastguard Worker}
703*1b3f573fSAndroid Build Coastguard Worker
704*1b3f573fSAndroid Build Coastguard Worker- (NSString *)textFormatName {
705*1b3f573fSAndroid Build Coastguard Worker  if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) {
706*1b3f573fSAndroid Build Coastguard Worker    NSValue *extraInfoValue =
707*1b3f573fSAndroid Build Coastguard Worker        objc_getAssociatedObject(self, &kTextFormatExtraValueKey);
708*1b3f573fSAndroid Build Coastguard Worker    // Support can be left out at generation time.
709*1b3f573fSAndroid Build Coastguard Worker    if (!extraInfoValue) {
710*1b3f573fSAndroid Build Coastguard Worker      return nil;
711*1b3f573fSAndroid Build Coastguard Worker    }
712*1b3f573fSAndroid Build Coastguard Worker    const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue];
713*1b3f573fSAndroid Build Coastguard Worker    return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self),
714*1b3f573fSAndroid Build Coastguard Worker                                   self.name);
715*1b3f573fSAndroid Build Coastguard Worker  }
716*1b3f573fSAndroid Build Coastguard Worker
717*1b3f573fSAndroid Build Coastguard Worker  // The logic here has to match SetCommonFieldVariables() from
718*1b3f573fSAndroid Build Coastguard Worker  // objectivec_field.cc in the proto compiler.
719*1b3f573fSAndroid Build Coastguard Worker  NSString *name = self.name;
720*1b3f573fSAndroid Build Coastguard Worker  NSUInteger len = [name length];
721*1b3f573fSAndroid Build Coastguard Worker
722*1b3f573fSAndroid Build Coastguard Worker  // Remove the "_p" added to reserved names.
723*1b3f573fSAndroid Build Coastguard Worker  if ([name hasSuffix:@"_p"]) {
724*1b3f573fSAndroid Build Coastguard Worker    name = [name substringToIndex:(len - 2)];
725*1b3f573fSAndroid Build Coastguard Worker    len = [name length];
726*1b3f573fSAndroid Build Coastguard Worker  }
727*1b3f573fSAndroid Build Coastguard Worker
728*1b3f573fSAndroid Build Coastguard Worker  // Remove "Array" from the end for repeated fields.
729*1b3f573fSAndroid Build Coastguard Worker  if (((description_->flags & GPBFieldRepeated) != 0) &&
730*1b3f573fSAndroid Build Coastguard Worker      [name hasSuffix:@"Array"]) {
731*1b3f573fSAndroid Build Coastguard Worker    name = [name substringToIndex:(len - 5)];
732*1b3f573fSAndroid Build Coastguard Worker    len = [name length];
733*1b3f573fSAndroid Build Coastguard Worker  }
734*1b3f573fSAndroid Build Coastguard Worker
735*1b3f573fSAndroid Build Coastguard Worker  // Groups vs. other fields.
736*1b3f573fSAndroid Build Coastguard Worker  if (description_->dataType == GPBDataTypeGroup) {
737*1b3f573fSAndroid Build Coastguard Worker    // Just capitalize the first letter.
738*1b3f573fSAndroid Build Coastguard Worker    unichar firstChar = [name characterAtIndex:0];
739*1b3f573fSAndroid Build Coastguard Worker    if (firstChar >= 'a' && firstChar <= 'z') {
740*1b3f573fSAndroid Build Coastguard Worker      NSString *firstCharString =
741*1b3f573fSAndroid Build Coastguard Worker          [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')];
742*1b3f573fSAndroid Build Coastguard Worker      NSString *result =
743*1b3f573fSAndroid Build Coastguard Worker          [name stringByReplacingCharactersInRange:NSMakeRange(0, 1)
744*1b3f573fSAndroid Build Coastguard Worker                                        withString:firstCharString];
745*1b3f573fSAndroid Build Coastguard Worker      return result;
746*1b3f573fSAndroid Build Coastguard Worker    }
747*1b3f573fSAndroid Build Coastguard Worker    return name;
748*1b3f573fSAndroid Build Coastguard Worker
749*1b3f573fSAndroid Build Coastguard Worker  } else {
750*1b3f573fSAndroid Build Coastguard Worker    // Undo the CamelCase.
751*1b3f573fSAndroid Build Coastguard Worker    NSMutableString *result = [NSMutableString stringWithCapacity:len];
752*1b3f573fSAndroid Build Coastguard Worker    for (uint32_t i = 0; i < len; i++) {
753*1b3f573fSAndroid Build Coastguard Worker      unichar c = [name characterAtIndex:i];
754*1b3f573fSAndroid Build Coastguard Worker      if (c >= 'A' && c <= 'Z') {
755*1b3f573fSAndroid Build Coastguard Worker        if (i > 0) {
756*1b3f573fSAndroid Build Coastguard Worker          [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')];
757*1b3f573fSAndroid Build Coastguard Worker        } else {
758*1b3f573fSAndroid Build Coastguard Worker          [result appendFormat:@"%C", c];
759*1b3f573fSAndroid Build Coastguard Worker        }
760*1b3f573fSAndroid Build Coastguard Worker      } else {
761*1b3f573fSAndroid Build Coastguard Worker        [result appendFormat:@"%C", c];
762*1b3f573fSAndroid Build Coastguard Worker      }
763*1b3f573fSAndroid Build Coastguard Worker    }
764*1b3f573fSAndroid Build Coastguard Worker    return result;
765*1b3f573fSAndroid Build Coastguard Worker  }
766*1b3f573fSAndroid Build Coastguard Worker}
767*1b3f573fSAndroid Build Coastguard Worker
768*1b3f573fSAndroid Build Coastguard Worker@end
769*1b3f573fSAndroid Build Coastguard Worker
770*1b3f573fSAndroid Build Coastguard Worker@implementation GPBEnumDescriptor {
771*1b3f573fSAndroid Build Coastguard Worker  NSString *name_;
772*1b3f573fSAndroid Build Coastguard Worker  // valueNames_ is a single c string with all of the value names appended
773*1b3f573fSAndroid Build Coastguard Worker  // together, each null terminated.  -calcValueNameOffsets fills in
774*1b3f573fSAndroid Build Coastguard Worker  // nameOffsets_ with the offsets to allow quicker access to the individual
775*1b3f573fSAndroid Build Coastguard Worker  // names.
776*1b3f573fSAndroid Build Coastguard Worker  const char *valueNames_;
777*1b3f573fSAndroid Build Coastguard Worker  const int32_t *values_;
778*1b3f573fSAndroid Build Coastguard Worker  GPBEnumValidationFunc enumVerifier_;
779*1b3f573fSAndroid Build Coastguard Worker  const uint8_t *extraTextFormatInfo_;
780*1b3f573fSAndroid Build Coastguard Worker  uint32_t *nameOffsets_;
781*1b3f573fSAndroid Build Coastguard Worker  uint32_t valueCount_;
782*1b3f573fSAndroid Build Coastguard Worker}
783*1b3f573fSAndroid Build Coastguard Worker
784*1b3f573fSAndroid Build Coastguard Worker@synthesize name = name_;
785*1b3f573fSAndroid Build Coastguard Worker@synthesize enumVerifier = enumVerifier_;
786*1b3f573fSAndroid Build Coastguard Worker
787*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)
788*1b3f573fSAndroid Build Coastguard Worker    allocDescriptorForName:(NSString *)name
789*1b3f573fSAndroid Build Coastguard Worker                valueNames:(const char *)valueNames
790*1b3f573fSAndroid Build Coastguard Worker                    values:(const int32_t *)values
791*1b3f573fSAndroid Build Coastguard Worker                     count:(uint32_t)valueCount
792*1b3f573fSAndroid Build Coastguard Worker              enumVerifier:(GPBEnumValidationFunc)enumVerifier {
793*1b3f573fSAndroid Build Coastguard Worker  GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
794*1b3f573fSAndroid Build Coastguard Worker                                                  valueNames:valueNames
795*1b3f573fSAndroid Build Coastguard Worker                                                      values:values
796*1b3f573fSAndroid Build Coastguard Worker                                                       count:valueCount
797*1b3f573fSAndroid Build Coastguard Worker                                                enumVerifier:enumVerifier];
798*1b3f573fSAndroid Build Coastguard Worker  return descriptor;
799*1b3f573fSAndroid Build Coastguard Worker}
800*1b3f573fSAndroid Build Coastguard Worker
801*1b3f573fSAndroid Build Coastguard Worker+ (instancetype)
802*1b3f573fSAndroid Build Coastguard Worker    allocDescriptorForName:(NSString *)name
803*1b3f573fSAndroid Build Coastguard Worker                valueNames:(const char *)valueNames
804*1b3f573fSAndroid Build Coastguard Worker                    values:(const int32_t *)values
805*1b3f573fSAndroid Build Coastguard Worker                     count:(uint32_t)valueCount
806*1b3f573fSAndroid Build Coastguard Worker              enumVerifier:(GPBEnumValidationFunc)enumVerifier
807*1b3f573fSAndroid Build Coastguard Worker       extraTextFormatInfo:(const char *)extraTextFormatInfo {
808*1b3f573fSAndroid Build Coastguard Worker  // Call the common case.
809*1b3f573fSAndroid Build Coastguard Worker  GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name
810*1b3f573fSAndroid Build Coastguard Worker                                                    valueNames:valueNames
811*1b3f573fSAndroid Build Coastguard Worker                                                        values:values
812*1b3f573fSAndroid Build Coastguard Worker                                                         count:valueCount
813*1b3f573fSAndroid Build Coastguard Worker                                                  enumVerifier:enumVerifier];
814*1b3f573fSAndroid Build Coastguard Worker  // Set the extra info.
815*1b3f573fSAndroid Build Coastguard Worker  descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
816*1b3f573fSAndroid Build Coastguard Worker  return descriptor;
817*1b3f573fSAndroid Build Coastguard Worker}
818*1b3f573fSAndroid Build Coastguard Worker
819*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithName:(NSString *)name
820*1b3f573fSAndroid Build Coastguard Worker                  valueNames:(const char *)valueNames
821*1b3f573fSAndroid Build Coastguard Worker                      values:(const int32_t *)values
822*1b3f573fSAndroid Build Coastguard Worker                       count:(uint32_t)valueCount
823*1b3f573fSAndroid Build Coastguard Worker                enumVerifier:(GPBEnumValidationFunc)enumVerifier {
824*1b3f573fSAndroid Build Coastguard Worker  if ((self = [super init])) {
825*1b3f573fSAndroid Build Coastguard Worker    name_ = [name copy];
826*1b3f573fSAndroid Build Coastguard Worker    valueNames_ = valueNames;
827*1b3f573fSAndroid Build Coastguard Worker    values_ = values;
828*1b3f573fSAndroid Build Coastguard Worker    valueCount_ = valueCount;
829*1b3f573fSAndroid Build Coastguard Worker    enumVerifier_ = enumVerifier;
830*1b3f573fSAndroid Build Coastguard Worker  }
831*1b3f573fSAndroid Build Coastguard Worker  return self;
832*1b3f573fSAndroid Build Coastguard Worker}
833*1b3f573fSAndroid Build Coastguard Worker
834*1b3f573fSAndroid Build Coastguard Worker- (void)dealloc {
835*1b3f573fSAndroid Build Coastguard Worker  [name_ release];
836*1b3f573fSAndroid Build Coastguard Worker  if (nameOffsets_) free(nameOffsets_);
837*1b3f573fSAndroid Build Coastguard Worker  [super dealloc];
838*1b3f573fSAndroid Build Coastguard Worker}
839*1b3f573fSAndroid Build Coastguard Worker
840*1b3f573fSAndroid Build Coastguard Worker- (void)calcValueNameOffsets {
841*1b3f573fSAndroid Build Coastguard Worker  @synchronized(self) {
842*1b3f573fSAndroid Build Coastguard Worker    if (nameOffsets_ != NULL) {
843*1b3f573fSAndroid Build Coastguard Worker      return;
844*1b3f573fSAndroid Build Coastguard Worker    }
845*1b3f573fSAndroid Build Coastguard Worker    uint32_t *offsets = malloc(valueCount_ * sizeof(uint32_t));
846*1b3f573fSAndroid Build Coastguard Worker    if (!offsets) return;
847*1b3f573fSAndroid Build Coastguard Worker    const char *scan = valueNames_;
848*1b3f573fSAndroid Build Coastguard Worker    for (uint32_t i = 0; i < valueCount_; ++i) {
849*1b3f573fSAndroid Build Coastguard Worker      offsets[i] = (uint32_t)(scan - valueNames_);
850*1b3f573fSAndroid Build Coastguard Worker      while (*scan != '\0') ++scan;
851*1b3f573fSAndroid Build Coastguard Worker      ++scan;  // Step over the null.
852*1b3f573fSAndroid Build Coastguard Worker    }
853*1b3f573fSAndroid Build Coastguard Worker    nameOffsets_ = offsets;
854*1b3f573fSAndroid Build Coastguard Worker  }
855*1b3f573fSAndroid Build Coastguard Worker}
856*1b3f573fSAndroid Build Coastguard Worker
857*1b3f573fSAndroid Build Coastguard Worker- (NSString *)enumNameForValue:(int32_t)number {
858*1b3f573fSAndroid Build Coastguard Worker  for (uint32_t i = 0; i < valueCount_; ++i) {
859*1b3f573fSAndroid Build Coastguard Worker    if (values_[i] == number) {
860*1b3f573fSAndroid Build Coastguard Worker      return [self getEnumNameForIndex:i];
861*1b3f573fSAndroid Build Coastguard Worker    }
862*1b3f573fSAndroid Build Coastguard Worker  }
863*1b3f573fSAndroid Build Coastguard Worker  return nil;
864*1b3f573fSAndroid Build Coastguard Worker}
865*1b3f573fSAndroid Build Coastguard Worker
866*1b3f573fSAndroid Build Coastguard Worker- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name {
867*1b3f573fSAndroid Build Coastguard Worker  // Must have the prefix.
868*1b3f573fSAndroid Build Coastguard Worker  NSUInteger prefixLen = name_.length + 1;
869*1b3f573fSAndroid Build Coastguard Worker  if ((name.length <= prefixLen) || ![name hasPrefix:name_] ||
870*1b3f573fSAndroid Build Coastguard Worker      ([name characterAtIndex:prefixLen - 1] != '_')) {
871*1b3f573fSAndroid Build Coastguard Worker    return NO;
872*1b3f573fSAndroid Build Coastguard Worker  }
873*1b3f573fSAndroid Build Coastguard Worker
874*1b3f573fSAndroid Build Coastguard Worker  // Skip over the prefix.
875*1b3f573fSAndroid Build Coastguard Worker  const char *nameAsCStr = [name UTF8String];
876*1b3f573fSAndroid Build Coastguard Worker  nameAsCStr += prefixLen;
877*1b3f573fSAndroid Build Coastguard Worker
878*1b3f573fSAndroid Build Coastguard Worker  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
879*1b3f573fSAndroid Build Coastguard Worker  if (nameOffsets_ == NULL) return NO;
880*1b3f573fSAndroid Build Coastguard Worker
881*1b3f573fSAndroid Build Coastguard Worker  // Find it.
882*1b3f573fSAndroid Build Coastguard Worker  for (uint32_t i = 0; i < valueCount_; ++i) {
883*1b3f573fSAndroid Build Coastguard Worker    const char *valueName = valueNames_ + nameOffsets_[i];
884*1b3f573fSAndroid Build Coastguard Worker    if (strcmp(nameAsCStr, valueName) == 0) {
885*1b3f573fSAndroid Build Coastguard Worker      if (outValue) {
886*1b3f573fSAndroid Build Coastguard Worker        *outValue = values_[i];
887*1b3f573fSAndroid Build Coastguard Worker      }
888*1b3f573fSAndroid Build Coastguard Worker      return YES;
889*1b3f573fSAndroid Build Coastguard Worker    }
890*1b3f573fSAndroid Build Coastguard Worker  }
891*1b3f573fSAndroid Build Coastguard Worker  return NO;
892*1b3f573fSAndroid Build Coastguard Worker}
893*1b3f573fSAndroid Build Coastguard Worker
894*1b3f573fSAndroid Build Coastguard Worker- (BOOL)getValue:(int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName {
895*1b3f573fSAndroid Build Coastguard Worker    if (nameOffsets_ == NULL) [self calcValueNameOffsets];
896*1b3f573fSAndroid Build Coastguard Worker    if (nameOffsets_ == NULL) return NO;
897*1b3f573fSAndroid Build Coastguard Worker
898*1b3f573fSAndroid Build Coastguard Worker    for (uint32_t i = 0; i < valueCount_; ++i) {
899*1b3f573fSAndroid Build Coastguard Worker        NSString *valueTextFormatName = [self getEnumTextFormatNameForIndex:i];
900*1b3f573fSAndroid Build Coastguard Worker        if ([valueTextFormatName isEqual:textFormatName]) {
901*1b3f573fSAndroid Build Coastguard Worker            if (outValue) {
902*1b3f573fSAndroid Build Coastguard Worker                *outValue = values_[i];
903*1b3f573fSAndroid Build Coastguard Worker            }
904*1b3f573fSAndroid Build Coastguard Worker            return YES;
905*1b3f573fSAndroid Build Coastguard Worker        }
906*1b3f573fSAndroid Build Coastguard Worker    }
907*1b3f573fSAndroid Build Coastguard Worker    return NO;
908*1b3f573fSAndroid Build Coastguard Worker}
909*1b3f573fSAndroid Build Coastguard Worker
910*1b3f573fSAndroid Build Coastguard Worker- (NSString *)textFormatNameForValue:(int32_t)number {
911*1b3f573fSAndroid Build Coastguard Worker  // Find the EnumValue descriptor and its index.
912*1b3f573fSAndroid Build Coastguard Worker  BOOL foundIt = NO;
913*1b3f573fSAndroid Build Coastguard Worker  uint32_t valueDescriptorIndex;
914*1b3f573fSAndroid Build Coastguard Worker  for (valueDescriptorIndex = 0; valueDescriptorIndex < valueCount_;
915*1b3f573fSAndroid Build Coastguard Worker       ++valueDescriptorIndex) {
916*1b3f573fSAndroid Build Coastguard Worker    if (values_[valueDescriptorIndex] == number) {
917*1b3f573fSAndroid Build Coastguard Worker      foundIt = YES;
918*1b3f573fSAndroid Build Coastguard Worker      break;
919*1b3f573fSAndroid Build Coastguard Worker    }
920*1b3f573fSAndroid Build Coastguard Worker  }
921*1b3f573fSAndroid Build Coastguard Worker
922*1b3f573fSAndroid Build Coastguard Worker  if (!foundIt) {
923*1b3f573fSAndroid Build Coastguard Worker    return nil;
924*1b3f573fSAndroid Build Coastguard Worker  }
925*1b3f573fSAndroid Build Coastguard Worker  return [self getEnumTextFormatNameForIndex:valueDescriptorIndex];
926*1b3f573fSAndroid Build Coastguard Worker}
927*1b3f573fSAndroid Build Coastguard Worker
928*1b3f573fSAndroid Build Coastguard Worker- (uint32_t)enumNameCount {
929*1b3f573fSAndroid Build Coastguard Worker  return valueCount_;
930*1b3f573fSAndroid Build Coastguard Worker}
931*1b3f573fSAndroid Build Coastguard Worker
932*1b3f573fSAndroid Build Coastguard Worker- (NSString *)getEnumNameForIndex:(uint32_t)index {
933*1b3f573fSAndroid Build Coastguard Worker  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
934*1b3f573fSAndroid Build Coastguard Worker  if (nameOffsets_ == NULL) return nil;
935*1b3f573fSAndroid Build Coastguard Worker
936*1b3f573fSAndroid Build Coastguard Worker  if (index >= valueCount_) {
937*1b3f573fSAndroid Build Coastguard Worker    return nil;
938*1b3f573fSAndroid Build Coastguard Worker  }
939*1b3f573fSAndroid Build Coastguard Worker  const char *valueName = valueNames_ + nameOffsets_[index];
940*1b3f573fSAndroid Build Coastguard Worker  NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
941*1b3f573fSAndroid Build Coastguard Worker  return fullName;
942*1b3f573fSAndroid Build Coastguard Worker}
943*1b3f573fSAndroid Build Coastguard Worker
944*1b3f573fSAndroid Build Coastguard Worker- (NSString *)getEnumTextFormatNameForIndex:(uint32_t)index {
945*1b3f573fSAndroid Build Coastguard Worker  if (nameOffsets_ == NULL) [self calcValueNameOffsets];
946*1b3f573fSAndroid Build Coastguard Worker  if (nameOffsets_ == NULL) return nil;
947*1b3f573fSAndroid Build Coastguard Worker
948*1b3f573fSAndroid Build Coastguard Worker  if (index >= valueCount_) {
949*1b3f573fSAndroid Build Coastguard Worker    return nil;
950*1b3f573fSAndroid Build Coastguard Worker  }
951*1b3f573fSAndroid Build Coastguard Worker  NSString *result = nil;
952*1b3f573fSAndroid Build Coastguard Worker  // Naming adds an underscore between enum name and value name, skip that also.
953*1b3f573fSAndroid Build Coastguard Worker  const char *valueName = valueNames_ + nameOffsets_[index];
954*1b3f573fSAndroid Build Coastguard Worker  NSString *shortName = @(valueName);
955*1b3f573fSAndroid Build Coastguard Worker
956*1b3f573fSAndroid Build Coastguard Worker  // See if it is in the map of special format handling.
957*1b3f573fSAndroid Build Coastguard Worker  if (extraTextFormatInfo_) {
958*1b3f573fSAndroid Build Coastguard Worker    result = GPBDecodeTextFormatName(extraTextFormatInfo_,
959*1b3f573fSAndroid Build Coastguard Worker                                     (int32_t)index, shortName);
960*1b3f573fSAndroid Build Coastguard Worker  }
961*1b3f573fSAndroid Build Coastguard Worker  // Logic here needs to match what objectivec_enum.cc does in the proto
962*1b3f573fSAndroid Build Coastguard Worker  // compiler.
963*1b3f573fSAndroid Build Coastguard Worker  if (result == nil) {
964*1b3f573fSAndroid Build Coastguard Worker    NSUInteger len = [shortName length];
965*1b3f573fSAndroid Build Coastguard Worker    NSMutableString *worker = [NSMutableString stringWithCapacity:len];
966*1b3f573fSAndroid Build Coastguard Worker    for (NSUInteger i = 0; i < len; i++) {
967*1b3f573fSAndroid Build Coastguard Worker      unichar c = [shortName characterAtIndex:i];
968*1b3f573fSAndroid Build Coastguard Worker      if (i > 0 && c >= 'A' && c <= 'Z') {
969*1b3f573fSAndroid Build Coastguard Worker        [worker appendString:@"_"];
970*1b3f573fSAndroid Build Coastguard Worker      }
971*1b3f573fSAndroid Build Coastguard Worker      [worker appendFormat:@"%c", toupper((char)c)];
972*1b3f573fSAndroid Build Coastguard Worker    }
973*1b3f573fSAndroid Build Coastguard Worker    result = worker;
974*1b3f573fSAndroid Build Coastguard Worker  }
975*1b3f573fSAndroid Build Coastguard Worker  return result;
976*1b3f573fSAndroid Build Coastguard Worker}
977*1b3f573fSAndroid Build Coastguard Worker
978*1b3f573fSAndroid Build Coastguard Worker@end
979*1b3f573fSAndroid Build Coastguard Worker
980*1b3f573fSAndroid Build Coastguard Worker@implementation GPBExtensionDescriptor {
981*1b3f573fSAndroid Build Coastguard Worker  GPBGenericValue defaultValue_;
982*1b3f573fSAndroid Build Coastguard Worker}
983*1b3f573fSAndroid Build Coastguard Worker
984*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc
985*1b3f573fSAndroid Build Coastguard Worker                               usesClassRefs:(BOOL)usesClassRefs {
986*1b3f573fSAndroid Build Coastguard Worker  if ((self = [super init])) {
987*1b3f573fSAndroid Build Coastguard Worker    description_ = desc;
988*1b3f573fSAndroid Build Coastguard Worker    if (!usesClassRefs) {
989*1b3f573fSAndroid Build Coastguard Worker      // Legacy without class ref support.
990*1b3f573fSAndroid Build Coastguard Worker      const char *className = description_->messageOrGroupClass.name;
991*1b3f573fSAndroid Build Coastguard Worker      if (className) {
992*1b3f573fSAndroid Build Coastguard Worker        Class clazz = objc_lookUpClass(className);
993*1b3f573fSAndroid Build Coastguard Worker        NSAssert(clazz != Nil, @"Class %s not defined", className);
994*1b3f573fSAndroid Build Coastguard Worker        description_->messageOrGroupClass.clazz = clazz;
995*1b3f573fSAndroid Build Coastguard Worker      }
996*1b3f573fSAndroid Build Coastguard Worker
997*1b3f573fSAndroid Build Coastguard Worker      const char *extendedClassName = description_->extendedClass.name;
998*1b3f573fSAndroid Build Coastguard Worker      if (extendedClassName) {
999*1b3f573fSAndroid Build Coastguard Worker        Class clazz = objc_lookUpClass(extendedClassName);
1000*1b3f573fSAndroid Build Coastguard Worker        NSAssert(clazz, @"Class %s not defined", extendedClassName);
1001*1b3f573fSAndroid Build Coastguard Worker        description_->extendedClass.clazz = clazz;
1002*1b3f573fSAndroid Build Coastguard Worker      }
1003*1b3f573fSAndroid Build Coastguard Worker    }
1004*1b3f573fSAndroid Build Coastguard Worker
1005*1b3f573fSAndroid Build Coastguard Worker    GPBDataType type = description_->dataType;
1006*1b3f573fSAndroid Build Coastguard Worker    if (type == GPBDataTypeBytes) {
1007*1b3f573fSAndroid Build Coastguard Worker      // Data stored as a length prefixed c-string in descriptor records.
1008*1b3f573fSAndroid Build Coastguard Worker      const uint8_t *bytes =
1009*1b3f573fSAndroid Build Coastguard Worker          (const uint8_t *)description_->defaultValue.valueData;
1010*1b3f573fSAndroid Build Coastguard Worker      if (bytes) {
1011*1b3f573fSAndroid Build Coastguard Worker        uint32_t length;
1012*1b3f573fSAndroid Build Coastguard Worker        memcpy(&length, bytes, sizeof(length));
1013*1b3f573fSAndroid Build Coastguard Worker        // The length is stored in network byte order.
1014*1b3f573fSAndroid Build Coastguard Worker        length = ntohl(length);
1015*1b3f573fSAndroid Build Coastguard Worker        bytes += sizeof(length);
1016*1b3f573fSAndroid Build Coastguard Worker        defaultValue_.valueData =
1017*1b3f573fSAndroid Build Coastguard Worker            [[NSData alloc] initWithBytes:bytes length:length];
1018*1b3f573fSAndroid Build Coastguard Worker      }
1019*1b3f573fSAndroid Build Coastguard Worker    } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) {
1020*1b3f573fSAndroid Build Coastguard Worker      // The default is looked up in -defaultValue instead since extensions
1021*1b3f573fSAndroid Build Coastguard Worker      // aren't common, we avoid the hit startup hit and it avoid initialization
1022*1b3f573fSAndroid Build Coastguard Worker      // order issues.
1023*1b3f573fSAndroid Build Coastguard Worker    } else {
1024*1b3f573fSAndroid Build Coastguard Worker      defaultValue_ = description_->defaultValue;
1025*1b3f573fSAndroid Build Coastguard Worker    }
1026*1b3f573fSAndroid Build Coastguard Worker  }
1027*1b3f573fSAndroid Build Coastguard Worker  return self;
1028*1b3f573fSAndroid Build Coastguard Worker}
1029*1b3f573fSAndroid Build Coastguard Worker
1030*1b3f573fSAndroid Build Coastguard Worker- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc {
1031*1b3f573fSAndroid Build Coastguard Worker  return [self initWithExtensionDescription:desc usesClassRefs:NO];
1032*1b3f573fSAndroid Build Coastguard Worker}
1033*1b3f573fSAndroid Build Coastguard Worker
1034*1b3f573fSAndroid Build Coastguard Worker- (void)dealloc {
1035*1b3f573fSAndroid Build Coastguard Worker  if ((description_->dataType == GPBDataTypeBytes) &&
1036*1b3f573fSAndroid Build Coastguard Worker      !GPBExtensionIsRepeated(description_)) {
1037*1b3f573fSAndroid Build Coastguard Worker    [defaultValue_.valueData release];
1038*1b3f573fSAndroid Build Coastguard Worker  }
1039*1b3f573fSAndroid Build Coastguard Worker  [super dealloc];
1040*1b3f573fSAndroid Build Coastguard Worker}
1041*1b3f573fSAndroid Build Coastguard Worker
1042*1b3f573fSAndroid Build Coastguard Worker- (instancetype)copyWithZone:(NSZone *)zone {
1043*1b3f573fSAndroid Build Coastguard Worker#pragma unused(zone)
1044*1b3f573fSAndroid Build Coastguard Worker  // Immutable.
1045*1b3f573fSAndroid Build Coastguard Worker  return [self retain];
1046*1b3f573fSAndroid Build Coastguard Worker}
1047*1b3f573fSAndroid Build Coastguard Worker
1048*1b3f573fSAndroid Build Coastguard Worker- (NSString *)singletonName {
1049*1b3f573fSAndroid Build Coastguard Worker  return (NSString * _Nonnull)@(description_->singletonName);
1050*1b3f573fSAndroid Build Coastguard Worker}
1051*1b3f573fSAndroid Build Coastguard Worker
1052*1b3f573fSAndroid Build Coastguard Worker- (const char *)singletonNameC {
1053*1b3f573fSAndroid Build Coastguard Worker  return description_->singletonName;
1054*1b3f573fSAndroid Build Coastguard Worker}
1055*1b3f573fSAndroid Build Coastguard Worker
1056*1b3f573fSAndroid Build Coastguard Worker- (uint32_t)fieldNumber {
1057*1b3f573fSAndroid Build Coastguard Worker  return description_->fieldNumber;
1058*1b3f573fSAndroid Build Coastguard Worker}
1059*1b3f573fSAndroid Build Coastguard Worker
1060*1b3f573fSAndroid Build Coastguard Worker- (GPBDataType)dataType {
1061*1b3f573fSAndroid Build Coastguard Worker  return description_->dataType;
1062*1b3f573fSAndroid Build Coastguard Worker}
1063*1b3f573fSAndroid Build Coastguard Worker
1064*1b3f573fSAndroid Build Coastguard Worker- (GPBWireFormat)wireType {
1065*1b3f573fSAndroid Build Coastguard Worker  return GPBWireFormatForType(description_->dataType,
1066*1b3f573fSAndroid Build Coastguard Worker                              GPBExtensionIsPacked(description_));
1067*1b3f573fSAndroid Build Coastguard Worker}
1068*1b3f573fSAndroid Build Coastguard Worker
1069*1b3f573fSAndroid Build Coastguard Worker- (GPBWireFormat)alternateWireType {
1070*1b3f573fSAndroid Build Coastguard Worker  NSAssert(GPBExtensionIsRepeated(description_),
1071*1b3f573fSAndroid Build Coastguard Worker           @"Only valid on repeated extensions");
1072*1b3f573fSAndroid Build Coastguard Worker  return GPBWireFormatForType(description_->dataType,
1073*1b3f573fSAndroid Build Coastguard Worker                              !GPBExtensionIsPacked(description_));
1074*1b3f573fSAndroid Build Coastguard Worker}
1075*1b3f573fSAndroid Build Coastguard Worker
1076*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isRepeated {
1077*1b3f573fSAndroid Build Coastguard Worker  return GPBExtensionIsRepeated(description_);
1078*1b3f573fSAndroid Build Coastguard Worker}
1079*1b3f573fSAndroid Build Coastguard Worker
1080*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isPackable {
1081*1b3f573fSAndroid Build Coastguard Worker  return GPBExtensionIsPacked(description_);
1082*1b3f573fSAndroid Build Coastguard Worker}
1083*1b3f573fSAndroid Build Coastguard Worker
1084*1b3f573fSAndroid Build Coastguard Worker- (Class)msgClass {
1085*1b3f573fSAndroid Build Coastguard Worker  return description_->messageOrGroupClass.clazz;
1086*1b3f573fSAndroid Build Coastguard Worker}
1087*1b3f573fSAndroid Build Coastguard Worker
1088*1b3f573fSAndroid Build Coastguard Worker- (Class)containingMessageClass {
1089*1b3f573fSAndroid Build Coastguard Worker  return description_->extendedClass.clazz;
1090*1b3f573fSAndroid Build Coastguard Worker}
1091*1b3f573fSAndroid Build Coastguard Worker
1092*1b3f573fSAndroid Build Coastguard Worker- (GPBEnumDescriptor *)enumDescriptor {
1093*1b3f573fSAndroid Build Coastguard Worker  if (description_->dataType == GPBDataTypeEnum) {
1094*1b3f573fSAndroid Build Coastguard Worker    GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc();
1095*1b3f573fSAndroid Build Coastguard Worker    return enumDescriptor;
1096*1b3f573fSAndroid Build Coastguard Worker  }
1097*1b3f573fSAndroid Build Coastguard Worker  return nil;
1098*1b3f573fSAndroid Build Coastguard Worker}
1099*1b3f573fSAndroid Build Coastguard Worker
1100*1b3f573fSAndroid Build Coastguard Worker- (id)defaultValue {
1101*1b3f573fSAndroid Build Coastguard Worker  if (GPBExtensionIsRepeated(description_)) {
1102*1b3f573fSAndroid Build Coastguard Worker    return nil;
1103*1b3f573fSAndroid Build Coastguard Worker  }
1104*1b3f573fSAndroid Build Coastguard Worker
1105*1b3f573fSAndroid Build Coastguard Worker  switch (description_->dataType) {
1106*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeBool:
1107*1b3f573fSAndroid Build Coastguard Worker      return @(defaultValue_.valueBool);
1108*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFloat:
1109*1b3f573fSAndroid Build Coastguard Worker      return @(defaultValue_.valueFloat);
1110*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeDouble:
1111*1b3f573fSAndroid Build Coastguard Worker      return @(defaultValue_.valueDouble);
1112*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeInt32:
1113*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSInt32:
1114*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeEnum:
1115*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSFixed32:
1116*1b3f573fSAndroid Build Coastguard Worker      return @(defaultValue_.valueInt32);
1117*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeInt64:
1118*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSInt64:
1119*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeSFixed64:
1120*1b3f573fSAndroid Build Coastguard Worker      return @(defaultValue_.valueInt64);
1121*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeUInt32:
1122*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFixed32:
1123*1b3f573fSAndroid Build Coastguard Worker      return @(defaultValue_.valueUInt32);
1124*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeUInt64:
1125*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeFixed64:
1126*1b3f573fSAndroid Build Coastguard Worker      return @(defaultValue_.valueUInt64);
1127*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeBytes:
1128*1b3f573fSAndroid Build Coastguard Worker      // Like message fields, the default is zero length data.
1129*1b3f573fSAndroid Build Coastguard Worker      return (defaultValue_.valueData ? defaultValue_.valueData
1130*1b3f573fSAndroid Build Coastguard Worker                                      : GPBEmptyNSData());
1131*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeString:
1132*1b3f573fSAndroid Build Coastguard Worker      // Like message fields, the default is zero length string.
1133*1b3f573fSAndroid Build Coastguard Worker      return (defaultValue_.valueString ? defaultValue_.valueString : @"");
1134*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeGroup:
1135*1b3f573fSAndroid Build Coastguard Worker    case GPBDataTypeMessage:
1136*1b3f573fSAndroid Build Coastguard Worker      return nil;
1137*1b3f573fSAndroid Build Coastguard Worker  }
1138*1b3f573fSAndroid Build Coastguard Worker}
1139*1b3f573fSAndroid Build Coastguard Worker
1140*1b3f573fSAndroid Build Coastguard Worker- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other {
1141*1b3f573fSAndroid Build Coastguard Worker  int32_t selfNumber = description_->fieldNumber;
1142*1b3f573fSAndroid Build Coastguard Worker  int32_t otherNumber = other->description_->fieldNumber;
1143*1b3f573fSAndroid Build Coastguard Worker  if (selfNumber < otherNumber) {
1144*1b3f573fSAndroid Build Coastguard Worker    return NSOrderedAscending;
1145*1b3f573fSAndroid Build Coastguard Worker  } else if (selfNumber == otherNumber) {
1146*1b3f573fSAndroid Build Coastguard Worker    return NSOrderedSame;
1147*1b3f573fSAndroid Build Coastguard Worker  } else {
1148*1b3f573fSAndroid Build Coastguard Worker    return NSOrderedDescending;
1149*1b3f573fSAndroid Build Coastguard Worker  }
1150*1b3f573fSAndroid Build Coastguard Worker}
1151*1b3f573fSAndroid Build Coastguard Worker
1152*1b3f573fSAndroid Build Coastguard Worker@end
1153*1b3f573fSAndroid Build Coastguard Worker
1154*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic pop
1155