1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
9 #import "GPBMessage_PackagePrivate.h"
11 #import <Foundation/Foundation.h>
12 #import <objc/message.h>
13 #import <objc/runtime.h>
18 #import "GPBArray_PackagePrivate.h"
19 #import "GPBCodedInputStream.h"
20 #import "GPBCodedInputStream_PackagePrivate.h"
21 #import "GPBCodedOutputStream.h"
22 #import "GPBCodedOutputStream_PackagePrivate.h"
23 #import "GPBDescriptor.h"
24 #import "GPBDescriptor_PackagePrivate.h"
25 #import "GPBDictionary.h"
26 #import "GPBDictionary_PackagePrivate.h"
27 #import "GPBExtensionInternals.h"
28 #import "GPBExtensionRegistry.h"
29 #import "GPBRootObject.h"
30 #import "GPBRootObject_PackagePrivate.h"
31 #import "GPBUnknownField.h"
32 #import "GPBUnknownFields.h"
33 #import "GPBUnknownFields_PackagePrivate.h"
34 #import "GPBUtilities.h"
35 #import "GPBUtilities_PackagePrivate.h"
37 // TODO: Consider using on other functions to reduce bloat when
38 // some compiler optimizations are enabled.
39 #define GPB_NOINLINE __attribute__((noinline))
41 // Returns a new instance that was automatically created by |autocreator| for
43 static GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, GPBMessage *autocreator,
44 GPBFieldDescriptor *field)
45 __attribute__((ns_returns_retained));
47 // Direct access is use for speed, to avoid even internally declaring things
48 // read/write, etc. The warning is enabled in the project to ensure code calling
49 // protos can turn on -Wdirect-ivar-access without issues.
50 #pragma clang diagnostic push
51 #pragma clang diagnostic ignored "-Wdirect-ivar-access"
53 NSString *const GPBMessageErrorDomain = GPBNSStringifySymbol(GPBMessageErrorDomain);
55 NSString *const GPBErrorReasonKey = @"Reason";
57 static NSString *const kGPBDataCoderKey = @"GPBData";
59 // Length-delimited has a max size of 2GB, and thus messages do also.
60 // src/google/protobuf/message_lite also does this enforcement on the C++ side. Validation for
61 // parsing is done with GPBCodedInputStream; but for messages, it is less checks to do it within
62 // the message side since the input stream code calls these same bottlenecks.
63 // https://protobuf.dev/programming-guides/encoding/#cheat-sheet
64 static const size_t kMaximumMessageSize = 0x7fffffff;
66 NSString *const GPBMessageExceptionMessageTooLarge =
67 GPBNSStringifySymbol(GPBMessageExceptionMessageTooLarge);
72 // This is the base class for *all* messages generated, so any selector defined,
73 // *public* or *private* could end up colliding with a proto message field. So
74 // avoid using selectors that could match a property, use C functions to hide
78 @interface GPBMessage () {
80 NSMutableData *unknownFieldData_;
82 NSMutableDictionary *extensionMap_;
83 // Readonly access to autocreatedExtensionMap_ is protected via readOnlyLock_.
84 NSMutableDictionary *autocreatedExtensionMap_;
86 // If the object was autocreated, we remember the creator so that if we get
87 // mutated, we can inform the creator to make our field visible.
88 GPBMessage *autocreator_;
89 GPBFieldDescriptor *autocreatorField_;
90 GPBExtensionDescriptor *autocreatorExtension_;
92 // Messages can only be mutated from one thread. But some *readonly* operations modify internal
93 // state because they autocreate things. The autocreatedExtensionMap_ is one such structure.
94 // Access during readonly operations is protected via this lock.
96 // Long ago, this was an OSSpinLock, but then it came to light that there were issues for that on
98 // http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/
99 // https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
100 // It was changed to a dispatch_semaphore_t, but that has potential for priority inversion issues.
101 // The minOS versions are now high enough that os_unfair_lock can be used, and should provide
102 // all the support we need. For more information in the concurrency/locking space see:
103 // https://gist.github.com/tclementdev/6af616354912b0347cdf6db159c37057
104 // https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html
105 // https://developer.apple.com/videos/play/wwdc2017/706/
106 os_unfair_lock readOnlyLock_;
110 static id CreateArrayForField(GPBFieldDescriptor *field, GPBMessage *autocreator)
111 __attribute__((ns_returns_retained));
112 static id GetOrCreateArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
113 static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
114 static id CreateMapForField(GPBFieldDescriptor *field, GPBMessage *autocreator)
115 __attribute__((ns_returns_retained));
116 static id GetOrCreateMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
117 static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field);
118 static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap, NSZone *zone)
119 __attribute__((ns_returns_retained));
121 #if defined(DEBUG) && DEBUG
122 static NSError *MessageError(NSInteger code, NSDictionary *userInfo) {
123 return [NSError errorWithDomain:GPBMessageErrorDomain code:code userInfo:userInfo];
127 static NSError *ErrorFromException(NSException *exception) {
128 NSError *error = nil;
130 if ([exception.name isEqual:GPBCodedInputStreamException]) {
131 NSDictionary *exceptionInfo = exception.userInfo;
132 error = exceptionInfo[GPBCodedInputStreamUnderlyingErrorKey];
136 NSString *reason = exception.reason;
137 NSDictionary *userInfo = nil;
138 if ([reason length]) {
139 userInfo = @{GPBErrorReasonKey : reason};
142 error = [NSError errorWithDomain:GPBMessageErrorDomain
143 code:GPBMessageErrorCodeOther
149 // Helper to encode varints onto the mutable data, the max size need is 10 bytes.
151 static uint8_t *EncodeVarintU64(uint64_t val, uint8_t *ptr) {
153 uint8_t byte = val & 0x7fU;
155 if (val) byte |= 0x80U;
161 // Helper to encode varints onto the mutable data, the max size need is 5 bytes.
163 static uint8_t *EncodeVarintU32(uint32_t val, uint8_t *ptr) {
165 uint8_t byte = val & 0x7fU;
167 if (val) byte |= 0x80U;
173 // Helper to encode signed int32 values as varints onto the mutable data, the max size need is 10
176 static uint8_t *EncodeVarintS32(int32_t val, uint8_t *ptr) {
178 return EncodeVarintU32((uint32_t)val, ptr);
181 int64_t extended = val;
182 return EncodeVarintU64((uint64_t)extended, ptr);
187 static void AddUnknownFieldVarint32(GPBMessage *self, uint32_t fieldNumber, int32_t value) {
190 ptr = EncodeVarintU32(GPBWireFormatMakeTag(fieldNumber, GPBWireFormatVarint), ptr);
191 ptr = EncodeVarintS32(value, ptr);
193 if (self->unknownFieldData_ == nil) {
194 self->unknownFieldData_ = [[NSMutableData alloc] initWithCapacity:ptr - buf];
195 GPBBecomeVisibleToAutocreator(self);
197 [self->unknownFieldData_ appendBytes:buf length:ptr - buf];
201 static void AddUnknownFieldLengthDelimited(GPBMessage *self, uint32_t fieldNumber, NSData *value) {
204 ptr = EncodeVarintU32(GPBWireFormatMakeTag(fieldNumber, GPBWireFormatLengthDelimited), ptr);
205 ptr = EncodeVarintU64((uint64_t)value.length, ptr);
207 if (self->unknownFieldData_ == nil) {
208 self->unknownFieldData_ = [[NSMutableData alloc] initWithCapacity:(ptr - buf) + value.length];
209 GPBBecomeVisibleToAutocreator(self);
211 [self->unknownFieldData_ appendBytes:buf length:ptr - buf];
212 [self->unknownFieldData_ appendData:value];
216 static void AddUnknownMessageSetEntry(GPBMessage *self, uint32_t typeId, NSData *value) {
219 ptr = EncodeVarintU32(GPBWireFormatMessageSetItemTag, ptr);
220 ptr = EncodeVarintU32(GPBWireFormatMessageSetTypeIdTag, ptr);
221 ptr = EncodeVarintU32(typeId, ptr);
222 ptr = EncodeVarintU32(GPBWireFormatMessageSetMessageTag, ptr);
223 ptr = EncodeVarintU64((uint64_t)value.length, ptr);
224 uint8_t *split = ptr;
226 ptr = EncodeVarintU32(GPBWireFormatMessageSetItemEndTag, ptr);
229 if (self->unknownFieldData_ == nil) {
230 self->unknownFieldData_ = [[NSMutableData alloc] initWithCapacity:(end - buf) + value.length];
231 GPBBecomeVisibleToAutocreator(self);
233 [self->unknownFieldData_ appendBytes:buf length:split - buf];
234 [self->unknownFieldData_ appendData:value];
235 [self->unknownFieldData_ appendBytes:split length:end - split];
239 static void ParseUnknownField(GPBMessage *self, uint32_t tag, GPBCodedInputStream *input) {
242 ptr = EncodeVarintU32(tag, ptr); // All will need the tag
243 NSData *bytesToAppend = nil;
245 GPBCodedInputStreamState *state = &input->state_;
247 switch (GPBWireFormatGetTagWireType(tag)) {
248 case GPBWireFormatVarint: {
249 ptr = EncodeVarintU64(GPBCodedInputStreamReadUInt64(state), ptr);
252 case GPBWireFormatFixed64: {
253 uint64_t value = GPBCodedInputStreamReadFixed64(state);
254 *(ptr++) = (uint8_t)(value) & 0xFF;
255 *(ptr++) = (uint8_t)(value >> 8) & 0xFF;
256 *(ptr++) = (uint8_t)(value >> 16) & 0xFF;
257 *(ptr++) = (uint8_t)(value >> 24) & 0xFF;
258 *(ptr++) = (uint8_t)(value >> 32) & 0xFF;
259 *(ptr++) = (uint8_t)(value >> 40) & 0xFF;
260 *(ptr++) = (uint8_t)(value >> 48) & 0xFF;
261 *(ptr++) = (uint8_t)(value >> 56) & 0xFF;
264 case GPBWireFormatLengthDelimited: {
265 bytesToAppend = GPBCodedInputStreamReadRetainedBytes(state);
266 ptr = EncodeVarintU64((uint64_t)bytesToAppend.length, ptr);
269 case GPBWireFormatStartGroup: {
270 bytesToAppend = GPBCodedInputStreamReadRetainedBytesToEndGroupNoCopy(
271 state, GPBWireFormatGetTagFieldNumber(tag));
274 case GPBWireFormatEndGroup:
275 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidTag, @"Unexpected end-group tag");
277 case GPBWireFormatFixed32: {
278 uint32_t value = GPBCodedInputStreamReadFixed32(state);
279 *(ptr++) = (uint8_t)(value) & 0xFF;
280 *(ptr++) = (uint8_t)(value >> 8) & 0xFF;
281 *(ptr++) = (uint8_t)(value >> 16) & 0xFF;
282 *(ptr++) = (uint8_t)(value >> 24) & 0xFF;
287 if (self->unknownFieldData_ == nil) {
288 self->unknownFieldData_ =
289 [[NSMutableData alloc] initWithCapacity:(ptr - buf) + bytesToAppend.length];
290 GPBBecomeVisibleToAutocreator(self);
293 [self->unknownFieldData_ appendBytes:buf length:ptr - buf];
295 [self->unknownFieldData_ appendData:bytesToAppend];
296 [bytesToAppend release];
300 static void CheckExtension(GPBMessage *self, GPBExtensionDescriptor *extension) {
301 if (![self isKindOfClass:extension.containingMessageClass]) {
302 [NSException raise:NSInvalidArgumentException
303 format:@"Extension %@ used on wrong class (%@ instead of %@)",
304 extension.singletonName, [self class], extension.containingMessageClass];
308 static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap, NSZone *zone) {
309 if (extensionMap.count == 0) {
312 NSMutableDictionary *result =
313 [[NSMutableDictionary allocWithZone:zone] initWithCapacity:extensionMap.count];
315 for (GPBExtensionDescriptor *extension in extensionMap) {
316 id value = [extensionMap objectForKey:extension];
317 BOOL isMessageExtension = GPBExtensionIsMessage(extension);
319 if (extension.repeated) {
320 if (isMessageExtension) {
321 NSMutableArray *list = [[NSMutableArray alloc] initWithCapacity:[value count]];
322 for (GPBMessage *listValue in value) {
323 GPBMessage *copiedValue = [listValue copyWithZone:zone];
324 [list addObject:copiedValue];
325 [copiedValue release];
327 [result setObject:list forKey:extension];
330 NSMutableArray *copiedValue = [value mutableCopyWithZone:zone];
331 [result setObject:copiedValue forKey:extension];
332 [copiedValue release];
335 if (isMessageExtension) {
336 GPBMessage *copiedValue = [value copyWithZone:zone];
337 [result setObject:copiedValue forKey:extension];
338 [copiedValue release];
340 [result setObject:value forKey:extension];
348 static id CreateArrayForField(GPBFieldDescriptor *field, GPBMessage *autocreator) {
350 GPBDataType fieldDataType = GPBGetFieldDataType(field);
351 switch (fieldDataType) {
352 case GPBDataTypeBool:
353 result = [[GPBBoolArray alloc] init];
355 case GPBDataTypeFixed32:
356 case GPBDataTypeUInt32:
357 result = [[GPBUInt32Array alloc] init];
359 case GPBDataTypeInt32:
360 case GPBDataTypeSFixed32:
361 case GPBDataTypeSInt32:
362 result = [[GPBInt32Array alloc] init];
364 case GPBDataTypeFixed64:
365 case GPBDataTypeUInt64:
366 result = [[GPBUInt64Array alloc] init];
368 case GPBDataTypeInt64:
369 case GPBDataTypeSFixed64:
370 case GPBDataTypeSInt64:
371 result = [[GPBInt64Array alloc] init];
373 case GPBDataTypeFloat:
374 result = [[GPBFloatArray alloc] init];
376 case GPBDataTypeDouble:
377 result = [[GPBDoubleArray alloc] init];
380 case GPBDataTypeEnum:
381 result = [[GPBEnumArray alloc] initWithValidationFunction:field.enumDescriptor.enumVerifier];
384 case GPBDataTypeBytes:
385 case GPBDataTypeGroup:
386 case GPBDataTypeMessage:
387 case GPBDataTypeString:
389 result = [[GPBAutocreatedArray alloc] init];
391 result = [[NSMutableArray alloc] init];
397 if (GPBDataTypeIsObject(fieldDataType)) {
398 GPBAutocreatedArray *autoArray = result;
399 autoArray->_autocreator = autocreator;
401 GPBInt32Array *gpbArray = result;
402 gpbArray->_autocreator = autocreator;
409 static id CreateMapForField(GPBFieldDescriptor *field, GPBMessage *autocreator) {
411 GPBDataType keyDataType = field.mapKeyDataType;
412 GPBDataType valueDataType = GPBGetFieldDataType(field);
413 switch (keyDataType) {
414 case GPBDataTypeBool:
415 switch (valueDataType) {
416 case GPBDataTypeBool:
417 result = [[GPBBoolBoolDictionary alloc] init];
419 case GPBDataTypeFixed32:
420 case GPBDataTypeUInt32:
421 result = [[GPBBoolUInt32Dictionary alloc] init];
423 case GPBDataTypeInt32:
424 case GPBDataTypeSFixed32:
425 case GPBDataTypeSInt32:
426 result = [[GPBBoolInt32Dictionary alloc] init];
428 case GPBDataTypeFixed64:
429 case GPBDataTypeUInt64:
430 result = [[GPBBoolUInt64Dictionary alloc] init];
432 case GPBDataTypeInt64:
433 case GPBDataTypeSFixed64:
434 case GPBDataTypeSInt64:
435 result = [[GPBBoolInt64Dictionary alloc] init];
437 case GPBDataTypeFloat:
438 result = [[GPBBoolFloatDictionary alloc] init];
440 case GPBDataTypeDouble:
441 result = [[GPBBoolDoubleDictionary alloc] init];
443 case GPBDataTypeEnum:
444 result = [[GPBBoolEnumDictionary alloc]
445 initWithValidationFunction:field.enumDescriptor.enumVerifier];
447 case GPBDataTypeBytes:
448 case GPBDataTypeMessage:
449 case GPBDataTypeString:
450 result = [[GPBBoolObjectDictionary alloc] init];
452 case GPBDataTypeGroup:
453 NSCAssert(NO, @"shouldn't happen");
457 case GPBDataTypeFixed32:
458 case GPBDataTypeUInt32:
459 switch (valueDataType) {
460 case GPBDataTypeBool:
461 result = [[GPBUInt32BoolDictionary alloc] init];
463 case GPBDataTypeFixed32:
464 case GPBDataTypeUInt32:
465 result = [[GPBUInt32UInt32Dictionary alloc] init];
467 case GPBDataTypeInt32:
468 case GPBDataTypeSFixed32:
469 case GPBDataTypeSInt32:
470 result = [[GPBUInt32Int32Dictionary alloc] init];
472 case GPBDataTypeFixed64:
473 case GPBDataTypeUInt64:
474 result = [[GPBUInt32UInt64Dictionary alloc] init];
476 case GPBDataTypeInt64:
477 case GPBDataTypeSFixed64:
478 case GPBDataTypeSInt64:
479 result = [[GPBUInt32Int64Dictionary alloc] init];
481 case GPBDataTypeFloat:
482 result = [[GPBUInt32FloatDictionary alloc] init];
484 case GPBDataTypeDouble:
485 result = [[GPBUInt32DoubleDictionary alloc] init];
487 case GPBDataTypeEnum:
488 result = [[GPBUInt32EnumDictionary alloc]
489 initWithValidationFunction:field.enumDescriptor.enumVerifier];
491 case GPBDataTypeBytes:
492 case GPBDataTypeMessage:
493 case GPBDataTypeString:
494 result = [[GPBUInt32ObjectDictionary alloc] init];
496 case GPBDataTypeGroup:
497 NSCAssert(NO, @"shouldn't happen");
501 case GPBDataTypeInt32:
502 case GPBDataTypeSFixed32:
503 case GPBDataTypeSInt32:
504 switch (valueDataType) {
505 case GPBDataTypeBool:
506 result = [[GPBInt32BoolDictionary alloc] init];
508 case GPBDataTypeFixed32:
509 case GPBDataTypeUInt32:
510 result = [[GPBInt32UInt32Dictionary alloc] init];
512 case GPBDataTypeInt32:
513 case GPBDataTypeSFixed32:
514 case GPBDataTypeSInt32:
515 result = [[GPBInt32Int32Dictionary alloc] init];
517 case GPBDataTypeFixed64:
518 case GPBDataTypeUInt64:
519 result = [[GPBInt32UInt64Dictionary alloc] init];
521 case GPBDataTypeInt64:
522 case GPBDataTypeSFixed64:
523 case GPBDataTypeSInt64:
524 result = [[GPBInt32Int64Dictionary alloc] init];
526 case GPBDataTypeFloat:
527 result = [[GPBInt32FloatDictionary alloc] init];
529 case GPBDataTypeDouble:
530 result = [[GPBInt32DoubleDictionary alloc] init];
532 case GPBDataTypeEnum:
533 result = [[GPBInt32EnumDictionary alloc]
534 initWithValidationFunction:field.enumDescriptor.enumVerifier];
536 case GPBDataTypeBytes:
537 case GPBDataTypeMessage:
538 case GPBDataTypeString:
539 result = [[GPBInt32ObjectDictionary alloc] init];
541 case GPBDataTypeGroup:
542 NSCAssert(NO, @"shouldn't happen");
546 case GPBDataTypeFixed64:
547 case GPBDataTypeUInt64:
548 switch (valueDataType) {
549 case GPBDataTypeBool:
550 result = [[GPBUInt64BoolDictionary alloc] init];
552 case GPBDataTypeFixed32:
553 case GPBDataTypeUInt32:
554 result = [[GPBUInt64UInt32Dictionary alloc] init];
556 case GPBDataTypeInt32:
557 case GPBDataTypeSFixed32:
558 case GPBDataTypeSInt32:
559 result = [[GPBUInt64Int32Dictionary alloc] init];
561 case GPBDataTypeFixed64:
562 case GPBDataTypeUInt64:
563 result = [[GPBUInt64UInt64Dictionary alloc] init];
565 case GPBDataTypeInt64:
566 case GPBDataTypeSFixed64:
567 case GPBDataTypeSInt64:
568 result = [[GPBUInt64Int64Dictionary alloc] init];
570 case GPBDataTypeFloat:
571 result = [[GPBUInt64FloatDictionary alloc] init];
573 case GPBDataTypeDouble:
574 result = [[GPBUInt64DoubleDictionary alloc] init];
576 case GPBDataTypeEnum:
577 result = [[GPBUInt64EnumDictionary alloc]
578 initWithValidationFunction:field.enumDescriptor.enumVerifier];
580 case GPBDataTypeBytes:
581 case GPBDataTypeMessage:
582 case GPBDataTypeString:
583 result = [[GPBUInt64ObjectDictionary alloc] init];
585 case GPBDataTypeGroup:
586 NSCAssert(NO, @"shouldn't happen");
590 case GPBDataTypeInt64:
591 case GPBDataTypeSFixed64:
592 case GPBDataTypeSInt64:
593 switch (valueDataType) {
594 case GPBDataTypeBool:
595 result = [[GPBInt64BoolDictionary alloc] init];
597 case GPBDataTypeFixed32:
598 case GPBDataTypeUInt32:
599 result = [[GPBInt64UInt32Dictionary alloc] init];
601 case GPBDataTypeInt32:
602 case GPBDataTypeSFixed32:
603 case GPBDataTypeSInt32:
604 result = [[GPBInt64Int32Dictionary alloc] init];
606 case GPBDataTypeFixed64:
607 case GPBDataTypeUInt64:
608 result = [[GPBInt64UInt64Dictionary alloc] init];
610 case GPBDataTypeInt64:
611 case GPBDataTypeSFixed64:
612 case GPBDataTypeSInt64:
613 result = [[GPBInt64Int64Dictionary alloc] init];
615 case GPBDataTypeFloat:
616 result = [[GPBInt64FloatDictionary alloc] init];
618 case GPBDataTypeDouble:
619 result = [[GPBInt64DoubleDictionary alloc] init];
621 case GPBDataTypeEnum:
622 result = [[GPBInt64EnumDictionary alloc]
623 initWithValidationFunction:field.enumDescriptor.enumVerifier];
625 case GPBDataTypeBytes:
626 case GPBDataTypeMessage:
627 case GPBDataTypeString:
628 result = [[GPBInt64ObjectDictionary alloc] init];
630 case GPBDataTypeGroup:
631 NSCAssert(NO, @"shouldn't happen");
635 case GPBDataTypeString:
636 switch (valueDataType) {
637 case GPBDataTypeBool:
638 result = [[GPBStringBoolDictionary alloc] init];
640 case GPBDataTypeFixed32:
641 case GPBDataTypeUInt32:
642 result = [[GPBStringUInt32Dictionary alloc] init];
644 case GPBDataTypeInt32:
645 case GPBDataTypeSFixed32:
646 case GPBDataTypeSInt32:
647 result = [[GPBStringInt32Dictionary alloc] init];
649 case GPBDataTypeFixed64:
650 case GPBDataTypeUInt64:
651 result = [[GPBStringUInt64Dictionary alloc] init];
653 case GPBDataTypeInt64:
654 case GPBDataTypeSFixed64:
655 case GPBDataTypeSInt64:
656 result = [[GPBStringInt64Dictionary alloc] init];
658 case GPBDataTypeFloat:
659 result = [[GPBStringFloatDictionary alloc] init];
661 case GPBDataTypeDouble:
662 result = [[GPBStringDoubleDictionary alloc] init];
664 case GPBDataTypeEnum:
665 result = [[GPBStringEnumDictionary alloc]
666 initWithValidationFunction:field.enumDescriptor.enumVerifier];
668 case GPBDataTypeBytes:
669 case GPBDataTypeMessage:
670 case GPBDataTypeString:
672 result = [[GPBAutocreatedDictionary alloc] init];
674 result = [[NSMutableDictionary alloc] init];
677 case GPBDataTypeGroup:
678 NSCAssert(NO, @"shouldn't happen");
683 case GPBDataTypeFloat:
684 case GPBDataTypeDouble:
685 case GPBDataTypeEnum:
686 case GPBDataTypeBytes:
687 case GPBDataTypeGroup:
688 case GPBDataTypeMessage:
689 NSCAssert(NO, @"shouldn't happen");
694 if ((keyDataType == GPBDataTypeString) && GPBDataTypeIsObject(valueDataType)) {
695 GPBAutocreatedDictionary *autoDict = result;
696 autoDict->_autocreator = autocreator;
698 GPBInt32Int32Dictionary *gpbDict = result;
699 gpbDict->_autocreator = autocreator;
706 #if !defined(__clang_analyzer__)
707 // These functions are blocked from the analyzer because the analyzer sees the
708 // GPBSetRetainedObjectIvarWithFieldPrivate() call as consuming the array/map,
709 // so use of the array/map after the call returns is flagged as a use after
711 // But GPBSetRetainedObjectIvarWithFieldPrivate() is "consuming" the retain
712 // count be holding onto the object (it is transferring it), the object is
713 // still valid after returning from the call. The other way to avoid this
714 // would be to add a -retain/-autorelease, but that would force every
715 // repeated/map field parsed into the autorelease pool which is both a memory
716 // and performance hit.
718 static id GetOrCreateArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
719 id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
721 // No lock needed, this is called from places expecting to mutate
722 // so no threading protection is needed.
723 array = CreateArrayForField(field, nil);
724 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, array);
729 // This is like GPBGetObjectIvarWithField(), but for arrays, it should
730 // only be used to wire the method into the class.
731 static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
732 uint8_t *storage = (uint8_t *)self->messageStorage_;
733 _Atomic(id) *typePtr = (_Atomic(id) *)&storage[field->description_->offset];
734 id array = atomic_load(typePtr);
740 id autocreated = CreateArrayForField(field, self);
741 if (atomic_compare_exchange_strong(typePtr, &expected, autocreated)) {
742 // Value was set, return it.
746 // Some other thread set it, release the one created and return what got set.
747 if (GPBFieldDataTypeIsObject(field)) {
748 GPBAutocreatedArray *autoArray = autocreated;
749 autoArray->_autocreator = nil;
751 GPBInt32Array *gpbArray = autocreated;
752 gpbArray->_autocreator = nil;
754 [autocreated release];
758 static id GetOrCreateMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
759 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
761 // No lock needed, this is called from places expecting to mutate
762 // so no threading protection is needed.
763 dict = CreateMapForField(field, nil);
764 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, dict);
769 // This is like GPBGetObjectIvarWithField(), but for maps, it should
770 // only be used to wire the method into the class.
771 static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
772 uint8_t *storage = (uint8_t *)self->messageStorage_;
773 _Atomic(id) *typePtr = (_Atomic(id) *)&storage[field->description_->offset];
774 id dict = atomic_load(typePtr);
780 id autocreated = CreateMapForField(field, self);
781 if (atomic_compare_exchange_strong(typePtr, &expected, autocreated)) {
782 // Value was set, return it.
786 // Some other thread set it, release the one created and return what got set.
787 if ((field.mapKeyDataType == GPBDataTypeString) && GPBFieldDataTypeIsObject(field)) {
788 GPBAutocreatedDictionary *autoDict = autocreated;
789 autoDict->_autocreator = nil;
791 GPBInt32Int32Dictionary *gpbDict = autocreated;
792 gpbDict->_autocreator = nil;
794 [autocreated release];
798 #endif // !defined(__clang_analyzer__)
800 static void DecodeSingleValueFromInputStream(GPBExtensionDescriptor *extension,
801 GPBMessage *messageToGetExtension,
802 GPBCodedInputStream *input,
803 id<GPBExtensionRegistry> extensionRegistry,
804 BOOL isRepeated, GPBMessage *targetMessage) {
805 GPBExtensionDescription *description = extension->description_;
806 #if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
807 if (GPBDataTypeIsMessage(description->dataType)) {
808 NSCAssert(targetMessage != nil, @"Internal error: must have a target message");
810 NSCAssert(targetMessage == nil, @"Internal error: should not have a target message");
813 GPBCodedInputStreamState *state = &input->state_;
815 switch (description->dataType) {
816 case GPBDataTypeBool: {
817 BOOL value = GPBCodedInputStreamReadBool(state);
818 nsValue = [[NSNumber alloc] initWithBool:value];
821 case GPBDataTypeFixed32: {
822 uint32_t value = GPBCodedInputStreamReadFixed32(state);
823 nsValue = [[NSNumber alloc] initWithUnsignedInt:value];
826 case GPBDataTypeSFixed32: {
827 int32_t value = GPBCodedInputStreamReadSFixed32(state);
828 nsValue = [[NSNumber alloc] initWithInt:value];
831 case GPBDataTypeFloat: {
832 float value = GPBCodedInputStreamReadFloat(state);
833 nsValue = [[NSNumber alloc] initWithFloat:value];
836 case GPBDataTypeFixed64: {
837 uint64_t value = GPBCodedInputStreamReadFixed64(state);
838 nsValue = [[NSNumber alloc] initWithUnsignedLongLong:value];
841 case GPBDataTypeSFixed64: {
842 int64_t value = GPBCodedInputStreamReadSFixed64(state);
843 nsValue = [[NSNumber alloc] initWithLongLong:value];
846 case GPBDataTypeDouble: {
847 double value = GPBCodedInputStreamReadDouble(state);
848 nsValue = [[NSNumber alloc] initWithDouble:value];
851 case GPBDataTypeInt32: {
852 int32_t value = GPBCodedInputStreamReadInt32(state);
853 nsValue = [[NSNumber alloc] initWithInt:value];
856 case GPBDataTypeInt64: {
857 int64_t value = GPBCodedInputStreamReadInt64(state);
858 nsValue = [[NSNumber alloc] initWithLongLong:value];
861 case GPBDataTypeSInt32: {
862 int32_t value = GPBCodedInputStreamReadSInt32(state);
863 nsValue = [[NSNumber alloc] initWithInt:value];
866 case GPBDataTypeSInt64: {
867 int64_t value = GPBCodedInputStreamReadSInt64(state);
868 nsValue = [[NSNumber alloc] initWithLongLong:value];
871 case GPBDataTypeUInt32: {
872 uint32_t value = GPBCodedInputStreamReadUInt32(state);
873 nsValue = [[NSNumber alloc] initWithUnsignedInt:value];
876 case GPBDataTypeUInt64: {
877 uint64_t value = GPBCodedInputStreamReadUInt64(state);
878 nsValue = [[NSNumber alloc] initWithUnsignedLongLong:value];
881 case GPBDataTypeBytes:
882 nsValue = GPBCodedInputStreamReadRetainedBytes(state);
884 case GPBDataTypeString:
885 nsValue = GPBCodedInputStreamReadRetainedString(state);
887 case GPBDataTypeEnum: {
888 int32_t val = GPBCodedInputStreamReadEnum(&input->state_);
889 GPBEnumDescriptor *enumDescriptor = extension.enumDescriptor;
890 // If run with source generated before the closed enum support, all enums
891 // will be considers not closed, so casing to the enum type for a switch
892 // could cause things to fall off the end of a switch.
893 if (!enumDescriptor.isClosed || enumDescriptor.enumVerifier(val)) {
894 nsValue = [[NSNumber alloc] initWithInt:val];
896 AddUnknownFieldVarint32(messageToGetExtension, extension->description_->fieldNumber, val);
901 case GPBDataTypeGroup:
902 case GPBDataTypeMessage: {
903 if (description->dataType == GPBDataTypeGroup) {
904 [input readGroup:description->fieldNumber
905 message:targetMessage
906 extensionRegistry:extensionRegistry];
908 // description->dataType == GPBDataTypeMessage
909 #if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
910 NSCAssert(!GPBExtensionIsWireFormat(description),
911 @"Internal error: got a MessageSet extension when not expected.");
913 [input readMessage:targetMessage extensionRegistry:extensionRegistry];
915 // Nothing to add below since the caller provided the message (and added it).
923 [messageToGetExtension addExtension:extension value:nsValue];
925 [messageToGetExtension setExtension:extension value:nsValue];
931 static void ExtensionMergeFromInputStream(GPBExtensionDescriptor *extension, BOOL isPackedOnStream,
932 GPBCodedInputStream *input,
933 id<GPBExtensionRegistry> extensionRegistry,
934 GPBMessage *message) {
935 GPBExtensionDescription *description = extension->description_;
936 GPBCodedInputStreamState *state = &input->state_;
937 if (isPackedOnStream) {
938 #if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
939 NSCAssert(GPBExtensionIsRepeated(description), @"How was it packed if it isn't repeated?");
941 int32_t length = GPBCodedInputStreamReadInt32(state);
942 size_t limit = GPBCodedInputStreamPushLimit(state, length);
943 while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
944 DecodeSingleValueFromInputStream(extension, message, input, extensionRegistry,
945 /*isRepeated=*/YES, nil);
947 GPBCodedInputStreamPopLimit(state, limit);
949 BOOL isRepeated = GPBExtensionIsRepeated(description);
950 GPBMessage *targetMessage = nil;
951 if (GPBDataTypeIsMessage(description->dataType)) {
952 // For messages/groups create the targetMessage out here and add it to the objects graph in
953 // advance, that way if DecodeSingleValueFromInputStream() throw for a parsing issue, the
954 // object won't be leaked.
956 GPBDescriptor *descriptor = [extension.msgClass descriptor];
957 targetMessage = [[descriptor.messageClass alloc] init];
958 [message addExtension:extension value:targetMessage];
959 [targetMessage release];
961 targetMessage = [message getExistingExtension:extension];
962 if (!targetMessage) {
963 GPBDescriptor *descriptor = [extension.msgClass descriptor];
964 targetMessage = [[descriptor.messageClass alloc] init];
965 [message setExtension:extension value:targetMessage];
966 [targetMessage release];
970 DecodeSingleValueFromInputStream(extension, message, input, extensionRegistry, isRepeated,
975 static GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, GPBMessage *autocreator,
976 GPBFieldDescriptor *field) {
977 GPBMessage *message = [[msgClass alloc] init];
978 message->autocreator_ = autocreator;
979 message->autocreatorField_ = [field retain];
983 static GPBMessage *CreateMessageWithAutocreatorForExtension(Class msgClass, GPBMessage *autocreator,
984 GPBExtensionDescriptor *extension)
985 __attribute__((ns_returns_retained));
987 static GPBMessage *CreateMessageWithAutocreatorForExtension(Class msgClass, GPBMessage *autocreator,
988 GPBExtensionDescriptor *extension) {
989 GPBMessage *message = [[msgClass alloc] init];
990 message->autocreator_ = autocreator;
991 message->autocreatorExtension_ = [extension retain];
995 BOOL GPBWasMessageAutocreatedBy(GPBMessage *message, GPBMessage *parent) {
996 return (message->autocreator_ == parent);
999 void GPBBecomeVisibleToAutocreator(GPBMessage *self) {
1000 // Message objects that are implicitly created by accessing a message field
1001 // are initially not visible via the hasX selector. This method makes them
1003 if (self->autocreator_) {
1004 // This will recursively make all parent messages visible until it reaches a
1005 // super-creator that's visible.
1006 if (self->autocreatorField_) {
1007 GPBSetObjectIvarWithFieldPrivate(self->autocreator_, self->autocreatorField_, self);
1009 [self->autocreator_ setExtension:self->autocreatorExtension_ value:self];
1014 void GPBAutocreatedArrayModified(GPBMessage *self, id array) {
1015 // When one of our autocreated arrays adds elements, make it visible.
1016 GPBDescriptor *descriptor = [[self class] descriptor];
1017 for (GPBFieldDescriptor *field in descriptor->fields_) {
1018 if (field.fieldType == GPBFieldTypeRepeated) {
1019 id curArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1020 if (curArray == array) {
1021 if (GPBFieldDataTypeIsObject(field)) {
1022 GPBAutocreatedArray *autoArray = array;
1023 autoArray->_autocreator = nil;
1025 GPBInt32Array *gpbArray = array;
1026 gpbArray->_autocreator = nil;
1028 GPBBecomeVisibleToAutocreator(self);
1033 NSCAssert(NO, @"Unknown autocreated %@ for %@.", [array class], self);
1036 void GPBAutocreatedDictionaryModified(GPBMessage *self, id dictionary) {
1037 // When one of our autocreated dicts adds elements, make it visible.
1038 GPBDescriptor *descriptor = [[self class] descriptor];
1039 for (GPBFieldDescriptor *field in descriptor->fields_) {
1040 if (field.fieldType == GPBFieldTypeMap) {
1041 id curDict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1042 if (curDict == dictionary) {
1043 if ((field.mapKeyDataType == GPBDataTypeString) && GPBFieldDataTypeIsObject(field)) {
1044 GPBAutocreatedDictionary *autoDict = dictionary;
1045 autoDict->_autocreator = nil;
1047 GPBInt32Int32Dictionary *gpbDict = dictionary;
1048 gpbDict->_autocreator = nil;
1050 GPBBecomeVisibleToAutocreator(self);
1055 NSCAssert(NO, @"Unknown autocreated %@ for %@.", [dictionary class], self);
1058 void GPBClearMessageAutocreator(GPBMessage *self) {
1059 if ((self == nil) || !self->autocreator_) {
1063 #if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
1064 // Either the autocreator must have its "has" flag set to YES, or it must be
1065 // NO and not equal to ourselves.
1066 BOOL autocreatorHas =
1067 (self->autocreatorField_ ? GPBGetHasIvarField(self->autocreator_, self->autocreatorField_)
1068 : [self->autocreator_ hasExtension:self->autocreatorExtension_]);
1069 GPBMessage *autocreatorFieldValue =
1070 (self->autocreatorField_
1071 ? GPBGetObjectIvarWithFieldNoAutocreate(self->autocreator_, self->autocreatorField_)
1072 : [self->autocreator_->autocreatedExtensionMap_
1073 objectForKey:self->autocreatorExtension_]);
1074 NSCAssert(autocreatorHas || autocreatorFieldValue != self,
1075 @"Cannot clear autocreator because it still refers to self, self: %@.", self);
1077 #endif // DEBUG && !defined(NS_BLOCK_ASSERTIONS)
1079 self->autocreator_ = nil;
1080 [self->autocreatorField_ release];
1081 self->autocreatorField_ = nil;
1082 [self->autocreatorExtension_ release];
1083 self->autocreatorExtension_ = nil;
1086 @implementation GPBMessage
1088 + (void)initialize {
1089 Class pbMessageClass = [GPBMessage class];
1090 if ([self class] == pbMessageClass) {
1091 // This is here to start up the "base" class descriptor.
1093 // Message shares extension method resolving with GPBRootObject so insure
1094 // it is started up at the same time.
1095 (void)[GPBRootObject class];
1096 } else if ([self superclass] == pbMessageClass) {
1097 // This is here to start up all the "message" subclasses. Just needs to be
1098 // done for the messages, not any of the subclasses.
1099 // This must be done in initialize to enforce thread safety of start up of
1100 // the protocol buffer library.
1101 // Note: The generated code for -descriptor calls
1102 // +[GPBDescriptor allocDescriptorForClass:...], passing the GPBRootObject
1103 // subclass for the file. That call chain is what ensures that *Root class
1104 // is started up to support extension resolution off the message class
1105 // (+resolveClassMethod: below) in a thread safe manner.
1110 + (instancetype)allocWithZone:(NSZone *)zone {
1111 // Override alloc to allocate our classes with the additional storage
1112 // required for the instance variables.
1113 GPBDescriptor *descriptor = [self descriptor];
1114 return NSAllocateObject(self, descriptor->storageSize_, zone);
1117 + (instancetype)alloc {
1118 return [self allocWithZone:nil];
1121 + (GPBDescriptor *)descriptor {
1122 // This is thread safe because it is called from +initialize.
1123 static GPBDescriptor *descriptor = NULL;
1124 static GPBFileDescription fileDescription = {
1125 .package = "internal", .prefix = "", .syntax = GPBFileSyntaxProto2};
1127 descriptor = [GPBDescriptor
1128 allocDescriptorForClass:[GPBMessage class]
1129 messageName:@"GPBMessage"
1130 fileDescription:&fileDescription
1134 flags:(GPBDescriptorInitializationFlag_UsesClassRefs |
1135 GPBDescriptorInitializationFlag_Proto3OptionalKnown |
1136 GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
1141 + (instancetype)message {
1142 return [[[self alloc] init] autorelease];
1145 - (instancetype)init {
1146 if ((self = [super init])) {
1148 (GPBMessage_StoragePtr)(((uint8_t *)self) + class_getInstanceSize([self class]));
1149 readOnlyLock_ = OS_UNFAIR_LOCK_INIT;
1155 - (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr {
1156 return [self initWithData:data extensionRegistry:nil error:errorPtr];
1159 - (instancetype)initWithData:(NSData *)data
1160 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
1161 error:(NSError **)errorPtr {
1162 if ((self = [self init])) {
1163 if (![self mergeFromData:data extensionRegistry:extensionRegistry error:errorPtr]) {
1166 #if defined(DEBUG) && DEBUG
1167 } else if (!self.initialized) {
1171 *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
1179 - (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input
1180 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
1181 error:(NSError **)errorPtr {
1182 if ((self = [self init])) {
1184 [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry endingTag:0];
1188 } @catch (NSException *exception) {
1192 *errorPtr = ErrorFromException(exception);
1195 #if defined(DEBUG) && DEBUG
1196 if (self && !self.initialized) {
1200 *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
1209 [self internalClear:NO];
1210 NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc.");
1214 - (void)copyFieldsInto:(GPBMessage *)message
1216 descriptor:(GPBDescriptor *)descriptor {
1217 // Copy all the storage...
1218 memcpy(message->messageStorage_, messageStorage_, descriptor->storageSize_);
1220 // Loop over the fields doing fixup...
1221 for (GPBFieldDescriptor *field in descriptor->fields_) {
1222 if (GPBFieldIsMapOrArray(field)) {
1223 id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1225 // We need to copy the array/map, but the catch is for message fields,
1226 // we also need to ensure all the messages as those need copying also.
1228 if (GPBFieldDataTypeIsMessage(field)) {
1229 if (field.fieldType == GPBFieldTypeRepeated) {
1230 NSArray *existingArray = (NSArray *)value;
1231 NSMutableArray *newArray =
1232 [[NSMutableArray alloc] initWithCapacity:existingArray.count];
1233 newValue = newArray;
1234 for (GPBMessage *msg in existingArray) {
1235 GPBMessage *copiedMsg = [msg copyWithZone:zone];
1236 [newArray addObject:copiedMsg];
1237 [copiedMsg release];
1240 if (field.mapKeyDataType == GPBDataTypeString) {
1241 // Map is an NSDictionary.
1242 NSDictionary *existingDict = value;
1243 NSMutableDictionary *newDict =
1244 [[NSMutableDictionary alloc] initWithCapacity:existingDict.count];
1246 [existingDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, GPBMessage *msg,
1247 __unused BOOL *stop) {
1248 GPBMessage *copiedMsg = [msg copyWithZone:zone];
1249 [newDict setObject:copiedMsg forKey:key];
1250 [copiedMsg release];
1253 // Is one of the GPB*ObjectDictionary classes. Type doesn't
1254 // matter, just need one to invoke the selector.
1255 GPBInt32ObjectDictionary *existingDict = value;
1256 newValue = [existingDict deepCopyWithZone:zone];
1260 // Not messages (but is a map/array)...
1261 if (field.fieldType == GPBFieldTypeRepeated) {
1262 if (GPBFieldDataTypeIsObject(field)) {
1264 newValue = [value mutableCopyWithZone:zone];
1267 newValue = [value copyWithZone:zone];
1270 if ((field.mapKeyDataType == GPBDataTypeString) && GPBFieldDataTypeIsObject(field)) {
1272 newValue = [value mutableCopyWithZone:zone];
1274 // Is one of the GPB*Dictionary classes. Type doesn't matter,
1275 // just need one to invoke the selector.
1276 GPBInt32Int32Dictionary *existingDict = value;
1277 newValue = [existingDict copyWithZone:zone];
1281 // We retain here because the memcpy picked up the pointer value and
1282 // the next call to SetRetainedObject... will release the current value.
1284 GPBSetRetainedObjectIvarWithFieldPrivate(message, field, newValue);
1286 } else if (GPBFieldDataTypeIsMessage(field)) {
1287 // For object types, if we have a value, copy it. If we don't,
1288 // zero it to remove the pointer to something that was autocreated
1289 // (and the ptr just got memcpyed).
1290 if (GPBGetHasIvarField(self, field)) {
1291 GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1292 GPBMessage *newValue = [value copyWithZone:zone];
1293 // We retain here because the memcpy picked up the pointer value and
1294 // the next call to SetRetainedObject... will release the current value.
1296 GPBSetRetainedObjectIvarWithFieldPrivate(message, field, newValue);
1298 uint8_t *storage = (uint8_t *)message->messageStorage_;
1299 id *typePtr = (id *)&storage[field->description_->offset];
1302 } else if (GPBFieldDataTypeIsObject(field) && GPBGetHasIvarField(self, field)) {
1303 // A set string/data value (message picked off above), copy it.
1304 id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1305 id newValue = [value copyWithZone:zone];
1306 // We retain here because the memcpy picked up the pointer value and
1307 // the next call to SetRetainedObject... will release the current value.
1309 GPBSetRetainedObjectIvarWithFieldPrivate(message, field, newValue);
1311 // memcpy took care of the rest of the primitive fields if they were set.
1313 } // for (field in descriptor->fields_)
1316 - (id)copyWithZone:(NSZone *)zone {
1317 GPBDescriptor *descriptor = [self descriptor];
1318 GPBMessage *result = [[descriptor.messageClass allocWithZone:zone] init];
1320 [self copyFieldsInto:result zone:zone descriptor:descriptor];
1322 result->unknownFieldData_ = [unknownFieldData_ mutableCopyWithZone:zone];
1323 result->extensionMap_ = CloneExtensionMap(extensionMap_, zone);
1328 [self internalClear:YES];
1331 - (void)internalClear:(BOOL)zeroStorage {
1332 GPBDescriptor *descriptor = [self descriptor];
1333 for (GPBFieldDescriptor *field in descriptor->fields_) {
1334 if (GPBFieldIsMapOrArray(field)) {
1335 id arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1337 if (field.fieldType == GPBFieldTypeRepeated) {
1338 if (GPBFieldDataTypeIsObject(field)) {
1339 if ([arrayOrMap isKindOfClass:[GPBAutocreatedArray class]]) {
1340 GPBAutocreatedArray *autoArray = arrayOrMap;
1341 if (autoArray->_autocreator == self) {
1342 autoArray->_autocreator = nil;
1346 // Type doesn't matter, it is a GPB*Array.
1347 GPBInt32Array *gpbArray = arrayOrMap;
1348 if (gpbArray->_autocreator == self) {
1349 gpbArray->_autocreator = nil;
1353 if ((field.mapKeyDataType == GPBDataTypeString) && GPBFieldDataTypeIsObject(field)) {
1354 if ([arrayOrMap isKindOfClass:[GPBAutocreatedDictionary class]]) {
1355 GPBAutocreatedDictionary *autoDict = arrayOrMap;
1356 if (autoDict->_autocreator == self) {
1357 autoDict->_autocreator = nil;
1361 // Type doesn't matter, it is a GPB*Dictionary.
1362 GPBInt32Int32Dictionary *gpbDict = arrayOrMap;
1363 if (gpbDict->_autocreator == self) {
1364 gpbDict->_autocreator = nil;
1368 [arrayOrMap release];
1370 } else if (GPBFieldDataTypeIsMessage(field)) {
1371 GPBClearAutocreatedMessageIvarWithField(self, field);
1372 GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1374 } else if (GPBFieldDataTypeIsObject(field) && GPBGetHasIvarField(self, field)) {
1375 id value = GPBGetObjectIvarWithField(self, field);
1380 // GPBClearMessageAutocreator() expects that its caller has already been
1381 // removed from autocreatedExtensionMap_ so we set to nil first.
1382 NSArray *autocreatedValues = [autocreatedExtensionMap_ allValues];
1383 [autocreatedExtensionMap_ release];
1384 autocreatedExtensionMap_ = nil;
1386 // Since we're clearing all of our extensions, make sure that we clear the
1387 // autocreator on any that we've created so they no longer refer to us.
1388 for (GPBMessage *value in autocreatedValues) {
1389 NSCAssert(GPBWasMessageAutocreatedBy(value, self),
1390 @"Autocreated extension does not refer back to self.");
1391 GPBClearMessageAutocreator(value);
1394 [extensionMap_ release];
1395 extensionMap_ = nil;
1396 [unknownFieldData_ release];
1397 unknownFieldData_ = nil;
1399 // Note that clearing does not affect autocreator_. If we are being cleared
1400 // because of a dealloc, then autocreator_ should be nil anyway. If we are
1401 // being cleared because someone explicitly clears us, we don't want to
1402 // sever our relationship with our autocreator.
1405 memset(messageStorage_, 0, descriptor->storageSize_);
1409 - (void)clearUnknownFields {
1410 [unknownFieldData_ release];
1411 unknownFieldData_ = nil;
1412 GPBBecomeVisibleToAutocreator(self);
1415 - (BOOL)mergeUnknownFields:(GPBUnknownFields *)unknownFields
1416 extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry
1417 error:(NSError **)errorPtr {
1418 return [self mergeFromData:[unknownFields serializeAsData]
1419 extensionRegistry:extensionRegistry
1423 - (BOOL)isInitialized {
1424 GPBDescriptor *descriptor = [self descriptor];
1425 for (GPBFieldDescriptor *field in descriptor->fields_) {
1426 if (field.isRequired) {
1427 if (!GPBGetHasIvarField(self, field)) {
1431 if (GPBFieldDataTypeIsMessage(field)) {
1432 GPBFieldType fieldType = field.fieldType;
1433 if (fieldType == GPBFieldTypeSingle) {
1434 if (field.isRequired) {
1435 GPBMessage *message = GPBGetMessageMessageField(self, field);
1436 if (!message.initialized) {
1440 NSAssert(field.isOptional, @"%@: Single message field %@ not required or optional?",
1441 [self class], field.name);
1442 if (GPBGetHasIvarField(self, field)) {
1443 GPBMessage *message = GPBGetMessageMessageField(self, field);
1444 if (!message.initialized) {
1449 } else if (fieldType == GPBFieldTypeRepeated) {
1450 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1451 for (GPBMessage *message in array) {
1452 if (!message.initialized) {
1456 } else { // fieldType == GPBFieldTypeMap
1457 if (field.mapKeyDataType == GPBDataTypeString) {
1458 NSDictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1459 if (map && !GPBDictionaryIsInitializedInternalHelper(map, field)) {
1463 // Real type is GPB*ObjectDictionary, exact type doesn't matter.
1464 GPBInt32ObjectDictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1465 if (map && ![map isInitialized]) {
1473 __block BOOL result = YES;
1475 enumerateKeysAndObjectsUsingBlock:^(GPBExtensionDescriptor *extension, id obj, BOOL *stop) {
1476 if (GPBExtensionIsMessage(extension)) {
1477 if (extension.isRepeated) {
1478 for (GPBMessage *msg in obj) {
1479 if (!msg.initialized) {
1486 GPBMessage *asMsg = obj;
1487 if (!asMsg.initialized) {
1497 - (GPBDescriptor *)descriptor {
1498 return [[self class] descriptor];
1502 #if defined(DEBUG) && DEBUG
1503 if (!self.initialized) {
1507 size_t expectedSize = [self serializedSize];
1508 if (expectedSize > kMaximumMessageSize) {
1511 NSMutableData *data = [NSMutableData dataWithLength:expectedSize];
1512 GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithData:data];
1514 [self writeToCodedOutputStream:stream];
1516 } @catch (NSException *exception) {
1517 // This really shouldn't happen. Normally, this could mean there was a bug in the library and it
1518 // failed to match between computing the size and writing out the bytes. However, the more
1519 // common cause is while one thread was writing out the data, some other thread had a reference
1520 // to this message or a message used as a nested field, and that other thread mutated that
1521 // message, causing the pre computed serializedSize to no longer match the final size after
1522 // serialization. It is not safe to mutate a message while accessing it from another thread.
1523 #if defined(DEBUG) && DEBUG
1524 NSLog(@"%@: Internal exception while building message data: %@", [self class], exception);
1528 #if defined(DEBUG) && DEBUG
1529 NSAssert(!data || [stream bytesWritten] == expectedSize, @"Internal error within the library");
1535 - (NSData *)delimitedData {
1536 size_t serializedSize = [self serializedSize];
1537 size_t varintSize = GPBComputeRawVarint32SizeForInteger(serializedSize);
1538 NSMutableData *data = [NSMutableData dataWithLength:(serializedSize + varintSize)];
1539 GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithData:data];
1541 [self writeDelimitedToCodedOutputStream:stream];
1543 } @catch (NSException *exception) {
1544 // This really shouldn't happen. Normally, this could mean there was a bug in the library and it
1545 // failed to match between computing the size and writing out the bytes. However, the more
1546 // common cause is while one thread was writing out the data, some other thread had a reference
1547 // to this message or a message used as a nested field, and that other thread mutated that
1548 // message, causing the pre computed serializedSize to no longer match the final size after
1549 // serialization. It is not safe to mutate a message while accessing it from another thread.
1550 #if defined(DEBUG) && DEBUG
1551 NSLog(@"%@: Internal exception while building message delimitedData: %@", [self class],
1554 // If it happens, return an empty data.
1556 return [NSData data];
1562 - (void)writeToOutputStream:(NSOutputStream *)output {
1563 GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithOutputStream:output];
1565 [self writeToCodedOutputStream:stream];
1567 size_t bytesWritten = [stream bytesWritten];
1568 if (bytesWritten > kMaximumMessageSize) {
1569 [NSException raise:GPBMessageExceptionMessageTooLarge
1570 format:@"Message would have been %zu bytes", bytesWritten];
1577 - (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output {
1578 GPBDescriptor *descriptor = [self descriptor];
1579 NSArray *fieldsArray = descriptor->fields_;
1580 NSUInteger fieldCount = fieldsArray.count;
1581 const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
1582 NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
1583 NSArray *sortedExtensions =
1584 [[extensionMap_ allKeys] sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
1585 for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
1586 if (i == fieldCount) {
1587 [self writeExtensionsToCodedOutputStream:output
1588 range:extensionRanges[j++]
1589 sortedExtensions:sortedExtensions];
1590 } else if (j == extensionRangesCount ||
1591 GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
1592 [self writeField:fieldsArray[i++] toCodedOutputStream:output];
1594 [self writeExtensionsToCodedOutputStream:output
1595 range:extensionRanges[j++]
1596 sortedExtensions:sortedExtensions];
1599 if (unknownFieldData_) {
1600 [output writeRawData:unknownFieldData_];
1604 - (void)writeDelimitedToOutputStream:(NSOutputStream *)output {
1605 GPBCodedOutputStream *codedOutput = [[GPBCodedOutputStream alloc] initWithOutputStream:output];
1607 [self writeDelimitedToCodedOutputStream:codedOutput];
1608 [codedOutput flush];
1610 [codedOutput release];
1614 - (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output {
1615 size_t expectedSize = [self serializedSize];
1616 if (expectedSize > kMaximumMessageSize) {
1617 [NSException raise:GPBMessageExceptionMessageTooLarge
1618 format:@"Message would have been %zu bytes", expectedSize];
1620 [output writeRawVarintSizeTAs32:expectedSize];
1621 #if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
1622 size_t initialSize = [output bytesWritten];
1624 [self writeToCodedOutputStream:output];
1625 #if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
1626 NSAssert(([output bytesWritten] - initialSize) == expectedSize,
1627 @"Internal error within the library");
1631 - (void)writeField:(GPBFieldDescriptor *)field toCodedOutputStream:(GPBCodedOutputStream *)output {
1632 GPBFieldType fieldType = field.fieldType;
1633 if (fieldType == GPBFieldTypeSingle) {
1634 BOOL has = GPBGetHasIvarField(self, field);
1639 uint32_t fieldNumber = GPBFieldNumber(field);
1641 switch (GPBGetFieldDataType(field)) {
1644 //%PDDM-DEFINE FIELD_CASE(TYPE, REAL_TYPE)
1645 //%FIELD_CASE_FULL(TYPE, REAL_TYPE, REAL_TYPE)
1646 //%PDDM-DEFINE FIELD_CASE_FULL(TYPE, REAL_TYPE, ARRAY_TYPE)
1647 //% case GPBDataType##TYPE:
1648 //% if (fieldType == GPBFieldTypeRepeated) {
1649 //% uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1650 //% GPB##ARRAY_TYPE##Array *array =
1651 //% GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1652 //% [output write##TYPE##Array:fieldNumber values:array tag:tag];
1653 //% } else if (fieldType == GPBFieldTypeSingle) {
1654 //% [output write##TYPE:fieldNumber
1655 //% TYPE$S value:GPBGetMessage##REAL_TYPE##Field(self, field)];
1656 //% } else { // fieldType == GPBFieldTypeMap
1657 //% // Exact type here doesn't matter.
1658 //% GPBInt32##ARRAY_TYPE##Dictionary *dict =
1659 //% GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1660 //% [dict writeToCodedOutputStream:output asField:field];
1664 //%PDDM-DEFINE FIELD_CASE2(TYPE)
1665 //% case GPBDataType##TYPE:
1666 //% if (fieldType == GPBFieldTypeRepeated) {
1667 //% NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1668 //% [output write##TYPE##Array:fieldNumber values:array];
1669 //% } else if (fieldType == GPBFieldTypeSingle) {
1670 //% // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1672 //% [output write##TYPE:fieldNumber
1673 //% TYPE$S value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1674 //% } else { // fieldType == GPBFieldTypeMap
1675 //% // Exact type here doesn't matter.
1676 //% id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1677 //% GPBDataType mapKeyDataType = field.mapKeyDataType;
1678 //% if (mapKeyDataType == GPBDataTypeString) {
1679 //% GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1681 //% [dict writeToCodedOutputStream:output asField:field];
1686 //%PDDM-EXPAND FIELD_CASE(Bool, Bool)
1687 // This block of code is generated, do not edit it directly.
1689 case GPBDataTypeBool:
1690 if (fieldType == GPBFieldTypeRepeated) {
1691 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1692 GPBBoolArray *array =
1693 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1694 [output writeBoolArray:fieldNumber values:array tag:tag];
1695 } else if (fieldType == GPBFieldTypeSingle) {
1696 [output writeBool:fieldNumber
1697 value:GPBGetMessageBoolField(self, field)];
1698 } else { // fieldType == GPBFieldTypeMap
1699 // Exact type here doesn't matter.
1700 GPBInt32BoolDictionary *dict =
1701 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1702 [dict writeToCodedOutputStream:output asField:field];
1706 //%PDDM-EXPAND FIELD_CASE(Fixed32, UInt32)
1707 // This block of code is generated, do not edit it directly.
1709 case GPBDataTypeFixed32:
1710 if (fieldType == GPBFieldTypeRepeated) {
1711 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1712 GPBUInt32Array *array =
1713 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1714 [output writeFixed32Array:fieldNumber values:array tag:tag];
1715 } else if (fieldType == GPBFieldTypeSingle) {
1716 [output writeFixed32:fieldNumber
1717 value:GPBGetMessageUInt32Field(self, field)];
1718 } else { // fieldType == GPBFieldTypeMap
1719 // Exact type here doesn't matter.
1720 GPBInt32UInt32Dictionary *dict =
1721 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1722 [dict writeToCodedOutputStream:output asField:field];
1726 //%PDDM-EXPAND FIELD_CASE(SFixed32, Int32)
1727 // This block of code is generated, do not edit it directly.
1729 case GPBDataTypeSFixed32:
1730 if (fieldType == GPBFieldTypeRepeated) {
1731 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1732 GPBInt32Array *array =
1733 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1734 [output writeSFixed32Array:fieldNumber values:array tag:tag];
1735 } else if (fieldType == GPBFieldTypeSingle) {
1736 [output writeSFixed32:fieldNumber
1737 value:GPBGetMessageInt32Field(self, field)];
1738 } else { // fieldType == GPBFieldTypeMap
1739 // Exact type here doesn't matter.
1740 GPBInt32Int32Dictionary *dict =
1741 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1742 [dict writeToCodedOutputStream:output asField:field];
1746 //%PDDM-EXPAND FIELD_CASE(Float, Float)
1747 // This block of code is generated, do not edit it directly.
1749 case GPBDataTypeFloat:
1750 if (fieldType == GPBFieldTypeRepeated) {
1751 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1752 GPBFloatArray *array =
1753 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1754 [output writeFloatArray:fieldNumber values:array tag:tag];
1755 } else if (fieldType == GPBFieldTypeSingle) {
1756 [output writeFloat:fieldNumber
1757 value:GPBGetMessageFloatField(self, field)];
1758 } else { // fieldType == GPBFieldTypeMap
1759 // Exact type here doesn't matter.
1760 GPBInt32FloatDictionary *dict =
1761 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1762 [dict writeToCodedOutputStream:output asField:field];
1766 //%PDDM-EXPAND FIELD_CASE(Fixed64, UInt64)
1767 // This block of code is generated, do not edit it directly.
1769 case GPBDataTypeFixed64:
1770 if (fieldType == GPBFieldTypeRepeated) {
1771 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1772 GPBUInt64Array *array =
1773 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1774 [output writeFixed64Array:fieldNumber values:array tag:tag];
1775 } else if (fieldType == GPBFieldTypeSingle) {
1776 [output writeFixed64:fieldNumber
1777 value:GPBGetMessageUInt64Field(self, field)];
1778 } else { // fieldType == GPBFieldTypeMap
1779 // Exact type here doesn't matter.
1780 GPBInt32UInt64Dictionary *dict =
1781 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1782 [dict writeToCodedOutputStream:output asField:field];
1786 //%PDDM-EXPAND FIELD_CASE(SFixed64, Int64)
1787 // This block of code is generated, do not edit it directly.
1789 case GPBDataTypeSFixed64:
1790 if (fieldType == GPBFieldTypeRepeated) {
1791 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1792 GPBInt64Array *array =
1793 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1794 [output writeSFixed64Array:fieldNumber values:array tag:tag];
1795 } else if (fieldType == GPBFieldTypeSingle) {
1796 [output writeSFixed64:fieldNumber
1797 value:GPBGetMessageInt64Field(self, field)];
1798 } else { // fieldType == GPBFieldTypeMap
1799 // Exact type here doesn't matter.
1800 GPBInt32Int64Dictionary *dict =
1801 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1802 [dict writeToCodedOutputStream:output asField:field];
1806 //%PDDM-EXPAND FIELD_CASE(Double, Double)
1807 // This block of code is generated, do not edit it directly.
1809 case GPBDataTypeDouble:
1810 if (fieldType == GPBFieldTypeRepeated) {
1811 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1812 GPBDoubleArray *array =
1813 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1814 [output writeDoubleArray:fieldNumber values:array tag:tag];
1815 } else if (fieldType == GPBFieldTypeSingle) {
1816 [output writeDouble:fieldNumber
1817 value:GPBGetMessageDoubleField(self, field)];
1818 } else { // fieldType == GPBFieldTypeMap
1819 // Exact type here doesn't matter.
1820 GPBInt32DoubleDictionary *dict =
1821 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1822 [dict writeToCodedOutputStream:output asField:field];
1826 //%PDDM-EXPAND FIELD_CASE(Int32, Int32)
1827 // This block of code is generated, do not edit it directly.
1829 case GPBDataTypeInt32:
1830 if (fieldType == GPBFieldTypeRepeated) {
1831 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1832 GPBInt32Array *array =
1833 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1834 [output writeInt32Array:fieldNumber values:array tag:tag];
1835 } else if (fieldType == GPBFieldTypeSingle) {
1836 [output writeInt32:fieldNumber
1837 value:GPBGetMessageInt32Field(self, field)];
1838 } else { // fieldType == GPBFieldTypeMap
1839 // Exact type here doesn't matter.
1840 GPBInt32Int32Dictionary *dict =
1841 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1842 [dict writeToCodedOutputStream:output asField:field];
1846 //%PDDM-EXPAND FIELD_CASE(Int64, Int64)
1847 // This block of code is generated, do not edit it directly.
1849 case GPBDataTypeInt64:
1850 if (fieldType == GPBFieldTypeRepeated) {
1851 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1852 GPBInt64Array *array =
1853 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1854 [output writeInt64Array:fieldNumber values:array tag:tag];
1855 } else if (fieldType == GPBFieldTypeSingle) {
1856 [output writeInt64:fieldNumber
1857 value:GPBGetMessageInt64Field(self, field)];
1858 } else { // fieldType == GPBFieldTypeMap
1859 // Exact type here doesn't matter.
1860 GPBInt32Int64Dictionary *dict =
1861 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1862 [dict writeToCodedOutputStream:output asField:field];
1866 //%PDDM-EXPAND FIELD_CASE(SInt32, Int32)
1867 // This block of code is generated, do not edit it directly.
1869 case GPBDataTypeSInt32:
1870 if (fieldType == GPBFieldTypeRepeated) {
1871 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1872 GPBInt32Array *array =
1873 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1874 [output writeSInt32Array:fieldNumber values:array tag:tag];
1875 } else if (fieldType == GPBFieldTypeSingle) {
1876 [output writeSInt32:fieldNumber
1877 value:GPBGetMessageInt32Field(self, field)];
1878 } else { // fieldType == GPBFieldTypeMap
1879 // Exact type here doesn't matter.
1880 GPBInt32Int32Dictionary *dict =
1881 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1882 [dict writeToCodedOutputStream:output asField:field];
1886 //%PDDM-EXPAND FIELD_CASE(SInt64, Int64)
1887 // This block of code is generated, do not edit it directly.
1889 case GPBDataTypeSInt64:
1890 if (fieldType == GPBFieldTypeRepeated) {
1891 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1892 GPBInt64Array *array =
1893 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1894 [output writeSInt64Array:fieldNumber values:array tag:tag];
1895 } else if (fieldType == GPBFieldTypeSingle) {
1896 [output writeSInt64:fieldNumber
1897 value:GPBGetMessageInt64Field(self, field)];
1898 } else { // fieldType == GPBFieldTypeMap
1899 // Exact type here doesn't matter.
1900 GPBInt32Int64Dictionary *dict =
1901 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1902 [dict writeToCodedOutputStream:output asField:field];
1906 //%PDDM-EXPAND FIELD_CASE(UInt32, UInt32)
1907 // This block of code is generated, do not edit it directly.
1909 case GPBDataTypeUInt32:
1910 if (fieldType == GPBFieldTypeRepeated) {
1911 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1912 GPBUInt32Array *array =
1913 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1914 [output writeUInt32Array:fieldNumber values:array tag:tag];
1915 } else if (fieldType == GPBFieldTypeSingle) {
1916 [output writeUInt32:fieldNumber
1917 value:GPBGetMessageUInt32Field(self, field)];
1918 } else { // fieldType == GPBFieldTypeMap
1919 // Exact type here doesn't matter.
1920 GPBInt32UInt32Dictionary *dict =
1921 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1922 [dict writeToCodedOutputStream:output asField:field];
1926 //%PDDM-EXPAND FIELD_CASE(UInt64, UInt64)
1927 // This block of code is generated, do not edit it directly.
1929 case GPBDataTypeUInt64:
1930 if (fieldType == GPBFieldTypeRepeated) {
1931 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1932 GPBUInt64Array *array =
1933 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1934 [output writeUInt64Array:fieldNumber values:array tag:tag];
1935 } else if (fieldType == GPBFieldTypeSingle) {
1936 [output writeUInt64:fieldNumber
1937 value:GPBGetMessageUInt64Field(self, field)];
1938 } else { // fieldType == GPBFieldTypeMap
1939 // Exact type here doesn't matter.
1940 GPBInt32UInt64Dictionary *dict =
1941 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1942 [dict writeToCodedOutputStream:output asField:field];
1946 //%PDDM-EXPAND FIELD_CASE_FULL(Enum, Int32, Enum)
1947 // This block of code is generated, do not edit it directly.
1949 case GPBDataTypeEnum:
1950 if (fieldType == GPBFieldTypeRepeated) {
1951 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0;
1952 GPBEnumArray *array =
1953 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1954 [output writeEnumArray:fieldNumber values:array tag:tag];
1955 } else if (fieldType == GPBFieldTypeSingle) {
1956 [output writeEnum:fieldNumber
1957 value:GPBGetMessageInt32Field(self, field)];
1958 } else { // fieldType == GPBFieldTypeMap
1959 // Exact type here doesn't matter.
1960 GPBInt32EnumDictionary *dict =
1961 GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1962 [dict writeToCodedOutputStream:output asField:field];
1966 //%PDDM-EXPAND FIELD_CASE2(Bytes)
1967 // This block of code is generated, do not edit it directly.
1969 case GPBDataTypeBytes:
1970 if (fieldType == GPBFieldTypeRepeated) {
1971 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1972 [output writeBytesArray:fieldNumber values:array];
1973 } else if (fieldType == GPBFieldTypeSingle) {
1974 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
1976 [output writeBytes:fieldNumber
1977 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
1978 } else { // fieldType == GPBFieldTypeMap
1979 // Exact type here doesn't matter.
1980 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1981 GPBDataType mapKeyDataType = field.mapKeyDataType;
1982 if (mapKeyDataType == GPBDataTypeString) {
1983 GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
1985 [dict writeToCodedOutputStream:output asField:field];
1990 //%PDDM-EXPAND FIELD_CASE2(String)
1991 // This block of code is generated, do not edit it directly.
1993 case GPBDataTypeString:
1994 if (fieldType == GPBFieldTypeRepeated) {
1995 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
1996 [output writeStringArray:fieldNumber values:array];
1997 } else if (fieldType == GPBFieldTypeSingle) {
1998 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
2000 [output writeString:fieldNumber
2001 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
2002 } else { // fieldType == GPBFieldTypeMap
2003 // Exact type here doesn't matter.
2004 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2005 GPBDataType mapKeyDataType = field.mapKeyDataType;
2006 if (mapKeyDataType == GPBDataTypeString) {
2007 GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
2009 [dict writeToCodedOutputStream:output asField:field];
2014 //%PDDM-EXPAND FIELD_CASE2(Message)
2015 // This block of code is generated, do not edit it directly.
2017 case GPBDataTypeMessage:
2018 if (fieldType == GPBFieldTypeRepeated) {
2019 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2020 [output writeMessageArray:fieldNumber values:array];
2021 } else if (fieldType == GPBFieldTypeSingle) {
2022 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
2024 [output writeMessage:fieldNumber
2025 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
2026 } else { // fieldType == GPBFieldTypeMap
2027 // Exact type here doesn't matter.
2028 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2029 GPBDataType mapKeyDataType = field.mapKeyDataType;
2030 if (mapKeyDataType == GPBDataTypeString) {
2031 GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
2033 [dict writeToCodedOutputStream:output asField:field];
2038 //%PDDM-EXPAND FIELD_CASE2(Group)
2039 // This block of code is generated, do not edit it directly.
2041 case GPBDataTypeGroup:
2042 if (fieldType == GPBFieldTypeRepeated) {
2043 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2044 [output writeGroupArray:fieldNumber values:array];
2045 } else if (fieldType == GPBFieldTypeSingle) {
2046 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check
2048 [output writeGroup:fieldNumber
2049 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)];
2050 } else { // fieldType == GPBFieldTypeMap
2051 // Exact type here doesn't matter.
2052 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2053 GPBDataType mapKeyDataType = field.mapKeyDataType;
2054 if (mapKeyDataType == GPBDataTypeString) {
2055 GPBDictionaryWriteToStreamInternalHelper(output, dict, field);
2057 [dict writeToCodedOutputStream:output asField:field];
2062 //%PDDM-EXPAND-END (18 expansions)
2068 #pragma mark - Extensions
2070 - (id)getExtension:(GPBExtensionDescriptor *)extension {
2071 CheckExtension(self, extension);
2072 id value = [extensionMap_ objectForKey:extension];
2077 // No default for repeated.
2078 if (extension.isRepeated) {
2081 // Non messages get their default.
2082 if (!GPBExtensionIsMessage(extension)) {
2083 return extension.defaultValue;
2086 // Check for an autocreated value.
2087 os_unfair_lock_lock(&readOnlyLock_);
2088 value = [autocreatedExtensionMap_ objectForKey:extension];
2090 // Auto create the message extensions to match normal fields.
2091 value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self, extension);
2093 if (autocreatedExtensionMap_ == nil) {
2094 autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init];
2097 // We can't simply call setExtension here because that would clear the new
2098 // value's autocreator.
2099 [autocreatedExtensionMap_ setObject:value forKey:extension];
2103 os_unfair_lock_unlock(&readOnlyLock_);
2107 - (id)getExistingExtension:(GPBExtensionDescriptor *)extension {
2108 // This is an internal method so we don't need to call CheckExtension().
2109 return [extensionMap_ objectForKey:extension];
2112 - (BOOL)hasExtension:(GPBExtensionDescriptor *)extension {
2113 #if defined(DEBUG) && DEBUG
2114 CheckExtension(self, extension);
2116 return nil != [extensionMap_ objectForKey:extension];
2119 - (NSArray *)extensionsCurrentlySet {
2120 return [extensionMap_ allKeys];
2123 - (void)writeExtensionsToCodedOutputStream:(GPBCodedOutputStream *)output
2124 range:(GPBExtensionRange)range
2125 sortedExtensions:(NSArray *)sortedExtensions {
2126 uint32_t start = range.start;
2127 uint32_t end = range.end;
2128 for (GPBExtensionDescriptor *extension in sortedExtensions) {
2129 uint32_t fieldNumber = extension.fieldNumber;
2130 if (fieldNumber < start) {
2133 if (fieldNumber >= end) {
2136 id value = [extensionMap_ objectForKey:extension];
2137 GPBWriteExtensionValueToOutputStream(extension, value, output);
2141 - (void)setExtension:(GPBExtensionDescriptor *)extension value:(id)value {
2143 [self clearExtension:extension];
2147 CheckExtension(self, extension);
2149 if (extension.repeated) {
2150 [NSException raise:NSInvalidArgumentException
2151 format:@"Must call addExtension() for repeated types."];
2154 if (extensionMap_ == nil) {
2155 extensionMap_ = [[NSMutableDictionary alloc] init];
2158 // This pointless cast is for CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION.
2159 // Without it, the compiler complains we're passing an id nullable when
2160 // setObject:forKey: requires a id nonnull for the value. The check for
2161 // !value at the start of the method ensures it isn't nil, but the check
2162 // isn't smart enough to realize that.
2163 [extensionMap_ setObject:(id)value forKey:extension];
2165 GPBExtensionDescriptor *descriptor = extension;
2167 if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) {
2168 GPBMessage *autocreatedValue = [[autocreatedExtensionMap_ objectForKey:extension] retain];
2169 // Must remove from the map before calling GPBClearMessageAutocreator() so
2170 // that GPBClearMessageAutocreator() knows its safe to clear.
2171 [autocreatedExtensionMap_ removeObjectForKey:extension];
2172 GPBClearMessageAutocreator(autocreatedValue);
2173 [autocreatedValue release];
2176 GPBBecomeVisibleToAutocreator(self);
2179 - (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value {
2180 CheckExtension(self, extension);
2182 if (!extension.repeated) {
2183 [NSException raise:NSInvalidArgumentException
2184 format:@"Must call setExtension() for singular types."];
2187 if (extensionMap_ == nil) {
2188 extensionMap_ = [[NSMutableDictionary alloc] init];
2190 NSMutableArray *list = [extensionMap_ objectForKey:extension];
2192 list = [NSMutableArray array];
2193 [extensionMap_ setObject:list forKey:extension];
2196 [list addObject:value];
2197 GPBBecomeVisibleToAutocreator(self);
2200 - (void)setExtension:(GPBExtensionDescriptor *)extension index:(NSUInteger)idx value:(id)value {
2201 CheckExtension(self, extension);
2203 if (!extension.repeated) {
2204 [NSException raise:NSInvalidArgumentException
2205 format:@"Must call setExtension() for singular types."];
2208 if (extensionMap_ == nil) {
2209 extensionMap_ = [[NSMutableDictionary alloc] init];
2212 NSMutableArray *list = [extensionMap_ objectForKey:extension];
2214 [list replaceObjectAtIndex:idx withObject:value];
2215 GPBBecomeVisibleToAutocreator(self);
2218 - (void)clearExtension:(GPBExtensionDescriptor *)extension {
2219 CheckExtension(self, extension);
2221 // Only become visible if there was actually a value to clear.
2222 if ([extensionMap_ objectForKey:extension]) {
2223 [extensionMap_ removeObjectForKey:extension];
2224 GPBBecomeVisibleToAutocreator(self);
2228 #pragma mark - mergeFrom
2230 - (BOOL)mergeFromData:(NSData *)data
2231 extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry
2232 error:(NSError **)errorPtr {
2233 GPBBecomeVisibleToAutocreator(self);
2234 GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
2236 [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry endingTag:0];
2237 [input checkLastTagWas:0];
2241 } @catch (NSException *exception) {
2244 *errorPtr = ErrorFromException(exception);
2252 #pragma mark - Parse From Data Support
2254 + (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr {
2255 return [self parseFromData:data extensionRegistry:nil error:errorPtr];
2258 + (instancetype)parseFromData:(NSData *)data
2259 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
2260 error:(NSError **)errorPtr {
2261 return [[[self alloc] initWithData:data extensionRegistry:extensionRegistry
2262 error:errorPtr] autorelease];
2265 + (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
2266 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
2267 error:(NSError **)errorPtr {
2268 return [[[self alloc] initWithCodedInputStream:input
2269 extensionRegistry:extensionRegistry
2270 error:errorPtr] autorelease];
2273 #pragma mark - Parse Delimited From Data Support
2275 + (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
2276 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
2277 error:(NSError **)errorPtr {
2278 GPBCodedInputStreamState *state = &input->state_;
2279 // This doesn't completely match the C++, but if the stream has nothing, just make an empty
2281 if (GPBCodedInputStreamIsAtEnd(state)) {
2282 return [[[self alloc] init] autorelease];
2285 // Manually extract the data and parse it. If we read a varint and push a limit, that consumes
2286 // some of the recursion buffer which isn't correct, it also can result in a change in error
2287 // codes for attempts to parse partial data; and there are projects sensitive to that, so this
2288 // maintains existing error flows.
2290 // Extract the data, but in a "no copy" mode since we will immediately parse it so this NSData
2294 data = GPBCodedInputStreamReadRetainedBytesNoCopy(state);
2295 } @catch (NSException *exception) {
2297 *errorPtr = ErrorFromException(exception);
2302 GPBMessage *result = [self parseFromData:data extensionRegistry:extensionRegistry error:errorPtr];
2304 if (result && errorPtr) {
2310 - (void)parseMessageSet:(GPBCodedInputStream *)input
2311 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
2312 uint32_t typeId = 0;
2313 NSData *rawBytes = nil;
2314 GPBCodedInputStreamState *state = &input->state_;
2318 uint32_t tag = GPBCodedInputStreamReadTag(state);
2319 if (tag == GPBWireFormatMessageSetItemEndTag || tag == 0) {
2323 if (tag == GPBWireFormatMessageSetTypeIdTag) {
2324 uint32_t tmp = GPBCodedInputStreamReadUInt32(state);
2325 // Spec says only use the first value.
2330 } else if (tag == GPBWireFormatMessageSetMessageTag) {
2332 // Skip over the payload instead of collecting it.
2333 [input skipField:tag];
2335 rawBytes = [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
2339 // Don't capture unknowns within the message set impl group.
2340 if (![input skipField:tag]) {
2346 // If we get here because of end of input (tag zero) or the wrong end tag (within the skipField:),
2348 GPBCodedInputStreamCheckLastTagWas(state, GPBWireFormatMessageSetItemEndTag);
2350 if (!gotType || !gotBytes) {
2351 // upb_Decoder_DecodeMessageSetItem does't keep this partial as an unknown field, it just drops
2352 // it, so do the same thing.
2356 GPBExtensionDescriptor *extension = [extensionRegistry extensionForDescriptor:[self descriptor]
2357 fieldNumber:typeId];
2359 #if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
2360 NSAssert(extension.dataType == GPBDataTypeMessage,
2361 @"Internal Error: MessageSet extension must be a message field.");
2362 NSAssert(GPBExtensionIsWireFormat(extension->description_),
2363 @"Internal Error: MessageSet extension must have message_set_wire_format set.");
2364 NSAssert(!GPBExtensionIsRepeated(extension->description_),
2365 @"Internal Error: MessageSet extension can't be repeated.");
2367 // Look up the existing one to merge to or create a new one.
2368 GPBMessage *targetMessage = [self getExistingExtension:extension];
2369 if (!targetMessage) {
2370 GPBDescriptor *descriptor = [extension.msgClass descriptor];
2371 targetMessage = [[descriptor.messageClass alloc] init];
2372 [self setExtension:extension value:targetMessage];
2373 [targetMessage release];
2375 GPBCodedInputStream *newInput = [[GPBCodedInputStream alloc] initWithData:rawBytes];
2377 [targetMessage mergeFromCodedInputStream:newInput
2378 extensionRegistry:extensionRegistry
2384 // The extension isn't in the registry, but it was well formed, so the whole group structure
2385 // get preserved as an unknown field.
2387 // rawBytes was created via a NoCopy, so it can be reusing a
2388 // subrange of another NSData that might go out of scope as things
2389 // unwind, so a copy is needed to ensure what is saved in the
2390 // unknown fields stays valid.
2391 NSData *cloned = [NSData dataWithData:rawBytes];
2392 AddUnknownMessageSetEntry(self, typeId, cloned);
2396 - (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data {
2397 AddUnknownFieldLengthDelimited(self, fieldNum, data);
2400 #pragma mark - MergeFromCodedInputStream Support
2402 static void MergeSingleFieldFromCodedInputStream(GPBMessage *self, GPBFieldDescriptor *field,
2403 GPBCodedInputStream *input,
2404 id<GPBExtensionRegistry> extensionRegistry) {
2405 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2406 switch (fieldDataType) {
2407 #define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
2408 case GPBDataType##NAME: { \
2409 TYPE val = GPBCodedInputStreamRead##NAME(&input->state_); \
2410 GPBSet##FUNC_TYPE##IvarWithFieldPrivate(self, field, val); \
2413 #define CASE_SINGLE_OBJECT(NAME) \
2414 case GPBDataType##NAME: { \
2415 id val = GPBCodedInputStreamReadRetained##NAME(&input->state_); \
2416 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, val); \
2419 CASE_SINGLE_POD(Bool, BOOL, Bool)
2420 CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
2421 CASE_SINGLE_POD(SFixed32, int32_t, Int32)
2422 CASE_SINGLE_POD(Float, float, Float)
2423 CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
2424 CASE_SINGLE_POD(SFixed64, int64_t, Int64)
2425 CASE_SINGLE_POD(Double, double, Double)
2426 CASE_SINGLE_POD(Int32, int32_t, Int32)
2427 CASE_SINGLE_POD(Int64, int64_t, Int64)
2428 CASE_SINGLE_POD(SInt32, int32_t, Int32)
2429 CASE_SINGLE_POD(SInt64, int64_t, Int64)
2430 CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
2431 CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
2432 CASE_SINGLE_OBJECT(Bytes)
2433 CASE_SINGLE_OBJECT(String)
2434 #undef CASE_SINGLE_POD
2435 #undef CASE_SINGLE_OBJECT
2437 case GPBDataTypeMessage: {
2438 if (GPBGetHasIvarField(self, field)) {
2439 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
2441 GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2442 [input readMessage:message extensionRegistry:extensionRegistry];
2444 GPBMessage *message = [[field.msgClass alloc] init];
2445 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
2446 [input readMessage:message extensionRegistry:extensionRegistry];
2451 case GPBDataTypeGroup: {
2452 if (GPBGetHasIvarField(self, field)) {
2453 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
2455 GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2456 [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
2458 GPBMessage *message = [[field.msgClass alloc] init];
2459 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
2460 [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
2465 case GPBDataTypeEnum: {
2466 int32_t val = GPBCodedInputStreamReadEnum(&input->state_);
2467 if ([field.enumDescriptor isOpenOrValidValue:val]) {
2468 GPBSetInt32IvarWithFieldPrivate(self, field, val);
2470 AddUnknownFieldVarint32(self, GPBFieldNumber(field), val);
2476 static void MergeRepeatedPackedFieldFromCodedInputStream(GPBMessage *self,
2477 GPBFieldDescriptor *field,
2478 GPBCodedInputStream *input) {
2479 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2480 GPBCodedInputStreamState *state = &input->state_;
2481 id genericArray = GetOrCreateArrayIvarWithField(self, field);
2482 int32_t length = GPBCodedInputStreamReadInt32(state);
2483 size_t limit = GPBCodedInputStreamPushLimit(state, length);
2484 while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
2485 switch (fieldDataType) {
2486 #define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
2487 case GPBDataType##NAME: { \
2488 TYPE val = GPBCodedInputStreamRead##NAME(state); \
2489 [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
2492 CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
2493 CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
2494 CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
2495 CASE_REPEATED_PACKED_POD(Float, float, Float)
2496 CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
2497 CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
2498 CASE_REPEATED_PACKED_POD(Double, double, Double)
2499 CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
2500 CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
2501 CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
2502 CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
2503 CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
2504 CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
2505 #undef CASE_REPEATED_PACKED_POD
2507 case GPBDataTypeBytes:
2508 case GPBDataTypeString:
2509 case GPBDataTypeMessage:
2510 case GPBDataTypeGroup:
2511 NSCAssert(NO, @"Non primitive types can't be packed");
2514 case GPBDataTypeEnum: {
2515 int32_t val = GPBCodedInputStreamReadEnum(state);
2516 if ([field.enumDescriptor isOpenOrValidValue:val]) {
2517 [(GPBEnumArray *)genericArray addRawValue:val];
2519 AddUnknownFieldVarint32(self, GPBFieldNumber(field), val);
2524 } // while(BytesUntilLimit() > 0)
2525 GPBCodedInputStreamPopLimit(state, limit);
2528 static void MergeRepeatedNotPackedFieldFromCodedInputStream(
2529 GPBMessage *self, GPBFieldDescriptor *field, GPBCodedInputStream *input,
2530 id<GPBExtensionRegistry> extensionRegistry) {
2531 GPBCodedInputStreamState *state = &input->state_;
2532 id genericArray = GetOrCreateArrayIvarWithField(self, field);
2533 switch (GPBGetFieldDataType(field)) {
2534 #define CASE_REPEATED_NOT_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
2535 case GPBDataType##NAME: { \
2536 TYPE val = GPBCodedInputStreamRead##NAME(state); \
2537 [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
2540 #define CASE_REPEATED_NOT_PACKED_OBJECT(NAME) \
2541 case GPBDataType##NAME: { \
2542 id val = GPBCodedInputStreamReadRetained##NAME(state); \
2543 [(NSMutableArray *)genericArray addObject:val]; \
2547 CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
2548 CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
2549 CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
2550 CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
2551 CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
2552 CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
2553 CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
2554 CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
2555 CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
2556 CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
2557 CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
2558 CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
2559 CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
2560 CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
2561 CASE_REPEATED_NOT_PACKED_OBJECT(String)
2562 #undef CASE_REPEATED_NOT_PACKED_POD
2563 #undef CASE_NOT_PACKED_OBJECT
2564 case GPBDataTypeMessage: {
2565 GPBMessage *message = [[field.msgClass alloc] init];
2566 [(NSMutableArray *)genericArray addObject:message];
2567 // The array will now retain message, so go ahead and release it in case
2568 // -readMessage:extensionRegistry: throws so it won't be leaked.
2570 [input readMessage:message extensionRegistry:extensionRegistry];
2573 case GPBDataTypeGroup: {
2574 GPBMessage *message = [[field.msgClass alloc] init];
2575 [(NSMutableArray *)genericArray addObject:message];
2576 // The array will now retain message, so go ahead and release it in case
2577 // -readGroup:extensionRegistry: throws so it won't be leaked.
2579 [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
2582 case GPBDataTypeEnum: {
2583 int32_t val = GPBCodedInputStreamReadEnum(state);
2584 if ([field.enumDescriptor isOpenOrValidValue:val]) {
2585 [(GPBEnumArray *)genericArray addRawValue:val];
2587 AddUnknownFieldVarint32(self, GPBFieldNumber(field), val);
2594 - (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input
2595 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
2596 endingTag:(uint32_t)endingTag {
2597 #if defined(DEBUG) && DEBUG
2598 NSAssert(endingTag == 0 || GPBWireFormatGetTagWireType(endingTag) == GPBWireFormatEndGroup,
2599 @"endingTag should have been an endGroup tag");
2601 GPBDescriptor *descriptor = [self descriptor];
2602 GPBCodedInputStreamState *state = &input->state_;
2604 NSUInteger startingIndex = 0;
2605 NSArray *fields = descriptor->fields_;
2606 BOOL isMessageSetWireFormat = descriptor.isWireFormat;
2607 NSUInteger numFields = fields.count;
2610 tag = GPBCodedInputStreamReadTag(state);
2611 if (tag == endingTag || tag == 0) {
2612 // If we got to the end (tag zero), when we were expecting the end group, this will
2614 GPBCodedInputStreamCheckLastTagWas(state, endingTag);
2617 for (NSUInteger i = 0; i < numFields; ++i) {
2618 if (startingIndex >= numFields) startingIndex = 0;
2619 GPBFieldDescriptor *fieldDescriptor = fields[startingIndex];
2620 if (GPBFieldTag(fieldDescriptor) == tag) {
2621 GPBFieldType fieldType = fieldDescriptor.fieldType;
2622 if (fieldType == GPBFieldTypeSingle) {
2623 MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, input, extensionRegistry);
2624 // Well formed protos will only have a single field once, advance
2625 // the starting index to the next field.
2627 } else if (fieldType == GPBFieldTypeRepeated) {
2628 if (fieldDescriptor.isPackable) {
2629 MergeRepeatedPackedFieldFromCodedInputStream(self, fieldDescriptor, input);
2630 // Well formed protos will only have a repeated field that is
2631 // packed once, advance the starting index to the next field.
2634 MergeRepeatedNotPackedFieldFromCodedInputStream(self, fieldDescriptor, input,
2637 } else { // fieldType == GPBFieldTypeMap
2638 // GPB*Dictionary or NSDictionary, exact type doesn't matter at this
2640 id map = GetOrCreateMapIvarWithField(self, fieldDescriptor);
2641 [input readMapEntry:map
2642 extensionRegistry:extensionRegistry
2643 field:fieldDescriptor
2644 parentMessage:self];
2651 } // for(i < numFields)
2653 if (merged) continue; // On to the next tag
2655 // Primitive, repeated types can be packed or unpacked on the wire, and
2656 // are parsed either way. The above loop covered tag in the preferred
2657 // for, so this need to check the alternate form.
2658 for (NSUInteger i = 0; i < numFields; ++i) {
2659 if (startingIndex >= numFields) startingIndex = 0;
2660 GPBFieldDescriptor *fieldDescriptor = fields[startingIndex];
2661 if ((fieldDescriptor.fieldType == GPBFieldTypeRepeated) &&
2662 !GPBFieldDataTypeIsObject(fieldDescriptor) &&
2663 (GPBFieldAlternateTag(fieldDescriptor) == tag)) {
2664 BOOL alternateIsPacked = !fieldDescriptor.isPackable;
2665 if (alternateIsPacked) {
2666 MergeRepeatedPackedFieldFromCodedInputStream(self, fieldDescriptor, input);
2667 // Well formed protos will only have a repeated field that is
2668 // packed once, advance the starting index to the next field.
2671 MergeRepeatedNotPackedFieldFromCodedInputStream(self, fieldDescriptor, input,
2681 if (merged) continue; // On to the next tag
2683 if (isMessageSetWireFormat) {
2684 if (GPBWireFormatMessageSetItemTag == tag) {
2685 [self parseMessageSet:input extensionRegistry:extensionRegistry];
2686 continue; // On to the next tag
2689 // ObjC Runtime currently doesn't track if a message supported extensions, so the check is
2691 GPBExtensionDescriptor *extension =
2692 [extensionRegistry extensionForDescriptor:descriptor
2693 fieldNumber:GPBWireFormatGetTagFieldNumber(tag)];
2695 GPBWireFormat wireType = GPBWireFormatGetTagWireType(tag);
2696 if (extension.wireType == wireType) {
2697 ExtensionMergeFromInputStream(extension, extension.packable, input, extensionRegistry,
2699 continue; // On to the next tag
2701 // Primitive, repeated types can be packed on unpacked on the wire, and are
2702 // parsed either way.
2703 if ([extension isRepeated] && !GPBDataTypeIsObject(extension->description_->dataType) &&
2704 (extension.alternateWireType == wireType)) {
2705 ExtensionMergeFromInputStream(extension, !extension.packable, input, extensionRegistry,
2707 continue; // On to the next tag
2712 ParseUnknownField(self, tag, input);
2716 #pragma mark - MergeFrom Support
2718 - (void)mergeFrom:(GPBMessage *)other {
2719 Class selfClass = [self class];
2720 Class otherClass = [other class];
2721 if (!([selfClass isSubclassOfClass:otherClass] || [otherClass isSubclassOfClass:selfClass])) {
2722 [NSException raise:NSInvalidArgumentException
2723 format:@"Classes must match %@ != %@", selfClass, otherClass];
2726 // We assume something will be done and become visible.
2727 GPBBecomeVisibleToAutocreator(self);
2729 GPBDescriptor *descriptor = [[self class] descriptor];
2731 for (GPBFieldDescriptor *field in descriptor->fields_) {
2732 GPBFieldType fieldType = field.fieldType;
2733 if (fieldType == GPBFieldTypeSingle) {
2734 int32_t hasIndex = GPBFieldHasIndex(field);
2735 uint32_t fieldNumber = GPBFieldNumber(field);
2736 if (!GPBGetHasIvar(other, hasIndex, fieldNumber)) {
2737 // Other doesn't have the field set, on to the next.
2740 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2741 switch (fieldDataType) {
2742 case GPBDataTypeBool:
2743 GPBSetBoolIvarWithFieldPrivate(self, field, GPBGetMessageBoolField(other, field));
2745 case GPBDataTypeSFixed32:
2746 case GPBDataTypeEnum:
2747 case GPBDataTypeInt32:
2748 case GPBDataTypeSInt32:
2749 GPBSetInt32IvarWithFieldPrivate(self, field, GPBGetMessageInt32Field(other, field));
2751 case GPBDataTypeFixed32:
2752 case GPBDataTypeUInt32:
2753 GPBSetUInt32IvarWithFieldPrivate(self, field, GPBGetMessageUInt32Field(other, field));
2755 case GPBDataTypeSFixed64:
2756 case GPBDataTypeInt64:
2757 case GPBDataTypeSInt64:
2758 GPBSetInt64IvarWithFieldPrivate(self, field, GPBGetMessageInt64Field(other, field));
2760 case GPBDataTypeFixed64:
2761 case GPBDataTypeUInt64:
2762 GPBSetUInt64IvarWithFieldPrivate(self, field, GPBGetMessageUInt64Field(other, field));
2764 case GPBDataTypeFloat:
2765 GPBSetFloatIvarWithFieldPrivate(self, field, GPBGetMessageFloatField(other, field));
2767 case GPBDataTypeDouble:
2768 GPBSetDoubleIvarWithFieldPrivate(self, field, GPBGetMessageDoubleField(other, field));
2770 case GPBDataTypeBytes:
2771 case GPBDataTypeString: {
2772 id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2773 GPBSetObjectIvarWithFieldPrivate(self, field, otherVal);
2776 case GPBDataTypeMessage:
2777 case GPBDataTypeGroup: {
2778 id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2779 if (GPBGetHasIvar(self, hasIndex, fieldNumber)) {
2780 GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2781 [message mergeFrom:otherVal];
2783 GPBMessage *message = [otherVal copy];
2784 GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
2789 } else if (fieldType == GPBFieldTypeRepeated) {
2790 // In the case of a list, they need to be appended, and there is no
2791 // _hasIvar to worry about setting.
2792 id otherArray = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2794 GPBDataType fieldDataType = field->description_->dataType;
2795 if (GPBDataTypeIsObject(fieldDataType)) {
2796 NSMutableArray *resultArray = GetOrCreateArrayIvarWithField(self, field);
2797 [resultArray addObjectsFromArray:otherArray];
2798 } else if (fieldDataType == GPBDataTypeEnum) {
2799 GPBEnumArray *resultArray = GetOrCreateArrayIvarWithField(self, field);
2800 [resultArray addRawValuesFromArray:otherArray];
2802 // The array type doesn't matter, that all implement
2803 // -addValuesFromArray:.
2804 GPBInt32Array *resultArray = GetOrCreateArrayIvarWithField(self, field);
2805 [resultArray addValuesFromArray:otherArray];
2808 } else { // fieldType = GPBFieldTypeMap
2809 // In the case of a map, they need to be merged, and there is no
2810 // _hasIvar to worry about setting.
2811 id otherDict = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2813 GPBDataType keyDataType = field.mapKeyDataType;
2814 GPBDataType valueDataType = field->description_->dataType;
2815 if (GPBDataTypeIsObject(keyDataType) && GPBDataTypeIsObject(valueDataType)) {
2816 NSMutableDictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
2817 [resultDict addEntriesFromDictionary:otherDict];
2818 } else if (valueDataType == GPBDataTypeEnum) {
2819 // The exact type doesn't matter, just need to know it is a
2820 // GPB*EnumDictionary.
2821 GPBInt32EnumDictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
2822 [resultDict addRawEntriesFromDictionary:otherDict];
2824 // The exact type doesn't matter, they all implement
2825 // -addEntriesFromDictionary:.
2826 GPBInt32Int32Dictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
2827 [resultDict addEntriesFromDictionary:otherDict];
2830 } // if (fieldType)..else if...else
2834 if (other->unknownFieldData_) {
2835 if (unknownFieldData_) {
2836 [unknownFieldData_ appendData:other->unknownFieldData_];
2838 unknownFieldData_ = [other->unknownFieldData_ mutableCopy];
2844 if (other->extensionMap_.count == 0) {
2848 if (extensionMap_ == nil) {
2849 extensionMap_ = CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
2851 for (GPBExtensionDescriptor *extension in other->extensionMap_) {
2852 id otherValue = [other->extensionMap_ objectForKey:extension];
2853 id value = [extensionMap_ objectForKey:extension];
2854 BOOL isMessageExtension = GPBExtensionIsMessage(extension);
2856 if (extension.repeated) {
2857 NSMutableArray *list = value;
2859 list = [[NSMutableArray alloc] init];
2860 [extensionMap_ setObject:list forKey:extension];
2863 if (isMessageExtension) {
2864 for (GPBMessage *otherListValue in otherValue) {
2865 GPBMessage *copiedValue = [otherListValue copy];
2866 [list addObject:copiedValue];
2867 [copiedValue release];
2870 [list addObjectsFromArray:otherValue];
2873 if (isMessageExtension) {
2875 [(GPBMessage *)value mergeFrom:(GPBMessage *)otherValue];
2877 GPBMessage *copiedValue = [otherValue copy];
2878 [extensionMap_ setObject:copiedValue forKey:extension];
2879 [copiedValue release];
2882 [extensionMap_ setObject:otherValue forKey:extension];
2886 if (isMessageExtension && !extension.isRepeated) {
2887 GPBMessage *autocreatedValue = [[autocreatedExtensionMap_ objectForKey:extension] retain];
2888 // Must remove from the map before calling GPBClearMessageAutocreator()
2889 // so that GPBClearMessageAutocreator() knows its safe to clear.
2890 [autocreatedExtensionMap_ removeObjectForKey:extension];
2891 GPBClearMessageAutocreator(autocreatedValue);
2892 [autocreatedValue release];
2898 #pragma mark - isEqual: & hash Support
2900 - (BOOL)isEqual:(id)other {
2901 if (other == self) {
2904 if (![other isKindOfClass:[GPBMessage class]]) {
2907 GPBMessage *otherMsg = other;
2908 GPBDescriptor *descriptor = [[self class] descriptor];
2909 if ([[otherMsg class] descriptor] != descriptor) {
2912 uint8_t *selfStorage = (uint8_t *)messageStorage_;
2913 uint8_t *otherStorage = (uint8_t *)otherMsg->messageStorage_;
2915 for (GPBFieldDescriptor *field in descriptor->fields_) {
2916 if (GPBFieldIsMapOrArray(field)) {
2917 // In the case of a list or map, there is no _hasIvar to worry about.
2918 // NOTE: These are NSArray/GPB*Array or NSDictionary/GPB*Dictionary, but
2919 // the type doesn't really matter as the objects all support -count and
2921 NSArray *resultMapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
2922 NSArray *otherMapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
2923 // nil and empty are equal
2924 if (resultMapOrArray.count != 0 || otherMapOrArray.count != 0) {
2925 if (![resultMapOrArray isEqual:otherMapOrArray]) {
2929 } else { // Single field
2930 int32_t hasIndex = GPBFieldHasIndex(field);
2931 uint32_t fieldNum = GPBFieldNumber(field);
2932 BOOL selfHas = GPBGetHasIvar(self, hasIndex, fieldNum);
2933 BOOL otherHas = GPBGetHasIvar(other, hasIndex, fieldNum);
2934 if (selfHas != otherHas) {
2935 return NO; // Differing has values, not equal.
2938 // Same has values, was no, nothing else to check for this field.
2941 // Now compare the values.
2942 GPBDataType fieldDataType = GPBGetFieldDataType(field);
2943 size_t fieldOffset = field->description_->offset;
2944 switch (fieldDataType) {
2945 case GPBDataTypeBool: {
2946 // Bools are stored in has_bits to avoid needing explicit space in
2947 // the storage structure.
2948 // (the field number passed to the HasIvar helper doesn't really
2949 // matter since the offset is never negative)
2950 BOOL selfValue = GPBGetHasIvar(self, (int32_t)(fieldOffset), 0);
2951 BOOL otherValue = GPBGetHasIvar(other, (int32_t)(fieldOffset), 0);
2952 if (selfValue != otherValue) {
2957 case GPBDataTypeSFixed32:
2958 case GPBDataTypeInt32:
2959 case GPBDataTypeSInt32:
2960 case GPBDataTypeEnum:
2961 case GPBDataTypeFixed32:
2962 case GPBDataTypeUInt32:
2963 case GPBDataTypeFloat: {
2964 GPBInternalCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits);
2965 // These are all 32bit, signed/unsigned doesn't matter for equality.
2966 uint32_t *selfValPtr = (uint32_t *)&selfStorage[fieldOffset];
2967 uint32_t *otherValPtr = (uint32_t *)&otherStorage[fieldOffset];
2968 if (*selfValPtr != *otherValPtr) {
2973 case GPBDataTypeSFixed64:
2974 case GPBDataTypeInt64:
2975 case GPBDataTypeSInt64:
2976 case GPBDataTypeFixed64:
2977 case GPBDataTypeUInt64:
2978 case GPBDataTypeDouble: {
2979 GPBInternalCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bits);
2980 // These are all 64bit, signed/unsigned doesn't matter for equality.
2981 uint64_t *selfValPtr = (uint64_t *)&selfStorage[fieldOffset];
2982 uint64_t *otherValPtr = (uint64_t *)&otherStorage[fieldOffset];
2983 if (*selfValPtr != *otherValPtr) {
2988 case GPBDataTypeBytes:
2989 case GPBDataTypeString:
2990 case GPBDataTypeMessage:
2991 case GPBDataTypeGroup: {
2992 // Type doesn't matter here, they all implement -isEqual:.
2993 id *selfValPtr = (id *)&selfStorage[fieldOffset];
2994 id *otherValPtr = (id *)&otherStorage[fieldOffset];
2995 if (![*selfValPtr isEqual:*otherValPtr]) {
3001 } // if(mapOrArray)...else
3004 // nil and empty are equal
3005 if (extensionMap_.count != 0 || otherMsg->extensionMap_.count != 0) {
3006 if (![extensionMap_ isEqual:otherMsg->extensionMap_]) {
3011 BOOL selfHas = unknownFieldData_ != nil;
3012 BOOL otherHas = otherMsg->unknownFieldData_ != nil;
3013 if (selfHas != otherHas) {
3014 return NO; // Only one has the data, not equal.
3016 // They both don't have (then equal) or they both have, and then compare the two.
3017 return !selfHas || [unknownFieldData_ isEqual:otherMsg->unknownFieldData_];
3020 // It is very difficult to implement a generic hash for ProtoBuf messages that
3021 // will perform well. If you need hashing on your ProtoBufs (eg you are using
3022 // them as dictionary keys) you will probably want to implement a ProtoBuf
3023 // message specific hash as a category on your protobuf class. Do not make it a
3024 // category on GPBMessage as you will conflict with this hash, and will possibly
3025 // override hash for all generated protobufs. A good implementation of hash will
3026 // be really fast, so we would recommend only hashing protobufs that have an
3027 // identifier field of some kind that you can easily hash. If you implement
3028 // hash, we would strongly recommend overriding isEqual: in your category as
3029 // well, as the default implementation of isEqual: is extremely slow, and may
3030 // drastically affect performance in large sets.
3031 - (NSUInteger)hash {
3032 GPBDescriptor *descriptor = [[self class] descriptor];
3033 const NSUInteger prime = 19;
3034 uint8_t *storage = (uint8_t *)messageStorage_;
3036 // Start with the descriptor and then mix it with some instance info.
3037 // Hopefully that will give a spread based on classes and what fields are set.
3038 NSUInteger result = (NSUInteger)descriptor;
3040 for (GPBFieldDescriptor *field in descriptor->fields_) {
3041 if (GPBFieldIsMapOrArray(field)) {
3042 // Exact type doesn't matter, just check if there are any elements.
3043 NSArray *mapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
3044 NSUInteger count = mapOrArray.count;
3046 // NSArray/NSDictionary use count, use the field number and the count.
3047 result = prime * result + GPBFieldNumber(field);
3048 result = prime * result + count;
3050 } else if (GPBGetHasIvarField(self, field)) {
3051 // Just using the field number seemed simple/fast, but then a small
3052 // message class where all the same fields are always set (to different
3053 // things would end up all with the same hash, so pull in some data).
3054 GPBDataType fieldDataType = GPBGetFieldDataType(field);
3055 size_t fieldOffset = field->description_->offset;
3056 switch (fieldDataType) {
3057 case GPBDataTypeBool: {
3058 // Bools are stored in has_bits to avoid needing explicit space in
3059 // the storage structure.
3060 // (the field number passed to the HasIvar helper doesn't really
3061 // matter since the offset is never negative)
3062 BOOL value = GPBGetHasIvar(self, (int32_t)(fieldOffset), 0);
3063 result = prime * result + value;
3066 case GPBDataTypeSFixed32:
3067 case GPBDataTypeInt32:
3068 case GPBDataTypeSInt32:
3069 case GPBDataTypeEnum:
3070 case GPBDataTypeFixed32:
3071 case GPBDataTypeUInt32:
3072 case GPBDataTypeFloat: {
3073 GPBInternalCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits);
3074 // These are all 32bit, just mix it in.
3075 uint32_t *valPtr = (uint32_t *)&storage[fieldOffset];
3076 result = prime * result + *valPtr;
3079 case GPBDataTypeSFixed64:
3080 case GPBDataTypeInt64:
3081 case GPBDataTypeSInt64:
3082 case GPBDataTypeFixed64:
3083 case GPBDataTypeUInt64:
3084 case GPBDataTypeDouble: {
3085 GPBInternalCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bits);
3086 // These are all 64bit, just mix what fits into an NSUInteger in.
3087 uint64_t *valPtr = (uint64_t *)&storage[fieldOffset];
3088 result = prime * result + (NSUInteger)(*valPtr);
3091 case GPBDataTypeBytes:
3092 case GPBDataTypeString: {
3093 // Type doesn't matter here, they both implement -hash:.
3094 id *valPtr = (id *)&storage[fieldOffset];
3095 result = prime * result + [*valPtr hash];
3099 case GPBDataTypeMessage:
3100 case GPBDataTypeGroup: {
3101 GPBMessage **valPtr = (GPBMessage **)&storage[fieldOffset];
3102 // Could call -hash on the sub message, but that could recurse pretty
3103 // deep; follow the lead of NSArray/NSDictionary and don't really
3104 // recurse for hash, instead use the field number and the descriptor
3105 // of the sub message. Yes, this could suck for a bunch of messages
3106 // where they all only differ in the sub messages, but if you are
3107 // using a message with sub messages for something that needs -hash,
3108 // odds are you are also copying them as keys, and that deep copy
3110 result = prime * result + GPBFieldNumber(field);
3111 result = prime * result + (NSUInteger)[[*valPtr class] descriptor];
3118 // Unknowns and extensions are not included.
3123 #pragma mark - Description Support
3125 - (NSString *)description {
3126 NSString *textFormat = GPBTextFormatForMessage(self, @" ");
3127 NSString *description =
3128 [NSString stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
3132 #if defined(DEBUG) && DEBUG
3134 // Xcode 5.1 added support for custom quick look info.
3135 // https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/CustomClassDisplay_in_QuickLook/CH01-quick_look_for_custom_objects/CH01-quick_look_for_custom_objects.html#//apple_ref/doc/uid/TP40014001-CH2-SW1
3136 - (id)debugQuickLookObject {
3137 return GPBTextFormatForMessage(self, nil);
3142 #pragma mark - SerializedSize
3144 - (size_t)serializedSize {
3145 GPBDescriptor *descriptor = [[self class] descriptor];
3148 // Has check is done explicitly, so GPBGetObjectIvarWithFieldNoAutocreate()
3149 // avoids doing the has check again.
3152 for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) {
3153 GPBFieldType fieldType = fieldDescriptor.fieldType;
3154 GPBDataType fieldDataType = GPBGetFieldDataType(fieldDescriptor);
3157 if (fieldType == GPBFieldTypeSingle) {
3158 BOOL selfHas = GPBGetHasIvarField(self, fieldDescriptor);
3160 continue; // Nothing to do.
3163 uint32_t fieldNumber = GPBFieldNumber(fieldDescriptor);
3165 switch (fieldDataType) {
3166 #define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
3167 case GPBDataType##NAME: { \
3168 TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
3169 result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
3172 #define CASE_SINGLE_OBJECT(NAME) \
3173 case GPBDataType##NAME: { \
3174 id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
3175 result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
3178 CASE_SINGLE_POD(Bool, BOOL, Bool)
3179 CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
3180 CASE_SINGLE_POD(SFixed32, int32_t, Int32)
3181 CASE_SINGLE_POD(Float, float, Float)
3182 CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
3183 CASE_SINGLE_POD(SFixed64, int64_t, Int64)
3184 CASE_SINGLE_POD(Double, double, Double)
3185 CASE_SINGLE_POD(Int32, int32_t, Int32)
3186 CASE_SINGLE_POD(Int64, int64_t, Int64)
3187 CASE_SINGLE_POD(SInt32, int32_t, Int32)
3188 CASE_SINGLE_POD(SInt64, int64_t, Int64)
3189 CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
3190 CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
3191 CASE_SINGLE_OBJECT(Bytes)
3192 CASE_SINGLE_OBJECT(String)
3193 CASE_SINGLE_OBJECT(Message)
3194 CASE_SINGLE_OBJECT(Group)
3195 CASE_SINGLE_POD(Enum, int32_t, Int32)
3196 #undef CASE_SINGLE_POD
3197 #undef CASE_SINGLE_OBJECT
3201 } else if (fieldType == GPBFieldTypeRepeated) {
3202 id genericArray = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
3203 NSUInteger count = [genericArray count];
3205 continue; // Nothing to add.
3207 __block size_t dataSize = 0;
3209 switch (fieldDataType) {
3210 #define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE) CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
3211 #define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME) \
3212 case GPBDataType##NAME: { \
3213 GPB##ARRAY_TYPE##Array *array = genericArray; \
3214 [array enumerate##ARRAY_ACCESSOR_NAME## \
3215 ValuesWithBlock:^(TYPE value, __unused NSUInteger idx, __unused BOOL * stop) { \
3216 dataSize += GPBCompute##NAME##SizeNoTag(value); \
3220 #define CASE_REPEATED_OBJECT(NAME) \
3221 case GPBDataType##NAME: { \
3222 for (id value in genericArray) { \
3223 dataSize += GPBCompute##NAME##SizeNoTag(value); \
3227 CASE_REPEATED_POD(Bool, BOOL, Bool)
3228 CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
3229 CASE_REPEATED_POD(SFixed32, int32_t, Int32)
3230 CASE_REPEATED_POD(Float, float, Float)
3231 CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
3232 CASE_REPEATED_POD(SFixed64, int64_t, Int64)
3233 CASE_REPEATED_POD(Double, double, Double)
3234 CASE_REPEATED_POD(Int32, int32_t, Int32)
3235 CASE_REPEATED_POD(Int64, int64_t, Int64)
3236 CASE_REPEATED_POD(SInt32, int32_t, Int32)
3237 CASE_REPEATED_POD(SInt64, int64_t, Int64)
3238 CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
3239 CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
3240 CASE_REPEATED_OBJECT(Bytes)
3241 CASE_REPEATED_OBJECT(String)
3242 CASE_REPEATED_OBJECT(Message)
3243 CASE_REPEATED_OBJECT(Group)
3244 CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
3245 #undef CASE_REPEATED_POD
3246 #undef CASE_REPEATED_POD_EXTRA
3247 #undef CASE_REPEATED_OBJECT
3250 size_t tagSize = GPBComputeTagSize(GPBFieldNumber(fieldDescriptor));
3251 if (fieldDataType == GPBDataTypeGroup) {
3252 // Groups have both a start and an end tag.
3255 if (fieldDescriptor.isPackable) {
3257 result += GPBComputeSizeTSizeAsInt32NoTag(dataSize);
3259 result += count * tagSize;
3263 } else { // fieldType == GPBFieldTypeMap
3264 if (GPBDataTypeIsObject(fieldDataType) &&
3265 (fieldDescriptor.mapKeyDataType == GPBDataTypeString)) {
3266 // If key type was string, then the map is an NSDictionary.
3267 NSDictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
3269 result += GPBDictionaryComputeSizeInternalHelper(map, fieldDescriptor);
3272 // Type will be GPB*GroupDictionary, exact type doesn't matter.
3273 GPBInt32Int32Dictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
3274 result += [map computeSerializedSizeAsField:fieldDescriptor];
3279 // Add any unknown fields.
3280 result += [unknownFieldData_ length];
3282 // Add any extensions.
3283 for (GPBExtensionDescriptor *extension in extensionMap_) {
3284 id value = [extensionMap_ objectForKey:extension];
3285 result += GPBComputeExtensionSerializedSizeIncludingTag(extension, value);
3291 #pragma mark - Resolve Methods Support
3293 typedef struct ResolveIvarAccessorMethodResult {
3295 SEL encodingSelector;
3296 } ResolveIvarAccessorMethodResult;
3298 // |field| can be __unsafe_unretained because they are created at startup
3299 // and are essentially global. No need to pay for retain/release when
3300 // they are captured in blocks.
3301 static void ResolveIvarGet(__unsafe_unretained GPBFieldDescriptor *field,
3302 ResolveIvarAccessorMethodResult *result) {
3303 GPBDataType fieldDataType = GPBGetFieldDataType(field);
3304 switch (fieldDataType) {
3305 #define CASE_GET(NAME, TYPE, TRUE_NAME) \
3306 case GPBDataType##NAME: { \
3307 result->impToAdd = imp_implementationWithBlock(^(id obj) { \
3308 return GPBGetMessage##TRUE_NAME##Field(obj, field); \
3310 result->encodingSelector = @selector(get##NAME); \
3313 #define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME) \
3314 case GPBDataType##NAME: { \
3315 result->impToAdd = imp_implementationWithBlock(^(id obj) { \
3316 return GPBGetObjectIvarWithField(obj, field); \
3318 result->encodingSelector = @selector(get##NAME); \
3321 CASE_GET(Bool, BOOL, Bool)
3322 CASE_GET(Fixed32, uint32_t, UInt32)
3323 CASE_GET(SFixed32, int32_t, Int32)
3324 CASE_GET(Float, float, Float)
3325 CASE_GET(Fixed64, uint64_t, UInt64)
3326 CASE_GET(SFixed64, int64_t, Int64)
3327 CASE_GET(Double, double, Double)
3328 CASE_GET(Int32, int32_t, Int32)
3329 CASE_GET(Int64, int64_t, Int64)
3330 CASE_GET(SInt32, int32_t, Int32)
3331 CASE_GET(SInt64, int64_t, Int64)
3332 CASE_GET(UInt32, uint32_t, UInt32)
3333 CASE_GET(UInt64, uint64_t, UInt64)
3334 CASE_GET_OBJECT(Bytes, id, Object)
3335 CASE_GET_OBJECT(String, id, Object)
3336 CASE_GET_OBJECT(Message, id, Object)
3337 CASE_GET_OBJECT(Group, id, Object)
3338 CASE_GET(Enum, int32_t, Enum)
3343 // See comment about __unsafe_unretained on ResolveIvarGet.
3344 static void ResolveIvarSet(__unsafe_unretained GPBFieldDescriptor *field,
3345 ResolveIvarAccessorMethodResult *result) {
3346 GPBDataType fieldDataType = GPBGetFieldDataType(field);
3347 switch (fieldDataType) {
3348 #define CASE_SET(NAME, TYPE, TRUE_NAME) \
3349 case GPBDataType##NAME: { \
3350 result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { \
3351 return GPBSet##TRUE_NAME##IvarWithFieldPrivate(obj, field, value); \
3353 result->encodingSelector = @selector(set##NAME:); \
3356 #define CASE_SET_COPY(NAME) \
3357 case GPBDataType##NAME: { \
3358 result->impToAdd = imp_implementationWithBlock(^(id obj, id value) { \
3359 return GPBSetRetainedObjectIvarWithFieldPrivate(obj, field, [value copy]); \
3361 result->encodingSelector = @selector(set##NAME:); \
3364 CASE_SET(Bool, BOOL, Bool)
3365 CASE_SET(Fixed32, uint32_t, UInt32)
3366 CASE_SET(SFixed32, int32_t, Int32)
3367 CASE_SET(Float, float, Float)
3368 CASE_SET(Fixed64, uint64_t, UInt64)
3369 CASE_SET(SFixed64, int64_t, Int64)
3370 CASE_SET(Double, double, Double)
3371 CASE_SET(Int32, int32_t, Int32)
3372 CASE_SET(Int64, int64_t, Int64)
3373 CASE_SET(SInt32, int32_t, Int32)
3374 CASE_SET(SInt64, int64_t, Int64)
3375 CASE_SET(UInt32, uint32_t, UInt32)
3376 CASE_SET(UInt64, uint64_t, UInt64)
3377 CASE_SET_COPY(Bytes)
3378 CASE_SET_COPY(String)
3379 CASE_SET(Message, id, Object)
3380 CASE_SET(Group, id, Object)
3381 CASE_SET(Enum, int32_t, Enum)
3386 // Highly optimized routines for determining selector types.
3387 // Meant to only be used by GPBMessage when resolving selectors in
3388 // `+ (BOOL)resolveInstanceMethod:(SEL)sel`.
3389 // These routines are intended to make negative decisions as fast as possible.
3390 GPB_INLINE char GPBFastToUpper(char c) { return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c; }
3392 GPB_INLINE BOOL GPBIsGetSelForField(const char *selName, GPBFieldDescriptor *descriptor) {
3393 // Does 'selName' == '<name>'?
3394 // selName and <name> have to be at least two characters long (i.e. ('a', '\0')" is the shortest
3395 // selector you can have).
3396 return (selName[0] == descriptor->description_->name[0]) &&
3397 (selName[1] == descriptor->description_->name[1]) &&
3398 (strcmp(selName + 1, descriptor->description_->name + 1) == 0);
3401 GPB_INLINE BOOL GPBIsSetSelForField(const char *selName, size_t selNameLength,
3402 GPBFieldDescriptor *descriptor) {
3403 // Does 'selName' == 'set<Name>:'?
3404 // Do fastest compares up front
3405 const size_t kSetLength = strlen("set");
3406 // kSetLength is 3 and one for the colon.
3407 if (selNameLength <= kSetLength + 1) {
3410 if (selName[kSetLength] != GPBFastToUpper(descriptor->description_->name[0])) {
3414 // NB we check for "set" and the colon later in this routine because we have already checked for
3415 // starting with "s" and ending with ":" in `+resolveInstanceMethod:` before we get here.
3416 if (selName[0] != 's' || selName[1] != 'e' || selName[2] != 't') {
3420 if (selName[selNameLength - 1] != ':') {
3425 size_t nameLength = strlen(descriptor->description_->name);
3426 size_t setSelLength = nameLength + kSetLength + 1;
3427 if (selNameLength != setSelLength) {
3430 if (strncmp(&selName[kSetLength + 1], descriptor->description_->name + 1, nameLength - 1) != 0) {
3437 GPB_INLINE BOOL GPBFieldHasHas(GPBFieldDescriptor *descriptor) {
3438 // It gets has/setHas selectors if...
3439 // - not in a oneof (negative has index)
3440 // - not clearing on zero
3441 return (descriptor->description_->hasIndex >= 0) &&
3442 ((descriptor->description_->flags & GPBFieldClearHasIvarOnZero) == 0);
3445 GPB_INLINE BOOL GPBIsHasSelForField(const char *selName, size_t selNameLength,
3446 GPBFieldDescriptor *descriptor) {
3447 // Does 'selName' == 'has<Name>'?
3448 // Do fastest compares up front.
3449 const size_t kHasLength = strlen("has");
3450 if (selNameLength <= kHasLength) {
3453 if (selName[0] != 'h' || selName[1] != 'a' || selName[2] != 's') {
3456 if (selName[kHasLength] != GPBFastToUpper(descriptor->description_->name[0])) {
3459 if (!GPBFieldHasHas(descriptor)) {
3464 size_t nameLength = strlen(descriptor->description_->name);
3465 size_t setSelLength = nameLength + kHasLength;
3466 if (selNameLength != setSelLength) {
3470 if (strncmp(&selName[kHasLength + 1], descriptor->description_->name + 1, nameLength - 1) != 0) {
3476 GPB_INLINE BOOL GPBIsCountSelForField(const char *selName, size_t selNameLength,
3477 GPBFieldDescriptor *descriptor) {
3478 // Does 'selName' == '<name>_Count'?
3479 // Do fastest compares up front.
3480 if (selName[0] != descriptor->description_->name[0]) {
3483 const size_t kCountLength = strlen("_Count");
3484 if (selNameLength <= kCountLength) {
3488 if (selName[selNameLength - kCountLength] != '_') {
3493 size_t nameLength = strlen(descriptor->description_->name);
3494 size_t setSelLength = nameLength + kCountLength;
3495 if (selNameLength != setSelLength) {
3498 if (strncmp(selName, descriptor->description_->name, nameLength) != 0) {
3501 if (strncmp(&selName[nameLength], "_Count", kCountLength) != 0) {
3507 GPB_INLINE BOOL GPBIsSetHasSelForField(const char *selName, size_t selNameLength,
3508 GPBFieldDescriptor *descriptor) {
3509 // Does 'selName' == 'setHas<Name>:'?
3510 // Do fastest compares up front.
3511 const size_t kSetHasLength = strlen("setHas");
3512 // kSetHasLength is 6 and one for the colon.
3513 if (selNameLength <= kSetHasLength + 1) {
3516 if (selName[selNameLength - 1] != ':') {
3519 if (selName[kSetHasLength] != GPBFastToUpper(descriptor->description_->name[0])) {
3522 if (selName[0] != 's' || selName[1] != 'e' || selName[2] != 't' || selName[3] != 'H' ||
3523 selName[4] != 'a' || selName[5] != 's') {
3527 if (!GPBFieldHasHas(descriptor)) {
3531 size_t nameLength = strlen(descriptor->description_->name);
3532 size_t setHasSelLength = nameLength + kSetHasLength + 1;
3533 if (selNameLength != setHasSelLength) {
3536 if (strncmp(&selName[kSetHasLength + 1], descriptor->description_->name + 1, nameLength - 1) !=
3544 GPB_INLINE BOOL GPBIsCaseOfSelForOneOf(const char *selName, size_t selNameLength,
3545 GPBOneofDescriptor *descriptor) {
3546 // Does 'selName' == '<name>OneOfCase'?
3547 // Do fastest compares up front.
3548 if (selName[0] != descriptor->name_[0]) {
3551 const size_t kOneOfCaseLength = strlen("OneOfCase");
3552 if (selNameLength <= kOneOfCaseLength) {
3555 if (selName[selNameLength - kOneOfCaseLength] != 'O') {
3560 size_t nameLength = strlen(descriptor->name_);
3561 size_t setSelLength = nameLength + kOneOfCaseLength;
3562 if (selNameLength != setSelLength) {
3565 if (strncmp(&selName[nameLength], "OneOfCase", kOneOfCaseLength) != 0) {
3568 if (strncmp(selName, descriptor->name_, nameLength) != 0) {
3574 + (BOOL)resolveInstanceMethod:(SEL)sel {
3575 const GPBDescriptor *descriptor = [self descriptor];
3577 return [super resolveInstanceMethod:sel];
3579 ResolveIvarAccessorMethodResult result = {NULL, NULL};
3581 const char *selName = sel_getName(sel);
3582 const size_t selNameLength = strlen(selName);
3583 // A setter has a leading 's' and a trailing ':' (e.g. 'setFoo:' or 'setHasFoo:').
3584 BOOL couldBeSetter = selName[0] == 's' && selName[selNameLength - 1] == ':';
3585 if (couldBeSetter) {
3586 // See comment about __unsafe_unretained on ResolveIvarGet.
3587 for (__unsafe_unretained GPBFieldDescriptor *field in descriptor->fields_) {
3588 BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
3589 if (GPBIsSetSelForField(selName, selNameLength, field)) {
3591 // Local for syntax so the block can directly capture it and not the
3593 result.impToAdd = imp_implementationWithBlock(^(id obj, id value) {
3594 GPBSetObjectIvarWithFieldPrivate(obj, field, value);
3596 result.encodingSelector = @selector(setArray:);
3598 ResolveIvarSet(field, &result);
3601 } else if (!isMapOrArray && GPBIsSetHasSelForField(selName, selNameLength, field)) {
3602 result.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) {
3604 [NSException raise:NSInvalidArgumentException
3605 format:@"%@: %@ can only be set to NO (to clear field).", [obj class],
3606 NSStringFromSelector(sel)];
3608 GPBClearMessageField(obj, field);
3610 result.encodingSelector = @selector(setBool:);
3615 // See comment about __unsafe_unretained on ResolveIvarGet.
3616 for (__unsafe_unretained GPBFieldDescriptor *field in descriptor->fields_) {
3617 BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
3618 if (GPBIsGetSelForField(selName, field)) {
3620 if (field.fieldType == GPBFieldTypeRepeated) {
3621 result.impToAdd = imp_implementationWithBlock(^(id obj) {
3622 return GetArrayIvarWithField(obj, field);
3625 result.impToAdd = imp_implementationWithBlock(^(id obj) {
3626 return GetMapIvarWithField(obj, field);
3629 result.encodingSelector = @selector(getArray);
3631 ResolveIvarGet(field, &result);
3635 if (!isMapOrArray) {
3636 if (GPBIsHasSelForField(selName, selNameLength, field)) {
3637 int32_t index = GPBFieldHasIndex(field);
3638 uint32_t fieldNum = GPBFieldNumber(field);
3639 result.impToAdd = imp_implementationWithBlock(^(id obj) {
3640 return GPBGetHasIvar(obj, index, fieldNum);
3642 result.encodingSelector = @selector(getBool);
3645 GPBOneofDescriptor *oneof = field->containingOneof_;
3646 if (oneof && GPBIsCaseOfSelForOneOf(selName, selNameLength, oneof)) {
3647 int32_t index = GPBFieldHasIndex(field);
3648 result.impToAdd = imp_implementationWithBlock(^(id obj) {
3649 return GPBGetHasOneof(obj, index);
3651 result.encodingSelector = @selector(getEnum);
3656 if (GPBIsCountSelForField(selName, selNameLength, field)) {
3657 result.impToAdd = imp_implementationWithBlock(^(id obj) {
3658 // Type doesn't matter, all *Array and *Dictionary types support
3660 NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
3661 return [arrayOrMap count];
3663 result.encodingSelector = @selector(getArrayCount);
3670 if (result.impToAdd) {
3671 const char *encoding = GPBMessageEncodingForSelector(result.encodingSelector, YES);
3672 Class msgClass = descriptor.messageClass;
3673 BOOL methodAdded = class_addMethod(msgClass, sel, result.impToAdd, encoding);
3674 // class_addMethod() is documented as also failing if the method was already
3675 // added; so we check if the method is already there and return success so
3676 // the method dispatch will still happen. Why would it already be added?
3677 // Two threads could cause the same method to be bound at the same time,
3678 // but only one will actually bind it; the other still needs to return true
3679 // so things will dispatch.
3681 methodAdded = GPBClassHasSel(msgClass, sel);
3685 return [super resolveInstanceMethod:sel];
3688 + (BOOL)resolveClassMethod:(SEL)sel {
3689 // Extensions scoped to a Message and looked up via class methods.
3690 if (GPBResolveExtensionClassMethod(self, sel)) {
3693 return [super resolveClassMethod:sel];
3696 #pragma mark - NSCoding Support
3698 + (BOOL)supportsSecureCoding {
3702 - (instancetype)initWithCoder:(NSCoder *)aDecoder {
3705 NSData *data = [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
3707 GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
3709 [self mergeFromCodedInputStream:input extensionRegistry:nil endingTag:0];
3718 - (void)encodeWithCoder:(NSCoder *)aCoder {
3719 #if defined(DEBUG) && DEBUG
3720 if (extensionMap_.count) {
3721 // Hint to go along with the docs on GPBMessage about this.
3723 // Note: This is incomplete, in that it only checked the "root" message,
3724 // if a sub message in a field has extensions, the issue still exists. A
3725 // recursive check could be done here (like the work in
3726 // GPBMessageDropUnknownFieldsRecursively()), but that has the potential to
3727 // be expensive and could slow down serialization in DEBUG enough to cause
3728 // developers other problems.
3729 NSLog(@"Warning: writing out a GPBMessage (%@) via NSCoding and it"
3730 @" has %ld extensions; when read back in, those fields will be"
3731 @" in the unknownFields property instead.",
3732 [self class], (long)extensionMap_.count);
3735 NSData *data = [self data];
3737 [aCoder encodeObject:data forKey:kGPBDataCoderKey];
3741 #pragma mark - KVC Support
3743 + (BOOL)accessInstanceVariablesDirectly {
3744 // Make sure KVC doesn't use instance variables.
3750 #pragma mark - Messages from GPBUtilities.h but defined here for access to helpers.
3752 // Only exists for public api, no core code should use this.
3753 id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field) {
3754 #if defined(DEBUG) && DEBUG
3755 if (field.fieldType != GPBFieldTypeRepeated) {
3756 [NSException raise:NSInvalidArgumentException
3757 format:@"%@.%@ is not a repeated field.", [self class], field.name];
3760 return GetOrCreateArrayIvarWithField(self, field);
3763 // Only exists for public api, no core code should use this.
3764 id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) {
3765 #if defined(DEBUG) && DEBUG
3766 if (field.fieldType != GPBFieldTypeMap) {
3767 [NSException raise:NSInvalidArgumentException
3768 format:@"%@.%@ is not a map<> field.", [self class], field.name];
3771 return GetOrCreateMapIvarWithField(self, field);
3774 id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
3775 NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here");
3776 if (!GPBFieldDataTypeIsMessage(field)) {
3777 if (GPBGetHasIvarField(self, field)) {
3778 uint8_t *storage = (uint8_t *)self->messageStorage_;
3779 id *typePtr = (id *)&storage[field->description_->offset];
3782 // Not set...non messages (string/data), get their default.
3783 return field.defaultValue.valueMessage;
3786 uint8_t *storage = (uint8_t *)self->messageStorage_;
3787 _Atomic(id) *typePtr = (_Atomic(id) *)&storage[field->description_->offset];
3788 id msg = atomic_load(typePtr);
3794 id autocreated = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
3795 if (atomic_compare_exchange_strong(typePtr, &expected, autocreated)) {
3796 // Value was set, return it.
3800 // Some other thread set it, release the one created and return what got set.
3801 GPBClearMessageAutocreator(autocreated);
3802 [autocreated release];
3806 NSData *GPBMessageUnknownFieldsData(GPBMessage *self) { return self->unknownFieldData_; }
3808 #pragma clang diagnostic pop