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