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 kParentClassNameValueKey = 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 130 void *desc; 131 for (uint32_t i = 0; i < fieldCount; ++i) { 132 if (fields == nil) { 133 fields = [[NSMutableArray alloc] initWithCapacity:fieldCount]; 134 } 135 // Need correctly typed pointer for array indexing below to work. 136 if (fieldsIncludeDefault) { 137 GPBMessageFieldDescriptionWithDefault *fieldDescWithDefault = fieldDescriptions; 138 desc = &(fieldDescWithDefault[i]); 139 } else { 140 GPBMessageFieldDescription *fieldDesc = fieldDescriptions; 141 desc = &(fieldDesc[i]); 142 } 143 GPBFieldDescriptor *fieldDescriptor = 144 [[GPBFieldDescriptor alloc] initWithFieldDescription:desc 145 includesDefault:fieldsIncludeDefault 146 syntax:syntax]; 147 [fields addObject:fieldDescriptor]; 148 [fieldDescriptor release]; 149 } 150 151 BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0; 152 GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass 153 file:file 154 fields:fields 155 storageSize:storageSize 156 wireFormat:wireFormat]; 157 [fields release]; 158 return descriptor; 159} 160 161- (instancetype)initWithClass:(Class)messageClass 162 file:(GPBFileDescriptor *)file 163 fields:(NSArray *)fields 164 storageSize:(uint32_t)storageSize 165 wireFormat:(BOOL)wireFormat { 166 if ((self = [super init])) { 167 messageClass_ = messageClass; 168 file_ = file; 169 fields_ = [fields retain]; 170 storageSize_ = storageSize; 171 wireFormat_ = wireFormat; 172 } 173 return self; 174} 175 176- (void)dealloc { 177 [fields_ release]; 178 [oneofs_ release]; 179 [super dealloc]; 180} 181 182- (void)setupOneofs:(const char **)oneofNames 183 count:(uint32_t)count 184 firstHasIndex:(int32_t)firstHasIndex { 185 NSCAssert(firstHasIndex < 0, @"Should always be <0"); 186 NSMutableArray *oneofs = [[NSMutableArray alloc] initWithCapacity:count]; 187 for (uint32_t i = 0, hasIndex = firstHasIndex; i < count; ++i, --hasIndex) { 188 const char *name = oneofNames[i]; 189 NSArray *fieldsForOneof = NewFieldsArrayForHasIndex(hasIndex, fields_); 190 NSCAssert(fieldsForOneof.count > 0, 191 @"No fields for this oneof? (%s:%d)", name, hasIndex); 192 GPBOneofDescriptor *oneofDescriptor = 193 [[GPBOneofDescriptor alloc] initWithName:name fields:fieldsForOneof]; 194 [oneofs addObject:oneofDescriptor]; 195 [oneofDescriptor release]; 196 [fieldsForOneof release]; 197 } 198 oneofs_ = oneofs; 199} 200 201- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo { 202 // Extra info is a compile time option, so skip the work if not needed. 203 if (extraTextFormatInfo) { 204 NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo]; 205 for (GPBFieldDescriptor *fieldDescriptor in fields_) { 206 if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) { 207 objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey, 208 extraInfoValue, 209 OBJC_ASSOCIATION_RETAIN_NONATOMIC); 210 } 211 } 212 } 213} 214 215- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count { 216 extensionRanges_ = ranges; 217 extensionRangesCount_ = count; 218} 219 220- (void)setupContainingMessageClassName:(const char *)msgClassName { 221 // Note: Only fetch the class here, can't send messages to it because 222 // that could cause cycles back to this class within +initialize if 223 // two messages have each other in fields (i.e. - they build a graph). 224 NSAssert(objc_getClass(msgClassName), @"Class %s not defined", msgClassName); 225 NSValue *parentNameValue = [NSValue valueWithPointer:msgClassName]; 226 objc_setAssociatedObject(self, &kParentClassNameValueKey, 227 parentNameValue, 228 OBJC_ASSOCIATION_RETAIN_NONATOMIC); 229} 230 231- (void)setupMessageClassNameSuffix:(NSString *)suffix { 232 if (suffix.length) { 233 objc_setAssociatedObject(self, &kClassNameSuffixKey, 234 suffix, 235 OBJC_ASSOCIATION_RETAIN_NONATOMIC); 236 } 237} 238 239- (NSString *)name { 240 return NSStringFromClass(messageClass_); 241} 242 243- (GPBDescriptor *)containingType { 244 NSValue *parentNameValue = 245 objc_getAssociatedObject(self, &kParentClassNameValueKey); 246 if (!parentNameValue) { 247 return nil; 248 } 249 const char *parentName = [parentNameValue pointerValue]; 250 Class parentClass = objc_getClass(parentName); 251 NSAssert(parentClass, @"Class %s not defined", parentName); 252 return [parentClass descriptor]; 253} 254 255- (NSString *)fullName { 256 NSString *className = NSStringFromClass(self.messageClass); 257 GPBFileDescriptor *file = self.file; 258 NSString *objcPrefix = file.objcPrefix; 259 if (objcPrefix && ![className hasPrefix:objcPrefix]) { 260 NSAssert(0, 261 @"Class didn't have correct prefix? (%@ - %@)", 262 className, objcPrefix); 263 return nil; 264 } 265 GPBDescriptor *parent = self.containingType; 266 267 NSString *name = nil; 268 if (parent) { 269 NSString *parentClassName = NSStringFromClass(parent.messageClass); 270 // The generator will add _Class to avoid reserved words, drop it. 271 NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey); 272 if (suffix) { 273 if (![parentClassName hasSuffix:suffix]) { 274 NSAssert(0, 275 @"ParentMessage class didn't have correct suffix? (%@ - %@)", 276 className, suffix); 277 return nil; 278 } 279 parentClassName = 280 [parentClassName substringToIndex:(parentClassName.length - suffix.length)]; 281 } 282 NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"]; 283 if (![className hasPrefix:parentPrefix]) { 284 NSAssert(0, 285 @"Class didn't have the correct parent name prefix? (%@ - %@)", 286 parentPrefix, className); 287 return nil; 288 } 289 name = [className substringFromIndex:parentPrefix.length]; 290 } else { 291 name = [className substringFromIndex:objcPrefix.length]; 292 } 293 294 // The generator will add _Class to avoid reserved words, drop it. 295 NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey); 296 if (suffix) { 297 if (![name hasSuffix:suffix]) { 298 NSAssert(0, 299 @"Message class didn't have correct suffix? (%@ - %@)", 300 name, suffix); 301 return nil; 302 } 303 name = [name substringToIndex:(name.length - suffix.length)]; 304 } 305 306 NSString *prefix = (parent != nil ? parent.fullName : file.package); 307 NSString *result; 308 if (prefix.length > 0) { 309 result = [NSString stringWithFormat:@"%@.%@", prefix, name]; 310 } else { 311 result = name; 312 } 313 return result; 314} 315 316- (id)copyWithZone:(NSZone *)zone { 317#pragma unused(zone) 318 return [self retain]; 319} 320 321- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber { 322 for (GPBFieldDescriptor *descriptor in fields_) { 323 if (GPBFieldNumber(descriptor) == fieldNumber) { 324 return descriptor; 325 } 326 } 327 return nil; 328} 329 330- (GPBFieldDescriptor *)fieldWithName:(NSString *)name { 331 for (GPBFieldDescriptor *descriptor in fields_) { 332 if ([descriptor.name isEqual:name]) { 333 return descriptor; 334 } 335 } 336 return nil; 337} 338 339- (GPBOneofDescriptor *)oneofWithName:(NSString *)name { 340 for (GPBOneofDescriptor *descriptor in oneofs_) { 341 if ([descriptor.name isEqual:name]) { 342 return descriptor; 343 } 344 } 345 return nil; 346} 347 348@end 349 350@implementation GPBFileDescriptor { 351 NSString *package_; 352 NSString *objcPrefix_; 353 GPBFileSyntax syntax_; 354} 355 356@synthesize package = package_; 357@synthesize objcPrefix = objcPrefix_; 358@synthesize syntax = syntax_; 359 360- (instancetype)initWithPackage:(NSString *)package 361 objcPrefix:(NSString *)objcPrefix 362 syntax:(GPBFileSyntax)syntax { 363 self = [super init]; 364 if (self) { 365 package_ = [package copy]; 366 objcPrefix_ = [objcPrefix copy]; 367 syntax_ = syntax; 368 } 369 return self; 370} 371 372- (instancetype)initWithPackage:(NSString *)package 373 syntax:(GPBFileSyntax)syntax { 374 self = [super init]; 375 if (self) { 376 package_ = [package copy]; 377 syntax_ = syntax; 378 } 379 return self; 380} 381 382- (void)dealloc { 383 [package_ release]; 384 [objcPrefix_ release]; 385 [super dealloc]; 386} 387 388@end 389 390@implementation GPBOneofDescriptor 391 392@synthesize fields = fields_; 393 394- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields { 395 self = [super init]; 396 if (self) { 397 name_ = name; 398 fields_ = [fields retain]; 399 for (GPBFieldDescriptor *fieldDesc in fields) { 400 fieldDesc->containingOneof_ = self; 401 } 402 403 caseSel_ = SelFromStrings(NULL, name, "OneOfCase", NO); 404 } 405 return self; 406} 407 408- (void)dealloc { 409 [fields_ release]; 410 [super dealloc]; 411} 412 413- (NSString *)name { 414 return (NSString * _Nonnull)@(name_); 415} 416 417- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber { 418 for (GPBFieldDescriptor *descriptor in fields_) { 419 if (GPBFieldNumber(descriptor) == fieldNumber) { 420 return descriptor; 421 } 422 } 423 return nil; 424} 425 426- (GPBFieldDescriptor *)fieldWithName:(NSString *)name { 427 for (GPBFieldDescriptor *descriptor in fields_) { 428 if ([descriptor.name isEqual:name]) { 429 return descriptor; 430 } 431 } 432 return nil; 433} 434 435@end 436 437uint32_t GPBFieldTag(GPBFieldDescriptor *self) { 438 GPBMessageFieldDescription *description = self->description_; 439 GPBWireFormat format; 440 if ((description->flags & GPBFieldMapKeyMask) != 0) { 441 // Maps are repeated messages on the wire. 442 format = GPBWireFormatForType(GPBDataTypeMessage, NO); 443 } else { 444 format = GPBWireFormatForType(description->dataType, 445 ((description->flags & GPBFieldPacked) != 0)); 446 } 447 return GPBWireFormatMakeTag(description->number, format); 448} 449 450uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { 451 GPBMessageFieldDescription *description = self->description_; 452 NSCAssert((description->flags & GPBFieldRepeated) != 0, 453 @"Only valid on repeated fields"); 454 GPBWireFormat format = 455 GPBWireFormatForType(description->dataType, 456 ((description->flags & GPBFieldPacked) == 0)); 457 return GPBWireFormatMakeTag(description->number, format); 458} 459 460@implementation GPBFieldDescriptor { 461 GPBGenericValue defaultValue_; 462 463 // Message ivars 464 Class msgClass_; 465 466 // Enum ivars. 467 // If protos are generated with GenerateEnumDescriptors on then it will 468 // be a enumDescriptor, otherwise it will be a enumVerifier. 469 union { 470 GPBEnumDescriptor *enumDescriptor_; 471 GPBEnumValidationFunc enumVerifier_; 472 } enumHandling_; 473} 474 475@synthesize msgClass = msgClass_; 476@synthesize containingOneof = containingOneof_; 477 478- (instancetype)init { 479 // Throw an exception if people attempt to not use the designated initializer. 480 self = [super init]; 481 if (self != nil) { 482 [self doesNotRecognizeSelector:_cmd]; 483 self = nil; 484 } 485 return self; 486} 487 488- (instancetype)initWithFieldDescription:(void *)description 489 includesDefault:(BOOL)includesDefault 490 syntax:(GPBFileSyntax)syntax { 491 if ((self = [super init])) { 492 GPBMessageFieldDescription *coreDesc; 493 if (includesDefault) { 494 coreDesc = &(((GPBMessageFieldDescriptionWithDefault *)description)->core); 495 } else { 496 coreDesc = description; 497 } 498 description_ = coreDesc; 499 getSel_ = sel_getUid(coreDesc->name); 500 setSel_ = SelFromStrings("set", coreDesc->name, NULL, YES); 501 502 GPBDataType dataType = coreDesc->dataType; 503 BOOL isMessage = GPBDataTypeIsMessage(dataType); 504 BOOL isMapOrArray = GPBFieldIsMapOrArray(self); 505 506 if (isMapOrArray) { 507 // map<>/repeated fields get a *Count property (inplace of a has*) to 508 // support checking if there are any entries without triggering 509 // autocreation. 510 hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO); 511 } else { 512 // If there is a positive hasIndex, then: 513 // - All fields types for proto2 messages get has* selectors. 514 // - Only message fields for proto3 messages get has* selectors. 515 // Note: the positive check is to handle oneOfs, we can't check 516 // containingOneof_ because it isn't set until after initialization. 517 if ((coreDesc->hasIndex >= 0) && 518 (coreDesc->hasIndex != GPBNoHasBit) && 519 ((syntax != GPBFileSyntaxProto3) || isMessage)) { 520 hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO); 521 setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES); 522 } 523 } 524 525 // Extra type specific data. 526 if (isMessage) { 527 const char *className = coreDesc->dataTypeSpecific.className; 528 // Note: Only fetch the class here, can't send messages to it because 529 // that could cause cycles back to this class within +initialize if 530 // two messages have each other in fields (i.e. - they build a graph). 531 msgClass_ = objc_getClass(className); 532 NSAssert(msgClass_, @"Class %s not defined", className); 533 } else if (dataType == GPBDataTypeEnum) { 534 if ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0) { 535 enumHandling_.enumDescriptor_ = 536 coreDesc->dataTypeSpecific.enumDescFunc(); 537 } else { 538 enumHandling_.enumVerifier_ = 539 coreDesc->dataTypeSpecific.enumVerifier; 540 } 541 } 542 543 // Non map<>/repeated fields can have defaults in proto2 syntax. 544 if (!isMapOrArray && includesDefault) { 545 defaultValue_ = ((GPBMessageFieldDescriptionWithDefault *)description)->defaultValue; 546 if (dataType == GPBDataTypeBytes) { 547 // Data stored as a length prefixed (network byte order) c-string in 548 // descriptor structure. 549 const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData; 550 if (bytes) { 551 uint32_t length; 552 memcpy(&length, bytes, sizeof(length)); 553 length = ntohl(length); 554 bytes += sizeof(length); 555 defaultValue_.valueData = 556 [[NSData alloc] initWithBytes:bytes length:length]; 557 } 558 } 559 } 560 } 561 return self; 562} 563 564- (void)dealloc { 565 if (description_->dataType == GPBDataTypeBytes && 566 !(description_->flags & GPBFieldRepeated)) { 567 [defaultValue_.valueData release]; 568 } 569 [super dealloc]; 570} 571 572- (GPBDataType)dataType { 573 return description_->dataType; 574} 575 576- (BOOL)hasDefaultValue { 577 return (description_->flags & GPBFieldHasDefaultValue) != 0; 578} 579 580- (uint32_t)number { 581 return description_->number; 582} 583 584- (NSString *)name { 585 return (NSString * _Nonnull)@(description_->name); 586} 587 588- (BOOL)isRequired { 589 return (description_->flags & GPBFieldRequired) != 0; 590} 591 592- (BOOL)isOptional { 593 return (description_->flags & GPBFieldOptional) != 0; 594} 595 596- (GPBFieldType)fieldType { 597 GPBFieldFlags flags = description_->flags; 598 if ((flags & GPBFieldRepeated) != 0) { 599 return GPBFieldTypeRepeated; 600 } else if ((flags & GPBFieldMapKeyMask) != 0) { 601 return GPBFieldTypeMap; 602 } else { 603 return GPBFieldTypeSingle; 604 } 605} 606 607- (GPBDataType)mapKeyDataType { 608 switch (description_->flags & GPBFieldMapKeyMask) { 609 case GPBFieldMapKeyInt32: 610 return GPBDataTypeInt32; 611 case GPBFieldMapKeyInt64: 612 return GPBDataTypeInt64; 613 case GPBFieldMapKeyUInt32: 614 return GPBDataTypeUInt32; 615 case GPBFieldMapKeyUInt64: 616 return GPBDataTypeUInt64; 617 case GPBFieldMapKeySInt32: 618 return GPBDataTypeSInt32; 619 case GPBFieldMapKeySInt64: 620 return GPBDataTypeSInt64; 621 case GPBFieldMapKeyFixed32: 622 return GPBDataTypeFixed32; 623 case GPBFieldMapKeyFixed64: 624 return GPBDataTypeFixed64; 625 case GPBFieldMapKeySFixed32: 626 return GPBDataTypeSFixed32; 627 case GPBFieldMapKeySFixed64: 628 return GPBDataTypeSFixed64; 629 case GPBFieldMapKeyBool: 630 return GPBDataTypeBool; 631 case GPBFieldMapKeyString: 632 return GPBDataTypeString; 633 634 default: 635 NSAssert(0, @"Not a map type"); 636 return GPBDataTypeInt32; // For lack of anything better. 637 } 638} 639 640- (BOOL)isPackable { 641 return (description_->flags & GPBFieldPacked) != 0; 642} 643 644- (BOOL)isValidEnumValue:(int32_t)value { 645 NSAssert(description_->dataType == GPBDataTypeEnum, 646 @"Field Must be of type GPBDataTypeEnum"); 647 if (description_->flags & GPBFieldHasEnumDescriptor) { 648 return enumHandling_.enumDescriptor_.enumVerifier(value); 649 } else { 650 return enumHandling_.enumVerifier_(value); 651 } 652} 653 654- (GPBEnumDescriptor *)enumDescriptor { 655 if (description_->flags & GPBFieldHasEnumDescriptor) { 656 return enumHandling_.enumDescriptor_; 657 } else { 658 return nil; 659 } 660} 661 662- (GPBGenericValue)defaultValue { 663 // Depends on the fact that defaultValue_ is initialized either to "0/nil" or 664 // to an actual defaultValue in our initializer. 665 GPBGenericValue value = defaultValue_; 666 667 if (!(description_->flags & GPBFieldRepeated)) { 668 // We special handle data and strings. If they are nil, we replace them 669 // with empty string/empty data. 670 GPBDataType type = description_->dataType; 671 if (type == GPBDataTypeBytes && value.valueData == nil) { 672 value.valueData = GPBEmptyNSData(); 673 } else if (type == GPBDataTypeString && value.valueString == nil) { 674 value.valueString = @""; 675 } 676 } 677 return value; 678} 679 680- (NSString *)textFormatName { 681 if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) { 682 NSValue *extraInfoValue = 683 objc_getAssociatedObject(self, &kTextFormatExtraValueKey); 684 // Support can be left out at generation time. 685 if (!extraInfoValue) { 686 return nil; 687 } 688 const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue]; 689 return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self), 690 self.name); 691 } 692 693 // The logic here has to match SetCommonFieldVariables() from 694 // objectivec_field.cc in the proto compiler. 695 NSString *name = self.name; 696 NSUInteger len = [name length]; 697 698 // Remove the "_p" added to reserved names. 699 if ([name hasSuffix:@"_p"]) { 700 name = [name substringToIndex:(len - 2)]; 701 len = [name length]; 702 } 703 704 // Remove "Array" from the end for repeated fields. 705 if (((description_->flags & GPBFieldRepeated) != 0) && 706 [name hasSuffix:@"Array"]) { 707 name = [name substringToIndex:(len - 5)]; 708 len = [name length]; 709 } 710 711 // Groups vs. other fields. 712 if (description_->dataType == GPBDataTypeGroup) { 713 // Just capitalize the first letter. 714 unichar firstChar = [name characterAtIndex:0]; 715 if (firstChar >= 'a' && firstChar <= 'z') { 716 NSString *firstCharString = 717 [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')]; 718 NSString *result = 719 [name stringByReplacingCharactersInRange:NSMakeRange(0, 1) 720 withString:firstCharString]; 721 return result; 722 } 723 return name; 724 725 } else { 726 // Undo the CamelCase. 727 NSMutableString *result = [NSMutableString stringWithCapacity:len]; 728 for (uint32_t i = 0; i < len; i++) { 729 unichar c = [name characterAtIndex:i]; 730 if (c >= 'A' && c <= 'Z') { 731 if (i > 0) { 732 [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')]; 733 } else { 734 [result appendFormat:@"%C", c]; 735 } 736 } else { 737 [result appendFormat:@"%C", c]; 738 } 739 } 740 return result; 741 } 742} 743 744@end 745 746@implementation GPBEnumDescriptor { 747 NSString *name_; 748 // valueNames_ is a single c string with all of the value names appended 749 // together, each null terminated. -calcValueNameOffsets fills in 750 // nameOffsets_ with the offsets to allow quicker access to the individual 751 // names. 752 const char *valueNames_; 753 const int32_t *values_; 754 GPBEnumValidationFunc enumVerifier_; 755 const uint8_t *extraTextFormatInfo_; 756 uint32_t *nameOffsets_; 757 uint32_t valueCount_; 758} 759 760@synthesize name = name_; 761@synthesize enumVerifier = enumVerifier_; 762 763+ (instancetype) 764 allocDescriptorForName:(NSString *)name 765 valueNames:(const char *)valueNames 766 values:(const int32_t *)values 767 count:(uint32_t)valueCount 768 enumVerifier:(GPBEnumValidationFunc)enumVerifier { 769 GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name 770 valueNames:valueNames 771 values:values 772 count:valueCount 773 enumVerifier:enumVerifier]; 774 return descriptor; 775} 776 777+ (instancetype) 778 allocDescriptorForName:(NSString *)name 779 valueNames:(const char *)valueNames 780 values:(const int32_t *)values 781 count:(uint32_t)valueCount 782 enumVerifier:(GPBEnumValidationFunc)enumVerifier 783 extraTextFormatInfo:(const char *)extraTextFormatInfo { 784 // Call the common case. 785 GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name 786 valueNames:valueNames 787 values:values 788 count:valueCount 789 enumVerifier:enumVerifier]; 790 // Set the extra info. 791 descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo; 792 return descriptor; 793} 794 795- (instancetype)initWithName:(NSString *)name 796 valueNames:(const char *)valueNames 797 values:(const int32_t *)values 798 count:(uint32_t)valueCount 799 enumVerifier:(GPBEnumValidationFunc)enumVerifier { 800 if ((self = [super init])) { 801 name_ = [name copy]; 802 valueNames_ = valueNames; 803 values_ = values; 804 valueCount_ = valueCount; 805 enumVerifier_ = enumVerifier; 806 } 807 return self; 808} 809 810- (void)dealloc { 811 [name_ release]; 812 if (nameOffsets_) free(nameOffsets_); 813 [super dealloc]; 814} 815 816- (void)calcValueNameOffsets { 817 @synchronized(self) { 818 if (nameOffsets_ != NULL) { 819 return; 820 } 821 uint32_t *offsets = malloc(valueCount_ * sizeof(uint32_t)); 822 if (!offsets) return; 823 const char *scan = valueNames_; 824 for (uint32_t i = 0; i < valueCount_; ++i) { 825 offsets[i] = (uint32_t)(scan - valueNames_); 826 while (*scan != '\0') ++scan; 827 ++scan; // Step over the null. 828 } 829 nameOffsets_ = offsets; 830 } 831} 832 833- (NSString *)enumNameForValue:(int32_t)number { 834 for (uint32_t i = 0; i < valueCount_; ++i) { 835 if (values_[i] == number) { 836 return [self getEnumNameForIndex:i]; 837 } 838 } 839 return nil; 840} 841 842- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name { 843 // Must have the prefix. 844 NSUInteger prefixLen = name_.length + 1; 845 if ((name.length <= prefixLen) || ![name hasPrefix:name_] || 846 ([name characterAtIndex:prefixLen - 1] != '_')) { 847 return NO; 848 } 849 850 // Skip over the prefix. 851 const char *nameAsCStr = [name UTF8String]; 852 nameAsCStr += prefixLen; 853 854 if (nameOffsets_ == NULL) [self calcValueNameOffsets]; 855 if (nameOffsets_ == NULL) return NO; 856 857 // Find it. 858 for (uint32_t i = 0; i < valueCount_; ++i) { 859 const char *valueName = valueNames_ + nameOffsets_[i]; 860 if (strcmp(nameAsCStr, valueName) == 0) { 861 if (outValue) { 862 *outValue = values_[i]; 863 } 864 return YES; 865 } 866 } 867 return NO; 868} 869 870- (BOOL)getValue:(int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName { 871 if (nameOffsets_ == NULL) [self calcValueNameOffsets]; 872 if (nameOffsets_ == NULL) return NO; 873 874 for (uint32_t i = 0; i < valueCount_; ++i) { 875 NSString *valueTextFormatName = [self getEnumTextFormatNameForIndex:i]; 876 if ([valueTextFormatName isEqual:textFormatName]) { 877 if (outValue) { 878 *outValue = values_[i]; 879 } 880 return YES; 881 } 882 } 883 return NO; 884} 885 886- (NSString *)textFormatNameForValue:(int32_t)number { 887 // Find the EnumValue descriptor and its index. 888 BOOL foundIt = NO; 889 uint32_t valueDescriptorIndex; 890 for (valueDescriptorIndex = 0; valueDescriptorIndex < valueCount_; 891 ++valueDescriptorIndex) { 892 if (values_[valueDescriptorIndex] == number) { 893 foundIt = YES; 894 break; 895 } 896 } 897 898 if (!foundIt) { 899 return nil; 900 } 901 return [self getEnumTextFormatNameForIndex:valueDescriptorIndex]; 902} 903 904- (uint32_t)enumNameCount { 905 return valueCount_; 906} 907 908- (NSString *)getEnumNameForIndex:(uint32_t)index { 909 if (nameOffsets_ == NULL) [self calcValueNameOffsets]; 910 if (nameOffsets_ == NULL) return nil; 911 912 if (index >= valueCount_) { 913 return nil; 914 } 915 const char *valueName = valueNames_ + nameOffsets_[index]; 916 NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName]; 917 return fullName; 918} 919 920- (NSString *)getEnumTextFormatNameForIndex:(uint32_t)index { 921 if (nameOffsets_ == NULL) [self calcValueNameOffsets]; 922 if (nameOffsets_ == NULL) return nil; 923 924 if (index >= valueCount_) { 925 return nil; 926 } 927 NSString *result = nil; 928 // Naming adds an underscore between enum name and value name, skip that also. 929 const char *valueName = valueNames_ + nameOffsets_[index]; 930 NSString *shortName = @(valueName); 931 932 // See if it is in the map of special format handling. 933 if (extraTextFormatInfo_) { 934 result = GPBDecodeTextFormatName(extraTextFormatInfo_, 935 (int32_t)index, shortName); 936 } 937 // Logic here needs to match what objectivec_enum.cc does in the proto 938 // compiler. 939 if (result == nil) { 940 NSUInteger len = [shortName length]; 941 NSMutableString *worker = [NSMutableString stringWithCapacity:len]; 942 for (NSUInteger i = 0; i < len; i++) { 943 unichar c = [shortName characterAtIndex:i]; 944 if (i > 0 && c >= 'A' && c <= 'Z') { 945 [worker appendString:@"_"]; 946 } 947 [worker appendFormat:@"%c", toupper((char)c)]; 948 } 949 result = worker; 950 } 951 return result; 952} 953 954@end 955 956@implementation GPBExtensionDescriptor { 957 GPBGenericValue defaultValue_; 958} 959 960@synthesize containingMessageClass = containingMessageClass_; 961 962- (instancetype)initWithExtensionDescription: 963 (GPBExtensionDescription *)description { 964 if ((self = [super init])) { 965 description_ = description; 966 967#if defined(DEBUG) && DEBUG 968 const char *className = description->messageOrGroupClassName; 969 if (className) { 970 NSAssert(objc_lookUpClass(className) != Nil, 971 @"Class %s not defined", className); 972 } 973#endif 974 975 if (description->extendedClass) { 976 Class containingClass = objc_lookUpClass(description->extendedClass); 977 NSAssert(containingClass, @"Class %s not defined", 978 description->extendedClass); 979 containingMessageClass_ = containingClass; 980 } 981 982 GPBDataType type = description_->dataType; 983 if (type == GPBDataTypeBytes) { 984 // Data stored as a length prefixed c-string in descriptor records. 985 const uint8_t *bytes = 986 (const uint8_t *)description->defaultValue.valueData; 987 if (bytes) { 988 uint32_t length; 989 memcpy(&length, bytes, sizeof(length)); 990 // The length is stored in network byte order. 991 length = ntohl(length); 992 bytes += sizeof(length); 993 defaultValue_.valueData = 994 [[NSData alloc] initWithBytes:bytes length:length]; 995 } 996 } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) { 997 // The default is looked up in -defaultValue instead since extensions 998 // aren't common, we avoid the hit startup hit and it avoid initialization 999 // order issues. 1000 } else { 1001 defaultValue_ = description->defaultValue; 1002 } 1003 } 1004 return self; 1005} 1006 1007- (void)dealloc { 1008 if ((description_->dataType == GPBDataTypeBytes) && 1009 !GPBExtensionIsRepeated(description_)) { 1010 [defaultValue_.valueData release]; 1011 } 1012 [super dealloc]; 1013} 1014 1015- (instancetype)copyWithZone:(NSZone *)zone { 1016#pragma unused(zone) 1017 // Immutable. 1018 return [self retain]; 1019} 1020 1021- (NSString *)singletonName { 1022 return (NSString * _Nonnull)@(description_->singletonName); 1023} 1024 1025- (const char *)singletonNameC { 1026 return description_->singletonName; 1027} 1028 1029- (uint32_t)fieldNumber { 1030 return description_->fieldNumber; 1031} 1032 1033- (GPBDataType)dataType { 1034 return description_->dataType; 1035} 1036 1037- (GPBWireFormat)wireType { 1038 return GPBWireFormatForType(description_->dataType, 1039 GPBExtensionIsPacked(description_)); 1040} 1041 1042- (GPBWireFormat)alternateWireType { 1043 NSAssert(GPBExtensionIsRepeated(description_), 1044 @"Only valid on repeated extensions"); 1045 return GPBWireFormatForType(description_->dataType, 1046 !GPBExtensionIsPacked(description_)); 1047} 1048 1049- (BOOL)isRepeated { 1050 return GPBExtensionIsRepeated(description_); 1051} 1052 1053- (BOOL)isPackable { 1054 return GPBExtensionIsPacked(description_); 1055} 1056 1057- (Class)msgClass { 1058 return objc_getClass(description_->messageOrGroupClassName); 1059} 1060 1061- (GPBEnumDescriptor *)enumDescriptor { 1062 if (description_->dataType == GPBDataTypeEnum) { 1063 GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc(); 1064 return enumDescriptor; 1065 } 1066 return nil; 1067} 1068 1069- (id)defaultValue { 1070 if (GPBExtensionIsRepeated(description_)) { 1071 return nil; 1072 } 1073 1074 switch (description_->dataType) { 1075 case GPBDataTypeBool: 1076 return @(defaultValue_.valueBool); 1077 case GPBDataTypeFloat: 1078 return @(defaultValue_.valueFloat); 1079 case GPBDataTypeDouble: 1080 return @(defaultValue_.valueDouble); 1081 case GPBDataTypeInt32: 1082 case GPBDataTypeSInt32: 1083 case GPBDataTypeEnum: 1084 case GPBDataTypeSFixed32: 1085 return @(defaultValue_.valueInt32); 1086 case GPBDataTypeInt64: 1087 case GPBDataTypeSInt64: 1088 case GPBDataTypeSFixed64: 1089 return @(defaultValue_.valueInt64); 1090 case GPBDataTypeUInt32: 1091 case GPBDataTypeFixed32: 1092 return @(defaultValue_.valueUInt32); 1093 case GPBDataTypeUInt64: 1094 case GPBDataTypeFixed64: 1095 return @(defaultValue_.valueUInt64); 1096 case GPBDataTypeBytes: 1097 // Like message fields, the default is zero length data. 1098 return (defaultValue_.valueData ? defaultValue_.valueData 1099 : GPBEmptyNSData()); 1100 case GPBDataTypeString: 1101 // Like message fields, the default is zero length string. 1102 return (defaultValue_.valueString ? defaultValue_.valueString : @""); 1103 case GPBDataTypeGroup: 1104 case GPBDataTypeMessage: 1105 return nil; 1106 } 1107} 1108 1109- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other { 1110 int32_t selfNumber = description_->fieldNumber; 1111 int32_t otherNumber = other->description_->fieldNumber; 1112 if (selfNumber < otherNumber) { 1113 return NSOrderedAscending; 1114 } else if (selfNumber == otherNumber) { 1115 return NSOrderedSame; 1116 } else { 1117 return NSOrderedDescending; 1118 } 1119} 1120 1121@end 1122 1123#pragma clang diagnostic pop 1124