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