• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#import "GPBUtilities_PackagePrivate.h"
32
33#import <objc/runtime.h>
34
35#import "GPBArray_PackagePrivate.h"
36#import "GPBDescriptor_PackagePrivate.h"
37#import "GPBDictionary_PackagePrivate.h"
38#import "GPBMessage_PackagePrivate.h"
39#import "GPBUnknownField.h"
40#import "GPBUnknownFieldSet.h"
41
42// Direct access is use for speed, to avoid even internally declaring things
43// read/write, etc. The warning is enabled in the project to ensure code calling
44// protos can turn on -Wdirect-ivar-access without issues.
45#pragma clang diagnostic push
46#pragma clang diagnostic ignored "-Wdirect-ivar-access"
47
48static void AppendTextFormatForMessage(GPBMessage *message,
49                                       NSMutableString *toStr,
50                                       NSString *lineIndent);
51
52NSData *GPBEmptyNSData(void) {
53  static dispatch_once_t onceToken;
54  static NSData *defaultNSData = nil;
55  dispatch_once(&onceToken, ^{
56    defaultNSData = [[NSData alloc] init];
57  });
58  return defaultNSData;
59}
60
61void GPBCheckRuntimeVersionInternal(int32_t version) {
62  if (version != GOOGLE_PROTOBUF_OBJC_GEN_VERSION) {
63    [NSException raise:NSInternalInconsistencyException
64                format:@"Linked to ProtocolBuffer runtime version %d,"
65                       @" but code compiled with version %d!",
66                       GOOGLE_PROTOBUF_OBJC_GEN_VERSION, version];
67  }
68}
69
70BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber) {
71  GPBDescriptor *descriptor = [self descriptor];
72  GPBFieldDescriptor *field = [descriptor fieldWithNumber:fieldNumber];
73  return GPBMessageHasFieldSet(self, field);
74}
75
76BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field) {
77  if (self == nil || field == nil) return NO;
78
79  // Repeated/Map don't use the bit, they check the count.
80  if (GPBFieldIsMapOrArray(field)) {
81    // Array/map type doesn't matter, since GPB*Array/NSArray and
82    // GPB*Dictionary/NSDictionary all support -count;
83    NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
84    return (arrayOrMap.count > 0);
85  } else {
86    return GPBGetHasIvarField(self, field);
87  }
88}
89
90void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field) {
91  // If not set, nothing to do.
92  if (!GPBGetHasIvarField(self, field)) {
93    return;
94  }
95
96  if (GPBFieldStoresObject(field)) {
97    // Object types are handled slightly differently, they need to be released.
98    uint8_t *storage = (uint8_t *)self->messageStorage_;
99    id *typePtr = (id *)&storage[field->description_->offset];
100    [*typePtr release];
101    *typePtr = nil;
102  } else {
103    // POD types just need to clear the has bit as the Get* method will
104    // fetch the default when needed.
105  }
106  GPBSetHasIvarField(self, field, NO);
107}
108
109BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) {
110  NSCAssert(self->messageStorage_ != NULL,
111            @"%@: All messages should have storage (from init)",
112            [self class]);
113  if (idx < 0) {
114    NSCAssert(fieldNumber != 0, @"Invalid field number.");
115    BOOL hasIvar = (self->messageStorage_->_has_storage_[-idx] == fieldNumber);
116    return hasIvar;
117  } else {
118    NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
119    uint32_t byteIndex = idx / 32;
120    uint32_t bitMask = (1 << (idx % 32));
121    BOOL hasIvar =
122        (self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO;
123    return hasIvar;
124  }
125}
126
127uint32_t GPBGetHasOneof(GPBMessage *self, int32_t idx) {
128  NSCAssert(idx < 0, @"%@: invalid index (%d) for oneof.",
129            [self class], idx);
130  uint32_t result = self->messageStorage_->_has_storage_[-idx];
131  return result;
132}
133
134void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber,
135                   BOOL value) {
136  if (idx < 0) {
137    NSCAssert(fieldNumber != 0, @"Invalid field number.");
138    uint32_t *has_storage = self->messageStorage_->_has_storage_;
139    has_storage[-idx] = (value ? fieldNumber : 0);
140  } else {
141    NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
142    uint32_t *has_storage = self->messageStorage_->_has_storage_;
143    uint32_t byte = idx / 32;
144    uint32_t bitMask = (1 << (idx % 32));
145    if (value) {
146      has_storage[byte] |= bitMask;
147    } else {
148      has_storage[byte] &= ~bitMask;
149    }
150  }
151}
152
153void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
154                        int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) {
155  uint32_t fieldNumberSet = GPBGetHasOneof(self, oneofHasIndex);
156  if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) {
157    // Do nothing/nothing set in the oneof.
158    return;
159  }
160
161  // Like GPBClearMessageField(), free the memory if an objecttype is set,
162  // pod types don't need to do anything.
163  GPBFieldDescriptor *fieldSet = [oneof fieldWithNumber:fieldNumberSet];
164  NSCAssert(fieldSet,
165            @"%@: oneof set to something (%u) not in the oneof?",
166            [self class], fieldNumberSet);
167  if (fieldSet && GPBFieldStoresObject(fieldSet)) {
168    uint8_t *storage = (uint8_t *)self->messageStorage_;
169    id *typePtr = (id *)&storage[fieldSet->description_->offset];
170    [*typePtr release];
171    *typePtr = nil;
172  }
173
174  // Set to nothing stored in the oneof.
175  // (field number doesn't matter since setting to nothing).
176  GPBSetHasIvar(self, oneofHasIndex, 1, NO);
177}
178
179#pragma mark - IVar accessors
180
181//%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE)
182//%TYPE GPBGetMessage##NAME##Field(GPBMessage *self,
183//% TYPE$S            NAME$S       GPBFieldDescriptor *field) {
184//%  if (GPBGetHasIvarField(self, field)) {
185//%    uint8_t *storage = (uint8_t *)self->messageStorage_;
186//%    TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
187//%    return *typePtr;
188//%  } else {
189//%    return field.defaultValue.value##NAME;
190//%  }
191//%}
192//%
193//%// Only exists for public api, no core code should use this.
194//%void GPBSetMessage##NAME##Field(GPBMessage *self,
195//%                   NAME$S     GPBFieldDescriptor *field,
196//%                   NAME$S     TYPE value) {
197//%  if (self == nil || field == nil) return;
198//%  GPBFileSyntax syntax = [self descriptor].file.syntax;
199//%  GPBSet##NAME##IvarWithFieldInternal(self, field, value, syntax);
200//%}
201//%
202//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self,
203//%            NAME$S                     GPBFieldDescriptor *field,
204//%            NAME$S                     TYPE value,
205//%            NAME$S                     GPBFileSyntax syntax) {
206//%  GPBOneofDescriptor *oneof = field->containingOneof_;
207//%  if (oneof) {
208//%    GPBMessageFieldDescription *fieldDesc = field->description_;
209//%    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
210//%  }
211//%  NSCAssert(self->messageStorage_ != NULL,
212//%            @"%@: All messages should have storage (from init)",
213//%            [self class]);
214//%#if defined(__clang_analyzer__)
215//%  if (self->messageStorage_ == NULL) return;
216//%#endif
217//%  uint8_t *storage = (uint8_t *)self->messageStorage_;
218//%  TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
219//%  *typePtr = value;
220//%  // proto2: any value counts as having been set; proto3, it
221//%  // has to be a non zero value.
222//%  BOOL hasValue =
223//%    (syntax == GPBFileSyntaxProto2) || (value != (TYPE)0);
224//%  GPBSetHasIvarField(self, field, hasValue);
225//%  GPBBecomeVisibleToAutocreator(self);
226//%}
227//%
228//%PDDM-DEFINE IVAR_ALIAS_DEFN_OBJECT(NAME, TYPE)
229//%// Only exists for public api, no core code should use this.
230//%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self,
231//% TYPE$S             NAME$S       GPBFieldDescriptor *field) {
232//%  return (TYPE *)GPBGetObjectIvarWithField(self, field);
233//%}
234//%
235//%// Only exists for public api, no core code should use this.
236//%void GPBSetMessage##NAME##Field(GPBMessage *self,
237//%                   NAME$S     GPBFieldDescriptor *field,
238//%                   NAME$S     TYPE *value) {
239//%  GPBSetObjectIvarWithField(self, field, (id)value);
240//%}
241//%
242
243// Object types are handled slightly differently, they need to be released
244// and retained.
245
246void GPBSetAutocreatedRetainedObjectIvarWithField(
247    GPBMessage *self, GPBFieldDescriptor *field,
248    id __attribute__((ns_consumed)) value) {
249  uint8_t *storage = (uint8_t *)self->messageStorage_;
250  id *typePtr = (id *)&storage[field->description_->offset];
251  NSCAssert(*typePtr == NULL, @"Can't set autocreated object more than once.");
252  *typePtr = value;
253}
254
255void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self,
256                                             GPBFieldDescriptor *field) {
257  if (GPBGetHasIvarField(self, field)) {
258    return;
259  }
260  uint8_t *storage = (uint8_t *)self->messageStorage_;
261  id *typePtr = (id *)&storage[field->description_->offset];
262  GPBMessage *oldValue = *typePtr;
263  *typePtr = NULL;
264  GPBClearMessageAutocreator(oldValue);
265  [oldValue release];
266}
267
268// This exists only for briging some aliased types, nothing else should use it.
269static void GPBSetObjectIvarWithField(GPBMessage *self,
270                                      GPBFieldDescriptor *field, id value) {
271  if (self == nil || field == nil) return;
272  GPBFileSyntax syntax = [self descriptor].file.syntax;
273  GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain],
274                                            syntax);
275}
276
277void GPBSetObjectIvarWithFieldInternal(GPBMessage *self,
278                                       GPBFieldDescriptor *field, id value,
279                                       GPBFileSyntax syntax) {
280  GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain],
281                                            syntax);
282}
283
284void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
285                                               GPBFieldDescriptor *field,
286                                               id value, GPBFileSyntax syntax) {
287  NSCAssert(self->messageStorage_ != NULL,
288            @"%@: All messages should have storage (from init)",
289            [self class]);
290#if defined(__clang_analyzer__)
291  if (self->messageStorage_ == NULL) return;
292#endif
293  GPBDataType fieldType = GPBGetFieldDataType(field);
294  BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
295  BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType);
296#ifdef DEBUG
297  if (value == nil && !isMapOrArray && !fieldIsMessage &&
298      field.hasDefaultValue) {
299    // Setting a message to nil is an obvious way to "clear" the value
300    // as there is no way to set a non-empty default value for messages.
301    //
302    // For Strings and Bytes that have default values set it is not clear what
303    // should be done when their value is set to nil. Is the intention just to
304    // clear the set value and reset to default, or is the intention to set the
305    // value to the empty string/data? Arguments can be made for both cases.
306    // 'nil' has been abused as a replacement for an empty string/data in ObjC.
307    // We decided to be consistent with all "object" types and clear the has
308    // field, and fall back on the default value. The warning below will only
309    // appear in debug, but the could should be changed so the intention is
310    // clear.
311    NSString *hasSel = NSStringFromSelector(field->hasOrCountSel_);
312    NSString *propName = field.name;
313    NSString *className = self.descriptor.name;
314    NSLog(@"warning: '%@.%@ = nil;' is not clearly defined for fields with "
315          @"default values. Please use '%@.%@ = %@' if you want to set it to "
316          @"empty, or call '%@.%@ = NO' to reset it to it's default value of "
317          @"'%@'. Defaulting to resetting default value.",
318          className, propName, className, propName,
319          (fieldType == GPBDataTypeString) ? @"@\"\"" : @"GPBEmptyNSData()",
320          className, hasSel, field.defaultValue.valueString);
321    // Note: valueString, depending on the type, it could easily be
322    // valueData/valueMessage.
323  }
324#endif  // DEBUG
325  if (!isMapOrArray) {
326    // Non repeated/map can be in an oneof, clear any existing value from the
327    // oneof.
328    GPBOneofDescriptor *oneof = field->containingOneof_;
329    if (oneof) {
330      GPBMessageFieldDescription *fieldDesc = field->description_;
331      GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
332    }
333    // Clear "has" if they are being set to nil.
334    BOOL setHasValue = (value != nil);
335    // Under proto3, Bytes & String fields get cleared by resetting them to
336    // their default (empty) values, so if they are set to something of length
337    // zero, they are being cleared.
338    if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage &&
339        ([value length] == 0)) {
340      setHasValue = NO;
341      value = nil;
342    }
343    GPBSetHasIvarField(self, field, setHasValue);
344  }
345  uint8_t *storage = (uint8_t *)self->messageStorage_;
346  id *typePtr = (id *)&storage[field->description_->offset];
347
348  id oldValue = *typePtr;
349
350  *typePtr = value;
351
352  if (oldValue) {
353    if (isMapOrArray) {
354      if (field.fieldType == GPBFieldTypeRepeated) {
355        // If the old array was autocreated by us, then clear it.
356        if (GPBDataTypeIsObject(fieldType)) {
357          GPBAutocreatedArray *autoArray = oldValue;
358          if (autoArray->_autocreator == self) {
359            autoArray->_autocreator = nil;
360          }
361        } else {
362          // Type doesn't matter, it is a GPB*Array.
363          GPBInt32Array *gpbArray = oldValue;
364          if (gpbArray->_autocreator == self) {
365            gpbArray->_autocreator = nil;
366          }
367        }
368      } else { // GPBFieldTypeMap
369        // If the old map was autocreated by us, then clear it.
370        if ((field.mapKeyDataType == GPBDataTypeString) &&
371            GPBDataTypeIsObject(fieldType)) {
372          GPBAutocreatedDictionary *autoDict = oldValue;
373          if (autoDict->_autocreator == self) {
374            autoDict->_autocreator = nil;
375          }
376        } else {
377          // Type doesn't matter, it is a GPB*Dictionary.
378          GPBInt32Int32Dictionary *gpbDict = oldValue;
379          if (gpbDict->_autocreator == self) {
380            gpbDict->_autocreator = nil;
381          }
382        }
383      }
384    } else if (fieldIsMessage) {
385      // If the old message value was autocreated by us, then clear it.
386      GPBMessage *oldMessageValue = oldValue;
387      if (GPBWasMessageAutocreatedBy(oldMessageValue, self)) {
388        GPBClearMessageAutocreator(oldMessageValue);
389      }
390    }
391    [oldValue release];
392  }
393
394  GPBBecomeVisibleToAutocreator(self);
395}
396
397id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
398                                         GPBFieldDescriptor *field) {
399  if (self->messageStorage_ == nil) {
400    return nil;
401  }
402  uint8_t *storage = (uint8_t *)self->messageStorage_;
403  id *typePtr = (id *)&storage[field->description_->offset];
404  return *typePtr;
405}
406
407id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
408  NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here");
409  if (GPBGetHasIvarField(self, field)) {
410    uint8_t *storage = (uint8_t *)self->messageStorage_;
411    id *typePtr = (id *)&storage[field->description_->offset];
412    return *typePtr;
413  }
414  // Not set...
415
416  // Non messages (string/data), get their default.
417  if (!GPBFieldDataTypeIsMessage(field)) {
418    return field.defaultValue.valueMessage;
419  }
420
421  GPBPrepareReadOnlySemaphore(self);
422  dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
423  GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
424  if (!result) {
425    // For non repeated messages, create the object, set it and return it.
426    // This object will not initially be visible via GPBGetHasIvar, so
427    // we save its creator so it can become visible if it's mutated later.
428    result = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
429    GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result);
430  }
431  dispatch_semaphore_signal(self->readOnlySemaphore_);
432  return result;
433}
434
435// Only exists for public api, no core code should use this.
436int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
437  GPBFileSyntax syntax = [self descriptor].file.syntax;
438  return GPBGetEnumIvarWithFieldInternal(self, field, syntax);
439}
440
441int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
442                                        GPBFieldDescriptor *field,
443                                        GPBFileSyntax syntax) {
444  int32_t result = GPBGetMessageInt32Field(self, field);
445  // If this is presevering unknown enums, make sure the value is valid before
446  // returning it.
447  if (GPBHasPreservingUnknownEnumSemantics(syntax) &&
448      ![field isValidEnumValue:result]) {
449    result = kGPBUnrecognizedEnumeratorValue;
450  }
451  return result;
452}
453
454// Only exists for public api, no core code should use this.
455void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
456                            int32_t value) {
457  GPBFileSyntax syntax = [self descriptor].file.syntax;
458  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
459}
460
461void GPBSetEnumIvarWithFieldInternal(GPBMessage *self,
462                                     GPBFieldDescriptor *field, int32_t value,
463                                     GPBFileSyntax syntax) {
464  // Don't allow in unknown values.  Proto3 can use the Raw method.
465  if (![field isValidEnumValue:value]) {
466    [NSException raise:NSInvalidArgumentException
467                format:@"%@.%@: Attempt to set an unknown enum value (%d)",
468                       [self class], field.name, value];
469  }
470  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
471}
472
473// Only exists for public api, no core code should use this.
474int32_t GPBGetMessageRawEnumField(GPBMessage *self,
475                                  GPBFieldDescriptor *field) {
476  int32_t result = GPBGetMessageInt32Field(self, field);
477  return result;
478}
479
480// Only exists for public api, no core code should use this.
481void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field,
482                               int32_t value) {
483  GPBFileSyntax syntax = [self descriptor].file.syntax;
484  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
485}
486
487BOOL GPBGetMessageBoolField(GPBMessage *self,
488                            GPBFieldDescriptor *field) {
489  if (GPBGetHasIvarField(self, field)) {
490    // Bools are stored in the has bits to avoid needing explicit space in the
491    // storage structure.
492    // (the field number passed to the HasIvar helper doesn't really matter
493    // since the offset is never negative)
494    GPBMessageFieldDescription *fieldDesc = field->description_;
495    return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number);
496  } else {
497    return field.defaultValue.valueBool;
498  }
499}
500
501// Only exists for public api, no core code should use this.
502void GPBSetMessageBoolField(GPBMessage *self,
503                            GPBFieldDescriptor *field,
504                            BOOL value) {
505  if (self == nil || field == nil) return;
506  GPBFileSyntax syntax = [self descriptor].file.syntax;
507  GPBSetBoolIvarWithFieldInternal(self, field, value, syntax);
508}
509
510void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
511                                     GPBFieldDescriptor *field,
512                                     BOOL value,
513                                     GPBFileSyntax syntax) {
514  GPBMessageFieldDescription *fieldDesc = field->description_;
515  GPBOneofDescriptor *oneof = field->containingOneof_;
516  if (oneof) {
517    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
518  }
519
520  // Bools are stored in the has bits to avoid needing explicit space in the
521  // storage structure.
522  // (the field number passed to the HasIvar helper doesn't really matter since
523  // the offset is never negative)
524  GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value);
525
526  // proto2: any value counts as having been set; proto3, it
527  // has to be a non zero value.
528  BOOL hasValue =
529    (syntax == GPBFileSyntaxProto2) || (value != (BOOL)0);
530  GPBSetHasIvarField(self, field, hasValue);
531  GPBBecomeVisibleToAutocreator(self);
532}
533
534//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int32, int32_t)
535// This block of code is generated, do not edit it directly.
536
537int32_t GPBGetMessageInt32Field(GPBMessage *self,
538                                GPBFieldDescriptor *field) {
539  if (GPBGetHasIvarField(self, field)) {
540    uint8_t *storage = (uint8_t *)self->messageStorage_;
541    int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
542    return *typePtr;
543  } else {
544    return field.defaultValue.valueInt32;
545  }
546}
547
548// Only exists for public api, no core code should use this.
549void GPBSetMessageInt32Field(GPBMessage *self,
550                             GPBFieldDescriptor *field,
551                             int32_t value) {
552  if (self == nil || field == nil) return;
553  GPBFileSyntax syntax = [self descriptor].file.syntax;
554  GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
555}
556
557void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
558                                      GPBFieldDescriptor *field,
559                                      int32_t value,
560                                      GPBFileSyntax syntax) {
561  GPBOneofDescriptor *oneof = field->containingOneof_;
562  if (oneof) {
563    GPBMessageFieldDescription *fieldDesc = field->description_;
564    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
565  }
566  NSCAssert(self->messageStorage_ != NULL,
567            @"%@: All messages should have storage (from init)",
568            [self class]);
569#if defined(__clang_analyzer__)
570  if (self->messageStorage_ == NULL) return;
571#endif
572  uint8_t *storage = (uint8_t *)self->messageStorage_;
573  int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
574  *typePtr = value;
575  // proto2: any value counts as having been set; proto3, it
576  // has to be a non zero value.
577  BOOL hasValue =
578    (syntax == GPBFileSyntaxProto2) || (value != (int32_t)0);
579  GPBSetHasIvarField(self, field, hasValue);
580  GPBBecomeVisibleToAutocreator(self);
581}
582
583//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt32, uint32_t)
584// This block of code is generated, do not edit it directly.
585
586uint32_t GPBGetMessageUInt32Field(GPBMessage *self,
587                                  GPBFieldDescriptor *field) {
588  if (GPBGetHasIvarField(self, field)) {
589    uint8_t *storage = (uint8_t *)self->messageStorage_;
590    uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
591    return *typePtr;
592  } else {
593    return field.defaultValue.valueUInt32;
594  }
595}
596
597// Only exists for public api, no core code should use this.
598void GPBSetMessageUInt32Field(GPBMessage *self,
599                              GPBFieldDescriptor *field,
600                              uint32_t value) {
601  if (self == nil || field == nil) return;
602  GPBFileSyntax syntax = [self descriptor].file.syntax;
603  GPBSetUInt32IvarWithFieldInternal(self, field, value, syntax);
604}
605
606void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
607                                       GPBFieldDescriptor *field,
608                                       uint32_t value,
609                                       GPBFileSyntax syntax) {
610  GPBOneofDescriptor *oneof = field->containingOneof_;
611  if (oneof) {
612    GPBMessageFieldDescription *fieldDesc = field->description_;
613    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
614  }
615  NSCAssert(self->messageStorage_ != NULL,
616            @"%@: All messages should have storage (from init)",
617            [self class]);
618#if defined(__clang_analyzer__)
619  if (self->messageStorage_ == NULL) return;
620#endif
621  uint8_t *storage = (uint8_t *)self->messageStorage_;
622  uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
623  *typePtr = value;
624  // proto2: any value counts as having been set; proto3, it
625  // has to be a non zero value.
626  BOOL hasValue =
627    (syntax == GPBFileSyntaxProto2) || (value != (uint32_t)0);
628  GPBSetHasIvarField(self, field, hasValue);
629  GPBBecomeVisibleToAutocreator(self);
630}
631
632//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int64, int64_t)
633// This block of code is generated, do not edit it directly.
634
635int64_t GPBGetMessageInt64Field(GPBMessage *self,
636                                GPBFieldDescriptor *field) {
637  if (GPBGetHasIvarField(self, field)) {
638    uint8_t *storage = (uint8_t *)self->messageStorage_;
639    int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
640    return *typePtr;
641  } else {
642    return field.defaultValue.valueInt64;
643  }
644}
645
646// Only exists for public api, no core code should use this.
647void GPBSetMessageInt64Field(GPBMessage *self,
648                             GPBFieldDescriptor *field,
649                             int64_t value) {
650  if (self == nil || field == nil) return;
651  GPBFileSyntax syntax = [self descriptor].file.syntax;
652  GPBSetInt64IvarWithFieldInternal(self, field, value, syntax);
653}
654
655void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
656                                      GPBFieldDescriptor *field,
657                                      int64_t value,
658                                      GPBFileSyntax syntax) {
659  GPBOneofDescriptor *oneof = field->containingOneof_;
660  if (oneof) {
661    GPBMessageFieldDescription *fieldDesc = field->description_;
662    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
663  }
664  NSCAssert(self->messageStorage_ != NULL,
665            @"%@: All messages should have storage (from init)",
666            [self class]);
667#if defined(__clang_analyzer__)
668  if (self->messageStorage_ == NULL) return;
669#endif
670  uint8_t *storage = (uint8_t *)self->messageStorage_;
671  int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
672  *typePtr = value;
673  // proto2: any value counts as having been set; proto3, it
674  // has to be a non zero value.
675  BOOL hasValue =
676    (syntax == GPBFileSyntaxProto2) || (value != (int64_t)0);
677  GPBSetHasIvarField(self, field, hasValue);
678  GPBBecomeVisibleToAutocreator(self);
679}
680
681//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt64, uint64_t)
682// This block of code is generated, do not edit it directly.
683
684uint64_t GPBGetMessageUInt64Field(GPBMessage *self,
685                                  GPBFieldDescriptor *field) {
686  if (GPBGetHasIvarField(self, field)) {
687    uint8_t *storage = (uint8_t *)self->messageStorage_;
688    uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
689    return *typePtr;
690  } else {
691    return field.defaultValue.valueUInt64;
692  }
693}
694
695// Only exists for public api, no core code should use this.
696void GPBSetMessageUInt64Field(GPBMessage *self,
697                              GPBFieldDescriptor *field,
698                              uint64_t value) {
699  if (self == nil || field == nil) return;
700  GPBFileSyntax syntax = [self descriptor].file.syntax;
701  GPBSetUInt64IvarWithFieldInternal(self, field, value, syntax);
702}
703
704void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
705                                       GPBFieldDescriptor *field,
706                                       uint64_t value,
707                                       GPBFileSyntax syntax) {
708  GPBOneofDescriptor *oneof = field->containingOneof_;
709  if (oneof) {
710    GPBMessageFieldDescription *fieldDesc = field->description_;
711    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
712  }
713  NSCAssert(self->messageStorage_ != NULL,
714            @"%@: All messages should have storage (from init)",
715            [self class]);
716#if defined(__clang_analyzer__)
717  if (self->messageStorage_ == NULL) return;
718#endif
719  uint8_t *storage = (uint8_t *)self->messageStorage_;
720  uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
721  *typePtr = value;
722  // proto2: any value counts as having been set; proto3, it
723  // has to be a non zero value.
724  BOOL hasValue =
725    (syntax == GPBFileSyntaxProto2) || (value != (uint64_t)0);
726  GPBSetHasIvarField(self, field, hasValue);
727  GPBBecomeVisibleToAutocreator(self);
728}
729
730//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Float, float)
731// This block of code is generated, do not edit it directly.
732
733float GPBGetMessageFloatField(GPBMessage *self,
734                              GPBFieldDescriptor *field) {
735  if (GPBGetHasIvarField(self, field)) {
736    uint8_t *storage = (uint8_t *)self->messageStorage_;
737    float *typePtr = (float *)&storage[field->description_->offset];
738    return *typePtr;
739  } else {
740    return field.defaultValue.valueFloat;
741  }
742}
743
744// Only exists for public api, no core code should use this.
745void GPBSetMessageFloatField(GPBMessage *self,
746                             GPBFieldDescriptor *field,
747                             float value) {
748  if (self == nil || field == nil) return;
749  GPBFileSyntax syntax = [self descriptor].file.syntax;
750  GPBSetFloatIvarWithFieldInternal(self, field, value, syntax);
751}
752
753void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
754                                      GPBFieldDescriptor *field,
755                                      float value,
756                                      GPBFileSyntax syntax) {
757  GPBOneofDescriptor *oneof = field->containingOneof_;
758  if (oneof) {
759    GPBMessageFieldDescription *fieldDesc = field->description_;
760    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
761  }
762  NSCAssert(self->messageStorage_ != NULL,
763            @"%@: All messages should have storage (from init)",
764            [self class]);
765#if defined(__clang_analyzer__)
766  if (self->messageStorage_ == NULL) return;
767#endif
768  uint8_t *storage = (uint8_t *)self->messageStorage_;
769  float *typePtr = (float *)&storage[field->description_->offset];
770  *typePtr = value;
771  // proto2: any value counts as having been set; proto3, it
772  // has to be a non zero value.
773  BOOL hasValue =
774    (syntax == GPBFileSyntaxProto2) || (value != (float)0);
775  GPBSetHasIvarField(self, field, hasValue);
776  GPBBecomeVisibleToAutocreator(self);
777}
778
779//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Double, double)
780// This block of code is generated, do not edit it directly.
781
782double GPBGetMessageDoubleField(GPBMessage *self,
783                                GPBFieldDescriptor *field) {
784  if (GPBGetHasIvarField(self, field)) {
785    uint8_t *storage = (uint8_t *)self->messageStorage_;
786    double *typePtr = (double *)&storage[field->description_->offset];
787    return *typePtr;
788  } else {
789    return field.defaultValue.valueDouble;
790  }
791}
792
793// Only exists for public api, no core code should use this.
794void GPBSetMessageDoubleField(GPBMessage *self,
795                              GPBFieldDescriptor *field,
796                              double value) {
797  if (self == nil || field == nil) return;
798  GPBFileSyntax syntax = [self descriptor].file.syntax;
799  GPBSetDoubleIvarWithFieldInternal(self, field, value, syntax);
800}
801
802void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
803                                       GPBFieldDescriptor *field,
804                                       double value,
805                                       GPBFileSyntax syntax) {
806  GPBOneofDescriptor *oneof = field->containingOneof_;
807  if (oneof) {
808    GPBMessageFieldDescription *fieldDesc = field->description_;
809    GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
810  }
811  NSCAssert(self->messageStorage_ != NULL,
812            @"%@: All messages should have storage (from init)",
813            [self class]);
814#if defined(__clang_analyzer__)
815  if (self->messageStorage_ == NULL) return;
816#endif
817  uint8_t *storage = (uint8_t *)self->messageStorage_;
818  double *typePtr = (double *)&storage[field->description_->offset];
819  *typePtr = value;
820  // proto2: any value counts as having been set; proto3, it
821  // has to be a non zero value.
822  BOOL hasValue =
823    (syntax == GPBFileSyntaxProto2) || (value != (double)0);
824  GPBSetHasIvarField(self, field, hasValue);
825  GPBBecomeVisibleToAutocreator(self);
826}
827
828//%PDDM-EXPAND-END (6 expansions)
829
830// Aliases are function calls that are virtually the same.
831
832//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(String, NSString)
833// This block of code is generated, do not edit it directly.
834
835// Only exists for public api, no core code should use this.
836NSString *GPBGetMessageStringField(GPBMessage *self,
837                                   GPBFieldDescriptor *field) {
838  return (NSString *)GPBGetObjectIvarWithField(self, field);
839}
840
841// Only exists for public api, no core code should use this.
842void GPBSetMessageStringField(GPBMessage *self,
843                              GPBFieldDescriptor *field,
844                              NSString *value) {
845  GPBSetObjectIvarWithField(self, field, (id)value);
846}
847
848//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Bytes, NSData)
849// This block of code is generated, do not edit it directly.
850
851// Only exists for public api, no core code should use this.
852NSData *GPBGetMessageBytesField(GPBMessage *self,
853                                GPBFieldDescriptor *field) {
854  return (NSData *)GPBGetObjectIvarWithField(self, field);
855}
856
857// Only exists for public api, no core code should use this.
858void GPBSetMessageBytesField(GPBMessage *self,
859                             GPBFieldDescriptor *field,
860                             NSData *value) {
861  GPBSetObjectIvarWithField(self, field, (id)value);
862}
863
864//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Message, GPBMessage)
865// This block of code is generated, do not edit it directly.
866
867// Only exists for public api, no core code should use this.
868GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
869                                      GPBFieldDescriptor *field) {
870  return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
871}
872
873// Only exists for public api, no core code should use this.
874void GPBSetMessageMessageField(GPBMessage *self,
875                               GPBFieldDescriptor *field,
876                               GPBMessage *value) {
877  GPBSetObjectIvarWithField(self, field, (id)value);
878}
879
880//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Group, GPBMessage)
881// This block of code is generated, do not edit it directly.
882
883// Only exists for public api, no core code should use this.
884GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
885                                    GPBFieldDescriptor *field) {
886  return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
887}
888
889// Only exists for public api, no core code should use this.
890void GPBSetMessageGroupField(GPBMessage *self,
891                             GPBFieldDescriptor *field,
892                             GPBMessage *value) {
893  GPBSetObjectIvarWithField(self, field, (id)value);
894}
895
896//%PDDM-EXPAND-END (4 expansions)
897
898// GPBGetMessageRepeatedField is defined in GPBMessage.m
899
900// Only exists for public api, no core code should use this.
901void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) {
902#if defined(DEBUG) && DEBUG
903  if (field.fieldType != GPBFieldTypeRepeated) {
904    [NSException raise:NSInvalidArgumentException
905                format:@"%@.%@ is not a repeated field.",
906                       [self class], field.name];
907  }
908  Class expectedClass = Nil;
909  switch (GPBGetFieldDataType(field)) {
910    case GPBDataTypeBool:
911      expectedClass = [GPBBoolArray class];
912      break;
913    case GPBDataTypeSFixed32:
914    case GPBDataTypeInt32:
915    case GPBDataTypeSInt32:
916      expectedClass = [GPBInt32Array class];
917      break;
918    case GPBDataTypeFixed32:
919    case GPBDataTypeUInt32:
920      expectedClass = [GPBUInt32Array class];
921      break;
922    case GPBDataTypeSFixed64:
923    case GPBDataTypeInt64:
924    case GPBDataTypeSInt64:
925      expectedClass = [GPBInt64Array class];
926      break;
927    case GPBDataTypeFixed64:
928    case GPBDataTypeUInt64:
929      expectedClass = [GPBUInt64Array class];
930      break;
931    case GPBDataTypeFloat:
932      expectedClass = [GPBFloatArray class];
933      break;
934    case GPBDataTypeDouble:
935      expectedClass = [GPBDoubleArray class];
936      break;
937    case GPBDataTypeBytes:
938    case GPBDataTypeString:
939    case GPBDataTypeMessage:
940    case GPBDataTypeGroup:
941      expectedClass = [NSMutableArray class];
942      break;
943    case GPBDataTypeEnum:
944      expectedClass = [GPBEnumArray class];
945      break;
946  }
947  if (array && ![array isKindOfClass:expectedClass]) {
948    [NSException raise:NSInvalidArgumentException
949                format:@"%@.%@: Expected %@ object, got %@.",
950                       [self class], field.name, expectedClass, [array class]];
951  }
952#endif
953  GPBSetObjectIvarWithField(self, field, array);
954}
955
956#if defined(DEBUG) && DEBUG
957static NSString *TypeToStr(GPBDataType dataType) {
958  switch (dataType) {
959    case GPBDataTypeBool:
960      return @"Bool";
961    case GPBDataTypeSFixed32:
962    case GPBDataTypeInt32:
963    case GPBDataTypeSInt32:
964      return @"Int32";
965    case GPBDataTypeFixed32:
966    case GPBDataTypeUInt32:
967      return @"UInt32";
968    case GPBDataTypeSFixed64:
969    case GPBDataTypeInt64:
970    case GPBDataTypeSInt64:
971      return @"Int64";
972    case GPBDataTypeFixed64:
973    case GPBDataTypeUInt64:
974      return @"UInt64";
975    case GPBDataTypeFloat:
976      return @"Float";
977    case GPBDataTypeDouble:
978      return @"Double";
979    case GPBDataTypeBytes:
980    case GPBDataTypeString:
981    case GPBDataTypeMessage:
982    case GPBDataTypeGroup:
983      return @"Object";
984    case GPBDataTypeEnum:
985      return @"Bool";
986  }
987}
988#endif
989
990// GPBGetMessageMapField is defined in GPBMessage.m
991
992// Only exists for public api, no core code should use this.
993void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
994                           id dictionary) {
995#if defined(DEBUG) && DEBUG
996  if (field.fieldType != GPBFieldTypeMap) {
997    [NSException raise:NSInvalidArgumentException
998                format:@"%@.%@ is not a map<> field.",
999                       [self class], field.name];
1000  }
1001  if (dictionary) {
1002    GPBDataType keyDataType = field.mapKeyDataType;
1003    GPBDataType valueDataType = GPBGetFieldDataType(field);
1004    NSString *keyStr = TypeToStr(keyDataType);
1005    NSString *valueStr = TypeToStr(valueDataType);
1006    if (keyDataType == GPBDataTypeString) {
1007      keyStr = @"String";
1008    }
1009    Class expectedClass = Nil;
1010    if ((keyDataType == GPBDataTypeString) &&
1011        GPBDataTypeIsObject(valueDataType)) {
1012      expectedClass = [NSMutableDictionary class];
1013    } else {
1014      NSString *className =
1015          [NSString stringWithFormat:@"GPB%@%@Dictionary", keyStr, valueStr];
1016      expectedClass = NSClassFromString(className);
1017      NSCAssert(expectedClass, @"Missing a class (%@)?", expectedClass);
1018    }
1019    if (![dictionary isKindOfClass:expectedClass]) {
1020      [NSException raise:NSInvalidArgumentException
1021                  format:@"%@.%@: Expected %@ object, got %@.",
1022                         [self class], field.name, expectedClass,
1023                         [dictionary class]];
1024    }
1025  }
1026#endif
1027  GPBSetObjectIvarWithField(self, field, dictionary);
1028}
1029
1030#pragma mark - Misc Dynamic Runtime Utils
1031
1032const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) {
1033  Protocol *protocol =
1034      objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol));
1035  struct objc_method_description description =
1036      protocol_getMethodDescription(protocol, selector, NO, instanceSel);
1037  return description.types;
1038}
1039
1040#pragma mark - Text Format Support
1041
1042static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) {
1043  [destStr appendString:@"\""];
1044  NSUInteger len = [toPrint length];
1045  for (NSUInteger i = 0; i < len; ++i) {
1046    unichar aChar = [toPrint characterAtIndex:i];
1047    switch (aChar) {
1048      case '\n': [destStr appendString:@"\\n"];  break;
1049      case '\r': [destStr appendString:@"\\r"];  break;
1050      case '\t': [destStr appendString:@"\\t"];  break;
1051      case '\"': [destStr appendString:@"\\\""]; break;
1052      case '\'': [destStr appendString:@"\\\'"]; break;
1053      case '\\': [destStr appendString:@"\\\\"]; break;
1054      default:
1055        [destStr appendFormat:@"%C", aChar];
1056        break;
1057    }
1058  }
1059  [destStr appendString:@"\""];
1060}
1061
1062static void AppendBufferAsString(NSData *buffer, NSMutableString *destStr) {
1063  const char *src = (const char *)[buffer bytes];
1064  size_t srcLen = [buffer length];
1065  [destStr appendString:@"\""];
1066  for (const char *srcEnd = src + srcLen; src < srcEnd; src++) {
1067    switch (*src) {
1068      case '\n': [destStr appendString:@"\\n"];  break;
1069      case '\r': [destStr appendString:@"\\r"];  break;
1070      case '\t': [destStr appendString:@"\\t"];  break;
1071      case '\"': [destStr appendString:@"\\\""]; break;
1072      case '\'': [destStr appendString:@"\\\'"]; break;
1073      case '\\': [destStr appendString:@"\\\\"]; break;
1074      default:
1075        if (isprint(*src)) {
1076          [destStr appendFormat:@"%c", *src];
1077        } else {
1078          // NOTE: doing hex means you have to worry about the letter after
1079          // the hex being another hex char and forcing that to be escaped, so
1080          // use octal to keep it simple.
1081          [destStr appendFormat:@"\\%03o", (uint8_t)(*src)];
1082        }
1083        break;
1084    }
1085  }
1086  [destStr appendString:@"\""];
1087}
1088
1089static void AppendTextFormatForMapMessageField(
1090    id map, GPBFieldDescriptor *field, NSMutableString *toStr,
1091    NSString *lineIndent, NSString *fieldName, NSString *lineEnding) {
1092  GPBDataType keyDataType = field.mapKeyDataType;
1093  GPBDataType valueDataType = GPBGetFieldDataType(field);
1094  BOOL isMessageValue = GPBDataTypeIsMessage(valueDataType);
1095
1096  NSString *msgStartFirst =
1097      [NSString stringWithFormat:@"%@%@ {%@\n", lineIndent, fieldName, lineEnding];
1098  NSString *msgStart =
1099      [NSString stringWithFormat:@"%@%@ {\n", lineIndent, fieldName];
1100  NSString *msgEnd = [NSString stringWithFormat:@"%@}\n", lineIndent];
1101
1102  NSString *keyLine = [NSString stringWithFormat:@"%@  key: ", lineIndent];
1103  NSString *valueLine = [NSString stringWithFormat:@"%@  value%s ", lineIndent,
1104                                                   (isMessageValue ? "" : ":")];
1105
1106  __block BOOL isFirst = YES;
1107
1108  if ((keyDataType == GPBDataTypeString) &&
1109      GPBDataTypeIsObject(valueDataType)) {
1110    // map is an NSDictionary.
1111    NSDictionary *dict = map;
1112    [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
1113      #pragma unused(stop)
1114      [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
1115      isFirst = NO;
1116
1117      [toStr appendString:keyLine];
1118      AppendStringEscaped(key, toStr);
1119      [toStr appendString:@"\n"];
1120
1121      [toStr appendString:valueLine];
1122#pragma clang diagnostic push
1123#pragma clang diagnostic ignored "-Wswitch-enum"
1124      switch (valueDataType) {
1125        case GPBDataTypeString:
1126          AppendStringEscaped(value, toStr);
1127          break;
1128
1129        case GPBDataTypeBytes:
1130          AppendBufferAsString(value, toStr);
1131          break;
1132
1133        case GPBDataTypeMessage:
1134          [toStr appendString:@"{\n"];
1135          NSString *subIndent = [lineIndent stringByAppendingString:@"    "];
1136          AppendTextFormatForMessage(value, toStr, subIndent);
1137          [toStr appendFormat:@"%@  }", lineIndent];
1138          break;
1139
1140        default:
1141          NSCAssert(NO, @"Can't happen");
1142          break;
1143      }
1144#pragma clang diagnostic pop
1145      [toStr appendString:@"\n"];
1146
1147      [toStr appendString:msgEnd];
1148    }];
1149  } else {
1150    // map is one of the GPB*Dictionary classes, type doesn't matter.
1151    GPBInt32Int32Dictionary *dict = map;
1152    [dict enumerateForTextFormat:^(id keyObj, id valueObj) {
1153      [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
1154      isFirst = NO;
1155
1156      // Key always is a NSString.
1157      if (keyDataType == GPBDataTypeString) {
1158        [toStr appendString:keyLine];
1159        AppendStringEscaped(keyObj, toStr);
1160        [toStr appendString:@"\n"];
1161      } else {
1162        [toStr appendFormat:@"%@%@\n", keyLine, keyObj];
1163      }
1164
1165      [toStr appendString:valueLine];
1166#pragma clang diagnostic push
1167#pragma clang diagnostic ignored "-Wswitch-enum"
1168      switch (valueDataType) {
1169        case GPBDataTypeString:
1170          AppendStringEscaped(valueObj, toStr);
1171          break;
1172
1173        case GPBDataTypeBytes:
1174          AppendBufferAsString(valueObj, toStr);
1175          break;
1176
1177        case GPBDataTypeMessage:
1178          [toStr appendString:@"{\n"];
1179          NSString *subIndent = [lineIndent stringByAppendingString:@"    "];
1180          AppendTextFormatForMessage(valueObj, toStr, subIndent);
1181          [toStr appendFormat:@"%@  }", lineIndent];
1182          break;
1183
1184        case GPBDataTypeEnum: {
1185          int32_t enumValue = [valueObj intValue];
1186          NSString *valueStr = nil;
1187          GPBEnumDescriptor *descriptor = field.enumDescriptor;
1188          if (descriptor) {
1189            valueStr = [descriptor textFormatNameForValue:enumValue];
1190          }
1191          if (valueStr) {
1192            [toStr appendString:valueStr];
1193          } else {
1194            [toStr appendFormat:@"%d", enumValue];
1195          }
1196          break;
1197        }
1198
1199        default:
1200          NSCAssert(valueDataType != GPBDataTypeGroup, @"Can't happen");
1201          // Everything else is a NSString.
1202          [toStr appendString:valueObj];
1203          break;
1204      }
1205#pragma clang diagnostic pop
1206      [toStr appendString:@"\n"];
1207
1208      [toStr appendString:msgEnd];
1209    }];
1210  }
1211}
1212
1213static void AppendTextFormatForMessageField(GPBMessage *message,
1214                                            GPBFieldDescriptor *field,
1215                                            NSMutableString *toStr,
1216                                            NSString *lineIndent) {
1217  id arrayOrMap;
1218  NSUInteger count;
1219  GPBFieldType fieldType = field.fieldType;
1220  switch (fieldType) {
1221    case GPBFieldTypeSingle:
1222      arrayOrMap = nil;
1223      count = (GPBGetHasIvarField(message, field) ? 1 : 0);
1224      break;
1225
1226    case GPBFieldTypeRepeated:
1227      // Will be NSArray or GPB*Array, type doesn't matter, they both
1228      // implement count.
1229      arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
1230      count = [(NSArray *)arrayOrMap count];
1231      break;
1232
1233    case GPBFieldTypeMap: {
1234      // Will be GPB*Dictionary or NSMutableDictionary, type doesn't matter,
1235      // they both implement count.
1236      arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
1237      count = [(NSDictionary *)arrayOrMap count];
1238      break;
1239    }
1240  }
1241
1242  if (count == 0) {
1243    // Nothing to print, out of here.
1244    return;
1245  }
1246
1247  NSString *lineEnding = @"";
1248
1249  // If the name can't be reversed or support for extra info was turned off,
1250  // this can return nil.
1251  NSString *fieldName = [field textFormatName];
1252  if ([fieldName length] == 0) {
1253    fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)];
1254    // If there is only one entry, put the objc name as a comment, other wise
1255    // add it before the repeated values.
1256    if (count > 1) {
1257      [toStr appendFormat:@"%@# %@\n", lineIndent, field.name];
1258    } else {
1259      lineEnding = [NSString stringWithFormat:@"  # %@", field.name];
1260    }
1261  }
1262
1263  if (fieldType == GPBFieldTypeMap) {
1264    AppendTextFormatForMapMessageField(arrayOrMap, field, toStr, lineIndent,
1265                                       fieldName, lineEnding);
1266    return;
1267  }
1268
1269  id array = arrayOrMap;
1270  const BOOL isRepeated = (array != nil);
1271
1272  GPBDataType fieldDataType = GPBGetFieldDataType(field);
1273  BOOL isMessageField = GPBDataTypeIsMessage(fieldDataType);
1274  for (NSUInteger j = 0; j < count; ++j) {
1275    // Start the line.
1276    [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName,
1277                        (isMessageField ? "" : ":")];
1278
1279    // The value.
1280    switch (fieldDataType) {
1281#define FIELD_CASE(GPBDATATYPE, CTYPE, REAL_TYPE, ...)                        \
1282  case GPBDataType##GPBDATATYPE: {                                            \
1283    CTYPE v = (isRepeated ? [(GPB##REAL_TYPE##Array *)array valueAtIndex:j]   \
1284                          : GPBGetMessage##REAL_TYPE##Field(message, field)); \
1285    [toStr appendFormat:__VA_ARGS__, v];                                      \
1286    break;                                                                    \
1287  }
1288
1289      FIELD_CASE(Int32, int32_t, Int32, @"%d")
1290      FIELD_CASE(SInt32, int32_t, Int32, @"%d")
1291      FIELD_CASE(SFixed32, int32_t, Int32, @"%d")
1292      FIELD_CASE(UInt32, uint32_t, UInt32, @"%u")
1293      FIELD_CASE(Fixed32, uint32_t, UInt32, @"%u")
1294      FIELD_CASE(Int64, int64_t, Int64, @"%lld")
1295      FIELD_CASE(SInt64, int64_t, Int64, @"%lld")
1296      FIELD_CASE(SFixed64, int64_t, Int64, @"%lld")
1297      FIELD_CASE(UInt64, uint64_t, UInt64, @"%llu")
1298      FIELD_CASE(Fixed64, uint64_t, UInt64, @"%llu")
1299      FIELD_CASE(Float, float, Float, @"%.*g", FLT_DIG)
1300      FIELD_CASE(Double, double, Double, @"%.*lg", DBL_DIG)
1301
1302#undef FIELD_CASE
1303
1304      case GPBDataTypeEnum: {
1305        int32_t v = (isRepeated ? [(GPBEnumArray *)array rawValueAtIndex:j]
1306                                : GPBGetMessageInt32Field(message, field));
1307        NSString *valueStr = nil;
1308        GPBEnumDescriptor *descriptor = field.enumDescriptor;
1309        if (descriptor) {
1310          valueStr = [descriptor textFormatNameForValue:v];
1311        }
1312        if (valueStr) {
1313          [toStr appendString:valueStr];
1314        } else {
1315          [toStr appendFormat:@"%d", v];
1316        }
1317        break;
1318      }
1319
1320      case GPBDataTypeBool: {
1321        BOOL v = (isRepeated ? [(GPBBoolArray *)array valueAtIndex:j]
1322                             : GPBGetMessageBoolField(message, field));
1323        [toStr appendString:(v ? @"true" : @"false")];
1324        break;
1325      }
1326
1327      case GPBDataTypeString: {
1328        NSString *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
1329                                  : GPBGetMessageStringField(message, field));
1330        AppendStringEscaped(v, toStr);
1331        break;
1332      }
1333
1334      case GPBDataTypeBytes: {
1335        NSData *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
1336                                : GPBGetMessageBytesField(message, field));
1337        AppendBufferAsString(v, toStr);
1338        break;
1339      }
1340
1341      case GPBDataTypeGroup:
1342      case GPBDataTypeMessage: {
1343        GPBMessage *v =
1344            (isRepeated ? [(NSArray *)array objectAtIndex:j]
1345                        : GPBGetObjectIvarWithField(message, field));
1346        [toStr appendFormat:@"{%@\n", lineEnding];
1347        NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
1348        AppendTextFormatForMessage(v, toStr, subIndent);
1349        [toStr appendFormat:@"%@}", lineIndent];
1350        lineEnding = @"";
1351        break;
1352      }
1353
1354    }  // switch(fieldDataType)
1355
1356    // End the line.
1357    [toStr appendFormat:@"%@\n", lineEnding];
1358
1359  }  // for(count)
1360}
1361
1362static void AppendTextFormatForMessageExtensionRange(GPBMessage *message,
1363                                                     NSArray *activeExtensions,
1364                                                     GPBExtensionRange range,
1365                                                     NSMutableString *toStr,
1366                                                     NSString *lineIndent) {
1367  uint32_t start = range.start;
1368  uint32_t end = range.end;
1369  for (GPBExtensionDescriptor *extension in activeExtensions) {
1370    uint32_t fieldNumber = extension.fieldNumber;
1371    if (fieldNumber < start) {
1372      // Not there yet.
1373      continue;
1374    }
1375    if (fieldNumber > end) {
1376      // Done.
1377      break;
1378    }
1379
1380    id rawExtValue = [message getExtension:extension];
1381    BOOL isRepeated = extension.isRepeated;
1382
1383    NSUInteger numValues = 1;
1384    NSString *lineEnding = @"";
1385    if (isRepeated) {
1386      numValues = [(NSArray *)rawExtValue count];
1387    }
1388
1389    NSString *singletonName = extension.singletonName;
1390    if (numValues == 1) {
1391      lineEnding = [NSString stringWithFormat:@"  # [%@]", singletonName];
1392    } else {
1393      [toStr appendFormat:@"%@# [%@]\n", lineIndent, singletonName];
1394    }
1395
1396    GPBDataType extDataType = extension.dataType;
1397    for (NSUInteger j = 0; j < numValues; ++j) {
1398      id curValue = (isRepeated ? [rawExtValue objectAtIndex:j] : rawExtValue);
1399
1400      // Start the line.
1401      [toStr appendFormat:@"%@%u%s ", lineIndent, fieldNumber,
1402                          (GPBDataTypeIsMessage(extDataType) ? "" : ":")];
1403
1404      // The value.
1405      switch (extDataType) {
1406#define FIELD_CASE(GPBDATATYPE, CTYPE, NUMSELECTOR, ...) \
1407  case GPBDataType##GPBDATATYPE: {                       \
1408    CTYPE v = [(NSNumber *)curValue NUMSELECTOR];        \
1409    [toStr appendFormat:__VA_ARGS__, v];                 \
1410    break;                                               \
1411  }
1412
1413        FIELD_CASE(Int32, int32_t, intValue, @"%d")
1414        FIELD_CASE(SInt32, int32_t, intValue, @"%d")
1415        FIELD_CASE(SFixed32, int32_t, unsignedIntValue, @"%d")
1416        FIELD_CASE(UInt32, uint32_t, unsignedIntValue, @"%u")
1417        FIELD_CASE(Fixed32, uint32_t, unsignedIntValue, @"%u")
1418        FIELD_CASE(Int64, int64_t, longLongValue, @"%lld")
1419        FIELD_CASE(SInt64, int64_t, longLongValue, @"%lld")
1420        FIELD_CASE(SFixed64, int64_t, longLongValue, @"%lld")
1421        FIELD_CASE(UInt64, uint64_t, unsignedLongLongValue, @"%llu")
1422        FIELD_CASE(Fixed64, uint64_t, unsignedLongLongValue, @"%llu")
1423        FIELD_CASE(Float, float, floatValue, @"%.*g", FLT_DIG)
1424        FIELD_CASE(Double, double, doubleValue, @"%.*lg", DBL_DIG)
1425        // TODO: Add a comment with the enum name from enum descriptors
1426        // (might not be real value, so leave it as a comment, ObjC compiler
1427        // name mangles differently).  Doesn't look like we actually generate
1428        // an enum descriptor reference like we do for normal fields, so this
1429        // will take a compiler change.
1430        FIELD_CASE(Enum, int32_t, intValue, @"%d")
1431
1432#undef FIELD_CASE
1433
1434        case GPBDataTypeBool:
1435          [toStr appendString:([(NSNumber *)curValue boolValue] ? @"true"
1436                                                                : @"false")];
1437          break;
1438
1439        case GPBDataTypeString:
1440          AppendStringEscaped(curValue, toStr);
1441          break;
1442
1443        case GPBDataTypeBytes:
1444          AppendBufferAsString((NSData *)curValue, toStr);
1445          break;
1446
1447        case GPBDataTypeGroup:
1448        case GPBDataTypeMessage: {
1449          [toStr appendFormat:@"{%@\n", lineEnding];
1450          NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
1451          AppendTextFormatForMessage(curValue, toStr, subIndent);
1452          [toStr appendFormat:@"%@}", lineIndent];
1453          lineEnding = @"";
1454          break;
1455        }
1456
1457      }  // switch(extDataType)
1458
1459    }  //  for(numValues)
1460
1461    // End the line.
1462    [toStr appendFormat:@"%@\n", lineEnding];
1463
1464  }  // for..in(activeExtensions)
1465}
1466
1467static void AppendTextFormatForMessage(GPBMessage *message,
1468                                       NSMutableString *toStr,
1469                                       NSString *lineIndent) {
1470  GPBDescriptor *descriptor = [message descriptor];
1471  NSArray *fieldsArray = descriptor->fields_;
1472  NSUInteger fieldCount = fieldsArray.count;
1473  const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
1474  NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
1475  NSArray *activeExtensions = [[message extensionsCurrentlySet]
1476      sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
1477  for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
1478    if (i == fieldCount) {
1479      AppendTextFormatForMessageExtensionRange(
1480          message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
1481    } else if (j == extensionRangesCount ||
1482               GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
1483      AppendTextFormatForMessageField(message, fieldsArray[i++], toStr,
1484                                      lineIndent);
1485    } else {
1486      AppendTextFormatForMessageExtensionRange(
1487          message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
1488    }
1489  }
1490
1491  NSString *unknownFieldsStr =
1492      GPBTextFormatForUnknownFieldSet(message.unknownFields, lineIndent);
1493  if ([unknownFieldsStr length] > 0) {
1494    [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent];
1495    [toStr appendString:unknownFieldsStr];
1496  }
1497}
1498
1499NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) {
1500  if (message == nil) return @"";
1501  if (lineIndent == nil) lineIndent = @"";
1502
1503  NSMutableString *buildString = [NSMutableString string];
1504  AppendTextFormatForMessage(message, buildString, lineIndent);
1505  return buildString;
1506}
1507
1508NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet,
1509                                          NSString *lineIndent) {
1510  if (unknownSet == nil) return @"";
1511  if (lineIndent == nil) lineIndent = @"";
1512
1513  NSMutableString *result = [NSMutableString string];
1514  for (GPBUnknownField *field in [unknownSet sortedFields]) {
1515    int32_t fieldNumber = [field number];
1516
1517#define PRINT_LOOP(PROPNAME, CTYPE, FORMAT)                                   \
1518  [field.PROPNAME                                                             \
1519      enumerateValuesWithBlock:^(CTYPE value, NSUInteger idx, BOOL * stop) {  \
1520    _Pragma("unused(idx, stop)");                                             \
1521    [result                                                                   \
1522        appendFormat:@"%@%d: " #FORMAT "\n", lineIndent, fieldNumber, value]; \
1523      }];
1524
1525    PRINT_LOOP(varintList, uint64_t, %llu);
1526    PRINT_LOOP(fixed32List, uint32_t, 0x%X);
1527    PRINT_LOOP(fixed64List, uint64_t, 0x%llX);
1528
1529#undef PRINT_LOOP
1530
1531    // NOTE: C++ version of TextFormat tries to parse this as a message
1532    // and print that if it succeeds.
1533    for (NSData *data in field.lengthDelimitedList) {
1534      [result appendFormat:@"%@%d: ", lineIndent, fieldNumber];
1535      AppendBufferAsString(data, result);
1536      [result appendString:@"\n"];
1537    }
1538
1539    for (GPBUnknownFieldSet *subUnknownSet in field.groupList) {
1540      [result appendFormat:@"%@%d: {\n", lineIndent, fieldNumber];
1541      NSString *subIndent = [lineIndent stringByAppendingString:@"  "];
1542      NSString *subUnknwonSetStr =
1543          GPBTextFormatForUnknownFieldSet(subUnknownSet, subIndent);
1544      [result appendString:subUnknwonSetStr];
1545      [result appendFormat:@"%@}\n", lineIndent];
1546    }
1547  }
1548  return result;
1549}
1550
1551// Helpers to decode a varint. Not using GPBCodedInputStream version because
1552// that needs a state object, and we don't want to create an input stream out
1553// of the data.
1554GPB_INLINE int8_t ReadRawByteFromData(const uint8_t **data) {
1555  int8_t result = *((int8_t *)(*data));
1556  ++(*data);
1557  return result;
1558}
1559
1560static int32_t ReadRawVarint32FromData(const uint8_t **data) {
1561  int8_t tmp = ReadRawByteFromData(data);
1562  if (tmp >= 0) {
1563    return tmp;
1564  }
1565  int32_t result = tmp & 0x7f;
1566  if ((tmp = ReadRawByteFromData(data)) >= 0) {
1567    result |= tmp << 7;
1568  } else {
1569    result |= (tmp & 0x7f) << 7;
1570    if ((tmp = ReadRawByteFromData(data)) >= 0) {
1571      result |= tmp << 14;
1572    } else {
1573      result |= (tmp & 0x7f) << 14;
1574      if ((tmp = ReadRawByteFromData(data)) >= 0) {
1575        result |= tmp << 21;
1576      } else {
1577        result |= (tmp & 0x7f) << 21;
1578        result |= (tmp = ReadRawByteFromData(data)) << 28;
1579        if (tmp < 0) {
1580          // Discard upper 32 bits.
1581          for (int i = 0; i < 5; i++) {
1582            if (ReadRawByteFromData(data) >= 0) {
1583              return result;
1584            }
1585          }
1586          [NSException raise:NSParseErrorException
1587                      format:@"Unable to read varint32"];
1588        }
1589      }
1590    }
1591  }
1592  return result;
1593}
1594
1595NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key,
1596                                  NSString *inputStr) {
1597  // decodData form:
1598  //  varint32: num entries
1599  //  for each entry:
1600  //    varint32: key
1601  //    bytes*: decode data
1602  //
1603  // decode data one of two forms:
1604  //  1: a \0 followed by the string followed by an \0
1605  //  2: bytecodes to transform an input into the right thing, ending with \0
1606  //
1607  // the bytes codes are of the form:
1608  //  0xabbccccc
1609  //  0x0 (all zeros), end.
1610  //  a - if set, add an underscore
1611  //  bb - 00 ccccc bytes as is
1612  //  bb - 10 ccccc upper first, as is on rest, ccccc byte total
1613  //  bb - 01 ccccc lower first, as is on rest, ccccc byte total
1614  //  bb - 11 ccccc all upper, ccccc byte total
1615
1616  if (!decodeData || !inputStr) {
1617    return nil;
1618  }
1619
1620  // Find key
1621  const uint8_t *scan = decodeData;
1622  int32_t numEntries = ReadRawVarint32FromData(&scan);
1623  BOOL foundKey = NO;
1624  while (!foundKey && (numEntries > 0)) {
1625    --numEntries;
1626    int32_t dataKey = ReadRawVarint32FromData(&scan);
1627    if (dataKey == key) {
1628      foundKey = YES;
1629    } else {
1630      // If it is a inlined string, it will start with \0; if it is bytecode it
1631      // will start with a code. So advance one (skipping the inline string
1632      // marker), and then loop until reaching the end marker (\0).
1633      ++scan;
1634      while (*scan != 0) ++scan;
1635      // Now move past the end marker.
1636      ++scan;
1637    }
1638  }
1639
1640  if (!foundKey) {
1641    return nil;
1642  }
1643
1644  // Decode
1645
1646  if (*scan == 0) {
1647    // Inline string. Move over the marker, and NSString can take it as
1648    // UTF8.
1649    ++scan;
1650    NSString *result = [NSString stringWithUTF8String:(const char *)scan];
1651    return result;
1652  }
1653
1654  NSMutableString *result =
1655      [NSMutableString stringWithCapacity:[inputStr length]];
1656
1657  const uint8_t kAddUnderscore  = 0b10000000;
1658  const uint8_t kOpMask         = 0b01100000;
1659  // const uint8_t kOpAsIs        = 0b00000000;
1660  const uint8_t kOpFirstUpper     = 0b01000000;
1661  const uint8_t kOpFirstLower     = 0b00100000;
1662  const uint8_t kOpAllUpper       = 0b01100000;
1663  const uint8_t kSegmentLenMask = 0b00011111;
1664
1665  NSInteger i = 0;
1666  for (; *scan != 0; ++scan) {
1667    if (*scan & kAddUnderscore) {
1668      [result appendString:@"_"];
1669    }
1670    int segmentLen = *scan & kSegmentLenMask;
1671    uint8_t decodeOp = *scan & kOpMask;
1672
1673    // Do op specific handling of the first character.
1674    if (decodeOp == kOpFirstUpper) {
1675      unichar c = [inputStr characterAtIndex:i];
1676      [result appendFormat:@"%c", toupper((char)c)];
1677      ++i;
1678      --segmentLen;
1679    } else if (decodeOp == kOpFirstLower) {
1680      unichar c = [inputStr characterAtIndex:i];
1681      [result appendFormat:@"%c", tolower((char)c)];
1682      ++i;
1683      --segmentLen;
1684    }
1685    // else op == kOpAsIs || op == kOpAllUpper
1686
1687    // Now pull over the rest of the length for this segment.
1688    for (int x = 0; x < segmentLen; ++x) {
1689      unichar c = [inputStr characterAtIndex:(i + x)];
1690      if (decodeOp == kOpAllUpper) {
1691        [result appendFormat:@"%c", toupper((char)c)];
1692      } else {
1693        [result appendFormat:@"%C", c];
1694      }
1695    }
1696    i += segmentLen;
1697  }
1698
1699  return result;
1700}
1701
1702#pragma clang diagnostic pop
1703
1704#pragma mark - GPBMessageSignatureProtocol
1705
1706// A series of selectors that are used solely to get @encoding values
1707// for them by the dynamic protobuf runtime code. An object using the protocol
1708// needs to be declared for the protocol to be valid at runtime.
1709@interface GPBMessageSignatureProtocol : NSObject<GPBMessageSignatureProtocol>
1710@end
1711@implementation GPBMessageSignatureProtocol
1712@end
1713