blob: 316ce76a6c37a6459c6e6be19769a6b1d2486f2b [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
Thomas Van Lenten189f6322022-09-19 17:21:13 -040035#import "GPBMessage_PackagePrivate.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040036#import "GPBUtilities_PackagePrivate.h"
37#import "GPBWireFormat.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.
Thomas Van Lenten189f6322022-09-19 17:21:13 -040051static SEL SelFromStrings(const char *prefix, const char *middle, const char *suffix,
52 BOOL takesArg) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -040053 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;
Thomas Van Lenten189f6322022-09-19 17:21:13 -040059 size_t totalLen = prefixLen + middleLen + suffixLen + 1; // include space for null on end.
Thomas Van Lenten30650d82015-05-01 08:57:16 -040060 if (takesArg) {
61 totalLen += 1;
62 }
63 char buffer[totalLen];
64 if (prefix != NULL) {
65 memcpy(buffer, prefix, prefixLen);
66 memcpy(buffer + prefixLen, middle, middleLen);
67 buffer[prefixLen] = (char)toupper(buffer[prefixLen]);
68 } else {
69 memcpy(buffer, middle, middleLen);
70 }
71 if (suffix != NULL) {
72 memcpy(buffer + prefixLen + middleLen, suffix, suffixLen);
73 }
74 if (takesArg) {
75 buffer[totalLen - 2] = ':';
76 }
77 // Always null terminate it.
78 buffer[totalLen - 1] = 0;
79
80 SEL result = sel_getUid(buffer);
81 return result;
82}
83
Thomas Van Lenten189f6322022-09-19 17:21:13 -040084static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageFields)
Thomas Van Lenten30650d82015-05-01 08:57:16 -040085 __attribute__((ns_returns_retained));
86
Thomas Van Lenten189f6322022-09-19 17:21:13 -040087static NSArray *NewFieldsArrayForHasIndex(int hasIndex, NSArray *allMessageFields) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -040088 NSMutableArray *result = [[NSMutableArray alloc] init];
89 for (GPBFieldDescriptor *fieldDesc in allMessageFields) {
90 if (fieldDesc->description_->hasIndex == hasIndex) {
91 [result addObject:fieldDesc];
92 }
93 }
94 return result;
95}
96
97@implementation GPBDescriptor {
98 Class messageClass_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -040099 GPBFileDescriptor *file_;
100 BOOL wireFormat_;
101}
102
103@synthesize messageClass = messageClass_;
104@synthesize fields = fields_;
105@synthesize oneofs = oneofs_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400106@synthesize extensionRanges = extensionRanges_;
107@synthesize extensionRangesCount = extensionRangesCount_;
108@synthesize file = file_;
109@synthesize wireFormat = wireFormat_;
110
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400111+ (instancetype)allocDescriptorForClass:(Class)messageClass
112 rootClass:(Class)rootClass
113 file:(GPBFileDescriptor *)file
114 fields:(void *)fieldDescriptions
115 fieldCount:(uint32_t)fieldCount
116 storageSize:(uint32_t)storageSize
117 flags:(GPBDescriptorInitializationFlags)flags {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400118 // The rootClass is no longer used, but it is passed in to ensure it
119 // was started up during initialization also.
120 (void)rootClass;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400121 NSMutableArray *fields = nil;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400122 GPBFileSyntax syntax = file.syntax;
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400123 BOOL fieldsIncludeDefault = (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
124 BOOL usesClassRefs = (flags & GPBDescriptorInitializationFlag_UsesClassRefs) != 0;
125 BOOL proto3OptionalKnown = (flags & GPBDescriptorInitializationFlag_Proto3OptionalKnown) != 0;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400126
127 void *desc;
128 for (uint32_t i = 0; i < fieldCount; ++i) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400129 if (fields == nil) {
130 fields = [[NSMutableArray alloc] initWithCapacity:fieldCount];
131 }
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400132 // Need correctly typed pointer for array indexing below to work.
133 if (fieldsIncludeDefault) {
134 GPBMessageFieldDescriptionWithDefault *fieldDescWithDefault = fieldDescriptions;
135 desc = &(fieldDescWithDefault[i]);
136 } else {
137 GPBMessageFieldDescription *fieldDesc = fieldDescriptions;
138 desc = &(fieldDesc[i]);
139 }
140 GPBFieldDescriptor *fieldDescriptor =
141 [[GPBFieldDescriptor alloc] initWithFieldDescription:desc
142 includesDefault:fieldsIncludeDefault
Dave MacLachlan74956e12019-12-17 17:32:09 -0800143 usesClassRefs:usesClassRefs
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400144 proto3OptionalKnown:proto3OptionalKnown
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400145 syntax:syntax];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400146 [fields addObject:fieldDescriptor];
147 [fieldDescriptor release];
148 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400149
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400150 BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400151 GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
152 file:file
153 fields:fields
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400154 storageSize:storageSize
155 wireFormat:wireFormat];
156 [fields release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400157 return descriptor;
158}
159
160- (instancetype)initWithClass:(Class)messageClass
161 file:(GPBFileDescriptor *)file
162 fields:(NSArray *)fields
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400163 storageSize:(uint32_t)storageSize
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400164 wireFormat:(BOOL)wireFormat {
165 if ((self = [super init])) {
166 messageClass_ = messageClass;
167 file_ = file;
168 fields_ = [fields retain];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400169 storageSize_ = storageSize;
170 wireFormat_ = wireFormat;
171 }
172 return self;
173}
174
175- (void)dealloc {
176 [fields_ release];
177 [oneofs_ release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400178 [super dealloc];
179}
180
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400181- (void)setupOneofs:(const char **)oneofNames
182 count:(uint32_t)count
183 firstHasIndex:(int32_t)firstHasIndex {
184 NSCAssert(firstHasIndex < 0, @"Should always be <0");
185 NSMutableArray *oneofs = [[NSMutableArray alloc] initWithCapacity:count];
186 for (uint32_t i = 0, hasIndex = firstHasIndex; i < count; ++i, --hasIndex) {
187 const char *name = oneofNames[i];
188 NSArray *fieldsForOneof = NewFieldsArrayForHasIndex(hasIndex, fields_);
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400189 NSCAssert(fieldsForOneof.count > 0, @"No fields for this oneof? (%s:%d)", name, hasIndex);
190 GPBOneofDescriptor *oneofDescriptor = [[GPBOneofDescriptor alloc] initWithName:name
191 fields:fieldsForOneof];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400192 [oneofs addObject:oneofDescriptor];
193 [oneofDescriptor release];
194 [fieldsForOneof release];
195 }
196 oneofs_ = oneofs;
197}
198
199- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo {
200 // Extra info is a compile time option, so skip the work if not needed.
201 if (extraTextFormatInfo) {
202 NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo];
203 for (GPBFieldDescriptor *fieldDescriptor in fields_) {
204 if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400205 objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey, extraInfoValue,
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400206 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
207 }
208 }
209 }
210}
211
212- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count {
213 extensionRanges_ = ranges;
214 extensionRangesCount_ = count;
215}
216
Dave MacLachlan74956e12019-12-17 17:32:09 -0800217- (void)setupContainingMessageClass:(Class)messageClass {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400218 objc_setAssociatedObject(self, &kParentClassValueKey, messageClass, OBJC_ASSOCIATION_ASSIGN);
Dave MacLachlan74956e12019-12-17 17:32:09 -0800219}
220
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400221- (void)setupContainingMessageClassName:(const char *)msgClassName {
222 // Note: Only fetch the class here, can't send messages to it because
223 // that could cause cycles back to this class within +initialize if
224 // two messages have each other in fields (i.e. - they build a graph).
Dave MacLachlan74956e12019-12-17 17:32:09 -0800225 Class clazz = objc_getClass(msgClassName);
226 NSAssert(clazz, @"Class %s not defined", msgClassName);
227 [self setupContainingMessageClass:clazz];
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400228}
229
230- (void)setupMessageClassNameSuffix:(NSString *)suffix {
231 if (suffix.length) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400232 objc_setAssociatedObject(self, &kClassNameSuffixKey, suffix, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400233 }
234}
235
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400236- (NSString *)name {
237 return NSStringFromClass(messageClass_);
238}
239
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400240- (GPBDescriptor *)containingType {
Dave MacLachlan74956e12019-12-17 17:32:09 -0800241 Class parentClass = objc_getAssociatedObject(self, &kParentClassValueKey);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400242 return [parentClass descriptor];
243}
244
245- (NSString *)fullName {
246 NSString *className = NSStringFromClass(self.messageClass);
247 GPBFileDescriptor *file = self.file;
248 NSString *objcPrefix = file.objcPrefix;
249 if (objcPrefix && ![className hasPrefix:objcPrefix]) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400250 NSAssert(0, @"Class didn't have correct prefix? (%@ - %@)", className, objcPrefix);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400251 return nil;
252 }
253 GPBDescriptor *parent = self.containingType;
254
255 NSString *name = nil;
256 if (parent) {
257 NSString *parentClassName = NSStringFromClass(parent.messageClass);
258 // The generator will add _Class to avoid reserved words, drop it.
259 NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
260 if (suffix) {
261 if (![parentClassName hasSuffix:suffix]) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400262 NSAssert(0, @"ParentMessage class didn't have correct suffix? (%@ - %@)", className,
263 suffix);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400264 return nil;
265 }
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400266 parentClassName = [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400267 }
268 NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
269 if (![className hasPrefix:parentPrefix]) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400270 NSAssert(0, @"Class didn't have the correct parent name prefix? (%@ - %@)", parentPrefix,
271 className);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400272 return nil;
273 }
274 name = [className substringFromIndex:parentPrefix.length];
275 } else {
276 name = [className substringFromIndex:objcPrefix.length];
277 }
278
279 // The generator will add _Class to avoid reserved words, drop it.
280 NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
281 if (suffix) {
282 if (![name hasSuffix:suffix]) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400283 NSAssert(0, @"Message class didn't have correct suffix? (%@ - %@)", name, suffix);
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400284 return nil;
285 }
286 name = [name substringToIndex:(name.length - suffix.length)];
287 }
288
289 NSString *prefix = (parent != nil ? parent.fullName : file.package);
290 NSString *result;
291 if (prefix.length > 0) {
292 result = [NSString stringWithFormat:@"%@.%@", prefix, name];
293 } else {
294 result = name;
295 }
296 return result;
297}
298
Thomas Van Lenten2fb33b82022-09-20 09:14:32 -0400299- (id)copyWithZone:(__unused NSZone *)zone {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400300 return [self retain];
301}
302
303- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
304 for (GPBFieldDescriptor *descriptor in fields_) {
305 if (GPBFieldNumber(descriptor) == fieldNumber) {
306 return descriptor;
307 }
308 }
309 return nil;
310}
311
312- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
313 for (GPBFieldDescriptor *descriptor in fields_) {
314 if ([descriptor.name isEqual:name]) {
315 return descriptor;
316 }
317 }
318 return nil;
319}
320
321- (GPBOneofDescriptor *)oneofWithName:(NSString *)name {
322 for (GPBOneofDescriptor *descriptor in oneofs_) {
323 if ([descriptor.name isEqual:name]) {
324 return descriptor;
325 }
326 }
327 return nil;
328}
329
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400330@end
331
332@implementation GPBFileDescriptor {
333 NSString *package_;
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400334 NSString *objcPrefix_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400335 GPBFileSyntax syntax_;
336}
337
338@synthesize package = package_;
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400339@synthesize objcPrefix = objcPrefix_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400340@synthesize syntax = syntax_;
341
342- (instancetype)initWithPackage:(NSString *)package
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400343 objcPrefix:(NSString *)objcPrefix
344 syntax:(GPBFileSyntax)syntax {
345 self = [super init];
346 if (self) {
347 package_ = [package copy];
348 objcPrefix_ = [objcPrefix copy];
349 syntax_ = syntax;
350 }
351 return self;
352}
353
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400354- (instancetype)initWithPackage:(NSString *)package syntax:(GPBFileSyntax)syntax {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400355 self = [super init];
356 if (self) {
357 package_ = [package copy];
358 syntax_ = syntax;
359 }
360 return self;
361}
362
Sergio Campamá71f4a9c2016-06-14 06:28:22 -0700363- (void)dealloc {
364 [package_ release];
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400365 [objcPrefix_ release];
Sergio Campamá71f4a9c2016-06-14 06:28:22 -0700366 [super dealloc];
367}
368
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400369@end
370
371@implementation GPBOneofDescriptor
372
373@synthesize fields = fields_;
374
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400375- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400376 self = [super init];
377 if (self) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400378 name_ = name;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400379 fields_ = [fields retain];
380 for (GPBFieldDescriptor *fieldDesc in fields) {
381 fieldDesc->containingOneof_ = self;
382 }
383
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400384 caseSel_ = SelFromStrings(NULL, name, "OneOfCase", NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400385 }
386 return self;
387}
388
389- (void)dealloc {
390 [fields_ release];
391 [super dealloc];
392}
393
394- (NSString *)name {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400395 return (NSString *_Nonnull)@(name_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400396}
397
398- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
399 for (GPBFieldDescriptor *descriptor in fields_) {
400 if (GPBFieldNumber(descriptor) == fieldNumber) {
401 return descriptor;
402 }
403 }
404 return nil;
405}
406
407- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
408 for (GPBFieldDescriptor *descriptor in fields_) {
409 if ([descriptor.name isEqual:name]) {
410 return descriptor;
411 }
412 }
413 return nil;
414}
415
416@end
417
418uint32_t GPBFieldTag(GPBFieldDescriptor *self) {
419 GPBMessageFieldDescription *description = self->description_;
420 GPBWireFormat format;
421 if ((description->flags & GPBFieldMapKeyMask) != 0) {
422 // Maps are repeated messages on the wire.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400423 format = GPBWireFormatForType(GPBDataTypeMessage, NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400424 } else {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400425 format =
426 GPBWireFormatForType(description->dataType, ((description->flags & GPBFieldPacked) != 0));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400427 }
428 return GPBWireFormatMakeTag(description->number, format);
429}
430
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400431uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
432 GPBMessageFieldDescription *description = self->description_;
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400433 NSCAssert((description->flags & GPBFieldRepeated) != 0, @"Only valid on repeated fields");
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400434 GPBWireFormat format =
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400435 GPBWireFormatForType(description->dataType, ((description->flags & GPBFieldPacked) == 0));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400436 return GPBWireFormatMakeTag(description->number, format);
437}
438
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400439@implementation GPBFieldDescriptor {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400440 GPBGenericValue defaultValue_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400441
442 // Message ivars
443 Class msgClass_;
444
445 // Enum ivars.
446 // If protos are generated with GenerateEnumDescriptors on then it will
447 // be a enumDescriptor, otherwise it will be a enumVerifier.
448 union {
449 GPBEnumDescriptor *enumDescriptor_;
450 GPBEnumValidationFunc enumVerifier_;
451 } enumHandling_;
452}
453
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400454@synthesize msgClass = msgClass_;
455@synthesize containingOneof = containingOneof_;
456
457- (instancetype)init {
458 // Throw an exception if people attempt to not use the designated initializer.
459 self = [super init];
460 if (self != nil) {
461 [self doesNotRecognizeSelector:_cmd];
462 self = nil;
463 }
464 return self;
465}
466
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400467- (instancetype)initWithFieldDescription:(void *)description
468 includesDefault:(BOOL)includesDefault
Dave MacLachlan74956e12019-12-17 17:32:09 -0800469 usesClassRefs:(BOOL)usesClassRefs
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400470 proto3OptionalKnown:(BOOL)proto3OptionalKnown
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400471 syntax:(GPBFileSyntax)syntax {
472 if ((self = [super init])) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400473 GPBMessageFieldDescription *coreDesc;
474 if (includesDefault) {
475 coreDesc = &(((GPBMessageFieldDescriptionWithDefault *)description)->core);
476 } else {
477 coreDesc = description;
478 }
479 description_ = coreDesc;
480 getSel_ = sel_getUid(coreDesc->name);
481 setSel_ = SelFromStrings("set", coreDesc->name, NULL, YES);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400482
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400483 GPBDataType dataType = coreDesc->dataType;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400484 BOOL isMessage = GPBDataTypeIsMessage(dataType);
485 BOOL isMapOrArray = GPBFieldIsMapOrArray(self);
486
Thomas Van Lentendddeed22020-04-24 13:40:59 -0400487 // If proto3 optionals weren't known (i.e. generated code from an
488 // older version), compute the flag for the rest of the runtime.
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400489 if (!proto3OptionalKnown) {
490 // If it was...
491 // - proto3 syntax
492 // - not repeated/map
493 // - not in a oneof (negative has index)
494 // - not a message (the flag doesn't make sense for messages)
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400495 BOOL clearOnZero = ((syntax == GPBFileSyntaxProto3) && !isMapOrArray &&
496 (coreDesc->hasIndex >= 0) && !isMessage);
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400497 if (clearOnZero) {
498 coreDesc->flags |= GPBFieldClearHasIvarOnZero;
499 }
500 }
501
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400502 if (isMapOrArray) {
503 // map<>/repeated fields get a *Count property (inplace of a has*) to
504 // support checking if there are any entries without triggering
505 // autocreation.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400506 hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400507 } else {
Thomas Van Lentendddeed22020-04-24 13:40:59 -0400508 // It is a single field; it gets has/setHas selectors if...
Thomas Van Lenten8d224b42020-04-08 11:34:37 -0400509 // - not in a oneof (negative has index)
510 // - not clearing on zero
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400511 if ((coreDesc->hasIndex >= 0) && ((coreDesc->flags & GPBFieldClearHasIvarOnZero) == 0)) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400512 hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO);
513 setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400514 }
515 }
516
517 // Extra type specific data.
518 if (isMessage) {
Thomas Van Lenten337ec302016-08-16 11:26:49 -0400519 // Note: Only fetch the class here, can't send messages to it because
520 // that could cause cycles back to this class within +initialize if
521 // two messages have each other in fields (i.e. - they build a graph).
Dave MacLachlan74956e12019-12-17 17:32:09 -0800522 if (usesClassRefs) {
523 msgClass_ = coreDesc->dataTypeSpecific.clazz;
524 } else {
525 // Backwards compatibility for sources generated with older protoc.
526 const char *className = coreDesc->dataTypeSpecific.className;
527 msgClass_ = objc_getClass(className);
528 NSAssert(msgClass_, @"Class %s not defined", className);
529 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400530 } else if (dataType == GPBDataTypeEnum) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400531 if ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400532 enumHandling_.enumDescriptor_ = coreDesc->dataTypeSpecific.enumDescFunc();
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400533 } else {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400534 enumHandling_.enumVerifier_ = coreDesc->dataTypeSpecific.enumVerifier;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400535 }
536 }
537
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400538 // Non map<>/repeated fields can have defaults in proto2 syntax.
539 if (!isMapOrArray && includesDefault) {
540 defaultValue_ = ((GPBMessageFieldDescriptionWithDefault *)description)->defaultValue;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400541 if (dataType == GPBDataTypeBytes) {
542 // Data stored as a length prefixed (network byte order) c-string in
543 // descriptor structure.
544 const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData;
545 if (bytes) {
Thomas Van Lentend570d482018-01-31 15:25:13 -0500546 uint32_t length;
547 memcpy(&length, bytes, sizeof(length));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400548 length = ntohl(length);
549 bytes += sizeof(length);
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400550 defaultValue_.valueData = [[NSData alloc] initWithBytes:bytes length:length];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400551 }
552 }
553 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400554 }
555 return self;
556}
557
558- (void)dealloc {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400559 if (description_->dataType == GPBDataTypeBytes && !(description_->flags & GPBFieldRepeated)) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400560 [defaultValue_.valueData release];
561 }
562 [super dealloc];
563}
564
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400565- (GPBDataType)dataType {
566 return description_->dataType;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400567}
568
569- (BOOL)hasDefaultValue {
570 return (description_->flags & GPBFieldHasDefaultValue) != 0;
571}
572
573- (uint32_t)number {
574 return description_->number;
575}
576
577- (NSString *)name {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400578 return (NSString *_Nonnull)@(description_->name);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400579}
580
581- (BOOL)isRequired {
582 return (description_->flags & GPBFieldRequired) != 0;
583}
584
585- (BOOL)isOptional {
586 return (description_->flags & GPBFieldOptional) != 0;
587}
588
589- (GPBFieldType)fieldType {
590 GPBFieldFlags flags = description_->flags;
591 if ((flags & GPBFieldRepeated) != 0) {
592 return GPBFieldTypeRepeated;
593 } else if ((flags & GPBFieldMapKeyMask) != 0) {
594 return GPBFieldTypeMap;
595 } else {
596 return GPBFieldTypeSingle;
597 }
598}
599
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400600- (GPBDataType)mapKeyDataType {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400601 switch (description_->flags & GPBFieldMapKeyMask) {
602 case GPBFieldMapKeyInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400603 return GPBDataTypeInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400604 case GPBFieldMapKeyInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400605 return GPBDataTypeInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400606 case GPBFieldMapKeyUInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400607 return GPBDataTypeUInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400608 case GPBFieldMapKeyUInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400609 return GPBDataTypeUInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400610 case GPBFieldMapKeySInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400611 return GPBDataTypeSInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400612 case GPBFieldMapKeySInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400613 return GPBDataTypeSInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400614 case GPBFieldMapKeyFixed32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400615 return GPBDataTypeFixed32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400616 case GPBFieldMapKeyFixed64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400617 return GPBDataTypeFixed64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400618 case GPBFieldMapKeySFixed32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400619 return GPBDataTypeSFixed32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400620 case GPBFieldMapKeySFixed64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400621 return GPBDataTypeSFixed64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400622 case GPBFieldMapKeyBool:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400623 return GPBDataTypeBool;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400624 case GPBFieldMapKeyString:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400625 return GPBDataTypeString;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400626
627 default:
628 NSAssert(0, @"Not a map type");
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400629 return GPBDataTypeInt32; // For lack of anything better.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400630 }
631}
632
633- (BOOL)isPackable {
634 return (description_->flags & GPBFieldPacked) != 0;
635}
636
637- (BOOL)isValidEnumValue:(int32_t)value {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400638 NSAssert(description_->dataType == GPBDataTypeEnum, @"Field Must be of type GPBDataTypeEnum");
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400639 if (description_->flags & GPBFieldHasEnumDescriptor) {
640 return enumHandling_.enumDescriptor_.enumVerifier(value);
641 } else {
642 return enumHandling_.enumVerifier_(value);
643 }
644}
645
646- (GPBEnumDescriptor *)enumDescriptor {
647 if (description_->flags & GPBFieldHasEnumDescriptor) {
648 return enumHandling_.enumDescriptor_;
649 } else {
650 return nil;
651 }
652}
653
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400654- (GPBGenericValue)defaultValue {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400655 // Depends on the fact that defaultValue_ is initialized either to "0/nil" or
656 // to an actual defaultValue in our initializer.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400657 GPBGenericValue value = defaultValue_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400658
659 if (!(description_->flags & GPBFieldRepeated)) {
660 // We special handle data and strings. If they are nil, we replace them
661 // with empty string/empty data.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400662 GPBDataType type = description_->dataType;
663 if (type == GPBDataTypeBytes && value.valueData == nil) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400664 value.valueData = GPBEmptyNSData();
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400665 } else if (type == GPBDataTypeString && value.valueString == nil) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400666 value.valueString = @"";
667 }
668 }
669 return value;
670}
671
672- (NSString *)textFormatName {
673 if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400674 NSValue *extraInfoValue = objc_getAssociatedObject(self, &kTextFormatExtraValueKey);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400675 // Support can be left out at generation time.
676 if (!extraInfoValue) {
677 return nil;
678 }
679 const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue];
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400680 return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self), self.name);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400681 }
682
683 // The logic here has to match SetCommonFieldVariables() from
Thomas Van Lenten53d8b032022-10-04 10:59:48 -0400684 // objectivec/field.cc in the proto compiler.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400685 NSString *name = self.name;
686 NSUInteger len = [name length];
687
688 // Remove the "_p" added to reserved names.
689 if ([name hasSuffix:@"_p"]) {
690 name = [name substringToIndex:(len - 2)];
691 len = [name length];
692 }
693
694 // Remove "Array" from the end for repeated fields.
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400695 if (((description_->flags & GPBFieldRepeated) != 0) && [name hasSuffix:@"Array"]) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400696 name = [name substringToIndex:(len - 5)];
697 len = [name length];
698 }
699
700 // Groups vs. other fields.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400701 if (description_->dataType == GPBDataTypeGroup) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400702 // Just capitalize the first letter.
703 unichar firstChar = [name characterAtIndex:0];
704 if (firstChar >= 'a' && firstChar <= 'z') {
705 NSString *firstCharString =
706 [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')];
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400707 NSString *result = [name stringByReplacingCharactersInRange:NSMakeRange(0, 1)
708 withString:firstCharString];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400709 return result;
710 }
711 return name;
712
713 } else {
714 // Undo the CamelCase.
715 NSMutableString *result = [NSMutableString stringWithCapacity:len];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400716 for (uint32_t i = 0; i < len; i++) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400717 unichar c = [name characterAtIndex:i];
718 if (c >= 'A' && c <= 'Z') {
719 if (i > 0) {
720 [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')];
721 } else {
722 [result appendFormat:@"%C", c];
723 }
724 } else {
725 [result appendFormat:@"%C", c];
726 }
727 }
728 return result;
729 }
730}
731
732@end
733
734@implementation GPBEnumDescriptor {
735 NSString *name_;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400736 // valueNames_ is a single c string with all of the value names appended
737 // together, each null terminated. -calcValueNameOffsets fills in
738 // nameOffsets_ with the offsets to allow quicker access to the individual
739 // names.
740 const char *valueNames_;
741 const int32_t *values_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400742 GPBEnumValidationFunc enumVerifier_;
743 const uint8_t *extraTextFormatInfo_;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400744 uint32_t *nameOffsets_;
745 uint32_t valueCount_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400746}
747
748@synthesize name = name_;
749@synthesize enumVerifier = enumVerifier_;
750
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400751+ (instancetype)allocDescriptorForName:(NSString *)name
752 valueNames:(const char *)valueNames
753 values:(const int32_t *)values
754 count:(uint32_t)valueCount
755 enumVerifier:(GPBEnumValidationFunc)enumVerifier {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400756 GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400757 valueNames:valueNames
758 values:values
759 count:valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400760 enumVerifier:enumVerifier];
761 return descriptor;
762}
763
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400764+ (instancetype)allocDescriptorForName:(NSString *)name
765 valueNames:(const char *)valueNames
766 values:(const int32_t *)values
767 count:(uint32_t)valueCount
768 enumVerifier:(GPBEnumValidationFunc)enumVerifier
769 extraTextFormatInfo:(const char *)extraTextFormatInfo {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400770 // Call the common case.
771 GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400772 valueNames:valueNames
773 values:values
774 count:valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400775 enumVerifier:enumVerifier];
776 // Set the extra info.
777 descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
778 return descriptor;
779}
780
781- (instancetype)initWithName:(NSString *)name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400782 valueNames:(const char *)valueNames
783 values:(const int32_t *)values
784 count:(uint32_t)valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400785 enumVerifier:(GPBEnumValidationFunc)enumVerifier {
786 if ((self = [super init])) {
787 name_ = [name copy];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400788 valueNames_ = valueNames;
789 values_ = values;
790 valueCount_ = valueCount;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400791 enumVerifier_ = enumVerifier;
792 }
793 return self;
794}
795
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400796- (void)dealloc {
797 [name_ release];
798 if (nameOffsets_) free(nameOffsets_);
799 [super dealloc];
800}
801
802- (void)calcValueNameOffsets {
803 @synchronized(self) {
804 if (nameOffsets_ != NULL) {
805 return;
806 }
807 uint32_t *offsets = malloc(valueCount_ * sizeof(uint32_t));
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400808 if (!offsets) return;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400809 const char *scan = valueNames_;
810 for (uint32_t i = 0; i < valueCount_; ++i) {
811 offsets[i] = (uint32_t)(scan - valueNames_);
812 while (*scan != '\0') ++scan;
813 ++scan; // Step over the null.
814 }
815 nameOffsets_ = offsets;
816 }
817}
818
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400819- (NSString *)enumNameForValue:(int32_t)number {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400820 for (uint32_t i = 0; i < valueCount_; ++i) {
821 if (values_[i] == number) {
leovitch28049022018-05-29 21:08:00 +0900822 return [self getEnumNameForIndex:i];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400823 }
824 }
825 return nil;
826}
827
828- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name {
829 // Must have the prefix.
830 NSUInteger prefixLen = name_.length + 1;
831 if ((name.length <= prefixLen) || ![name hasPrefix:name_] ||
832 ([name characterAtIndex:prefixLen - 1] != '_')) {
833 return NO;
834 }
835
836 // Skip over the prefix.
837 const char *nameAsCStr = [name UTF8String];
838 nameAsCStr += prefixLen;
839
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400840 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400841 if (nameOffsets_ == NULL) return NO;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400842
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400843 // Find it.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400844 for (uint32_t i = 0; i < valueCount_; ++i) {
845 const char *valueName = valueNames_ + nameOffsets_[i];
846 if (strcmp(nameAsCStr, valueName) == 0) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400847 if (outValue) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400848 *outValue = values_[i];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400849 }
850 return YES;
851 }
852 }
853 return NO;
854}
855
Thomas Van Lentenbe0d7f62016-06-27 14:24:59 -0400856- (BOOL)getValue:(int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400857 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
858 if (nameOffsets_ == NULL) return NO;
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -0700859
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400860 for (uint32_t i = 0; i < valueCount_; ++i) {
861 NSString *valueTextFormatName = [self getEnumTextFormatNameForIndex:i];
862 if ([valueTextFormatName isEqual:textFormatName]) {
863 if (outValue) {
864 *outValue = values_[i];
865 }
866 return YES;
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -0700867 }
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400868 }
869 return NO;
Dimitris Koutsogiorgas37ca94f2016-06-24 17:40:29 -0700870}
871
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400872- (NSString *)textFormatNameForValue:(int32_t)number {
873 // Find the EnumValue descriptor and its index.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400874 BOOL foundIt = NO;
875 uint32_t valueDescriptorIndex;
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400876 for (valueDescriptorIndex = 0; valueDescriptorIndex < valueCount_; ++valueDescriptorIndex) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400877 if (values_[valueDescriptorIndex] == number) {
878 foundIt = YES;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400879 break;
880 }
881 }
882
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400883 if (!foundIt) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400884 return nil;
885 }
leovitch28049022018-05-29 21:08:00 +0900886 return [self getEnumTextFormatNameForIndex:valueDescriptorIndex];
887}
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400888
leovitch28049022018-05-29 21:08:00 +0900889- (uint32_t)enumNameCount {
890 return valueCount_;
891}
892
893- (NSString *)getEnumNameForIndex:(uint32_t)index {
894 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400895 if (nameOffsets_ == NULL) return nil;
leovitch28049022018-05-29 21:08:00 +0900896
897 if (index >= valueCount_) {
898 return nil;
899 }
900 const char *valueName = valueNames_ + nameOffsets_[index];
901 NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
902 return fullName;
903}
904
905- (NSString *)getEnumTextFormatNameForIndex:(uint32_t)index {
906 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
Parveen Bhatia29f27bf2018-10-19 15:37:00 -0400907 if (nameOffsets_ == NULL) return nil;
leovitch28049022018-05-29 21:08:00 +0900908
909 if (index >= valueCount_) {
910 return nil;
911 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400912 NSString *result = nil;
913 // Naming adds an underscore between enum name and value name, skip that also.
leovitch28049022018-05-29 21:08:00 +0900914 const char *valueName = valueNames_ + nameOffsets_[index];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400915 NSString *shortName = @(valueName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400916
917 // See if it is in the map of special format handling.
918 if (extraTextFormatInfo_) {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400919 result = GPBDecodeTextFormatName(extraTextFormatInfo_, (int32_t)index, shortName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400920 }
Thomas Van Lenten53d8b032022-10-04 10:59:48 -0400921 // Logic here needs to match what objectivec/enum.cc does in the proto
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400922 // compiler.
923 if (result == nil) {
924 NSUInteger len = [shortName length];
925 NSMutableString *worker = [NSMutableString stringWithCapacity:len];
926 for (NSUInteger i = 0; i < len; i++) {
927 unichar c = [shortName characterAtIndex:i];
928 if (i > 0 && c >= 'A' && c <= 'Z') {
929 [worker appendString:@"_"];
930 }
931 [worker appendFormat:@"%c", toupper((char)c)];
932 }
933 result = worker;
934 }
935 return result;
936}
937
938@end
939
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400940@implementation GPBExtensionDescriptor {
941 GPBGenericValue defaultValue_;
942}
943
Dave MacLachlan74956e12019-12-17 17:32:09 -0800944- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc
945 usesClassRefs:(BOOL)usesClassRefs {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400946 if ((self = [super init])) {
Dave MacLachlan74956e12019-12-17 17:32:09 -0800947 description_ = desc;
948 if (!usesClassRefs) {
949 // Legacy without class ref support.
950 const char *className = description_->messageOrGroupClass.name;
951 if (className) {
952 Class clazz = objc_lookUpClass(className);
953 NSAssert(clazz != Nil, @"Class %s not defined", className);
954 description_->messageOrGroupClass.clazz = clazz;
955 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400956
Dave MacLachlan74956e12019-12-17 17:32:09 -0800957 const char *extendedClassName = description_->extendedClass.name;
958 if (extendedClassName) {
959 Class clazz = objc_lookUpClass(extendedClassName);
960 NSAssert(clazz, @"Class %s not defined", extendedClassName);
961 description_->extendedClass.clazz = clazz;
962 }
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400963 }
964
965 GPBDataType type = description_->dataType;
966 if (type == GPBDataTypeBytes) {
967 // Data stored as a length prefixed c-string in descriptor records.
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400968 const uint8_t *bytes = (const uint8_t *)description_->defaultValue.valueData;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400969 if (bytes) {
Thomas Van Lentend570d482018-01-31 15:25:13 -0500970 uint32_t length;
971 memcpy(&length, bytes, sizeof(length));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400972 // The length is stored in network byte order.
973 length = ntohl(length);
974 bytes += sizeof(length);
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400975 defaultValue_.valueData = [[NSData alloc] initWithBytes:bytes length:length];
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400976 }
977 } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) {
978 // The default is looked up in -defaultValue instead since extensions
979 // aren't common, we avoid the hit startup hit and it avoid initialization
980 // order issues.
981 } else {
Dave MacLachlan74956e12019-12-17 17:32:09 -0800982 defaultValue_ = description_->defaultValue;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400983 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400984 }
985 return self;
986}
987
Dave MacLachlan74956e12019-12-17 17:32:09 -0800988- (instancetype)initWithExtensionDescription:(GPBExtensionDescription *)desc {
989 return [self initWithExtensionDescription:desc usesClassRefs:NO];
990}
991
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400992- (void)dealloc {
Thomas Van Lenten189f6322022-09-19 17:21:13 -0400993 if ((description_->dataType == GPBDataTypeBytes) && !GPBExtensionIsRepeated(description_)) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400994 [defaultValue_.valueData release];
995 }
996 [super dealloc];
997}
998
Thomas Van Lenten2fb33b82022-09-20 09:14:32 -0400999- (instancetype)copyWithZone:(__unused NSZone *)zone {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001000 // Immutable.
1001 return [self retain];
1002}
1003
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001004- (NSString *)singletonName {
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001005 return (NSString *_Nonnull)@(description_->singletonName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001006}
1007
1008- (const char *)singletonNameC {
1009 return description_->singletonName;
1010}
1011
1012- (uint32_t)fieldNumber {
1013 return description_->fieldNumber;
1014}
1015
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001016- (GPBDataType)dataType {
1017 return description_->dataType;
1018}
1019
1020- (GPBWireFormat)wireType {
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001021 return GPBWireFormatForType(description_->dataType, GPBExtensionIsPacked(description_));
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001022}
1023
1024- (GPBWireFormat)alternateWireType {
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001025 NSAssert(GPBExtensionIsRepeated(description_), @"Only valid on repeated extensions");
1026 return GPBWireFormatForType(description_->dataType, !GPBExtensionIsPacked(description_));
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001027}
1028
1029- (BOOL)isRepeated {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001030 return GPBExtensionIsRepeated(description_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001031}
1032
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001033- (BOOL)isPackable {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001034 return GPBExtensionIsPacked(description_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001035}
1036
1037- (Class)msgClass {
Dave MacLachlan74956e12019-12-17 17:32:09 -08001038 return description_->messageOrGroupClass.clazz;
1039}
1040
1041- (Class)containingMessageClass {
1042 return description_->extendedClass.clazz;
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001043}
1044
1045- (GPBEnumDescriptor *)enumDescriptor {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001046 if (description_->dataType == GPBDataTypeEnum) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001047 GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc();
1048 return enumDescriptor;
1049 }
1050 return nil;
1051}
1052
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001053- (id)defaultValue {
1054 if (GPBExtensionIsRepeated(description_)) {
1055 return nil;
1056 }
1057
1058 switch (description_->dataType) {
1059 case GPBDataTypeBool:
1060 return @(defaultValue_.valueBool);
1061 case GPBDataTypeFloat:
1062 return @(defaultValue_.valueFloat);
1063 case GPBDataTypeDouble:
1064 return @(defaultValue_.valueDouble);
1065 case GPBDataTypeInt32:
1066 case GPBDataTypeSInt32:
1067 case GPBDataTypeEnum:
1068 case GPBDataTypeSFixed32:
1069 return @(defaultValue_.valueInt32);
1070 case GPBDataTypeInt64:
1071 case GPBDataTypeSInt64:
1072 case GPBDataTypeSFixed64:
1073 return @(defaultValue_.valueInt64);
1074 case GPBDataTypeUInt32:
1075 case GPBDataTypeFixed32:
1076 return @(defaultValue_.valueUInt32);
1077 case GPBDataTypeUInt64:
1078 case GPBDataTypeFixed64:
1079 return @(defaultValue_.valueUInt64);
1080 case GPBDataTypeBytes:
1081 // Like message fields, the default is zero length data.
Thomas Van Lenten189f6322022-09-19 17:21:13 -04001082 return (defaultValue_.valueData ? defaultValue_.valueData : GPBEmptyNSData());
Thomas Van Lentend846b0b2015-06-08 16:24:57 -04001083 case GPBDataTypeString:
1084 // Like message fields, the default is zero length string.
1085 return (defaultValue_.valueString ? defaultValue_.valueString : @"");
1086 case GPBDataTypeGroup:
1087 case GPBDataTypeMessage:
1088 return nil;
1089 }
1090}
1091
1092- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other {
1093 int32_t selfNumber = description_->fieldNumber;
1094 int32_t otherNumber = other->description_->fieldNumber;
1095 if (selfNumber < otherNumber) {
1096 return NSOrderedAscending;
1097 } else if (selfNumber == otherNumber) {
1098 return NSOrderedSame;
1099 } else {
1100 return NSOrderedDescending;
1101 }
1102}
1103
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001104@end
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -04001105
1106#pragma clang diagnostic pop