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