blob: 2709737cad6ad26eda139af8d9a42880d2a63e16 [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
39// The address of this variable is used as a key for obj_getAssociatedObject.
40static const char kTextFormatExtraValueKey = 0;
41
42// Utility function to generate selectors on the fly.
43static SEL SelFromStrings(const char *prefix, const char *middle,
44 const char *suffix, BOOL takesArg) {
45 if (prefix == NULL && suffix == NULL && !takesArg) {
46 return sel_getUid(middle);
47 }
48 const size_t prefixLen = prefix != NULL ? strlen(prefix) : 0;
49 const size_t middleLen = strlen(middle);
50 const size_t suffixLen = suffix != NULL ? strlen(suffix) : 0;
51 size_t totalLen =
52 prefixLen + middleLen + suffixLen + 1; // include space for null on end.
53 if (takesArg) {
54 totalLen += 1;
55 }
56 char buffer[totalLen];
57 if (prefix != NULL) {
58 memcpy(buffer, prefix, prefixLen);
59 memcpy(buffer + prefixLen, middle, middleLen);
60 buffer[prefixLen] = (char)toupper(buffer[prefixLen]);
61 } else {
62 memcpy(buffer, middle, middleLen);
63 }
64 if (suffix != NULL) {
65 memcpy(buffer + prefixLen + middleLen, suffix, suffixLen);
66 }
67 if (takesArg) {
68 buffer[totalLen - 2] = ':';
69 }
70 // Always null terminate it.
71 buffer[totalLen - 1] = 0;
72
73 SEL result = sel_getUid(buffer);
74 return result;
75}
76
77static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
78 NSArray *allMessageFields)
79 __attribute__((ns_returns_retained));
80
81static NSArray *NewFieldsArrayForHasIndex(int hasIndex,
82 NSArray *allMessageFields) {
83 NSMutableArray *result = [[NSMutableArray alloc] init];
84 for (GPBFieldDescriptor *fieldDesc in allMessageFields) {
85 if (fieldDesc->description_->hasIndex == hasIndex) {
86 [result addObject:fieldDesc];
87 }
88 }
89 return result;
90}
91
92@implementation GPBDescriptor {
93 Class messageClass_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -040094 GPBFileDescriptor *file_;
95 BOOL wireFormat_;
96}
97
98@synthesize messageClass = messageClass_;
99@synthesize fields = fields_;
100@synthesize oneofs = oneofs_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400101@synthesize extensionRanges = extensionRanges_;
102@synthesize extensionRangesCount = extensionRangesCount_;
103@synthesize file = file_;
104@synthesize wireFormat = wireFormat_;
105
106+ (instancetype)
107 allocDescriptorForClass:(Class)messageClass
108 rootClass:(Class)rootClass
109 file:(GPBFileDescriptor *)file
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400110 fields:(void *)fieldDescriptions
111 fieldCount:(uint32_t)fieldCount
112 storageSize:(uint32_t)storageSize
113 flags:(GPBDescriptorInitializationFlags)flags {
114 // The rootClass is no longer used, but it is passed in to ensure it
115 // was started up during initialization also.
116 (void)rootClass;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400117 NSMutableArray *fields = nil;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400118 GPBFileSyntax syntax = file.syntax;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400119 BOOL fieldsIncludeDefault =
120 (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0;
121
122 void *desc;
123 for (uint32_t i = 0; i < fieldCount; ++i) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400124 if (fields == nil) {
125 fields = [[NSMutableArray alloc] initWithCapacity:fieldCount];
126 }
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400127 // Need correctly typed pointer for array indexing below to work.
128 if (fieldsIncludeDefault) {
129 GPBMessageFieldDescriptionWithDefault *fieldDescWithDefault = fieldDescriptions;
130 desc = &(fieldDescWithDefault[i]);
131 } else {
132 GPBMessageFieldDescription *fieldDesc = fieldDescriptions;
133 desc = &(fieldDesc[i]);
134 }
135 GPBFieldDescriptor *fieldDescriptor =
136 [[GPBFieldDescriptor alloc] initWithFieldDescription:desc
137 includesDefault:fieldsIncludeDefault
138 syntax:syntax];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400139 [fields addObject:fieldDescriptor];
140 [fieldDescriptor release];
141 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400142
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400143 BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400144 GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass
145 file:file
146 fields:fields
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400147 storageSize:storageSize
148 wireFormat:wireFormat];
149 [fields release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400150 return descriptor;
151}
152
153- (instancetype)initWithClass:(Class)messageClass
154 file:(GPBFileDescriptor *)file
155 fields:(NSArray *)fields
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400156 storageSize:(uint32_t)storageSize
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400157 wireFormat:(BOOL)wireFormat {
158 if ((self = [super init])) {
159 messageClass_ = messageClass;
160 file_ = file;
161 fields_ = [fields retain];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400162 storageSize_ = storageSize;
163 wireFormat_ = wireFormat;
164 }
165 return self;
166}
167
168- (void)dealloc {
169 [fields_ release];
170 [oneofs_ release];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400171 [super dealloc];
172}
173
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400174- (void)setupOneofs:(const char **)oneofNames
175 count:(uint32_t)count
176 firstHasIndex:(int32_t)firstHasIndex {
177 NSCAssert(firstHasIndex < 0, @"Should always be <0");
178 NSMutableArray *oneofs = [[NSMutableArray alloc] initWithCapacity:count];
179 for (uint32_t i = 0, hasIndex = firstHasIndex; i < count; ++i, --hasIndex) {
180 const char *name = oneofNames[i];
181 NSArray *fieldsForOneof = NewFieldsArrayForHasIndex(hasIndex, fields_);
182 NSCAssert(fieldsForOneof.count > 0,
183 @"No fields for this oneof? (%s:%d)", name, hasIndex);
184 GPBOneofDescriptor *oneofDescriptor =
185 [[GPBOneofDescriptor alloc] initWithName:name fields:fieldsForOneof];
186 [oneofs addObject:oneofDescriptor];
187 [oneofDescriptor release];
188 [fieldsForOneof release];
189 }
190 oneofs_ = oneofs;
191}
192
193- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo {
194 // Extra info is a compile time option, so skip the work if not needed.
195 if (extraTextFormatInfo) {
196 NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo];
197 for (GPBFieldDescriptor *fieldDescriptor in fields_) {
198 if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) {
199 objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey,
200 extraInfoValue,
201 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
202 }
203 }
204 }
205}
206
207- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count {
208 extensionRanges_ = ranges;
209 extensionRangesCount_ = count;
210}
211
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400212- (NSString *)name {
213 return NSStringFromClass(messageClass_);
214}
215
216- (id)copyWithZone:(NSZone *)zone {
217#pragma unused(zone)
218 return [self retain];
219}
220
221- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
222 for (GPBFieldDescriptor *descriptor in fields_) {
223 if (GPBFieldNumber(descriptor) == fieldNumber) {
224 return descriptor;
225 }
226 }
227 return nil;
228}
229
230- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
231 for (GPBFieldDescriptor *descriptor in fields_) {
232 if ([descriptor.name isEqual:name]) {
233 return descriptor;
234 }
235 }
236 return nil;
237}
238
239- (GPBOneofDescriptor *)oneofWithName:(NSString *)name {
240 for (GPBOneofDescriptor *descriptor in oneofs_) {
241 if ([descriptor.name isEqual:name]) {
242 return descriptor;
243 }
244 }
245 return nil;
246}
247
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400248@end
249
250@implementation GPBFileDescriptor {
251 NSString *package_;
252 GPBFileSyntax syntax_;
253}
254
255@synthesize package = package_;
256@synthesize syntax = syntax_;
257
258- (instancetype)initWithPackage:(NSString *)package
259 syntax:(GPBFileSyntax)syntax {
260 self = [super init];
261 if (self) {
262 package_ = [package copy];
263 syntax_ = syntax;
264 }
265 return self;
266}
267
268@end
269
270@implementation GPBOneofDescriptor
271
272@synthesize fields = fields_;
273
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400274- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400275 self = [super init];
276 if (self) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400277 name_ = name;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400278 fields_ = [fields retain];
279 for (GPBFieldDescriptor *fieldDesc in fields) {
280 fieldDesc->containingOneof_ = self;
281 }
282
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400283 caseSel_ = SelFromStrings(NULL, name, "OneOfCase", NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400284 }
285 return self;
286}
287
288- (void)dealloc {
289 [fields_ release];
290 [super dealloc];
291}
292
293- (NSString *)name {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400294 return @(name_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400295}
296
297- (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber {
298 for (GPBFieldDescriptor *descriptor in fields_) {
299 if (GPBFieldNumber(descriptor) == fieldNumber) {
300 return descriptor;
301 }
302 }
303 return nil;
304}
305
306- (GPBFieldDescriptor *)fieldWithName:(NSString *)name {
307 for (GPBFieldDescriptor *descriptor in fields_) {
308 if ([descriptor.name isEqual:name]) {
309 return descriptor;
310 }
311 }
312 return nil;
313}
314
315@end
316
317uint32_t GPBFieldTag(GPBFieldDescriptor *self) {
318 GPBMessageFieldDescription *description = self->description_;
319 GPBWireFormat format;
320 if ((description->flags & GPBFieldMapKeyMask) != 0) {
321 // Maps are repeated messages on the wire.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400322 format = GPBWireFormatForType(GPBDataTypeMessage, NO);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400323 } else {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400324 format = GPBWireFormatForType(description->dataType,
325 ((description->flags & GPBFieldPacked) != 0));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400326 }
327 return GPBWireFormatMakeTag(description->number, format);
328}
329
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400330uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
331 GPBMessageFieldDescription *description = self->description_;
332 NSCAssert((description->flags & GPBFieldRepeated) != 0,
333 @"Only valid on repeated fields");
334 GPBWireFormat format =
335 GPBWireFormatForType(description->dataType,
336 ((description->flags & GPBFieldPacked) == 0));
337 return GPBWireFormatMakeTag(description->number, format);
338}
339
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400340@implementation GPBFieldDescriptor {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400341 GPBGenericValue defaultValue_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400342
343 // Message ivars
344 Class msgClass_;
345
346 // Enum ivars.
347 // If protos are generated with GenerateEnumDescriptors on then it will
348 // be a enumDescriptor, otherwise it will be a enumVerifier.
349 union {
350 GPBEnumDescriptor *enumDescriptor_;
351 GPBEnumValidationFunc enumVerifier_;
352 } enumHandling_;
353}
354
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400355@synthesize msgClass = msgClass_;
356@synthesize containingOneof = containingOneof_;
357
358- (instancetype)init {
359 // Throw an exception if people attempt to not use the designated initializer.
360 self = [super init];
361 if (self != nil) {
362 [self doesNotRecognizeSelector:_cmd];
363 self = nil;
364 }
365 return self;
366}
367
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400368- (instancetype)initWithFieldDescription:(void *)description
369 includesDefault:(BOOL)includesDefault
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400370 syntax:(GPBFileSyntax)syntax {
371 if ((self = [super init])) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400372 GPBMessageFieldDescription *coreDesc;
373 if (includesDefault) {
374 coreDesc = &(((GPBMessageFieldDescriptionWithDefault *)description)->core);
375 } else {
376 coreDesc = description;
377 }
378 description_ = coreDesc;
379 getSel_ = sel_getUid(coreDesc->name);
380 setSel_ = SelFromStrings("set", coreDesc->name, NULL, YES);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400381
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400382 GPBDataType dataType = coreDesc->dataType;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400383 BOOL isMessage = GPBDataTypeIsMessage(dataType);
384 BOOL isMapOrArray = GPBFieldIsMapOrArray(self);
385
386 if (isMapOrArray) {
387 // map<>/repeated fields get a *Count property (inplace of a has*) to
388 // support checking if there are any entries without triggering
389 // autocreation.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400390 hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400391 } else {
392 // If there is a positive hasIndex, then:
393 // - All fields types for proto2 messages get has* selectors.
394 // - Only message fields for proto3 messages get has* selectors.
395 // Note: the positive check is to handle oneOfs, we can't check
396 // containingOneof_ because it isn't set until after initialization.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400397 if ((coreDesc->hasIndex >= 0) &&
398 (coreDesc->hasIndex != GPBNoHasBit) &&
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400399 ((syntax != GPBFileSyntaxProto3) || isMessage)) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400400 hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO);
401 setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES);
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400402 }
403 }
404
405 // Extra type specific data.
406 if (isMessage) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400407 const char *className = coreDesc->dataTypeSpecific.className;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400408 msgClass_ = objc_getClass(className);
409 NSAssert(msgClass_, @"Class %s not defined", className);
410 } else if (dataType == GPBDataTypeEnum) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400411 if ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0) {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400412 enumHandling_.enumDescriptor_ =
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400413 coreDesc->dataTypeSpecific.enumDescFunc();
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400414 } else {
415 enumHandling_.enumVerifier_ =
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400416 coreDesc->dataTypeSpecific.enumVerifier;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400417 }
418 }
419
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400420 // Non map<>/repeated fields can have defaults in proto2 syntax.
421 if (!isMapOrArray && includesDefault) {
422 defaultValue_ = ((GPBMessageFieldDescriptionWithDefault *)description)->defaultValue;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400423 if (dataType == GPBDataTypeBytes) {
424 // Data stored as a length prefixed (network byte order) c-string in
425 // descriptor structure.
426 const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData;
427 if (bytes) {
428 uint32_t length = *((uint32_t *)bytes);
429 length = ntohl(length);
430 bytes += sizeof(length);
431 defaultValue_.valueData =
432 [[NSData alloc] initWithBytes:bytes length:length];
433 }
434 }
435 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400436 }
437 return self;
438}
439
440- (void)dealloc {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400441 if (description_->dataType == GPBDataTypeBytes &&
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400442 !(description_->flags & GPBFieldRepeated)) {
443 [defaultValue_.valueData release];
444 }
445 [super dealloc];
446}
447
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400448- (GPBDataType)dataType {
449 return description_->dataType;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400450}
451
452- (BOOL)hasDefaultValue {
453 return (description_->flags & GPBFieldHasDefaultValue) != 0;
454}
455
456- (uint32_t)number {
457 return description_->number;
458}
459
460- (NSString *)name {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400461 return @(description_->name);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400462}
463
464- (BOOL)isRequired {
465 return (description_->flags & GPBFieldRequired) != 0;
466}
467
468- (BOOL)isOptional {
469 return (description_->flags & GPBFieldOptional) != 0;
470}
471
472- (GPBFieldType)fieldType {
473 GPBFieldFlags flags = description_->flags;
474 if ((flags & GPBFieldRepeated) != 0) {
475 return GPBFieldTypeRepeated;
476 } else if ((flags & GPBFieldMapKeyMask) != 0) {
477 return GPBFieldTypeMap;
478 } else {
479 return GPBFieldTypeSingle;
480 }
481}
482
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400483- (GPBDataType)mapKeyDataType {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400484 switch (description_->flags & GPBFieldMapKeyMask) {
485 case GPBFieldMapKeyInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400486 return GPBDataTypeInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400487 case GPBFieldMapKeyInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400488 return GPBDataTypeInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400489 case GPBFieldMapKeyUInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400490 return GPBDataTypeUInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400491 case GPBFieldMapKeyUInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400492 return GPBDataTypeUInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400493 case GPBFieldMapKeySInt32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400494 return GPBDataTypeSInt32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400495 case GPBFieldMapKeySInt64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400496 return GPBDataTypeSInt64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400497 case GPBFieldMapKeyFixed32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400498 return GPBDataTypeFixed32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400499 case GPBFieldMapKeyFixed64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400500 return GPBDataTypeFixed64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400501 case GPBFieldMapKeySFixed32:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400502 return GPBDataTypeSFixed32;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400503 case GPBFieldMapKeySFixed64:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400504 return GPBDataTypeSFixed64;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400505 case GPBFieldMapKeyBool:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400506 return GPBDataTypeBool;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400507 case GPBFieldMapKeyString:
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400508 return GPBDataTypeString;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400509
510 default:
511 NSAssert(0, @"Not a map type");
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400512 return GPBDataTypeInt32; // For lack of anything better.
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400513 }
514}
515
516- (BOOL)isPackable {
517 return (description_->flags & GPBFieldPacked) != 0;
518}
519
520- (BOOL)isValidEnumValue:(int32_t)value {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400521 NSAssert(description_->dataType == GPBDataTypeEnum,
522 @"Field Must be of type GPBDataTypeEnum");
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400523 if (description_->flags & GPBFieldHasEnumDescriptor) {
524 return enumHandling_.enumDescriptor_.enumVerifier(value);
525 } else {
526 return enumHandling_.enumVerifier_(value);
527 }
528}
529
530- (GPBEnumDescriptor *)enumDescriptor {
531 if (description_->flags & GPBFieldHasEnumDescriptor) {
532 return enumHandling_.enumDescriptor_;
533 } else {
534 return nil;
535 }
536}
537
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400538- (GPBGenericValue)defaultValue {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400539 // Depends on the fact that defaultValue_ is initialized either to "0/nil" or
540 // to an actual defaultValue in our initializer.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400541 GPBGenericValue value = defaultValue_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400542
543 if (!(description_->flags & GPBFieldRepeated)) {
544 // We special handle data and strings. If they are nil, we replace them
545 // with empty string/empty data.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400546 GPBDataType type = description_->dataType;
547 if (type == GPBDataTypeBytes && value.valueData == nil) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400548 value.valueData = GPBEmptyNSData();
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400549 } else if (type == GPBDataTypeString && value.valueString == nil) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400550 value.valueString = @"";
551 }
552 }
553 return value;
554}
555
556- (NSString *)textFormatName {
557 if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) {
558 NSValue *extraInfoValue =
559 objc_getAssociatedObject(self, &kTextFormatExtraValueKey);
560 // Support can be left out at generation time.
561 if (!extraInfoValue) {
562 return nil;
563 }
564 const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue];
565 return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self),
566 self.name);
567 }
568
569 // The logic here has to match SetCommonFieldVariables() from
570 // objectivec_field.cc in the proto compiler.
571 NSString *name = self.name;
572 NSUInteger len = [name length];
573
574 // Remove the "_p" added to reserved names.
575 if ([name hasSuffix:@"_p"]) {
576 name = [name substringToIndex:(len - 2)];
577 len = [name length];
578 }
579
580 // Remove "Array" from the end for repeated fields.
581 if (((description_->flags & GPBFieldRepeated) != 0) &&
582 [name hasSuffix:@"Array"]) {
583 name = [name substringToIndex:(len - 5)];
584 len = [name length];
585 }
586
587 // Groups vs. other fields.
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400588 if (description_->dataType == GPBDataTypeGroup) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400589 // Just capitalize the first letter.
590 unichar firstChar = [name characterAtIndex:0];
591 if (firstChar >= 'a' && firstChar <= 'z') {
592 NSString *firstCharString =
593 [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')];
594 NSString *result =
595 [name stringByReplacingCharactersInRange:NSMakeRange(0, 1)
596 withString:firstCharString];
597 return result;
598 }
599 return name;
600
601 } else {
602 // Undo the CamelCase.
603 NSMutableString *result = [NSMutableString stringWithCapacity:len];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400604 for (uint32_t i = 0; i < len; i++) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400605 unichar c = [name characterAtIndex:i];
606 if (c >= 'A' && c <= 'Z') {
607 if (i > 0) {
608 [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')];
609 } else {
610 [result appendFormat:@"%C", c];
611 }
612 } else {
613 [result appendFormat:@"%C", c];
614 }
615 }
616 return result;
617 }
618}
619
620@end
621
622@implementation GPBEnumDescriptor {
623 NSString *name_;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400624 // valueNames_ is a single c string with all of the value names appended
625 // together, each null terminated. -calcValueNameOffsets fills in
626 // nameOffsets_ with the offsets to allow quicker access to the individual
627 // names.
628 const char *valueNames_;
629 const int32_t *values_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400630 GPBEnumValidationFunc enumVerifier_;
631 const uint8_t *extraTextFormatInfo_;
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400632 uint32_t *nameOffsets_;
633 uint32_t valueCount_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400634}
635
636@synthesize name = name_;
637@synthesize enumVerifier = enumVerifier_;
638
639+ (instancetype)
640 allocDescriptorForName:(NSString *)name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400641 valueNames:(const char *)valueNames
642 values:(const int32_t *)values
643 count:(uint32_t)valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400644 enumVerifier:(GPBEnumValidationFunc)enumVerifier {
645 GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400646 valueNames:valueNames
647 values:values
648 count:valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400649 enumVerifier:enumVerifier];
650 return descriptor;
651}
652
653+ (instancetype)
654 allocDescriptorForName:(NSString *)name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400655 valueNames:(const char *)valueNames
656 values:(const int32_t *)values
657 count:(uint32_t)valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400658 enumVerifier:(GPBEnumValidationFunc)enumVerifier
659 extraTextFormatInfo:(const char *)extraTextFormatInfo {
660 // Call the common case.
661 GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400662 valueNames:valueNames
663 values:values
664 count:valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400665 enumVerifier:enumVerifier];
666 // Set the extra info.
667 descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo;
668 return descriptor;
669}
670
671- (instancetype)initWithName:(NSString *)name
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400672 valueNames:(const char *)valueNames
673 values:(const int32_t *)values
674 count:(uint32_t)valueCount
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400675 enumVerifier:(GPBEnumValidationFunc)enumVerifier {
676 if ((self = [super init])) {
677 name_ = [name copy];
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400678 valueNames_ = valueNames;
679 values_ = values;
680 valueCount_ = valueCount;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400681 enumVerifier_ = enumVerifier;
682 }
683 return self;
684}
685
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400686- (void)dealloc {
687 [name_ release];
688 if (nameOffsets_) free(nameOffsets_);
689 [super dealloc];
690}
691
692- (void)calcValueNameOffsets {
693 @synchronized(self) {
694 if (nameOffsets_ != NULL) {
695 return;
696 }
697 uint32_t *offsets = malloc(valueCount_ * sizeof(uint32_t));
698 const char *scan = valueNames_;
699 for (uint32_t i = 0; i < valueCount_; ++i) {
700 offsets[i] = (uint32_t)(scan - valueNames_);
701 while (*scan != '\0') ++scan;
702 ++scan; // Step over the null.
703 }
704 nameOffsets_ = offsets;
705 }
706}
707
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400708- (NSString *)enumNameForValue:(int32_t)number {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400709 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
710
711 for (uint32_t i = 0; i < valueCount_; ++i) {
712 if (values_[i] == number) {
713 const char *valueName = valueNames_ + nameOffsets_[i];
714 NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400715 return fullName;
716 }
717 }
718 return nil;
719}
720
721- (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name {
722 // Must have the prefix.
723 NSUInteger prefixLen = name_.length + 1;
724 if ((name.length <= prefixLen) || ![name hasPrefix:name_] ||
725 ([name characterAtIndex:prefixLen - 1] != '_')) {
726 return NO;
727 }
728
729 // Skip over the prefix.
730 const char *nameAsCStr = [name UTF8String];
731 nameAsCStr += prefixLen;
732
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400733 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
734
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400735 // Find it.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400736 for (uint32_t i = 0; i < valueCount_; ++i) {
737 const char *valueName = valueNames_ + nameOffsets_[i];
738 if (strcmp(nameAsCStr, valueName) == 0) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400739 if (outValue) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400740 *outValue = values_[i];
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400741 }
742 return YES;
743 }
744 }
745 return NO;
746}
747
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400748- (NSString *)textFormatNameForValue:(int32_t)number {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400749 if (nameOffsets_ == NULL) [self calcValueNameOffsets];
750
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400751 // Find the EnumValue descriptor and its index.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400752 BOOL foundIt = NO;
753 uint32_t valueDescriptorIndex;
754 for (valueDescriptorIndex = 0; valueDescriptorIndex < valueCount_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400755 ++valueDescriptorIndex) {
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400756 if (values_[valueDescriptorIndex] == number) {
757 foundIt = YES;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400758 break;
759 }
760 }
761
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400762 if (!foundIt) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400763 return nil;
764 }
765
766 NSString *result = nil;
767 // Naming adds an underscore between enum name and value name, skip that also.
Thomas Van Lenten79a23c42016-03-17 10:04:21 -0400768 const char *valueName = valueNames_ + nameOffsets_[valueDescriptorIndex];
769 NSString *shortName = @(valueName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400770
771 // See if it is in the map of special format handling.
772 if (extraTextFormatInfo_) {
773 result = GPBDecodeTextFormatName(extraTextFormatInfo_,
774 (int32_t)valueDescriptorIndex, shortName);
775 }
776 // Logic here needs to match what objectivec_enum.cc does in the proto
777 // compiler.
778 if (result == nil) {
779 NSUInteger len = [shortName length];
780 NSMutableString *worker = [NSMutableString stringWithCapacity:len];
781 for (NSUInteger i = 0; i < len; i++) {
782 unichar c = [shortName characterAtIndex:i];
783 if (i > 0 && c >= 'A' && c <= 'Z') {
784 [worker appendString:@"_"];
785 }
786 [worker appendFormat:@"%c", toupper((char)c)];
787 }
788 result = worker;
789 }
790 return result;
791}
792
793@end
794
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400795@implementation GPBExtensionDescriptor {
796 GPBGenericValue defaultValue_;
797}
798
799@synthesize containingMessageClass = containingMessageClass_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400800
801- (instancetype)initWithExtensionDescription:
802 (GPBExtensionDescription *)description {
803 if ((self = [super init])) {
804 description_ = description;
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400805
806#if DEBUG
807 const char *className = description->messageOrGroupClassName;
808 if (className) {
809 NSAssert(objc_lookUpClass(className) != Nil,
810 @"Class %s not defined", className);
811 }
812#endif
813
814 if (description->extendedClass) {
815 Class containingClass = objc_lookUpClass(description->extendedClass);
816 NSAssert(containingClass, @"Class %s not defined",
817 description->extendedClass);
818 containingMessageClass_ = containingClass;
819 }
820
821 GPBDataType type = description_->dataType;
822 if (type == GPBDataTypeBytes) {
823 // Data stored as a length prefixed c-string in descriptor records.
824 const uint8_t *bytes =
825 (const uint8_t *)description->defaultValue.valueData;
826 if (bytes) {
827 uint32_t length = *((uint32_t *)bytes);
828 // The length is stored in network byte order.
829 length = ntohl(length);
830 bytes += sizeof(length);
831 defaultValue_.valueData =
832 [[NSData alloc] initWithBytes:bytes length:length];
833 }
834 } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) {
835 // The default is looked up in -defaultValue instead since extensions
836 // aren't common, we avoid the hit startup hit and it avoid initialization
837 // order issues.
838 } else {
839 defaultValue_ = description->defaultValue;
840 }
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400841 }
842 return self;
843}
844
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400845- (void)dealloc {
846 if ((description_->dataType == GPBDataTypeBytes) &&
847 !GPBExtensionIsRepeated(description_)) {
848 [defaultValue_.valueData release];
849 }
850 [super dealloc];
851}
852
853- (instancetype)copyWithZone:(NSZone *)zone {
854#pragma unused(zone)
855 // Immutable.
856 return [self retain];
857}
858
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400859- (NSString *)singletonName {
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -0400860 return @(description_->singletonName);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400861}
862
863- (const char *)singletonNameC {
864 return description_->singletonName;
865}
866
867- (uint32_t)fieldNumber {
868 return description_->fieldNumber;
869}
870
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400871- (GPBDataType)dataType {
872 return description_->dataType;
873}
874
875- (GPBWireFormat)wireType {
876 return GPBWireFormatForType(description_->dataType,
877 GPBExtensionIsPacked(description_));
878}
879
880- (GPBWireFormat)alternateWireType {
881 NSAssert(GPBExtensionIsRepeated(description_),
882 @"Only valid on repeated extensions");
883 return GPBWireFormatForType(description_->dataType,
884 !GPBExtensionIsPacked(description_));
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400885}
886
887- (BOOL)isRepeated {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400888 return GPBExtensionIsRepeated(description_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400889}
890
891- (BOOL)isMap {
892 return (description_->options & GPBFieldMapKeyMask) != 0;
893}
894
895- (BOOL)isPackable {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400896 return GPBExtensionIsPacked(description_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400897}
898
899- (Class)msgClass {
900 return objc_getClass(description_->messageOrGroupClassName);
901}
902
903- (GPBEnumDescriptor *)enumDescriptor {
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400904 if (description_->dataType == GPBDataTypeEnum) {
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400905 GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc();
906 return enumDescriptor;
907 }
908 return nil;
909}
910
Thomas Van Lentend846b0b2015-06-08 16:24:57 -0400911- (id)defaultValue {
912 if (GPBExtensionIsRepeated(description_)) {
913 return nil;
914 }
915
916 switch (description_->dataType) {
917 case GPBDataTypeBool:
918 return @(defaultValue_.valueBool);
919 case GPBDataTypeFloat:
920 return @(defaultValue_.valueFloat);
921 case GPBDataTypeDouble:
922 return @(defaultValue_.valueDouble);
923 case GPBDataTypeInt32:
924 case GPBDataTypeSInt32:
925 case GPBDataTypeEnum:
926 case GPBDataTypeSFixed32:
927 return @(defaultValue_.valueInt32);
928 case GPBDataTypeInt64:
929 case GPBDataTypeSInt64:
930 case GPBDataTypeSFixed64:
931 return @(defaultValue_.valueInt64);
932 case GPBDataTypeUInt32:
933 case GPBDataTypeFixed32:
934 return @(defaultValue_.valueUInt32);
935 case GPBDataTypeUInt64:
936 case GPBDataTypeFixed64:
937 return @(defaultValue_.valueUInt64);
938 case GPBDataTypeBytes:
939 // Like message fields, the default is zero length data.
940 return (defaultValue_.valueData ? defaultValue_.valueData
941 : GPBEmptyNSData());
942 case GPBDataTypeString:
943 // Like message fields, the default is zero length string.
944 return (defaultValue_.valueString ? defaultValue_.valueString : @"");
945 case GPBDataTypeGroup:
946 case GPBDataTypeMessage:
947 return nil;
948 }
949}
950
951- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other {
952 int32_t selfNumber = description_->fieldNumber;
953 int32_t otherNumber = other->description_->fieldNumber;
954 if (selfNumber < otherNumber) {
955 return NSOrderedAscending;
956 } else if (selfNumber == otherNumber) {
957 return NSOrderedSame;
958 } else {
959 return NSOrderedDescending;
960 }
961}
962
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400963@end