blob: 5029ec73b3469b7471e1fd0ab9a5fed92b83a8c2 [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
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -040042// 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
Thomas Van Lenten30650d82015-05-01 08:57:16 -040048static void AppendTextFormatForMessage(GPBMessage *message,
49 NSMutableString *toStr,
50 NSString *lineIndent);
51
52NSData *GPBEmptyNSData(void) {
53 static dispatch_once_t onceToken;
54 static NSData *defaultNSData = nil;
55 dispatch_once(&onceToken, ^{
56 defaultNSData = [[NSData alloc] init];
57 });
58 return defaultNSData;
59}
60
Thomas Van Lentend0717662017-02-23 12:29:00 -050061void GPBMessageDropUnknownFieldsRecursively(GPBMessage *initialMessage) {
62 if (!initialMessage) {
63 return;
64 }
65
66 // Use an array as a list to process to avoid recursion.
67 NSMutableArray *todo = [NSMutableArray arrayWithObject:initialMessage];
68
69 while (todo.count) {
70 GPBMessage *msg = todo.lastObject;
71 [todo removeLastObject];
72
73 // Clear unknowns.
74 msg.unknownFields = nil;
75
76 // Handle the message fields.
77 GPBDescriptor *descriptor = [[msg class] descriptor];
78 for (GPBFieldDescriptor *field in descriptor->fields_) {
79 if (!GPBFieldDataTypeIsMessage(field)) {
80 continue;
81 }
82 switch (field.fieldType) {
83 case GPBFieldTypeSingle:
84 if (GPBGetHasIvarField(msg, field)) {
85 GPBMessage *fieldMessage = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
86 [todo addObject:fieldMessage];
87 }
88 break;
89
90 case GPBFieldTypeRepeated: {
91 NSArray *fieldMessages = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
92 if (fieldMessages.count) {
93 [todo addObjectsFromArray:fieldMessages];
94 }
95 break;
96 }
97
98 case GPBFieldTypeMap: {
99 id rawFieldMap = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
100 switch (field.mapKeyDataType) {
101 case GPBDataTypeBool:
102 [(GPBBoolObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
103 BOOL key, id _Nonnull object, BOOL * _Nonnull stop) {
104 #pragma unused(key, stop)
105 [todo addObject:object];
106 }];
107 break;
108 case GPBDataTypeFixed32:
109 case GPBDataTypeUInt32:
110 [(GPBUInt32ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
111 uint32_t key, id _Nonnull object, BOOL * _Nonnull stop) {
112 #pragma unused(key, stop)
113 [todo addObject:object];
114 }];
115 break;
116 case GPBDataTypeInt32:
117 case GPBDataTypeSFixed32:
118 case GPBDataTypeSInt32:
119 [(GPBInt32ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
120 int32_t key, id _Nonnull object, BOOL * _Nonnull stop) {
121 #pragma unused(key, stop)
122 [todo addObject:object];
123 }];
124 break;
125 case GPBDataTypeFixed64:
126 case GPBDataTypeUInt64:
127 [(GPBUInt64ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
128 uint64_t key, id _Nonnull object, BOOL * _Nonnull stop) {
129 #pragma unused(key, stop)
130 [todo addObject:object];
131 }];
132 break;
133 case GPBDataTypeInt64:
134 case GPBDataTypeSFixed64:
135 case GPBDataTypeSInt64:
136 [(GPBInt64ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
137 int64_t key, id _Nonnull object, BOOL * _Nonnull stop) {
138 #pragma unused(key, stop)
139 [todo addObject:object];
140 }];
141 break;
142 case GPBDataTypeString:
143 [(NSDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
144 NSString * _Nonnull key, GPBMessage * _Nonnull obj, BOOL * _Nonnull stop) {
145 #pragma unused(key, stop)
146 [todo addObject:obj];
147 }];
148 break;
149 case GPBDataTypeFloat:
150 case GPBDataTypeDouble:
151 case GPBDataTypeEnum:
152 case GPBDataTypeBytes:
153 case GPBDataTypeGroup:
154 case GPBDataTypeMessage:
155 NSCAssert(NO, @"Aren't valid key types.");
156 }
157 break;
158 } // switch(field.mapKeyDataType)
159 } // switch(field.fieldType)
160 } // for(fields)
161
162 // Handle any extensions holding messages.
163 for (GPBExtensionDescriptor *extension in [msg extensionsCurrentlySet]) {
164 if (!GPBDataTypeIsMessage(extension.dataType)) {
165 continue;
166 }
167 if (extension.isRepeated) {
168 NSArray *extMessages = [msg getExtension:extension];
169 [todo addObjectsFromArray:extMessages];
170 } else {
171 GPBMessage *extMessage = [msg getExtension:extension];
172 [todo addObject:extMessage];
173 }
174 } // for(extensionsCurrentlySet)
175
176 } // while(todo.count)
177}
178
179
Thomas Van Lenten1aa65002016-09-15 13:27:17 -0400180// -- About Version Checks --
181// There's actually 3 places these checks all come into play:
182// 1. When the generated source is compile into .o files, the header check
183// happens. This is checking the protoc used matches the library being used
184// when making the .o.
185// 2. Every place a generated proto header is included in a developer's code,
186// the header check comes into play again. But this time it is checking that
187// the current library headers being used still support/match the ones for
188// the generated code.
189// 3. At runtime the final check here (GPBCheckRuntimeVersionsInternal), is
190// called from the generated code passing in values captured when the
191// generated code's .o was made. This checks that at runtime the generated
192// code and runtime library match.
193
194void GPBCheckRuntimeVersionSupport(int32_t objcRuntimeVersion) {
195 // NOTE: This is passing the value captured in the compiled code to check
196 // against the values captured when the runtime support was compiled. This
197 // ensures the library code isn't in a different framework/library that
198 // was generated with a non matching version.
199 if (GOOGLE_PROTOBUF_OBJC_VERSION < objcRuntimeVersion) {
200 // Library is too old for headers.
201 [NSException raise:NSInternalInconsistencyException
202 format:@"Linked to ProtocolBuffer runtime version %d,"
203 @" but code compiled needing atleast %d!",
204 GOOGLE_PROTOBUF_OBJC_VERSION, objcRuntimeVersion];
205 }
206 if (objcRuntimeVersion < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) {
207 // Headers are too old for library.
208 [NSException raise:NSInternalInconsistencyException
209 format:@"Proto generation source compiled against runtime"
210 @" version %d, but this version of the runtime only"
211 @" supports back to %d!",
212 objcRuntimeVersion,
213 GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION];
214 }
215}
216
217// This api is no longer used for version checks. 30001 is the last version
218// using this old versioning model. When that support is removed, this function
219// can be removed (along with the declaration in GPBUtilities_PackagePrivate.h).
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400220void GPBCheckRuntimeVersionInternal(int32_t version) {
Thomas Van Lenten1aa65002016-09-15 13:27:17 -0400221 GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION == 30001,
222 time_to_remove_this_old_version_shim);
223 if (version != GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400224 [NSException raise:NSInternalInconsistencyException
225 format:@"Linked to ProtocolBuffer runtime version %d,"
226 @" but code compiled with version %d!",
227 GOOGLE_PROTOBUF_OBJC_GEN_VERSION, version];
228 }
229}
230
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400231BOOL GPBMessageHasFieldNumberSet(GPBMessage *self, uint32_t fieldNumber) {
232 GPBDescriptor *descriptor = [self descriptor];
233 GPBFieldDescriptor *field = [descriptor fieldWithNumber:fieldNumber];
234 return GPBMessageHasFieldSet(self, field);
235}
236
237BOOL GPBMessageHasFieldSet(GPBMessage *self, GPBFieldDescriptor *field) {
238 if (self == nil || field == nil) return NO;
239
240 // Repeated/Map don't use the bit, they check the count.
241 if (GPBFieldIsMapOrArray(field)) {
242 // Array/map type doesn't matter, since GPB*Array/NSArray and
243 // GPB*Dictionary/NSDictionary all support -count;
244 NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
245 return (arrayOrMap.count > 0);
246 } else {
247 return GPBGetHasIvarField(self, field);
248 }
249}
250
251void GPBClearMessageField(GPBMessage *self, GPBFieldDescriptor *field) {
252 // If not set, nothing to do.
253 if (!GPBGetHasIvarField(self, field)) {
254 return;
255 }
256
257 if (GPBFieldStoresObject(field)) {
258 // Object types are handled slightly differently, they need to be released.
259 uint8_t *storage = (uint8_t *)self->messageStorage_;
260 id *typePtr = (id *)&storage[field->description_->offset];
261 [*typePtr release];
262 *typePtr = nil;
263 } else {
264 // POD types just need to clear the has bit as the Get* method will
265 // fetch the default when needed.
266 }
267 GPBSetHasIvarField(self, field, NO);
268}
269
270BOOL GPBGetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400271 NSCAssert(self->messageStorage_ != NULL,
272 @"%@: All messages should have storage (from init)",
273 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400274 if (idx < 0) {
275 NSCAssert(fieldNumber != 0, @"Invalid field number.");
276 BOOL hasIvar = (self->messageStorage_->_has_storage_[-idx] == fieldNumber);
277 return hasIvar;
278 } else {
279 NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
280 uint32_t byteIndex = idx / 32;
281 uint32_t bitMask = (1 << (idx % 32));
282 BOOL hasIvar =
283 (self->messageStorage_->_has_storage_[byteIndex] & bitMask) ? YES : NO;
284 return hasIvar;
285 }
286}
287
288uint32_t GPBGetHasOneof(GPBMessage *self, int32_t idx) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400289 NSCAssert(idx < 0, @"%@: invalid index (%d) for oneof.",
290 [self class], idx);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400291 uint32_t result = self->messageStorage_->_has_storage_[-idx];
292 return result;
293}
294
295void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber,
296 BOOL value) {
297 if (idx < 0) {
298 NSCAssert(fieldNumber != 0, @"Invalid field number.");
299 uint32_t *has_storage = self->messageStorage_->_has_storage_;
300 has_storage[-idx] = (value ? fieldNumber : 0);
301 } else {
302 NSCAssert(idx != GPBNoHasBit, @"Invalid has bit.");
303 uint32_t *has_storage = self->messageStorage_->_has_storage_;
304 uint32_t byte = idx / 32;
305 uint32_t bitMask = (1 << (idx % 32));
306 if (value) {
307 has_storage[byte] |= bitMask;
308 } else {
309 has_storage[byte] &= ~bitMask;
310 }
311 }
312}
313
314void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof,
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400315 int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) {
316 uint32_t fieldNumberSet = GPBGetHasOneof(self, oneofHasIndex);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400317 if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) {
318 // Do nothing/nothing set in the oneof.
319 return;
320 }
321
322 // Like GPBClearMessageField(), free the memory if an objecttype is set,
323 // pod types don't need to do anything.
324 GPBFieldDescriptor *fieldSet = [oneof fieldWithNumber:fieldNumberSet];
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400325 NSCAssert(fieldSet,
326 @"%@: oneof set to something (%u) not in the oneof?",
327 [self class], fieldNumberSet);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400328 if (fieldSet && GPBFieldStoresObject(fieldSet)) {
329 uint8_t *storage = (uint8_t *)self->messageStorage_;
330 id *typePtr = (id *)&storage[fieldSet->description_->offset];
331 [*typePtr release];
332 *typePtr = nil;
333 }
334
335 // Set to nothing stored in the oneof.
336 // (field number doesn't matter since setting to nothing).
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400337 GPBSetHasIvar(self, oneofHasIndex, 1, NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400338}
339
340#pragma mark - IVar accessors
341
342//%PDDM-DEFINE IVAR_POD_ACCESSORS_DEFN(NAME, TYPE)
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400343//%TYPE GPBGetMessage##NAME##Field(GPBMessage *self,
344//% TYPE$S NAME$S GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400345//% if (GPBGetHasIvarField(self, field)) {
346//% uint8_t *storage = (uint8_t *)self->messageStorage_;
347//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
348//% return *typePtr;
349//% } else {
350//% return field.defaultValue.value##NAME;
351//% }
352//%}
353//%
354//%// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400355//%void GPBSetMessage##NAME##Field(GPBMessage *self,
356//% NAME$S GPBFieldDescriptor *field,
357//% NAME$S TYPE value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400358//% if (self == nil || field == nil) return;
359//% GPBFileSyntax syntax = [self descriptor].file.syntax;
360//% GPBSet##NAME##IvarWithFieldInternal(self, field, value, syntax);
361//%}
362//%
363//%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self,
364//% NAME$S GPBFieldDescriptor *field,
365//% NAME$S TYPE value,
366//% NAME$S GPBFileSyntax syntax) {
367//% GPBOneofDescriptor *oneof = field->containingOneof_;
368//% if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400369//% GPBMessageFieldDescription *fieldDesc = field->description_;
370//% GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400371//% }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400372//% NSCAssert(self->messageStorage_ != NULL,
373//% @"%@: All messages should have storage (from init)",
374//% [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400375//%#if defined(__clang_analyzer__)
376//% if (self->messageStorage_ == NULL) return;
377//%#endif
378//% uint8_t *storage = (uint8_t *)self->messageStorage_;
379//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset];
380//% *typePtr = value;
381//% // proto2: any value counts as having been set; proto3, it
Thomas Van Lentenca5b7752016-08-11 10:37:02 -0400382//% // has to be a non zero value or be in a oneof.
383//% BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
384//% || (value != (TYPE)0)
385//% || (field->containingOneof_ != NULL));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400386//% GPBSetHasIvarField(self, field, hasValue);
387//% GPBBecomeVisibleToAutocreator(self);
388//%}
389//%
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400390//%PDDM-DEFINE IVAR_ALIAS_DEFN_OBJECT(NAME, TYPE)
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400391//%// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400392//%TYPE *GPBGetMessage##NAME##Field(GPBMessage *self,
393//% TYPE$S NAME$S GPBFieldDescriptor *field) {
394//% return (TYPE *)GPBGetObjectIvarWithField(self, field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400395//%}
396//%
397//%// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400398//%void GPBSetMessage##NAME##Field(GPBMessage *self,
399//% NAME$S GPBFieldDescriptor *field,
400//% NAME$S TYPE *value) {
401//% GPBSetObjectIvarWithField(self, field, (id)value);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400402//%}
403//%
404
405// Object types are handled slightly differently, they need to be released
406// and retained.
407
408void GPBSetAutocreatedRetainedObjectIvarWithField(
409 GPBMessage *self, GPBFieldDescriptor *field,
410 id __attribute__((ns_consumed)) value) {
411 uint8_t *storage = (uint8_t *)self->messageStorage_;
412 id *typePtr = (id *)&storage[field->description_->offset];
413 NSCAssert(*typePtr == NULL, @"Can't set autocreated object more than once.");
414 *typePtr = value;
415}
416
417void GPBClearAutocreatedMessageIvarWithField(GPBMessage *self,
418 GPBFieldDescriptor *field) {
419 if (GPBGetHasIvarField(self, field)) {
420 return;
421 }
422 uint8_t *storage = (uint8_t *)self->messageStorage_;
423 id *typePtr = (id *)&storage[field->description_->offset];
424 GPBMessage *oldValue = *typePtr;
425 *typePtr = NULL;
426 GPBClearMessageAutocreator(oldValue);
427 [oldValue release];
428}
429
430// This exists only for briging some aliased types, nothing else should use it.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400431static void GPBSetObjectIvarWithField(GPBMessage *self,
432 GPBFieldDescriptor *field, id value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400433 if (self == nil || field == nil) return;
434 GPBFileSyntax syntax = [self descriptor].file.syntax;
435 GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain],
436 syntax);
437}
438
439void GPBSetObjectIvarWithFieldInternal(GPBMessage *self,
440 GPBFieldDescriptor *field, id value,
441 GPBFileSyntax syntax) {
442 GPBSetRetainedObjectIvarWithFieldInternal(self, field, [value retain],
443 syntax);
444}
445
446void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
447 GPBFieldDescriptor *field,
448 id value, GPBFileSyntax syntax) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400449 NSCAssert(self->messageStorage_ != NULL,
450 @"%@: All messages should have storage (from init)",
451 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400452#if defined(__clang_analyzer__)
453 if (self->messageStorage_ == NULL) return;
454#endif
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400455 GPBDataType fieldType = GPBGetFieldDataType(field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400456 BOOL isMapOrArray = GPBFieldIsMapOrArray(field);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400457 BOOL fieldIsMessage = GPBDataTypeIsMessage(fieldType);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400458#ifdef DEBUG
459 if (value == nil && !isMapOrArray && !fieldIsMessage &&
460 field.hasDefaultValue) {
461 // Setting a message to nil is an obvious way to "clear" the value
462 // as there is no way to set a non-empty default value for messages.
463 //
464 // For Strings and Bytes that have default values set it is not clear what
465 // should be done when their value is set to nil. Is the intention just to
466 // clear the set value and reset to default, or is the intention to set the
467 // value to the empty string/data? Arguments can be made for both cases.
468 // 'nil' has been abused as a replacement for an empty string/data in ObjC.
469 // We decided to be consistent with all "object" types and clear the has
470 // field, and fall back on the default value. The warning below will only
471 // appear in debug, but the could should be changed so the intention is
472 // clear.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400473 NSString *hasSel = NSStringFromSelector(field->hasOrCountSel_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400474 NSString *propName = field.name;
475 NSString *className = self.descriptor.name;
476 NSLog(@"warning: '%@.%@ = nil;' is not clearly defined for fields with "
477 @"default values. Please use '%@.%@ = %@' if you want to set it to "
478 @"empty, or call '%@.%@ = NO' to reset it to it's default value of "
479 @"'%@'. Defaulting to resetting default value.",
480 className, propName, className, propName,
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400481 (fieldType == GPBDataTypeString) ? @"@\"\"" : @"GPBEmptyNSData()",
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400482 className, hasSel, field.defaultValue.valueString);
483 // Note: valueString, depending on the type, it could easily be
484 // valueData/valueMessage.
485 }
486#endif // DEBUG
487 if (!isMapOrArray) {
488 // Non repeated/map can be in an oneof, clear any existing value from the
489 // oneof.
490 GPBOneofDescriptor *oneof = field->containingOneof_;
491 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400492 GPBMessageFieldDescription *fieldDesc = field->description_;
493 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400494 }
495 // Clear "has" if they are being set to nil.
496 BOOL setHasValue = (value != nil);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400497 // Under proto3, Bytes & String fields get cleared by resetting them to
498 // their default (empty) values, so if they are set to something of length
499 // zero, they are being cleared.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400500 if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage &&
501 ([value length] == 0)) {
Thomas Van Lentenca5b7752016-08-11 10:37:02 -0400502 // Except, if the field was in a oneof, then it still gets recorded as
503 // having been set so the state of the oneof can be serialized back out.
504 if (!oneof) {
505 setHasValue = NO;
506 }
507 if (setHasValue) {
508 NSCAssert(value != nil, @"Should never be setting has for nil");
509 } else {
510 // The value passed in was retained, it must be released since we
511 // aren't saving anything in the field.
512 [value release];
513 value = nil;
514 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400515 }
516 GPBSetHasIvarField(self, field, setHasValue);
517 }
518 uint8_t *storage = (uint8_t *)self->messageStorage_;
519 id *typePtr = (id *)&storage[field->description_->offset];
520
521 id oldValue = *typePtr;
522
523 *typePtr = value;
524
525 if (oldValue) {
526 if (isMapOrArray) {
527 if (field.fieldType == GPBFieldTypeRepeated) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400528 // If the old array was autocreated by us, then clear it.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400529 if (GPBDataTypeIsObject(fieldType)) {
Thomas Van Lenten988ffe02017-01-04 15:03:42 -0500530 if ([oldValue isKindOfClass:[GPBAutocreatedArray class]]) {
531 GPBAutocreatedArray *autoArray = oldValue;
532 if (autoArray->_autocreator == self) {
533 autoArray->_autocreator = nil;
534 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400535 }
536 } else {
537 // Type doesn't matter, it is a GPB*Array.
538 GPBInt32Array *gpbArray = oldValue;
539 if (gpbArray->_autocreator == self) {
540 gpbArray->_autocreator = nil;
541 }
542 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400543 } else { // GPBFieldTypeMap
544 // If the old map was autocreated by us, then clear it.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400545 if ((field.mapKeyDataType == GPBDataTypeString) &&
546 GPBDataTypeIsObject(fieldType)) {
Thomas Van Lenten988ffe02017-01-04 15:03:42 -0500547 if ([oldValue isKindOfClass:[GPBAutocreatedDictionary class]]) {
548 GPBAutocreatedDictionary *autoDict = oldValue;
549 if (autoDict->_autocreator == self) {
550 autoDict->_autocreator = nil;
551 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400552 }
553 } else {
554 // Type doesn't matter, it is a GPB*Dictionary.
555 GPBInt32Int32Dictionary *gpbDict = oldValue;
556 if (gpbDict->_autocreator == self) {
557 gpbDict->_autocreator = nil;
558 }
559 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400560 }
561 } else if (fieldIsMessage) {
562 // If the old message value was autocreated by us, then clear it.
563 GPBMessage *oldMessageValue = oldValue;
564 if (GPBWasMessageAutocreatedBy(oldMessageValue, self)) {
565 GPBClearMessageAutocreator(oldMessageValue);
566 }
567 }
568 [oldValue release];
569 }
570
571 GPBBecomeVisibleToAutocreator(self);
572}
573
574id GPBGetObjectIvarWithFieldNoAutocreate(GPBMessage *self,
575 GPBFieldDescriptor *field) {
576 if (self->messageStorage_ == nil) {
577 return nil;
578 }
579 uint8_t *storage = (uint8_t *)self->messageStorage_;
580 id *typePtr = (id *)&storage[field->description_->offset];
581 return *typePtr;
582}
583
584id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) {
585 NSCAssert(!GPBFieldIsMapOrArray(field), @"Shouldn't get here");
586 if (GPBGetHasIvarField(self, field)) {
587 uint8_t *storage = (uint8_t *)self->messageStorage_;
588 id *typePtr = (id *)&storage[field->description_->offset];
589 return *typePtr;
590 }
591 // Not set...
592
593 // Non messages (string/data), get their default.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400594 if (!GPBFieldDataTypeIsMessage(field)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400595 return field.defaultValue.valueMessage;
596 }
597
Thomas Van Lentenbd41a392016-03-21 11:11:14 -0400598 GPBPrepareReadOnlySemaphore(self);
Thomas Van Lentend6590d62015-12-17 14:35:44 -0500599 dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400600 GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
601 if (!result) {
602 // For non repeated messages, create the object, set it and return it.
603 // This object will not initially be visible via GPBGetHasIvar, so
604 // we save its creator so it can become visible if it's mutated later.
605 result = GPBCreateMessageWithAutocreator(field.msgClass, self, field);
606 GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result);
607 }
Thomas Van Lentend6590d62015-12-17 14:35:44 -0500608 dispatch_semaphore_signal(self->readOnlySemaphore_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400609 return result;
610}
611
612// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400613int32_t GPBGetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400614 GPBFileSyntax syntax = [self descriptor].file.syntax;
615 return GPBGetEnumIvarWithFieldInternal(self, field, syntax);
616}
617
618int32_t GPBGetEnumIvarWithFieldInternal(GPBMessage *self,
619 GPBFieldDescriptor *field,
620 GPBFileSyntax syntax) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400621 int32_t result = GPBGetMessageInt32Field(self, field);
622 // If this is presevering unknown enums, make sure the value is valid before
623 // returning it.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400624 if (GPBHasPreservingUnknownEnumSemantics(syntax) &&
625 ![field isValidEnumValue:result]) {
626 result = kGPBUnrecognizedEnumeratorValue;
627 }
628 return result;
629}
630
631// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400632void GPBSetMessageEnumField(GPBMessage *self, GPBFieldDescriptor *field,
633 int32_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400634 GPBFileSyntax syntax = [self descriptor].file.syntax;
635 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
636}
637
638void GPBSetEnumIvarWithFieldInternal(GPBMessage *self,
639 GPBFieldDescriptor *field, int32_t value,
640 GPBFileSyntax syntax) {
641 // Don't allow in unknown values. Proto3 can use the Raw method.
642 if (![field isValidEnumValue:value]) {
643 [NSException raise:NSInvalidArgumentException
644 format:@"%@.%@: Attempt to set an unknown enum value (%d)",
645 [self class], field.name, value];
646 }
647 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
648}
649
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400650// Only exists for public api, no core code should use this.
651int32_t GPBGetMessageRawEnumField(GPBMessage *self,
652 GPBFieldDescriptor *field) {
653 int32_t result = GPBGetMessageInt32Field(self, field);
654 return result;
655}
656
657// Only exists for public api, no core code should use this.
658void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field,
659 int32_t value) {
660 GPBFileSyntax syntax = [self descriptor].file.syntax;
661 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
662}
663
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400664BOOL GPBGetMessageBoolField(GPBMessage *self,
665 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400666 if (GPBGetHasIvarField(self, field)) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400667 // Bools are stored in the has bits to avoid needing explicit space in the
668 // storage structure.
669 // (the field number passed to the HasIvar helper doesn't really matter
670 // since the offset is never negative)
671 GPBMessageFieldDescription *fieldDesc = field->description_;
672 return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400673 } else {
674 return field.defaultValue.valueBool;
675 }
676}
677
678// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400679void GPBSetMessageBoolField(GPBMessage *self,
680 GPBFieldDescriptor *field,
681 BOOL value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400682 if (self == nil || field == nil) return;
683 GPBFileSyntax syntax = [self descriptor].file.syntax;
684 GPBSetBoolIvarWithFieldInternal(self, field, value, syntax);
685}
686
687void GPBSetBoolIvarWithFieldInternal(GPBMessage *self,
688 GPBFieldDescriptor *field,
689 BOOL value,
690 GPBFileSyntax syntax) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400691 GPBMessageFieldDescription *fieldDesc = field->description_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400692 GPBOneofDescriptor *oneof = field->containingOneof_;
693 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400694 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400695 }
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400696
697 // Bools are stored in the has bits to avoid needing explicit space in the
698 // storage structure.
699 // (the field number passed to the HasIvar helper doesn't really matter since
700 // the offset is never negative)
701 GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value);
702
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400703 // proto2: any value counts as having been set; proto3, it
Thomas Van Lentenca5b7752016-08-11 10:37:02 -0400704 // has to be a non zero value or be in a oneof.
705 BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
706 || (value != (BOOL)0)
707 || (field->containingOneof_ != NULL));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400708 GPBSetHasIvarField(self, field, hasValue);
709 GPBBecomeVisibleToAutocreator(self);
710}
711
712//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int32, int32_t)
713// This block of code is generated, do not edit it directly.
714
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400715int32_t GPBGetMessageInt32Field(GPBMessage *self,
716 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400717 if (GPBGetHasIvarField(self, field)) {
718 uint8_t *storage = (uint8_t *)self->messageStorage_;
719 int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
720 return *typePtr;
721 } else {
722 return field.defaultValue.valueInt32;
723 }
724}
725
726// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400727void GPBSetMessageInt32Field(GPBMessage *self,
728 GPBFieldDescriptor *field,
729 int32_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400730 if (self == nil || field == nil) return;
731 GPBFileSyntax syntax = [self descriptor].file.syntax;
732 GPBSetInt32IvarWithFieldInternal(self, field, value, syntax);
733}
734
735void GPBSetInt32IvarWithFieldInternal(GPBMessage *self,
736 GPBFieldDescriptor *field,
737 int32_t value,
738 GPBFileSyntax syntax) {
739 GPBOneofDescriptor *oneof = field->containingOneof_;
740 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400741 GPBMessageFieldDescription *fieldDesc = field->description_;
742 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400743 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400744 NSCAssert(self->messageStorage_ != NULL,
745 @"%@: All messages should have storage (from init)",
746 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400747#if defined(__clang_analyzer__)
748 if (self->messageStorage_ == NULL) return;
749#endif
750 uint8_t *storage = (uint8_t *)self->messageStorage_;
751 int32_t *typePtr = (int32_t *)&storage[field->description_->offset];
752 *typePtr = value;
753 // proto2: any value counts as having been set; proto3, it
Thomas Van Lentenca5b7752016-08-11 10:37:02 -0400754 // has to be a non zero value or be in a oneof.
755 BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
756 || (value != (int32_t)0)
757 || (field->containingOneof_ != NULL));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400758 GPBSetHasIvarField(self, field, hasValue);
759 GPBBecomeVisibleToAutocreator(self);
760}
761
762//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt32, uint32_t)
763// This block of code is generated, do not edit it directly.
764
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400765uint32_t GPBGetMessageUInt32Field(GPBMessage *self,
766 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400767 if (GPBGetHasIvarField(self, field)) {
768 uint8_t *storage = (uint8_t *)self->messageStorage_;
769 uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
770 return *typePtr;
771 } else {
772 return field.defaultValue.valueUInt32;
773 }
774}
775
776// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400777void GPBSetMessageUInt32Field(GPBMessage *self,
778 GPBFieldDescriptor *field,
779 uint32_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400780 if (self == nil || field == nil) return;
781 GPBFileSyntax syntax = [self descriptor].file.syntax;
782 GPBSetUInt32IvarWithFieldInternal(self, field, value, syntax);
783}
784
785void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self,
786 GPBFieldDescriptor *field,
787 uint32_t value,
788 GPBFileSyntax syntax) {
789 GPBOneofDescriptor *oneof = field->containingOneof_;
790 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400791 GPBMessageFieldDescription *fieldDesc = field->description_;
792 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400793 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400794 NSCAssert(self->messageStorage_ != NULL,
795 @"%@: All messages should have storage (from init)",
796 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400797#if defined(__clang_analyzer__)
798 if (self->messageStorage_ == NULL) return;
799#endif
800 uint8_t *storage = (uint8_t *)self->messageStorage_;
801 uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset];
802 *typePtr = value;
803 // proto2: any value counts as having been set; proto3, it
Thomas Van Lentenca5b7752016-08-11 10:37:02 -0400804 // has to be a non zero value or be in a oneof.
805 BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
806 || (value != (uint32_t)0)
807 || (field->containingOneof_ != NULL));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400808 GPBSetHasIvarField(self, field, hasValue);
809 GPBBecomeVisibleToAutocreator(self);
810}
811
812//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Int64, int64_t)
813// This block of code is generated, do not edit it directly.
814
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400815int64_t GPBGetMessageInt64Field(GPBMessage *self,
816 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400817 if (GPBGetHasIvarField(self, field)) {
818 uint8_t *storage = (uint8_t *)self->messageStorage_;
819 int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
820 return *typePtr;
821 } else {
822 return field.defaultValue.valueInt64;
823 }
824}
825
826// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400827void GPBSetMessageInt64Field(GPBMessage *self,
828 GPBFieldDescriptor *field,
829 int64_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400830 if (self == nil || field == nil) return;
831 GPBFileSyntax syntax = [self descriptor].file.syntax;
832 GPBSetInt64IvarWithFieldInternal(self, field, value, syntax);
833}
834
835void GPBSetInt64IvarWithFieldInternal(GPBMessage *self,
836 GPBFieldDescriptor *field,
837 int64_t value,
838 GPBFileSyntax syntax) {
839 GPBOneofDescriptor *oneof = field->containingOneof_;
840 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400841 GPBMessageFieldDescription *fieldDesc = field->description_;
842 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400843 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400844 NSCAssert(self->messageStorage_ != NULL,
845 @"%@: All messages should have storage (from init)",
846 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400847#if defined(__clang_analyzer__)
848 if (self->messageStorage_ == NULL) return;
849#endif
850 uint8_t *storage = (uint8_t *)self->messageStorage_;
851 int64_t *typePtr = (int64_t *)&storage[field->description_->offset];
852 *typePtr = value;
853 // proto2: any value counts as having been set; proto3, it
Thomas Van Lentenca5b7752016-08-11 10:37:02 -0400854 // has to be a non zero value or be in a oneof.
855 BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
856 || (value != (int64_t)0)
857 || (field->containingOneof_ != NULL));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400858 GPBSetHasIvarField(self, field, hasValue);
859 GPBBecomeVisibleToAutocreator(self);
860}
861
862//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(UInt64, uint64_t)
863// This block of code is generated, do not edit it directly.
864
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400865uint64_t GPBGetMessageUInt64Field(GPBMessage *self,
866 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400867 if (GPBGetHasIvarField(self, field)) {
868 uint8_t *storage = (uint8_t *)self->messageStorage_;
869 uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
870 return *typePtr;
871 } else {
872 return field.defaultValue.valueUInt64;
873 }
874}
875
876// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400877void GPBSetMessageUInt64Field(GPBMessage *self,
878 GPBFieldDescriptor *field,
879 uint64_t value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400880 if (self == nil || field == nil) return;
881 GPBFileSyntax syntax = [self descriptor].file.syntax;
882 GPBSetUInt64IvarWithFieldInternal(self, field, value, syntax);
883}
884
885void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self,
886 GPBFieldDescriptor *field,
887 uint64_t value,
888 GPBFileSyntax syntax) {
889 GPBOneofDescriptor *oneof = field->containingOneof_;
890 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400891 GPBMessageFieldDescription *fieldDesc = field->description_;
892 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400893 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400894 NSCAssert(self->messageStorage_ != NULL,
895 @"%@: All messages should have storage (from init)",
896 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400897#if defined(__clang_analyzer__)
898 if (self->messageStorage_ == NULL) return;
899#endif
900 uint8_t *storage = (uint8_t *)self->messageStorage_;
901 uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset];
902 *typePtr = value;
903 // proto2: any value counts as having been set; proto3, it
Thomas Van Lentenca5b7752016-08-11 10:37:02 -0400904 // has to be a non zero value or be in a oneof.
905 BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
906 || (value != (uint64_t)0)
907 || (field->containingOneof_ != NULL));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400908 GPBSetHasIvarField(self, field, hasValue);
909 GPBBecomeVisibleToAutocreator(self);
910}
911
912//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Float, float)
913// This block of code is generated, do not edit it directly.
914
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400915float GPBGetMessageFloatField(GPBMessage *self,
916 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400917 if (GPBGetHasIvarField(self, field)) {
918 uint8_t *storage = (uint8_t *)self->messageStorage_;
919 float *typePtr = (float *)&storage[field->description_->offset];
920 return *typePtr;
921 } else {
922 return field.defaultValue.valueFloat;
923 }
924}
925
926// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400927void GPBSetMessageFloatField(GPBMessage *self,
928 GPBFieldDescriptor *field,
929 float value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400930 if (self == nil || field == nil) return;
931 GPBFileSyntax syntax = [self descriptor].file.syntax;
932 GPBSetFloatIvarWithFieldInternal(self, field, value, syntax);
933}
934
935void GPBSetFloatIvarWithFieldInternal(GPBMessage *self,
936 GPBFieldDescriptor *field,
937 float value,
938 GPBFileSyntax syntax) {
939 GPBOneofDescriptor *oneof = field->containingOneof_;
940 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400941 GPBMessageFieldDescription *fieldDesc = field->description_;
942 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400943 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400944 NSCAssert(self->messageStorage_ != NULL,
945 @"%@: All messages should have storage (from init)",
946 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400947#if defined(__clang_analyzer__)
948 if (self->messageStorage_ == NULL) return;
949#endif
950 uint8_t *storage = (uint8_t *)self->messageStorage_;
951 float *typePtr = (float *)&storage[field->description_->offset];
952 *typePtr = value;
953 // proto2: any value counts as having been set; proto3, it
Thomas Van Lentenca5b7752016-08-11 10:37:02 -0400954 // has to be a non zero value or be in a oneof.
955 BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
956 || (value != (float)0)
957 || (field->containingOneof_ != NULL));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400958 GPBSetHasIvarField(self, field, hasValue);
959 GPBBecomeVisibleToAutocreator(self);
960}
961
962//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Double, double)
963// This block of code is generated, do not edit it directly.
964
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400965double GPBGetMessageDoubleField(GPBMessage *self,
966 GPBFieldDescriptor *field) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400967 if (GPBGetHasIvarField(self, field)) {
968 uint8_t *storage = (uint8_t *)self->messageStorage_;
969 double *typePtr = (double *)&storage[field->description_->offset];
970 return *typePtr;
971 } else {
972 return field.defaultValue.valueDouble;
973 }
974}
975
976// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400977void GPBSetMessageDoubleField(GPBMessage *self,
978 GPBFieldDescriptor *field,
979 double value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400980 if (self == nil || field == nil) return;
981 GPBFileSyntax syntax = [self descriptor].file.syntax;
982 GPBSetDoubleIvarWithFieldInternal(self, field, value, syntax);
983}
984
985void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self,
986 GPBFieldDescriptor *field,
987 double value,
988 GPBFileSyntax syntax) {
989 GPBOneofDescriptor *oneof = field->containingOneof_;
990 if (oneof) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400991 GPBMessageFieldDescription *fieldDesc = field->description_;
992 GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400993 }
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400994 NSCAssert(self->messageStorage_ != NULL,
995 @"%@: All messages should have storage (from init)",
996 [self class]);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400997#if defined(__clang_analyzer__)
998 if (self->messageStorage_ == NULL) return;
999#endif
1000 uint8_t *storage = (uint8_t *)self->messageStorage_;
1001 double *typePtr = (double *)&storage[field->description_->offset];
1002 *typePtr = value;
1003 // proto2: any value counts as having been set; proto3, it
Thomas Van Lentenca5b7752016-08-11 10:37:02 -04001004 // has to be a non zero value or be in a oneof.
1005 BOOL hasValue = ((syntax == GPBFileSyntaxProto2)
1006 || (value != (double)0)
1007 || (field->containingOneof_ != NULL));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001008 GPBSetHasIvarField(self, field, hasValue);
1009 GPBBecomeVisibleToAutocreator(self);
1010}
1011
Thomas Van Lenten79a23c42016-03-17 10:04:21 -04001012//%PDDM-EXPAND-END (6 expansions)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001013
1014// Aliases are function calls that are virtually the same.
1015
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001016//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(String, NSString)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001017// This block of code is generated, do not edit it directly.
1018
1019// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001020NSString *GPBGetMessageStringField(GPBMessage *self,
1021 GPBFieldDescriptor *field) {
1022 return (NSString *)GPBGetObjectIvarWithField(self, field);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001023}
1024
1025// Only exists for public api, no core code should use this.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001026void GPBSetMessageStringField(GPBMessage *self,
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001027 GPBFieldDescriptor *field,
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001028 NSString *value) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001029 GPBSetObjectIvarWithField(self, field, (id)value);
1030}
1031
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001032//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Bytes, NSData)
1033// This block of code is generated, do not edit it directly.
1034
1035// Only exists for public api, no core code should use this.
1036NSData *GPBGetMessageBytesField(GPBMessage *self,
1037 GPBFieldDescriptor *field) {
1038 return (NSData *)GPBGetObjectIvarWithField(self, field);
1039}
1040
1041// Only exists for public api, no core code should use this.
1042void GPBSetMessageBytesField(GPBMessage *self,
1043 GPBFieldDescriptor *field,
1044 NSData *value) {
1045 GPBSetObjectIvarWithField(self, field, (id)value);
1046}
1047
1048//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Message, GPBMessage)
1049// This block of code is generated, do not edit it directly.
1050
1051// Only exists for public api, no core code should use this.
1052GPBMessage *GPBGetMessageMessageField(GPBMessage *self,
1053 GPBFieldDescriptor *field) {
1054 return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
1055}
1056
1057// Only exists for public api, no core code should use this.
1058void GPBSetMessageMessageField(GPBMessage *self,
1059 GPBFieldDescriptor *field,
1060 GPBMessage *value) {
1061 GPBSetObjectIvarWithField(self, field, (id)value);
1062}
1063
1064//%PDDM-EXPAND IVAR_ALIAS_DEFN_OBJECT(Group, GPBMessage)
1065// This block of code is generated, do not edit it directly.
1066
1067// Only exists for public api, no core code should use this.
1068GPBMessage *GPBGetMessageGroupField(GPBMessage *self,
1069 GPBFieldDescriptor *field) {
1070 return (GPBMessage *)GPBGetObjectIvarWithField(self, field);
1071}
1072
1073// Only exists for public api, no core code should use this.
1074void GPBSetMessageGroupField(GPBMessage *self,
1075 GPBFieldDescriptor *field,
1076 GPBMessage *value) {
1077 GPBSetObjectIvarWithField(self, field, (id)value);
1078}
1079
1080//%PDDM-EXPAND-END (4 expansions)
1081
Thomas Van Lentenfc4c6172016-06-27 20:45:16 -04001082// GPBGetMessageRepeatedField is defined in GPBMessage.m
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001083
1084// Only exists for public api, no core code should use this.
1085void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) {
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001086#if defined(DEBUG) && DEBUG
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001087 if (field.fieldType != GPBFieldTypeRepeated) {
1088 [NSException raise:NSInvalidArgumentException
1089 format:@"%@.%@ is not a repeated field.",
1090 [self class], field.name];
1091 }
1092 Class expectedClass = Nil;
1093 switch (GPBGetFieldDataType(field)) {
1094 case GPBDataTypeBool:
1095 expectedClass = [GPBBoolArray class];
1096 break;
1097 case GPBDataTypeSFixed32:
1098 case GPBDataTypeInt32:
1099 case GPBDataTypeSInt32:
1100 expectedClass = [GPBInt32Array class];
1101 break;
1102 case GPBDataTypeFixed32:
1103 case GPBDataTypeUInt32:
1104 expectedClass = [GPBUInt32Array class];
1105 break;
1106 case GPBDataTypeSFixed64:
1107 case GPBDataTypeInt64:
1108 case GPBDataTypeSInt64:
1109 expectedClass = [GPBInt64Array class];
1110 break;
1111 case GPBDataTypeFixed64:
1112 case GPBDataTypeUInt64:
1113 expectedClass = [GPBUInt64Array class];
1114 break;
1115 case GPBDataTypeFloat:
1116 expectedClass = [GPBFloatArray class];
1117 break;
1118 case GPBDataTypeDouble:
1119 expectedClass = [GPBDoubleArray class];
1120 break;
1121 case GPBDataTypeBytes:
1122 case GPBDataTypeString:
1123 case GPBDataTypeMessage:
1124 case GPBDataTypeGroup:
Jon Walle72805e2016-05-26 12:23:41 -04001125 expectedClass = [NSMutableArray class];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001126 break;
1127 case GPBDataTypeEnum:
Jon Walle72805e2016-05-26 12:23:41 -04001128 expectedClass = [GPBEnumArray class];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001129 break;
1130 }
1131 if (array && ![array isKindOfClass:expectedClass]) {
1132 [NSException raise:NSInvalidArgumentException
1133 format:@"%@.%@: Expected %@ object, got %@.",
1134 [self class], field.name, expectedClass, [array class]];
1135 }
1136#endif
1137 GPBSetObjectIvarWithField(self, field, array);
1138}
1139
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001140#if defined(DEBUG) && DEBUG
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001141static NSString *TypeToStr(GPBDataType dataType) {
1142 switch (dataType) {
1143 case GPBDataTypeBool:
1144 return @"Bool";
1145 case GPBDataTypeSFixed32:
1146 case GPBDataTypeInt32:
1147 case GPBDataTypeSInt32:
1148 return @"Int32";
1149 case GPBDataTypeFixed32:
1150 case GPBDataTypeUInt32:
1151 return @"UInt32";
1152 case GPBDataTypeSFixed64:
1153 case GPBDataTypeInt64:
1154 case GPBDataTypeSInt64:
1155 return @"Int64";
1156 case GPBDataTypeFixed64:
1157 case GPBDataTypeUInt64:
1158 return @"UInt64";
1159 case GPBDataTypeFloat:
1160 return @"Float";
1161 case GPBDataTypeDouble:
1162 return @"Double";
1163 case GPBDataTypeBytes:
1164 case GPBDataTypeString:
1165 case GPBDataTypeMessage:
1166 case GPBDataTypeGroup:
1167 return @"Object";
1168 case GPBDataTypeEnum:
1169 return @"Bool";
1170 }
1171}
1172#endif
1173
Thomas Van Lentenfc4c6172016-06-27 20:45:16 -04001174// GPBGetMessageMapField is defined in GPBMessage.m
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001175
1176// Only exists for public api, no core code should use this.
1177void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field,
1178 id dictionary) {
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001179#if defined(DEBUG) && DEBUG
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001180 if (field.fieldType != GPBFieldTypeMap) {
1181 [NSException raise:NSInvalidArgumentException
1182 format:@"%@.%@ is not a map<> field.",
1183 [self class], field.name];
1184 }
1185 if (dictionary) {
1186 GPBDataType keyDataType = field.mapKeyDataType;
1187 GPBDataType valueDataType = GPBGetFieldDataType(field);
1188 NSString *keyStr = TypeToStr(keyDataType);
1189 NSString *valueStr = TypeToStr(valueDataType);
1190 if (keyDataType == GPBDataTypeString) {
1191 keyStr = @"String";
1192 }
1193 Class expectedClass = Nil;
1194 if ((keyDataType == GPBDataTypeString) &&
1195 GPBDataTypeIsObject(valueDataType)) {
1196 expectedClass = [NSMutableDictionary class];
1197 } else {
1198 NSString *className =
1199 [NSString stringWithFormat:@"GPB%@%@Dictionary", keyStr, valueStr];
1200 expectedClass = NSClassFromString(className);
1201 NSCAssert(expectedClass, @"Missing a class (%@)?", expectedClass);
1202 }
1203 if (![dictionary isKindOfClass:expectedClass]) {
1204 [NSException raise:NSInvalidArgumentException
1205 format:@"%@.%@: Expected %@ object, got %@.",
1206 [self class], field.name, expectedClass,
1207 [dictionary class]];
1208 }
1209 }
1210#endif
1211 GPBSetObjectIvarWithField(self, field, dictionary);
1212}
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001213
1214#pragma mark - Misc Dynamic Runtime Utils
1215
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001216const char *GPBMessageEncodingForSelector(SEL selector, BOOL instanceSel) {
1217 Protocol *protocol =
1218 objc_getProtocol(GPBStringifySymbol(GPBMessageSignatureProtocol));
1219 struct objc_method_description description =
1220 protocol_getMethodDescription(protocol, selector, NO, instanceSel);
1221 return description.types;
1222}
1223
1224#pragma mark - Text Format Support
1225
1226static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) {
1227 [destStr appendString:@"\""];
1228 NSUInteger len = [toPrint length];
1229 for (NSUInteger i = 0; i < len; ++i) {
1230 unichar aChar = [toPrint characterAtIndex:i];
1231 switch (aChar) {
1232 case '\n': [destStr appendString:@"\\n"]; break;
1233 case '\r': [destStr appendString:@"\\r"]; break;
1234 case '\t': [destStr appendString:@"\\t"]; break;
1235 case '\"': [destStr appendString:@"\\\""]; break;
1236 case '\'': [destStr appendString:@"\\\'"]; break;
1237 case '\\': [destStr appendString:@"\\\\"]; break;
1238 default:
Thomas Van Lenten1a6c1d02016-08-08 18:02:43 -04001239 // This differs slightly from the C++ code in that the C++ doesn't
1240 // generate UTF8; it looks at the string in UTF8, but escapes every
1241 // byte > 0x7E.
1242 if (aChar < 0x20) {
1243 [destStr appendFormat:@"\\%d%d%d",
1244 (aChar / 64), ((aChar % 64) / 8), (aChar % 8)];
1245 } else {
1246 [destStr appendFormat:@"%C", aChar];
1247 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001248 break;
1249 }
1250 }
1251 [destStr appendString:@"\""];
1252}
1253
1254static void AppendBufferAsString(NSData *buffer, NSMutableString *destStr) {
1255 const char *src = (const char *)[buffer bytes];
1256 size_t srcLen = [buffer length];
1257 [destStr appendString:@"\""];
1258 for (const char *srcEnd = src + srcLen; src < srcEnd; src++) {
1259 switch (*src) {
1260 case '\n': [destStr appendString:@"\\n"]; break;
1261 case '\r': [destStr appendString:@"\\r"]; break;
1262 case '\t': [destStr appendString:@"\\t"]; break;
1263 case '\"': [destStr appendString:@"\\\""]; break;
1264 case '\'': [destStr appendString:@"\\\'"]; break;
1265 case '\\': [destStr appendString:@"\\\\"]; break;
1266 default:
1267 if (isprint(*src)) {
1268 [destStr appendFormat:@"%c", *src];
1269 } else {
1270 // NOTE: doing hex means you have to worry about the letter after
1271 // the hex being another hex char and forcing that to be escaped, so
1272 // use octal to keep it simple.
1273 [destStr appendFormat:@"\\%03o", (uint8_t)(*src)];
1274 }
1275 break;
1276 }
1277 }
1278 [destStr appendString:@"\""];
1279}
1280
1281static void AppendTextFormatForMapMessageField(
1282 id map, GPBFieldDescriptor *field, NSMutableString *toStr,
1283 NSString *lineIndent, NSString *fieldName, NSString *lineEnding) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001284 GPBDataType keyDataType = field.mapKeyDataType;
1285 GPBDataType valueDataType = GPBGetFieldDataType(field);
1286 BOOL isMessageValue = GPBDataTypeIsMessage(valueDataType);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001287
1288 NSString *msgStartFirst =
1289 [NSString stringWithFormat:@"%@%@ {%@\n", lineIndent, fieldName, lineEnding];
1290 NSString *msgStart =
1291 [NSString stringWithFormat:@"%@%@ {\n", lineIndent, fieldName];
1292 NSString *msgEnd = [NSString stringWithFormat:@"%@}\n", lineIndent];
1293
1294 NSString *keyLine = [NSString stringWithFormat:@"%@ key: ", lineIndent];
1295 NSString *valueLine = [NSString stringWithFormat:@"%@ value%s ", lineIndent,
1296 (isMessageValue ? "" : ":")];
1297
1298 __block BOOL isFirst = YES;
1299
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001300 if ((keyDataType == GPBDataTypeString) &&
1301 GPBDataTypeIsObject(valueDataType)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001302 // map is an NSDictionary.
1303 NSDictionary *dict = map;
1304 [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
1305 #pragma unused(stop)
1306 [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
1307 isFirst = NO;
1308
1309 [toStr appendString:keyLine];
1310 AppendStringEscaped(key, toStr);
1311 [toStr appendString:@"\n"];
1312
1313 [toStr appendString:valueLine];
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001314#pragma clang diagnostic push
1315#pragma clang diagnostic ignored "-Wswitch-enum"
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001316 switch (valueDataType) {
1317 case GPBDataTypeString:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001318 AppendStringEscaped(value, toStr);
1319 break;
1320
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001321 case GPBDataTypeBytes:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001322 AppendBufferAsString(value, toStr);
1323 break;
1324
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001325 case GPBDataTypeMessage:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001326 [toStr appendString:@"{\n"];
1327 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1328 AppendTextFormatForMessage(value, toStr, subIndent);
1329 [toStr appendFormat:@"%@ }", lineIndent];
1330 break;
1331
1332 default:
1333 NSCAssert(NO, @"Can't happen");
1334 break;
1335 }
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001336#pragma clang diagnostic pop
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001337 [toStr appendString:@"\n"];
1338
1339 [toStr appendString:msgEnd];
1340 }];
1341 } else {
1342 // map is one of the GPB*Dictionary classes, type doesn't matter.
1343 GPBInt32Int32Dictionary *dict = map;
1344 [dict enumerateForTextFormat:^(id keyObj, id valueObj) {
1345 [toStr appendString:(isFirst ? msgStartFirst : msgStart)];
1346 isFirst = NO;
1347
1348 // Key always is a NSString.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001349 if (keyDataType == GPBDataTypeString) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001350 [toStr appendString:keyLine];
1351 AppendStringEscaped(keyObj, toStr);
1352 [toStr appendString:@"\n"];
1353 } else {
1354 [toStr appendFormat:@"%@%@\n", keyLine, keyObj];
1355 }
1356
1357 [toStr appendString:valueLine];
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001358#pragma clang diagnostic push
1359#pragma clang diagnostic ignored "-Wswitch-enum"
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001360 switch (valueDataType) {
1361 case GPBDataTypeString:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001362 AppendStringEscaped(valueObj, toStr);
1363 break;
1364
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001365 case GPBDataTypeBytes:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001366 AppendBufferAsString(valueObj, toStr);
1367 break;
1368
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001369 case GPBDataTypeMessage:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001370 [toStr appendString:@"{\n"];
1371 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1372 AppendTextFormatForMessage(valueObj, toStr, subIndent);
1373 [toStr appendFormat:@"%@ }", lineIndent];
1374 break;
1375
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001376 case GPBDataTypeEnum: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001377 int32_t enumValue = [valueObj intValue];
1378 NSString *valueStr = nil;
1379 GPBEnumDescriptor *descriptor = field.enumDescriptor;
1380 if (descriptor) {
1381 valueStr = [descriptor textFormatNameForValue:enumValue];
1382 }
1383 if (valueStr) {
1384 [toStr appendString:valueStr];
1385 } else {
1386 [toStr appendFormat:@"%d", enumValue];
1387 }
1388 break;
1389 }
1390
1391 default:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001392 NSCAssert(valueDataType != GPBDataTypeGroup, @"Can't happen");
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001393 // Everything else is a NSString.
1394 [toStr appendString:valueObj];
1395 break;
1396 }
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001397#pragma clang diagnostic pop
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001398 [toStr appendString:@"\n"];
1399
1400 [toStr appendString:msgEnd];
1401 }];
1402 }
1403}
1404
1405static void AppendTextFormatForMessageField(GPBMessage *message,
1406 GPBFieldDescriptor *field,
1407 NSMutableString *toStr,
1408 NSString *lineIndent) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001409 id arrayOrMap;
1410 NSUInteger count;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001411 GPBFieldType fieldType = field.fieldType;
1412 switch (fieldType) {
1413 case GPBFieldTypeSingle:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001414 arrayOrMap = nil;
1415 count = (GPBGetHasIvarField(message, field) ? 1 : 0);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001416 break;
1417
1418 case GPBFieldTypeRepeated:
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001419 // Will be NSArray or GPB*Array, type doesn't matter, they both
1420 // implement count.
1421 arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
1422 count = [(NSArray *)arrayOrMap count];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001423 break;
1424
1425 case GPBFieldTypeMap: {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001426 // Will be GPB*Dictionary or NSMutableDictionary, type doesn't matter,
1427 // they both implement count.
1428 arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(message, field);
1429 count = [(NSDictionary *)arrayOrMap count];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001430 break;
1431 }
1432 }
1433
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001434 if (count == 0) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001435 // Nothing to print, out of here.
1436 return;
1437 }
1438
1439 NSString *lineEnding = @"";
1440
1441 // If the name can't be reversed or support for extra info was turned off,
1442 // this can return nil.
1443 NSString *fieldName = [field textFormatName];
1444 if ([fieldName length] == 0) {
1445 fieldName = [NSString stringWithFormat:@"%u", GPBFieldNumber(field)];
1446 // If there is only one entry, put the objc name as a comment, other wise
Dongjoon Hyun7a9040f2016-01-14 22:12:03 -08001447 // add it before the repeated values.
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001448 if (count > 1) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001449 [toStr appendFormat:@"%@# %@\n", lineIndent, field.name];
1450 } else {
1451 lineEnding = [NSString stringWithFormat:@" # %@", field.name];
1452 }
1453 }
1454
1455 if (fieldType == GPBFieldTypeMap) {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001456 AppendTextFormatForMapMessageField(arrayOrMap, field, toStr, lineIndent,
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001457 fieldName, lineEnding);
1458 return;
1459 }
1460
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001461 id array = arrayOrMap;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001462 const BOOL isRepeated = (array != nil);
1463
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001464 GPBDataType fieldDataType = GPBGetFieldDataType(field);
1465 BOOL isMessageField = GPBDataTypeIsMessage(fieldDataType);
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001466 for (NSUInteger j = 0; j < count; ++j) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001467 // Start the line.
1468 [toStr appendFormat:@"%@%@%s ", lineIndent, fieldName,
1469 (isMessageField ? "" : ":")];
1470
1471 // The value.
1472 switch (fieldDataType) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001473#define FIELD_CASE(GPBDATATYPE, CTYPE, REAL_TYPE, ...) \
1474 case GPBDataType##GPBDATATYPE: { \
1475 CTYPE v = (isRepeated ? [(GPB##REAL_TYPE##Array *)array valueAtIndex:j] \
1476 : GPBGetMessage##REAL_TYPE##Field(message, field)); \
1477 [toStr appendFormat:__VA_ARGS__, v]; \
1478 break; \
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001479 }
1480
1481 FIELD_CASE(Int32, int32_t, Int32, @"%d")
1482 FIELD_CASE(SInt32, int32_t, Int32, @"%d")
1483 FIELD_CASE(SFixed32, int32_t, Int32, @"%d")
1484 FIELD_CASE(UInt32, uint32_t, UInt32, @"%u")
1485 FIELD_CASE(Fixed32, uint32_t, UInt32, @"%u")
1486 FIELD_CASE(Int64, int64_t, Int64, @"%lld")
1487 FIELD_CASE(SInt64, int64_t, Int64, @"%lld")
1488 FIELD_CASE(SFixed64, int64_t, Int64, @"%lld")
1489 FIELD_CASE(UInt64, uint64_t, UInt64, @"%llu")
1490 FIELD_CASE(Fixed64, uint64_t, UInt64, @"%llu")
1491 FIELD_CASE(Float, float, Float, @"%.*g", FLT_DIG)
1492 FIELD_CASE(Double, double, Double, @"%.*lg", DBL_DIG)
1493
1494#undef FIELD_CASE
1495
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001496 case GPBDataTypeEnum: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001497 int32_t v = (isRepeated ? [(GPBEnumArray *)array rawValueAtIndex:j]
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001498 : GPBGetMessageInt32Field(message, field));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001499 NSString *valueStr = nil;
1500 GPBEnumDescriptor *descriptor = field.enumDescriptor;
1501 if (descriptor) {
1502 valueStr = [descriptor textFormatNameForValue:v];
1503 }
1504 if (valueStr) {
1505 [toStr appendString:valueStr];
1506 } else {
1507 [toStr appendFormat:@"%d", v];
1508 }
1509 break;
1510 }
1511
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001512 case GPBDataTypeBool: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001513 BOOL v = (isRepeated ? [(GPBBoolArray *)array valueAtIndex:j]
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001514 : GPBGetMessageBoolField(message, field));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001515 [toStr appendString:(v ? @"true" : @"false")];
1516 break;
1517 }
1518
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001519 case GPBDataTypeString: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001520 NSString *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001521 : GPBGetMessageStringField(message, field));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001522 AppendStringEscaped(v, toStr);
1523 break;
1524 }
1525
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001526 case GPBDataTypeBytes: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001527 NSData *v = (isRepeated ? [(NSArray *)array objectAtIndex:j]
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001528 : GPBGetMessageBytesField(message, field));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001529 AppendBufferAsString(v, toStr);
1530 break;
1531 }
1532
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001533 case GPBDataTypeGroup:
1534 case GPBDataTypeMessage: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001535 GPBMessage *v =
1536 (isRepeated ? [(NSArray *)array objectAtIndex:j]
1537 : GPBGetObjectIvarWithField(message, field));
1538 [toStr appendFormat:@"{%@\n", lineEnding];
1539 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1540 AppendTextFormatForMessage(v, toStr, subIndent);
1541 [toStr appendFormat:@"%@}", lineIndent];
1542 lineEnding = @"";
1543 break;
1544 }
1545
1546 } // switch(fieldDataType)
1547
1548 // End the line.
1549 [toStr appendFormat:@"%@\n", lineEnding];
1550
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -04001551 } // for(count)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001552}
1553
1554static void AppendTextFormatForMessageExtensionRange(GPBMessage *message,
1555 NSArray *activeExtensions,
1556 GPBExtensionRange range,
1557 NSMutableString *toStr,
1558 NSString *lineIndent) {
1559 uint32_t start = range.start;
1560 uint32_t end = range.end;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001561 for (GPBExtensionDescriptor *extension in activeExtensions) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001562 uint32_t fieldNumber = extension.fieldNumber;
1563 if (fieldNumber < start) {
1564 // Not there yet.
1565 continue;
1566 }
1567 if (fieldNumber > end) {
1568 // Done.
1569 break;
1570 }
1571
1572 id rawExtValue = [message getExtension:extension];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001573 BOOL isRepeated = extension.isRepeated;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001574
1575 NSUInteger numValues = 1;
1576 NSString *lineEnding = @"";
1577 if (isRepeated) {
1578 numValues = [(NSArray *)rawExtValue count];
1579 }
1580
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001581 NSString *singletonName = extension.singletonName;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001582 if (numValues == 1) {
1583 lineEnding = [NSString stringWithFormat:@" # [%@]", singletonName];
1584 } else {
1585 [toStr appendFormat:@"%@# [%@]\n", lineIndent, singletonName];
1586 }
1587
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001588 GPBDataType extDataType = extension.dataType;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001589 for (NSUInteger j = 0; j < numValues; ++j) {
1590 id curValue = (isRepeated ? [rawExtValue objectAtIndex:j] : rawExtValue);
1591
1592 // Start the line.
1593 [toStr appendFormat:@"%@%u%s ", lineIndent, fieldNumber,
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001594 (GPBDataTypeIsMessage(extDataType) ? "" : ":")];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001595
1596 // The value.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001597 switch (extDataType) {
1598#define FIELD_CASE(GPBDATATYPE, CTYPE, NUMSELECTOR, ...) \
1599 case GPBDataType##GPBDATATYPE: { \
1600 CTYPE v = [(NSNumber *)curValue NUMSELECTOR]; \
1601 [toStr appendFormat:__VA_ARGS__, v]; \
1602 break; \
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001603 }
1604
1605 FIELD_CASE(Int32, int32_t, intValue, @"%d")
1606 FIELD_CASE(SInt32, int32_t, intValue, @"%d")
1607 FIELD_CASE(SFixed32, int32_t, unsignedIntValue, @"%d")
1608 FIELD_CASE(UInt32, uint32_t, unsignedIntValue, @"%u")
1609 FIELD_CASE(Fixed32, uint32_t, unsignedIntValue, @"%u")
1610 FIELD_CASE(Int64, int64_t, longLongValue, @"%lld")
1611 FIELD_CASE(SInt64, int64_t, longLongValue, @"%lld")
1612 FIELD_CASE(SFixed64, int64_t, longLongValue, @"%lld")
1613 FIELD_CASE(UInt64, uint64_t, unsignedLongLongValue, @"%llu")
1614 FIELD_CASE(Fixed64, uint64_t, unsignedLongLongValue, @"%llu")
1615 FIELD_CASE(Float, float, floatValue, @"%.*g", FLT_DIG)
1616 FIELD_CASE(Double, double, doubleValue, @"%.*lg", DBL_DIG)
1617 // TODO: Add a comment with the enum name from enum descriptors
1618 // (might not be real value, so leave it as a comment, ObjC compiler
1619 // name mangles differently). Doesn't look like we actually generate
1620 // an enum descriptor reference like we do for normal fields, so this
1621 // will take a compiler change.
1622 FIELD_CASE(Enum, int32_t, intValue, @"%d")
1623
1624#undef FIELD_CASE
1625
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001626 case GPBDataTypeBool:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001627 [toStr appendString:([(NSNumber *)curValue boolValue] ? @"true"
1628 : @"false")];
1629 break;
1630
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001631 case GPBDataTypeString:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001632 AppendStringEscaped(curValue, toStr);
1633 break;
1634
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001635 case GPBDataTypeBytes:
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001636 AppendBufferAsString((NSData *)curValue, toStr);
1637 break;
1638
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001639 case GPBDataTypeGroup:
1640 case GPBDataTypeMessage: {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001641 [toStr appendFormat:@"{%@\n", lineEnding];
1642 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1643 AppendTextFormatForMessage(curValue, toStr, subIndent);
1644 [toStr appendFormat:@"%@}", lineIndent];
1645 lineEnding = @"";
1646 break;
1647 }
1648
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001649 } // switch(extDataType)
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001650
1651 } // for(numValues)
1652
1653 // End the line.
1654 [toStr appendFormat:@"%@\n", lineEnding];
1655
1656 } // for..in(activeExtensions)
1657}
1658
1659static void AppendTextFormatForMessage(GPBMessage *message,
1660 NSMutableString *toStr,
1661 NSString *lineIndent) {
1662 GPBDescriptor *descriptor = [message descriptor];
1663 NSArray *fieldsArray = descriptor->fields_;
1664 NSUInteger fieldCount = fieldsArray.count;
1665 const GPBExtensionRange *extensionRanges = descriptor.extensionRanges;
1666 NSUInteger extensionRangesCount = descriptor.extensionRangesCount;
Sergio Campamáb99577c2016-07-15 15:04:01 -07001667 NSArray *activeExtensions = [[message extensionsCurrentlySet]
1668 sortedArrayUsingSelector:@selector(compareByFieldNumber:)];
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001669 for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) {
1670 if (i == fieldCount) {
1671 AppendTextFormatForMessageExtensionRange(
1672 message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
1673 } else if (j == extensionRangesCount ||
1674 GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) {
1675 AppendTextFormatForMessageField(message, fieldsArray[i++], toStr,
1676 lineIndent);
1677 } else {
1678 AppendTextFormatForMessageExtensionRange(
1679 message, activeExtensions, extensionRanges[j++], toStr, lineIndent);
1680 }
1681 }
1682
1683 NSString *unknownFieldsStr =
1684 GPBTextFormatForUnknownFieldSet(message.unknownFields, lineIndent);
1685 if ([unknownFieldsStr length] > 0) {
1686 [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent];
1687 [toStr appendString:unknownFieldsStr];
1688 }
1689}
1690
1691NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) {
Thomas Van Lenten8c889572015-06-16 16:45:14 -04001692 if (message == nil) return @"";
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001693 if (lineIndent == nil) lineIndent = @"";
1694
1695 NSMutableString *buildString = [NSMutableString string];
1696 AppendTextFormatForMessage(message, buildString, lineIndent);
1697 return buildString;
1698}
1699
1700NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *unknownSet,
1701 NSString *lineIndent) {
Thomas Van Lenten8c889572015-06-16 16:45:14 -04001702 if (unknownSet == nil) return @"";
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001703 if (lineIndent == nil) lineIndent = @"";
1704
1705 NSMutableString *result = [NSMutableString string];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001706 for (GPBUnknownField *field in [unknownSet sortedFields]) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001707 int32_t fieldNumber = [field number];
1708
1709#define PRINT_LOOP(PROPNAME, CTYPE, FORMAT) \
1710 [field.PROPNAME \
1711 enumerateValuesWithBlock:^(CTYPE value, NSUInteger idx, BOOL * stop) { \
1712 _Pragma("unused(idx, stop)"); \
1713 [result \
1714 appendFormat:@"%@%d: " #FORMAT "\n", lineIndent, fieldNumber, value]; \
1715 }];
1716
1717 PRINT_LOOP(varintList, uint64_t, %llu);
1718 PRINT_LOOP(fixed32List, uint32_t, 0x%X);
1719 PRINT_LOOP(fixed64List, uint64_t, 0x%llX);
1720
1721#undef PRINT_LOOP
1722
1723 // NOTE: C++ version of TextFormat tries to parse this as a message
1724 // and print that if it succeeds.
1725 for (NSData *data in field.lengthDelimitedList) {
1726 [result appendFormat:@"%@%d: ", lineIndent, fieldNumber];
1727 AppendBufferAsString(data, result);
1728 [result appendString:@"\n"];
1729 }
1730
1731 for (GPBUnknownFieldSet *subUnknownSet in field.groupList) {
1732 [result appendFormat:@"%@%d: {\n", lineIndent, fieldNumber];
1733 NSString *subIndent = [lineIndent stringByAppendingString:@" "];
1734 NSString *subUnknwonSetStr =
1735 GPBTextFormatForUnknownFieldSet(subUnknownSet, subIndent);
1736 [result appendString:subUnknwonSetStr];
1737 [result appendFormat:@"%@}\n", lineIndent];
1738 }
1739 }
1740 return result;
1741}
1742
1743// Helpers to decode a varint. Not using GPBCodedInputStream version because
1744// that needs a state object, and we don't want to create an input stream out
1745// of the data.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001746GPB_INLINE int8_t ReadRawByteFromData(const uint8_t **data) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001747 int8_t result = *((int8_t *)(*data));
1748 ++(*data);
1749 return result;
1750}
1751
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001752static int32_t ReadRawVarint32FromData(const uint8_t **data) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001753 int8_t tmp = ReadRawByteFromData(data);
1754 if (tmp >= 0) {
1755 return tmp;
1756 }
1757 int32_t result = tmp & 0x7f;
1758 if ((tmp = ReadRawByteFromData(data)) >= 0) {
1759 result |= tmp << 7;
1760 } else {
1761 result |= (tmp & 0x7f) << 7;
1762 if ((tmp = ReadRawByteFromData(data)) >= 0) {
1763 result |= tmp << 14;
1764 } else {
1765 result |= (tmp & 0x7f) << 14;
1766 if ((tmp = ReadRawByteFromData(data)) >= 0) {
1767 result |= tmp << 21;
1768 } else {
1769 result |= (tmp & 0x7f) << 21;
1770 result |= (tmp = ReadRawByteFromData(data)) << 28;
1771 if (tmp < 0) {
1772 // Discard upper 32 bits.
1773 for (int i = 0; i < 5; i++) {
1774 if (ReadRawByteFromData(data) >= 0) {
1775 return result;
1776 }
1777 }
1778 [NSException raise:NSParseErrorException
1779 format:@"Unable to read varint32"];
1780 }
1781 }
1782 }
1783 }
1784 return result;
1785}
1786
1787NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key,
1788 NSString *inputStr) {
1789 // decodData form:
1790 // varint32: num entries
1791 // for each entry:
1792 // varint32: key
1793 // bytes*: decode data
1794 //
1795 // decode data one of two forms:
1796 // 1: a \0 followed by the string followed by an \0
1797 // 2: bytecodes to transform an input into the right thing, ending with \0
1798 //
1799 // the bytes codes are of the form:
1800 // 0xabbccccc
1801 // 0x0 (all zeros), end.
1802 // a - if set, add an underscore
1803 // bb - 00 ccccc bytes as is
1804 // bb - 10 ccccc upper first, as is on rest, ccccc byte total
1805 // bb - 01 ccccc lower first, as is on rest, ccccc byte total
1806 // bb - 11 ccccc all upper, ccccc byte total
1807
1808 if (!decodeData || !inputStr) {
1809 return nil;
1810 }
1811
1812 // Find key
1813 const uint8_t *scan = decodeData;
1814 int32_t numEntries = ReadRawVarint32FromData(&scan);
1815 BOOL foundKey = NO;
1816 while (!foundKey && (numEntries > 0)) {
1817 --numEntries;
1818 int32_t dataKey = ReadRawVarint32FromData(&scan);
1819 if (dataKey == key) {
1820 foundKey = YES;
1821 } else {
1822 // If it is a inlined string, it will start with \0; if it is bytecode it
1823 // will start with a code. So advance one (skipping the inline string
1824 // marker), and then loop until reaching the end marker (\0).
1825 ++scan;
1826 while (*scan != 0) ++scan;
1827 // Now move past the end marker.
1828 ++scan;
1829 }
1830 }
1831
1832 if (!foundKey) {
1833 return nil;
1834 }
1835
1836 // Decode
1837
1838 if (*scan == 0) {
1839 // Inline string. Move over the marker, and NSString can take it as
1840 // UTF8.
1841 ++scan;
1842 NSString *result = [NSString stringWithUTF8String:(const char *)scan];
1843 return result;
1844 }
1845
1846 NSMutableString *result =
1847 [NSMutableString stringWithCapacity:[inputStr length]];
1848
1849 const uint8_t kAddUnderscore = 0b10000000;
1850 const uint8_t kOpMask = 0b01100000;
1851 // const uint8_t kOpAsIs = 0b00000000;
1852 const uint8_t kOpFirstUpper = 0b01000000;
1853 const uint8_t kOpFirstLower = 0b00100000;
1854 const uint8_t kOpAllUpper = 0b01100000;
1855 const uint8_t kSegmentLenMask = 0b00011111;
1856
1857 NSInteger i = 0;
1858 for (; *scan != 0; ++scan) {
1859 if (*scan & kAddUnderscore) {
1860 [result appendString:@"_"];
1861 }
1862 int segmentLen = *scan & kSegmentLenMask;
1863 uint8_t decodeOp = *scan & kOpMask;
1864
1865 // Do op specific handling of the first character.
1866 if (decodeOp == kOpFirstUpper) {
1867 unichar c = [inputStr characterAtIndex:i];
1868 [result appendFormat:@"%c", toupper((char)c)];
1869 ++i;
1870 --segmentLen;
1871 } else if (decodeOp == kOpFirstLower) {
1872 unichar c = [inputStr characterAtIndex:i];
1873 [result appendFormat:@"%c", tolower((char)c)];
1874 ++i;
1875 --segmentLen;
1876 }
1877 // else op == kOpAsIs || op == kOpAllUpper
1878
1879 // Now pull over the rest of the length for this segment.
1880 for (int x = 0; x < segmentLen; ++x) {
1881 unichar c = [inputStr characterAtIndex:(i + x)];
1882 if (decodeOp == kOpAllUpper) {
1883 [result appendFormat:@"%c", toupper((char)c)];
1884 } else {
1885 [result appendFormat:@"%C", c];
1886 }
1887 }
1888 i += segmentLen;
1889 }
1890
1891 return result;
1892}
1893
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001894#pragma clang diagnostic pop
1895
Thomas Van Lenten2d1c5e22017-03-02 14:50:10 -05001896BOOL GPBClassHasSel(Class aClass, SEL sel) {
1897 // NOTE: We have to use class_copyMethodList, all other runtime method
1898 // lookups actually also resolve the method implementation and this
1899 // is called from within those methods.
1900
1901 BOOL result = NO;
1902 unsigned int methodCount = 0;
1903 Method *methodList = class_copyMethodList(aClass, &methodCount);
1904 for (unsigned int i = 0; i < methodCount; ++i) {
1905 SEL methodSelector = method_getName(methodList[i]);
1906 if (methodSelector == sel) {
1907 result = YES;
1908 break;
1909 }
1910 }
1911 free(methodList);
1912 return result;
1913}
1914
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001915#pragma mark - GPBMessageSignatureProtocol
1916
1917// A series of selectors that are used solely to get @encoding values
1918// for them by the dynamic protobuf runtime code. An object using the protocol
1919// needs to be declared for the protocol to be valid at runtime.
1920@interface GPBMessageSignatureProtocol : NSObject<GPBMessageSignatureProtocol>
1921@end
1922@implementation GPBMessageSignatureProtocol
1923@end