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 static void AppendTextFormatForMessage(GPBMessage *message, 43 NSMutableString *toStr, 44 NSString *lineIndent); 45 46 NSData *GPBEmptyNSData(void) { 47 static dispatch_once_t onceToken; 48 static NSData *defaultNSData = nil; 49 dispatch_once(&onceToken, ^{ 50 defaultNSData = [[NSData alloc] init]; 51 }); 52 return defaultNSData; 53 } 54 55 void GPBCheckRuntimeVersionInternal(int32_t version) { 56 if (version != GOOGLE_PROTOBUF_OBJC_GEN_VERSION) { 57 [NSException raise:NSInternalInconsistencyException 58 format:@"Linked to ProtocolBuffer runtime version %d," 59 @" but code compiled with version %d!", 60 GOOGLE_PROTOBUF_OBJC_GEN_VERSION, version]; 61 } 62 } 63 64 BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber) { 65 GPBDescriptor *descriptor = [self descriptor]; 66 GPBFieldDescriptor *field = [descriptor fieldWithNumber:fieldNumber]; 67 return GPBMessageHasFieldSet(self, field); 68 } 69 70 BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field) { 71 if (self == nil || field == nil) return NO; 72 73 // Repeated/Map don't use the bit, they check the count. 74 if (GPBFieldIsMapOrArray(field)) { 75 // Array/map type doesn't matter, since GPB*Array/NSArray and 76 // GPB*Dictionary/NSDictionary all support -count; 77 NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field); 78 return (arrayOrMap.count > 0); 79 } else { 80 return GPBGetHasIvarField(self, field); 81 } 82 } 83 84 void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field) { 85 // If not set, nothing to do. 86 if (!GPBGetHasIvarField(self, field)) { 87 return; 88 } 89 90 if (GPBFieldStoresObject(field)) { 91 // Object types are handled slightly differently, they need to be released. 92 uint8_t *storage = (uint8_t *)self->messageStorage_; 93 id *typePtr = (id *)&storage[field->description_->offset]; 94 [*typePtr release]; 95 *typePtr = nil; 96 } else { 97 // POD types just need to clear the has bit as the Get* method will 98 // fetch the default when needed. 99 } 100 GPBSetHasIvarField(self, field, NO); 101 } 102 103 BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) { 104 NSCAssert(self->messageStorage_ != NULL, 105 @"%@: All messages should have storage (from init)", 106 [self class]); 107 if (idx < 0) { 108 NSCAssert(fieldNumber != 0, @"Invalid field number."); 109 BOOL hasIvar = (self->messageStorage_->_has_storage_[-idx] == fieldNumber); 110 return hasIvar; 111 } else { 112 NSCAssert(idx != GPBNoHasBit, @"Invalid has bit."); 113 uint32_t byteIndex = idx / 32; 114 uint32_t bitMask = (1 << (idx % 32)); 115 BOOL hasIvar = 116 (self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO; 117 return hasIvar; 118 } 119 } 120 121 uint32_t GPBGetHasOneof(GPBMessage *self, int32_t idx) { 122 NSCAssert(idx < 0, @"%@: invalid index (%d) for oneof.", 123 [self class], idx); 124 uint32_t result = self->messageStorage_->_has_storage_[-idx]; 125 return result; 126 } 127 128 void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber, 129 BOOL value) { 130 if (idx < 0) { 131 NSCAssert(fieldNumber != 0, @"Invalid field number."); 132 uint32_t *has_storage = self->messageStorage_->_has_storage_; 133 has_storage[-idx] = (value ? fieldNumber : 0); 134 } else { 135 NSCAssert(idx != GPBNoHasBit, @"Invalid has bit."); 136 uint32_t *has_storage = self->messageStorage_->_has_storage_; 137 uint32_t byte = idx / 32; 138 uint32_t bitMask = (1 << (idx % 32)); 139 if (value) { 140 has_storage[byte] |= bitMask; 141 } else { 142 has_storage[byte] &= ~bitMask; 143 } 144 } 145 } 146 147 void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, 148 int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) { 149 uint32_t fieldNumberSet = GPBGetHasOneof(self, oneofHasIndex); 150 if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) { 151 // Do nothing/nothing set in the oneof. 152 return; 153 } 154 155 // Like GPBClearMessageField(), free the memory if an objecttype is set, 156 // pod types don't need to do anything. 157 GPBFieldDescriptor *fieldSet = [oneof fieldWithNumber:fieldNumberSet]; 158 NSCAssert(fieldSet, 159 @"%@: oneof set to something (%u) not in the oneof?", 160 [self class], fieldNumberSet); 161 if (fieldSet && GPBFieldStoresObject(fieldSet)) { 162 uint8_t *storage = (uint8_t *)self->messageStorage_; 163 id *typePtr = (id *)&storage[fieldSet->description_->offset]; 164 [*typePtr release]; 165 *typePtr = nil; 166 } 167 168 // Set to nothing stored in the oneof. 169 // (field number doesn't matter since setting to nothing). 170 GPBSetHasIvar(self, oneofHasIndex, 1, NO); 171 } 172 173 #pragma mark - IVar accessors 174 175 //%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE) 176 //%TYPE GPBGetMessage##NAME##Field(GPBMessage *self, 177 //% TYPE$S NAME$S GPBFieldDescriptor *field) { 178 //% if (GPBGetHasIvarField(self, field)) { 179 //% uint8_t *storage = (uint8_t *)self->messageStorage_; 180 //% TYPE *typePtr = (TYPE *)&storage[field->description_->offset]; 181 //% return *typePtr; 182 //% } else { 183 //% return field.defaultValue.value##NAME; 184 //% } 185 //%} 186 //% 187 //%// Only exists for public api, no core code should use this. 188 //%void GPBSetMessage##NAME##Field(GPBMessage *self, 189 //% NAME$S GPBFieldDescriptor *field, 190 //% NAME$S TYPE value) { 191 //% if (self == nil || field == nil) return; 192 //% GPBFileSyntax syntax = [self descriptor].file.syntax; 193 //% GPBSet##NAME##IvarWithFieldInternal(self, field, value, syntax); 194 //%} 195 //% 196 //%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self, 197 //% NAME$S GPBFieldDescriptor *field, 198 //% NAME$S TYPE value, 199 //% NAME$S GPBFileSyntax syntax) { 200 //% GPBOneofDescriptor *oneof = field->containingOneof_; 201 //% if (oneof) { 202 //% GPBMessageFieldDescription *fieldDesc = field->description_; 203 //% GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 204 //% } 205 //% NSCAssert(self->messageStorage_ != NULL, 206 //% @"%@: All messages should have storage (from init)", 207 //% [self class]); 208 //%#if defined(__clang_analyzer__) 209 //% if (self->messageStorage_ == NULL) return; 210 //%#endif 211 //% uint8_t *storage = (uint8_t *)self->messageStorage_; 212 //% TYPE *typePtr = (TYPE *)&storage[field->description_->offset]; 213 //% *typePtr = value; 214 //% // proto2: any value counts as having been set; proto3, it 215 //% // has to be a non zero value. 216 //% BOOL hasValue = 217 //% (syntax == GPBFileSyntaxProto2) || (value != (TYPE)0); 218 //% GPBSetHasIvarField(self, field, hasValue); 219 //% GPBBecomeVisibleToAutocreator(self); 220 //%} 221 //% 222 //%PDDM-DEFINE IVAR_ALIAS_DEFN_OBJECT(NAME, TYPE) 223 //%// Only exists for public api, no core code should use this. 224 //%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self, 225 //% TYPE$S NAME$S GPBFieldDescriptor *field) { 226 //% return (TYPE *)GPBGetObjectIvarWithField(self, field); 227 //%} 228 //% 229 //%// Only exists for public api, no core code should use this. 230 //%void GPBSetMessage##NAME##Field(GPBMessage *self, 231 //% NAME$S GPBFieldDescriptor *field, 232 //% NAME$S TYPE *value) { 233 //% GPBSetObjectIvarWithField(self, field, (id)value); 234 //%} 235 //% 236 237 // Object types are handled slightly differently, they need to be released 238 // and retained. 239 240 void GPBSetAutocreatedRetainedObjectIvarWithField( 241 GPBMessage *self, GPBFieldDescriptor *field, 242 id __attribute__((ns_consumed)) value) { 243 uint8_t *storage = (uint8_t *)self->messageStorage_; 244 id *typePtr = (id *)&storage[field->description_->offset]; 245 NSCAssert(*typePtr == NULL, @"Can't set autocreated object more than once."); 246 *typePtr = value; 247 } 248 249 void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self, 250 GPBFieldDescriptor *field) { 251 if (GPBGetHasIvarField(self, field)) { 252 return; 253 } 254 uint8_t *storage = (uint8_t *)self->messageStorage_; 255 id *typePtr = (id *)&storage[field->description_->offset]; 256 GPBMessage *oldValue = *typePtr; 257 *typePtr = NULL; 258 GPBClearMessageAutocreator(oldValue); 259 [oldValue release]; 260 } 261 262 // This exists only for briging some aliased types, nothing else should use it. 263 static void GPBSetObjectIvarWithField(GPBMessage *self, 264 GPBFieldDescriptor *field, id value) { 265 if (self == nil || field == nil) return; 266 GPBFileSyntax syntax = [self descriptor].file.syntax; 267 GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain], 268 syntax); 269 } 270 271 void GPBSetObjectIvarWithFieldInternal(GPBMessage *self, 272 GPBFieldDescriptor *field, id value, 273 GPBFileSyntax syntax) { 274 GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain], 275 syntax); 276 } 277 278 void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self, 279 GPBFieldDescriptor *field, 280 id value, GPBFileSyntax syntax) { 281 NSCAssert(self->messageStorage_ != NULL, 282 @"%@: All messages should have storage (from init)", 283 [self class]); 284 #if defined(__clang_analyzer__) 285 if (self->messageStorage_ == NULL) return; 286 #endif 287 GPBDataType fieldType = GPBGetFieldDataType(field); 288 BOOL isMapOrArray = GPBFieldIsMapOrArray(field); 289 BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType); 290 #ifdef DEBUG 291 if (value == nil && !isMapOrArray && !fieldIsMessage && 292 field.hasDefaultValue) { 293 // Setting a message to nil is an obvious way to "clear" the value 294 // as there is no way to set a non-empty default value for messages. 295 // 296 // For Strings and Bytes that have default values set it is not clear what 297 // should be done when their value is set to nil. Is the intention just to 298 // clear the set value and reset to default, or is the intention to set the 299 // value to the empty string/data? Arguments can be made for both cases. 300 // 'nil' has been abused as a replacement for an empty string/data in ObjC. 301 // We decided to be consistent with all "object" types and clear the has 302 // field, and fall back on the default value. The warning below will only 303 // appear in debug, but the could should be changed so the intention is 304 // clear. 305 NSString *hasSel = NSStringFromSelector(field->hasOrCountSel_); 306 NSString *propName = field.name; 307 NSString *className = self.descriptor.name; 308 NSLog(@"warning: '%@.%@ = nil;' is not clearly defined for fields with " 309 @"default values. Please use '%@.%@ = %@' if you want to set it to " 310 @"empty, or call '%@.%@ = NO' to reset it to it's default value of " 311 @"'%@'. Defaulting to resetting default value.", 312 className, propName, className, propName, 313 (fieldType == GPBDataTypeString) ? @"@\"\"" : @"GPBEmptyNSData()", 314 className, hasSel, field.defaultValue.valueString); 315 // Note: valueString, depending on the type, it could easily be 316 // valueData/valueMessage. 317 } 318 #endif // DEBUG 319 if (!isMapOrArray) { 320 // Non repeated/map can be in an oneof, clear any existing value from the 321 // oneof. 322 GPBOneofDescriptor *oneof = field->containingOneof_; 323 if (oneof) { 324 GPBMessageFieldDescription *fieldDesc = field->description_; 325 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 326 } 327 // Clear "has" if they are being set to nil. 328 BOOL setHasValue = (value != nil); 329 // Under proto3, Bytes & String fields get cleared by resetting them to 330 // their default (empty) values, so if they are set to something of length 331 // zero, they are being cleared. 332 if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage && 333 ([value length] == 0)) { 334 setHasValue = NO; 335 value = nil; 336 } 337 GPBSetHasIvarField(self, field, setHasValue); 338 } 339 uint8_t *storage = (uint8_t *)self->messageStorage_; 340 id *typePtr = (id *)&storage[field->description_->offset]; 341 342 id oldValue = *typePtr; 343 344 *typePtr = value; 345 346 if (oldValue) { 347 if (isMapOrArray) { 348 if (field.fieldType == GPBFieldTypeRepeated) { 349 // If the old array was autocreated by us, then clear it. 350 if (GPBDataTypeIsObject(fieldType)) { 351 GPBAutocreatedArray *autoArray = oldValue; 352 if (autoArray->_autocreator == self) { 353 autoArray->_autocreator = nil; 354 } 355 } else { 356 // Type doesn't matter, it is a GPB*Array. 357 GPBInt32Array *gpbArray = oldValue; 358 if (gpbArray->_autocreator == self) { 359 gpbArray->_autocreator = nil; 360 } 361 } 362 } else { // GPBFieldTypeMap 363 // If the old map was autocreated by us, then clear it. 364 if ((field.mapKeyDataType == GPBDataTypeString) && 365 GPBDataTypeIsObject(fieldType)) { 366 GPBAutocreatedDictionary *autoDict = oldValue; 367 if (autoDict->_autocreator == self) { 368 autoDict->_autocreator = nil; 369 } 370 } else { 371 // Type doesn't matter, it is a GPB*Dictionary. 372 GPBInt32Int32Dictionary *gpbDict = oldValue; 373 if (gpbDict->_autocreator == self) { 374 gpbDict->_autocreator = nil; 375 } 376 } 377 } 378 } else if (fieldIsMessage) { 379 // If the old message value was autocreated by us, then clear it. 380 GPBMessage *oldMessageValue = oldValue; 381 if (GPBWasMessageAutocreatedBy(oldMessageValue, self)) { 382 GPBClearMessageAutocreator(oldMessageValue); 383 } 384 } 385 [oldValue release]; 386 } 387 388 GPBBecomeVisibleToAutocreator(self); 389 } 390 391 id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self, 392 GPBFieldDescriptor *field) { 393 if (self->messageStorage_ == nil) { 394 return nil; 395 } 396 uint8_t *storage = (uint8_t *)self->messageStorage_; 397 id *typePtr = (id *)&storage[field->description_->offset]; 398 return *typePtr; 399 } 400 401 id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { 402 NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here"); 403 if (GPBGetHasIvarField(self, field)) { 404 uint8_t *storage = (uint8_t *)self->messageStorage_; 405 id *typePtr = (id *)&storage[field->description_->offset]; 406 return *typePtr; 407 } 408 // Not set... 409 410 // Non messages (string/data), get their default. 411 if (!GPBFieldDataTypeIsMessage(field)) { 412 return field.defaultValue.valueMessage; 413 } 414 415 GPBPrepareReadOnlySemaphore(self); 416 dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); 417 GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field); 418 if (!result) { 419 // For non repeated messages, create the object, set it and return it. 420 // This object will not initially be visible via GPBGetHasIvar, so 421 // we save its creator so it can become visible if it's mutated later. 422 result = GPBCreateMessageWithAutocreator(field.msgClass, self, field); 423 GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result); 424 } 425 dispatch_semaphore_signal(self->readOnlySemaphore_); 426 return result; 427 } 428 429 // Only exists for public api, no core code should use this. 430 int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) { 431 GPBFileSyntax syntax = [self descriptor].file.syntax; 432 return GPBGetEnumIvarWithFieldInternal(self, field, syntax); 433 } 434 435 int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self, 436 GPBFieldDescriptor *field, 437 GPBFileSyntax syntax) { 438 int32_t result = GPBGetMessageInt32Field(self, field); 439 // If this is presevering unknown enums, make sure the value is valid before 440 // returning it. 441 if (GPBHasPreservingUnknownEnumSemantics(syntax) && 442 ![field isValidEnumValue:result]) { 443 result = kGPBUnrecognizedEnumeratorValue; 444 } 445 return result; 446 } 447 448 // Only exists for public api, no core code should use this. 449 void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field, 450 int32_t value) { 451 GPBFileSyntax syntax = [self descriptor].file.syntax; 452 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax); 453 } 454 455 void GPBSetEnumIvarWithFieldInternal(GPBMessage *self, 456 GPBFieldDescriptor *field, int32_t value, 457 GPBFileSyntax syntax) { 458 // Don't allow in unknown values. Proto3 can use the Raw method. 459 if (![field isValidEnumValue:value]) { 460 [NSException raise:NSInvalidArgumentException 461 format:@"%@.%@: Attempt to set an unknown enum value (%d)", 462 [self class], field.name, value]; 463 } 464 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax); 465 } 466 467 // Only exists for public api, no core code should use this. 468 int32_t GPBGetMessageRawEnumField(GPBMessage *self, 469 GPBFieldDescriptor *field) { 470 int32_t result = GPBGetMessageInt32Field(self, field); 471 return result; 472 } 473 474 // Only exists for public api, no core code should use this. 475 void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, 476 int32_t value) { 477 GPBFileSyntax syntax = [self descriptor].file.syntax; 478 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax); 479 } 480 481 BOOL GPBGetMessageBoolField(GPBMessage *self, 482 GPBFieldDescriptor *field) { 483 if (GPBGetHasIvarField(self, field)) { 484 // Bools are stored in the has bits to avoid needing explicit space in the 485 // storage structure. 486 // (the field number passed to the HasIvar helper doesn't really matter 487 // since the offset is never negative) 488 GPBMessageFieldDescription *fieldDesc = field->description_; 489 return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number); 490 } else { 491 return field.defaultValue.valueBool; 492 } 493 } 494 495 // Only exists for public api, no core code should use this. 496 void GPBSetMessageBoolField(GPBMessage *self, 497 GPBFieldDescriptor *field, 498 BOOL value) { 499 if (self == nil || field == nil) return; 500 GPBFileSyntax syntax = [self descriptor].file.syntax; 501 GPBSetBoolIvarWithFieldInternal(self, field, value, syntax); 502 } 503 504 void GPBSetBoolIvarWithFieldInternal(GPBMessage *self, 505 GPBFieldDescriptor *field, 506 BOOL value, 507 GPBFileSyntax syntax) { 508 GPBMessageFieldDescription *fieldDesc = field->description_; 509 GPBOneofDescriptor *oneof = field->containingOneof_; 510 if (oneof) { 511 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 512 } 513 514 // Bools are stored in the has bits to avoid needing explicit space in the 515 // storage structure. 516 // (the field number passed to the HasIvar helper doesn't really matter since 517 // the offset is never negative) 518 GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value); 519 520 // proto2: any value counts as having been set; proto3, it 521 // has to be a non zero value. 522 BOOL hasValue = 523 (syntax == GPBFileSyntaxProto2) || (value != (BOOL)0); 524 GPBSetHasIvarField(self, field, hasValue); 525 GPBBecomeVisibleToAutocreator(self); 526 } 527 528 //%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int32, int32_t) 529 // This block of code is generated, do not edit it directly. 530 531 int32_t GPBGetMessageInt32Field(GPBMessage *self, 532 GPBFieldDescriptor *field) { 533 if (GPBGetHasIvarField(self, field)) { 534 uint8_t *storage = (uint8_t *)self->messageStorage_; 535 int32_t *typePtr = (int32_t *)&storage[field->description_->offset]; 536 return *typePtr; 537 } else { 538 return field.defaultValue.valueInt32; 539 } 540 } 541 542 // Only exists for public api, no core code should use this. 543 void GPBSetMessageInt32Field(GPBMessage *self, 544 GPBFieldDescriptor *field, 545 int32_t value) { 546 if (self == nil || field == nil) return; 547 GPBFileSyntax syntax = [self descriptor].file.syntax; 548 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax); 549 } 550 551 void GPBSetInt32IvarWithFieldInternal(GPBMessage *self, 552 GPBFieldDescriptor *field, 553 int32_t value, 554 GPBFileSyntax syntax) { 555 GPBOneofDescriptor *oneof = field->containingOneof_; 556 if (oneof) { 557 GPBMessageFieldDescription *fieldDesc = field->description_; 558 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 559 } 560 NSCAssert(self->messageStorage_ != NULL, 561 @"%@: All messages should have storage (from init)", 562 [self class]); 563 #if defined(__clang_analyzer__) 564 if (self->messageStorage_ == NULL) return; 565 #endif 566 uint8_t *storage = (uint8_t *)self->messageStorage_; 567 int32_t *typePtr = (int32_t *)&storage[field->description_->offset]; 568 *typePtr = value; 569 // proto2: any value counts as having been set; proto3, it 570 // has to be a non zero value. 571 BOOL hasValue = 572 (syntax == GPBFileSyntaxProto2) || (value != (int32_t)0); 573 GPBSetHasIvarField(self, field, hasValue); 574 GPBBecomeVisibleToAutocreator(self); 575 } 576 577 //%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt32, uint32_t) 578 // This block of code is generated, do not edit it directly. 579 580 uint32_t GPBGetMessageUInt32Field(GPBMessage *self, 581 GPBFieldDescriptor *field) { 582 if (GPBGetHasIvarField(self, field)) { 583 uint8_t *storage = (uint8_t *)self->messageStorage_; 584 uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset]; 585 return *typePtr; 586 } else { 587 return field.defaultValue.valueUInt32; 588 } 589 } 590 591 // Only exists for public api, no core code should use this. 592 void GPBSetMessageUInt32Field(GPBMessage *self, 593 GPBFieldDescriptor *field, 594 uint32_t value) { 595 if (self == nil || field == nil) return; 596 GPBFileSyntax syntax = [self descriptor].file.syntax; 597 GPBSetUInt32IvarWithFieldInternal(self, field, value, syntax); 598 } 599 600 void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self, 601 GPBFieldDescriptor *field, 602 uint32_t value, 603 GPBFileSyntax syntax) { 604 GPBOneofDescriptor *oneof = field->containingOneof_; 605 if (oneof) { 606 GPBMessageFieldDescription *fieldDesc = field->description_; 607 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 608 } 609 NSCAssert(self->messageStorage_ != NULL, 610 @"%@: All messages should have storage (from init)", 611 [self class]); 612 #if defined(__clang_analyzer__) 613 if (self->messageStorage_ == NULL) return; 614 #endif 615 uint8_t *storage = (uint8_t *)self->messageStorage_; 616 uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset]; 617 *typePtr = value; 618 // proto2: any value counts as having been set; proto3, it 619 // has to be a non zero value. 620 BOOL hasValue = 621 (syntax == GPBFileSyntaxProto2) || (value != (uint32_t)0); 622 GPBSetHasIvarField(self, field, hasValue); 623 GPBBecomeVisibleToAutocreator(self); 624 } 625 626 //%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int64, int64_t) 627 // This block of code is generated, do not edit it directly. 628 629 int64_t GPBGetMessageInt64Field(GPBMessage *self, 630 GPBFieldDescriptor *field) { 631 if (GPBGetHasIvarField(self, field)) { 632 uint8_t *storage = (uint8_t *)self->messageStorage_; 633 int64_t *typePtr = (int64_t *)&storage[field->description_->offset]; 634 return *typePtr; 635 } else { 636 return field.defaultValue.valueInt64; 637 } 638 } 639 640 // Only exists for public api, no core code should use this. 641 void GPBSetMessageInt64Field(GPBMessage *self, 642 GPBFieldDescriptor *field, 643 int64_t value) { 644 if (self == nil || field == nil) return; 645 GPBFileSyntax syntax = [self descriptor].file.syntax; 646 GPBSetInt64IvarWithFieldInternal(self, field, value, syntax); 647 } 648 649 void GPBSetInt64IvarWithFieldInternal(GPBMessage *self, 650 GPBFieldDescriptor *field, 651 int64_t value, 652 GPBFileSyntax syntax) { 653 GPBOneofDescriptor *oneof = field->containingOneof_; 654 if (oneof) { 655 GPBMessageFieldDescription *fieldDesc = field->description_; 656 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 657 } 658 NSCAssert(self->messageStorage_ != NULL, 659 @"%@: All messages should have storage (from init)", 660 [self class]); 661 #if defined(__clang_analyzer__) 662 if (self->messageStorage_ == NULL) return; 663 #endif 664 uint8_t *storage = (uint8_t *)self->messageStorage_; 665 int64_t *typePtr = (int64_t *)&storage[field->description_->offset]; 666 *typePtr = value; 667 // proto2: any value counts as having been set; proto3, it 668 // has to be a non zero value. 669 BOOL hasValue = 670 (syntax == GPBFileSyntaxProto2) || (value != (int64_t)0); 671 GPBSetHasIvarField(self, field, hasValue); 672 GPBBecomeVisibleToAutocreator(self); 673 } 674 675 //%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt64, uint64_t) 676 // This block of code is generated, do not edit it directly. 677 678 uint64_t GPBGetMessageUInt64Field(GPBMessage *self, 679 GPBFieldDescriptor *field) { 680 if (GPBGetHasIvarField(self, field)) { 681 uint8_t *storage = (uint8_t *)self->messageStorage_; 682 uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset]; 683 return *typePtr; 684 } else { 685 return field.defaultValue.valueUInt64; 686 } 687 } 688 689 // Only exists for public api, no core code should use this. 690 void GPBSetMessageUInt64Field(GPBMessage *self, 691 GPBFieldDescriptor *field, 692 uint64_t value) { 693 if (self == nil || field == nil) return; 694 GPBFileSyntax syntax = [self descriptor].file.syntax; 695 GPBSetUInt64IvarWithFieldInternal(self, field, value, syntax); 696 } 697 698 void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self, 699 GPBFieldDescriptor *field, 700 uint64_t value, 701 GPBFileSyntax syntax) { 702 GPBOneofDescriptor *oneof = field->containingOneof_; 703 if (oneof) { 704 GPBMessageFieldDescription *fieldDesc = field->description_; 705 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 706 } 707 NSCAssert(self->messageStorage_ != NULL, 708 @"%@: All messages should have storage (from init)", 709 [self class]); 710 #if defined(__clang_analyzer__) 711 if (self->messageStorage_ == NULL) return; 712 #endif 713 uint8_t *storage = (uint8_t *)self->messageStorage_; 714 uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset]; 715 *typePtr = value; 716 // proto2: any value counts as having been set; proto3, it 717 // has to be a non zero value. 718 BOOL hasValue = 719 (syntax == GPBFileSyntaxProto2) || (value != (uint64_t)0); 720 GPBSetHasIvarField(self, field, hasValue); 721 GPBBecomeVisibleToAutocreator(self); 722 } 723 724 //%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Float, float) 725 // This block of code is generated, do not edit it directly. 726 727 float GPBGetMessageFloatField(GPBMessage *self, 728 GPBFieldDescriptor *field) { 729 if (GPBGetHasIvarField(self, field)) { 730 uint8_t *storage = (uint8_t *)self->messageStorage_; 731 float *typePtr = (float *)&storage[field->description_->offset]; 732 return *typePtr; 733 } else { 734 return field.defaultValue.valueFloat; 735 } 736 } 737 738 // Only exists for public api, no core code should use this. 739 void GPBSetMessageFloatField(GPBMessage *self, 740 GPBFieldDescriptor *field, 741 float value) { 742 if (self == nil || field == nil) return; 743 GPBFileSyntax syntax = [self descriptor].file.syntax; 744 GPBSetFloatIvarWithFieldInternal(self, field, value, syntax); 745 } 746 747 void GPBSetFloatIvarWithFieldInternal(GPBMessage *self, 748 GPBFieldDescriptor *field, 749 float value, 750 GPBFileSyntax syntax) { 751 GPBOneofDescriptor *oneof = field->containingOneof_; 752 if (oneof) { 753 GPBMessageFieldDescription *fieldDesc = field->description_; 754 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 755 } 756 NSCAssert(self->messageStorage_ != NULL, 757 @"%@: All messages should have storage (from init)", 758 [self class]); 759 #if defined(__clang_analyzer__) 760 if (self->messageStorage_ == NULL) return; 761 #endif 762 uint8_t *storage = (uint8_t *)self->messageStorage_; 763 float *typePtr = (float *)&storage[field->description_->offset]; 764 *typePtr = value; 765 // proto2: any value counts as having been set; proto3, it 766 // has to be a non zero value. 767 BOOL hasValue = 768 (syntax == GPBFileSyntaxProto2) || (value != (float)0); 769 GPBSetHasIvarField(self, field, hasValue); 770 GPBBecomeVisibleToAutocreator(self); 771 } 772 773 //%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Double, double) 774 // This block of code is generated, do not edit it directly. 775 776 double GPBGetMessageDoubleField(GPBMessage *self, 777 GPBFieldDescriptor *field) { 778 if (GPBGetHasIvarField(self, field)) { 779 uint8_t *storage = (uint8_t *)self->messageStorage_; 780 double *typePtr = (double *)&storage[field->description_->offset]; 781 return *typePtr; 782 } else { 783 return field.defaultValue.valueDouble; 784 } 785 } 786 787 // Only exists for public api, no core code should use this. 788 void GPBSetMessageDoubleField(GPBMessage *self, 789 GPBFieldDescriptor *field, 790 double value) { 791 if (self == nil || field == nil) return; 792 GPBFileSyntax syntax = [self descriptor].file.syntax; 793 GPBSetDoubleIvarWithFieldInternal(self, field, value, syntax); 794 } 795 796 void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self, 797 GPBFieldDescriptor *field, 798 double value, 799 GPBFileSyntax syntax) { 800 GPBOneofDescriptor *oneof = field->containingOneof_; 801 if (oneof) { 802 GPBMessageFieldDescription *fieldDesc = field->description_; 803 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); 804 } 805 NSCAssert(self->messageStorage_ != NULL, 806 @"%@: All messages should have storage (from init)", 807 [self class]); 808 #if defined(__clang_analyzer__) 809 if (self->messageStorage_ == NULL) return; 810 #endif 811 uint8_t *storage = (uint8_t *)self->messageStorage_; 812 double *typePtr = (double *)&storage[field->description_->offset]; 813 *typePtr = value; 814 // proto2: any value counts as having been set; proto3, it 815 // has to be a non zero value. 816 BOOL hasValue = 817 (syntax == GPBFileSyntaxProto2) || (value != (double)0); 818 GPBSetHasIvarField(self, field, hasValue); 819 GPBBecomeVisibleToAutocreator(self); 820 } 821 822 //%PDDM-EXPAND-END (6 expansions) 823 824 // Aliases are function calls that are virtually the same. 825 826 //%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(String, NSString) 827 // This block of code is generated, do not edit it directly. 828 829 // Only exists for public api, no core code should use this. 830 NSString *GPBGetMessageStringField(GPBMessage *self, 831 GPBFieldDescriptor *field) { 832 return (NSString *)GPBGetObjectIvarWithField(self, field); 833 } 834 835 // Only exists for public api, no core code should use this. 836 void GPBSetMessageStringField(GPBMessage *self, 837 GPBFieldDescriptor *field, 838 NSString *value) { 839 GPBSetObjectIvarWithField(self, field, (id)value); 840 } 841 842 //%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Bytes, NSData) 843 // This block of code is generated, do not edit it directly. 844 845 // Only exists for public api, no core code should use this. 846 NSData *GPBGetMessageBytesField(GPBMessage *self, 847 GPBFieldDescriptor *field) { 848 return (NSData *)GPBGetObjectIvarWithField(self, field); 849 } 850 851 // Only exists for public api, no core code should use this. 852 void GPBSetMessageBytesField(GPBMessage *self, 853 GPBFieldDescriptor *field, 854 NSData *value) { 855 GPBSetObjectIvarWithField(self, field, (id)value); 856 } 857 858 //%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Message, GPBMessage) 859 // This block of code is generated, do not edit it directly. 860 861 // Only exists for public api, no core code should use this. 862 GPBMessage *GPBGetMessageMessageField(GPBMessage *self, 863 GPBFieldDescriptor *field) { 864 return (GPBMessage *)GPBGetObjectIvarWithField(self, field); 865 } 866 867 // Only exists for public api, no core code should use this. 868 void GPBSetMessageMessageField(GPBMessage *self, 869 GPBFieldDescriptor *field, 870 GPBMessage *value) { 871 GPBSetObjectIvarWithField(self, field, (id)value); 872 } 873 874 //%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Group, GPBMessage) 875 // This block of code is generated, do not edit it directly. 876 877 // Only exists for public api, no core code should use this. 878 GPBMessage *GPBGetMessageGroupField(GPBMessage *self, 879 GPBFieldDescriptor *field) { 880 return (GPBMessage *)GPBGetObjectIvarWithField(self, field); 881 } 882 883 // Only exists for public api, no core code should use this. 884 void GPBSetMessageGroupField(GPBMessage *self, 885 GPBFieldDescriptor *field, 886 GPBMessage *value) { 887 GPBSetObjectIvarWithField(self, field, (id)value); 888 } 889 890 //%PDDM-EXPAND-END (4 expansions) 891 892 // Only exists for public api, no core code should use this. 893 id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field) { 894 #if DEBUG 895 if (field.fieldType != GPBFieldTypeRepeated) { 896 [NSException raise:NSInvalidArgumentException 897 format:@"%@.%@ is not a repeated field.", 898 [self class], field.name]; 899 } 900 #endif 901 return GPBGetObjectIvarWithField(self, field); 902 } 903 904 // Only exists for public api, no core code should use this. 905 void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) { 906 #if DEBUG 907 if (field.fieldType != GPBFieldTypeRepeated) { 908 [NSException raise:NSInvalidArgumentException 909 format:@"%@.%@ is not a repeated field.", 910 [self class], field.name]; 911 } 912 Class expectedClass = Nil; 913 switch (GPBGetFieldDataType(field)) { 914 case GPBDataTypeBool: 915 expectedClass = [GPBBoolArray class]; 916 break; 917 case GPBDataTypeSFixed32: 918 case GPBDataTypeInt32: 919 case GPBDataTypeSInt32: 920 expectedClass = [GPBInt32Array class]; 921 break; 922 case GPBDataTypeFixed32: 923 case GPBDataTypeUInt32: 924 expectedClass = [GPBUInt32Array class]; 925 break; 926 case GPBDataTypeSFixed64: 927 case GPBDataTypeInt64: 928 case GPBDataTypeSInt64: 929 expectedClass = [GPBInt64Array class]; 930 break; 931 case GPBDataTypeFixed64: 932 case GPBDataTypeUInt64: 933 expectedClass = [GPBUInt64Array class]; 934 break; 935 case GPBDataTypeFloat: 936 expectedClass = [GPBFloatArray class]; 937 break; 938 case GPBDataTypeDouble: 939 expectedClass = [GPBDoubleArray class]; 940 break; 941 case GPBDataTypeBytes: 942 case GPBDataTypeString: 943 case GPBDataTypeMessage: 944 case GPBDataTypeGroup: 945 expectedClass = [NSMutableDictionary class]; 946 break; 947 case GPBDataTypeEnum: 948 expectedClass = [GPBBoolArray class]; 949 break; 950 } 951 if (array && ![array isKindOfClass:expectedClass]) { 952 [NSException raise:NSInvalidArgumentException 953 format:@"%@.%@: Expected %@ object, got %@.", 954 [self class], field.name, expectedClass, [array class]]; 955 } 956 #endif 957 GPBSetObjectIvarWithField(self, field, array); 958 } 959 960 #if DEBUG 961 static NSString *TypeToStr(GPBDataType dataType) { 962 switch (dataType) { 963 case GPBDataTypeBool: 964 return @"Bool"; 965 case GPBDataTypeSFixed32: 966 case GPBDataTypeInt32: 967 case GPBDataTypeSInt32: 968 return @"Int32"; 969 case GPBDataTypeFixed32: 970 case GPBDataTypeUInt32: 971 return @"UInt32"; 972 case GPBDataTypeSFixed64: 973 case GPBDataTypeInt64: 974 case GPBDataTypeSInt64: 975 return @"Int64"; 976 case GPBDataTypeFixed64: 977 case GPBDataTypeUInt64: 978 return @"UInt64"; 979 case GPBDataTypeFloat: 980 return @"Float"; 981 case GPBDataTypeDouble: 982 return @"Double"; 983 case GPBDataTypeBytes: 984 case GPBDataTypeString: 985 case GPBDataTypeMessage: 986 case GPBDataTypeGroup: 987 return @"Object"; 988 case GPBDataTypeEnum: 989 return @"Bool"; 990 } 991 } 992 #endif 993 994 // Only exists for public api, no core code should use this. 995 id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) { 996 #if DEBUG 997 if (field.fieldType != GPBFieldTypeMap) { 998 [NSException raise:NSInvalidArgumentException 999 format:@"%@.%@ is not a map<> field.", 1000 [self class], field.name]; 1001 } 1002 #endif 1003 return GPBGetObjectIvarWithField(self, field); 1004 } 1005 1006 // Only exists for public api, no core code should use this. 1007 void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field, 1008 id dictionary) { 1009 #if DEBUG 1010 if (field.fieldType != GPBFieldTypeMap) { 1011 [NSException raise:NSInvalidArgumentException 1012 format:@"%@.%@ is not a map<> field.", 1013 [self class], field.name]; 1014 } 1015 if (dictionary) { 1016 GPBDataType keyDataType = field.mapKeyDataType; 1017 GPBDataType valueDataType = GPBGetFieldDataType(field); 1018 NSString *keyStr = TypeToStr(keyDataType); 1019 NSString *valueStr = TypeToStr(valueDataType); 1020 if (keyDataType == GPBDataTypeString) { 1021 keyStr = @"String"; 1022 } 1023 Class expectedClass = Nil; 1024 if ((keyDataType == GPBDataTypeString) && 1025 GPBDataTypeIsObject(valueDataType)) { 1026 expectedClass = [NSMutableDictionary class]; 1027 } else { 1028 NSString *className = 1029 [NSString stringWithFormat:@"GPB%@%@Dictionary", keyStr, valueStr]; 1030 expectedClass = NSClassFromString(className); 1031 NSCAssert(expectedClass, @"Missing a class (%@)?", expectedClass); 1032 } 1033 if (![dictionary isKindOfClass:expectedClass]) { 1034 [NSException raise:NSInvalidArgumentException 1035 format:@"%@.%@: Expected %@ object, got %@.", 1036 [self class], field.name, expectedClass, 1037 [dictionary class]]; 1038 } 1039 } 1040 #endif 1041 GPBSetObjectIvarWithField(self, field, dictionary); 1042 } 1043 1044 #pragma mark - Misc Dynamic Runtime Utils 1045 1046 const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) { 1047 Protocol *protocol = 1048 objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol)); 1049 struct objc_method_description description = 1050 protocol_getMethodDescription(protocol, selector, NO, instanceSel); 1051 return description.types; 1052 } 1053 1054 #pragma mark - Text Format Support 1055 1056 static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) { 1057 [destStr appendString:@"\""]; 1058 NSUInteger len = [toPrint length]; 1059 for (NSUInteger i = 0; i < len; ++i) { 1060 unichar aChar = [toPrint characterAtIndex:i]; 1061 switch (aChar) { 1062 case '\n': [destStr appendString:@"\\n"]; break; 1063 case '\r': [destStr appendString:@"\\r"]; break; 1064 case '\t': [destStr appendString:@"\\t"]; break; 1065 case '\"': [destStr appendString:@"\\\""]; break; 1066 case '\'': [destStr appendString:@"\\\'"]; break; 1067 case '\\': [destStr appendString:@"\\\\"]; break; 1068 default: 1069 [destStr appendFormat:@"%C", aChar]; 1070 break; 1071 } 1072 } 1073 [destStr appendString:@"\""]; 1074 } 1075 1076 static void AppendBufferAsString(NSData *buffer, NSMutableString *destStr) { 1077 const char *src = (const char *)[buffer bytes]; 1078 size_t srcLen = [buffer length]; 1079 [destStr appendString:@"\""]; 1080 for (const char *srcEnd = src + srcLen; src < srcEnd; src++) { 1081 switch (*src) { 1082 case '\n': [destStr appendString:@"\\n"]; break; 1083 case '\r': [destStr appendString:@"\\r"]; break; 1084 case '\t': [destStr appendString:@"\\t"]; break; 1085 case '\"': [destStr appendString:@"\\\""]; break; 1086 case '\'': [destStr appendString:@"\\\'"]; break; 1087 case '\\': [destStr appendString:@"\\\\"]; break; 1088 default: 1089 if (isprint(*src)) { 1090 [destStr appendFormat:@"%c", *src]; 1091 } else { 1092 // NOTE: doing hex means you have to worry about the letter after 1093 // the hex being another hex char and forcing that to be escaped, so 1094 // use octal to keep it simple. 1095 [destStr appendFormat:@"\\%03o", (uint8_t)(*src)]; 1096 } 1097 break; 1098 } 1099 } 1100 [destStr appendString:@"\""]; 1101 } 1102 1103 static void AppendTextFormatForMapMessageField( 1104 id map, GPBFieldDescriptor *field, NSMutableString *toStr, 1105 NSString *lineIndent, NSString *fieldName, NSString *lineEnding) { 1106 GPBDataType keyDataType = field.mapKeyDataType; 1107 GPBDataType valueDataType = GPBGetFieldDataType(field); 1108 BOOL isMessageValue = GPBDataTypeIsMessage(valueDataType); 1109 1110 NSString *msgStartFirst = 1111 [NSString stringWithFormat:@"%@%@ {%@\n", lineIndent, fieldName, lineEnding]; 1112 NSString *msgStart = 1113 [NSString stringWithFormat:@"%@%@ {\n", lineIndent, fieldName]; 1114 NSString *msgEnd = [NSString stringWithFormat:@"%@}\n", lineIndent]; 1115 1116 NSString *keyLine = [NSString stringWithFormat:@"%@ key: ", lineIndent]; 1117 NSString *valueLine = [NSString stringWithFormat:@"%@ value%s ", lineIndent, 1118 (isMessageValue ? "" : ":")]; 1119 1120 __block BOOL isFirst = YES; 1121 1122 if ((keyDataType == GPBDataTypeString) && 1123 GPBDataTypeIsObject(valueDataType)) { 1124 // map is an NSDictionary. 1125 NSDictionary *dict = map; 1126 [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) { 1127 #pragma unused(stop) 1128 [toStr appendString:(isFirst ? msgStartFirst : msgStart)]; 1129 isFirst = NO; 1130 1131 [toStr appendString:keyLine]; 1132 AppendStringEscaped(key, toStr); 1133 [toStr appendString:@"\n"]; 1134 1135 [toStr appendString:valueLine]; 1136 switch (valueDataType) { 1137 case GPBDataTypeString: 1138 AppendStringEscaped(value, toStr); 1139 break; 1140 1141 case GPBDataTypeBytes: 1142 AppendBufferAsString(value, toStr); 1143 break; 1144 1145 case GPBDataTypeMessage: 1146 [toStr appendString:@"{\n"]; 1147 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1148 AppendTextFormatForMessage(value, toStr, subIndent); 1149 [toStr appendFormat:@"%@ }", lineIndent]; 1150 break; 1151 1152 default: 1153 NSCAssert(NO, @"Can't happen"); 1154 break; 1155 } 1156 [toStr appendString:@"\n"]; 1157 1158 [toStr appendString:msgEnd]; 1159 }]; 1160 } else { 1161 // map is one of the GPB*Dictionary classes, type doesn't matter. 1162 GPBInt32Int32Dictionary *dict = map; 1163 [dict enumerateForTextFormat:^(id keyObj, id valueObj) { 1164 [toStr appendString:(isFirst ? msgStartFirst : msgStart)]; 1165 isFirst = NO; 1166 1167 // Key always is a NSString. 1168 if (keyDataType == GPBDataTypeString) { 1169 [toStr appendString:keyLine]; 1170 AppendStringEscaped(keyObj, toStr); 1171 [toStr appendString:@"\n"]; 1172 } else { 1173 [toStr appendFormat:@"%@%@\n", keyLine, keyObj]; 1174 } 1175 1176 [toStr appendString:valueLine]; 1177 switch (valueDataType) { 1178 case GPBDataTypeString: 1179 AppendStringEscaped(valueObj, toStr); 1180 break; 1181 1182 case GPBDataTypeBytes: 1183 AppendBufferAsString(valueObj, toStr); 1184 break; 1185 1186 case GPBDataTypeMessage: 1187 [toStr appendString:@"{\n"]; 1188 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1189 AppendTextFormatForMessage(valueObj, toStr, subIndent); 1190 [toStr appendFormat:@"%@ }", lineIndent]; 1191 break; 1192 1193 case GPBDataTypeEnum: { 1194 int32_t enumValue = [valueObj intValue]; 1195 NSString *valueStr = nil; 1196 GPBEnumDescriptor *descriptor = field.enumDescriptor; 1197 if (descriptor) { 1198 valueStr = [descriptor textFormatNameForValue:enumValue]; 1199 } 1200 if (valueStr) { 1201 [toStr appendString:valueStr]; 1202 } else { 1203 [toStr appendFormat:@"%d", enumValue]; 1204 } 1205 break; 1206 } 1207 1208 default: 1209 NSCAssert(valueDataType != GPBDataTypeGroup, @"Can't happen"); 1210 // Everything else is a NSString. 1211 [toStr appendString:valueObj]; 1212 break; 1213 } 1214 [toStr appendString:@"\n"]; 1215 1216 [toStr appendString:msgEnd]; 1217 }]; 1218 } 1219 } 1220 1221 static void AppendTextFormatForMessageField(GPBMessage *message, 1222 GPBFieldDescriptor *field, 1223 NSMutableString *toStr, 1224 NSString *lineIndent) { 1225 id arrayOrMap; 1226 NSUInteger count; 1227 GPBFieldType fieldType = field.fieldType; 1228 switch (fieldType) { 1229 case GPBFieldTypeSingle: 1230 arrayOrMap = nil; 1231 count = (GPBGetHasIvarField(message, field) ? 1 : 0); 1232 break; 1233 1234 case GPBFieldTypeRepeated: 1235 // Will be NSArray or GPB*Array, type doesn't matter, they both 1236 // implement count. 1237 arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field); 1238 count = [(NSArray *)arrayOrMap count]; 1239 break; 1240 1241 case GPBFieldTypeMap: { 1242 // Will be GPB*Dictionary or NSMutableDictionary, type doesn't matter, 1243 // they both implement count. 1244 arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field); 1245 count = [(NSDictionary *)arrayOrMap count]; 1246 break; 1247 } 1248 } 1249 1250 if (count == 0) { 1251 // Nothing to print, out of here. 1252 return; 1253 } 1254 1255 NSString *lineEnding = @""; 1256 1257 // If the name can't be reversed or support for extra info was turned off, 1258 // this can return nil. 1259 NSString *fieldName = [field textFormatName]; 1260 if ([fieldName length] == 0) { 1261 fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)]; 1262 // If there is only one entry, put the objc name as a comment, other wise 1263 // add it before the repeated values. 1264 if (count > 1) { 1265 [toStr appendFormat:@"%@# %@\n", lineIndent, field.name]; 1266 } else { 1267 lineEnding = [NSString stringWithFormat:@" # %@", field.name]; 1268 } 1269 } 1270 1271 if (fieldType == GPBFieldTypeMap) { 1272 AppendTextFormatForMapMessageField(arrayOrMap, field, toStr, lineIndent, 1273 fieldName, lineEnding); 1274 return; 1275 } 1276 1277 id array = arrayOrMap; 1278 const BOOL isRepeated = (array != nil); 1279 1280 GPBDataType fieldDataType = GPBGetFieldDataType(field); 1281 BOOL isMessageField = GPBDataTypeIsMessage(fieldDataType); 1282 for (NSUInteger j = 0; j < count; ++j) { 1283 // Start the line. 1284 [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName, 1285 (isMessageField ? "" : ":")]; 1286 1287 // The value. 1288 switch (fieldDataType) { 1289 #define FIELD_CASE(GPBDATATYPE, CTYPE, REAL_TYPE, ...) \ 1290 case GPBDataType##GPBDATATYPE: { \ 1291 CTYPE v = (isRepeated ? [(GPB##REAL_TYPE##Array *)array valueAtIndex:j] \ 1292 : GPBGetMessage##REAL_TYPE##Field(message, field)); \ 1293 [toStr appendFormat:__VA_ARGS__, v]; \ 1294 break; \ 1295 } 1296 1297 FIELD_CASE(Int32, int32_t, Int32, @"%d") 1298 FIELD_CASE(SInt32, int32_t, Int32, @"%d") 1299 FIELD_CASE(SFixed32, int32_t, Int32, @"%d") 1300 FIELD_CASE(UInt32, uint32_t, UInt32, @"%u") 1301 FIELD_CASE(Fixed32, uint32_t, UInt32, @"%u") 1302 FIELD_CASE(Int64, int64_t, Int64, @"%lld") 1303 FIELD_CASE(SInt64, int64_t, Int64, @"%lld") 1304 FIELD_CASE(SFixed64, int64_t, Int64, @"%lld") 1305 FIELD_CASE(UInt64, uint64_t, UInt64, @"%llu") 1306 FIELD_CASE(Fixed64, uint64_t, UInt64, @"%llu") 1307 FIELD_CASE(Float, float, Float, @"%.*g", FLT_DIG) 1308 FIELD_CASE(Double, double, Double, @"%.*lg", DBL_DIG) 1309 1310 #undef FIELD_CASE 1311 1312 case GPBDataTypeEnum: { 1313 int32_t v = (isRepeated ? [(GPBEnumArray *)array rawValueAtIndex:j] 1314 : GPBGetMessageInt32Field(message, field)); 1315 NSString *valueStr = nil; 1316 GPBEnumDescriptor *descriptor = field.enumDescriptor; 1317 if (descriptor) { 1318 valueStr = [descriptor textFormatNameForValue:v]; 1319 } 1320 if (valueStr) { 1321 [toStr appendString:valueStr]; 1322 } else { 1323 [toStr appendFormat:@"%d", v]; 1324 } 1325 break; 1326 } 1327 1328 case GPBDataTypeBool: { 1329 BOOL v = (isRepeated ? [(GPBBoolArray *)array valueAtIndex:j] 1330 : GPBGetMessageBoolField(message, field)); 1331 [toStr appendString:(v ? @"true" : @"false")]; 1332 break; 1333 } 1334 1335 case GPBDataTypeString: { 1336 NSString *v = (isRepeated ? [(NSArray *)array objectAtIndex:j] 1337 : GPBGetMessageStringField(message, field)); 1338 AppendStringEscaped(v, toStr); 1339 break; 1340 } 1341 1342 case GPBDataTypeBytes: { 1343 NSData *v = (isRepeated ? [(NSArray *)array objectAtIndex:j] 1344 : GPBGetMessageBytesField(message, field)); 1345 AppendBufferAsString(v, toStr); 1346 break; 1347 } 1348 1349 case GPBDataTypeGroup: 1350 case GPBDataTypeMessage: { 1351 GPBMessage *v = 1352 (isRepeated ? [(NSArray *)array objectAtIndex:j] 1353 : GPBGetObjectIvarWithField(message, field)); 1354 [toStr appendFormat:@"{%@\n", lineEnding]; 1355 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1356 AppendTextFormatForMessage(v, toStr, subIndent); 1357 [toStr appendFormat:@"%@}", lineIndent]; 1358 lineEnding = @""; 1359 break; 1360 } 1361 1362 } // switch(fieldDataType) 1363 1364 // End the line. 1365 [toStr appendFormat:@"%@\n", lineEnding]; 1366 1367 } // for(count) 1368 } 1369 1370 static void AppendTextFormatForMessageExtensionRange(GPBMessage *message, 1371 NSArray *activeExtensions, 1372 GPBExtensionRange range, 1373 NSMutableString *toStr, 1374 NSString *lineIndent) { 1375 uint32_t start = range.start; 1376 uint32_t end = range.end; 1377 for (GPBExtensionDescriptor *extension in activeExtensions) { 1378 uint32_t fieldNumber = extension.fieldNumber; 1379 if (fieldNumber < start) { 1380 // Not there yet. 1381 continue; 1382 } 1383 if (fieldNumber > end) { 1384 // Done. 1385 break; 1386 } 1387 1388 id rawExtValue = [message getExtension:extension]; 1389 BOOL isRepeated = extension.isRepeated; 1390 1391 NSUInteger numValues = 1; 1392 NSString *lineEnding = @""; 1393 if (isRepeated) { 1394 numValues = [(NSArray *)rawExtValue count]; 1395 } 1396 1397 NSString *singletonName = extension.singletonName; 1398 if (numValues == 1) { 1399 lineEnding = [NSString stringWithFormat:@" # [%@]", singletonName]; 1400 } else { 1401 [toStr appendFormat:@"%@# [%@]\n", lineIndent, singletonName]; 1402 } 1403 1404 GPBDataType extDataType = extension.dataType; 1405 for (NSUInteger j = 0; j < numValues; ++j) { 1406 id curValue = (isRepeated ? [rawExtValue objectAtIndex:j] : rawExtValue); 1407 1408 // Start the line. 1409 [toStr appendFormat:@"%@%u%s ", lineIndent, fieldNumber, 1410 (GPBDataTypeIsMessage(extDataType) ? "" : ":")]; 1411 1412 // The value. 1413 switch (extDataType) { 1414 #define FIELD_CASE(GPBDATATYPE, CTYPE, NUMSELECTOR, ...) \ 1415 case GPBDataType##GPBDATATYPE: { \ 1416 CTYPE v = [(NSNumber *)curValue NUMSELECTOR]; \ 1417 [toStr appendFormat:__VA_ARGS__, v]; \ 1418 break; \ 1419 } 1420 1421 FIELD_CASE(Int32, int32_t, intValue, @"%d") 1422 FIELD_CASE(SInt32, int32_t, intValue, @"%d") 1423 FIELD_CASE(SFixed32, int32_t, unsignedIntValue, @"%d") 1424 FIELD_CASE(UInt32, uint32_t, unsignedIntValue, @"%u") 1425 FIELD_CASE(Fixed32, uint32_t, unsignedIntValue, @"%u") 1426 FIELD_CASE(Int64, int64_t, longLongValue, @"%lld") 1427 FIELD_CASE(SInt64, int64_t, longLongValue, @"%lld") 1428 FIELD_CASE(SFixed64, int64_t, longLongValue, @"%lld") 1429 FIELD_CASE(UInt64, uint64_t, unsignedLongLongValue, @"%llu") 1430 FIELD_CASE(Fixed64, uint64_t, unsignedLongLongValue, @"%llu") 1431 FIELD_CASE(Float, float, floatValue, @"%.*g", FLT_DIG) 1432 FIELD_CASE(Double, double, doubleValue, @"%.*lg", DBL_DIG) 1433 // TODO: Add a comment with the enum name from enum descriptors 1434 // (might not be real value, so leave it as a comment, ObjC compiler 1435 // name mangles differently). Doesn't look like we actually generate 1436 // an enum descriptor reference like we do for normal fields, so this 1437 // will take a compiler change. 1438 FIELD_CASE(Enum, int32_t, intValue, @"%d") 1439 1440 #undef FIELD_CASE 1441 1442 case GPBDataTypeBool: 1443 [toStr appendString:([(NSNumber *)curValue boolValue] ? @"true" 1444 : @"false")]; 1445 break; 1446 1447 case GPBDataTypeString: 1448 AppendStringEscaped(curValue, toStr); 1449 break; 1450 1451 case GPBDataTypeBytes: 1452 AppendBufferAsString((NSData *)curValue, toStr); 1453 break; 1454 1455 case GPBDataTypeGroup: 1456 case GPBDataTypeMessage: { 1457 [toStr appendFormat:@"{%@\n", lineEnding]; 1458 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1459 AppendTextFormatForMessage(curValue, toStr, subIndent); 1460 [toStr appendFormat:@"%@}", lineIndent]; 1461 lineEnding = @""; 1462 break; 1463 } 1464 1465 } // switch(extDataType) 1466 1467 } // for(numValues) 1468 1469 // End the line. 1470 [toStr appendFormat:@"%@\n", lineEnding]; 1471 1472 } // for..in(activeExtensions) 1473 } 1474 1475 static void AppendTextFormatForMessage(GPBMessage *message, 1476 NSMutableString *toStr, 1477 NSString *lineIndent) { 1478 GPBDescriptor *descriptor = [message descriptor]; 1479 NSArray *fieldsArray = descriptor->fields_; 1480 NSUInteger fieldCount = fieldsArray.count; 1481 const GPBExtensionRange *extensionRanges = descriptor.extensionRanges; 1482 NSUInteger extensionRangesCount = descriptor.extensionRangesCount; 1483 NSArray *activeExtensions = [message sortedExtensionsInUse]; 1484 for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) { 1485 if (i == fieldCount) { 1486 AppendTextFormatForMessageExtensionRange( 1487 message, activeExtensions, extensionRanges[j++], toStr, lineIndent); 1488 } else if (j == extensionRangesCount || 1489 GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) { 1490 AppendTextFormatForMessageField(message, fieldsArray[i++], toStr, 1491 lineIndent); 1492 } else { 1493 AppendTextFormatForMessageExtensionRange( 1494 message, activeExtensions, extensionRanges[j++], toStr, lineIndent); 1495 } 1496 } 1497 1498 NSString *unknownFieldsStr = 1499 GPBTextFormatForUnknownFieldSet(message.unknownFields, lineIndent); 1500 if ([unknownFieldsStr length] > 0) { 1501 [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent]; 1502 [toStr appendString:unknownFieldsStr]; 1503 } 1504 } 1505 1506 NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) { 1507 if (message == nil) return @""; 1508 if (lineIndent == nil) lineIndent = @""; 1509 1510 NSMutableString *buildString = [NSMutableString string]; 1511 AppendTextFormatForMessage(message, buildString, lineIndent); 1512 return buildString; 1513 } 1514 1515 NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet, 1516 NSString *lineIndent) { 1517 if (unknownSet == nil) return @""; 1518 if (lineIndent == nil) lineIndent = @""; 1519 1520 NSMutableString *result = [NSMutableString string]; 1521 for (GPBUnknownField *field in [unknownSet sortedFields]) { 1522 int32_t fieldNumber = [field number]; 1523 1524 #define PRINT_LOOP(PROPNAME, CTYPE, FORMAT) \ 1525 [field.PROPNAME \ 1526 enumerateValuesWithBlock:^(CTYPE value, NSUInteger idx, BOOL * stop) { \ 1527 _Pragma("unused(idx, stop)"); \ 1528 [result \ 1529 appendFormat:@"%@%d: " #FORMAT "\n", lineIndent, fieldNumber, value]; \ 1530 }]; 1531 1532 PRINT_LOOP(varintList, uint64_t, %llu); 1533 PRINT_LOOP(fixed32List, uint32_t, 0x%X); 1534 PRINT_LOOP(fixed64List, uint64_t, 0x%llX); 1535 1536 #undef PRINT_LOOP 1537 1538 // NOTE: C++ version of TextFormat tries to parse this as a message 1539 // and print that if it succeeds. 1540 for (NSData *data in field.lengthDelimitedList) { 1541 [result appendFormat:@"%@%d: ", lineIndent, fieldNumber]; 1542 AppendBufferAsString(data, result); 1543 [result appendString:@"\n"]; 1544 } 1545 1546 for (GPBUnknownFieldSet *subUnknownSet in field.groupList) { 1547 [result appendFormat:@"%@%d: {\n", lineIndent, fieldNumber]; 1548 NSString *subIndent = [lineIndent stringByAppendingString:@" "]; 1549 NSString *subUnknwonSetStr = 1550 GPBTextFormatForUnknownFieldSet(subUnknownSet, subIndent); 1551 [result appendString:subUnknwonSetStr]; 1552 [result appendFormat:@"%@}\n", lineIndent]; 1553 } 1554 } 1555 return result; 1556 } 1557 1558 // Helpers to decode a varint. Not using GPBCodedInputStream version because 1559 // that needs a state object, and we don't want to create an input stream out 1560 // of the data. 1561 GPB_INLINE int8_t ReadRawByteFromData(const uint8_t **data) { 1562 int8_t result = *((int8_t *)(*data)); 1563 ++(*data); 1564 return result; 1565 } 1566 1567 static int32_t ReadRawVarint32FromData(const uint8_t **data) { 1568 int8_t tmp = ReadRawByteFromData(data); 1569 if (tmp >= 0) { 1570 return tmp; 1571 } 1572 int32_t result = tmp & 0x7f; 1573 if ((tmp = ReadRawByteFromData(data)) >= 0) { 1574 result |= tmp << 7; 1575 } else { 1576 result |= (tmp & 0x7f) << 7; 1577 if ((tmp = ReadRawByteFromData(data)) >= 0) { 1578 result |= tmp << 14; 1579 } else { 1580 result |= (tmp & 0x7f) << 14; 1581 if ((tmp = ReadRawByteFromData(data)) >= 0) { 1582 result |= tmp << 21; 1583 } else { 1584 result |= (tmp & 0x7f) << 21; 1585 result |= (tmp = ReadRawByteFromData(data)) << 28; 1586 if (tmp < 0) { 1587 // Discard upper 32 bits. 1588 for (int i = 0; i < 5; i++) { 1589 if (ReadRawByteFromData(data) >= 0) { 1590 return result; 1591 } 1592 } 1593 [NSException raise:NSParseErrorException 1594 format:@"Unable to read varint32"]; 1595 } 1596 } 1597 } 1598 } 1599 return result; 1600 } 1601 1602 NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key, 1603 NSString *inputStr) { 1604 // decodData form: 1605 // varint32: num entries 1606 // for each entry: 1607 // varint32: key 1608 // bytes*: decode data 1609 // 1610 // decode data one of two forms: 1611 // 1: a \0 followed by the string followed by an \0 1612 // 2: bytecodes to transform an input into the right thing, ending with \0 1613 // 1614 // the bytes codes are of the form: 1615 // 0xabbccccc 1616 // 0x0 (all zeros), end. 1617 // a - if set, add an underscore 1618 // bb - 00 ccccc bytes as is 1619 // bb - 10 ccccc upper first, as is on rest, ccccc byte total 1620 // bb - 01 ccccc lower first, as is on rest, ccccc byte total 1621 // bb - 11 ccccc all upper, ccccc byte total 1622 1623 if (!decodeData || !inputStr) { 1624 return nil; 1625 } 1626 1627 // Find key 1628 const uint8_t *scan = decodeData; 1629 int32_t numEntries = ReadRawVarint32FromData(&scan); 1630 BOOL foundKey = NO; 1631 while (!foundKey && (numEntries > 0)) { 1632 --numEntries; 1633 int32_t dataKey = ReadRawVarint32FromData(&scan); 1634 if (dataKey == key) { 1635 foundKey = YES; 1636 } else { 1637 // If it is a inlined string, it will start with \0; if it is bytecode it 1638 // will start with a code. So advance one (skipping the inline string 1639 // marker), and then loop until reaching the end marker (\0). 1640 ++scan; 1641 while (*scan != 0) ++scan; 1642 // Now move past the end marker. 1643 ++scan; 1644 } 1645 } 1646 1647 if (!foundKey) { 1648 return nil; 1649 } 1650 1651 // Decode 1652 1653 if (*scan == 0) { 1654 // Inline string. Move over the marker, and NSString can take it as 1655 // UTF8. 1656 ++scan; 1657 NSString *result = [NSString stringWithUTF8String:(const char *)scan]; 1658 return result; 1659 } 1660 1661 NSMutableString *result = 1662 [NSMutableString stringWithCapacity:[inputStr length]]; 1663 1664 const uint8_t kAddUnderscore = 0b10000000; 1665 const uint8_t kOpMask = 0b01100000; 1666 // const uint8_t kOpAsIs = 0b00000000; 1667 const uint8_t kOpFirstUpper = 0b01000000; 1668 const uint8_t kOpFirstLower = 0b00100000; 1669 const uint8_t kOpAllUpper = 0b01100000; 1670 const uint8_t kSegmentLenMask = 0b00011111; 1671 1672 NSInteger i = 0; 1673 for (; *scan != 0; ++scan) { 1674 if (*scan & kAddUnderscore) { 1675 [result appendString:@"_"]; 1676 } 1677 int segmentLen = *scan & kSegmentLenMask; 1678 uint8_t decodeOp = *scan & kOpMask; 1679 1680 // Do op specific handling of the first character. 1681 if (decodeOp == kOpFirstUpper) { 1682 unichar c = [inputStr characterAtIndex:i]; 1683 [result appendFormat:@"%c", toupper((char)c)]; 1684 ++i; 1685 --segmentLen; 1686 } else if (decodeOp == kOpFirstLower) { 1687 unichar c = [inputStr characterAtIndex:i]; 1688 [result appendFormat:@"%c", tolower((char)c)]; 1689 ++i; 1690 --segmentLen; 1691 } 1692 // else op == kOpAsIs || op == kOpAllUpper 1693 1694 // Now pull over the rest of the length for this segment. 1695 for (int x = 0; x < segmentLen; ++x) { 1696 unichar c = [inputStr characterAtIndex:(i + x)]; 1697 if (decodeOp == kOpAllUpper) { 1698 [result appendFormat:@"%c", toupper((char)c)]; 1699 } else { 1700 [result appendFormat:@"%C", c]; 1701 } 1702 } 1703 i += segmentLen; 1704 } 1705 1706 return result; 1707 } 1708 1709 #pragma mark - GPBMessageSignatureProtocol 1710 1711 // A series of selectors that are used solely to get @encoding values 1712 // for them by the dynamic protobuf runtime code. An object using the protocol 1713 // needs to be declared for the protocol to be valid at runtime. 1714 @interface GPBMessageSignatureProtocol : NSObject<GPBMessageSignatureProtocol> 1715 @end 1716 @implementation GPBMessageSignatureProtocol 1717 @end 1718