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