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