blob: bb178138aa74afbdc1d25715bf175989c7f8d333 [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 "GPBDescriptor_PackagePrivate.h"
32
33#import <objc/runtime.h>
34
35#import "GPBUtilities_PackagePrivate.h"
36#import "GPBWireFormat.h"
37#import "GPBMessage_PackagePrivate.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040038
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -040039// Direct access is use for speed, to avoid even internally declaring things
40// read/write, etc. The warning is enabled in the project to ensure code calling
41// protos can turn on -Wdirect-ivar-access without issues.
42#pragma clang diagnostic push
43#pragma clang diagnostic ignored "-Wdirect-ivar-access"
44
Thomas Van Lenten337ec302016-08-16 11:26:49 -040045// The addresses of these variables are used as keys for objc_getAssociatedObject.
Thomas Van Lenten30650d82015-05-01 08:57:16 -040046static const char kTextFormatExtraValueKey = 0;
Dave MacLachlan74956e12019-12-17 17:32:09 -080047static const char kParentClassValueKey = 0;
Thomas Van Lenten337ec302016-08-16 11:26:49 -040048static const char kClassNameSuffixKey = 0;
Thomas Van Lenten30650d82015-05-01 08:57:16 -040049
50// Utility function to generate selectors on the fly.
51static SEL SelFromStrings(const char *prefix, const char *middle,
52 const char *suffix, BOOL takesArg) {
53 if (prefix == NULL && suffix == NULL && !takesArg) {
54 return sel_getUid(middle);
55 }
56 const size_t prefixLen = prefix != NULL ? strlen(prefix) : 0;
57 const size_t middleLen = strlen(middle);
58 const size_t suffixLen = suffix != NULL ? strlen(suffix) : 0;
59 size_t totalLen =
60 prefixLen + middleLen + suffixLen + 1; // include space for null on end.
61 if (takesArg) {
62 totalLen += 1;
63 }
64 char buffer[totalLen];
65 if (prefix != NULL) {
66 memcpy(buffer, prefix, prefixLen);
67 memcpy(buffer + prefixLen, middle, middleLen);
68 buffer[prefixLen] = (char)toupper(buffer[prefixLen]);
69 } else {
70 memcpy(buffer, middle, middleLen);
71 }
72 if (suffix != NULL) {
73 memcpy(buffer + prefixLen + middleLen, suffix, suffixLen);
74 }
75 if (takesArg) {
76 buffer[totalLen - 2] = ':';
77 }
78 // Always null terminate it.
79 buffer[totalLen - 1] = 0;
80
81 SEL result = sel_getUid(buffer);
82 return result;
83}
84
85static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
86 NSArray *allMessageFields)
87 __attribute__((ns_returns_retained));
88
89static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
90 NSArray *allMessageFields) {
91 NSMutableArray *result = [[NSMutableArray alloc] init];
92 for (GPBFieldDescriptor *fieldDesc in allMessageFields) {
93 if (fieldDesc->description_->hasIndex == hasIndex) {
94 [result addObject:fieldDesc];
95 }
96 }
97 return result;
98}
99
100@implementation GPBDescriptor {
101 Class messageClass_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400102 GPBFileDescriptor *file_;
103 BOOL wireFormat_;
104}
105
106@synthesize messageClass = messageClass_;
107@synthesize fields = fields_;
108@synthesize oneofs = oneofs_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400109@synthesize extensionRanges = extensionRanges_;
110@synthesize extensionRangesCount = extensionRangesCount_;
111@synthesize file = file_;
112@synthesize wireFormat = wireFormat_;
113
114+ (instancetype)
115 allocDescriptorForClass:(Class)messageClass
116 rootClass:(Class)rootClass
117 file:(GPBFileDescriptor *)file
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400118 fields:(void *)fieldDescriptions
119 fieldCount:(uint32_t)fieldCount
120 storageSize:(uint32_t)storageSize
121 flags:(GPBDescriptorInitializationFlags)flags {
122 // The rootClass is no longer used, but it is passed in to ensure it
123 // was started up during initialization also.
124 (void)rootClass;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400125 NSMutableArray *fields = nil;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400126 GPBFileSyntax syntax = file.syntax;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400127 BOOL fieldsIncludeDefault =
128 (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
Dave MacLachlan74956e12019-12-17 17:32:09 -0800129 BOOL usesClassRefs =
130 (flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0;
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400131 BOOL proto3OptionalKnown =
132 (flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) != 0;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400133
134 void *desc;
135 for (uint32_t i = 0; i < fieldCount; ++i) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400136 if (fields == nil) {
137 fields = [[NSMutableArray alloc] initWithCapacity:fieldCount];
138 }
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400139 // Need correctly typed pointer for array indexing below to work.
140 if (fieldsIncludeDefault) {
141 GPBMessageFieldDescriptionWithDefault *fieldDescWithDefault = fieldDescriptions;
142 desc = &(fieldDescWithDefault[i]);
143 } else {
144 GPBMessageFieldDescription *fieldDesc = fieldDescriptions;
145 desc = &(fieldDesc[i]);
146 }
147 GPBFieldDescriptor *fieldDescriptor =
148 [[GPBFieldDescriptor alloc] initWithFieldDescription:desc
149 includesDefault:fieldsIncludeDefault
Dave MacLachlan74956e12019-12-17 17:32:09 -0800150 usesClassRefs:usesClassRefs
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400151 proto3OptionalKnown:proto3OptionalKnown
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400152 syntax:syntax];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400153 [fields addObject:fieldDescriptor];
154 [fieldDescriptor release];
155 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400156
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400157 BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400158 GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
159 file:file
160 fields:fields
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400161 storageSize:storageSize
162 wireFormat:wireFormat];
163 [fields release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400164 return descriptor;
165}
166
167- (instancetype)initWithClass:(Class)messageClass
168 file:(GPBFileDescriptor *)file
169 fields:(NSArray *)fields
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400170 storageSize:(uint32_t)storageSize
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400171 wireFormat:(BOOL)wireFormat {
172 if ((self = [super init])) {
173 messageClass_ = messageClass;
174 file_ = file;
175 fields_ = [fields retain];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400176 storageSize_ = storageSize;
177 wireFormat_ = wireFormat;
178 }
179 return self;
180}
181
182- (void)dealloc {
183 [fields_ release];
184 [oneofs_ release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400185 [super dealloc];
186}
187
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400188- (void)setupOneofs:(const char **)oneofNames
189 count:(uint32_t)count
190 firstHasIndex:(int32_t)firstHasIndex {
191 NSCAssert(firstHasIndex < 0, @"Should always be <0");
192 NSMutableArray *oneofs = [[NSMutableArray alloc] initWithCapacity:count];
193 for (uint32_t i = 0, hasIndex = firstHasIndex; i < count; ++i, --hasIndex) {
194 const char *name = oneofNames[i];
195 NSArray *fieldsForOneof = NewFieldsArrayForHasIndex(hasIndex, fields_);
196 NSCAssert(fieldsForOneof.count > 0,
197 @"No fields for this oneof? (%s:%d)", name, hasIndex);
198 GPBOneofDescriptor *oneofDescriptor =
199 [[GPBOneofDescriptor alloc] initWithName:name fields:fieldsForOneof];
200 [oneofs addObject:oneofDescriptor];
201 [oneofDescriptor release];
202 [fieldsForOneof release];
203 }
204 oneofs_ = oneofs;
205}
206
207- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo {
208 // Extra info is a compile time option, so skip the work if not needed.
209 if (extraTextFormatInfo) {
210 NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo];
211 for (GPBFieldDescriptor *fieldDescriptor in fields_) {
212 if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) {
213 objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey,
214 extraInfoValue,
215 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
216 }
217 }
218 }
219}
220
221- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count {
222 extensionRanges_ = ranges;
223 extensionRangesCount_ = count;
224}
225
Dave MacLachlan74956e12019-12-17 17:32:09 -0800226- (void)setupContainingMessageClass:(Class)messageClass {
227 objc_setAssociatedObject(self, &kParentClassValueKey,
228 messageClass,
229 OBJC_ASSOCIATION_ASSIGN);
230}
231
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400232- (void)setupContainingMessageClassName:(const char *)msgClassName {
233 // Note: Only fetch the class here, can't send messages to it because
234 // that could cause cycles back to this class within +initialize if
235 // two messages have each other in fields (i.e. - they build a graph).
Dave MacLachlan74956e12019-12-17 17:32:09 -0800236 Class clazz = objc_getClass(msgClassName);
237 NSAssert(clazz, @"Class %s not defined", msgClassName);
238 [self setupContainingMessageClass:clazz];
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400239}
240
241- (void)setupMessageClassNameSuffix:(NSString *)suffix {
242 if (suffix.length) {
243 objc_setAssociatedObject(self, &kClassNameSuffixKey,
244 suffix,
245 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
246 }
247}
248
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400249- (NSString *)name {
250 return NSStringFromClass(messageClass_);
251}
252
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400253- (GPBDescriptor *)containingType {
Dave MacLachlan74956e12019-12-17 17:32:09 -0800254 Class parentClass = objc_getAssociatedObject(self, &kParentClassValueKey);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400255 return [parentClass descriptor];
256}
257
258- (NSString *)fullName {
259 NSString *className = NSStringFromClass(self.messageClass);
260 GPBFileDescriptor *file = self.file;
261 NSString *objcPrefix = file.objcPrefix;
262 if (objcPrefix && ![className hasPrefix:objcPrefix]) {
263 NSAssert(0,
264 @"Class didn't have correct prefix? (%@ - %@)",
265 className, objcPrefix);
266 return nil;
267 }
268 GPBDescriptor *parent = self.containingType;
269
270 NSString *name = nil;
271 if (parent) {
272 NSString *parentClassName = NSStringFromClass(parent.messageClass);
273 // The generator will add _Class to avoid reserved words, drop it.
274 NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
275 if (suffix) {
276 if (![parentClassName hasSuffix:suffix]) {
277 NSAssert(0,
278 @"ParentMessage class didn't have correct suffix? (%@ - %@)",
279 className, suffix);
280 return nil;
281 }
282 parentClassName =
283 [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
284 }
285 NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
286 if (![className hasPrefix:parentPrefix]) {
287 NSAssert(0,
288 @"Class didn't have the correct parent name prefix? (%@ - %@)",
289 parentPrefix, className);
290 return nil;
291 }
292 name = [className substringFromIndex:parentPrefix.length];
293 } else {
294 name = [className substringFromIndex:objcPrefix.length];
295 }
296
297 // The generator will add _Class to avoid reserved words, drop it.
298 NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
299 if (suffix) {
300 if (![name hasSuffix:suffix]) {
301 NSAssert(0,
302 @"Message class didn't have correct suffix? (%@ - %@)",
303 name, suffix);
304 return nil;
305 }
306 name = [name substringToIndex:(name.length - suffix.length)];
307 }
308
309 NSString *prefix = (parent != nil ? parent.fullName : file.package);
310 NSString *result;
311 if (prefix.length > 0) {
312 result = [NSString stringWithFormat:@"%@.%@", prefix, name];
313 } else {
314 result = name;
315 }
316 return result;
317}
318
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400319- (id)copyWithZone:(NSZone *)zone {
320#pragma unused(zone)
321 return [self retain];
322}
323
324- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
325 for (GPBFieldDescriptor *descriptor in fields_) {
326 if (GPBFieldNumber(descriptor) == fieldNumber) {
327 return descriptor;
328 }
329 }
330 return nil;
331}
332
333- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
334 for (GPBFieldDescriptor *descriptor in fields_) {
335 if ([descriptor.name isEqual:name]) {
336 return descriptor;
337 }
338 }
339 return nil;
340}
341
342- (GPBOneofDescriptor *)oneofWithName:(NSString *)name {
343 for (GPBOneofDescriptor *descriptor in oneofs_) {
344 if ([descriptor.name isEqual:name]) {
345 return descriptor;
346 }
347 }
348 return nil;
349}
350
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400351@end
352
353@implementation GPBFileDescriptor {
354 NSString *package_;
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400355 NSString *objcPrefix_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400356 GPBFileSyntax syntax_;
357}
358
359@synthesize package = package_;
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400360@synthesize objcPrefix = objcPrefix_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400361@synthesize syntax = syntax_;
362
363- (instancetype)initWithPackage:(NSString *)package
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400364 objcPrefix:(NSString *)objcPrefix
365 syntax:(GPBFileSyntax)syntax {
366 self = [super init];
367 if (self) {
368 package_ = [package copy];
369 objcPrefix_ = [objcPrefix copy];
370 syntax_ = syntax;
371 }
372 return self;
373}
374
375- (instancetype)initWithPackage:(NSString *)package
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400376 syntax:(GPBFileSyntax)syntax {
377 self = [super init];
378 if (self) {
379 package_ = [package copy];
380 syntax_ = syntax;
381 }
382 return self;
383}
384
Sergio Campamá71f4a9c2016-06-14 06:28:22 -0700385- (void)dealloc {
386 [package_ release];
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400387 [objcPrefix_ release];
Sergio Campamá71f4a9c2016-06-14 06:28:22 -0700388 [super dealloc];
389}
390
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400391@end
392
393@implementation GPBOneofDescriptor
394
395@synthesize fields = fields_;
396
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400397- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400398 self = [super init];
399 if (self) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400400 name_ = name;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400401 fields_ = [fields retain];
402 for (GPBFieldDescriptor *fieldDesc in fields) {
403 fieldDesc->containingOneof_ = self;
404 }
405
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400406 caseSel_ = SelFromStrings(NULL, name, "OneOfCase", NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400407 }
408 return self;
409}
410
411- (void)dealloc {
412 [fields_ release];
413 [super dealloc];
414}
415
416- (NSString *)name {
Sergio Campamá6933e2f2018-06-05 15:14:19 -0400417 return (NSString * _Nonnull)@(name_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400418}
419
420- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
421 for (GPBFieldDescriptor *descriptor in fields_) {
422 if (GPBFieldNumber(descriptor) == fieldNumber) {
423 return descriptor;
424 }
425 }
426 return nil;
427}
428
429- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
430 for (GPBFieldDescriptor *descriptor in fields_) {
431 if ([descriptor.name isEqual:name]) {
432 return descriptor;
433 }
434 }
435 return nil;
436}
437
438@end
439
440uint32_t GPBFieldTag(GPBFieldDescriptor *self) {
441 GPBMessageFieldDescription *description = self->description_;
442 GPBWireFormat format;
443 if ((description->flags & GPBFieldMapKeyMask) != 0) {
444 // Maps are repeated messages on the wire.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400445 format = GPBWireFormatForType(GPBDataTypeMessage, NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400446 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400447 format = GPBWireFormatForType(description->dataType,
448 ((description->flags & GPBFieldPacked) != 0));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400449 }
450 return GPBWireFormatMakeTag(description->number, format);
451}
452
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400453uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
454 GPBMessageFieldDescription *description = self->description_;
455 NSCAssert((description->flags & GPBFieldRepeated) != 0,
456 @"Only valid on repeated fields");
457 GPBWireFormat format =
458 GPBWireFormatForType(description->dataType,
459 ((description->flags & GPBFieldPacked) == 0));
460 return GPBWireFormatMakeTag(description->number, format);
461}
462
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400463@implementation GPBFieldDescriptor {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400464 GPBGenericValue defaultValue_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400465
466 // Message ivars
467 Class msgClass_;
468
469 // Enum ivars.
470 // If protos are generated with GenerateEnumDescriptors on then it will
471 // be a enumDescriptor, otherwise it will be a enumVerifier.
472 union {
473 GPBEnumDescriptor *enumDescriptor_;
474 GPBEnumValidationFunc enumVerifier_;
475 } enumHandling_;
476}
477
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400478@synthesize msgClass = msgClass_;
479@synthesize containingOneof = containingOneof_;
480
481- (instancetype)init {
482 // Throw an exception if people attempt to not use the designated initializer.
483 self = [super init];
484 if (self != nil) {
485 [self doesNotRecognizeSelector:_cmd];
486 self = nil;
487 }
488 return self;
489}
490
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400491- (instancetype)initWithFieldDescription:(void *)description
492 includesDefault:(BOOL)includesDefault
Dave MacLachlan74956e12019-12-17 17:32:09 -0800493 usesClassRefs:(BOOL)usesClassRefs
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400494 proto3OptionalKnown:(BOOL)proto3OptionalKnown
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400495 syntax:(GPBFileSyntax)syntax {
496 if ((self = [super init])) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400497 GPBMessageFieldDescription *coreDesc;
498 if (includesDefault) {
499 coreDesc = &(((GPBMessageFieldDescriptionWithDefault *)description)->core);
500 } else {
501 coreDesc = description;
502 }
503 description_ = coreDesc;
504 getSel_ = sel_getUid(coreDesc->name);
505 setSel_ = SelFromStrings("set", coreDesc->name, NULL, YES);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400506
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400507 GPBDataType dataType = coreDesc->dataType;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400508 BOOL isMessage = GPBDataTypeIsMessage(dataType);
509 BOOL isMapOrArray = GPBFieldIsMapOrArray(self);
510
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400511 // If proto3 optionals weren't know, compute the flag for the rest of the runtime.
512 if (!proto3OptionalKnown) {
513 // If it was...
514 // - proto3 syntax
515 // - not repeated/map
516 // - not in a oneof (negative has index)
517 // - not a message (the flag doesn't make sense for messages)
518 BOOL clearOnZero = ((syntax == GPBFileSyntaxProto3) &&
519 !isMapOrArray &&
520 (coreDesc->hasIndex >= 0) &&
521 !isMessage);
522 if (clearOnZero) {
523 coreDesc->flags |= GPBFieldClearHasIvarOnZero;
524 }
525 }
526
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400527 if (isMapOrArray) {
528 // map<>/repeated fields get a *Count property (inplace of a has*) to
529 // support checking if there are any entries without triggering
530 // autocreation.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400531 hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400532 } else {
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400533 // Know it is a single field; it gets has/setHas selectors if...
534 // - not in a oneof (negative has index)
535 // - not clearing on zero
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400536 if ((coreDesc->hasIndex >= 0) &&
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400537 ((coreDesc->flags & GPBFieldClearHasIvarOnZero) == 0)) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400538 hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO);
539 setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400540 }
541 }
542
543 // Extra type specific data.
544 if (isMessage) {
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400545 // Note: Only fetch the class here, can't send messages to it because
546 // that could cause cycles back to this class within +initialize if
547 // two messages have each other in fields (i.e. - they build a graph).
Dave MacLachlan74956e12019-12-17 17:32:09 -0800548 if (usesClassRefs) {
549 msgClass_ = coreDesc->dataTypeSpecific.clazz;
550 } else {
551 // Backwards compatibility for sources generated with older protoc.
552 const char *className = coreDesc->dataTypeSpecific.className;
553 msgClass_ = objc_getClass(className);
554 NSAssert(msgClass_, @"Class %s not defined", className);
555 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400556 } else if (dataType == GPBDataTypeEnum) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400557 if ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400558 enumHandling_.enumDescriptor_ =
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400559 coreDesc->dataTypeSpecific.enumDescFunc();
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400560 } else {
561 enumHandling_.enumVerifier_ =
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400562 coreDesc->dataTypeSpecific.enumVerifier;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400563 }
564 }
565
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400566 // Non map<>/repeated fields can have defaults in proto2 syntax.
567 if (!isMapOrArray && includesDefault) {
568 defaultValue_ = ((GPBMessageFieldDescriptionWithDefault *)description)->defaultValue;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400569 if (dataType == GPBDataTypeBytes) {
570 // Data stored as a length prefixed (network byte order) c-string in
571 // descriptor structure.
572 const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData;
573 if (bytes) {
Thomas Van Lentend570d482018-01-31 15:25:13 -0500574 uint32_t length;
575 memcpy(&length, bytes, sizeof(length));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400576 length = ntohl(length);
577 bytes += sizeof(length);
578 defaultValue_.valueData =
579 [[NSData alloc] initWithBytes:bytes length:length];
580 }
581 }
582 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400583 }
584 return self;
585}
586
587- (void)dealloc {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400588 if (description_->dataType == GPBDataTypeBytes &&
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400589 !(description_->flags & GPBFieldRepeated)) {
590 [defaultValue_.valueData release];
591 }
592 [super dealloc];
593}
594
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400595- (GPBDataType)dataType {
596 return description_->dataType;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400597}
598
599- (BOOL)hasDefaultValue {
600 return (description_->flags & GPBFieldHasDefaultValue) != 0;
601}
602
603- (uint32_t)number {
604 return description_->number;
605}
606
607- (NSString *)name {
Sergio Campamá6933e2f2018-06-05 15:14:19 -0400608 return (NSString * _Nonnull)@(description_->name);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400609}
610
611- (BOOL)isRequired {
612 return (description_->flags & GPBFieldRequired) != 0;
613}
614
615- (BOOL)isOptional {
616 return (description_->flags & GPBFieldOptional) != 0;
617}
618
619- (GPBFieldType)fieldType {
620 GPBFieldFlags flags = description_->flags;
621 if ((flags & GPBFieldRepeated) != 0) {
622 return GPBFieldTypeRepeated;
623 } else if ((flags & GPBFieldMapKeyMask) != 0) {
624 return GPBFieldTypeMap;
625 } else {
626 return GPBFieldTypeSingle;
627 }
628}
629
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400630- (GPBDataType)mapKeyDataType {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400631 switch (description_->flags & GPBFieldMapKeyMask) {
632 case GPBFieldMapKeyInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400633 return GPBDataTypeInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400634 case GPBFieldMapKeyInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400635 return GPBDataTypeInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400636 case GPBFieldMapKeyUInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400637 return GPBDataTypeUInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400638 case GPBFieldMapKeyUInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400639 return GPBDataTypeUInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400640 case GPBFieldMapKeySInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400641 return GPBDataTypeSInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400642 case GPBFieldMapKeySInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400643 return GPBDataTypeSInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400644 case GPBFieldMapKeyFixed32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400645 return GPBDataTypeFixed32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400646 case GPBFieldMapKeyFixed64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400647 return GPBDataTypeFixed64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400648 case GPBFieldMapKeySFixed32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400649 return GPBDataTypeSFixed32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400650 case GPBFieldMapKeySFixed64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400651 return GPBDataTypeSFixed64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400652 case GPBFieldMapKeyBool:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400653 return GPBDataTypeBool;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400654 case GPBFieldMapKeyString:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400655 return GPBDataTypeString;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400656
657 default:
658 NSAssert(0, @"Not a map type");
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400659 return GPBDataTypeInt32; // For lack of anything better.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400660 }
661}
662
663- (BOOL)isPackable {
664 return (description_->flags & GPBFieldPacked) != 0;
665}
666
667- (BOOL)isValidEnumValue:(int32_t)value {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400668 NSAssert(description_->dataType == GPBDataTypeEnum,
669 @"Field Must be of type GPBDataTypeEnum");
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400670 if (description_->flags & GPBFieldHasEnumDescriptor) {
671 return enumHandling_.enumDescriptor_.enumVerifier(value);
672 } else {
673 return enumHandling_.enumVerifier_(value);
674 }
675}
676
677- (GPBEnumDescriptor *)enumDescriptor {
678 if (description_->flags & GPBFieldHasEnumDescriptor) {
679 return enumHandling_.enumDescriptor_;
680 } else {
681 return nil;
682 }
683}
684
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400685- (GPBGenericValue)defaultValue {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400686 // Depends on the fact that defaultValue_ is initialized either to "0/nil" or
687 // to an actual defaultValue in our initializer.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400688 GPBGenericValue value = defaultValue_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400689
690 if (!(description_->flags & GPBFieldRepeated)) {
691 // We special handle data and strings. If they are nil, we replace them
692 // with empty string/empty data.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400693 GPBDataType type = description_->dataType;
694 if (type == GPBDataTypeBytes && value.valueData == nil) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400695 value.valueData = GPBEmptyNSData();
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400696 } else if (type == GPBDataTypeString && value.valueString == nil) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400697 value.valueString = @"";
698 }
699 }
700 return value;
701}
702
703- (NSString *)textFormatName {
704 if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) {
705 NSValue *extraInfoValue =
706 objc_getAssociatedObject(self, &kTextFormatExtraValueKey);
707 // Support can be left out at generation time.
708 if (!extraInfoValue) {
709 return nil;
710 }
711 const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue];
712 return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self),
713 self.name);
714 }
715
716 // The logic here has to match SetCommonFieldVariables() from
717 // objectivec_field.cc in the proto compiler.
718 NSString *name = self.name;
719 NSUInteger len = [name length];
720
721 // Remove the "_p" added to reserved names.
722 if ([name hasSuffix:@"_p"]) {
723 name = [name substringToIndex:(len - 2)];
724 len = [name length];
725 }
726
727 // Remove "Array" from the end for repeated fields.
728 if (((description_->flags & GPBFieldRepeated) != 0) &&
729 [name hasSuffix:@"Array"]) {
730 name = [name substringToIndex:(len - 5)];
731 len = [name length];
732 }
733
734 // Groups vs. other fields.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400735 if (description_->dataType == GPBDataTypeGroup) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400736 // Just capitalize the first letter.
737 unichar firstChar = [name characterAtIndex:0];
738 if (firstChar >= 'a' && firstChar <= 'z') {
739 NSString *firstCharString =
740 [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')];
741 NSString *result =
742 [name stringByReplacingCharactersInRange:NSMakeRange(0, 1)
743 withString:firstCharString];
744 return result;
745 }
746 return name;
747
748 } else {
749 // Undo the CamelCase.
750 NSMutableString *result = [NSMutableString stringWithCapacity:len];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400751 for (uint32_t i = 0; i < len; i++) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400752 unichar c = [name characterAtIndex:i];
753 if (c >= 'A' && c <= 'Z') {
754 if (i > 0) {
755 [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')];
756 } else {
757 [result appendFormat:@"%C", c];
758 }
759 } else {
760 [result appendFormat:@"%C", c];
761 }
762 }
763 return result;
764 }
765}
766
767@end
768
769@implementation GPBEnumDescriptor {
770 NSString *name_;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400771 // valueNames_ is a single c string with all of the value names appended
772 // together, each null terminated. -calcValueNameOffsets fills in
773 // nameOffsets_ with the offsets to allow quicker access to the individual
774 // names.
775 const char *valueNames_;
776 const int32_t *values_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400777 GPBEnumValidationFunc enumVerifier_;
778 const uint8_t *extraTextFormatInfo_;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400779 uint32_t *nameOffsets_;
780 uint32_t valueCount_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400781}
782
783@synthesize name = name_;
784@synthesize enumVerifier = enumVerifier_;
785
786+ (instancetype)
787 allocDescriptorForName:(NSString *)name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400788 valueNames:(const char *)valueNames
789 values:(const int32_t *)values
790 count:(uint32_t)valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400791 enumVerifier:(GPBEnumValidationFunc)enumVerifier {
792 GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400793 valueNames:valueNames
794 values:values
795 count:valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400796 enumVerifier:enumVerifier];
797 return descriptor;
798}
799
800+ (instancetype)
801 allocDescriptorForName:(NSString *)name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400802 valueNames:(const char *)valueNames
803 values:(const int32_t *)values
804 count:(uint32_t)valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400805 enumVerifier:(GPBEnumValidationFunc)enumVerifier
806 extraTextFormatInfo:(const char *)extraTextFormatInfo {
807 // Call the common case.
808 GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400809 valueNames:valueNames
810 values:values
811 count:valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400812 enumVerifier:enumVerifier];
813 // Set the extra info.
814 descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
815 return descriptor;
816}
817
818- (instancetype)initWithName:(NSString *)name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400819 valueNames:(const char *)valueNames
820 values:(const int32_t *)values
821 count:(uint32_t)valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400822 enumVerifier:(GPBEnumValidationFunc)enumVerifier {
823 if ((self = [super init])) {
824 name_ = [name copy];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400825 valueNames_ = valueNames;
826 values_ = values;
827 valueCount_ = valueCount;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400828 enumVerifier_ = enumVerifier;
829 }
830 return self;
831}
832
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400833- (void)dealloc {
834 [name_ release];
835 if (nameOffsets_) free(nameOffsets_);
836 [super dealloc];
837}
838
839- (void)calcValueNameOffsets {
840 @synchronized(self) {
841 if (nameOffsets_ != NULL) {
842 return;
843 }
844 uint32_t *offsets = malloc(valueCount_ * sizeof(uint32_t));
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400845 if (!offsets) return;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400846 const char *scan = valueNames_;
847 for (uint32_t i = 0; i < valueCount_; ++i) {
848 offsets[i] = (uint32_t)(scan - valueNames_);
849 while (*scan != '\0') ++scan;
850 ++scan; // Step over the null.
851 }
852 nameOffsets_ = offsets;
853 }
854}
855
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400856- (NSString *)enumNameForValue:(int32_t)number {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400857 for (uint32_t i = 0; i < valueCount_; ++i) {
858 if (values_[i] == number) {
leovitch28049022018-05-29 21:08:00 +0900859 return [self getEnumNameForIndex:i];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400860 }
861 }
862 return nil;
863}
864
865- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name {
866 // Must have the prefix.
867 NSUInteger prefixLen = name_.length + 1;
868 if ((name.length <= prefixLen) || ![name hasPrefix:name_] ||
869 ([name characterAtIndex:prefixLen - 1] != '_')) {
870 return NO;
871 }
872
873 // Skip over the prefix.
874 const char *nameAsCStr = [name UTF8String];
875 nameAsCStr += prefixLen;
876
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400877 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400878 if (nameOffsets_ == NULL) return NO;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400879
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400880 // Find it.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400881 for (uint32_t i = 0; i < valueCount_; ++i) {
882 const char *valueName = valueNames_ + nameOffsets_[i];
883 if (strcmp(nameAsCStr, valueName) == 0) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400884 if (outValue) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400885 *outValue = values_[i];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400886 }
887 return YES;
888 }
889 }
890 return NO;
891}
892
Thomas Van Lentenbe0d7f62016-06-27 14:24:59 -0400893- (BOOL)getValue:(int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName {
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -0700894 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400895 if (nameOffsets_ == NULL) return NO;
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -0700896
897 for (uint32_t i = 0; i < valueCount_; ++i) {
Thomas Van Lenten4c559312018-12-17 17:19:10 -0500898 NSString *valueTextFormatName = [self getEnumTextFormatNameForIndex:i];
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -0700899 if ([valueTextFormatName isEqual:textFormatName]) {
900 if (outValue) {
Thomas Van Lenten4c559312018-12-17 17:19:10 -0500901 *outValue = values_[i];
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -0700902 }
903 return YES;
904 }
905 }
906 return NO;
907}
908
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400909- (NSString *)textFormatNameForValue:(int32_t)number {
910 // Find the EnumValue descriptor and its index.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400911 BOOL foundIt = NO;
912 uint32_t valueDescriptorIndex;
913 for (valueDescriptorIndex = 0; valueDescriptorIndex < valueCount_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400914 ++valueDescriptorIndex) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400915 if (values_[valueDescriptorIndex] == number) {
916 foundIt = YES;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400917 break;
918 }
919 }
920
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400921 if (!foundIt) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400922 return nil;
923 }
leovitch28049022018-05-29 21:08:00 +0900924 return [self getEnumTextFormatNameForIndex:valueDescriptorIndex];
925}
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400926
leovitch28049022018-05-29 21:08:00 +0900927- (uint32_t)enumNameCount {
928 return valueCount_;
929}
930
931- (NSString *)getEnumNameForIndex:(uint32_t)index {
932 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400933 if (nameOffsets_ == NULL) return nil;
leovitch28049022018-05-29 21:08:00 +0900934
935 if (index >= valueCount_) {
936 return nil;
937 }
938 const char *valueName = valueNames_ + nameOffsets_[index];
939 NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
940 return fullName;
941}
942
943- (NSString *)getEnumTextFormatNameForIndex:(uint32_t)index {
944 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400945 if (nameOffsets_ == NULL) return nil;
leovitch28049022018-05-29 21:08:00 +0900946
947 if (index >= valueCount_) {
948 return nil;
949 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400950 NSString *result = nil;
951 // Naming adds an underscore between enum name and value name, skip that also.
leovitch28049022018-05-29 21:08:00 +0900952 const char *valueName = valueNames_ + nameOffsets_[index];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400953 NSString *shortName = @(valueName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400954
955 // See if it is in the map of special format handling.
956 if (extraTextFormatInfo_) {
957 result = GPBDecodeTextFormatName(extraTextFormatInfo_,
leovitch28049022018-05-29 21:08:00 +0900958 (int32_t)index, shortName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400959 }
960 // Logic here needs to match what objectivec_enum.cc does in the proto
961 // compiler.
962 if (result == nil) {
963 NSUInteger len = [shortName length];
964 NSMutableString *worker = [NSMutableString stringWithCapacity:len];
965 for (NSUInteger i = 0; i < len; i++) {
966 unichar c = [shortName characterAtIndex:i];
967 if (i > 0 && c >= 'A' && c <= 'Z') {
968 [worker appendString:@"_"];
969 }
970 [worker appendFormat:@"%c", toupper((char)c)];
971 }
972 result = worker;
973 }
974 return result;
975}
976
977@end
978
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400979@implementation GPBExtensionDescriptor {
980 GPBGenericValue defaultValue_;
981}
982
Dave MacLachlan74956e12019-12-17 17:32:09 -0800983- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc
984 usesClassRefs:(BOOL)usesClassRefs {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400985 if ((self = [super init])) {
Dave MacLachlan74956e12019-12-17 17:32:09 -0800986 description_ = desc;
987 if (!usesClassRefs) {
988 // Legacy without class ref support.
989 const char *className = description_->messageOrGroupClass.name;
990 if (className) {
991 Class clazz = objc_lookUpClass(className);
992 NSAssert(clazz != Nil, @"Class %s not defined", className);
993 description_->messageOrGroupClass.clazz = clazz;
994 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400995
Dave MacLachlan74956e12019-12-17 17:32:09 -0800996 const char *extendedClassName = description_->extendedClass.name;
997 if (extendedClassName) {
998 Class clazz = objc_lookUpClass(extendedClassName);
999 NSAssert(clazz, @"Class %s not defined", extendedClassName);
1000 description_->extendedClass.clazz = clazz;
1001 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001002 }
1003
1004 GPBDataType type = description_->dataType;
1005 if (type == GPBDataTypeBytes) {
1006 // Data stored as a length prefixed c-string in descriptor records.
1007 const uint8_t *bytes =
Dave MacLachlan74956e12019-12-17 17:32:09 -08001008 (const uint8_t *)description_->defaultValue.valueData;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001009 if (bytes) {
Thomas Van Lentend570d482018-01-31 15:25:13 -05001010 uint32_t length;
1011 memcpy(&length, bytes, sizeof(length));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001012 // The length is stored in network byte order.
1013 length = ntohl(length);
1014 bytes += sizeof(length);
1015 defaultValue_.valueData =
1016 [[NSData alloc] initWithBytes:bytes length:length];
1017 }
1018 } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) {
1019 // The default is looked up in -defaultValue instead since extensions
1020 // aren't common, we avoid the hit startup hit and it avoid initialization
1021 // order issues.
1022 } else {
Dave MacLachlan74956e12019-12-17 17:32:09 -08001023 defaultValue_ = description_->defaultValue;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001024 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001025 }
1026 return self;
1027}
1028
Dave MacLachlan74956e12019-12-17 17:32:09 -08001029- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc {
1030 return [self initWithExtensionDescription:desc usesClassRefs:NO];
1031}
1032
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001033- (void)dealloc {
1034 if ((description_->dataType == GPBDataTypeBytes) &&
1035 !GPBExtensionIsRepeated(description_)) {
1036 [defaultValue_.valueData release];
1037 }
1038 [super dealloc];
1039}
1040
1041- (instancetype)copyWithZone:(NSZone *)zone {
1042#pragma unused(zone)
1043 // Immutable.
1044 return [self retain];
1045}
1046
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001047- (NSString *)singletonName {
Sergio Campamá6933e2f2018-06-05 15:14:19 -04001048 return (NSString * _Nonnull)@(description_->singletonName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001049}
1050
1051- (const char *)singletonNameC {
1052 return description_->singletonName;
1053}
1054
1055- (uint32_t)fieldNumber {
1056 return description_->fieldNumber;
1057}
1058
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001059- (GPBDataType)dataType {
1060 return description_->dataType;
1061}
1062
1063- (GPBWireFormat)wireType {
1064 return GPBWireFormatForType(description_->dataType,
1065 GPBExtensionIsPacked(description_));
1066}
1067
1068- (GPBWireFormat)alternateWireType {
1069 NSAssert(GPBExtensionIsRepeated(description_),
1070 @"Only valid on repeated extensions");
1071 return GPBWireFormatForType(description_->dataType,
1072 !GPBExtensionIsPacked(description_));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001073}
1074
1075- (BOOL)isRepeated {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001076 return GPBExtensionIsRepeated(description_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001077}
1078
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001079- (BOOL)isPackable {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001080 return GPBExtensionIsPacked(description_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001081}
1082
1083- (Class)msgClass {
Dave MacLachlan74956e12019-12-17 17:32:09 -08001084 return description_->messageOrGroupClass.clazz;
1085}
1086
1087- (Class)containingMessageClass {
1088 return description_->extendedClass.clazz;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001089}
1090
1091- (GPBEnumDescriptor *)enumDescriptor {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001092 if (description_->dataType == GPBDataTypeEnum) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001093 GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc();
1094 return enumDescriptor;
1095 }
1096 return nil;
1097}
1098
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001099- (id)defaultValue {
1100 if (GPBExtensionIsRepeated(description_)) {
1101 return nil;
1102 }
1103
1104 switch (description_->dataType) {
1105 case GPBDataTypeBool:
1106 return @(defaultValue_.valueBool);
1107 case GPBDataTypeFloat:
1108 return @(defaultValue_.valueFloat);
1109 case GPBDataTypeDouble:
1110 return @(defaultValue_.valueDouble);
1111 case GPBDataTypeInt32:
1112 case GPBDataTypeSInt32:
1113 case GPBDataTypeEnum:
1114 case GPBDataTypeSFixed32:
1115 return @(defaultValue_.valueInt32);
1116 case GPBDataTypeInt64:
1117 case GPBDataTypeSInt64:
1118 case GPBDataTypeSFixed64:
1119 return @(defaultValue_.valueInt64);
1120 case GPBDataTypeUInt32:
1121 case GPBDataTypeFixed32:
1122 return @(defaultValue_.valueUInt32);
1123 case GPBDataTypeUInt64:
1124 case GPBDataTypeFixed64:
1125 return @(defaultValue_.valueUInt64);
1126 case GPBDataTypeBytes:
1127 // Like message fields, the default is zero length data.
1128 return (defaultValue_.valueData ? defaultValue_.valueData
1129 : GPBEmptyNSData());
1130 case GPBDataTypeString:
1131 // Like message fields, the default is zero length string.
1132 return (defaultValue_.valueString ? defaultValue_.valueString : @"");
1133 case GPBDataTypeGroup:
1134 case GPBDataTypeMessage:
1135 return nil;
1136 }
1137}
1138
1139- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other {
1140 int32_t selfNumber = description_->fieldNumber;
1141 int32_t otherNumber = other->description_->fieldNumber;
1142 if (selfNumber < otherNumber) {
1143 return NSOrderedAscending;
1144 } else if (selfNumber == otherNumber) {
1145 return NSOrderedSame;
1146 } else {
1147 return NSOrderedDescending;
1148 }
1149}
1150
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001151@end
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001152
1153#pragma clang diagnostic pop