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