blob: 447c749aa76779877e6f754a69f248ba414cf1db [file] [log] [blame]
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001// 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"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040038#import "GPBMessage_PackagePrivate.h"
Thomas Van Lentend846b0b2015-06-08 16:24:57 -040039#import "GPBUnknownField.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040040#import "GPBUnknownFieldSet.h"
41
42static void AppendTextFormatForMessage(GPBMessage *message,
43 NSMutableString *toStr,
44 NSString *lineIndent);
45
46NSData *GPBEmptyNSData(void) {
47 static dispatch_once_t onceToken;
48 static NSData *defaultNSData = nil;
49 dispatch_once(&onceToken, ^{
50 defaultNSData = [[NSData alloc] init];
51 });
52 return defaultNSData;
53}
54
Thomas Van Lentend846b0b2015-06-08 16:24:57 -040055void GPBCheckRuntimeVersionInternal(int32_t version) {
56 if (version != GOOGLE_PROTOBUF_OBJC_GEN_VERSION) {
57 [NSException raise:NSInternalInconsistencyException
58 format:@"Linked to ProtocolBuffer runtime version %d,"
59 @" but code compiled with version %d!",
60 GOOGLE_PROTOBUF_OBJC_GEN_VERSION, version];
61 }
62}
63
Thomas Van Lenten30650d82015-05-01 08:57:16 -040064BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber) {
65 GPBDescriptor *descriptor = [self descriptor];
66 GPBFieldDescriptor *field = [descriptor fieldWithNumber:fieldNumber];
67 return GPBMessageHasFieldSet(self, field);
68}
69
70BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field) {
71 if (self == nil || field == nil) return NO;
72
73 // Repeated/Map don't use the bit, they check the count.
74 if (GPBFieldIsMapOrArray(field)) {
75 // Array/map type doesn't matter, since GPB*Array/NSArray and
76 // GPB*Dictionary/NSDictionary all support -count;
77 NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
78 return (arrayOrMap.count > 0);
79 } else {
80 return GPBGetHasIvarField(self, field);
81 }
82}
83
84void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field) {
85 // If not set, nothing to do.
86 if (!GPBGetHasIvarField(self, field)) {
87 return;
88 }
89
90 if (GPBFieldStoresObject(field)) {
91 // Object types are handled slightly differently, they need to be released.
92 uint8_t *storage = (uint8_t *)self->messageStorage_;
93 id *typePtr = (id *)&storage[field->description_->offset];
94 [*typePtr release];
95 *typePtr = nil;
96 } else {
97 // POD types just need to clear the has bit as the Get* method will
98 // fetch the default when needed.
99 }
100 GPBSetHasIvarField(self, field, NO);
101}
102
103BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400104 NSCAssert(self->messageStorage_ != NULL,
105 @"%@: All messages should have storage (from init)",
106 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400107 if (idx < 0) {
108 NSCAssert(fieldNumber != 0, @"Invalid field number.");
109 BOOL hasIvar = (self->messageStorage_->_has_storage_[-idx] == fieldNumber);
110 return hasIvar;
111 } else {
112 NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
113 uint32_t byteIndex = idx / 32;
114 uint32_t bitMask = (1 << (idx % 32));
115 BOOL hasIvar =
116 (self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO;
117 return hasIvar;
118 }
119}
120
121uint32_t GPBGetHasOneof(GPBMessage *self, int32_t idx) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400122 NSCAssert(idx < 0, @"%@: invalid index (%d) for oneof.",
123 [self class], idx);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400124 uint32_t result = self->messageStorage_->_has_storage_[-idx];
125 return result;
126}
127
128void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber,
129 BOOL value) {
130 if (idx < 0) {
131 NSCAssert(fieldNumber != 0, @"Invalid field number.");
132 uint32_t *has_storage = self->messageStorage_->_has_storage_;
133 has_storage[-idx] = (value ? fieldNumber : 0);
134 } else {
135 NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
136 uint32_t *has_storage = self->messageStorage_->_has_storage_;
137 uint32_t byte = idx / 32;
138 uint32_t bitMask = (1 << (idx % 32));
139 if (value) {
140 has_storage[byte] |= bitMask;
141 } else {
142 has_storage[byte] &= ~bitMask;
143 }
144 }
145}
146
147void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400148 int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) {
149 uint32_t fieldNumberSet = GPBGetHasOneof(self, oneofHasIndex);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400150 if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) {
151 // Do nothing/nothing set in the oneof.
152 return;
153 }
154
155 // Like GPBClearMessageField(), free the memory if an objecttype is set,
156 // pod types don't need to do anything.
157 GPBFieldDescriptor *fieldSet = [oneof fieldWithNumber:fieldNumberSet];
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400158 NSCAssert(fieldSet,
159 @"%@: oneof set to something (%u) not in the oneof?",
160 [self class], fieldNumberSet);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400161 if (fieldSet && GPBFieldStoresObject(fieldSet)) {
162 uint8_t *storage = (uint8_t *)self->messageStorage_;
163 id *typePtr = (id *)&storage[fieldSet->description_->offset];
164 [*typePtr release];
165 *typePtr = nil;
166 }
167
168 // Set to nothing stored in the oneof.
169 // (field number doesn't matter since setting to nothing).
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400170 GPBSetHasIvar(self, oneofHasIndex, 1, NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400171}
172
173#pragma mark - IVar accessors
174
175//%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE)
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400176//%TYPE GPBGetMessage##NAME##Field(GPBMessage *self,
177//% TYPE$S NAME$S GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400178//% if (GPBGetHasIvarField(self, field)) {
179//% uint8_t *storage = (uint8_t *)self->messageStorage_;
180//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
181//% return *typePtr;
182//% } else {
183//% return field.defaultValue.value##NAME;
184//% }
185//%}
186//%
187//%// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400188//%void GPBSetMessage##NAME##Field(GPBMessage *self,
189//% NAME$S GPBFieldDescriptor *field,
190//% NAME$S TYPE value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400191//% if (self == nil || field == nil) return;
192//% GPBFileSyntax syntax = [self descriptor].file.syntax;
193//% GPBSet##NAME##IvarWithFieldInternal(self, field, value, syntax);
194//%}
195//%
196//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self,
197//% NAME$S GPBFieldDescriptor *field,
198//% NAME$S TYPE value,
199//% NAME$S GPBFileSyntax syntax) {
200//% GPBOneofDescriptor *oneof = field->containingOneof_;
201//% if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400202//% GPBMessageFieldDescription *fieldDesc = field->description_;
203//% GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400204//% }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400205//% NSCAssert(self->messageStorage_ != NULL,
206//% @"%@: All messages should have storage (from init)",
207//% [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400208//%#if defined(__clang_analyzer__)
209//% if (self->messageStorage_ == NULL) return;
210//%#endif
211//% uint8_t *storage = (uint8_t *)self->messageStorage_;
212//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
213//% *typePtr = value;
214//% // proto2: any value counts as having been set; proto3, it
215//% // has to be a non zero value.
216//% BOOL hasValue =
217//% (syntax == GPBFileSyntaxProto2) || (value != (TYPE)0);
218//% GPBSetHasIvarField(self, field, hasValue);
219//% GPBBecomeVisibleToAutocreator(self);
220//%}
221//%
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400222//%PDDM-DEFINE IVAR_ALIAS_DEFN_OBJECT(NAME, TYPE)
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400223//%// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400224//%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self,
225//% TYPE$S NAME$S GPBFieldDescriptor *field) {
226//% return (TYPE *)GPBGetObjectIvarWithField(self, field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400227//%}
228//%
229//%// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400230//%void GPBSetMessage##NAME##Field(GPBMessage *self,
231//% NAME$S GPBFieldDescriptor *field,
232//% NAME$S TYPE *value) {
233//% GPBSetObjectIvarWithField(self, field, (id)value);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400234//%}
235//%
236
237// Object types are handled slightly differently, they need to be released
238// and retained.
239
240void GPBSetAutocreatedRetainedObjectIvarWithField(
241 GPBMessage *self, GPBFieldDescriptor *field,
242 id __attribute__((ns_consumed)) value) {
243 uint8_t *storage = (uint8_t *)self->messageStorage_;
244 id *typePtr = (id *)&storage[field->description_->offset];
245 NSCAssert(*typePtr == NULL, @"Can't set autocreated object more than once.");
246 *typePtr = value;
247}
248
249void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self,
250 GPBFieldDescriptor *field) {
251 if (GPBGetHasIvarField(self, field)) {
252 return;
253 }
254 uint8_t *storage = (uint8_t *)self->messageStorage_;
255 id *typePtr = (id *)&storage[field->description_->offset];
256 GPBMessage *oldValue = *typePtr;
257 *typePtr = NULL;
258 GPBClearMessageAutocreator(oldValue);
259 [oldValue release];
260}
261
262// This exists only for briging some aliased types, nothing else should use it.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400263static void GPBSetObjectIvarWithField(GPBMessage *self,
264 GPBFieldDescriptor *field, id value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400265 if (self == nil || field == nil) return;
266 GPBFileSyntax syntax = [self descriptor].file.syntax;
267 GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain],
268 syntax);
269}
270
271void GPBSetObjectIvarWithFieldInternal(GPBMessage *self,
272 GPBFieldDescriptor *field, id value,
273 GPBFileSyntax syntax) {
274 GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain],
275 syntax);
276}
277
278void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
279 GPBFieldDescriptor *field,
280 id value, GPBFileSyntax syntax) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400281 NSCAssert(self->messageStorage_ != NULL,
282 @"%@: All messages should have storage (from init)",
283 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400284#if defined(__clang_analyzer__)
285 if (self->messageStorage_ == NULL) return;
286#endif
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400287 GPBDataType fieldType = GPBGetFieldDataType(field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400288 BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400289 BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400290#ifdef DEBUG
291 if (value == nil && !isMapOrArray && !fieldIsMessage &&
292 field.hasDefaultValue) {
293 // Setting a message to nil is an obvious way to "clear" the value
294 // as there is no way to set a non-empty default value for messages.
295 //
296 // For Strings and Bytes that have default values set it is not clear what
297 // should be done when their value is set to nil. Is the intention just to
298 // clear the set value and reset to default, or is the intention to set the
299 // value to the empty string/data? Arguments can be made for both cases.
300 // 'nil' has been abused as a replacement for an empty string/data in ObjC.
301 // We decided to be consistent with all "object" types and clear the has
302 // field, and fall back on the default value. The warning below will only
303 // appear in debug, but the could should be changed so the intention is
304 // clear.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400305 NSString *hasSel = NSStringFromSelector(field->hasOrCountSel_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400306 NSString *propName = field.name;
307 NSString *className = self.descriptor.name;
308 NSLog(@"warning: '%@.%@ = nil;' is not clearly defined for fields with "
309 @"default values. Please use '%@.%@ = %@' if you want to set it to "
310 @"empty, or call '%@.%@ = NO' to reset it to it's default value of "
311 @"'%@'. Defaulting to resetting default value.",
312 className, propName, className, propName,
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400313 (fieldType == GPBDataTypeString) ? @"@\"\"" : @"GPBEmptyNSData()",
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400314 className, hasSel, field.defaultValue.valueString);
315 // Note: valueString, depending on the type, it could easily be
316 // valueData/valueMessage.
317 }
318#endif // DEBUG
319 if (!isMapOrArray) {
320 // Non repeated/map can be in an oneof, clear any existing value from the
321 // oneof.
322 GPBOneofDescriptor *oneof = field->containingOneof_;
323 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400324 GPBMessageFieldDescription *fieldDesc = field->description_;
325 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400326 }
327 // Clear "has" if they are being set to nil.
328 BOOL setHasValue = (value != nil);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400329 // Under proto3, Bytes & String fields get cleared by resetting them to
330 // their default (empty) values, so if they are set to something of length
331 // zero, they are being cleared.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400332 if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage &&
333 ([value length] == 0)) {
334 setHasValue = NO;
335 value = nil;
336 }
337 GPBSetHasIvarField(self, field, setHasValue);
338 }
339 uint8_t *storage = (uint8_t *)self->messageStorage_;
340 id *typePtr = (id *)&storage[field->description_->offset];
341
342 id oldValue = *typePtr;
343
344 *typePtr = value;
345
346 if (oldValue) {
347 if (isMapOrArray) {
348 if (field.fieldType == GPBFieldTypeRepeated) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400349 // If the old array was autocreated by us, then clear it.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400350 if (GPBDataTypeIsObject(fieldType)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400351 GPBAutocreatedArray *autoArray = oldValue;
352 if (autoArray->_autocreator == self) {
353 autoArray->_autocreator = nil;
354 }
355 } else {
356 // Type doesn't matter, it is a GPB*Array.
357 GPBInt32Array *gpbArray = oldValue;
358 if (gpbArray->_autocreator == self) {
359 gpbArray->_autocreator = nil;
360 }
361 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400362 } else { // GPBFieldTypeMap
363 // If the old map was autocreated by us, then clear it.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400364 if ((field.mapKeyDataType == GPBDataTypeString) &&
365 GPBDataTypeIsObject(fieldType)) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400366 GPBAutocreatedDictionary *autoDict = oldValue;
367 if (autoDict->_autocreator == self) {
368 autoDict->_autocreator = nil;
369 }
370 } else {
371 // Type doesn't matter, it is a GPB*Dictionary.
372 GPBInt32Int32Dictionary *gpbDict = oldValue;
373 if (gpbDict->_autocreator == self) {
374 gpbDict->_autocreator = nil;
375 }
376 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400377 }
378 } else if (fieldIsMessage) {
379 // If the old message value was autocreated by us, then clear it.
380 GPBMessage *oldMessageValue = oldValue;
381 if (GPBWasMessageAutocreatedBy(oldMessageValue, self)) {
382 GPBClearMessageAutocreator(oldMessageValue);
383 }
384 }
385 [oldValue release];
386 }
387
388 GPBBecomeVisibleToAutocreator(self);
389}
390
391id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
392 GPBFieldDescriptor *field) {
393 if (self->messageStorage_ == nil) {
394 return nil;
395 }
396 uint8_t *storage = (uint8_t *)self->messageStorage_;
397 id *typePtr = (id *)&storage[field->description_->offset];
398 return *typePtr;
399}
400
401id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
402 NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here");
403 if (GPBGetHasIvarField(self, field)) {
404 uint8_t *storage = (uint8_t *)self->messageStorage_;
405 id *typePtr = (id *)&storage[field->description_->offset];
406 return *typePtr;
407 }
408 // Not set...
409
410 // Non messages (string/data), get their default.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400411 if (!GPBFieldDataTypeIsMessage(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400412 return field.defaultValue.valueMessage;
413 }
414
Thomas Van Lentenbd41a392016-03-21 11:11:14 -0400415 GPBPrepareReadOnlySemaphore(self);
Thomas Van Lentend6590d62015-12-17 14:35:44 -0500416 dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400417 GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
418 if (!result) {
419 // For non repeated messages, create the object, set it and return it.
420 // This object will not initially be visible via GPBGetHasIvar, so
421 // we save its creator so it can become visible if it's mutated later.
422 result = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
423 GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result);
424 }
Thomas Van Lentend6590d62015-12-17 14:35:44 -0500425 dispatch_semaphore_signal(self->readOnlySemaphore_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400426 return result;
427}
428
429// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400430int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400431 GPBFileSyntax syntax = [self descriptor].file.syntax;
432 return GPBGetEnumIvarWithFieldInternal(self, field, syntax);
433}
434
435int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
436 GPBFieldDescriptor *field,
437 GPBFileSyntax syntax) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400438 int32_t result = GPBGetMessageInt32Field(self, field);
439 // If this is presevering unknown enums, make sure the value is valid before
440 // returning it.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400441 if (GPBHasPreservingUnknownEnumSemantics(syntax) &&
442 ![field isValidEnumValue:result]) {
443 result = kGPBUnrecognizedEnumeratorValue;
444 }
445 return result;
446}
447
448// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400449void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
450 int32_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400451 GPBFileSyntax syntax = [self descriptor].file.syntax;
452 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
453}
454
455void GPBSetEnumIvarWithFieldInternal(GPBMessage *self,
456 GPBFieldDescriptor *field, int32_t value,
457 GPBFileSyntax syntax) {
458 // Don't allow in unknown values. Proto3 can use the Raw method.
459 if (![field isValidEnumValue:value]) {
460 [NSException raise:NSInvalidArgumentException
461 format:@"%@.%@: Attempt to set an unknown enum value (%d)",
462 [self class], field.name, value];
463 }
464 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
465}
466
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400467// Only exists for public api, no core code should use this.
468int32_t GPBGetMessageRawEnumField(GPBMessage *self,
469 GPBFieldDescriptor *field) {
470 int32_t result = GPBGetMessageInt32Field(self, field);
471 return result;
472}
473
474// Only exists for public api, no core code should use this.
475void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field,
476 int32_t value) {
477 GPBFileSyntax syntax = [self descriptor].file.syntax;
478 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
479}
480
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400481BOOL GPBGetMessageBoolField(GPBMessage *self,
482 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400483 if (GPBGetHasIvarField(self, field)) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400484 // Bools are stored in the has bits to avoid needing explicit space in the
485 // storage structure.
486 // (the field number passed to the HasIvar helper doesn't really matter
487 // since the offset is never negative)
488 GPBMessageFieldDescription *fieldDesc = field->description_;
489 return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400490 } else {
491 return field.defaultValue.valueBool;
492 }
493}
494
495// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400496void GPBSetMessageBoolField(GPBMessage *self,
497 GPBFieldDescriptor *field,
498 BOOL value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400499 if (self == nil || field == nil) return;
500 GPBFileSyntax syntax = [self descriptor].file.syntax;
501 GPBSetBoolIvarWithFieldInternal(self, field, value, syntax);
502}
503
504void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
505 GPBFieldDescriptor *field,
506 BOOL value,
507 GPBFileSyntax syntax) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400508 GPBMessageFieldDescription *fieldDesc = field->description_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400509 GPBOneofDescriptor *oneof = field->containingOneof_;
510 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400511 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400512 }
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400513
514 // Bools are stored in the has bits to avoid needing explicit space in the
515 // storage structure.
516 // (the field number passed to the HasIvar helper doesn't really matter since
517 // the offset is never negative)
518 GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value);
519
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400520 // proto2: any value counts as having been set; proto3, it
521 // has to be a non zero value.
522 BOOL hasValue =
523 (syntax == GPBFileSyntaxProto2) || (value != (BOOL)0);
524 GPBSetHasIvarField(self, field, hasValue);
525 GPBBecomeVisibleToAutocreator(self);
526}
527
528//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int32, int32_t)
529// This block of code is generated, do not edit it directly.
530
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400531int32_t GPBGetMessageInt32Field(GPBMessage *self,
532 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400533 if (GPBGetHasIvarField(self, field)) {
534 uint8_t *storage = (uint8_t *)self->messageStorage_;
535 int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
536 return *typePtr;
537 } else {
538 return field.defaultValue.valueInt32;
539 }
540}
541
542// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400543void GPBSetMessageInt32Field(GPBMessage *self,
544 GPBFieldDescriptor *field,
545 int32_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400546 if (self == nil || field == nil) return;
547 GPBFileSyntax syntax = [self descriptor].file.syntax;
548 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
549}
550
551void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
552 GPBFieldDescriptor *field,
553 int32_t value,
554 GPBFileSyntax syntax) {
555 GPBOneofDescriptor *oneof = field->containingOneof_;
556 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400557 GPBMessageFieldDescription *fieldDesc = field->description_;
558 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400559 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400560 NSCAssert(self->messageStorage_ != NULL,
561 @"%@: All messages should have storage (from init)",
562 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400563#if defined(__clang_analyzer__)
564 if (self->messageStorage_ == NULL) return;
565#endif
566 uint8_t *storage = (uint8_t *)self->messageStorage_;
567 int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
568 *typePtr = value;
569 // proto2: any value counts as having been set; proto3, it
570 // has to be a non zero value.
571 BOOL hasValue =
572 (syntax == GPBFileSyntaxProto2) || (value != (int32_t)0);
573 GPBSetHasIvarField(self, field, hasValue);
574 GPBBecomeVisibleToAutocreator(self);
575}
576
577//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt32, uint32_t)
578// This block of code is generated, do not edit it directly.
579
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400580uint32_t GPBGetMessageUInt32Field(GPBMessage *self,
581 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400582 if (GPBGetHasIvarField(self, field)) {
583 uint8_t *storage = (uint8_t *)self->messageStorage_;
584 uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
585 return *typePtr;
586 } else {
587 return field.defaultValue.valueUInt32;
588 }
589}
590
591// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400592void GPBSetMessageUInt32Field(GPBMessage *self,
593 GPBFieldDescriptor *field,
594 uint32_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400595 if (self == nil || field == nil) return;
596 GPBFileSyntax syntax = [self descriptor].file.syntax;
597 GPBSetUInt32IvarWithFieldInternal(self, field, value, syntax);
598}
599
600void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
601 GPBFieldDescriptor *field,
602 uint32_t value,
603 GPBFileSyntax syntax) {
604 GPBOneofDescriptor *oneof = field->containingOneof_;
605 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400606 GPBMessageFieldDescription *fieldDesc = field->description_;
607 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400608 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400609 NSCAssert(self->messageStorage_ != NULL,
610 @"%@: All messages should have storage (from init)",
611 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400612#if defined(__clang_analyzer__)
613 if (self->messageStorage_ == NULL) return;
614#endif
615 uint8_t *storage = (uint8_t *)self->messageStorage_;
616 uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
617 *typePtr = value;
618 // proto2: any value counts as having been set; proto3, it
619 // has to be a non zero value.
620 BOOL hasValue =
621 (syntax == GPBFileSyntaxProto2) || (value != (uint32_t)0);
622 GPBSetHasIvarField(self, field, hasValue);
623 GPBBecomeVisibleToAutocreator(self);
624}
625
626//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int64, int64_t)
627// This block of code is generated, do not edit it directly.
628
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400629int64_t GPBGetMessageInt64Field(GPBMessage *self,
630 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400631 if (GPBGetHasIvarField(self, field)) {
632 uint8_t *storage = (uint8_t *)self->messageStorage_;
633 int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
634 return *typePtr;
635 } else {
636 return field.defaultValue.valueInt64;
637 }
638}
639
640// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400641void GPBSetMessageInt64Field(GPBMessage *self,
642 GPBFieldDescriptor *field,
643 int64_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400644 if (self == nil || field == nil) return;
645 GPBFileSyntax syntax = [self descriptor].file.syntax;
646 GPBSetInt64IvarWithFieldInternal(self, field, value, syntax);
647}
648
649void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
650 GPBFieldDescriptor *field,
651 int64_t value,
652 GPBFileSyntax syntax) {
653 GPBOneofDescriptor *oneof = field->containingOneof_;
654 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400655 GPBMessageFieldDescription *fieldDesc = field->description_;
656 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400657 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400658 NSCAssert(self->messageStorage_ != NULL,
659 @"%@: All messages should have storage (from init)",
660 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400661#if defined(__clang_analyzer__)
662 if (self->messageStorage_ == NULL) return;
663#endif
664 uint8_t *storage = (uint8_t *)self->messageStorage_;
665 int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
666 *typePtr = value;
667 // proto2: any value counts as having been set; proto3, it
668 // has to be a non zero value.
669 BOOL hasValue =
670 (syntax == GPBFileSyntaxProto2) || (value != (int64_t)0);
671 GPBSetHasIvarField(self, field, hasValue);
672 GPBBecomeVisibleToAutocreator(self);
673}
674
675//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt64, uint64_t)
676// This block of code is generated, do not edit it directly.
677
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400678uint64_t GPBGetMessageUInt64Field(GPBMessage *self,
679 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400680 if (GPBGetHasIvarField(self, field)) {
681 uint8_t *storage = (uint8_t *)self->messageStorage_;
682 uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
683 return *typePtr;
684 } else {
685 return field.defaultValue.valueUInt64;
686 }
687}
688
689// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400690void GPBSetMessageUInt64Field(GPBMessage *self,
691 GPBFieldDescriptor *field,
692 uint64_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400693 if (self == nil || field == nil) return;
694 GPBFileSyntax syntax = [self descriptor].file.syntax;
695 GPBSetUInt64IvarWithFieldInternal(self, field, value, syntax);
696}
697
698void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
699 GPBFieldDescriptor *field,
700 uint64_t value,
701 GPBFileSyntax syntax) {
702 GPBOneofDescriptor *oneof = field->containingOneof_;
703 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400704 GPBMessageFieldDescription *fieldDesc = field->description_;
705 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400706 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400707 NSCAssert(self->messageStorage_ != NULL,
708 @"%@: All messages should have storage (from init)",
709 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400710#if defined(__clang_analyzer__)
711 if (self->messageStorage_ == NULL) return;
712#endif
713 uint8_t *storage = (uint8_t *)self->messageStorage_;
714 uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
715 *typePtr = value;
716 // proto2: any value counts as having been set; proto3, it
717 // has to be a non zero value.
718 BOOL hasValue =
719 (syntax == GPBFileSyntaxProto2) || (value != (uint64_t)0);
720 GPBSetHasIvarField(self, field, hasValue);
721 GPBBecomeVisibleToAutocreator(self);
722}
723
724//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Float, float)
725// This block of code is generated, do not edit it directly.
726
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400727float GPBGetMessageFloatField(GPBMessage *self,
728 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400729 if (GPBGetHasIvarField(self, field)) {
730 uint8_t *storage = (uint8_t *)self->messageStorage_;
731 float *typePtr = (float *)&storage[field->description_->offset];
732 return *typePtr;
733 } else {
734 return field.defaultValue.valueFloat;
735 }
736}
737
738// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400739void GPBSetMessageFloatField(GPBMessage *self,
740 GPBFieldDescriptor *field,
741 float value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400742 if (self == nil || field == nil) return;
743 GPBFileSyntax syntax = [self descriptor].file.syntax;
744 GPBSetFloatIvarWithFieldInternal(self, field, value, syntax);
745}
746
747void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
748 GPBFieldDescriptor *field,
749 float value,
750 GPBFileSyntax syntax) {
751 GPBOneofDescriptor *oneof = field->containingOneof_;
752 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400753 GPBMessageFieldDescription *fieldDesc = field->description_;
754 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400755 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400756 NSCAssert(self->messageStorage_ != NULL,
757 @"%@: All messages should have storage (from init)",
758 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400759#if defined(__clang_analyzer__)
760 if (self->messageStorage_ == NULL) return;
761#endif
762 uint8_t *storage = (uint8_t *)self->messageStorage_;
763 float *typePtr = (float *)&storage[field->description_->offset];
764 *typePtr = value;
765 // proto2: any value counts as having been set; proto3, it
766 // has to be a non zero value.
767 BOOL hasValue =
768 (syntax == GPBFileSyntaxProto2) || (value != (float)0);
769 GPBSetHasIvarField(self, field, hasValue);
770 GPBBecomeVisibleToAutocreator(self);
771}
772
773//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Double, double)
774// This block of code is generated, do not edit it directly.
775
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400776double GPBGetMessageDoubleField(GPBMessage *self,
777 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400778 if (GPBGetHasIvarField(self, field)) {
779 uint8_t *storage = (uint8_t *)self->messageStorage_;
780 double *typePtr = (double *)&storage[field->description_->offset];
781 return *typePtr;
782 } else {
783 return field.defaultValue.valueDouble;
784 }
785}
786
787// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400788void GPBSetMessageDoubleField(GPBMessage *self,
789 GPBFieldDescriptor *field,
790 double value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400791 if (self == nil || field == nil) return;
792 GPBFileSyntax syntax = [self descriptor].file.syntax;
793 GPBSetDoubleIvarWithFieldInternal(self, field, value, syntax);
794}
795
796void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
797 GPBFieldDescriptor *field,
798 double value,
799 GPBFileSyntax syntax) {
800 GPBOneofDescriptor *oneof = field->containingOneof_;
801 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400802 GPBMessageFieldDescription *fieldDesc = field->description_;
803 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400804 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400805 NSCAssert(self->messageStorage_ != NULL,
806 @"%@: All messages should have storage (from init)",
807 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400808#if defined(__clang_analyzer__)
809 if (self->messageStorage_ == NULL) return;
810#endif
811 uint8_t *storage = (uint8_t *)self->messageStorage_;
812 double *typePtr = (double *)&storage[field->description_->offset];
813 *typePtr = value;
814 // proto2: any value counts as having been set; proto3, it
815 // has to be a non zero value.
816 BOOL hasValue =
817 (syntax == GPBFileSyntaxProto2) || (value != (double)0);
818 GPBSetHasIvarField(self, field, hasValue);
819 GPBBecomeVisibleToAutocreator(self);
820}
821
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400822//%PDDM-EXPAND-END (6 expansions)
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400823
824// Aliases are function calls that are virtually the same.
825
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400826//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(String, NSString)
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400827// This block of code is generated, do not edit it directly.
828
829// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400830NSString *GPBGetMessageStringField(GPBMessage *self,
831 GPBFieldDescriptor *field) {
832 return (NSString *)GPBGetObjectIvarWithField(self, field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400833}
834
835// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400836void GPBSetMessageStringField(GPBMessage *self,
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400837 GPBFieldDescriptor *field,
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400838 NSString *value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400839 GPBSetObjectIvarWithField(self, field, (id)value);
840}
841
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400842//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Bytes, NSData)
843// This block of code is generated, do not edit it directly.
844
845// Only exists for public api, no core code should use this.
846NSData *GPBGetMessageBytesField(GPBMessage *self,
847 GPBFieldDescriptor *field) {
848 return (NSData *)GPBGetObjectIvarWithField(self, field);
849}
850
851// Only exists for public api, no core code should use this.
852void GPBSetMessageBytesField(GPBMessage *self,
853 GPBFieldDescriptor *field,
854 NSData *value) {
855 GPBSetObjectIvarWithField(self, field, (id)value);
856}
857
858//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Message, GPBMessage)
859// This block of code is generated, do not edit it directly.
860
861// Only exists for public api, no core code should use this.
862GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
863 GPBFieldDescriptor *field) {
864 return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
865}
866
867// Only exists for public api, no core code should use this.
868void GPBSetMessageMessageField(GPBMessage *self,
869 GPBFieldDescriptor *field,
870 GPBMessage *value) {
871 GPBSetObjectIvarWithField(self, field, (id)value);
872}
873
874//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Group, GPBMessage)
875// This block of code is generated, do not edit it directly.
876
877// Only exists for public api, no core code should use this.
878GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
879 GPBFieldDescriptor *field) {
880 return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
881}
882
883// Only exists for public api, no core code should use this.
884void GPBSetMessageGroupField(GPBMessage *self,
885 GPBFieldDescriptor *field,
886 GPBMessage *value) {
887 GPBSetObjectIvarWithField(self, field, (id)value);
888}
889
890//%PDDM-EXPAND-END (4 expansions)
891
892// Only exists for public api, no core code should use this.
893id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field) {
894#if DEBUG
895 if (field.fieldType != GPBFieldTypeRepeated) {
896 [NSException raise:NSInvalidArgumentException
897 format:@"%@.%@ is not a repeated field.",
898 [self class], field.name];
899 }
900#endif
901 return GPBGetObjectIvarWithField(self, field);
902}
903
904// Only exists for public api, no core code should use this.
905void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) {
906#if DEBUG
907 if (field.fieldType != GPBFieldTypeRepeated) {
908 [NSException raise:NSInvalidArgumentException
909 format:@"%@.%@ is not a repeated field.",
910 [self class], field.name];
911 }
912 Class expectedClass = Nil;
913 switch (GPBGetFieldDataType(field)) {
914 case GPBDataTypeBool:
915 expectedClass = [GPBBoolArray class];
916 break;
917 case GPBDataTypeSFixed32:
918 case GPBDataTypeInt32:
919 case GPBDataTypeSInt32:
920 expectedClass = [GPBInt32Array class];
921 break;
922 case GPBDataTypeFixed32:
923 case GPBDataTypeUInt32:
924 expectedClass = [GPBUInt32Array class];
925 break;
926 case GPBDataTypeSFixed64:
927 case GPBDataTypeInt64:
928 case GPBDataTypeSInt64:
929 expectedClass = [GPBInt64Array class];
930 break;
931 case GPBDataTypeFixed64:
932 case GPBDataTypeUInt64:
933 expectedClass = [GPBUInt64Array class];
934 break;
935 case GPBDataTypeFloat:
936 expectedClass = [GPBFloatArray class];
937 break;
938 case GPBDataTypeDouble:
939 expectedClass = [GPBDoubleArray class];
940 break;
941 case GPBDataTypeBytes:
942 case GPBDataTypeString:
943 case GPBDataTypeMessage:
944 case GPBDataTypeGroup:
945 expectedClass = [NSMutableDictionary class];
946 break;
947 case GPBDataTypeEnum:
948 expectedClass = [GPBBoolArray class];
949 break;
950 }
951 if (array && ![array isKindOfClass:expectedClass]) {
952 [NSException raise:NSInvalidArgumentException
953 format:@"%@.%@: Expected %@ object, got %@.",
954 [self class], field.name, expectedClass, [array class]];
955 }
956#endif
957 GPBSetObjectIvarWithField(self, field, array);
958}
959
960#if DEBUG
961static NSString *TypeToStr(GPBDataType dataType) {
962 switch (dataType) {
963 case GPBDataTypeBool:
964 return @"Bool";
965 case GPBDataTypeSFixed32:
966 case GPBDataTypeInt32:
967 case GPBDataTypeSInt32:
968 return @"Int32";
969 case GPBDataTypeFixed32:
970 case GPBDataTypeUInt32:
971 return @"UInt32";
972 case GPBDataTypeSFixed64:
973 case GPBDataTypeInt64:
974 case GPBDataTypeSInt64:
975 return @"Int64";
976 case GPBDataTypeFixed64:
977 case GPBDataTypeUInt64:
978 return @"UInt64";
979 case GPBDataTypeFloat:
980 return @"Float";
981 case GPBDataTypeDouble:
982 return @"Double";
983 case GPBDataTypeBytes:
984 case GPBDataTypeString:
985 case GPBDataTypeMessage:
986 case GPBDataTypeGroup:
987 return @"Object";
988 case GPBDataTypeEnum:
989 return @"Bool";
990 }
991}
992#endif
993
994// Only exists for public api, no core code should use this.
995id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) {
996#if DEBUG
997 if (field.fieldType != GPBFieldTypeMap) {
998 [NSException raise:NSInvalidArgumentException
999 format:@"%@.%@ is not a map<> field.",
1000 [self class], field.name];
1001 }
1002#endif
1003 return GPBGetObjectIvarWithField(self, field);
1004}
1005
1006// Only exists for public api, no core code should use this.
1007void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
1008 id dictionary) {
1009#if DEBUG
1010 if (field.fieldType != GPBFieldTypeMap) {
1011 [NSException raise:NSInvalidArgumentException
1012 format:@"%@.%@ is not a map<> field.",
1013 [self class], field.name];
1014 }
1015 if (dictionary) {
1016 GPBDataType keyDataType = field.mapKeyDataType;
1017 GPBDataType valueDataType = GPBGetFieldDataType(field);
1018 NSString *keyStr = TypeToStr(keyDataType);
1019 NSString *valueStr = TypeToStr(valueDataType);
1020 if (keyDataType == GPBDataTypeString) {
1021 keyStr = @"String";
1022 }
1023 Class expectedClass = Nil;
1024 if ((keyDataType == GPBDataTypeString) &&
1025 GPBDataTypeIsObject(valueDataType)) {
1026 expectedClass = [NSMutableDictionary class];
1027 } else {
1028 NSString *className =
1029 [NSString stringWithFormat:@"GPB%@%@Dictionary", keyStr, valueStr];
1030 expectedClass = NSClassFromString(className);
1031 NSCAssert(expectedClass, @"Missing a class (%@)?", expectedClass);
1032 }
1033 if (![dictionary isKindOfClass:expectedClass]) {
1034 [NSException raise:NSInvalidArgumentException
1035 format:@"%@.%@: Expected %@ object, got %@.",
1036 [self class], field.name, expectedClass,
1037 [dictionary class]];
1038 }
1039 }
1040#endif
1041 GPBSetObjectIvarWithField(self, field, dictionary);
1042}
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001043
1044#pragma mark - Misc Dynamic Runtime Utils
1045
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001046const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) {
1047 Protocol *protocol =
1048 objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol));
1049 struct objc_method_description description =
1050 protocol_getMethodDescription(protocol, selector, NO, instanceSel);
1051 return description.types;
1052}
1053
1054#pragma mark - Text Format Support
1055
1056static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) {
1057 [destStr appendString:@"\""];
1058 NSUInteger len = [toPrint length];
1059 for (NSUInteger i = 0; i < len; ++i) {
1060 unichar aChar = [toPrint characterAtIndex:i];
1061 switch (aChar) {
1062 case '\n': [destStr appendString:@"\\n"]; break;
1063 case '\r': [destStr appendString:@"\\r"]; break;
1064 case '\t': [destStr appendString:@"\\t"]; break;
1065 case '\"': [destStr appendString:@"\\\""]; break;
1066 case '\'': [destStr appendString:@"\\\'"]; break;
1067 case '\\': [destStr appendString:@"\\\\"]; break;
1068 default:
1069 [destStr appendFormat:@"%C", aChar];
1070 break;
1071 }
1072 }
1073 [destStr appendString:@"\""];
1074}
1075
1076static void AppendBufferAsString(NSData *buffer, NSMutableString *destStr) {
1077 const char *src = (const char *)[buffer bytes];
1078 size_t srcLen = [buffer length];
1079 [destStr appendString:@"\""];
1080 for (const char *srcEnd = src + srcLen; src < srcEnd; src++) {
1081 switch (*src) {
1082 case '\n': [destStr appendString:@"\\n"]; break;
1083 case '\r': [destStr appendString:@"\\r"]; break;
1084 case '\t': [destStr appendString:@"\\t"]; break;
1085 case '\"': [destStr appendString:@"\\\""]; break;
1086 case '\'': [destStr appendString:@"\\\'"]; break;
1087 case '\\': [destStr appendString:@"\\\\"]; break;
1088 default:
1089 if (isprint(*src)) {
1090 [destStr appendFormat:@"%c", *src];
1091 } else {
1092 // NOTE: doing hex means you have to worry about the letter after
1093 // the hex being another hex char and forcing that to be escaped, so
1094 // use octal to keep it simple.
1095 [destStr appendFormat:@"\\%03o", (uint8_t)(*src)];
1096 }
1097 break;
1098 }
1099 }
1100 [destStr appendString:@"\""];
1101}
1102
1103static void AppendTextFormatForMapMessageField(
1104 id map, GPBFieldDescriptor *field, NSMutableString *toStr,
1105 NSString *lineIndent, NSString *fieldName, NSString *lineEnding) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001106 GPBDataType keyDataType = field.mapKeyDataType;
1107 GPBDataType valueDataType = GPBGetFieldDataType(field);
1108 BOOL isMessageValue = GPBDataTypeIsMessage(valueDataType);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001109
1110 NSString *msgStartFirst =
1111 [NSString stringWithFormat:@"%@%@ {%@\n", lineIndent, fieldName, lineEnding];
1112 NSString *msgStart =
1113 [NSString stringWithFormat:@"%@%@ {\n", lineIndent, fieldName];
1114 NSString *msgEnd = [NSString stringWithFormat:@"%@}\n", lineIndent];
1115
1116 NSString *keyLine = [NSString stringWithFormat:@"%@ key: ", lineIndent];
1117 NSString *valueLine = [NSString stringWithFormat:@"%@ value%s ", lineIndent,
1118 (isMessageValue ? "" : ":")];
1119
1120 __block BOOL isFirst = YES;
1121
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001122 if ((keyDataType == GPBDataTypeString) &&
1123 GPBDataTypeIsObject(valueDataType)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001124 // map is an NSDictionary.
1125 NSDictionary *dict = map;
1126 [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
1127 #pragma unused(stop)
1128 [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
1129 isFirst = NO;
1130
1131 [toStr appendString:keyLine];
1132 AppendStringEscaped(key, toStr);
1133 [toStr appendString:@"\n"];
1134
1135 [toStr appendString:valueLine];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001136 switch (valueDataType) {
1137 case GPBDataTypeString:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001138 AppendStringEscaped(value, toStr);
1139 break;
1140
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001141 case GPBDataTypeBytes:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001142 AppendBufferAsString(value, toStr);
1143 break;
1144
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001145 case GPBDataTypeMessage:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001146 [toStr appendString:@"{\n"];
1147 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1148 AppendTextFormatForMessage(value, toStr, subIndent);
1149 [toStr appendFormat:@"%@ }", lineIndent];
1150 break;
1151
1152 default:
1153 NSCAssert(NO, @"Can't happen");
1154 break;
1155 }
1156 [toStr appendString:@"\n"];
1157
1158 [toStr appendString:msgEnd];
1159 }];
1160 } else {
1161 // map is one of the GPB*Dictionary classes, type doesn't matter.
1162 GPBInt32Int32Dictionary *dict = map;
1163 [dict enumerateForTextFormat:^(id keyObj, id valueObj) {
1164 [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
1165 isFirst = NO;
1166
1167 // Key always is a NSString.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001168 if (keyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001169 [toStr appendString:keyLine];
1170 AppendStringEscaped(keyObj, toStr);
1171 [toStr appendString:@"\n"];
1172 } else {
1173 [toStr appendFormat:@"%@%@\n", keyLine, keyObj];
1174 }
1175
1176 [toStr appendString:valueLine];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001177 switch (valueDataType) {
1178 case GPBDataTypeString:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001179 AppendStringEscaped(valueObj, toStr);
1180 break;
1181
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001182 case GPBDataTypeBytes:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001183 AppendBufferAsString(valueObj, toStr);
1184 break;
1185
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001186 case GPBDataTypeMessage:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001187 [toStr appendString:@"{\n"];
1188 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1189 AppendTextFormatForMessage(valueObj, toStr, subIndent);
1190 [toStr appendFormat:@"%@ }", lineIndent];
1191 break;
1192
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001193 case GPBDataTypeEnum: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001194 int32_t enumValue = [valueObj intValue];
1195 NSString *valueStr = nil;
1196 GPBEnumDescriptor *descriptor = field.enumDescriptor;
1197 if (descriptor) {
1198 valueStr = [descriptor textFormatNameForValue:enumValue];
1199 }
1200 if (valueStr) {
1201 [toStr appendString:valueStr];
1202 } else {
1203 [toStr appendFormat:@"%d", enumValue];
1204 }
1205 break;
1206 }
1207
1208 default:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001209 NSCAssert(valueDataType != GPBDataTypeGroup, @"Can't happen");
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001210 // Everything else is a NSString.
1211 [toStr appendString:valueObj];
1212 break;
1213 }
1214 [toStr appendString:@"\n"];
1215
1216 [toStr appendString:msgEnd];
1217 }];
1218 }
1219}
1220
1221static void AppendTextFormatForMessageField(GPBMessage *message,
1222 GPBFieldDescriptor *field,
1223 NSMutableString *toStr,
1224 NSString *lineIndent) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001225 id arrayOrMap;
1226 NSUInteger count;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001227 GPBFieldType fieldType = field.fieldType;
1228 switch (fieldType) {
1229 case GPBFieldTypeSingle:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001230 arrayOrMap = nil;
1231 count = (GPBGetHasIvarField(message, field) ? 1 : 0);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001232 break;
1233
1234 case GPBFieldTypeRepeated:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001235 // Will be NSArray or GPB*Array, type doesn't matter, they both
1236 // implement count.
1237 arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
1238 count = [(NSArray *)arrayOrMap count];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001239 break;
1240
1241 case GPBFieldTypeMap: {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001242 // Will be GPB*Dictionary or NSMutableDictionary, type doesn't matter,
1243 // they both implement count.
1244 arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
1245 count = [(NSDictionary *)arrayOrMap count];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001246 break;
1247 }
1248 }
1249
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001250 if (count == 0) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001251 // Nothing to print, out of here.
1252 return;
1253 }
1254
1255 NSString *lineEnding = @"";
1256
1257 // If the name can't be reversed or support for extra info was turned off,
1258 // this can return nil.
1259 NSString *fieldName = [field textFormatName];
1260 if ([fieldName length] == 0) {
1261 fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)];
1262 // If there is only one entry, put the objc name as a comment, other wise
Dongjoon Hyun7a9040f2016-01-14 22:12:03 -08001263 // add it before the repeated values.
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001264 if (count > 1) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001265 [toStr appendFormat:@"%@# %@\n", lineIndent, field.name];
1266 } else {
1267 lineEnding = [NSString stringWithFormat:@" # %@", field.name];
1268 }
1269 }
1270
1271 if (fieldType == GPBFieldTypeMap) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001272 AppendTextFormatForMapMessageField(arrayOrMap, field, toStr, lineIndent,
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001273 fieldName, lineEnding);
1274 return;
1275 }
1276
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001277 id array = arrayOrMap;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001278 const BOOL isRepeated = (array != nil);
1279
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001280 GPBDataType fieldDataType = GPBGetFieldDataType(field);
1281 BOOL isMessageField = GPBDataTypeIsMessage(fieldDataType);
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001282 for (NSUInteger j = 0; j < count; ++j) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001283 // Start the line.
1284 [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName,
1285 (isMessageField ? "" : ":")];
1286
1287 // The value.
1288 switch (fieldDataType) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001289#define FIELD_CASE(GPBDATATYPE, CTYPE, REAL_TYPE, ...) \
1290 case GPBDataType##GPBDATATYPE: { \
1291 CTYPE v = (isRepeated ? [(GPB##REAL_TYPE##Array *)array valueAtIndex:j] \
1292 : GPBGetMessage##REAL_TYPE##Field(message, field)); \
1293 [toStr appendFormat:__VA_ARGS__, v]; \
1294 break; \
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001295 }
1296
1297 FIELD_CASE(Int32, int32_t, Int32, @"%d")
1298 FIELD_CASE(SInt32, int32_t, Int32, @"%d")
1299 FIELD_CASE(SFixed32, int32_t, Int32, @"%d")
1300 FIELD_CASE(UInt32, uint32_t, UInt32, @"%u")
1301 FIELD_CASE(Fixed32, uint32_t, UInt32, @"%u")
1302 FIELD_CASE(Int64, int64_t, Int64, @"%lld")
1303 FIELD_CASE(SInt64, int64_t, Int64, @"%lld")
1304 FIELD_CASE(SFixed64, int64_t, Int64, @"%lld")
1305 FIELD_CASE(UInt64, uint64_t, UInt64, @"%llu")
1306 FIELD_CASE(Fixed64, uint64_t, UInt64, @"%llu")
1307 FIELD_CASE(Float, float, Float, @"%.*g", FLT_DIG)
1308 FIELD_CASE(Double, double, Double, @"%.*lg", DBL_DIG)
1309
1310#undef FIELD_CASE
1311
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001312 case GPBDataTypeEnum: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001313 int32_t v = (isRepeated ? [(GPBEnumArray *)array rawValueAtIndex:j]
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001314 : GPBGetMessageInt32Field(message, field));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001315 NSString *valueStr = nil;
1316 GPBEnumDescriptor *descriptor = field.enumDescriptor;
1317 if (descriptor) {
1318 valueStr = [descriptor textFormatNameForValue:v];
1319 }
1320 if (valueStr) {
1321 [toStr appendString:valueStr];
1322 } else {
1323 [toStr appendFormat:@"%d", v];
1324 }
1325 break;
1326 }
1327
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001328 case GPBDataTypeBool: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001329 BOOL v = (isRepeated ? [(GPBBoolArray *)array valueAtIndex:j]
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001330 : GPBGetMessageBoolField(message, field));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001331 [toStr appendString:(v ? @"true" : @"false")];
1332 break;
1333 }
1334
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001335 case GPBDataTypeString: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001336 NSString *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001337 : GPBGetMessageStringField(message, field));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001338 AppendStringEscaped(v, toStr);
1339 break;
1340 }
1341
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001342 case GPBDataTypeBytes: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001343 NSData *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001344 : GPBGetMessageBytesField(message, field));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001345 AppendBufferAsString(v, toStr);
1346 break;
1347 }
1348
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001349 case GPBDataTypeGroup:
1350 case GPBDataTypeMessage: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001351 GPBMessage *v =
1352 (isRepeated ? [(NSArray *)array objectAtIndex:j]
1353 : GPBGetObjectIvarWithField(message, field));
1354 [toStr appendFormat:@"{%@\n", lineEnding];
1355 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1356 AppendTextFormatForMessage(v, toStr, subIndent);
1357 [toStr appendFormat:@"%@}", lineIndent];
1358 lineEnding = @"";
1359 break;
1360 }
1361
1362 } // switch(fieldDataType)
1363
1364 // End the line.
1365 [toStr appendFormat:@"%@\n", lineEnding];
1366
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001367 } // for(count)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001368}
1369
1370static void AppendTextFormatForMessageExtensionRange(GPBMessage *message,
1371 NSArray *activeExtensions,
1372 GPBExtensionRange range,
1373 NSMutableString *toStr,
1374 NSString *lineIndent) {
1375 uint32_t start = range.start;
1376 uint32_t end = range.end;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001377 for (GPBExtensionDescriptor *extension in activeExtensions) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001378 uint32_t fieldNumber = extension.fieldNumber;
1379 if (fieldNumber < start) {
1380 // Not there yet.
1381 continue;
1382 }
1383 if (fieldNumber > end) {
1384 // Done.
1385 break;
1386 }
1387
1388 id rawExtValue = [message getExtension:extension];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001389 BOOL isRepeated = extension.isRepeated;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001390
1391 NSUInteger numValues = 1;
1392 NSString *lineEnding = @"";
1393 if (isRepeated) {
1394 numValues = [(NSArray *)rawExtValue count];
1395 }
1396
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001397 NSString *singletonName = extension.singletonName;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001398 if (numValues == 1) {
1399 lineEnding = [NSString stringWithFormat:@" # [%@]", singletonName];
1400 } else {
1401 [toStr appendFormat:@"%@# [%@]\n", lineIndent, singletonName];
1402 }
1403
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001404 GPBDataType extDataType = extension.dataType;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001405 for (NSUInteger j = 0; j < numValues; ++j) {
1406 id curValue = (isRepeated ? [rawExtValue objectAtIndex:j] : rawExtValue);
1407
1408 // Start the line.
1409 [toStr appendFormat:@"%@%u%s ", lineIndent, fieldNumber,
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001410 (GPBDataTypeIsMessage(extDataType) ? "" : ":")];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001411
1412 // The value.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001413 switch (extDataType) {
1414#define FIELD_CASE(GPBDATATYPE, CTYPE, NUMSELECTOR, ...) \
1415 case GPBDataType##GPBDATATYPE: { \
1416 CTYPE v = [(NSNumber *)curValue NUMSELECTOR]; \
1417 [toStr appendFormat:__VA_ARGS__, v]; \
1418 break; \
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001419 }
1420
1421 FIELD_CASE(Int32, int32_t, intValue, @"%d")
1422 FIELD_CASE(SInt32, int32_t, intValue, @"%d")
1423 FIELD_CASE(SFixed32, int32_t, unsignedIntValue, @"%d")
1424 FIELD_CASE(UInt32, uint32_t, unsignedIntValue, @"%u")
1425 FIELD_CASE(Fixed32, uint32_t, unsignedIntValue, @"%u")
1426 FIELD_CASE(Int64, int64_t, longLongValue, @"%lld")
1427 FIELD_CASE(SInt64, int64_t, longLongValue, @"%lld")
1428 FIELD_CASE(SFixed64, int64_t, longLongValue, @"%lld")
1429 FIELD_CASE(UInt64, uint64_t, unsignedLongLongValue, @"%llu")
1430 FIELD_CASE(Fixed64, uint64_t, unsignedLongLongValue, @"%llu")
1431 FIELD_CASE(Float, float, floatValue, @"%.*g", FLT_DIG)
1432 FIELD_CASE(Double, double, doubleValue, @"%.*lg", DBL_DIG)
1433 // TODO: Add a comment with the enum name from enum descriptors
1434 // (might not be real value, so leave it as a comment, ObjC compiler
1435 // name mangles differently). Doesn't look like we actually generate
1436 // an enum descriptor reference like we do for normal fields, so this
1437 // will take a compiler change.
1438 FIELD_CASE(Enum, int32_t, intValue, @"%d")
1439
1440#undef FIELD_CASE
1441
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001442 case GPBDataTypeBool:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001443 [toStr appendString:([(NSNumber *)curValue boolValue] ? @"true"
1444 : @"false")];
1445 break;
1446
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001447 case GPBDataTypeString:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001448 AppendStringEscaped(curValue, toStr);
1449 break;
1450
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001451 case GPBDataTypeBytes:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001452 AppendBufferAsString((NSData *)curValue, toStr);
1453 break;
1454
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001455 case GPBDataTypeGroup:
1456 case GPBDataTypeMessage: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001457 [toStr appendFormat:@"{%@\n", lineEnding];
1458 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1459 AppendTextFormatForMessage(curValue, toStr, subIndent);
1460 [toStr appendFormat:@"%@}", lineIndent];
1461 lineEnding = @"";
1462 break;
1463 }
1464
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001465 } // switch(extDataType)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001466
1467 } // for(numValues)
1468
1469 // End the line.
1470 [toStr appendFormat:@"%@\n", lineEnding];
1471
1472 } // for..in(activeExtensions)
1473}
1474
1475static void AppendTextFormatForMessage(GPBMessage *message,
1476 NSMutableString *toStr,
1477 NSString *lineIndent) {
1478 GPBDescriptor *descriptor = [message descriptor];
1479 NSArray *fieldsArray = descriptor->fields_;
1480 NSUInteger fieldCount = fieldsArray.count;
1481 const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
1482 NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
1483 NSArray *activeExtensions = [message sortedExtensionsInUse];
1484 for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
1485 if (i == fieldCount) {
1486 AppendTextFormatForMessageExtensionRange(
1487 message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
1488 } else if (j == extensionRangesCount ||
1489 GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
1490 AppendTextFormatForMessageField(message, fieldsArray[i++], toStr,
1491 lineIndent);
1492 } else {
1493 AppendTextFormatForMessageExtensionRange(
1494 message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
1495 }
1496 }
1497
1498 NSString *unknownFieldsStr =
1499 GPBTextFormatForUnknownFieldSet(message.unknownFields, lineIndent);
1500 if ([unknownFieldsStr length] > 0) {
1501 [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent];
1502 [toStr appendString:unknownFieldsStr];
1503 }
1504}
1505
1506NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) {
Thomas Van Lenten8c889572015-06-16 16:45:14 -04001507 if (message == nil) return @"";
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001508 if (lineIndent == nil) lineIndent = @"";
1509
1510 NSMutableString *buildString = [NSMutableString string];
1511 AppendTextFormatForMessage(message, buildString, lineIndent);
1512 return buildString;
1513}
1514
1515NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet,
1516 NSString *lineIndent) {
Thomas Van Lenten8c889572015-06-16 16:45:14 -04001517 if (unknownSet == nil) return @"";
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001518 if (lineIndent == nil) lineIndent = @"";
1519
1520 NSMutableString *result = [NSMutableString string];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001521 for (GPBUnknownField *field in [unknownSet sortedFields]) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001522 int32_t fieldNumber = [field number];
1523
1524#define PRINT_LOOP(PROPNAME, CTYPE, FORMAT) \
1525 [field.PROPNAME \
1526 enumerateValuesWithBlock:^(CTYPE value, NSUInteger idx, BOOL * stop) { \
1527 _Pragma("unused(idx, stop)"); \
1528 [result \
1529 appendFormat:@"%@%d: " #FORMAT "\n", lineIndent, fieldNumber, value]; \
1530 }];
1531
1532 PRINT_LOOP(varintList, uint64_t, %llu);
1533 PRINT_LOOP(fixed32List, uint32_t, 0x%X);
1534 PRINT_LOOP(fixed64List, uint64_t, 0x%llX);
1535
1536#undef PRINT_LOOP
1537
1538 // NOTE: C++ version of TextFormat tries to parse this as a message
1539 // and print that if it succeeds.
1540 for (NSData *data in field.lengthDelimitedList) {
1541 [result appendFormat:@"%@%d: ", lineIndent, fieldNumber];
1542 AppendBufferAsString(data, result);
1543 [result appendString:@"\n"];
1544 }
1545
1546 for (GPBUnknownFieldSet *subUnknownSet in field.groupList) {
1547 [result appendFormat:@"%@%d: {\n", lineIndent, fieldNumber];
1548 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1549 NSString *subUnknwonSetStr =
1550 GPBTextFormatForUnknownFieldSet(subUnknownSet, subIndent);
1551 [result appendString:subUnknwonSetStr];
1552 [result appendFormat:@"%@}\n", lineIndent];
1553 }
1554 }
1555 return result;
1556}
1557
1558// Helpers to decode a varint. Not using GPBCodedInputStream version because
1559// that needs a state object, and we don't want to create an input stream out
1560// of the data.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001561GPB_INLINE int8_t ReadRawByteFromData(const uint8_t **data) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001562 int8_t result = *((int8_t *)(*data));
1563 ++(*data);
1564 return result;
1565}
1566
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001567static int32_t ReadRawVarint32FromData(const uint8_t **data) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001568 int8_t tmp = ReadRawByteFromData(data);
1569 if (tmp >= 0) {
1570 return tmp;
1571 }
1572 int32_t result = tmp & 0x7f;
1573 if ((tmp = ReadRawByteFromData(data)) >= 0) {
1574 result |= tmp << 7;
1575 } else {
1576 result |= (tmp & 0x7f) << 7;
1577 if ((tmp = ReadRawByteFromData(data)) >= 0) {
1578 result |= tmp << 14;
1579 } else {
1580 result |= (tmp & 0x7f) << 14;
1581 if ((tmp = ReadRawByteFromData(data)) >= 0) {
1582 result |= tmp << 21;
1583 } else {
1584 result |= (tmp & 0x7f) << 21;
1585 result |= (tmp = ReadRawByteFromData(data)) << 28;
1586 if (tmp < 0) {
1587 // Discard upper 32 bits.
1588 for (int i = 0; i < 5; i++) {
1589 if (ReadRawByteFromData(data) >= 0) {
1590 return result;
1591 }
1592 }
1593 [NSException raise:NSParseErrorException
1594 format:@"Unable to read varint32"];
1595 }
1596 }
1597 }
1598 }
1599 return result;
1600}
1601
1602NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key,
1603 NSString *inputStr) {
1604 // decodData form:
1605 // varint32: num entries
1606 // for each entry:
1607 // varint32: key
1608 // bytes*: decode data
1609 //
1610 // decode data one of two forms:
1611 // 1: a \0 followed by the string followed by an \0
1612 // 2: bytecodes to transform an input into the right thing, ending with \0
1613 //
1614 // the bytes codes are of the form:
1615 // 0xabbccccc
1616 // 0x0 (all zeros), end.
1617 // a - if set, add an underscore
1618 // bb - 00 ccccc bytes as is
1619 // bb - 10 ccccc upper first, as is on rest, ccccc byte total
1620 // bb - 01 ccccc lower first, as is on rest, ccccc byte total
1621 // bb - 11 ccccc all upper, ccccc byte total
1622
1623 if (!decodeData || !inputStr) {
1624 return nil;
1625 }
1626
1627 // Find key
1628 const uint8_t *scan = decodeData;
1629 int32_t numEntries = ReadRawVarint32FromData(&scan);
1630 BOOL foundKey = NO;
1631 while (!foundKey && (numEntries > 0)) {
1632 --numEntries;
1633 int32_t dataKey = ReadRawVarint32FromData(&scan);
1634 if (dataKey == key) {
1635 foundKey = YES;
1636 } else {
1637 // If it is a inlined string, it will start with \0; if it is bytecode it
1638 // will start with a code. So advance one (skipping the inline string
1639 // marker), and then loop until reaching the end marker (\0).
1640 ++scan;
1641 while (*scan != 0) ++scan;
1642 // Now move past the end marker.
1643 ++scan;
1644 }
1645 }
1646
1647 if (!foundKey) {
1648 return nil;
1649 }
1650
1651 // Decode
1652
1653 if (*scan == 0) {
1654 // Inline string. Move over the marker, and NSString can take it as
1655 // UTF8.
1656 ++scan;
1657 NSString *result = [NSString stringWithUTF8String:(const char *)scan];
1658 return result;
1659 }
1660
1661 NSMutableString *result =
1662 [NSMutableString stringWithCapacity:[inputStr length]];
1663
1664 const uint8_t kAddUnderscore = 0b10000000;
1665 const uint8_t kOpMask = 0b01100000;
1666 // const uint8_t kOpAsIs = 0b00000000;
1667 const uint8_t kOpFirstUpper = 0b01000000;
1668 const uint8_t kOpFirstLower = 0b00100000;
1669 const uint8_t kOpAllUpper = 0b01100000;
1670 const uint8_t kSegmentLenMask = 0b00011111;
1671
1672 NSInteger i = 0;
1673 for (; *scan != 0; ++scan) {
1674 if (*scan & kAddUnderscore) {
1675 [result appendString:@"_"];
1676 }
1677 int segmentLen = *scan & kSegmentLenMask;
1678 uint8_t decodeOp = *scan & kOpMask;
1679
1680 // Do op specific handling of the first character.
1681 if (decodeOp == kOpFirstUpper) {
1682 unichar c = [inputStr characterAtIndex:i];
1683 [result appendFormat:@"%c", toupper((char)c)];
1684 ++i;
1685 --segmentLen;
1686 } else if (decodeOp == kOpFirstLower) {
1687 unichar c = [inputStr characterAtIndex:i];
1688 [result appendFormat:@"%c", tolower((char)c)];
1689 ++i;
1690 --segmentLen;
1691 }
1692 // else op == kOpAsIs || op == kOpAllUpper
1693
1694 // Now pull over the rest of the length for this segment.
1695 for (int x = 0; x < segmentLen; ++x) {
1696 unichar c = [inputStr characterAtIndex:(i + x)];
1697 if (decodeOp == kOpAllUpper) {
1698 [result appendFormat:@"%c", toupper((char)c)];
1699 } else {
1700 [result appendFormat:@"%C", c];
1701 }
1702 }
1703 i += segmentLen;
1704 }
1705
1706 return result;
1707}
1708
1709#pragma mark - GPBMessageSignatureProtocol
1710
1711// A series of selectors that are used solely to get @encoding values
1712// for them by the dynamic protobuf runtime code. An object using the protocol
1713// needs to be declared for the protocol to be valid at runtime.
1714@interface GPBMessageSignatureProtocol : NSObject<GPBMessageSignatureProtocol>
1715@end
1716@implementation GPBMessageSignatureProtocol
1717@end