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