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