1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file or at 6// https://developers.google.com/open-source/licenses/bsd 7 8#import "GPBUtilities.h" 9 10#import <objc/runtime.h> 11 12#import "GPBArray.h" 13#import "GPBArray_PackagePrivate.h" 14#import "GPBDescriptor.h" 15#import "GPBDescriptor_PackagePrivate.h" 16#import "GPBDictionary.h" 17#import "GPBDictionary_PackagePrivate.h" 18#import "GPBMessage.h" 19#import "GPBMessage_PackagePrivate.h" 20#import "GPBUnknownField.h" 21#import "GPBUnknownFieldSet.h" 22#import "GPBUnknownField_PackagePrivate.h" 23#import "GPBUnknownFields.h" 24#import "GPBUtilities.h" 25#import "GPBUtilities_PackagePrivate.h" 26 27// Direct access is use for speed, to avoid even internally declaring things 28// read/write, etc. The warning is enabled in the project to ensure code calling 29// protos can turn on -Wdirect-ivar-access without issues. 30#pragma clang diagnostic push 31#pragma clang diagnostic ignored "-Wdirect-ivar-access" 32 33static void AppendTextFormatForMessage(GPBMessage *message, NSMutableString *toStr, 34 NSString *lineIndent); 35 36// Are two datatypes the same basic type representation (ex Int32 and SInt32). 37// Marked unused because currently only called from asserts/debug. 38static BOOL DataTypesEquivalent(GPBDataType type1, GPBDataType type2) __attribute__((unused)); 39 40// Basic type representation for a type (ex: for SInt32 it is Int32). 41// Marked unused because currently only called from asserts/debug. 42static GPBDataType BaseDataType(GPBDataType type) __attribute__((unused)); 43 44// String name for a data type. 45// Marked unused because currently only called from asserts/debug. 46static NSString *TypeToString(GPBDataType dataType) __attribute__((unused)); 47 48// Helper for clearing oneofs. 49static void GPBMaybeClearOneofPrivate(GPBMessage *self, GPBOneofDescriptor *oneof, 50 int32_t oneofHasIndex, uint32_t fieldNumberNotToClear); 51 52NSData *GPBEmptyNSData(void) { 53 static dispatch_once_t onceToken; 54 static NSData *defaultNSData = nil; 55 dispatch_once(&onceToken, ^{ 56 defaultNSData = [[NSData alloc] init]; 57 }); 58 return defaultNSData; 59} 60 61void GPBMessageDropUnknownFieldsRecursively(GPBMessage *initialMessage) { 62 if (!initialMessage) { 63 return; 64 } 65 66 // Use an array as a list to process to avoid recursion. 67 NSMutableArray *todo = [NSMutableArray arrayWithObject:initialMessage]; 68 69 while (todo.count) { 70 GPBMessage *msg = todo.lastObject; 71 [todo removeLastObject]; 72 73 // Clear unknowns. 74 [msg clearUnknownFields]; 75 76 // Handle the message fields. 77 GPBDescriptor *descriptor = [[msg class] descriptor]; 78 for (GPBFieldDescriptor *field in descriptor->fields_) { 79 if (!GPBFieldDataTypeIsMessage(field)) { 80 continue; 81 } 82 switch (field.fieldType) { 83 case GPBFieldTypeSingle: 84 if (GPBGetHasIvarField(msg, field)) { 85 GPBMessage *fieldMessage = GPBGetObjectIvarWithFieldNoAutocreate(msg, field); 86 [todo addObject:fieldMessage]; 87 } 88 break; 89 90 case GPBFieldTypeRepeated: { 91 NSArray *fieldMessages = GPBGetObjectIvarWithFieldNoAutocreate(msg, field); 92 if (fieldMessages.count) { 93 [todo addObjectsFromArray:fieldMessages]; 94 } 95 break; 96 } 97 98 case GPBFieldTypeMap: { 99 id rawFieldMap = GPBGetObjectIvarWithFieldNoAutocreate(msg, field); 100 switch (field.mapKeyDataType) { 101 case GPBDataTypeBool: 102 [(GPBBoolObjectDictionary *)rawFieldMap 103 enumerateKeysAndObjectsUsingBlock:^(__unused BOOL key, id _Nonnull object, 104 __unused BOOL *_Nonnull stop) { 105 [todo addObject:object]; 106 }]; 107 break; 108 case GPBDataTypeFixed32: 109 case GPBDataTypeUInt32: 110 [(GPBUInt32ObjectDictionary *)rawFieldMap 111 enumerateKeysAndObjectsUsingBlock:^(__unused uint32_t key, id _Nonnull object, 112 __unused BOOL *_Nonnull stop) { 113 [todo addObject:object]; 114 }]; 115 break; 116 case GPBDataTypeInt32: 117 case GPBDataTypeSFixed32: 118 case GPBDataTypeSInt32: 119 [(GPBInt32ObjectDictionary *)rawFieldMap 120 enumerateKeysAndObjectsUsingBlock:^(__unused int32_t key, id _Nonnull object, 121 __unused BOOL *_Nonnull stop) { 122 [todo addObject:object]; 123 }]; 124 break; 125 case GPBDataTypeFixed64: 126 case GPBDataTypeUInt64: 127 [(GPBUInt64ObjectDictionary *)rawFieldMap 128 enumerateKeysAndObjectsUsingBlock:^(__unused uint64_t key, id _Nonnull object, 129 __unused BOOL *_Nonnull stop) { 130 [todo addObject:object]; 131 }]; 132 break; 133 case GPBDataTypeInt64: 134 case GPBDataTypeSFixed64: 135 case GPBDataTypeSInt64: 136 [(GPBInt64ObjectDictionary *)rawFieldMap 137 enumerateKeysAndObjectsUsingBlock:^(__unused int64_t key, id _Nonnull object, 138 __unused BOOL *_Nonnull stop) { 139 [todo addObject:object]; 140 }]; 141 break; 142 case GPBDataTypeString: 143 [(NSDictionary *)rawFieldMap 144 enumerateKeysAndObjectsUsingBlock:^(__unused NSString *_Nonnull key, 145 GPBMessage *_Nonnull obj, 146 __unused BOOL *_Nonnull stop) { 147 [todo addObject:obj]; 148 }]; 149 break; 150 case GPBDataTypeFloat: 151 case GPBDataTypeDouble: 152 case GPBDataTypeEnum: 153 case GPBDataTypeBytes: 154 case GPBDataTypeGroup: 155 case GPBDataTypeMessage: 156 NSCAssert(NO, @"Aren't valid key types."); 157 } 158 break; 159 } // switch(field.mapKeyDataType) 160 } // switch(field.fieldType) 161 } // for(fields) 162 163 // Handle any extensions holding messages. 164 for (GPBExtensionDescriptor *extension in [msg extensionsCurrentlySet]) { 165 if (!GPBDataTypeIsMessage(extension.dataType)) { 166 continue; 167 } 168 if (extension.isRepeated) { 169 NSArray *extMessages = [msg getExtension:extension]; 170 [todo addObjectsFromArray:extMessages]; 171 } else { 172 GPBMessage *extMessage = [msg getExtension:extension]; 173 [todo addObject:extMessage]; 174 } 175 } // for(extensionsCurrentlySet) 176 177 } // while(todo.count) 178} 179 180// -- About Version Checks -- 181// There's actually 3 places these checks all come into play: 182// 1. When the generated source is compile into .o files, the header check 183// happens. This is checking the protoc used matches the library being used 184// when making the .o. 185// 2. Every place a generated proto header is included in a developer's code, 186// the header check comes into play again. But this time it is checking that 187// the current library headers being used still support/match the ones for 188// the generated code. 189// 3. At runtime the final check here (GPBCheckRuntimeVersionsInternal), is 190// called from the generated code passing in values captured when the 191// generated code's .o was made. This checks that at runtime the generated 192// code and runtime library match. 193 194void GPBCheckRuntimeVersionSupport(int32_t objcRuntimeVersion) { 195 // NOTE: This is passing the value captured in the compiled code to check 196 // against the values captured when the runtime support was compiled. This 197 // ensures the library code isn't in a different framework/library that 198 // was generated with a non matching version. 199 if (GOOGLE_PROTOBUF_OBJC_VERSION < objcRuntimeVersion) { 200 // Library is too old for headers. 201 [NSException raise:NSInternalInconsistencyException 202 format:@"Linked to ProtocolBuffer runtime version %d," 203 @" but code compiled needing at least %d!", 204 GOOGLE_PROTOBUF_OBJC_VERSION, objcRuntimeVersion]; 205 } 206 if (objcRuntimeVersion < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) { 207 // Headers are too old for library. 208 [NSException raise:NSInternalInconsistencyException 209 format:@"Proto generation source compiled against runtime" 210 @" version %d, but this version of the runtime only" 211 @" supports back to %d!", 212 objcRuntimeVersion, GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION]; 213 } 214#if defined(DEBUG) && DEBUG 215 if (objcRuntimeVersion < GOOGLE_PROTOBUF_OBJC_VERSION) { 216 // This is a version we haven't generated for yet. 217 NSLog(@"WARNING: Code from generated Objective-C proto from an older version of the library is " 218 @"being used. Please regenerate with the current version as the code will stop working " 219 @"in a future release."); 220 } 221#endif 222} 223 224void GPBRuntimeMatchFailure(void) { 225 [NSException raise:NSInternalInconsistencyException 226 format:@"Proto generation source appears to have been from a" 227 @" version newer that this runtime (%d).", 228 GOOGLE_PROTOBUF_OBJC_VERSION]; 229} 230 231// This api is no longer used for version checks. 30001 is the last version 232// using this old versioning model. When that support is removed, this function 233// can be removed (along with the declaration in GPBUtilities_PackagePrivate.h). 234void GPBCheckRuntimeVersionInternal(int32_t version) { 235 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION <= 30001, 236 time_to_remove_this_old_version_shim); 237 if (version != GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) { 238 [NSException raise:NSInternalInconsistencyException 239 format:@"Linked to ProtocolBuffer runtime version %d," 240 @" but code compiled with version %d!", 241 GOOGLE_PROTOBUF_OBJC_GEN_VERSION, version]; 242 } 243} 244 245BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber) { 246 GPBDescriptor *descriptor = [self descriptor]; 247 GPBFieldDescriptor *field = [descriptor fieldWithNumber:fieldNumber]; 248 return GPBMessageHasFieldSet(self, field); 249} 250 251BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field) { 252 if (self == nil || field == nil) return NO; 253 254 // Repeated/Map don't use the bit, they check the count. 255 if (GPBFieldIsMapOrArray(field)) { 256 // Array/map type doesn't matter, since GPB*Array/NSArray and 257 // GPB*Dictionary/NSDictionary all support -count; 258 NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field); 259 return (arrayOrMap.count > 0); 260 } else { 261 return GPBGetHasIvarField(self, field); 262 } 263} 264 265void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field) { 266 // If not set, nothing to do. 267 if (!GPBGetHasIvarField(self, field)) { 268 return; 269 } 270 271 GPBMessageFieldDescription *fieldDesc = field->description_; 272 if (GPBFieldStoresObject(field)) { 273 // Object types are handled slightly differently, they need to be released. 274 uint8_t *storage = (uint8_t *)self->messageStorage_; 275 id *typePtr = (id *)&storage[fieldDesc->offset]; 276 [*typePtr release]; 277 *typePtr = nil; 278 } else { 279 // POD types just need to clear the has bit as the Get* method will 280 // fetch the default when needed. 281 } 282 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, NO); 283} 284 285void GPBClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof) { 286#if defined(DEBUG) && DEBUG 287 NSCAssert([[self descriptor] oneofWithName:oneof.name] == oneof, 288 @"OneofDescriptor %@ doesn't appear to be for %@ messages.", oneof.name, [self class]); 289#endif 290 GPBFieldDescriptor *firstField = oneof->fields_[0]; 291 GPBMaybeClearOneofPrivate(self, oneof, firstField->description_->hasIndex, 0); 292} 293 294BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) { 295 NSCAssert(self->messageStorage_ != NULL, @"%@: All messages should have storage (from init)", 296 [self class]); 297 if (idx < 0) { 298 NSCAssert(fieldNumber != 0, @"Invalid field number."); 299 BOOL hasIvar = (self->messageStorage_->_has_storage_[-idx] == fieldNumber); 300 return hasIvar; 301 } else { 302 NSCAssert(idx != GPBNoHasBit, @"Invalid has bit."); 303 uint32_t byteIndex = idx / 32; 304 uint32_t bitMask = (1U << (idx % 32)); 305 BOOL hasIvar = (self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO; 306 return hasIvar; 307 } 308} 309 310uint32_t GPBGetHasOneof(GPBMessage *self, int32_t idx) { 311 NSCAssert(idx < 0, @"%@: invalid index (%d) for oneof.", [self class], idx); 312 uint32_t result = self->messageStorage_->_has_storage_[-idx]; 313 return result; 314} 315 316void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber, BOOL value) { 317 if (idx < 0) { 318 NSCAssert(fieldNumber != 0, @"Invalid field number."); 319 uint32_t *has_storage = self->messageStorage_->_has_storage_; 320 has_storage[-idx] = (value ? fieldNumber : 0); 321 } else { 322 NSCAssert(idx != GPBNoHasBit, @"Invalid has bit."); 323 uint32_t *has_storage = self->messageStorage_->_has_storage_; 324 uint32_t byte = idx / 32; 325 uint32_t bitMask = (1U << (idx % 32)); 326 if (value) { 327 has_storage[byte] |= bitMask; 328 } else { 329 has_storage[byte] &= ~bitMask; 330 } 331 } 332} 333 334static void GPBMaybeClearOneofPrivate(GPBMessage *self, GPBOneofDescriptor *oneof, 335 int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) { 336 uint32_t fieldNumberSet = GPBGetHasOneof(self, oneofHasIndex); 337 if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) { 338 // Do nothing/nothing set in the oneof. 339 return; 340 } 341 342 // Like GPBClearMessageField(), free the memory if an objecttype is set, 343 // pod types don't need to do anything. 344 GPBFieldDescriptor *fieldSet = [oneof fieldWithNumber:fieldNumberSet]; 345 NSCAssert(fieldSet, @"%@: oneof set to something (%u) not in the oneof?", [self class], 346 fieldNumberSet); 347 if (fieldSet && GPBFieldStoresObject(fieldSet)) { 348 uint8_t *storage = (uint8_t *)self->messageStorage_; 349 id *typePtr = (id *)&storage[fieldSet->description_->offset]; 350 [*typePtr release]; 351 *typePtr = nil; 352 } 353 354 // Set to nothing stored in the oneof. 355 // (field number doesn't matter since setting to nothing). 356 GPBSetHasIvar(self, oneofHasIndex, 1, NO); 357} 358 359#pragma mark - IVar accessors 360 361// clang-format off 362 363//%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE) 364//%TYPE GPBGetMessage##NAME##Field(GPBMessage *self, 365//% TYPE$S NAME$S GPBFieldDescriptor *field) { 366//%#if defined(DEBUG) && DEBUG 367//% NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 368//% @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 369//% field.name, [self class]); 370//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 371//% GPBDataType##NAME), 372//% @"Attempting to get value of TYPE from field %@ " 373//% @"of %@ which is of type %@.", 374//% [self class], field.name, 375//% TypeToString(GPBGetFieldDataType(field))); 376//%#endif 377//% if (GPBGetHasIvarField(self, field)) { 378//% uint8_t *storage = (uint8_t *)self->messageStorage_; 379//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset]; 380//% return *typePtr; 381//% } else { 382//% return field.defaultValue.value##NAME; 383//% } 384//%} 385//% 386//%// Only exists for public api, no core code should use this. 387//%void GPBSetMessage##NAME##Field(GPBMessage *self, 388//% NAME$S GPBFieldDescriptor *field, 389//% NAME$S TYPE value) { 390//% if (self == nil || field == nil) return; 391//%#if defined(DEBUG) && DEBUG 392//% NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 393//% @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 394//% field.name, [self class]); 395//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 396//% GPBDataType##NAME), 397//% @"Attempting to set field %@ of %@ which is of type %@ with " 398//% @"value of type TYPE.", 399//% [self class], field.name, 400//% TypeToString(GPBGetFieldDataType(field))); 401//%#endif 402//% GPBSet##NAME##IvarWithFieldPrivate(self, field, value); 403//%} 404//% 405//%void GPBSet##NAME##IvarWithFieldPrivate(GPBMessage *self, 406//% NAME$S GPBFieldDescriptor *field, 407//% NAME$S TYPE value) { 408//% GPBOneofDescriptor *oneof = field->containingOneof_; 409//% GPBMessageFieldDescription *fieldDesc = field->description_; 410//% if (oneof) { 411//% GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 412//% } 413//%#if defined(DEBUG) && DEBUG 414//% NSCAssert(self->messageStorage_ != NULL, 415//% @"%@: All messages should have storage (from init)", 416//% [self class]); 417//%#endif 418//%#if defined(__clang_analyzer__) 419//% if (self->messageStorage_ == NULL) return; 420//%#endif 421//% uint8_t *storage = (uint8_t *)self->messageStorage_; 422//% TYPE *typePtr = (TYPE *)&storage[fieldDesc->offset]; 423//% *typePtr = value; 424//% // If the value is zero, then we only count the field as "set" if the field 425//% // shouldn't auto clear on zero. 426//% BOOL hasValue = ((value != (TYPE)0) 427//% || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0)); 428//% GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue); 429//% GPBBecomeVisibleToAutocreator(self); 430//%} 431//% 432//%PDDM-DEFINE IVAR_ALIAS_DEFN_OBJECT(NAME, TYPE) 433//%// Only exists for public api, no core code should use this. 434//%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self, 435//% TYPE$S NAME$S GPBFieldDescriptor *field) { 436//%#if defined(DEBUG) && DEBUG 437//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 438//% GPBDataType##NAME), 439//% @"Attempting to get value of TYPE from field %@ " 440//% @"of %@ which is of type %@.", 441//% [self class], field.name, 442//% TypeToString(GPBGetFieldDataType(field))); 443//%#endif 444//% return (TYPE *)GPBGetObjectIvarWithField(self, field); 445//%} 446//% 447//%// Only exists for public api, no core code should use this. 448//%void GPBSetMessage##NAME##Field(GPBMessage *self, 449//% NAME$S GPBFieldDescriptor *field, 450//% NAME$S TYPE *value) { 451//%#if defined(DEBUG) && DEBUG 452//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 453//% GPBDataType##NAME), 454//% @"Attempting to set field %@ of %@ which is of type %@ with " 455//% @"value of type TYPE.", 456//% [self class], field.name, 457//% TypeToString(GPBGetFieldDataType(field))); 458//%#endif 459//% GPBSetObjectIvarWithField(self, field, (id)value); 460//%} 461//% 462//%PDDM-DEFINE IVAR_ALIAS_DEFN_COPY_OBJECT(NAME, TYPE) 463//%// Only exists for public api, no core code should use this. 464//%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self, 465//% TYPE$S NAME$S GPBFieldDescriptor *field) { 466//%#if defined(DEBUG) && DEBUG 467//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 468//% GPBDataType##NAME), 469//% @"Attempting to get value of TYPE from field %@ " 470//% @"of %@ which is of type %@.", 471//% [self class], field.name, 472//% TypeToString(GPBGetFieldDataType(field))); 473//%#endif 474//% return (TYPE *)GPBGetObjectIvarWithField(self, field); 475//%} 476//% 477//%// Only exists for public api, no core code should use this. 478//%void GPBSetMessage##NAME##Field(GPBMessage *self, 479//% NAME$S GPBFieldDescriptor *field, 480//% NAME$S TYPE *value) { 481//%#if defined(DEBUG) && DEBUG 482//% NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 483//% GPBDataType##NAME), 484//% @"Attempting to set field %@ of %@ which is of type %@ with " 485//% @"value of type TYPE.", 486//% [self class], field.name, 487//% TypeToString(GPBGetFieldDataType(field))); 488//%#endif 489//% GPBSetCopyObjectIvarWithField(self, field, (id)value); 490//%} 491//% 492 493// clang-format on 494 495// Object types are handled slightly differently, they need to be released 496// and retained. 497 498void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { 499 if (GPBGetHasIvarField(self, field)) { 500 return; 501 } 502 uint8_t *storage = (uint8_t *)self->messageStorage_; 503 id *typePtr = (id *)&storage[field->description_->offset]; 504 GPBMessage *oldValue = *typePtr; 505 *typePtr = NULL; 506 GPBClearMessageAutocreator(oldValue); 507 [oldValue release]; 508} 509 510// This exists only for bridging some aliased types, nothing else should use it. 511static void GPBSetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field, id value) { 512 if (self == nil || field == nil) return; 513 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, [value retain]); 514} 515 516static void GPBSetCopyObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field, id value); 517 518// GPBSetCopyObjectIvarWithField is blocked from the analyzer because it flags 519// a leak for the -copy even though GPBSetRetainedObjectIvarWithFieldPrivate 520// is marked as consuming the value. Note: For some reason this doesn't happen 521// with the -retain in GPBSetObjectIvarWithField. 522#if !defined(__clang_analyzer__) 523// This exists only for bridging some aliased types, nothing else should use it. 524static void GPBSetCopyObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field, id value) { 525 if (self == nil || field == nil) return; 526 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, [value copy]); 527} 528#endif // !defined(__clang_analyzer__) 529 530void GPBSetObjectIvarWithFieldPrivate(GPBMessage *self, GPBFieldDescriptor *field, id value) { 531 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, [value retain]); 532} 533 534void GPBSetRetainedObjectIvarWithFieldPrivate(GPBMessage *self, GPBFieldDescriptor *field, 535 id value) { 536 NSCAssert(self->messageStorage_ != NULL, @"%@: All messages should have storage (from init)", 537 [self class]); 538#if defined(__clang_analyzer__) 539 if (self->messageStorage_ == NULL) return; 540#endif 541 GPBDataType fieldType = GPBGetFieldDataType(field); 542 BOOL isMapOrArray = GPBFieldIsMapOrArray(field); 543 BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType); 544#if defined(DEBUG) && DEBUG 545 if (value == nil && !isMapOrArray && !fieldIsMessage && field.hasDefaultValue) { 546 // Setting a message to nil is an obvious way to "clear" the value 547 // as there is no way to set a non-empty default value for messages. 548 // 549 // For Strings and Bytes that have default values set it is not clear what 550 // should be done when their value is set to nil. Is the intention just to 551 // clear the set value and reset to default, or is the intention to set the 552 // value to the empty string/data? Arguments can be made for both cases. 553 // 'nil' has been abused as a replacement for an empty string/data in ObjC. 554 // We decided to be consistent with all "object" types and clear the has 555 // field, and fall back on the default value. The warning below will only 556 // appear in debug, but the could should be changed so the intention is 557 // clear. 558 NSString *propName = field.name; 559 NSString *className = self.descriptor.name; 560 NSString *firstLetterCapitalizedName = [[[className substringToIndex:1] uppercaseString] 561 stringByAppendingString:[className substringFromIndex:1]]; 562 NSLog(@"warning: '%@.%@ = nil;' is not clearly defined for fields with " 563 @"default values. Please use '%@.%@ = %@' if you want to set it to " 564 @"empty, or call '%@.has%@ = NO' to reset it to it's default value of " 565 @"'%@'. Defaulting to resetting default value.", 566 className, propName, className, propName, 567 (fieldType == GPBDataTypeString) ? @"@\"\"" : @"GPBEmptyNSData()", className, 568 firstLetterCapitalizedName, field.defaultValue.valueString); 569 // Note: valueString, depending on the type, it could easily be 570 // valueData/valueMessage. 571 } 572#endif // DEBUG 573 GPBMessageFieldDescription *fieldDesc = field->description_; 574 if (!isMapOrArray) { 575 // Non repeated/map can be in an oneof, clear any existing value from the 576 // oneof. 577 GPBOneofDescriptor *oneof = field->containingOneof_; 578 if (oneof) { 579 GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 580 } 581 // Clear "has" if they are being set to nil. 582 BOOL setHasValue = (value != nil); 583 // If the field should clear on a "zero" value, then check if the string/data 584 // was zero length, and clear instead. 585 if (((fieldDesc->flags & GPBFieldClearHasIvarOnZero) != 0) && ([value length] == 0)) { 586 setHasValue = NO; 587 // The value passed in was retained, it must be released since we 588 // aren't saving anything in the field. 589 [value release]; 590 value = nil; 591 } 592 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, setHasValue); 593 } 594 uint8_t *storage = (uint8_t *)self->messageStorage_; 595 id *typePtr = (id *)&storage[fieldDesc->offset]; 596 597 id oldValue = *typePtr; 598 599 *typePtr = value; 600 601 if (oldValue) { 602 if (isMapOrArray) { 603 if (field.fieldType == GPBFieldTypeRepeated) { 604 // If the old array was autocreated by us, then clear it. 605 if (GPBDataTypeIsObject(fieldType)) { 606 if ([oldValue isKindOfClass:[GPBAutocreatedArray class]]) { 607 GPBAutocreatedArray *autoArray = oldValue; 608 if (autoArray->_autocreator == self) { 609 autoArray->_autocreator = nil; 610 } 611 } 612 } else { 613 // Type doesn't matter, it is a GPB*Array. 614 GPBInt32Array *gpbArray = oldValue; 615 if (gpbArray->_autocreator == self) { 616 gpbArray->_autocreator = nil; 617 } 618 } 619 } else { // GPBFieldTypeMap 620 // If the old map was autocreated by us, then clear it. 621 if ((field.mapKeyDataType == GPBDataTypeString) && GPBDataTypeIsObject(fieldType)) { 622 if ([oldValue isKindOfClass:[GPBAutocreatedDictionary class]]) { 623 GPBAutocreatedDictionary *autoDict = oldValue; 624 if (autoDict->_autocreator == self) { 625 autoDict->_autocreator = nil; 626 } 627 } 628 } else { 629 // Type doesn't matter, it is a GPB*Dictionary. 630 GPBInt32Int32Dictionary *gpbDict = oldValue; 631 if (gpbDict->_autocreator == self) { 632 gpbDict->_autocreator = nil; 633 } 634 } 635 } 636 } else if (fieldIsMessage) { 637 // If the old message value was autocreated by us, then clear it. 638 GPBMessage *oldMessageValue = oldValue; 639 if (GPBWasMessageAutocreatedBy(oldMessageValue, self)) { 640 GPBClearMessageAutocreator(oldMessageValue); 641 } 642 } 643 [oldValue release]; 644 } 645 646 GPBBecomeVisibleToAutocreator(self); 647} 648 649id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self, GPBFieldDescriptor *field) { 650 if (self->messageStorage_ == nil) { 651 return nil; 652 } 653 uint8_t *storage = (uint8_t *)self->messageStorage_; 654 id *typePtr = (id *)&storage[field->description_->offset]; 655 return *typePtr; 656} 657 658// Only exists for public api, no core code should use this. 659int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) { 660#if defined(DEBUG) && DEBUG 661 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 662 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", field.name, [self class]); 663 NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum, 664 @"Attempting to get value of type Enum from field %@ " 665 @"of %@ which is of type %@.", 666 [self class], field.name, TypeToString(GPBGetFieldDataType(field))); 667#endif 668 669 int32_t result = GPBGetMessageInt32Field(self, field); 670 // If this is presevering unknown enums, make sure the value is valid before 671 // returning it. 672 673 if (!GPBFieldIsClosedEnum(field) && ![field isValidEnumValue:result]) { 674 result = kGPBUnrecognizedEnumeratorValue; 675 } 676 return result; 677} 678 679// Only exists for public api, no core code should use this. 680void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value) { 681#if defined(DEBUG) && DEBUG 682 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 683 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", field.name, [self class]); 684 NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum, 685 @"Attempting to set field %@ of %@ which is of type %@ with " 686 @"value of type Enum.", 687 [self class], field.name, TypeToString(GPBGetFieldDataType(field))); 688#endif 689 GPBSetEnumIvarWithFieldPrivate(self, field, value); 690} 691 692void GPBSetEnumIvarWithFieldPrivate(GPBMessage *self, GPBFieldDescriptor *field, int32_t value) { 693 // Don't allow in unknown values. Proto3 can use the Raw method. 694 if (![field isValidEnumValue:value]) { 695 [NSException raise:NSInvalidArgumentException 696 format:@"%@.%@: Attempt to set an unknown enum value (%d)", [self class], 697 field.name, value]; 698 } 699 GPBSetInt32IvarWithFieldPrivate(self, field, value); 700} 701 702// Only exists for public api, no core code should use this. 703int32_t GPBGetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field) { 704 int32_t result = GPBGetMessageInt32Field(self, field); 705 return result; 706} 707 708// Only exists for public api, no core code should use this. 709void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, int32_t value) { 710 GPBSetInt32IvarWithFieldPrivate(self, field, value); 711} 712 713BOOL GPBGetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field) { 714#if defined(DEBUG) && DEBUG 715 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 716 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", field.name, [self class]); 717 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool), 718 @"Attempting to get value of type bool from field %@ " 719 @"of %@ which is of type %@.", 720 [self class], field.name, TypeToString(GPBGetFieldDataType(field))); 721#endif 722 if (GPBGetHasIvarField(self, field)) { 723 // Bools are stored in the has bits to avoid needing explicit space in the 724 // storage structure. 725 // (the field number passed to the HasIvar helper doesn't really matter 726 // since the offset is never negative) 727 GPBMessageFieldDescription *fieldDesc = field->description_; 728 return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number); 729 } else { 730 return field.defaultValue.valueBool; 731 } 732} 733 734// Only exists for public api, no core code should use this. 735void GPBSetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field, BOOL value) { 736 if (self == nil || field == nil) return; 737#if defined(DEBUG) && DEBUG 738 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 739 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", field.name, [self class]); 740 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool), 741 @"Attempting to set field %@ of %@ which is of type %@ with " 742 @"value of type bool.", 743 [self class], field.name, TypeToString(GPBGetFieldDataType(field))); 744#endif 745 GPBSetBoolIvarWithFieldPrivate(self, field, value); 746} 747 748void GPBSetBoolIvarWithFieldPrivate(GPBMessage *self, GPBFieldDescriptor *field, BOOL value) { 749 GPBMessageFieldDescription *fieldDesc = field->description_; 750 GPBOneofDescriptor *oneof = field->containingOneof_; 751 if (oneof) { 752 GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 753 } 754 755 // Bools are stored in the has bits to avoid needing explicit space in the 756 // storage structure. 757 // (the field number passed to the HasIvar helper doesn't really matter since 758 // the offset is never negative) 759 GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value); 760 761 // If the value is zero, then we only count the field as "set" if the field 762 // shouldn't auto clear on zero. 763 BOOL hasValue = ((value != (BOOL)0) || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0)); 764 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue); 765 GPBBecomeVisibleToAutocreator(self); 766} 767 768// clang-format off 769 770//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int32, int32_t) 771// This block of code is generated, do not edit it directly. 772 773int32_t GPBGetMessageInt32Field(GPBMessage *self, 774 GPBFieldDescriptor *field) { 775#if defined(DEBUG) && DEBUG 776 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 777 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 778 field.name, [self class]); 779 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 780 GPBDataTypeInt32), 781 @"Attempting to get value of int32_t from field %@ " 782 @"of %@ which is of type %@.", 783 [self class], field.name, 784 TypeToString(GPBGetFieldDataType(field))); 785#endif 786 if (GPBGetHasIvarField(self, field)) { 787 uint8_t *storage = (uint8_t *)self->messageStorage_; 788 int32_t *typePtr = (int32_t *)&storage[field->description_->offset]; 789 return *typePtr; 790 } else { 791 return field.defaultValue.valueInt32; 792 } 793} 794 795// Only exists for public api, no core code should use this. 796void GPBSetMessageInt32Field(GPBMessage *self, 797 GPBFieldDescriptor *field, 798 int32_t value) { 799 if (self == nil || field == nil) return; 800#if defined(DEBUG) && DEBUG 801 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 802 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 803 field.name, [self class]); 804 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 805 GPBDataTypeInt32), 806 @"Attempting to set field %@ of %@ which is of type %@ with " 807 @"value of type int32_t.", 808 [self class], field.name, 809 TypeToString(GPBGetFieldDataType(field))); 810#endif 811 GPBSetInt32IvarWithFieldPrivate(self, field, value); 812} 813 814void GPBSetInt32IvarWithFieldPrivate(GPBMessage *self, 815 GPBFieldDescriptor *field, 816 int32_t value) { 817 GPBOneofDescriptor *oneof = field->containingOneof_; 818 GPBMessageFieldDescription *fieldDesc = field->description_; 819 if (oneof) { 820 GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 821 } 822#if defined(DEBUG) && DEBUG 823 NSCAssert(self->messageStorage_ != NULL, 824 @"%@: All messages should have storage (from init)", 825 [self class]); 826#endif 827#if defined(__clang_analyzer__) 828 if (self->messageStorage_ == NULL) return; 829#endif 830 uint8_t *storage = (uint8_t *)self->messageStorage_; 831 int32_t *typePtr = (int32_t *)&storage[fieldDesc->offset]; 832 *typePtr = value; 833 // If the value is zero, then we only count the field as "set" if the field 834 // shouldn't auto clear on zero. 835 BOOL hasValue = ((value != (int32_t)0) 836 || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0)); 837 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue); 838 GPBBecomeVisibleToAutocreator(self); 839} 840 841//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt32, uint32_t) 842// This block of code is generated, do not edit it directly. 843 844uint32_t GPBGetMessageUInt32Field(GPBMessage *self, 845 GPBFieldDescriptor *field) { 846#if defined(DEBUG) && DEBUG 847 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 848 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 849 field.name, [self class]); 850 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 851 GPBDataTypeUInt32), 852 @"Attempting to get value of uint32_t from field %@ " 853 @"of %@ which is of type %@.", 854 [self class], field.name, 855 TypeToString(GPBGetFieldDataType(field))); 856#endif 857 if (GPBGetHasIvarField(self, field)) { 858 uint8_t *storage = (uint8_t *)self->messageStorage_; 859 uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset]; 860 return *typePtr; 861 } else { 862 return field.defaultValue.valueUInt32; 863 } 864} 865 866// Only exists for public api, no core code should use this. 867void GPBSetMessageUInt32Field(GPBMessage *self, 868 GPBFieldDescriptor *field, 869 uint32_t value) { 870 if (self == nil || field == nil) return; 871#if defined(DEBUG) && DEBUG 872 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 873 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 874 field.name, [self class]); 875 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 876 GPBDataTypeUInt32), 877 @"Attempting to set field %@ of %@ which is of type %@ with " 878 @"value of type uint32_t.", 879 [self class], field.name, 880 TypeToString(GPBGetFieldDataType(field))); 881#endif 882 GPBSetUInt32IvarWithFieldPrivate(self, field, value); 883} 884 885void GPBSetUInt32IvarWithFieldPrivate(GPBMessage *self, 886 GPBFieldDescriptor *field, 887 uint32_t value) { 888 GPBOneofDescriptor *oneof = field->containingOneof_; 889 GPBMessageFieldDescription *fieldDesc = field->description_; 890 if (oneof) { 891 GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 892 } 893#if defined(DEBUG) && DEBUG 894 NSCAssert(self->messageStorage_ != NULL, 895 @"%@: All messages should have storage (from init)", 896 [self class]); 897#endif 898#if defined(__clang_analyzer__) 899 if (self->messageStorage_ == NULL) return; 900#endif 901 uint8_t *storage = (uint8_t *)self->messageStorage_; 902 uint32_t *typePtr = (uint32_t *)&storage[fieldDesc->offset]; 903 *typePtr = value; 904 // If the value is zero, then we only count the field as "set" if the field 905 // shouldn't auto clear on zero. 906 BOOL hasValue = ((value != (uint32_t)0) 907 || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0)); 908 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue); 909 GPBBecomeVisibleToAutocreator(self); 910} 911 912//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int64, int64_t) 913// This block of code is generated, do not edit it directly. 914 915int64_t GPBGetMessageInt64Field(GPBMessage *self, 916 GPBFieldDescriptor *field) { 917#if defined(DEBUG) && DEBUG 918 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 919 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 920 field.name, [self class]); 921 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 922 GPBDataTypeInt64), 923 @"Attempting to get value of int64_t from field %@ " 924 @"of %@ which is of type %@.", 925 [self class], field.name, 926 TypeToString(GPBGetFieldDataType(field))); 927#endif 928 if (GPBGetHasIvarField(self, field)) { 929 uint8_t *storage = (uint8_t *)self->messageStorage_; 930 int64_t *typePtr = (int64_t *)&storage[field->description_->offset]; 931 return *typePtr; 932 } else { 933 return field.defaultValue.valueInt64; 934 } 935} 936 937// Only exists for public api, no core code should use this. 938void GPBSetMessageInt64Field(GPBMessage *self, 939 GPBFieldDescriptor *field, 940 int64_t value) { 941 if (self == nil || field == nil) return; 942#if defined(DEBUG) && DEBUG 943 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 944 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 945 field.name, [self class]); 946 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 947 GPBDataTypeInt64), 948 @"Attempting to set field %@ of %@ which is of type %@ with " 949 @"value of type int64_t.", 950 [self class], field.name, 951 TypeToString(GPBGetFieldDataType(field))); 952#endif 953 GPBSetInt64IvarWithFieldPrivate(self, field, value); 954} 955 956void GPBSetInt64IvarWithFieldPrivate(GPBMessage *self, 957 GPBFieldDescriptor *field, 958 int64_t value) { 959 GPBOneofDescriptor *oneof = field->containingOneof_; 960 GPBMessageFieldDescription *fieldDesc = field->description_; 961 if (oneof) { 962 GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 963 } 964#if defined(DEBUG) && DEBUG 965 NSCAssert(self->messageStorage_ != NULL, 966 @"%@: All messages should have storage (from init)", 967 [self class]); 968#endif 969#if defined(__clang_analyzer__) 970 if (self->messageStorage_ == NULL) return; 971#endif 972 uint8_t *storage = (uint8_t *)self->messageStorage_; 973 int64_t *typePtr = (int64_t *)&storage[fieldDesc->offset]; 974 *typePtr = value; 975 // If the value is zero, then we only count the field as "set" if the field 976 // shouldn't auto clear on zero. 977 BOOL hasValue = ((value != (int64_t)0) 978 || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0)); 979 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue); 980 GPBBecomeVisibleToAutocreator(self); 981} 982 983//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt64, uint64_t) 984// This block of code is generated, do not edit it directly. 985 986uint64_t GPBGetMessageUInt64Field(GPBMessage *self, 987 GPBFieldDescriptor *field) { 988#if defined(DEBUG) && DEBUG 989 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 990 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 991 field.name, [self class]); 992 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 993 GPBDataTypeUInt64), 994 @"Attempting to get value of uint64_t from field %@ " 995 @"of %@ which is of type %@.", 996 [self class], field.name, 997 TypeToString(GPBGetFieldDataType(field))); 998#endif 999 if (GPBGetHasIvarField(self, field)) { 1000 uint8_t *storage = (uint8_t *)self->messageStorage_; 1001 uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset]; 1002 return *typePtr; 1003 } else { 1004 return field.defaultValue.valueUInt64; 1005 } 1006} 1007 1008// Only exists for public api, no core code should use this. 1009void GPBSetMessageUInt64Field(GPBMessage *self, 1010 GPBFieldDescriptor *field, 1011 uint64_t value) { 1012 if (self == nil || field == nil) return; 1013#if defined(DEBUG) && DEBUG 1014 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 1015 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 1016 field.name, [self class]); 1017 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1018 GPBDataTypeUInt64), 1019 @"Attempting to set field %@ of %@ which is of type %@ with " 1020 @"value of type uint64_t.", 1021 [self class], field.name, 1022 TypeToString(GPBGetFieldDataType(field))); 1023#endif 1024 GPBSetUInt64IvarWithFieldPrivate(self, field, value); 1025} 1026 1027void GPBSetUInt64IvarWithFieldPrivate(GPBMessage *self, 1028 GPBFieldDescriptor *field, 1029 uint64_t value) { 1030 GPBOneofDescriptor *oneof = field->containingOneof_; 1031 GPBMessageFieldDescription *fieldDesc = field->description_; 1032 if (oneof) { 1033 GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 1034 } 1035#if defined(DEBUG) && DEBUG 1036 NSCAssert(self->messageStorage_ != NULL, 1037 @"%@: All messages should have storage (from init)", 1038 [self class]); 1039#endif 1040#if defined(__clang_analyzer__) 1041 if (self->messageStorage_ == NULL) return; 1042#endif 1043 uint8_t *storage = (uint8_t *)self->messageStorage_; 1044 uint64_t *typePtr = (uint64_t *)&storage[fieldDesc->offset]; 1045 *typePtr = value; 1046 // If the value is zero, then we only count the field as "set" if the field 1047 // shouldn't auto clear on zero. 1048 BOOL hasValue = ((value != (uint64_t)0) 1049 || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0)); 1050 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue); 1051 GPBBecomeVisibleToAutocreator(self); 1052} 1053 1054//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Float, float) 1055// This block of code is generated, do not edit it directly. 1056 1057float GPBGetMessageFloatField(GPBMessage *self, 1058 GPBFieldDescriptor *field) { 1059#if defined(DEBUG) && DEBUG 1060 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 1061 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 1062 field.name, [self class]); 1063 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1064 GPBDataTypeFloat), 1065 @"Attempting to get value of float from field %@ " 1066 @"of %@ which is of type %@.", 1067 [self class], field.name, 1068 TypeToString(GPBGetFieldDataType(field))); 1069#endif 1070 if (GPBGetHasIvarField(self, field)) { 1071 uint8_t *storage = (uint8_t *)self->messageStorage_; 1072 float *typePtr = (float *)&storage[field->description_->offset]; 1073 return *typePtr; 1074 } else { 1075 return field.defaultValue.valueFloat; 1076 } 1077} 1078 1079// Only exists for public api, no core code should use this. 1080void GPBSetMessageFloatField(GPBMessage *self, 1081 GPBFieldDescriptor *field, 1082 float value) { 1083 if (self == nil || field == nil) return; 1084#if defined(DEBUG) && DEBUG 1085 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 1086 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 1087 field.name, [self class]); 1088 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1089 GPBDataTypeFloat), 1090 @"Attempting to set field %@ of %@ which is of type %@ with " 1091 @"value of type float.", 1092 [self class], field.name, 1093 TypeToString(GPBGetFieldDataType(field))); 1094#endif 1095 GPBSetFloatIvarWithFieldPrivate(self, field, value); 1096} 1097 1098void GPBSetFloatIvarWithFieldPrivate(GPBMessage *self, 1099 GPBFieldDescriptor *field, 1100 float value) { 1101 GPBOneofDescriptor *oneof = field->containingOneof_; 1102 GPBMessageFieldDescription *fieldDesc = field->description_; 1103 if (oneof) { 1104 GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 1105 } 1106#if defined(DEBUG) && DEBUG 1107 NSCAssert(self->messageStorage_ != NULL, 1108 @"%@: All messages should have storage (from init)", 1109 [self class]); 1110#endif 1111#if defined(__clang_analyzer__) 1112 if (self->messageStorage_ == NULL) return; 1113#endif 1114 uint8_t *storage = (uint8_t *)self->messageStorage_; 1115 float *typePtr = (float *)&storage[fieldDesc->offset]; 1116 *typePtr = value; 1117 // If the value is zero, then we only count the field as "set" if the field 1118 // shouldn't auto clear on zero. 1119 BOOL hasValue = ((value != (float)0) 1120 || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0)); 1121 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue); 1122 GPBBecomeVisibleToAutocreator(self); 1123} 1124 1125//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Double, double) 1126// This block of code is generated, do not edit it directly. 1127 1128double GPBGetMessageDoubleField(GPBMessage *self, 1129 GPBFieldDescriptor *field) { 1130#if defined(DEBUG) && DEBUG 1131 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 1132 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 1133 field.name, [self class]); 1134 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1135 GPBDataTypeDouble), 1136 @"Attempting to get value of double from field %@ " 1137 @"of %@ which is of type %@.", 1138 [self class], field.name, 1139 TypeToString(GPBGetFieldDataType(field))); 1140#endif 1141 if (GPBGetHasIvarField(self, field)) { 1142 uint8_t *storage = (uint8_t *)self->messageStorage_; 1143 double *typePtr = (double *)&storage[field->description_->offset]; 1144 return *typePtr; 1145 } else { 1146 return field.defaultValue.valueDouble; 1147 } 1148} 1149 1150// Only exists for public api, no core code should use this. 1151void GPBSetMessageDoubleField(GPBMessage *self, 1152 GPBFieldDescriptor *field, 1153 double value) { 1154 if (self == nil || field == nil) return; 1155#if defined(DEBUG) && DEBUG 1156 NSCAssert([[self descriptor] fieldWithNumber:field.number] == field, 1157 @"FieldDescriptor %@ doesn't appear to be for %@ messages.", 1158 field.name, [self class]); 1159 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1160 GPBDataTypeDouble), 1161 @"Attempting to set field %@ of %@ which is of type %@ with " 1162 @"value of type double.", 1163 [self class], field.name, 1164 TypeToString(GPBGetFieldDataType(field))); 1165#endif 1166 GPBSetDoubleIvarWithFieldPrivate(self, field, value); 1167} 1168 1169void GPBSetDoubleIvarWithFieldPrivate(GPBMessage *self, 1170 GPBFieldDescriptor *field, 1171 double value) { 1172 GPBOneofDescriptor *oneof = field->containingOneof_; 1173 GPBMessageFieldDescription *fieldDesc = field->description_; 1174 if (oneof) { 1175 GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 1176 } 1177#if defined(DEBUG) && DEBUG 1178 NSCAssert(self->messageStorage_ != NULL, 1179 @"%@: All messages should have storage (from init)", 1180 [self class]); 1181#endif 1182#if defined(__clang_analyzer__) 1183 if (self->messageStorage_ == NULL) return; 1184#endif 1185 uint8_t *storage = (uint8_t *)self->messageStorage_; 1186 double *typePtr = (double *)&storage[fieldDesc->offset]; 1187 *typePtr = value; 1188 // If the value is zero, then we only count the field as "set" if the field 1189 // shouldn't auto clear on zero. 1190 BOOL hasValue = ((value != (double)0) 1191 || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0)); 1192 GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue); 1193 GPBBecomeVisibleToAutocreator(self); 1194} 1195 1196//%PDDM-EXPAND-END (6 expansions) 1197 1198// Aliases are function calls that are virtually the same. 1199 1200//%PDDM-EXPAND IVAR_ALIAS_DEFN_COPY_OBJECT(String, NSString) 1201// This block of code is generated, do not edit it directly. 1202 1203// Only exists for public api, no core code should use this. 1204NSString *GPBGetMessageStringField(GPBMessage *self, 1205 GPBFieldDescriptor *field) { 1206#if defined(DEBUG) && DEBUG 1207 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1208 GPBDataTypeString), 1209 @"Attempting to get value of NSString from field %@ " 1210 @"of %@ which is of type %@.", 1211 [self class], field.name, 1212 TypeToString(GPBGetFieldDataType(field))); 1213#endif 1214 return (NSString *)GPBGetObjectIvarWithField(self, field); 1215} 1216 1217// Only exists for public api, no core code should use this. 1218void GPBSetMessageStringField(GPBMessage *self, 1219 GPBFieldDescriptor *field, 1220 NSString *value) { 1221#if defined(DEBUG) && DEBUG 1222 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1223 GPBDataTypeString), 1224 @"Attempting to set field %@ of %@ which is of type %@ with " 1225 @"value of type NSString.", 1226 [self class], field.name, 1227 TypeToString(GPBGetFieldDataType(field))); 1228#endif 1229 GPBSetCopyObjectIvarWithField(self, field, (id)value); 1230} 1231 1232//%PDDM-EXPAND IVAR_ALIAS_DEFN_COPY_OBJECT(Bytes, NSData) 1233// This block of code is generated, do not edit it directly. 1234 1235// Only exists for public api, no core code should use this. 1236NSData *GPBGetMessageBytesField(GPBMessage *self, 1237 GPBFieldDescriptor *field) { 1238#if defined(DEBUG) && DEBUG 1239 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1240 GPBDataTypeBytes), 1241 @"Attempting to get value of NSData from field %@ " 1242 @"of %@ which is of type %@.", 1243 [self class], field.name, 1244 TypeToString(GPBGetFieldDataType(field))); 1245#endif 1246 return (NSData *)GPBGetObjectIvarWithField(self, field); 1247} 1248 1249// Only exists for public api, no core code should use this. 1250void GPBSetMessageBytesField(GPBMessage *self, 1251 GPBFieldDescriptor *field, 1252 NSData *value) { 1253#if defined(DEBUG) && DEBUG 1254 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1255 GPBDataTypeBytes), 1256 @"Attempting to set field %@ of %@ which is of type %@ with " 1257 @"value of type NSData.", 1258 [self class], field.name, 1259 TypeToString(GPBGetFieldDataType(field))); 1260#endif 1261 GPBSetCopyObjectIvarWithField(self, field, (id)value); 1262} 1263 1264//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Message, GPBMessage) 1265// This block of code is generated, do not edit it directly. 1266 1267// Only exists for public api, no core code should use this. 1268GPBMessage *GPBGetMessageMessageField(GPBMessage *self, 1269 GPBFieldDescriptor *field) { 1270#if defined(DEBUG) && DEBUG 1271 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1272 GPBDataTypeMessage), 1273 @"Attempting to get value of GPBMessage from field %@ " 1274 @"of %@ which is of type %@.", 1275 [self class], field.name, 1276 TypeToString(GPBGetFieldDataType(field))); 1277#endif 1278 return (GPBMessage *)GPBGetObjectIvarWithField(self, field); 1279} 1280 1281// Only exists for public api, no core code should use this. 1282void GPBSetMessageMessageField(GPBMessage *self, 1283 GPBFieldDescriptor *field, 1284 GPBMessage *value) { 1285#if defined(DEBUG) && DEBUG 1286 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1287 GPBDataTypeMessage), 1288 @"Attempting to set field %@ of %@ which is of type %@ with " 1289 @"value of type GPBMessage.", 1290 [self class], field.name, 1291 TypeToString(GPBGetFieldDataType(field))); 1292#endif 1293 GPBSetObjectIvarWithField(self, field, (id)value); 1294} 1295 1296//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Group, GPBMessage) 1297// This block of code is generated, do not edit it directly. 1298 1299// Only exists for public api, no core code should use this. 1300GPBMessage *GPBGetMessageGroupField(GPBMessage *self, 1301 GPBFieldDescriptor *field) { 1302#if defined(DEBUG) && DEBUG 1303 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1304 GPBDataTypeGroup), 1305 @"Attempting to get value of GPBMessage from field %@ " 1306 @"of %@ which is of type %@.", 1307 [self class], field.name, 1308 TypeToString(GPBGetFieldDataType(field))); 1309#endif 1310 return (GPBMessage *)GPBGetObjectIvarWithField(self, field); 1311} 1312 1313// Only exists for public api, no core code should use this. 1314void GPBSetMessageGroupField(GPBMessage *self, 1315 GPBFieldDescriptor *field, 1316 GPBMessage *value) { 1317#if defined(DEBUG) && DEBUG 1318 NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), 1319 GPBDataTypeGroup), 1320 @"Attempting to set field %@ of %@ which is of type %@ with " 1321 @"value of type GPBMessage.", 1322 [self class], field.name, 1323 TypeToString(GPBGetFieldDataType(field))); 1324#endif 1325 GPBSetObjectIvarWithField(self, field, (id)value); 1326} 1327 1328//%PDDM-EXPAND-END (4 expansions) 1329 1330// clang-format on 1331 1332// GPBGetMessageRepeatedField is defined in GPBMessage.m 1333 1334// Only exists for public api, no core code should use this. 1335void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) { 1336#if defined(DEBUG) && DEBUG 1337 if (field.fieldType != GPBFieldTypeRepeated) { 1338 [NSException raise:NSInvalidArgumentException 1339 format:@"%@.%@ is not a repeated field.", [self class], field.name]; 1340 } 1341 Class expectedClass = Nil; 1342 switch (GPBGetFieldDataType(field)) { 1343 case GPBDataTypeBool: 1344 expectedClass = [GPBBoolArray class]; 1345 break; 1346 case GPBDataTypeSFixed32: 1347 case GPBDataTypeInt32: 1348 case GPBDataTypeSInt32: 1349 expectedClass = [GPBInt32Array class]; 1350 break; 1351 case GPBDataTypeFixed32: 1352 case GPBDataTypeUInt32: 1353 expectedClass = [GPBUInt32Array class]; 1354 break; 1355 case GPBDataTypeSFixed64: 1356 case GPBDataTypeInt64: 1357 case GPBDataTypeSInt64: 1358 expectedClass = [GPBInt64Array class]; 1359 break; 1360 case GPBDataTypeFixed64: 1361 case GPBDataTypeUInt64: 1362 expectedClass = [GPBUInt64Array class]; 1363 break; 1364 case GPBDataTypeFloat: 1365 expectedClass = [GPBFloatArray class]; 1366 break; 1367 case GPBDataTypeDouble: 1368 expectedClass = [GPBDoubleArray class]; 1369 break; 1370 case GPBDataTypeBytes: 1371 case GPBDataTypeString: 1372 case GPBDataTypeMessage: 1373 case GPBDataTypeGroup: 1374 expectedClass = [NSMutableArray class]; 1375 break; 1376 case GPBDataTypeEnum: 1377 expectedClass = [GPBEnumArray class]; 1378 break; 1379 } 1380 if (array && ![array isKindOfClass:expectedClass]) { 1381 [NSException raise:NSInvalidArgumentException 1382 format:@"%@.%@: Expected %@ object, got %@.", [self class], field.name, 1383 expectedClass, [array class]]; 1384 } 1385#endif 1386 GPBSetObjectIvarWithField(self, field, array); 1387} 1388 1389static GPBDataType BaseDataType(GPBDataType type) { 1390 switch (type) { 1391 case GPBDataTypeSFixed32: 1392 case GPBDataTypeInt32: 1393 case GPBDataTypeSInt32: 1394 case GPBDataTypeEnum: 1395 return GPBDataTypeInt32; 1396 case GPBDataTypeFixed32: 1397 case GPBDataTypeUInt32: 1398 return GPBDataTypeUInt32; 1399 case GPBDataTypeSFixed64: 1400 case GPBDataTypeInt64: 1401 case GPBDataTypeSInt64: 1402 return GPBDataTypeInt64; 1403 case GPBDataTypeFixed64: 1404 case GPBDataTypeUInt64: 1405 return GPBDataTypeUInt64; 1406 case GPBDataTypeMessage: 1407 case GPBDataTypeGroup: 1408 return GPBDataTypeMessage; 1409 case GPBDataTypeBool: 1410 case GPBDataTypeFloat: 1411 case GPBDataTypeDouble: 1412 case GPBDataTypeBytes: 1413 case GPBDataTypeString: 1414 return type; 1415 } 1416} 1417 1418static BOOL DataTypesEquivalent(GPBDataType type1, GPBDataType type2) { 1419 return BaseDataType(type1) == BaseDataType(type2); 1420} 1421 1422static NSString *TypeToString(GPBDataType dataType) { 1423 switch (dataType) { 1424 case GPBDataTypeBool: 1425 return @"Bool"; 1426 case GPBDataTypeSFixed32: 1427 case GPBDataTypeInt32: 1428 case GPBDataTypeSInt32: 1429 return @"Int32"; 1430 case GPBDataTypeFixed32: 1431 case GPBDataTypeUInt32: 1432 return @"UInt32"; 1433 case GPBDataTypeSFixed64: 1434 case GPBDataTypeInt64: 1435 case GPBDataTypeSInt64: 1436 return @"Int64"; 1437 case GPBDataTypeFixed64: 1438 case GPBDataTypeUInt64: 1439 return @"UInt64"; 1440 case GPBDataTypeFloat: 1441 return @"Float"; 1442 case GPBDataTypeDouble: 1443 return @"Double"; 1444 case GPBDataTypeBytes: 1445 case GPBDataTypeString: 1446 case GPBDataTypeMessage: 1447 case GPBDataTypeGroup: 1448 return @"Object"; 1449 case GPBDataTypeEnum: 1450 return @"Enum"; 1451 } 1452} 1453 1454// GPBGetMessageMapField is defined in GPBMessage.m 1455 1456// Only exists for public api, no core code should use this. 1457void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field, id dictionary) { 1458#if defined(DEBUG) && DEBUG 1459 if (field.fieldType != GPBFieldTypeMap) { 1460 [NSException raise:NSInvalidArgumentException 1461 format:@"%@.%@ is not a map<> field.", [self class], field.name]; 1462 } 1463 if (dictionary) { 1464 GPBDataType keyDataType = field.mapKeyDataType; 1465 GPBDataType valueDataType = GPBGetFieldDataType(field); 1466 NSString *keyStr = TypeToString(keyDataType); 1467 NSString *valueStr = TypeToString(valueDataType); 1468 if (keyDataType == GPBDataTypeString) { 1469 keyStr = @"String"; 1470 } 1471 Class expectedClass = Nil; 1472 if ((keyDataType == GPBDataTypeString) && GPBDataTypeIsObject(valueDataType)) { 1473 expectedClass = [NSMutableDictionary class]; 1474 } else { 1475 NSString *className = [NSString stringWithFormat:@"GPB%@%@Dictionary", keyStr, valueStr]; 1476 expectedClass = NSClassFromString(className); 1477 NSCAssert(expectedClass, @"Missing a class (%@)?", expectedClass); 1478 } 1479 if (![dictionary isKindOfClass:expectedClass]) { 1480 [NSException raise:NSInvalidArgumentException 1481 format:@"%@.%@: Expected %@ object, got %@.", [self class], field.name, 1482 expectedClass, [dictionary class]]; 1483 } 1484 } 1485#endif 1486 GPBSetObjectIvarWithField(self, field, dictionary); 1487} 1488 1489#pragma mark - Misc Dynamic Runtime Utils 1490 1491const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) { 1492 Protocol *protocol = objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol)); 1493 NSCAssert(protocol, @"Missing GPBMessageSignatureProtocol"); 1494 struct objc_method_description description = 1495 protocol_getMethodDescription(protocol, selector, NO, instanceSel); 1496 NSCAssert(description.name != Nil && description.types != nil, @"Missing method for selector %@", 1497 NSStringFromSelector(selector)); 1498 return description.types; 1499} 1500 1501#pragma mark - Text Format Support 1502 1503static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) { 1504 [destStr appendString:@"\""]; 1505 NSUInteger len = [toPrint length]; 1506 for (NSUInteger i = 0; i < len; ++i) { 1507 unichar aChar = [toPrint characterAtIndex:i]; 1508 switch (aChar) { 1509 case '\n': 1510 [destStr appendString:@"\\n"]; 1511 break; 1512 case '\r': 1513 [destStr appendString:@"\\r"]; 1514 break; 1515 case '\t': 1516 [destStr appendString:@"\\t"]; 1517 break; 1518 case '\"': 1519 [destStr appendString:@"\\\""]; 1520 break; 1521 case '\'': 1522 [destStr appendString:@"\\\'"]; 1523 break; 1524 case '\\': 1525 [destStr appendString:@"\\\\"]; 1526 break; 1527 default: 1528 // This differs slightly from the C++ code in that the C++ doesn't 1529 // generate UTF8; it looks at the string in UTF8, but escapes every 1530 // byte > 0x7E. 1531 if (aChar < 0x20) { 1532 [destStr appendFormat:@"\\%d%d%d", (aChar / 64), ((aChar % 64) / 8), (aChar % 8)]; 1533 } else { 1534 [destStr appendFormat:@"%C", aChar]; 1535 } 1536 break; 1537 } 1538 } 1539 [destStr appendString:@"\""]; 1540} 1541 1542static void AppendBufferAsString(NSData *buffer, NSMutableString *destStr) { 1543 const char *src = (const char *)[buffer bytes]; 1544 size_t srcLen = [buffer length]; 1545 [destStr appendString:@"\""]; 1546 for (const char *srcEnd = src + srcLen; src < srcEnd; src++) { 1547 switch (*src) { 1548 case '\n': 1549 [destStr appendString:@"\\n"]; 1550 break; 1551 case '\r': 1552 [destStr appendString:@"\\r"]; 1553 break; 1554 case '\t': 1555 [destStr appendString:@"\\t"]; 1556 break; 1557 case '\"': 1558 [destStr appendString:@"\\\""]; 1559 break; 1560 case '\'': 1561 [destStr appendString:@"\\\'"]; 1562 break; 1563 case '\\': 1564 [destStr appendString:@"\\\\"]; 1565 break; 1566 default: 1567 if (isprint(*src)) { 1568 [destStr appendFormat:@"%c", *src]; 1569 } else { 1570 // NOTE: doing hex means you have to worry about the letter after 1571 // the hex being another hex char and forcing that to be escaped, so 1572 // use octal to keep it simple. 1573 [destStr appendFormat:@"\\%03o", (uint8_t)(*src)]; 1574 } 1575 break; 1576 } 1577 } 1578 [destStr appendString:@"\""]; 1579} 1580 1581static void AppendTextFormatForMapMessageField(id map, GPBFieldDescriptor *field, 1582 NSMutableString *toStr, NSString *lineIndent, 1583 NSString *fieldName, NSString *lineEnding) { 1584 GPBDataType keyDataType = field.mapKeyDataType; 1585 GPBDataType valueDataType = GPBGetFieldDataType(field); 1586 BOOL isMessageValue = GPBDataTypeIsMessage(valueDataType); 1587 1588 NSString *msgStartFirst = 1589 [NSString stringWithFormat:@"%@%@ {%@\n", lineIndent, fieldName, lineEnding]; 1590 NSString *msgStart = [NSString stringWithFormat:@"%@%@ {\n", lineIndent, fieldName]; 1591 NSString *msgEnd = [NSString stringWithFormat:@"%@}\n", lineIndent]; 1592 1593 NSString *keyLine = [NSString stringWithFormat:@"%@ key: ", lineIndent]; 1594 NSString *valueLine = 1595 [NSString stringWithFormat:@"%@ value%s ", lineIndent, (isMessageValue ? "" : ":")]; 1596 1597 __block BOOL isFirst = YES; 1598 1599 if ((keyDataType == GPBDataTypeString) && GPBDataTypeIsObject(valueDataType)) { 1600 // map is an NSDictionary. 1601 NSDictionary *dict = map; 1602 [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, __unused BOOL *stop) { 1603 [toStr appendString:(isFirst ? msgStartFirst : msgStart)]; 1604 isFirst = NO; 1605 1606 [toStr appendString:keyLine]; 1607 AppendStringEscaped(key, toStr); 1608 [toStr appendString:@"\n"]; 1609 1610 [toStr appendString:valueLine]; 1611#pragma clang diagnostic push 1612#pragma clang diagnostic ignored "-Wswitch-enum" 1613 switch (valueDataType) { 1614 case GPBDataTypeString: 1615 AppendStringEscaped(value, toStr); 1616 break; 1617 1618 case GPBDataTypeBytes: 1619 AppendBufferAsString(value, toStr); 1620 break; 1621 1622 case GPBDataTypeMessage: 1623 [toStr appendString:@"{\n"]; 1624 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1625 AppendTextFormatForMessage(value, toStr, subIndent); 1626 [toStr appendFormat:@"%@ }", lineIndent]; 1627 break; 1628 1629 default: 1630 NSCAssert(NO, @"Can't happen"); 1631 break; 1632 } 1633#pragma clang diagnostic pop 1634 [toStr appendString:@"\n"]; 1635 1636 [toStr appendString:msgEnd]; 1637 }]; 1638 } else { 1639 // map is one of the GPB*Dictionary classes, type doesn't matter. 1640 GPBInt32Int32Dictionary *dict = map; 1641 [dict enumerateForTextFormat:^(id keyObj, id valueObj) { 1642 [toStr appendString:(isFirst ? msgStartFirst : msgStart)]; 1643 isFirst = NO; 1644 1645 // Key always is a NSString. 1646 if (keyDataType == GPBDataTypeString) { 1647 [toStr appendString:keyLine]; 1648 AppendStringEscaped(keyObj, toStr); 1649 [toStr appendString:@"\n"]; 1650 } else { 1651 [toStr appendFormat:@"%@%@\n", keyLine, keyObj]; 1652 } 1653 1654 [toStr appendString:valueLine]; 1655#pragma clang diagnostic push 1656#pragma clang diagnostic ignored "-Wswitch-enum" 1657 switch (valueDataType) { 1658 case GPBDataTypeString: 1659 AppendStringEscaped(valueObj, toStr); 1660 break; 1661 1662 case GPBDataTypeBytes: 1663 AppendBufferAsString(valueObj, toStr); 1664 break; 1665 1666 case GPBDataTypeMessage: 1667 [toStr appendString:@"{\n"]; 1668 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1669 AppendTextFormatForMessage(valueObj, toStr, subIndent); 1670 [toStr appendFormat:@"%@ }", lineIndent]; 1671 break; 1672 1673 case GPBDataTypeEnum: { 1674 int32_t enumValue = [valueObj intValue]; 1675 NSString *valueStr = nil; 1676 GPBEnumDescriptor *descriptor = field.enumDescriptor; 1677 if (descriptor) { 1678 valueStr = [descriptor textFormatNameForValue:enumValue]; 1679 } 1680 if (valueStr) { 1681 [toStr appendString:valueStr]; 1682 } else { 1683 [toStr appendFormat:@"%d", enumValue]; 1684 } 1685 break; 1686 } 1687 1688 default: 1689 NSCAssert(valueDataType != GPBDataTypeGroup, @"Can't happen"); 1690 // Everything else is a NSString. 1691 [toStr appendString:valueObj]; 1692 break; 1693 } 1694#pragma clang diagnostic pop 1695 [toStr appendString:@"\n"]; 1696 1697 [toStr appendString:msgEnd]; 1698 }]; 1699 } 1700} 1701 1702static void AppendTextFormatForMessageField(GPBMessage *message, GPBFieldDescriptor *field, 1703 NSMutableString *toStr, NSString *lineIndent) { 1704 id arrayOrMap; 1705 NSUInteger count; 1706 GPBFieldType fieldType = field.fieldType; 1707 switch (fieldType) { 1708 case GPBFieldTypeSingle: 1709 arrayOrMap = nil; 1710 count = (GPBGetHasIvarField(message, field) ? 1 : 0); 1711 break; 1712 1713 case GPBFieldTypeRepeated: 1714 // Will be NSArray or GPB*Array, type doesn't matter, they both 1715 // implement count. 1716 arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field); 1717 count = [(NSArray *)arrayOrMap count]; 1718 break; 1719 1720 case GPBFieldTypeMap: { 1721 // Will be GPB*Dictionary or NSMutableDictionary, type doesn't matter, 1722 // they both implement count. 1723 arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field); 1724 count = [(NSDictionary *)arrayOrMap count]; 1725 break; 1726 } 1727 } 1728 1729 if (count == 0) { 1730 // Nothing to print, out of here. 1731 return; 1732 } 1733 1734 NSString *lineEnding = @""; 1735 1736 // If the name can't be reversed or support for extra info was turned off, 1737 // this can return nil. 1738 NSString *fieldName = [field textFormatName]; 1739 if ([fieldName length] == 0) { 1740 fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)]; 1741 // If there is only one entry, put the objc name as a comment, other wise 1742 // add it before the repeated values. 1743 if (count > 1) { 1744 [toStr appendFormat:@"%@# %@\n", lineIndent, field.name]; 1745 } else { 1746 lineEnding = [NSString stringWithFormat:@" # %@", field.name]; 1747 } 1748 } 1749 1750 if (fieldType == GPBFieldTypeMap) { 1751 AppendTextFormatForMapMessageField(arrayOrMap, field, toStr, lineIndent, fieldName, lineEnding); 1752 return; 1753 } 1754 1755 id array = arrayOrMap; 1756 const BOOL isRepeated = (array != nil); 1757 1758 GPBDataType fieldDataType = GPBGetFieldDataType(field); 1759 BOOL isMessageField = GPBDataTypeIsMessage(fieldDataType); 1760 for (NSUInteger j = 0; j < count; ++j) { 1761 // Start the line. 1762 [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName, (isMessageField ? "" : ":")]; 1763 1764 // The value. 1765 switch (fieldDataType) { 1766#define FIELD_CASE(GPBDATATYPE, CTYPE, REAL_TYPE, ...) \ 1767 case GPBDataType##GPBDATATYPE: { \ 1768 CTYPE v = (isRepeated ? [(GPB##REAL_TYPE##Array *)array valueAtIndex:j] \ 1769 : GPBGetMessage##REAL_TYPE##Field(message, field)); \ 1770 [toStr appendFormat:__VA_ARGS__, v]; \ 1771 break; \ 1772 } 1773 1774 FIELD_CASE(Int32, int32_t, Int32, @"%d") 1775 FIELD_CASE(SInt32, int32_t, Int32, @"%d") 1776 FIELD_CASE(SFixed32, int32_t, Int32, @"%d") 1777 FIELD_CASE(UInt32, uint32_t, UInt32, @"%u") 1778 FIELD_CASE(Fixed32, uint32_t, UInt32, @"%u") 1779 FIELD_CASE(Int64, int64_t, Int64, @"%lld") 1780 FIELD_CASE(SInt64, int64_t, Int64, @"%lld") 1781 FIELD_CASE(SFixed64, int64_t, Int64, @"%lld") 1782 FIELD_CASE(UInt64, uint64_t, UInt64, @"%llu") 1783 FIELD_CASE(Fixed64, uint64_t, UInt64, @"%llu") 1784 FIELD_CASE(Float, float, Float, @"%.*g", FLT_DIG) 1785 FIELD_CASE(Double, double, Double, @"%.*lg", DBL_DIG) 1786 1787#undef FIELD_CASE 1788 1789 case GPBDataTypeEnum: { 1790 int32_t v = (isRepeated ? [(GPBEnumArray *)array rawValueAtIndex:j] 1791 : GPBGetMessageInt32Field(message, field)); 1792 NSString *valueStr = nil; 1793 GPBEnumDescriptor *descriptor = field.enumDescriptor; 1794 if (descriptor) { 1795 valueStr = [descriptor textFormatNameForValue:v]; 1796 } 1797 if (valueStr) { 1798 [toStr appendString:valueStr]; 1799 } else { 1800 [toStr appendFormat:@"%d", v]; 1801 } 1802 break; 1803 } 1804 1805 case GPBDataTypeBool: { 1806 BOOL v = (isRepeated ? [(GPBBoolArray *)array valueAtIndex:j] 1807 : GPBGetMessageBoolField(message, field)); 1808 [toStr appendString:(v ? @"true" : @"false")]; 1809 break; 1810 } 1811 1812 case GPBDataTypeString: { 1813 NSString *v = (isRepeated ? [(NSArray *)array objectAtIndex:j] 1814 : GPBGetMessageStringField(message, field)); 1815 AppendStringEscaped(v, toStr); 1816 break; 1817 } 1818 1819 case GPBDataTypeBytes: { 1820 NSData *v = (isRepeated ? [(NSArray *)array objectAtIndex:j] 1821 : GPBGetMessageBytesField(message, field)); 1822 AppendBufferAsString(v, toStr); 1823 break; 1824 } 1825 1826 case GPBDataTypeGroup: 1827 case GPBDataTypeMessage: { 1828 GPBMessage *v = (isRepeated ? [(NSArray *)array objectAtIndex:j] 1829 : GPBGetObjectIvarWithField(message, field)); 1830 [toStr appendFormat:@"{%@\n", lineEnding]; 1831 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1832 AppendTextFormatForMessage(v, toStr, subIndent); 1833 [toStr appendFormat:@"%@}", lineIndent]; 1834 lineEnding = @""; 1835 break; 1836 } 1837 1838 } // switch(fieldDataType) 1839 1840 // End the line. 1841 [toStr appendFormat:@"%@\n", lineEnding]; 1842 1843 } // for(count) 1844} 1845 1846static void AppendTextFormatForMessageExtensionRange(GPBMessage *message, NSArray *activeExtensions, 1847 GPBExtensionRange range, 1848 NSMutableString *toStr, NSString *lineIndent) { 1849 uint32_t start = range.start; 1850 uint32_t end = range.end; 1851 for (GPBExtensionDescriptor *extension in activeExtensions) { 1852 uint32_t fieldNumber = extension.fieldNumber; 1853 if (fieldNumber < start) { 1854 // Not there yet. 1855 continue; 1856 } 1857 if (fieldNumber >= end) { 1858 // Done. 1859 break; 1860 } 1861 1862 id rawExtValue = [message getExtension:extension]; 1863 BOOL isRepeated = extension.isRepeated; 1864 1865 NSUInteger numValues = 1; 1866 NSString *lineEnding = @""; 1867 if (isRepeated) { 1868 numValues = [(NSArray *)rawExtValue count]; 1869 } 1870 1871 NSString *singletonName = extension.singletonName; 1872 if (numValues == 1) { 1873 lineEnding = [NSString stringWithFormat:@" # [%@]", singletonName]; 1874 } else { 1875 [toStr appendFormat:@"%@# [%@]\n", lineIndent, singletonName]; 1876 } 1877 1878 GPBDataType extDataType = extension.dataType; 1879 for (NSUInteger j = 0; j < numValues; ++j) { 1880 id curValue = (isRepeated ? [rawExtValue objectAtIndex:j] : rawExtValue); 1881 1882 // Start the line. 1883 [toStr appendFormat:@"%@%u%s ", lineIndent, fieldNumber, 1884 (GPBDataTypeIsMessage(extDataType) ? "" : ":")]; 1885 1886 // The value. 1887 switch (extDataType) { 1888#define FIELD_CASE(GPBDATATYPE, CTYPE, NUMSELECTOR, ...) \ 1889 case GPBDataType##GPBDATATYPE: { \ 1890 CTYPE v = [(NSNumber *)curValue NUMSELECTOR]; \ 1891 [toStr appendFormat:__VA_ARGS__, v]; \ 1892 break; \ 1893 } 1894 1895 FIELD_CASE(Int32, int32_t, intValue, @"%d") 1896 FIELD_CASE(SInt32, int32_t, intValue, @"%d") 1897 FIELD_CASE(SFixed32, int32_t, unsignedIntValue, @"%d") 1898 FIELD_CASE(UInt32, uint32_t, unsignedIntValue, @"%u") 1899 FIELD_CASE(Fixed32, uint32_t, unsignedIntValue, @"%u") 1900 FIELD_CASE(Int64, int64_t, longLongValue, @"%lld") 1901 FIELD_CASE(SInt64, int64_t, longLongValue, @"%lld") 1902 FIELD_CASE(SFixed64, int64_t, longLongValue, @"%lld") 1903 FIELD_CASE(UInt64, uint64_t, unsignedLongLongValue, @"%llu") 1904 FIELD_CASE(Fixed64, uint64_t, unsignedLongLongValue, @"%llu") 1905 FIELD_CASE(Float, float, floatValue, @"%.*g", FLT_DIG) 1906 FIELD_CASE(Double, double, doubleValue, @"%.*lg", DBL_DIG) 1907 // TODO: Add a comment with the enum name from enum descriptors 1908 // (might not be real value, so leave it as a comment, ObjC compiler 1909 // name mangles differently). Doesn't look like we actually generate 1910 // an enum descriptor reference like we do for normal fields, so this 1911 // will take a compiler change. 1912 FIELD_CASE(Enum, int32_t, intValue, @"%d") 1913 1914#undef FIELD_CASE 1915 1916 case GPBDataTypeBool: 1917 [toStr appendString:([(NSNumber *)curValue boolValue] ? @"true" : @"false")]; 1918 break; 1919 1920 case GPBDataTypeString: 1921 AppendStringEscaped(curValue, toStr); 1922 break; 1923 1924 case GPBDataTypeBytes: 1925 AppendBufferAsString((NSData *)curValue, toStr); 1926 break; 1927 1928 case GPBDataTypeGroup: 1929 case GPBDataTypeMessage: { 1930 [toStr appendFormat:@"{%@\n", lineEnding]; 1931 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1932 AppendTextFormatForMessage(curValue, toStr, subIndent); 1933 [toStr appendFormat:@"%@}", lineIndent]; 1934 lineEnding = @""; 1935 break; 1936 } 1937 1938 } // switch(extDataType) 1939 1940 // End the line. 1941 [toStr appendFormat:@"%@\n", lineEnding]; 1942 1943 } // for(numValues) 1944 1945 } // for..in(activeExtensions) 1946} 1947 1948static void AppendTextFormatForUnknownFields(GPBUnknownFields *ufs, NSMutableString *toStr, 1949 NSString *lineIndent) { 1950#if defined(DEBUG) && DEBUG 1951 NSCAssert(!ufs.empty, @"Internal Error: No unknown fields to format."); 1952#endif 1953 // Extract the fields and sort them by field number. Use a stable sort and sort just by the field 1954 // numbers, that way the output will still show the order the different types were added as well 1955 // as maintaining the order within a give number/type pair (i.e. - repeated fields say in order). 1956 NSMutableArray *sortedFields = [[NSMutableArray alloc] initWithCapacity:ufs.count]; 1957 for (GPBUnknownField *field in ufs) { 1958 [sortedFields addObject:field]; 1959 } 1960 [sortedFields 1961 sortWithOptions:NSSortStable 1962 usingComparator:^NSComparisonResult(GPBUnknownField *field1, GPBUnknownField *field2) { 1963 int32_t fieldNumber1 = field1->number_; 1964 int32_t fieldNumber2 = field2->number_; 1965 if (fieldNumber1 < fieldNumber2) { 1966 return NSOrderedAscending; 1967 } else if (fieldNumber1 > fieldNumber2) { 1968 return NSOrderedDescending; 1969 } else { 1970 return NSOrderedSame; 1971 } 1972 }]; 1973 1974 NSString *subIndent = nil; 1975 1976 for (GPBUnknownField *field in sortedFields) { 1977 int32_t fieldNumber = field->number_; 1978 switch (field->type_) { 1979 case GPBUnknownFieldTypeVarint: 1980 [toStr appendFormat:@"%@%d: %llu\n", lineIndent, fieldNumber, field->storage_.intValue]; 1981 break; 1982 case GPBUnknownFieldTypeFixed32: 1983 [toStr appendFormat:@"%@%d: 0x%X\n", lineIndent, fieldNumber, 1984 (uint32_t)field->storage_.intValue]; 1985 break; 1986 case GPBUnknownFieldTypeFixed64: 1987 [toStr appendFormat:@"%@%d: 0x%llX\n", lineIndent, fieldNumber, field->storage_.intValue]; 1988 break; 1989 case GPBUnknownFieldTypeLengthDelimited: 1990 [toStr appendFormat:@"%@%d: ", lineIndent, fieldNumber]; 1991 AppendBufferAsString(field->storage_.lengthDelimited, toStr); 1992 [toStr appendString:@"\n"]; 1993 break; 1994 case GPBUnknownFieldTypeGroup: { 1995 GPBUnknownFields *group = field->storage_.group; 1996 if (group.empty) { 1997 [toStr appendFormat:@"%@%d: {}\n", lineIndent, fieldNumber]; 1998 } else { 1999 [toStr appendFormat:@"%@%d: {\n", lineIndent, fieldNumber]; 2000 if (subIndent == nil) { 2001 subIndent = [lineIndent stringByAppendingString:@" "]; 2002 } 2003 AppendTextFormatForUnknownFields(group, toStr, subIndent); 2004 [toStr appendFormat:@"%@}\n", lineIndent]; 2005 } 2006 } break; 2007 case GPBUnknownFieldTypeLegacy: 2008#if defined(DEBUG) && DEBUG 2009 NSCAssert( 2010 NO, 2011 @"Internal error: Shouldn't have gotten a legacy field type in the unknown fields."); 2012#endif 2013 break; 2014 } 2015 } 2016 [subIndent release]; 2017 [sortedFields release]; 2018} 2019 2020static void AppendTextFormatForMessage(GPBMessage *message, NSMutableString *toStr, 2021 NSString *lineIndent) { 2022 GPBDescriptor *descriptor = [message descriptor]; 2023 NSArray *fieldsArray = descriptor->fields_; 2024 NSUInteger fieldCount = fieldsArray.count; 2025 const GPBExtensionRange *extensionRanges = descriptor.extensionRanges; 2026 NSUInteger extensionRangesCount = descriptor.extensionRangesCount; 2027 NSArray *activeExtensions = 2028 [[message extensionsCurrentlySet] sortedArrayUsingSelector:@selector(compareByFieldNumber:)]; 2029 for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) { 2030 if (i == fieldCount) { 2031 AppendTextFormatForMessageExtensionRange(message, activeExtensions, extensionRanges[j++], 2032 toStr, lineIndent); 2033 } else if (j == extensionRangesCount || 2034 GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) { 2035 AppendTextFormatForMessageField(message, fieldsArray[i++], toStr, lineIndent); 2036 } else { 2037 AppendTextFormatForMessageExtensionRange(message, activeExtensions, extensionRanges[j++], 2038 toStr, lineIndent); 2039 } 2040 } 2041 2042 GPBUnknownFields *ufs = [[GPBUnknownFields alloc] initFromMessage:message]; 2043 if (ufs.count > 0) { 2044 [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent]; 2045 AppendTextFormatForUnknownFields(ufs, toStr, lineIndent); 2046 } 2047 [ufs release]; 2048} 2049 2050NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) { 2051 if (message == nil) return @""; 2052 if (lineIndent == nil) lineIndent = @""; 2053 2054 NSMutableString *buildString = [NSMutableString string]; 2055 AppendTextFormatForMessage(message, buildString, lineIndent); 2056 return buildString; 2057} 2058 2059NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet, NSString *lineIndent) { 2060 if (unknownSet == nil) return @""; 2061 if (lineIndent == nil) lineIndent = @""; 2062 2063 NSMutableString *result = [NSMutableString string]; 2064 for (GPBUnknownField *field in [unknownSet sortedFields]) { 2065 int32_t fieldNumber = [field number]; 2066 2067#define PRINT_LOOP(PROPNAME, CTYPE, FORMAT) \ 2068 [field.PROPNAME \ 2069 enumerateValuesWithBlock:^(CTYPE value, __unused NSUInteger idx, __unused BOOL * stop) { \ 2070 [result appendFormat:@"%@%d: " FORMAT "\n", lineIndent, fieldNumber, value]; \ 2071 }]; 2072 2073 PRINT_LOOP(varintList, uint64_t, "%llu"); 2074 PRINT_LOOP(fixed32List, uint32_t, "0x%X"); 2075 PRINT_LOOP(fixed64List, uint64_t, "0x%llX"); 2076 2077#undef PRINT_LOOP 2078 2079 // NOTE: C++ version of TextFormat tries to parse this as a message 2080 // and print that if it succeeds. 2081 for (NSData *data in field.lengthDelimitedList) { 2082 [result appendFormat:@"%@%d: ", lineIndent, fieldNumber]; 2083 AppendBufferAsString(data, result); 2084 [result appendString:@"\n"]; 2085 } 2086 2087 for (GPBUnknownFieldSet *subUnknownSet in field.groupList) { 2088 [result appendFormat:@"%@%d: {\n", lineIndent, fieldNumber]; 2089 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 2090 NSString *subUnknownSetStr = GPBTextFormatForUnknownFieldSet(subUnknownSet, subIndent); 2091 [result appendString:subUnknownSetStr]; 2092 [result appendFormat:@"%@}\n", lineIndent]; 2093 } 2094 } 2095 return result; 2096} 2097 2098// Helpers to decode a varint. Not using GPBCodedInputStream version because 2099// that needs a state object, and we don't want to create an input stream out 2100// of the data. 2101GPB_INLINE int8_t ReadRawByteFromData(const uint8_t **data) { 2102 int8_t result = *((int8_t *)(*data)); 2103 ++(*data); 2104 return result; 2105} 2106 2107static int32_t ReadRawVarint32FromData(const uint8_t **data) { 2108 int8_t tmp = ReadRawByteFromData(data); 2109 if (tmp >= 0) { 2110 return tmp; 2111 } 2112 int32_t result = tmp & 0x7f; 2113 if ((tmp = ReadRawByteFromData(data)) >= 0) { 2114 result |= tmp << 7; 2115 } else { 2116 result |= (tmp & 0x7f) << 7; 2117 if ((tmp = ReadRawByteFromData(data)) >= 0) { 2118 result |= tmp << 14; 2119 } else { 2120 result |= (tmp & 0x7f) << 14; 2121 if ((tmp = ReadRawByteFromData(data)) >= 0) { 2122 result |= tmp << 21; 2123 } else { 2124 result |= (tmp & 0x7f) << 21; 2125 result |= (tmp = ReadRawByteFromData(data)) << 28; 2126 if (tmp < 0) { 2127 // Discard upper 32 bits. 2128 for (int i = 0; i < 5; i++) { 2129 if (ReadRawByteFromData(data) >= 0) { 2130 return result; 2131 } 2132 } 2133 [NSException raise:NSParseErrorException format:@"Unable to read varint32"]; 2134 } 2135 } 2136 } 2137 } 2138 return result; 2139} 2140 2141NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key, NSString *inputStr) { 2142 // decodData form: 2143 // varint32: num entries 2144 // for each entry: 2145 // varint32: key 2146 // bytes*: decode data 2147 // 2148 // decode data one of two forms: 2149 // 1: a \0 followed by the string followed by an \0 2150 // 2: bytecodes to transform an input into the right thing, ending with \0 2151 // 2152 // the bytes codes are of the form: 2153 // 0xabbccccc 2154 // 0x0 (all zeros), end. 2155 // a - if set, add an underscore 2156 // bb - 00 ccccc bytes as is 2157 // bb - 10 ccccc upper first, as is on rest, ccccc byte total 2158 // bb - 01 ccccc lower first, as is on rest, ccccc byte total 2159 // bb - 11 ccccc all upper, ccccc byte total 2160 2161 if (!decodeData || !inputStr) { 2162 return nil; 2163 } 2164 2165 // Find key 2166 const uint8_t *scan = decodeData; 2167 int32_t numEntries = ReadRawVarint32FromData(&scan); 2168 BOOL foundKey = NO; 2169 while (!foundKey && (numEntries > 0)) { 2170 --numEntries; 2171 int32_t dataKey = ReadRawVarint32FromData(&scan); 2172 if (dataKey == key) { 2173 foundKey = YES; 2174 } else { 2175 // If it is a inlined string, it will start with \0; if it is bytecode it 2176 // will start with a code. So advance one (skipping the inline string 2177 // marker), and then loop until reaching the end marker (\0). 2178 ++scan; 2179 while (*scan != 0) ++scan; 2180 // Now move past the end marker. 2181 ++scan; 2182 } 2183 } 2184 2185 if (!foundKey) { 2186 return nil; 2187 } 2188 2189 // Decode 2190 2191 if (*scan == 0) { 2192 // Inline string. Move over the marker, and NSString can take it as 2193 // UTF8. 2194 ++scan; 2195 NSString *result = [NSString stringWithUTF8String:(const char *)scan]; 2196 return result; 2197 } 2198 2199 NSMutableString *result = [NSMutableString stringWithCapacity:[inputStr length]]; 2200 2201 const uint8_t kAddUnderscore = 0b10000000; 2202 const uint8_t kOpMask = 0b01100000; 2203 // const uint8_t kOpAsIs = 0b00000000; 2204 const uint8_t kOpFirstUpper = 0b01000000; 2205 const uint8_t kOpFirstLower = 0b00100000; 2206 const uint8_t kOpAllUpper = 0b01100000; 2207 const uint8_t kSegmentLenMask = 0b00011111; 2208 2209 NSInteger i = 0; 2210 for (; *scan != 0; ++scan) { 2211 if (*scan & kAddUnderscore) { 2212 [result appendString:@"_"]; 2213 } 2214 int segmentLen = *scan & kSegmentLenMask; 2215 uint8_t decodeOp = *scan & kOpMask; 2216 2217 // Do op specific handling of the first character. 2218 if (decodeOp == kOpFirstUpper) { 2219 unichar c = [inputStr characterAtIndex:i]; 2220 [result appendFormat:@"%c", toupper((char)c)]; 2221 ++i; 2222 --segmentLen; 2223 } else if (decodeOp == kOpFirstLower) { 2224 unichar c = [inputStr characterAtIndex:i]; 2225 [result appendFormat:@"%c", tolower((char)c)]; 2226 ++i; 2227 --segmentLen; 2228 } 2229 // else op == kOpAsIs || op == kOpAllUpper 2230 2231 // Now pull over the rest of the length for this segment. 2232 for (int x = 0; x < segmentLen; ++x) { 2233 unichar c = [inputStr characterAtIndex:(i + x)]; 2234 if (decodeOp == kOpAllUpper) { 2235 [result appendFormat:@"%c", toupper((char)c)]; 2236 } else { 2237 [result appendFormat:@"%C", c]; 2238 } 2239 } 2240 i += segmentLen; 2241 } 2242 2243 return result; 2244} 2245 2246#pragma mark Legacy methods old generated code calls 2247 2248// Shim from the older generated code into the runtime. 2249void GPBSetInt32IvarWithFieldInternal(GPBMessage *self, GPBFieldDescriptor *field, int32_t value, 2250 __unused GPBFileSyntax syntax) { 2251 GPBSetMessageInt32Field(self, field, value); 2252} 2253 2254void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, int32_t oneofHasIndex, 2255 __unused uint32_t fieldNumberNotToClear) { 2256#if defined(DEBUG) && DEBUG 2257 NSCAssert([[self descriptor] oneofWithName:oneof.name] == oneof, 2258 @"OneofDescriptor %@ doesn't appear to be for %@ messages.", oneof.name, [self class]); 2259 GPBFieldDescriptor *firstField __unused = oneof->fields_[0]; 2260 NSCAssert(firstField->description_->hasIndex == oneofHasIndex, 2261 @"Internal error, oneofHasIndex (%d) doesn't match (%d).", 2262 firstField->description_->hasIndex, oneofHasIndex); 2263#endif 2264 GPBMaybeClearOneofPrivate(self, oneof, oneofHasIndex, 0); 2265} 2266 2267#pragma clang diagnostic pop 2268 2269#pragma mark Misc Helpers 2270 2271BOOL GPBClassHasSel(Class aClass, SEL sel) { 2272 // NOTE: We have to use class_copyMethodList, all other runtime method 2273 // lookups actually also resolve the method implementation and this 2274 // is called from within those methods. 2275 2276 BOOL result = NO; 2277 unsigned int methodCount = 0; 2278 Method *methodList = class_copyMethodList(aClass, &methodCount); 2279 for (unsigned int i = 0; i < methodCount; ++i) { 2280 SEL methodSelector = method_getName(methodList[i]); 2281 if (methodSelector == sel) { 2282 result = YES; 2283 break; 2284 } 2285 } 2286 free(methodList); 2287 return result; 2288} 2289