• 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 atleast %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 GPBSetAutocreatedRetainedObjectIvarWithField(
508    GPBMessage *self, GPBFieldDescriptor *field,
509    id __attribute__((ns_consumed)) value) {
510  uint8_t *storage = (uint8_t *)self->messageStorage_;
511  id *typePtr = (id *)&storage[field->description_->offset];
512  NSCAssert(*typePtr == NULL, @"Can't set autocreated object more than once.");
513  *typePtr = value;
514}
515
516void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self,
517                                             GPBFieldDescriptor *field) {
518  if (GPBGetHasIvarField(self, field)) {
519    return;
520  }
521  uint8_t *storage = (uint8_t *)self->messageStorage_;
522  id *typePtr = (id *)&storage[field->description_->offset];
523  GPBMessage *oldValue = *typePtr;
524  *typePtr = NULL;
525  GPBClearMessageAutocreator(oldValue);
526  [oldValue release];
527}
528
529// This exists only for bridging some aliased types, nothing else should use it.
530static void GPBSetObjectIvarWithField(GPBMessage *self,
531                                      GPBFieldDescriptor *field, id value) {
532  if (self == nil || field == nil) return;
533  GPBSetRetainedObjectIvarWithFieldPrivate(self, field, [value retain]);
534}
535
536static void GPBSetCopyObjectIvarWithField(GPBMessage *self,
537                                          GPBFieldDescriptor *field, id value);
538
539// GPBSetCopyObjectIvarWithField is blocked from the analyzer because it flags
540// a leak for the -copy even though GPBSetRetainedObjectIvarWithFieldPrivate
541// is marked as consuming the value. Note: For some reason this doesn't happen
542// with the -retain in GPBSetObjectIvarWithField.
543#if !defined(__clang_analyzer__)
544// This exists only for bridging some aliased types, nothing else should use it.
545static void GPBSetCopyObjectIvarWithField(GPBMessage *self,
546                                          GPBFieldDescriptor *field, id value) {
547  if (self == nil || field == nil) return;
548  GPBSetRetainedObjectIvarWithFieldPrivate(self, field, [value copy]);
549}
550#endif  // !defined(__clang_analyzer__)
551
552void GPBSetObjectIvarWithFieldPrivate(GPBMessage *self,
553                                      GPBFieldDescriptor *field, id value) {
554  GPBSetRetainedObjectIvarWithFieldPrivate(self, field, [value retain]);
555}
556
557void GPBSetRetainedObjectIvarWithFieldPrivate(GPBMessage *self,
558                                              GPBFieldDescriptor *field,
559                                              id value) {
560  NSCAssert(self->messageStorage_ != NULL,
561            @"%@: All messages should have storage (from init)",
562            [self class]);
563#if defined(__clang_analyzer__)
564  if (self->messageStorage_ == NULL) return;
565#endif
566  GPBDataType fieldType = GPBGetFieldDataType(field);
567  BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
568  BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType);
569#if defined(DEBUG) && DEBUG
570  if (value == nil && !isMapOrArray && !fieldIsMessage &&
571      field.hasDefaultValue) {
572    // Setting a message to nil is an obvious way to "clear" the value
573    // as there is no way to set a non-empty default value for messages.
574    //
575    // For Strings and Bytes that have default values set it is not clear what
576    // should be done when their value is set to nil. Is the intention just to
577    // clear the set value and reset to default, or is the intention to set the
578    // value to the empty string/data? Arguments can be made for both cases.
579    // 'nil' has been abused as a replacement for an empty string/data in ObjC.
580    // We decided to be consistent with all "object" types and clear the has
581    // field, and fall back on the default value. The warning below will only
582    // appear in debug, but the could should be changed so the intention is
583    // clear.
584    NSString *hasSel = NSStringFromSelector(field->hasOrCountSel_);
585    NSString *propName = field.name;
586    NSString *className = self.descriptor.name;
587    NSLog(@"warning: '%@.%@ = nil;' is not clearly defined for fields with "
588          @"default values. Please use '%@.%@ = %@' if you want to set it to "
589          @"empty, or call '%@.%@ = NO' to reset it to it's default value of "
590          @"'%@'. Defaulting to resetting default value.",
591          className, propName, className, propName,
592          (fieldType == GPBDataTypeString) ? @"@\"\"" : @"GPBEmptyNSData()",
593          className, hasSel, field.defaultValue.valueString);
594    // Note: valueString, depending on the type, it could easily be
595    // valueData/valueMessage.
596  }
597#endif  // DEBUG
598  GPBMessageFieldDescription *fieldDesc = field->description_;
599  if (!isMapOrArray) {
600    // Non repeated/map can be in an oneof, clear any existing value from the
601    // oneof.
602    GPBOneofDescriptor *oneof = field->containingOneof_;
603    if (oneof) {
604      GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
605    }
606    // Clear "has" if they are being set to nil.
607    BOOL setHasValue = (value != nil);
608    // If the field should clear on a "zero" value, then check if the string/data
609    // was zero length, and clear instead.
610    if (((fieldDesc->flags & GPBFieldClearHasIvarOnZero) != 0) &&
611        ([value length] == 0)) {
612      setHasValue = NO;
613      // The value passed in was retained, it must be released since we
614      // aren't saving anything in the field.
615      [value release];
616      value = nil;
617    }
618    GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, setHasValue);
619  }
620  uint8_t *storage = (uint8_t *)self->messageStorage_;
621  id *typePtr = (id *)&storage[fieldDesc->offset];
622
623  id oldValue = *typePtr;
624
625  *typePtr = value;
626
627  if (oldValue) {
628    if (isMapOrArray) {
629      if (field.fieldType == GPBFieldTypeRepeated) {
630        // If the old array was autocreated by us, then clear it.
631        if (GPBDataTypeIsObject(fieldType)) {
632          if ([oldValue isKindOfClass:[GPBAutocreatedArray class]]) {
633            GPBAutocreatedArray *autoArray = oldValue;
634            if (autoArray->_autocreator == self) {
635              autoArray->_autocreator = nil;
636            }
637          }
638        } else {
639          // Type doesn't matter, it is a GPB*Array.
640          GPBInt32Array *gpbArray = oldValue;
641          if (gpbArray->_autocreator == self) {
642            gpbArray->_autocreator = nil;
643          }
644        }
645      } else { // GPBFieldTypeMap
646        // If the old map was autocreated by us, then clear it.
647        if ((field.mapKeyDataType == GPBDataTypeString) &&
648            GPBDataTypeIsObject(fieldType)) {
649          if ([oldValue isKindOfClass:[GPBAutocreatedDictionary class]]) {
650            GPBAutocreatedDictionary *autoDict = oldValue;
651            if (autoDict->_autocreator == self) {
652              autoDict->_autocreator = nil;
653            }
654          }
655        } else {
656          // Type doesn't matter, it is a GPB*Dictionary.
657          GPBInt32Int32Dictionary *gpbDict = oldValue;
658          if (gpbDict->_autocreator == self) {
659            gpbDict->_autocreator = nil;
660          }
661        }
662      }
663    } else if (fieldIsMessage) {
664      // If the old message value was autocreated by us, then clear it.
665      GPBMessage *oldMessageValue = oldValue;
666      if (GPBWasMessageAutocreatedBy(oldMessageValue, self)) {
667        GPBClearMessageAutocreator(oldMessageValue);
668      }
669    }
670    [oldValue release];
671  }
672
673  GPBBecomeVisibleToAutocreator(self);
674}
675
676id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
677                                         GPBFieldDescriptor *field) {
678  if (self->messageStorage_ == nil) {
679    return nil;
680  }
681  uint8_t *storage = (uint8_t *)self->messageStorage_;
682  id *typePtr = (id *)&storage[field->description_->offset];
683  return *typePtr;
684}
685
686// Only exists for public api, no core code should use this.
687int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
688  #if defined(DEBUG) && DEBUG
689    NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
690              @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
691              field.name, [self class]);
692    NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
693              @"Attempting to get value of type Enum from field %@ "
694              @"of %@ which is of type %@.",
695              [self class], field.name,
696              TypeToString(GPBGetFieldDataType(field)));
697  #endif
698
699  int32_t result = GPBGetMessageInt32Field(self, field);
700  // If this is presevering unknown enums, make sure the value is valid before
701  // returning it.
702
703  GPBFileSyntax syntax = [self descriptor].file.syntax;
704  if (GPBHasPreservingUnknownEnumSemantics(syntax) &&
705      ![field isValidEnumValue:result]) {
706    result = kGPBUnrecognizedEnumeratorValue;
707  }
708  return result;
709}
710
711// Only exists for public api, no core code should use this.
712void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
713                            int32_t value) {
714  #if defined(DEBUG) && DEBUG
715    NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
716              @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
717              field.name, [self class]);
718    NSCAssert(GPBGetFieldDataType(field) == GPBDataTypeEnum,
719              @"Attempting to set field %@ of %@ which is of type %@ with "
720              @"value of type Enum.",
721              [self class], field.name,
722              TypeToString(GPBGetFieldDataType(field)));
723  #endif
724  GPBSetEnumIvarWithFieldPrivate(self, field, value);
725}
726
727void GPBSetEnumIvarWithFieldPrivate(GPBMessage *self,
728                                    GPBFieldDescriptor *field, int32_t value) {
729  // Don't allow in unknown values.  Proto3 can use the Raw method.
730  if (![field isValidEnumValue:value]) {
731    [NSException raise:NSInvalidArgumentException
732                format:@"%@.%@: Attempt to set an unknown enum value (%d)",
733                       [self class], field.name, value];
734  }
735  GPBSetInt32IvarWithFieldPrivate(self, field, value);
736}
737
738// Only exists for public api, no core code should use this.
739int32_t GPBGetMessageRawEnumField(GPBMessage *self,
740                                  GPBFieldDescriptor *field) {
741  int32_t result = GPBGetMessageInt32Field(self, field);
742  return result;
743}
744
745// Only exists for public api, no core code should use this.
746void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field,
747                               int32_t value) {
748  GPBSetInt32IvarWithFieldPrivate(self, field, value);
749}
750
751BOOL GPBGetMessageBoolField(GPBMessage *self,
752                            GPBFieldDescriptor *field) {
753#if defined(DEBUG) && DEBUG
754  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
755            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
756            field.name, [self class]);
757  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
758            @"Attempting to get value of type bool from field %@ "
759            @"of %@ which is of type %@.",
760            [self class], field.name,
761            TypeToString(GPBGetFieldDataType(field)));
762#endif
763  if (GPBGetHasIvarField(self, field)) {
764    // Bools are stored in the has bits to avoid needing explicit space in the
765    // storage structure.
766    // (the field number passed to the HasIvar helper doesn't really matter
767    // since the offset is never negative)
768    GPBMessageFieldDescription *fieldDesc = field->description_;
769    return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number);
770  } else {
771    return field.defaultValue.valueBool;
772  }
773}
774
775// Only exists for public api, no core code should use this.
776void GPBSetMessageBoolField(GPBMessage *self,
777                            GPBFieldDescriptor *field,
778                            BOOL value) {
779  if (self == nil || field == nil) return;
780  #if defined(DEBUG) && DEBUG
781    NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
782              @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
783              field.name, [self class]);
784    NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field), GPBDataTypeBool),
785              @"Attempting to set field %@ of %@ which is of type %@ with "
786              @"value of type bool.",
787              [self class], field.name,
788              TypeToString(GPBGetFieldDataType(field)));
789  #endif
790  GPBSetBoolIvarWithFieldPrivate(self, field, value);
791}
792
793void GPBSetBoolIvarWithFieldPrivate(GPBMessage *self,
794                                    GPBFieldDescriptor *field,
795                                    BOOL value) {
796  GPBMessageFieldDescription *fieldDesc = field->description_;
797  GPBOneofDescriptor *oneof = field->containingOneof_;
798  if (oneof) {
799    GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
800  }
801
802  // Bools are stored in the has bits to avoid needing explicit space in the
803  // storage structure.
804  // (the field number passed to the HasIvar helper doesn't really matter since
805  // the offset is never negative)
806  GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value);
807
808  // If the value is zero, then we only count the field as "set" if the field
809  // shouldn't auto clear on zero.
810  BOOL hasValue = ((value != (BOOL)0)
811                   || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0));
812  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
813  GPBBecomeVisibleToAutocreator(self);
814}
815
816//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int32, int32_t)
817// This block of code is generated, do not edit it directly.
818// clang-format off
819
820int32_t GPBGetMessageInt32Field(GPBMessage *self,
821                                GPBFieldDescriptor *field) {
822#if defined(DEBUG) && DEBUG
823  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
824            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
825            field.name, [self class]);
826  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
827                                GPBDataTypeInt32),
828            @"Attempting to get value of int32_t from field %@ "
829            @"of %@ which is of type %@.",
830            [self class], field.name,
831            TypeToString(GPBGetFieldDataType(field)));
832#endif
833  if (GPBGetHasIvarField(self, field)) {
834    uint8_t *storage = (uint8_t *)self->messageStorage_;
835    int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
836    return *typePtr;
837  } else {
838    return field.defaultValue.valueInt32;
839  }
840}
841
842// Only exists for public api, no core code should use this.
843void GPBSetMessageInt32Field(GPBMessage *self,
844                             GPBFieldDescriptor *field,
845                             int32_t value) {
846  if (self == nil || field == nil) return;
847#if defined(DEBUG) && DEBUG
848  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
849            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
850            field.name, [self class]);
851  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
852                                GPBDataTypeInt32),
853            @"Attempting to set field %@ of %@ which is of type %@ with "
854            @"value of type int32_t.",
855            [self class], field.name,
856            TypeToString(GPBGetFieldDataType(field)));
857#endif
858  GPBSetInt32IvarWithFieldPrivate(self, field, value);
859}
860
861void GPBSetInt32IvarWithFieldPrivate(GPBMessage *self,
862                                     GPBFieldDescriptor *field,
863                                     int32_t value) {
864  GPBOneofDescriptor *oneof = field->containingOneof_;
865  GPBMessageFieldDescription *fieldDesc = field->description_;
866  if (oneof) {
867    GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
868  }
869#if defined(DEBUG) && DEBUG
870  NSCAssert(self->messageStorage_ != NULL,
871            @"%@: All messages should have storage (from init)",
872            [self class]);
873#endif
874#if defined(__clang_analyzer__)
875  if (self->messageStorage_ == NULL) return;
876#endif
877  uint8_t *storage = (uint8_t *)self->messageStorage_;
878  int32_t *typePtr = (int32_t *)&storage[fieldDesc->offset];
879  *typePtr = value;
880  // If the value is zero, then we only count the field as "set" if the field
881  // shouldn't auto clear on zero.
882  BOOL hasValue = ((value != (int32_t)0)
883                   || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0));
884  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
885  GPBBecomeVisibleToAutocreator(self);
886}
887
888// clang-format on
889//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt32, uint32_t)
890// This block of code is generated, do not edit it directly.
891// clang-format off
892
893uint32_t GPBGetMessageUInt32Field(GPBMessage *self,
894                                  GPBFieldDescriptor *field) {
895#if defined(DEBUG) && DEBUG
896  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
897            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
898            field.name, [self class]);
899  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
900                                GPBDataTypeUInt32),
901            @"Attempting to get value of uint32_t from field %@ "
902            @"of %@ which is of type %@.",
903            [self class], field.name,
904            TypeToString(GPBGetFieldDataType(field)));
905#endif
906  if (GPBGetHasIvarField(self, field)) {
907    uint8_t *storage = (uint8_t *)self->messageStorage_;
908    uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
909    return *typePtr;
910  } else {
911    return field.defaultValue.valueUInt32;
912  }
913}
914
915// Only exists for public api, no core code should use this.
916void GPBSetMessageUInt32Field(GPBMessage *self,
917                              GPBFieldDescriptor *field,
918                              uint32_t value) {
919  if (self == nil || field == nil) return;
920#if defined(DEBUG) && DEBUG
921  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
922            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
923            field.name, [self class]);
924  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
925                                GPBDataTypeUInt32),
926            @"Attempting to set field %@ of %@ which is of type %@ with "
927            @"value of type uint32_t.",
928            [self class], field.name,
929            TypeToString(GPBGetFieldDataType(field)));
930#endif
931  GPBSetUInt32IvarWithFieldPrivate(self, field, value);
932}
933
934void GPBSetUInt32IvarWithFieldPrivate(GPBMessage *self,
935                                      GPBFieldDescriptor *field,
936                                      uint32_t value) {
937  GPBOneofDescriptor *oneof = field->containingOneof_;
938  GPBMessageFieldDescription *fieldDesc = field->description_;
939  if (oneof) {
940    GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
941  }
942#if defined(DEBUG) && DEBUG
943  NSCAssert(self->messageStorage_ != NULL,
944            @"%@: All messages should have storage (from init)",
945            [self class]);
946#endif
947#if defined(__clang_analyzer__)
948  if (self->messageStorage_ == NULL) return;
949#endif
950  uint8_t *storage = (uint8_t *)self->messageStorage_;
951  uint32_t *typePtr = (uint32_t *)&storage[fieldDesc->offset];
952  *typePtr = value;
953  // If the value is zero, then we only count the field as "set" if the field
954  // shouldn't auto clear on zero.
955  BOOL hasValue = ((value != (uint32_t)0)
956                   || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0));
957  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
958  GPBBecomeVisibleToAutocreator(self);
959}
960
961// clang-format on
962//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int64, int64_t)
963// This block of code is generated, do not edit it directly.
964// clang-format off
965
966int64_t GPBGetMessageInt64Field(GPBMessage *self,
967                                GPBFieldDescriptor *field) {
968#if defined(DEBUG) && DEBUG
969  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
970            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
971            field.name, [self class]);
972  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
973                                GPBDataTypeInt64),
974            @"Attempting to get value of int64_t from field %@ "
975            @"of %@ which is of type %@.",
976            [self class], field.name,
977            TypeToString(GPBGetFieldDataType(field)));
978#endif
979  if (GPBGetHasIvarField(self, field)) {
980    uint8_t *storage = (uint8_t *)self->messageStorage_;
981    int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
982    return *typePtr;
983  } else {
984    return field.defaultValue.valueInt64;
985  }
986}
987
988// Only exists for public api, no core code should use this.
989void GPBSetMessageInt64Field(GPBMessage *self,
990                             GPBFieldDescriptor *field,
991                             int64_t value) {
992  if (self == nil || field == nil) return;
993#if defined(DEBUG) && DEBUG
994  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
995            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
996            field.name, [self class]);
997  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
998                                GPBDataTypeInt64),
999            @"Attempting to set field %@ of %@ which is of type %@ with "
1000            @"value of type int64_t.",
1001            [self class], field.name,
1002            TypeToString(GPBGetFieldDataType(field)));
1003#endif
1004  GPBSetInt64IvarWithFieldPrivate(self, field, value);
1005}
1006
1007void GPBSetInt64IvarWithFieldPrivate(GPBMessage *self,
1008                                     GPBFieldDescriptor *field,
1009                                     int64_t value) {
1010  GPBOneofDescriptor *oneof = field->containingOneof_;
1011  GPBMessageFieldDescription *fieldDesc = field->description_;
1012  if (oneof) {
1013    GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
1014  }
1015#if defined(DEBUG) && DEBUG
1016  NSCAssert(self->messageStorage_ != NULL,
1017            @"%@: All messages should have storage (from init)",
1018            [self class]);
1019#endif
1020#if defined(__clang_analyzer__)
1021  if (self->messageStorage_ == NULL) return;
1022#endif
1023  uint8_t *storage = (uint8_t *)self->messageStorage_;
1024  int64_t *typePtr = (int64_t *)&storage[fieldDesc->offset];
1025  *typePtr = value;
1026  // If the value is zero, then we only count the field as "set" if the field
1027  // shouldn't auto clear on zero.
1028  BOOL hasValue = ((value != (int64_t)0)
1029                   || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0));
1030  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
1031  GPBBecomeVisibleToAutocreator(self);
1032}
1033
1034// clang-format on
1035//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt64, uint64_t)
1036// This block of code is generated, do not edit it directly.
1037// clang-format off
1038
1039uint64_t GPBGetMessageUInt64Field(GPBMessage *self,
1040                                  GPBFieldDescriptor *field) {
1041#if defined(DEBUG) && DEBUG
1042  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
1043            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
1044            field.name, [self class]);
1045  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1046                                GPBDataTypeUInt64),
1047            @"Attempting to get value of uint64_t from field %@ "
1048            @"of %@ which is of type %@.",
1049            [self class], field.name,
1050            TypeToString(GPBGetFieldDataType(field)));
1051#endif
1052  if (GPBGetHasIvarField(self, field)) {
1053    uint8_t *storage = (uint8_t *)self->messageStorage_;
1054    uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
1055    return *typePtr;
1056  } else {
1057    return field.defaultValue.valueUInt64;
1058  }
1059}
1060
1061// Only exists for public api, no core code should use this.
1062void GPBSetMessageUInt64Field(GPBMessage *self,
1063                              GPBFieldDescriptor *field,
1064                              uint64_t value) {
1065  if (self == nil || field == nil) return;
1066#if defined(DEBUG) && DEBUG
1067  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
1068            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
1069            field.name, [self class]);
1070  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1071                                GPBDataTypeUInt64),
1072            @"Attempting to set field %@ of %@ which is of type %@ with "
1073            @"value of type uint64_t.",
1074            [self class], field.name,
1075            TypeToString(GPBGetFieldDataType(field)));
1076#endif
1077  GPBSetUInt64IvarWithFieldPrivate(self, field, value);
1078}
1079
1080void GPBSetUInt64IvarWithFieldPrivate(GPBMessage *self,
1081                                      GPBFieldDescriptor *field,
1082                                      uint64_t value) {
1083  GPBOneofDescriptor *oneof = field->containingOneof_;
1084  GPBMessageFieldDescription *fieldDesc = field->description_;
1085  if (oneof) {
1086    GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
1087  }
1088#if defined(DEBUG) && DEBUG
1089  NSCAssert(self->messageStorage_ != NULL,
1090            @"%@: All messages should have storage (from init)",
1091            [self class]);
1092#endif
1093#if defined(__clang_analyzer__)
1094  if (self->messageStorage_ == NULL) return;
1095#endif
1096  uint8_t *storage = (uint8_t *)self->messageStorage_;
1097  uint64_t *typePtr = (uint64_t *)&storage[fieldDesc->offset];
1098  *typePtr = value;
1099  // If the value is zero, then we only count the field as "set" if the field
1100  // shouldn't auto clear on zero.
1101  BOOL hasValue = ((value != (uint64_t)0)
1102                   || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0));
1103  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
1104  GPBBecomeVisibleToAutocreator(self);
1105}
1106
1107// clang-format on
1108//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Float, float)
1109// This block of code is generated, do not edit it directly.
1110// clang-format off
1111
1112float GPBGetMessageFloatField(GPBMessage *self,
1113                              GPBFieldDescriptor *field) {
1114#if defined(DEBUG) && DEBUG
1115  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
1116            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
1117            field.name, [self class]);
1118  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1119                                GPBDataTypeFloat),
1120            @"Attempting to get value of float from field %@ "
1121            @"of %@ which is of type %@.",
1122            [self class], field.name,
1123            TypeToString(GPBGetFieldDataType(field)));
1124#endif
1125  if (GPBGetHasIvarField(self, field)) {
1126    uint8_t *storage = (uint8_t *)self->messageStorage_;
1127    float *typePtr = (float *)&storage[field->description_->offset];
1128    return *typePtr;
1129  } else {
1130    return field.defaultValue.valueFloat;
1131  }
1132}
1133
1134// Only exists for public api, no core code should use this.
1135void GPBSetMessageFloatField(GPBMessage *self,
1136                             GPBFieldDescriptor *field,
1137                             float value) {
1138  if (self == nil || field == nil) return;
1139#if defined(DEBUG) && DEBUG
1140  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
1141            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
1142            field.name, [self class]);
1143  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1144                                GPBDataTypeFloat),
1145            @"Attempting to set field %@ of %@ which is of type %@ with "
1146            @"value of type float.",
1147            [self class], field.name,
1148            TypeToString(GPBGetFieldDataType(field)));
1149#endif
1150  GPBSetFloatIvarWithFieldPrivate(self, field, value);
1151}
1152
1153void GPBSetFloatIvarWithFieldPrivate(GPBMessage *self,
1154                                     GPBFieldDescriptor *field,
1155                                     float value) {
1156  GPBOneofDescriptor *oneof = field->containingOneof_;
1157  GPBMessageFieldDescription *fieldDesc = field->description_;
1158  if (oneof) {
1159    GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
1160  }
1161#if defined(DEBUG) && DEBUG
1162  NSCAssert(self->messageStorage_ != NULL,
1163            @"%@: All messages should have storage (from init)",
1164            [self class]);
1165#endif
1166#if defined(__clang_analyzer__)
1167  if (self->messageStorage_ == NULL) return;
1168#endif
1169  uint8_t *storage = (uint8_t *)self->messageStorage_;
1170  float *typePtr = (float *)&storage[fieldDesc->offset];
1171  *typePtr = value;
1172  // If the value is zero, then we only count the field as "set" if the field
1173  // shouldn't auto clear on zero.
1174  BOOL hasValue = ((value != (float)0)
1175                   || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0));
1176  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
1177  GPBBecomeVisibleToAutocreator(self);
1178}
1179
1180// clang-format on
1181//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Double, double)
1182// This block of code is generated, do not edit it directly.
1183// clang-format off
1184
1185double GPBGetMessageDoubleField(GPBMessage *self,
1186                                GPBFieldDescriptor *field) {
1187#if defined(DEBUG) && DEBUG
1188  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
1189            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
1190            field.name, [self class]);
1191  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1192                                GPBDataTypeDouble),
1193            @"Attempting to get value of double from field %@ "
1194            @"of %@ which is of type %@.",
1195            [self class], field.name,
1196            TypeToString(GPBGetFieldDataType(field)));
1197#endif
1198  if (GPBGetHasIvarField(self, field)) {
1199    uint8_t *storage = (uint8_t *)self->messageStorage_;
1200    double *typePtr = (double *)&storage[field->description_->offset];
1201    return *typePtr;
1202  } else {
1203    return field.defaultValue.valueDouble;
1204  }
1205}
1206
1207// Only exists for public api, no core code should use this.
1208void GPBSetMessageDoubleField(GPBMessage *self,
1209                              GPBFieldDescriptor *field,
1210                              double value) {
1211  if (self == nil || field == nil) return;
1212#if defined(DEBUG) && DEBUG
1213  NSCAssert([[self descriptor] fieldWithNumber:field.number] == field,
1214            @"FieldDescriptor %@ doesn't appear to be for %@ messages.",
1215            field.name, [self class]);
1216  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1217                                GPBDataTypeDouble),
1218            @"Attempting to set field %@ of %@ which is of type %@ with "
1219            @"value of type double.",
1220            [self class], field.name,
1221            TypeToString(GPBGetFieldDataType(field)));
1222#endif
1223  GPBSetDoubleIvarWithFieldPrivate(self, field, value);
1224}
1225
1226void GPBSetDoubleIvarWithFieldPrivate(GPBMessage *self,
1227                                      GPBFieldDescriptor *field,
1228                                      double value) {
1229  GPBOneofDescriptor *oneof = field->containingOneof_;
1230  GPBMessageFieldDescription *fieldDesc = field->description_;
1231  if (oneof) {
1232    GPBMaybeClearOneofPrivate(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
1233  }
1234#if defined(DEBUG) && DEBUG
1235  NSCAssert(self->messageStorage_ != NULL,
1236            @"%@: All messages should have storage (from init)",
1237            [self class]);
1238#endif
1239#if defined(__clang_analyzer__)
1240  if (self->messageStorage_ == NULL) return;
1241#endif
1242  uint8_t *storage = (uint8_t *)self->messageStorage_;
1243  double *typePtr = (double *)&storage[fieldDesc->offset];
1244  *typePtr = value;
1245  // If the value is zero, then we only count the field as "set" if the field
1246  // shouldn't auto clear on zero.
1247  BOOL hasValue = ((value != (double)0)
1248                   || ((fieldDesc->flags & GPBFieldClearHasIvarOnZero) == 0));
1249  GPBSetHasIvar(self, fieldDesc->hasIndex, fieldDesc->number, hasValue);
1250  GPBBecomeVisibleToAutocreator(self);
1251}
1252
1253// clang-format on
1254//%PDDM-EXPAND-END (6 expansions)
1255
1256// Aliases are function calls that are virtually the same.
1257
1258//%PDDM-EXPAND IVAR_ALIAS_DEFN_COPY_OBJECT(String, NSString)
1259// This block of code is generated, do not edit it directly.
1260// clang-format off
1261
1262// Only exists for public api, no core code should use this.
1263NSString *GPBGetMessageStringField(GPBMessage *self,
1264                                   GPBFieldDescriptor *field) {
1265#if defined(DEBUG) && DEBUG
1266  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1267                                GPBDataTypeString),
1268            @"Attempting to get value of NSString from field %@ "
1269            @"of %@ which is of type %@.",
1270            [self class], field.name,
1271            TypeToString(GPBGetFieldDataType(field)));
1272#endif
1273  return (NSString *)GPBGetObjectIvarWithField(self, field);
1274}
1275
1276// Only exists for public api, no core code should use this.
1277void GPBSetMessageStringField(GPBMessage *self,
1278                              GPBFieldDescriptor *field,
1279                              NSString *value) {
1280#if defined(DEBUG) && DEBUG
1281  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1282                                GPBDataTypeString),
1283            @"Attempting to set field %@ of %@ which is of type %@ with "
1284            @"value of type NSString.",
1285            [self class], field.name,
1286            TypeToString(GPBGetFieldDataType(field)));
1287#endif
1288  GPBSetCopyObjectIvarWithField(self, field, (id)value);
1289}
1290
1291// clang-format on
1292//%PDDM-EXPAND IVAR_ALIAS_DEFN_COPY_OBJECT(Bytes, NSData)
1293// This block of code is generated, do not edit it directly.
1294// clang-format off
1295
1296// Only exists for public api, no core code should use this.
1297NSData *GPBGetMessageBytesField(GPBMessage *self,
1298                                GPBFieldDescriptor *field) {
1299#if defined(DEBUG) && DEBUG
1300  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1301                                GPBDataTypeBytes),
1302            @"Attempting to get value of NSData from field %@ "
1303            @"of %@ which is of type %@.",
1304            [self class], field.name,
1305            TypeToString(GPBGetFieldDataType(field)));
1306#endif
1307  return (NSData *)GPBGetObjectIvarWithField(self, field);
1308}
1309
1310// Only exists for public api, no core code should use this.
1311void GPBSetMessageBytesField(GPBMessage *self,
1312                             GPBFieldDescriptor *field,
1313                             NSData *value) {
1314#if defined(DEBUG) && DEBUG
1315  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1316                                GPBDataTypeBytes),
1317            @"Attempting to set field %@ of %@ which is of type %@ with "
1318            @"value of type NSData.",
1319            [self class], field.name,
1320            TypeToString(GPBGetFieldDataType(field)));
1321#endif
1322  GPBSetCopyObjectIvarWithField(self, field, (id)value);
1323}
1324
1325// clang-format on
1326//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Message, GPBMessage)
1327// This block of code is generated, do not edit it directly.
1328// clang-format off
1329
1330// Only exists for public api, no core code should use this.
1331GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
1332                                      GPBFieldDescriptor *field) {
1333#if defined(DEBUG) && DEBUG
1334  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1335                                GPBDataTypeMessage),
1336            @"Attempting to get value of GPBMessage from field %@ "
1337            @"of %@ which is of type %@.",
1338            [self class], field.name,
1339            TypeToString(GPBGetFieldDataType(field)));
1340#endif
1341  return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
1342}
1343
1344// Only exists for public api, no core code should use this.
1345void GPBSetMessageMessageField(GPBMessage *self,
1346                               GPBFieldDescriptor *field,
1347                               GPBMessage *value) {
1348#if defined(DEBUG) && DEBUG
1349  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1350                                GPBDataTypeMessage),
1351            @"Attempting to set field %@ of %@ which is of type %@ with "
1352            @"value of type GPBMessage.",
1353            [self class], field.name,
1354            TypeToString(GPBGetFieldDataType(field)));
1355#endif
1356  GPBSetObjectIvarWithField(self, field, (id)value);
1357}
1358
1359// clang-format on
1360//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Group, GPBMessage)
1361// This block of code is generated, do not edit it directly.
1362// clang-format off
1363
1364// Only exists for public api, no core code should use this.
1365GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
1366                                    GPBFieldDescriptor *field) {
1367#if defined(DEBUG) && DEBUG
1368  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1369                                GPBDataTypeGroup),
1370            @"Attempting to get value of GPBMessage from field %@ "
1371            @"of %@ which is of type %@.",
1372            [self class], field.name,
1373            TypeToString(GPBGetFieldDataType(field)));
1374#endif
1375  return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
1376}
1377
1378// Only exists for public api, no core code should use this.
1379void GPBSetMessageGroupField(GPBMessage *self,
1380                             GPBFieldDescriptor *field,
1381                             GPBMessage *value) {
1382#if defined(DEBUG) && DEBUG
1383  NSCAssert(DataTypesEquivalent(GPBGetFieldDataType(field),
1384                                GPBDataTypeGroup),
1385            @"Attempting to set field %@ of %@ which is of type %@ with "
1386            @"value of type GPBMessage.",
1387            [self class], field.name,
1388            TypeToString(GPBGetFieldDataType(field)));
1389#endif
1390  GPBSetObjectIvarWithField(self, field, (id)value);
1391}
1392
1393// clang-format on
1394//%PDDM-EXPAND-END (4 expansions)
1395
1396// GPBGetMessageRepeatedField is defined in GPBMessage.m
1397
1398// Only exists for public api, no core code should use this.
1399void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) {
1400#if defined(DEBUG) && DEBUG
1401  if (field.fieldType != GPBFieldTypeRepeated) {
1402    [NSException raise:NSInvalidArgumentException
1403                format:@"%@.%@ is not a repeated field.",
1404                       [self class], field.name];
1405  }
1406  Class expectedClass = Nil;
1407  switch (GPBGetFieldDataType(field)) {
1408    case GPBDataTypeBool:
1409      expectedClass = [GPBBoolArray class];
1410      break;
1411    case GPBDataTypeSFixed32:
1412    case GPBDataTypeInt32:
1413    case GPBDataTypeSInt32:
1414      expectedClass = [GPBInt32Array class];
1415      break;
1416    case GPBDataTypeFixed32:
1417    case GPBDataTypeUInt32:
1418      expectedClass = [GPBUInt32Array class];
1419      break;
1420    case GPBDataTypeSFixed64:
1421    case GPBDataTypeInt64:
1422    case GPBDataTypeSInt64:
1423      expectedClass = [GPBInt64Array class];
1424      break;
1425    case GPBDataTypeFixed64:
1426    case GPBDataTypeUInt64:
1427      expectedClass = [GPBUInt64Array class];
1428      break;
1429    case GPBDataTypeFloat:
1430      expectedClass = [GPBFloatArray class];
1431      break;
1432    case GPBDataTypeDouble:
1433      expectedClass = [GPBDoubleArray class];
1434      break;
1435    case GPBDataTypeBytes:
1436    case GPBDataTypeString:
1437    case GPBDataTypeMessage:
1438    case GPBDataTypeGroup:
1439      expectedClass = [NSMutableArray class];
1440      break;
1441    case GPBDataTypeEnum:
1442      expectedClass = [GPBEnumArray class];
1443      break;
1444  }
1445  if (array && ![array isKindOfClass:expectedClass]) {
1446    [NSException raise:NSInvalidArgumentException
1447                format:@"%@.%@: Expected %@ object, got %@.",
1448                       [self class], field.name, expectedClass, [array class]];
1449  }
1450#endif
1451  GPBSetObjectIvarWithField(self, field, array);
1452}
1453
1454static GPBDataType BaseDataType(GPBDataType type) {
1455  switch (type) {
1456    case GPBDataTypeSFixed32:
1457    case GPBDataTypeInt32:
1458    case GPBDataTypeSInt32:
1459    case GPBDataTypeEnum:
1460      return GPBDataTypeInt32;
1461    case GPBDataTypeFixed32:
1462    case GPBDataTypeUInt32:
1463      return GPBDataTypeUInt32;
1464    case GPBDataTypeSFixed64:
1465    case GPBDataTypeInt64:
1466    case GPBDataTypeSInt64:
1467      return GPBDataTypeInt64;
1468    case GPBDataTypeFixed64:
1469    case GPBDataTypeUInt64:
1470      return GPBDataTypeUInt64;
1471    case GPBDataTypeMessage:
1472    case GPBDataTypeGroup:
1473      return GPBDataTypeMessage;
1474    case GPBDataTypeBool:
1475    case GPBDataTypeFloat:
1476    case GPBDataTypeDouble:
1477    case GPBDataTypeBytes:
1478    case GPBDataTypeString:
1479      return type;
1480   }
1481}
1482
1483static BOOL DataTypesEquivalent(GPBDataType type1, GPBDataType type2) {
1484  return BaseDataType(type1) == BaseDataType(type2);
1485}
1486
1487static NSString *TypeToString(GPBDataType dataType) {
1488  switch (dataType) {
1489    case GPBDataTypeBool:
1490      return @"Bool";
1491    case GPBDataTypeSFixed32:
1492    case GPBDataTypeInt32:
1493    case GPBDataTypeSInt32:
1494      return @"Int32";
1495    case GPBDataTypeFixed32:
1496    case GPBDataTypeUInt32:
1497      return @"UInt32";
1498    case GPBDataTypeSFixed64:
1499    case GPBDataTypeInt64:
1500    case GPBDataTypeSInt64:
1501      return @"Int64";
1502    case GPBDataTypeFixed64:
1503    case GPBDataTypeUInt64:
1504      return @"UInt64";
1505    case GPBDataTypeFloat:
1506      return @"Float";
1507    case GPBDataTypeDouble:
1508      return @"Double";
1509    case GPBDataTypeBytes:
1510    case GPBDataTypeString:
1511    case GPBDataTypeMessage:
1512    case GPBDataTypeGroup:
1513      return @"Object";
1514    case GPBDataTypeEnum:
1515      return @"Enum";
1516  }
1517}
1518
1519// GPBGetMessageMapField is defined in GPBMessage.m
1520
1521// Only exists for public api, no core code should use this.
1522void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
1523                           id dictionary) {
1524#if defined(DEBUG) && DEBUG
1525  if (field.fieldType != GPBFieldTypeMap) {
1526    [NSException raise:NSInvalidArgumentException
1527                format:@"%@.%@ is not a map<> field.",
1528                       [self class], field.name];
1529  }
1530  if (dictionary) {
1531    GPBDataType keyDataType = field.mapKeyDataType;
1532    GPBDataType valueDataType = GPBGetFieldDataType(field);
1533    NSString *keyStr = TypeToString(keyDataType);
1534    NSString *valueStr = TypeToString(valueDataType);
1535    if (keyDataType == GPBDataTypeString) {
1536      keyStr = @"String";
1537    }
1538    Class expectedClass = Nil;
1539    if ((keyDataType == GPBDataTypeString) &&
1540        GPBDataTypeIsObject(valueDataType)) {
1541      expectedClass = [NSMutableDictionary class];
1542    } else {
1543      NSString *className =
1544          [NSString stringWithFormat:@"GPB%@%@Dictionary", keyStr, valueStr];
1545      expectedClass = NSClassFromString(className);
1546      NSCAssert(expectedClass, @"Missing a class (%@)?", expectedClass);
1547    }
1548    if (![dictionary isKindOfClass:expectedClass]) {
1549      [NSException raise:NSInvalidArgumentException
1550                  format:@"%@.%@: Expected %@ object, got %@.",
1551                         [self class], field.name, expectedClass,
1552                         [dictionary class]];
1553    }
1554  }
1555#endif
1556  GPBSetObjectIvarWithField(self, field, dictionary);
1557}
1558
1559#pragma mark - Misc Dynamic Runtime Utils
1560
1561const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) {
1562  Protocol *protocol =
1563      objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol));
1564  NSCAssert(protocol, @"Missing GPBMessageSignatureProtocol");
1565  struct objc_method_description description =
1566      protocol_getMethodDescription(protocol, selector, NO, instanceSel);
1567  NSCAssert(description.name != Nil && description.types != nil,
1568            @"Missing method for selector %@", NSStringFromSelector(selector));
1569  return description.types;
1570}
1571
1572#pragma mark - Text Format Support
1573
1574static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) {
1575  [destStr appendString:@"\""];
1576  NSUInteger len = [toPrint length];
1577  for (NSUInteger i = 0; i < len; ++i) {
1578    unichar aChar = [toPrint characterAtIndex:i];
1579    switch (aChar) {
1580      case '\n': [destStr appendString:@"\\n"];  break;
1581      case '\r': [destStr appendString:@"\\r"];  break;
1582      case '\t': [destStr appendString:@"\\t"];  break;
1583      case '\"': [destStr appendString:@"\\\""]; break;
1584      case '\'': [destStr appendString:@"\\\'"]; break;
1585      case '\\': [destStr appendString:@"\\\\"]; break;
1586      default:
1587        // This differs slightly from the C++ code in that the C++ doesn't
1588        // generate UTF8; it looks at the string in UTF8, but escapes every
1589        // byte > 0x7E.
1590        if (aChar < 0x20) {
1591          [destStr appendFormat:@"\\%d%d%d",
1592                                (aChar / 64), ((aChar % 64) / 8), (aChar % 8)];
1593        } else {
1594          [destStr appendFormat:@"%C", aChar];
1595        }
1596        break;
1597    }
1598  }
1599  [destStr appendString:@"\""];
1600}
1601
1602static void AppendBufferAsString(NSData *buffer, NSMutableString *destStr) {
1603  const char *src = (const char *)[buffer bytes];
1604  size_t srcLen = [buffer length];
1605  [destStr appendString:@"\""];
1606  for (const char *srcEnd = src + srcLen; src < srcEnd; src++) {
1607    switch (*src) {
1608      case '\n': [destStr appendString:@"\\n"];  break;
1609      case '\r': [destStr appendString:@"\\r"];  break;
1610      case '\t': [destStr appendString:@"\\t"];  break;
1611      case '\"': [destStr appendString:@"\\\""]; break;
1612      case '\'': [destStr appendString:@"\\\'"]; break;
1613      case '\\': [destStr appendString:@"\\\\"]; break;
1614      default:
1615        if (isprint(*src)) {
1616          [destStr appendFormat:@"%c", *src];
1617        } else {
1618          // NOTE: doing hex means you have to worry about the letter after
1619          // the hex being another hex char and forcing that to be escaped, so
1620          // use octal to keep it simple.
1621          [destStr appendFormat:@"\\%03o", (uint8_t)(*src)];
1622        }
1623        break;
1624    }
1625  }
1626  [destStr appendString:@"\""];
1627}
1628
1629static void AppendTextFormatForMapMessageField(
1630    id map, GPBFieldDescriptor *field, NSMutableString *toStr,
1631    NSString *lineIndent, NSString *fieldName, NSString *lineEnding) {
1632  GPBDataType keyDataType = field.mapKeyDataType;
1633  GPBDataType valueDataType = GPBGetFieldDataType(field);
1634  BOOL isMessageValue = GPBDataTypeIsMessage(valueDataType);
1635
1636  NSString *msgStartFirst =
1637      [NSString stringWithFormat:@"%@%@ {%@\n", lineIndent, fieldName, lineEnding];
1638  NSString *msgStart =
1639      [NSString stringWithFormat:@"%@%@ {\n", lineIndent, fieldName];
1640  NSString *msgEnd = [NSString stringWithFormat:@"%@}\n", lineIndent];
1641
1642  NSString *keyLine = [NSString stringWithFormat:@"%@  key: ", lineIndent];
1643  NSString *valueLine = [NSString stringWithFormat:@"%@  value%s ", lineIndent,
1644                                                   (isMessageValue ? "" : ":")];
1645
1646  __block BOOL isFirst = YES;
1647
1648  if ((keyDataType == GPBDataTypeString) &&
1649      GPBDataTypeIsObject(valueDataType)) {
1650    // map is an NSDictionary.
1651    NSDictionary *dict = map;
1652    [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
1653      #pragma unused(stop)
1654      [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
1655      isFirst = NO;
1656
1657      [toStr appendString:keyLine];
1658      AppendStringEscaped(key, toStr);
1659      [toStr appendString:@"\n"];
1660
1661      [toStr appendString:valueLine];
1662#pragma clang diagnostic push
1663#pragma clang diagnostic ignored "-Wswitch-enum"
1664      switch (valueDataType) {
1665        case GPBDataTypeString:
1666          AppendStringEscaped(value, toStr);
1667          break;
1668
1669        case GPBDataTypeBytes:
1670          AppendBufferAsString(value, toStr);
1671          break;
1672
1673        case GPBDataTypeMessage:
1674          [toStr appendString:@"{\n"];
1675          NSString *subIndent = [lineIndent stringByAppendingString:@"    "];
1676          AppendTextFormatForMessage(value, toStr, subIndent);
1677          [toStr appendFormat:@"%@  }", lineIndent];
1678          break;
1679
1680        default:
1681          NSCAssert(NO, @"Can't happen");
1682          break;
1683      }
1684#pragma clang diagnostic pop
1685      [toStr appendString:@"\n"];
1686
1687      [toStr appendString:msgEnd];
1688    }];
1689  } else {
1690    // map is one of the GPB*Dictionary classes, type doesn't matter.
1691    GPBInt32Int32Dictionary *dict = map;
1692    [dict enumerateForTextFormat:^(id keyObj, id valueObj) {
1693      [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
1694      isFirst = NO;
1695
1696      // Key always is a NSString.
1697      if (keyDataType == GPBDataTypeString) {
1698        [toStr appendString:keyLine];
1699        AppendStringEscaped(keyObj, toStr);
1700        [toStr appendString:@"\n"];
1701      } else {
1702        [toStr appendFormat:@"%@%@\n", keyLine, keyObj];
1703      }
1704
1705      [toStr appendString:valueLine];
1706#pragma clang diagnostic push
1707#pragma clang diagnostic ignored "-Wswitch-enum"
1708      switch (valueDataType) {
1709        case GPBDataTypeString:
1710          AppendStringEscaped(valueObj, toStr);
1711          break;
1712
1713        case GPBDataTypeBytes:
1714          AppendBufferAsString(valueObj, toStr);
1715          break;
1716
1717        case GPBDataTypeMessage:
1718          [toStr appendString:@"{\n"];
1719          NSString *subIndent = [lineIndent stringByAppendingString:@"    "];
1720          AppendTextFormatForMessage(valueObj, toStr, subIndent);
1721          [toStr appendFormat:@"%@  }", lineIndent];
1722          break;
1723
1724        case GPBDataTypeEnum: {
1725          int32_t enumValue = [valueObj intValue];
1726          NSString *valueStr = nil;
1727          GPBEnumDescriptor *descriptor = field.enumDescriptor;
1728          if (descriptor) {
1729            valueStr = [descriptor textFormatNameForValue:enumValue];
1730          }
1731          if (valueStr) {
1732            [toStr appendString:valueStr];
1733          } else {
1734            [toStr appendFormat:@"%d", enumValue];
1735          }
1736          break;
1737        }
1738
1739        default:
1740          NSCAssert(valueDataType != GPBDataTypeGroup, @"Can't happen");
1741          // Everything else is a NSString.
1742          [toStr appendString:valueObj];
1743          break;
1744      }
1745#pragma clang diagnostic pop
1746      [toStr appendString:@"\n"];
1747
1748      [toStr appendString:msgEnd];
1749    }];
1750  }
1751}
1752
1753static void AppendTextFormatForMessageField(GPBMessage *message,
1754                                            GPBFieldDescriptor *field,
1755                                            NSMutableString *toStr,
1756                                            NSString *lineIndent) {
1757  id arrayOrMap;
1758  NSUInteger count;
1759  GPBFieldType fieldType = field.fieldType;
1760  switch (fieldType) {
1761    case GPBFieldTypeSingle:
1762      arrayOrMap = nil;
1763      count = (GPBGetHasIvarField(message, field) ? 1 : 0);
1764      break;
1765
1766    case GPBFieldTypeRepeated:
1767      // Will be NSArray or GPB*Array, type doesn't matter, they both
1768      // implement count.
1769      arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
1770      count = [(NSArray *)arrayOrMap count];
1771      break;
1772
1773    case GPBFieldTypeMap: {
1774      // Will be GPB*Dictionary or NSMutableDictionary, type doesn't matter,
1775      // they both implement count.
1776      arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
1777      count = [(NSDictionary *)arrayOrMap count];
1778      break;
1779    }
1780  }
1781
1782  if (count == 0) {
1783    // Nothing to print, out of here.
1784    return;
1785  }
1786
1787  NSString *lineEnding = @"";
1788
1789  // If the name can't be reversed or support for extra info was turned off,
1790  // this can return nil.
1791  NSString *fieldName = [field textFormatName];
1792  if ([fieldName length] == 0) {
1793    fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)];
1794    // If there is only one entry, put the objc name as a comment, other wise
1795    // add it before the repeated values.
1796    if (count > 1) {
1797      [toStr appendFormat:@"%@# %@\n", lineIndent, field.name];
1798    } else {
1799      lineEnding = [NSString stringWithFormat:@"  # %@", field.name];
1800    }
1801  }
1802
1803  if (fieldType == GPBFieldTypeMap) {
1804    AppendTextFormatForMapMessageField(arrayOrMap, field, toStr, lineIndent,
1805                                       fieldName, lineEnding);
1806    return;
1807  }
1808
1809  id array = arrayOrMap;
1810  const BOOL isRepeated = (array != nil);
1811
1812  GPBDataType fieldDataType = GPBGetFieldDataType(field);
1813  BOOL isMessageField = GPBDataTypeIsMessage(fieldDataType);
1814  for (NSUInteger j = 0; j < count; ++j) {
1815    // Start the line.
1816    [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName,
1817                        (isMessageField ? "" : ":")];
1818
1819    // The value.
1820    switch (fieldDataType) {
1821#define FIELD_CASE(GPBDATATYPE, CTYPE, REAL_TYPE, ...)                        \
1822  case GPBDataType##GPBDATATYPE: {                                            \
1823    CTYPE v = (isRepeated ? [(GPB##REAL_TYPE##Array *)array valueAtIndex:j]   \
1824                          : GPBGetMessage##REAL_TYPE##Field(message, field)); \
1825    [toStr appendFormat:__VA_ARGS__, v];                                      \
1826    break;                                                                    \
1827  }
1828
1829      FIELD_CASE(Int32, int32_t, Int32, @"%d")
1830      FIELD_CASE(SInt32, int32_t, Int32, @"%d")
1831      FIELD_CASE(SFixed32, int32_t, Int32, @"%d")
1832      FIELD_CASE(UInt32, uint32_t, UInt32, @"%u")
1833      FIELD_CASE(Fixed32, uint32_t, UInt32, @"%u")
1834      FIELD_CASE(Int64, int64_t, Int64, @"%lld")
1835      FIELD_CASE(SInt64, int64_t, Int64, @"%lld")
1836      FIELD_CASE(SFixed64, int64_t, Int64, @"%lld")
1837      FIELD_CASE(UInt64, uint64_t, UInt64, @"%llu")
1838      FIELD_CASE(Fixed64, uint64_t, UInt64, @"%llu")
1839      FIELD_CASE(Float, float, Float, @"%.*g", FLT_DIG)
1840      FIELD_CASE(Double, double, Double, @"%.*lg", DBL_DIG)
1841
1842#undef FIELD_CASE
1843
1844      case GPBDataTypeEnum: {
1845        int32_t v = (isRepeated ? [(GPBEnumArray *)array rawValueAtIndex:j]
1846                                : GPBGetMessageInt32Field(message, field));
1847        NSString *valueStr = nil;
1848        GPBEnumDescriptor *descriptor = field.enumDescriptor;
1849        if (descriptor) {
1850          valueStr = [descriptor textFormatNameForValue:v];
1851        }
1852        if (valueStr) {
1853          [toStr appendString:valueStr];
1854        } else {
1855          [toStr appendFormat:@"%d", v];
1856        }
1857        break;
1858      }
1859
1860      case GPBDataTypeBool: {
1861        BOOL v = (isRepeated ? [(GPBBoolArray *)array valueAtIndex:j]
1862                             : GPBGetMessageBoolField(message, field));
1863        [toStr appendString:(v ? @"true" : @"false")];
1864        break;
1865      }
1866
1867      case GPBDataTypeString: {
1868        NSString *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
1869                                  : GPBGetMessageStringField(message, field));
1870        AppendStringEscaped(v, toStr);
1871        break;
1872      }
1873
1874      case GPBDataTypeBytes: {
1875        NSData *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
1876                                : GPBGetMessageBytesField(message, field));
1877        AppendBufferAsString(v, toStr);
1878        break;
1879      }
1880
1881      case GPBDataTypeGroup:
1882      case GPBDataTypeMessage: {
1883        GPBMessage *v =
1884            (isRepeated ? [(NSArray *)array objectAtIndex:j]
1885                        : GPBGetObjectIvarWithField(message, field));
1886        [toStr appendFormat:@"{%@\n", lineEnding];
1887        NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
1888        AppendTextFormatForMessage(v, toStr, subIndent);
1889        [toStr appendFormat:@"%@}", lineIndent];
1890        lineEnding = @"";
1891        break;
1892      }
1893
1894    }  // switch(fieldDataType)
1895
1896    // End the line.
1897    [toStr appendFormat:@"%@\n", lineEnding];
1898
1899  }  // for(count)
1900}
1901
1902static void AppendTextFormatForMessageExtensionRange(GPBMessage *message,
1903                                                     NSArray *activeExtensions,
1904                                                     GPBExtensionRange range,
1905                                                     NSMutableString *toStr,
1906                                                     NSString *lineIndent) {
1907  uint32_t start = range.start;
1908  uint32_t end = range.end;
1909  for (GPBExtensionDescriptor *extension in activeExtensions) {
1910    uint32_t fieldNumber = extension.fieldNumber;
1911    if (fieldNumber < start) {
1912      // Not there yet.
1913      continue;
1914    }
1915    if (fieldNumber >= end) {
1916      // Done.
1917      break;
1918    }
1919
1920    id rawExtValue = [message getExtension:extension];
1921    BOOL isRepeated = extension.isRepeated;
1922
1923    NSUInteger numValues = 1;
1924    NSString *lineEnding = @"";
1925    if (isRepeated) {
1926      numValues = [(NSArray *)rawExtValue count];
1927    }
1928
1929    NSString *singletonName = extension.singletonName;
1930    if (numValues == 1) {
1931      lineEnding = [NSString stringWithFormat:@"  # [%@]", singletonName];
1932    } else {
1933      [toStr appendFormat:@"%@# [%@]\n", lineIndent, singletonName];
1934    }
1935
1936    GPBDataType extDataType = extension.dataType;
1937    for (NSUInteger j = 0; j < numValues; ++j) {
1938      id curValue = (isRepeated ? [rawExtValue objectAtIndex:j] : rawExtValue);
1939
1940      // Start the line.
1941      [toStr appendFormat:@"%@%u%s ", lineIndent, fieldNumber,
1942                          (GPBDataTypeIsMessage(extDataType) ? "" : ":")];
1943
1944      // The value.
1945      switch (extDataType) {
1946#define FIELD_CASE(GPBDATATYPE, CTYPE, NUMSELECTOR, ...) \
1947  case GPBDataType##GPBDATATYPE: {                       \
1948    CTYPE v = [(NSNumber *)curValue NUMSELECTOR];        \
1949    [toStr appendFormat:__VA_ARGS__, v];                 \
1950    break;                                               \
1951  }
1952
1953        FIELD_CASE(Int32, int32_t, intValue, @"%d")
1954        FIELD_CASE(SInt32, int32_t, intValue, @"%d")
1955        FIELD_CASE(SFixed32, int32_t, unsignedIntValue, @"%d")
1956        FIELD_CASE(UInt32, uint32_t, unsignedIntValue, @"%u")
1957        FIELD_CASE(Fixed32, uint32_t, unsignedIntValue, @"%u")
1958        FIELD_CASE(Int64, int64_t, longLongValue, @"%lld")
1959        FIELD_CASE(SInt64, int64_t, longLongValue, @"%lld")
1960        FIELD_CASE(SFixed64, int64_t, longLongValue, @"%lld")
1961        FIELD_CASE(UInt64, uint64_t, unsignedLongLongValue, @"%llu")
1962        FIELD_CASE(Fixed64, uint64_t, unsignedLongLongValue, @"%llu")
1963        FIELD_CASE(Float, float, floatValue, @"%.*g", FLT_DIG)
1964        FIELD_CASE(Double, double, doubleValue, @"%.*lg", DBL_DIG)
1965        // TODO: Add a comment with the enum name from enum descriptors
1966        // (might not be real value, so leave it as a comment, ObjC compiler
1967        // name mangles differently).  Doesn't look like we actually generate
1968        // an enum descriptor reference like we do for normal fields, so this
1969        // will take a compiler change.
1970        FIELD_CASE(Enum, int32_t, intValue, @"%d")
1971
1972#undef FIELD_CASE
1973
1974        case GPBDataTypeBool:
1975          [toStr appendString:([(NSNumber *)curValue boolValue] ? @"true"
1976                                                                : @"false")];
1977          break;
1978
1979        case GPBDataTypeString:
1980          AppendStringEscaped(curValue, toStr);
1981          break;
1982
1983        case GPBDataTypeBytes:
1984          AppendBufferAsString((NSData *)curValue, toStr);
1985          break;
1986
1987        case GPBDataTypeGroup:
1988        case GPBDataTypeMessage: {
1989          [toStr appendFormat:@"{%@\n", lineEnding];
1990          NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
1991          AppendTextFormatForMessage(curValue, toStr, subIndent);
1992          [toStr appendFormat:@"%@}", lineIndent];
1993          lineEnding = @"";
1994          break;
1995        }
1996
1997      }  // switch(extDataType)
1998
1999      // End the line.
2000      [toStr appendFormat:@"%@\n", lineEnding];
2001
2002    }  //  for(numValues)
2003
2004  }  // for..in(activeExtensions)
2005}
2006
2007static void AppendTextFormatForMessage(GPBMessage *message,
2008                                       NSMutableString *toStr,
2009                                       NSString *lineIndent) {
2010  GPBDescriptor *descriptor = [message descriptor];
2011  NSArray *fieldsArray = descriptor->fields_;
2012  NSUInteger fieldCount = fieldsArray.count;
2013  const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
2014  NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
2015  NSArray *activeExtensions = [[message extensionsCurrentlySet]
2016      sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
2017  for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
2018    if (i == fieldCount) {
2019      AppendTextFormatForMessageExtensionRange(
2020          message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
2021    } else if (j == extensionRangesCount ||
2022               GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
2023      AppendTextFormatForMessageField(message, fieldsArray[i++], toStr,
2024                                      lineIndent);
2025    } else {
2026      AppendTextFormatForMessageExtensionRange(
2027          message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
2028    }
2029  }
2030
2031  NSString *unknownFieldsStr =
2032      GPBTextFormatForUnknownFieldSet(message.unknownFields, lineIndent);
2033  if ([unknownFieldsStr length] > 0) {
2034    [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent];
2035    [toStr appendString:unknownFieldsStr];
2036  }
2037}
2038
2039NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) {
2040  if (message == nil) return @"";
2041  if (lineIndent == nil) lineIndent = @"";
2042
2043  NSMutableString *buildString = [NSMutableString string];
2044  AppendTextFormatForMessage(message, buildString, lineIndent);
2045  return buildString;
2046}
2047
2048NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet,
2049                                          NSString *lineIndent) {
2050  if (unknownSet == nil) return @"";
2051  if (lineIndent == nil) lineIndent = @"";
2052
2053  NSMutableString *result = [NSMutableString string];
2054  for (GPBUnknownField *field in [unknownSet sortedFields]) {
2055    int32_t fieldNumber = [field number];
2056
2057#define PRINT_LOOP(PROPNAME, CTYPE, FORMAT)                                   \
2058  [field.PROPNAME                                                             \
2059      enumerateValuesWithBlock:^(CTYPE value, NSUInteger idx, BOOL * stop) {  \
2060    _Pragma("unused(idx, stop)");                                             \
2061    [result                                                                   \
2062        appendFormat:@"%@%d: " #FORMAT "\n", lineIndent, fieldNumber, value]; \
2063      }];
2064
2065    PRINT_LOOP(varintList, uint64_t, %llu);
2066    PRINT_LOOP(fixed32List, uint32_t, 0x%X);
2067    PRINT_LOOP(fixed64List, uint64_t, 0x%llX);
2068
2069#undef PRINT_LOOP
2070
2071    // NOTE: C++ version of TextFormat tries to parse this as a message
2072    // and print that if it succeeds.
2073    for (NSData *data in field.lengthDelimitedList) {
2074      [result appendFormat:@"%@%d: ", lineIndent, fieldNumber];
2075      AppendBufferAsString(data, result);
2076      [result appendString:@"\n"];
2077    }
2078
2079    for (GPBUnknownFieldSet *subUnknownSet in field.groupList) {
2080      [result appendFormat:@"%@%d: {\n", lineIndent, fieldNumber];
2081      NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
2082      NSString *subUnknwonSetStr =
2083          GPBTextFormatForUnknownFieldSet(subUnknownSet, subIndent);
2084      [result appendString:subUnknwonSetStr];
2085      [result appendFormat:@"%@}\n", lineIndent];
2086    }
2087  }
2088  return result;
2089}
2090
2091// Helpers to decode a varint. Not using GPBCodedInputStream version because
2092// that needs a state object, and we don't want to create an input stream out
2093// of the data.
2094GPB_INLINE int8_t ReadRawByteFromData(const uint8_t **data) {
2095  int8_t result = *((int8_t *)(*data));
2096  ++(*data);
2097  return result;
2098}
2099
2100static int32_t ReadRawVarint32FromData(const uint8_t **data) {
2101  int8_t tmp = ReadRawByteFromData(data);
2102  if (tmp >= 0) {
2103    return tmp;
2104  }
2105  int32_t result = tmp & 0x7f;
2106  if ((tmp = ReadRawByteFromData(data)) >= 0) {
2107    result |= tmp << 7;
2108  } else {
2109    result |= (tmp & 0x7f) << 7;
2110    if ((tmp = ReadRawByteFromData(data)) >= 0) {
2111      result |= tmp << 14;
2112    } else {
2113      result |= (tmp & 0x7f) << 14;
2114      if ((tmp = ReadRawByteFromData(data)) >= 0) {
2115        result |= tmp << 21;
2116      } else {
2117        result |= (tmp & 0x7f) << 21;
2118        result |= (tmp = ReadRawByteFromData(data)) << 28;
2119        if (tmp < 0) {
2120          // Discard upper 32 bits.
2121          for (int i = 0; i < 5; i++) {
2122            if (ReadRawByteFromData(data) >= 0) {
2123              return result;
2124            }
2125          }
2126          [NSException raise:NSParseErrorException
2127                      format:@"Unable to read varint32"];
2128        }
2129      }
2130    }
2131  }
2132  return result;
2133}
2134
2135NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key,
2136                                  NSString *inputStr) {
2137  // decodData form:
2138  //  varint32: num entries
2139  //  for each entry:
2140  //    varint32: key
2141  //    bytes*: decode data
2142  //
2143  // decode data one of two forms:
2144  //  1: a \0 followed by the string followed by an \0
2145  //  2: bytecodes to transform an input into the right thing, ending with \0
2146  //
2147  // the bytes codes are of the form:
2148  //  0xabbccccc
2149  //  0x0 (all zeros), end.
2150  //  a - if set, add an underscore
2151  //  bb - 00 ccccc bytes as is
2152  //  bb - 10 ccccc upper first, as is on rest, ccccc byte total
2153  //  bb - 01 ccccc lower first, as is on rest, ccccc byte total
2154  //  bb - 11 ccccc all upper, ccccc byte total
2155
2156  if (!decodeData || !inputStr) {
2157    return nil;
2158  }
2159
2160  // Find key
2161  const uint8_t *scan = decodeData;
2162  int32_t numEntries = ReadRawVarint32FromData(&scan);
2163  BOOL foundKey = NO;
2164  while (!foundKey && (numEntries > 0)) {
2165    --numEntries;
2166    int32_t dataKey = ReadRawVarint32FromData(&scan);
2167    if (dataKey == key) {
2168      foundKey = YES;
2169    } else {
2170      // If it is a inlined string, it will start with \0; if it is bytecode it
2171      // will start with a code. So advance one (skipping the inline string
2172      // marker), and then loop until reaching the end marker (\0).
2173      ++scan;
2174      while (*scan != 0) ++scan;
2175      // Now move past the end marker.
2176      ++scan;
2177    }
2178  }
2179
2180  if (!foundKey) {
2181    return nil;
2182  }
2183
2184  // Decode
2185
2186  if (*scan == 0) {
2187    // Inline string. Move over the marker, and NSString can take it as
2188    // UTF8.
2189    ++scan;
2190    NSString *result = [NSString stringWithUTF8String:(const char *)scan];
2191    return result;
2192  }
2193
2194  NSMutableString *result =
2195      [NSMutableString stringWithCapacity:[inputStr length]];
2196
2197  const uint8_t kAddUnderscore  = 0b10000000;
2198  const uint8_t kOpMask         = 0b01100000;
2199  // const uint8_t kOpAsIs        = 0b00000000;
2200  const uint8_t kOpFirstUpper     = 0b01000000;
2201  const uint8_t kOpFirstLower     = 0b00100000;
2202  const uint8_t kOpAllUpper       = 0b01100000;
2203  const uint8_t kSegmentLenMask = 0b00011111;
2204
2205  NSInteger i = 0;
2206  for (; *scan != 0; ++scan) {
2207    if (*scan & kAddUnderscore) {
2208      [result appendString:@"_"];
2209    }
2210    int segmentLen = *scan & kSegmentLenMask;
2211    uint8_t decodeOp = *scan & kOpMask;
2212
2213    // Do op specific handling of the first character.
2214    if (decodeOp == kOpFirstUpper) {
2215      unichar c = [inputStr characterAtIndex:i];
2216      [result appendFormat:@"%c", toupper((char)c)];
2217      ++i;
2218      --segmentLen;
2219    } else if (decodeOp == kOpFirstLower) {
2220      unichar c = [inputStr characterAtIndex:i];
2221      [result appendFormat:@"%c", tolower((char)c)];
2222      ++i;
2223      --segmentLen;
2224    }
2225    // else op == kOpAsIs || op == kOpAllUpper
2226
2227    // Now pull over the rest of the length for this segment.
2228    for (int x = 0; x < segmentLen; ++x) {
2229      unichar c = [inputStr characterAtIndex:(i + x)];
2230      if (decodeOp == kOpAllUpper) {
2231        [result appendFormat:@"%c", toupper((char)c)];
2232      } else {
2233        [result appendFormat:@"%C", c];
2234      }
2235    }
2236    i += segmentLen;
2237  }
2238
2239  return result;
2240}
2241
2242#pragma mark Legacy methods old generated code calls
2243
2244// Shim from the older generated code into the runtime.
2245void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
2246                                      GPBFieldDescriptor *field,
2247                                      int32_t value,
2248                                      GPBFileSyntax syntax) {
2249#pragma unused(syntax)
2250  GPBSetMessageInt32Field(self, field, value);
2251}
2252
2253void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
2254                        int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) {
2255#pragma unused(fieldNumberNotToClear)
2256  #if defined(DEBUG) && DEBUG
2257    NSCAssert([[self descriptor] oneofWithName:oneof.name] == oneof,
2258              @"OneofDescriptor %@ doesn't appear to be for %@ messages.",
2259              oneof.name, [self class]);
2260    GPBFieldDescriptor *firstField = oneof->fields_[0];
2261    NSCAssert(firstField->description_->hasIndex == oneofHasIndex,
2262              @"Internal error, oneofHasIndex (%d) doesn't match (%d).",
2263              firstField->description_->hasIndex, oneofHasIndex);
2264  #endif
2265  GPBMaybeClearOneofPrivate(self, oneof, oneofHasIndex, 0);
2266}
2267
2268#pragma clang diagnostic pop
2269
2270#pragma mark Misc Helpers
2271
2272BOOL GPBClassHasSel(Class aClass, SEL sel) {
2273  // NOTE: We have to use class_copyMethodList, all other runtime method
2274  // lookups actually also resolve the method implementation and this
2275  // is called from within those methods.
2276
2277  BOOL result = NO;
2278  unsigned int methodCount = 0;
2279  Method *methodList = class_copyMethodList(aClass, &methodCount);
2280  for (unsigned int i = 0; i < methodCount; ++i) {
2281    SEL methodSelector = method_getName(methodList[i]);
2282    if (methodSelector == sel) {
2283      result = YES;
2284      break;
2285    }
2286  }
2287  free(methodList);
2288  return result;
2289}
2290