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