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