OLD | NEW |
| (Empty) |
1 // 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" | |
38 #import "google/protobuf/Descriptor.pbobjc.h" | |
39 | |
40 // The address of this variable is used as a key for obj_getAssociatedObject. | |
41 static const char kTextFormatExtraValueKey = 0; | |
42 | |
43 // Utility function to generate selectors on the fly. | |
44 static SEL SelFromStrings(const char *prefix, const char *middle, | |
45 const char *suffix, BOOL takesArg) { | |
46 if (prefix == NULL && suffix == NULL && !takesArg) { | |
47 return sel_getUid(middle); | |
48 } | |
49 const size_t prefixLen = prefix != NULL ? strlen(prefix) : 0; | |
50 const size_t middleLen = strlen(middle); | |
51 const size_t suffixLen = suffix != NULL ? strlen(suffix) : 0; | |
52 size_t totalLen = | |
53 prefixLen + middleLen + suffixLen + 1; // include space for null on end. | |
54 if (takesArg) { | |
55 totalLen += 1; | |
56 } | |
57 char buffer[totalLen]; | |
58 if (prefix != NULL) { | |
59 memcpy(buffer, prefix, prefixLen); | |
60 memcpy(buffer + prefixLen, middle, middleLen); | |
61 buffer[prefixLen] = (char)toupper(buffer[prefixLen]); | |
62 } else { | |
63 memcpy(buffer, middle, middleLen); | |
64 } | |
65 if (suffix != NULL) { | |
66 memcpy(buffer + prefixLen + middleLen, suffix, suffixLen); | |
67 } | |
68 if (takesArg) { | |
69 buffer[totalLen - 2] = ':'; | |
70 } | |
71 // Always null terminate it. | |
72 buffer[totalLen - 1] = 0; | |
73 | |
74 SEL result = sel_getUid(buffer); | |
75 return result; | |
76 } | |
77 | |
78 static NSArray *NewFieldsArrayForHasIndex(int hasIndex, | |
79 NSArray *allMessageFields) | |
80 __attribute__((ns_returns_retained)); | |
81 | |
82 static NSArray *NewFieldsArrayForHasIndex(int hasIndex, | |
83 NSArray *allMessageFields) { | |
84 NSMutableArray *result = [[NSMutableArray alloc] init]; | |
85 for (GPBFieldDescriptor *fieldDesc in allMessageFields) { | |
86 if (fieldDesc->description_->hasIndex == hasIndex) { | |
87 [result addObject:fieldDesc]; | |
88 } | |
89 } | |
90 return result; | |
91 } | |
92 | |
93 @implementation GPBDescriptor { | |
94 Class messageClass_; | |
95 NSArray *enums_; | |
96 GPBFileDescriptor *file_; | |
97 BOOL wireFormat_; | |
98 } | |
99 | |
100 @synthesize messageClass = messageClass_; | |
101 @synthesize fields = fields_; | |
102 @synthesize oneofs = oneofs_; | |
103 @synthesize enums = enums_; | |
104 @synthesize extensionRanges = extensionRanges_; | |
105 @synthesize extensionRangesCount = extensionRangesCount_; | |
106 @synthesize file = file_; | |
107 @synthesize wireFormat = wireFormat_; | |
108 | |
109 + (instancetype) | |
110 allocDescriptorForClass:(Class)messageClass | |
111 rootClass:(Class)rootClass | |
112 file:(GPBFileDescriptor *)file | |
113 fields:(GPBMessageFieldDescription *)fieldDescriptions | |
114 fieldCount:(NSUInteger)fieldCount | |
115 oneofs:(GPBMessageOneofDescription *)oneofDescriptions | |
116 oneofCount:(NSUInteger)oneofCount | |
117 enums:(GPBMessageEnumDescription *)enumDescriptions | |
118 enumCount:(NSUInteger)enumCount | |
119 ranges:(const GPBExtensionRange *)ranges | |
120 rangeCount:(NSUInteger)rangeCount | |
121 storageSize:(size_t)storageSize | |
122 wireFormat:(BOOL)wireFormat { | |
123 NSMutableArray *fields = nil; | |
124 NSMutableArray *oneofs = nil; | |
125 NSMutableArray *enums = nil; | |
126 NSMutableArray *extensionRanges = nil; | |
127 GPBFileSyntax syntax = file.syntax; | |
128 for (NSUInteger i = 0; i < fieldCount; ++i) { | |
129 if (fields == nil) { | |
130 fields = [[NSMutableArray alloc] initWithCapacity:fieldCount]; | |
131 } | |
132 GPBFieldDescriptor *fieldDescriptor = [[GPBFieldDescriptor alloc] | |
133 initWithFieldDescription:&fieldDescriptions[i] | |
134 rootClass:rootClass | |
135 syntax:syntax]; | |
136 [fields addObject:fieldDescriptor]; | |
137 [fieldDescriptor release]; | |
138 } | |
139 for (NSUInteger i = 0; i < oneofCount; ++i) { | |
140 if (oneofs == nil) { | |
141 oneofs = [[NSMutableArray alloc] initWithCapacity:oneofCount]; | |
142 } | |
143 GPBMessageOneofDescription *oneofDescription = &oneofDescriptions[i]; | |
144 NSArray *fieldsForOneof = | |
145 NewFieldsArrayForHasIndex(oneofDescription->index, fields); | |
146 GPBOneofDescriptor *oneofDescriptor = | |
147 [[GPBOneofDescriptor alloc] initWithOneofDescription:oneofDescription | |
148 fields:fieldsForOneof]; | |
149 [oneofs addObject:oneofDescriptor]; | |
150 [oneofDescriptor release]; | |
151 [fieldsForOneof release]; | |
152 } | |
153 for (NSUInteger i = 0; i < enumCount; ++i) { | |
154 if (enums == nil) { | |
155 enums = [[NSMutableArray alloc] initWithCapacity:enumCount]; | |
156 } | |
157 GPBEnumDescriptor *enumDescriptor = | |
158 enumDescriptions[i].enumDescriptorFunc(); | |
159 [enums addObject:enumDescriptor]; | |
160 } | |
161 | |
162 GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass | |
163 file:file | |
164 fields:fields | |
165 oneofs:oneofs | |
166 enums:enums | |
167 extensionRanges:ranges | |
168 extensionRangesCount:rangeCount | |
169 storageSize:storageSize | |
170 wireFormat:wireFormat]; | |
171 [fields release]; | |
172 [oneofs release]; | |
173 [enums release]; | |
174 [extensionRanges release]; | |
175 return descriptor; | |
176 } | |
177 | |
178 + (instancetype) | |
179 allocDescriptorForClass:(Class)messageClass | |
180 rootClass:(Class)rootClass | |
181 file:(GPBFileDescriptor *)file | |
182 fields:(GPBMessageFieldDescription *)fieldDescriptions | |
183 fieldCount:(NSUInteger)fieldCount | |
184 oneofs:(GPBMessageOneofDescription *)oneofDescriptions | |
185 oneofCount:(NSUInteger)oneofCount | |
186 enums:(GPBMessageEnumDescription *)enumDescriptions | |
187 enumCount:(NSUInteger)enumCount | |
188 ranges:(const GPBExtensionRange *)ranges | |
189 rangeCount:(NSUInteger)rangeCount | |
190 storageSize:(size_t)storageSize | |
191 wireFormat:(BOOL)wireFormat | |
192 extraTextFormatInfo:(const char *)extraTextFormatInfo { | |
193 GPBDescriptor *descriptor = [self allocDescriptorForClass:messageClass | |
194 rootClass:rootClass | |
195 file:file | |
196 fields:fieldDescriptions | |
197 fieldCount:fieldCount | |
198 oneofs:oneofDescriptions | |
199 oneofCount:oneofCount | |
200 enums:enumDescriptions | |
201 enumCount:enumCount | |
202 ranges:ranges | |
203 rangeCount:rangeCount | |
204 storageSize:storageSize | |
205 wireFormat:wireFormat]; | |
206 // Extra info is a compile time option, so skip the work if not needed. | |
207 if (extraTextFormatInfo) { | |
208 NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo]; | |
209 for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) { | |
210 if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) { | |
211 objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey, | |
212 extraInfoValue, | |
213 OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
214 } | |
215 } | |
216 } | |
217 return descriptor; | |
218 } | |
219 | |
220 - (instancetype)initWithClass:(Class)messageClass | |
221 file:(GPBFileDescriptor *)file | |
222 fields:(NSArray *)fields | |
223 oneofs:(NSArray *)oneofs | |
224 enums:(NSArray *)enums | |
225 extensionRanges:(const GPBExtensionRange *)extensionRanges | |
226 extensionRangesCount:(NSUInteger)extensionRangesCount | |
227 storageSize:(size_t)storageSize | |
228 wireFormat:(BOOL)wireFormat { | |
229 if ((self = [super init])) { | |
230 messageClass_ = messageClass; | |
231 file_ = file; | |
232 fields_ = [fields retain]; | |
233 oneofs_ = [oneofs retain]; | |
234 enums_ = [enums retain]; | |
235 extensionRanges_ = extensionRanges; | |
236 extensionRangesCount_ = extensionRangesCount; | |
237 storageSize_ = storageSize; | |
238 wireFormat_ = wireFormat; | |
239 } | |
240 return self; | |
241 } | |
242 | |
243 - (void)dealloc { | |
244 [fields_ release]; | |
245 [oneofs_ release]; | |
246 [enums_ release]; | |
247 [super dealloc]; | |
248 } | |
249 | |
250 - (NSString *)name { | |
251 return NSStringFromClass(messageClass_); | |
252 } | |
253 | |
254 - (id)copyWithZone:(NSZone *)zone { | |
255 #pragma unused(zone) | |
256 return [self retain]; | |
257 } | |
258 | |
259 - (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber { | |
260 for (GPBFieldDescriptor *descriptor in fields_) { | |
261 if (GPBFieldNumber(descriptor) == fieldNumber) { | |
262 return descriptor; | |
263 } | |
264 } | |
265 return nil; | |
266 } | |
267 | |
268 - (GPBFieldDescriptor *)fieldWithName:(NSString *)name { | |
269 for (GPBFieldDescriptor *descriptor in fields_) { | |
270 if ([descriptor.name isEqual:name]) { | |
271 return descriptor; | |
272 } | |
273 } | |
274 return nil; | |
275 } | |
276 | |
277 - (GPBOneofDescriptor *)oneofWithName:(NSString *)name { | |
278 for (GPBOneofDescriptor *descriptor in oneofs_) { | |
279 if ([descriptor.name isEqual:name]) { | |
280 return descriptor; | |
281 } | |
282 } | |
283 return nil; | |
284 } | |
285 | |
286 - (GPBEnumDescriptor *)enumWithName:(NSString *)name { | |
287 for (GPBEnumDescriptor *descriptor in enums_) { | |
288 if ([descriptor.name isEqual:name]) { | |
289 return descriptor; | |
290 } | |
291 } | |
292 return nil; | |
293 } | |
294 | |
295 @end | |
296 | |
297 @implementation GPBFileDescriptor { | |
298 NSString *package_; | |
299 GPBFileSyntax syntax_; | |
300 } | |
301 | |
302 @synthesize package = package_; | |
303 @synthesize syntax = syntax_; | |
304 | |
305 - (instancetype)initWithPackage:(NSString *)package | |
306 syntax:(GPBFileSyntax)syntax { | |
307 self = [super init]; | |
308 if (self) { | |
309 package_ = [package copy]; | |
310 syntax_ = syntax; | |
311 } | |
312 return self; | |
313 } | |
314 | |
315 @end | |
316 | |
317 @implementation GPBOneofDescriptor | |
318 | |
319 @synthesize fields = fields_; | |
320 | |
321 - (instancetype)initWithOneofDescription: | |
322 (GPBMessageOneofDescription *)oneofDescription | |
323 fields:(NSArray *)fields { | |
324 self = [super init]; | |
325 if (self) { | |
326 NSAssert(oneofDescription->index < 0, @"Should always be <0"); | |
327 oneofDescription_ = oneofDescription; | |
328 fields_ = [fields retain]; | |
329 for (GPBFieldDescriptor *fieldDesc in fields) { | |
330 fieldDesc->containingOneof_ = self; | |
331 } | |
332 | |
333 caseSel_ = SelFromStrings(NULL, oneofDescription->name, "OneOfCase", NO); | |
334 } | |
335 return self; | |
336 } | |
337 | |
338 - (void)dealloc { | |
339 [fields_ release]; | |
340 [super dealloc]; | |
341 } | |
342 | |
343 - (NSString *)name { | |
344 return @(oneofDescription_->name); | |
345 } | |
346 | |
347 - (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber { | |
348 for (GPBFieldDescriptor *descriptor in fields_) { | |
349 if (GPBFieldNumber(descriptor) == fieldNumber) { | |
350 return descriptor; | |
351 } | |
352 } | |
353 return nil; | |
354 } | |
355 | |
356 - (GPBFieldDescriptor *)fieldWithName:(NSString *)name { | |
357 for (GPBFieldDescriptor *descriptor in fields_) { | |
358 if ([descriptor.name isEqual:name]) { | |
359 return descriptor; | |
360 } | |
361 } | |
362 return nil; | |
363 } | |
364 | |
365 @end | |
366 | |
367 uint32_t GPBFieldTag(GPBFieldDescriptor *self) { | |
368 GPBMessageFieldDescription *description = self->description_; | |
369 GPBWireFormat format; | |
370 if ((description->flags & GPBFieldMapKeyMask) != 0) { | |
371 // Maps are repeated messages on the wire. | |
372 format = GPBWireFormatForType(GPBDataTypeMessage, NO); | |
373 } else { | |
374 format = GPBWireFormatForType(description->dataType, | |
375 ((description->flags & GPBFieldPacked) != 0)); | |
376 } | |
377 return GPBWireFormatMakeTag(description->number, format); | |
378 } | |
379 | |
380 uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { | |
381 GPBMessageFieldDescription *description = self->description_; | |
382 NSCAssert((description->flags & GPBFieldRepeated) != 0, | |
383 @"Only valid on repeated fields"); | |
384 GPBWireFormat format = | |
385 GPBWireFormatForType(description->dataType, | |
386 ((description->flags & GPBFieldPacked) == 0)); | |
387 return GPBWireFormatMakeTag(description->number, format); | |
388 } | |
389 | |
390 @implementation GPBFieldDescriptor { | |
391 GPBGenericValue defaultValue_; | |
392 GPBFieldOptions *fieldOptions_; | |
393 | |
394 // Message ivars | |
395 Class msgClass_; | |
396 | |
397 // Enum ivars. | |
398 // If protos are generated with GenerateEnumDescriptors on then it will | |
399 // be a enumDescriptor, otherwise it will be a enumVerifier. | |
400 union { | |
401 GPBEnumDescriptor *enumDescriptor_; | |
402 GPBEnumValidationFunc enumVerifier_; | |
403 } enumHandling_; | |
404 } | |
405 | |
406 @synthesize fieldOptions = fieldOptions_; | |
407 @synthesize msgClass = msgClass_; | |
408 @synthesize containingOneof = containingOneof_; | |
409 | |
410 - (instancetype)init { | |
411 // Throw an exception if people attempt to not use the designated initializer. | |
412 self = [super init]; | |
413 if (self != nil) { | |
414 [self doesNotRecognizeSelector:_cmd]; | |
415 self = nil; | |
416 } | |
417 return self; | |
418 } | |
419 | |
420 - (instancetype)initWithFieldDescription: | |
421 (GPBMessageFieldDescription *)description | |
422 rootClass:(Class)rootClass | |
423 syntax:(GPBFileSyntax)syntax { | |
424 if ((self = [super init])) { | |
425 description_ = description; | |
426 getSel_ = sel_getUid(description->name); | |
427 setSel_ = SelFromStrings("set", description->name, NULL, YES); | |
428 | |
429 GPBDataType dataType = description->dataType; | |
430 BOOL isMessage = GPBDataTypeIsMessage(dataType); | |
431 BOOL isMapOrArray = GPBFieldIsMapOrArray(self); | |
432 | |
433 if (isMapOrArray) { | |
434 // map<>/repeated fields get a *Count property (inplace of a has*) to | |
435 // support checking if there are any entries without triggering | |
436 // autocreation. | |
437 hasOrCountSel_ = SelFromStrings(NULL, description->name, "_Count", NO); | |
438 } else { | |
439 // If there is a positive hasIndex, then: | |
440 // - All fields types for proto2 messages get has* selectors. | |
441 // - Only message fields for proto3 messages get has* selectors. | |
442 // Note: the positive check is to handle oneOfs, we can't check | |
443 // containingOneof_ because it isn't set until after initialization. | |
444 if ((description->hasIndex >= 0) && | |
445 (description->hasIndex != GPBNoHasBit) && | |
446 ((syntax != GPBFileSyntaxProto3) || isMessage)) { | |
447 hasOrCountSel_ = SelFromStrings("has", description->name, NULL, NO); | |
448 setHasSel_ = SelFromStrings("setHas", description->name, NULL, YES); | |
449 } | |
450 } | |
451 | |
452 // Extra type specific data. | |
453 if (isMessage) { | |
454 const char *className = description->dataTypeSpecific.className; | |
455 msgClass_ = objc_getClass(className); | |
456 NSAssert(msgClass_, @"Class %s not defined", className); | |
457 } else if (dataType == GPBDataTypeEnum) { | |
458 if ((description_->flags & GPBFieldHasEnumDescriptor) != 0) { | |
459 enumHandling_.enumDescriptor_ = | |
460 description->dataTypeSpecific.enumDescFunc(); | |
461 } else { | |
462 enumHandling_.enumVerifier_ = | |
463 description->dataTypeSpecific.enumVerifier; | |
464 } | |
465 } | |
466 | |
467 // Non map<>/repeated fields can have defaults. | |
468 if (!isMapOrArray) { | |
469 defaultValue_ = description->defaultValue; | |
470 if (dataType == GPBDataTypeBytes) { | |
471 // Data stored as a length prefixed (network byte order) c-string in | |
472 // descriptor structure. | |
473 const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData; | |
474 if (bytes) { | |
475 uint32_t length = *((uint32_t *)bytes); | |
476 length = ntohl(length); | |
477 bytes += sizeof(length); | |
478 defaultValue_.valueData = | |
479 [[NSData alloc] initWithBytes:bytes length:length]; | |
480 } | |
481 } | |
482 } | |
483 | |
484 // FieldOptions stored as a length prefixed (network byte order) c-escaped | |
485 // string in descriptor records. | |
486 if (description->fieldOptions) { | |
487 uint8_t *optionsBytes = (uint8_t *)description->fieldOptions; | |
488 uint32_t optionsLength = *((uint32_t *)optionsBytes); | |
489 optionsLength = ntohl(optionsLength); | |
490 if (optionsLength > 0) { | |
491 optionsBytes += sizeof(optionsLength); | |
492 NSData *optionsData = [NSData dataWithBytesNoCopy:optionsBytes | |
493 length:optionsLength | |
494 freeWhenDone:NO]; | |
495 GPBExtensionRegistry *registry = [rootClass extensionRegistry]; | |
496 fieldOptions_ = [[GPBFieldOptions parseFromData:optionsData | |
497 extensionRegistry:registry | |
498 error:NULL] retain]; | |
499 } | |
500 } | |
501 } | |
502 return self; | |
503 } | |
504 | |
505 - (void)dealloc { | |
506 if (description_->dataType == GPBDataTypeBytes && | |
507 !(description_->flags & GPBFieldRepeated)) { | |
508 [defaultValue_.valueData release]; | |
509 } | |
510 [super dealloc]; | |
511 } | |
512 | |
513 - (GPBDataType)dataType { | |
514 return description_->dataType; | |
515 } | |
516 | |
517 - (BOOL)hasDefaultValue { | |
518 return (description_->flags & GPBFieldHasDefaultValue) != 0; | |
519 } | |
520 | |
521 - (uint32_t)number { | |
522 return description_->number; | |
523 } | |
524 | |
525 - (NSString *)name { | |
526 return @(description_->name); | |
527 } | |
528 | |
529 - (BOOL)isRequired { | |
530 return (description_->flags & GPBFieldRequired) != 0; | |
531 } | |
532 | |
533 - (BOOL)isOptional { | |
534 return (description_->flags & GPBFieldOptional) != 0; | |
535 } | |
536 | |
537 - (GPBFieldType)fieldType { | |
538 GPBFieldFlags flags = description_->flags; | |
539 if ((flags & GPBFieldRepeated) != 0) { | |
540 return GPBFieldTypeRepeated; | |
541 } else if ((flags & GPBFieldMapKeyMask) != 0) { | |
542 return GPBFieldTypeMap; | |
543 } else { | |
544 return GPBFieldTypeSingle; | |
545 } | |
546 } | |
547 | |
548 - (GPBDataType)mapKeyDataType { | |
549 switch (description_->flags & GPBFieldMapKeyMask) { | |
550 case GPBFieldMapKeyInt32: | |
551 return GPBDataTypeInt32; | |
552 case GPBFieldMapKeyInt64: | |
553 return GPBDataTypeInt64; | |
554 case GPBFieldMapKeyUInt32: | |
555 return GPBDataTypeUInt32; | |
556 case GPBFieldMapKeyUInt64: | |
557 return GPBDataTypeUInt64; | |
558 case GPBFieldMapKeySInt32: | |
559 return GPBDataTypeSInt32; | |
560 case GPBFieldMapKeySInt64: | |
561 return GPBDataTypeSInt64; | |
562 case GPBFieldMapKeyFixed32: | |
563 return GPBDataTypeFixed32; | |
564 case GPBFieldMapKeyFixed64: | |
565 return GPBDataTypeFixed64; | |
566 case GPBFieldMapKeySFixed32: | |
567 return GPBDataTypeSFixed32; | |
568 case GPBFieldMapKeySFixed64: | |
569 return GPBDataTypeSFixed64; | |
570 case GPBFieldMapKeyBool: | |
571 return GPBDataTypeBool; | |
572 case GPBFieldMapKeyString: | |
573 return GPBDataTypeString; | |
574 | |
575 default: | |
576 NSAssert(0, @"Not a map type"); | |
577 return GPBDataTypeInt32; // For lack of anything better. | |
578 } | |
579 } | |
580 | |
581 - (BOOL)isPackable { | |
582 return (description_->flags & GPBFieldPacked) != 0; | |
583 } | |
584 | |
585 - (BOOL)isValidEnumValue:(int32_t)value { | |
586 NSAssert(description_->dataType == GPBDataTypeEnum, | |
587 @"Field Must be of type GPBDataTypeEnum"); | |
588 if (description_->flags & GPBFieldHasEnumDescriptor) { | |
589 return enumHandling_.enumDescriptor_.enumVerifier(value); | |
590 } else { | |
591 return enumHandling_.enumVerifier_(value); | |
592 } | |
593 } | |
594 | |
595 - (GPBEnumDescriptor *)enumDescriptor { | |
596 if (description_->flags & GPBFieldHasEnumDescriptor) { | |
597 return enumHandling_.enumDescriptor_; | |
598 } else { | |
599 return nil; | |
600 } | |
601 } | |
602 | |
603 - (GPBGenericValue)defaultValue { | |
604 // Depends on the fact that defaultValue_ is initialized either to "0/nil" or | |
605 // to an actual defaultValue in our initializer. | |
606 GPBGenericValue value = defaultValue_; | |
607 | |
608 if (!(description_->flags & GPBFieldRepeated)) { | |
609 // We special handle data and strings. If they are nil, we replace them | |
610 // with empty string/empty data. | |
611 GPBDataType type = description_->dataType; | |
612 if (type == GPBDataTypeBytes && value.valueData == nil) { | |
613 value.valueData = GPBEmptyNSData(); | |
614 } else if (type == GPBDataTypeString && value.valueString == nil) { | |
615 value.valueString = @""; | |
616 } | |
617 } | |
618 return value; | |
619 } | |
620 | |
621 - (NSString *)textFormatName { | |
622 if ((description_->flags & GPBFieldTextFormatNameCustom) != 0) { | |
623 NSValue *extraInfoValue = | |
624 objc_getAssociatedObject(self, &kTextFormatExtraValueKey); | |
625 // Support can be left out at generation time. | |
626 if (!extraInfoValue) { | |
627 return nil; | |
628 } | |
629 const uint8_t *extraTextFormatInfo = [extraInfoValue pointerValue]; | |
630 return GPBDecodeTextFormatName(extraTextFormatInfo, GPBFieldNumber(self), | |
631 self.name); | |
632 } | |
633 | |
634 // The logic here has to match SetCommonFieldVariables() from | |
635 // objectivec_field.cc in the proto compiler. | |
636 NSString *name = self.name; | |
637 NSUInteger len = [name length]; | |
638 | |
639 // Remove the "_p" added to reserved names. | |
640 if ([name hasSuffix:@"_p"]) { | |
641 name = [name substringToIndex:(len - 2)]; | |
642 len = [name length]; | |
643 } | |
644 | |
645 // Remove "Array" from the end for repeated fields. | |
646 if (((description_->flags & GPBFieldRepeated) != 0) && | |
647 [name hasSuffix:@"Array"]) { | |
648 name = [name substringToIndex:(len - 5)]; | |
649 len = [name length]; | |
650 } | |
651 | |
652 // Groups vs. other fields. | |
653 if (description_->dataType == GPBDataTypeGroup) { | |
654 // Just capitalize the first letter. | |
655 unichar firstChar = [name characterAtIndex:0]; | |
656 if (firstChar >= 'a' && firstChar <= 'z') { | |
657 NSString *firstCharString = | |
658 [NSString stringWithFormat:@"%C", (unichar)(firstChar - 'a' + 'A')]; | |
659 NSString *result = | |
660 [name stringByReplacingCharactersInRange:NSMakeRange(0, 1) | |
661 withString:firstCharString]; | |
662 return result; | |
663 } | |
664 return name; | |
665 | |
666 } else { | |
667 // Undo the CamelCase. | |
668 NSMutableString *result = [NSMutableString stringWithCapacity:len]; | |
669 for (NSUInteger i = 0; i < len; i++) { | |
670 unichar c = [name characterAtIndex:i]; | |
671 if (c >= 'A' && c <= 'Z') { | |
672 if (i > 0) { | |
673 [result appendFormat:@"_%C", (unichar)(c - 'A' + 'a')]; | |
674 } else { | |
675 [result appendFormat:@"%C", c]; | |
676 } | |
677 } else { | |
678 [result appendFormat:@"%C", c]; | |
679 } | |
680 } | |
681 return result; | |
682 } | |
683 } | |
684 | |
685 @end | |
686 | |
687 @implementation GPBEnumDescriptor { | |
688 NSString *name_; | |
689 GPBMessageEnumValueDescription *valueDescriptions_; | |
690 NSUInteger valueDescriptionsCount_; | |
691 GPBEnumValidationFunc enumVerifier_; | |
692 const uint8_t *extraTextFormatInfo_; | |
693 } | |
694 | |
695 @synthesize name = name_; | |
696 @synthesize enumVerifier = enumVerifier_; | |
697 | |
698 + (instancetype) | |
699 allocDescriptorForName:(NSString *)name | |
700 values:(GPBMessageEnumValueDescription *)valueDescriptions | |
701 valueCount:(NSUInteger)valueCount | |
702 enumVerifier:(GPBEnumValidationFunc)enumVerifier { | |
703 GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name | |
704 values:valueDescriptions | |
705 valueCount:valueCount | |
706 enumVerifier:enumVerifier]; | |
707 return descriptor; | |
708 } | |
709 | |
710 + (instancetype) | |
711 allocDescriptorForName:(NSString *)name | |
712 values:(GPBMessageEnumValueDescription *)valueDescriptions | |
713 valueCount:(NSUInteger)valueCount | |
714 enumVerifier:(GPBEnumValidationFunc)enumVerifier | |
715 extraTextFormatInfo:(const char *)extraTextFormatInfo { | |
716 // Call the common case. | |
717 GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name | |
718 values:valueDescriptions | |
719 valueCount:valueCount | |
720 enumVerifier:enumVerifier]; | |
721 // Set the extra info. | |
722 descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo; | |
723 return descriptor; | |
724 } | |
725 | |
726 - (instancetype)initWithName:(NSString *)name | |
727 values:(GPBMessageEnumValueDescription *)valueDescriptions | |
728 valueCount:(NSUInteger)valueCount | |
729 enumVerifier:(GPBEnumValidationFunc)enumVerifier { | |
730 if ((self = [super init])) { | |
731 name_ = [name copy]; | |
732 valueDescriptions_ = valueDescriptions; | |
733 valueDescriptionsCount_ = valueCount; | |
734 enumVerifier_ = enumVerifier; | |
735 } | |
736 return self; | |
737 } | |
738 | |
739 - (NSString *)enumNameForValue:(int32_t)number { | |
740 for (NSUInteger i = 0; i < valueDescriptionsCount_; ++i) { | |
741 GPBMessageEnumValueDescription *scan = &valueDescriptions_[i]; | |
742 if ((scan->number == number) && (scan->name != NULL)) { | |
743 NSString *fullName = | |
744 [NSString stringWithFormat:@"%@_%s", name_, scan->name]; | |
745 return fullName; | |
746 } | |
747 } | |
748 return nil; | |
749 } | |
750 | |
751 - (BOOL)getValue:(int32_t *)outValue forEnumName:(NSString *)name { | |
752 // Must have the prefix. | |
753 NSUInteger prefixLen = name_.length + 1; | |
754 if ((name.length <= prefixLen) || ![name hasPrefix:name_] || | |
755 ([name characterAtIndex:prefixLen - 1] != '_')) { | |
756 return NO; | |
757 } | |
758 | |
759 // Skip over the prefix. | |
760 const char *nameAsCStr = [name UTF8String]; | |
761 nameAsCStr += prefixLen; | |
762 | |
763 // Find it. | |
764 for (NSUInteger i = 0; i < valueDescriptionsCount_; ++i) { | |
765 GPBMessageEnumValueDescription *scan = &valueDescriptions_[i]; | |
766 if ((scan->name != NULL) && (strcmp(nameAsCStr, scan->name) == 0)) { | |
767 if (outValue) { | |
768 *outValue = scan->number; | |
769 } | |
770 return YES; | |
771 } | |
772 } | |
773 return NO; | |
774 } | |
775 | |
776 - (void)dealloc { | |
777 [name_ release]; | |
778 [super dealloc]; | |
779 } | |
780 | |
781 - (NSString *)textFormatNameForValue:(int32_t)number { | |
782 // Find the EnumValue descriptor and its index. | |
783 GPBMessageEnumValueDescription *valueDescriptor = NULL; | |
784 NSUInteger valueDescriptorIndex; | |
785 for (valueDescriptorIndex = 0; valueDescriptorIndex < valueDescriptionsCount_; | |
786 ++valueDescriptorIndex) { | |
787 GPBMessageEnumValueDescription *scan = | |
788 &valueDescriptions_[valueDescriptorIndex]; | |
789 if (scan->number == number) { | |
790 valueDescriptor = scan; | |
791 break; | |
792 } | |
793 } | |
794 | |
795 // If we didn't find it, or names were disable at proto compile time, nothing | |
796 // we can do. | |
797 if (!valueDescriptor || !valueDescriptor->name) { | |
798 return nil; | |
799 } | |
800 | |
801 NSString *result = nil; | |
802 // Naming adds an underscore between enum name and value name, skip that also. | |
803 NSString *shortName = @(valueDescriptor->name); | |
804 | |
805 // See if it is in the map of special format handling. | |
806 if (extraTextFormatInfo_) { | |
807 result = GPBDecodeTextFormatName(extraTextFormatInfo_, | |
808 (int32_t)valueDescriptorIndex, shortName); | |
809 } | |
810 // Logic here needs to match what objectivec_enum.cc does in the proto | |
811 // compiler. | |
812 if (result == nil) { | |
813 NSUInteger len = [shortName length]; | |
814 NSMutableString *worker = [NSMutableString stringWithCapacity:len]; | |
815 for (NSUInteger i = 0; i < len; i++) { | |
816 unichar c = [shortName characterAtIndex:i]; | |
817 if (i > 0 && c >= 'A' && c <= 'Z') { | |
818 [worker appendString:@"_"]; | |
819 } | |
820 [worker appendFormat:@"%c", toupper((char)c)]; | |
821 } | |
822 result = worker; | |
823 } | |
824 return result; | |
825 } | |
826 | |
827 @end | |
828 | |
829 @implementation GPBExtensionDescriptor { | |
830 GPBGenericValue defaultValue_; | |
831 } | |
832 | |
833 @synthesize containingMessageClass = containingMessageClass_; | |
834 | |
835 - (instancetype)initWithExtensionDescription: | |
836 (GPBExtensionDescription *)description { | |
837 if ((self = [super init])) { | |
838 description_ = description; | |
839 | |
840 #if DEBUG | |
841 const char *className = description->messageOrGroupClassName; | |
842 if (className) { | |
843 NSAssert(objc_lookUpClass(className) != Nil, | |
844 @"Class %s not defined", className); | |
845 } | |
846 #endif | |
847 | |
848 if (description->extendedClass) { | |
849 Class containingClass = objc_lookUpClass(description->extendedClass); | |
850 NSAssert(containingClass, @"Class %s not defined", | |
851 description->extendedClass); | |
852 containingMessageClass_ = containingClass; | |
853 } | |
854 | |
855 GPBDataType type = description_->dataType; | |
856 if (type == GPBDataTypeBytes) { | |
857 // Data stored as a length prefixed c-string in descriptor records. | |
858 const uint8_t *bytes = | |
859 (const uint8_t *)description->defaultValue.valueData; | |
860 if (bytes) { | |
861 uint32_t length = *((uint32_t *)bytes); | |
862 // The length is stored in network byte order. | |
863 length = ntohl(length); | |
864 bytes += sizeof(length); | |
865 defaultValue_.valueData = | |
866 [[NSData alloc] initWithBytes:bytes length:length]; | |
867 } | |
868 } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) { | |
869 // The default is looked up in -defaultValue instead since extensions | |
870 // aren't common, we avoid the hit startup hit and it avoid initialization | |
871 // order issues. | |
872 } else { | |
873 defaultValue_ = description->defaultValue; | |
874 } | |
875 } | |
876 return self; | |
877 } | |
878 | |
879 - (void)dealloc { | |
880 if ((description_->dataType == GPBDataTypeBytes) && | |
881 !GPBExtensionIsRepeated(description_)) { | |
882 [defaultValue_.valueData release]; | |
883 } | |
884 [super dealloc]; | |
885 } | |
886 | |
887 - (instancetype)copyWithZone:(NSZone *)zone { | |
888 #pragma unused(zone) | |
889 // Immutable. | |
890 return [self retain]; | |
891 } | |
892 | |
893 - (NSString *)singletonName { | |
894 return @(description_->singletonName); | |
895 } | |
896 | |
897 - (const char *)singletonNameC { | |
898 return description_->singletonName; | |
899 } | |
900 | |
901 - (uint32_t)fieldNumber { | |
902 return description_->fieldNumber; | |
903 } | |
904 | |
905 - (GPBDataType)dataType { | |
906 return description_->dataType; | |
907 } | |
908 | |
909 - (GPBWireFormat)wireType { | |
910 return GPBWireFormatForType(description_->dataType, | |
911 GPBExtensionIsPacked(description_)); | |
912 } | |
913 | |
914 - (GPBWireFormat)alternateWireType { | |
915 NSAssert(GPBExtensionIsRepeated(description_), | |
916 @"Only valid on repeated extensions"); | |
917 return GPBWireFormatForType(description_->dataType, | |
918 !GPBExtensionIsPacked(description_)); | |
919 } | |
920 | |
921 - (BOOL)isRepeated { | |
922 return GPBExtensionIsRepeated(description_); | |
923 } | |
924 | |
925 - (BOOL)isMap { | |
926 return (description_->options & GPBFieldMapKeyMask) != 0; | |
927 } | |
928 | |
929 - (BOOL)isPackable { | |
930 return GPBExtensionIsPacked(description_); | |
931 } | |
932 | |
933 - (Class)msgClass { | |
934 return objc_getClass(description_->messageOrGroupClassName); | |
935 } | |
936 | |
937 - (GPBEnumDescriptor *)enumDescriptor { | |
938 if (description_->dataType == GPBDataTypeEnum) { | |
939 GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc(); | |
940 return enumDescriptor; | |
941 } | |
942 return nil; | |
943 } | |
944 | |
945 - (id)defaultValue { | |
946 if (GPBExtensionIsRepeated(description_)) { | |
947 return nil; | |
948 } | |
949 | |
950 switch (description_->dataType) { | |
951 case GPBDataTypeBool: | |
952 return @(defaultValue_.valueBool); | |
953 case GPBDataTypeFloat: | |
954 return @(defaultValue_.valueFloat); | |
955 case GPBDataTypeDouble: | |
956 return @(defaultValue_.valueDouble); | |
957 case GPBDataTypeInt32: | |
958 case GPBDataTypeSInt32: | |
959 case GPBDataTypeEnum: | |
960 case GPBDataTypeSFixed32: | |
961 return @(defaultValue_.valueInt32); | |
962 case GPBDataTypeInt64: | |
963 case GPBDataTypeSInt64: | |
964 case GPBDataTypeSFixed64: | |
965 return @(defaultValue_.valueInt64); | |
966 case GPBDataTypeUInt32: | |
967 case GPBDataTypeFixed32: | |
968 return @(defaultValue_.valueUInt32); | |
969 case GPBDataTypeUInt64: | |
970 case GPBDataTypeFixed64: | |
971 return @(defaultValue_.valueUInt64); | |
972 case GPBDataTypeBytes: | |
973 // Like message fields, the default is zero length data. | |
974 return (defaultValue_.valueData ? defaultValue_.valueData | |
975 : GPBEmptyNSData()); | |
976 case GPBDataTypeString: | |
977 // Like message fields, the default is zero length string. | |
978 return (defaultValue_.valueString ? defaultValue_.valueString : @""); | |
979 case GPBDataTypeGroup: | |
980 case GPBDataTypeMessage: | |
981 return nil; | |
982 } | |
983 } | |
984 | |
985 - (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other { | |
986 int32_t selfNumber = description_->fieldNumber; | |
987 int32_t otherNumber = other->description_->fieldNumber; | |
988 if (selfNumber < otherNumber) { | |
989 return NSOrderedAscending; | |
990 } else if (selfNumber == otherNumber) { | |
991 return NSOrderedSame; | |
992 } else { | |
993 return NSOrderedDescending; | |
994 } | |
995 } | |
996 | |
997 @end | |
OLD | NEW |