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 "GPBMessage_PackagePrivate.h" | |
32 | |
33 #import <objc/runtime.h> | |
34 #import <objc/message.h> | |
35 | |
36 #import "GPBArray_PackagePrivate.h" | |
37 #import "GPBCodedInputStream_PackagePrivate.h" | |
38 #import "GPBCodedOutputStream.h" | |
39 #import "GPBDescriptor_PackagePrivate.h" | |
40 #import "GPBDictionary_PackagePrivate.h" | |
41 #import "GPBExtensionInternals.h" | |
42 #import "GPBExtensionRegistry.h" | |
43 #import "GPBRootObject_PackagePrivate.h" | |
44 #import "GPBUnknownFieldSet_PackagePrivate.h" | |
45 #import "GPBUtilities_PackagePrivate.h" | |
46 | |
47 NSString *const GPBMessageErrorDomain = | |
48 GPBNSStringifySymbol(GPBMessageErrorDomain); | |
49 | |
50 #ifdef DEBUG | |
51 NSString *const GPBExceptionMessageKey = | |
52 GPBNSStringifySymbol(GPBExceptionMessage); | |
53 #endif // DEBUG | |
54 | |
55 static NSString *const kGPBDataCoderKey = @"GPBData"; | |
56 | |
57 #ifndef _GPBCompileAssert | |
58 #define _GPBCompileAssertSymbolInner(line, msg) _GPBCompileAssert ## line ## __
## msg | |
59 #define _GPBCompileAssertSymbol(line, msg) _GPBCompileAssertSymbolInner(line, ms
g) | |
60 #define _GPBCompileAssert(test, msg) \ | |
61 typedef char _GPBCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] | |
62 #endif // _GPBCompileAssert | |
63 | |
64 // | |
65 // PLEASE REMEMBER: | |
66 // | |
67 // This is the base class for *all* messages generated, so any selector defined, | |
68 // *public* or *private* could end up colliding with a proto message field. So | |
69 // avoid using selectors that could match a property, use C functions to hide | |
70 // them, etc. | |
71 // | |
72 | |
73 @interface GPBMessage () { | |
74 @package | |
75 GPBUnknownFieldSet *unknownFields_; | |
76 NSMutableDictionary *extensionMap_; | |
77 NSMutableDictionary *autocreatedExtensionMap_; | |
78 | |
79 // If the object was autocreated, we remember the creator so that if we get | |
80 // mutated, we can inform the creator to make our field visible. | |
81 GPBMessage *autocreator_; | |
82 GPBFieldDescriptor *autocreatorField_; | |
83 GPBExtensionDescriptor *autocreatorExtension_; | |
84 } | |
85 @end | |
86 | |
87 static id CreateArrayForField(GPBFieldDescriptor *field, | |
88 GPBMessage *autocreator) | |
89 __attribute__((ns_returns_retained)); | |
90 static id GetOrCreateArrayIvarWithField(GPBMessage *self, | |
91 GPBFieldDescriptor *field, | |
92 GPBFileSyntax syntax); | |
93 static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field); | |
94 static id CreateMapForField(GPBFieldDescriptor *field, | |
95 GPBMessage *autocreator) | |
96 __attribute__((ns_returns_retained)); | |
97 static id GetOrCreateMapIvarWithField(GPBMessage *self, | |
98 GPBFieldDescriptor *field, | |
99 GPBFileSyntax syntax); | |
100 static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field); | |
101 static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap, | |
102 NSZone *zone) | |
103 __attribute__((ns_returns_retained)); | |
104 | |
105 static NSError *MessageError(NSInteger code, NSDictionary *userInfo) { | |
106 return [NSError errorWithDomain:GPBMessageErrorDomain | |
107 code:code | |
108 userInfo:userInfo]; | |
109 } | |
110 | |
111 static NSError *MessageErrorWithReason(NSInteger code, NSString *reason) { | |
112 NSDictionary *userInfo = nil; | |
113 if ([reason length]) { | |
114 userInfo = @{ @"Reason" : reason }; | |
115 } | |
116 return MessageError(code, userInfo); | |
117 } | |
118 | |
119 | |
120 static void CheckExtension(GPBMessage *self, | |
121 GPBExtensionDescriptor *extension) { | |
122 if ([self class] != extension.containingMessageClass) { | |
123 [NSException | |
124 raise:NSInvalidArgumentException | |
125 format:@"Extension %@ used on wrong class (%@ instead of %@)", | |
126 extension.singletonName, | |
127 [self class], extension.containingMessageClass]; | |
128 } | |
129 } | |
130 | |
131 static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap, | |
132 NSZone *zone) { | |
133 if (extensionMap.count == 0) { | |
134 return nil; | |
135 } | |
136 NSMutableDictionary *result = [[NSMutableDictionary allocWithZone:zone] | |
137 initWithCapacity:extensionMap.count]; | |
138 | |
139 for (GPBExtensionDescriptor *extension in extensionMap) { | |
140 id value = [extensionMap objectForKey:extension]; | |
141 BOOL isMessageExtension = GPBExtensionIsMessage(extension); | |
142 | |
143 if (extension.repeated) { | |
144 if (isMessageExtension) { | |
145 NSMutableArray *list = | |
146 [[NSMutableArray alloc] initWithCapacity:[value count]]; | |
147 for (GPBMessage *listValue in value) { | |
148 GPBMessage *copiedValue = [listValue copyWithZone:zone]; | |
149 [list addObject:copiedValue]; | |
150 [copiedValue release]; | |
151 } | |
152 [result setObject:list forKey:extension]; | |
153 [list release]; | |
154 } else { | |
155 NSMutableArray *copiedValue = [value mutableCopyWithZone:zone]; | |
156 [result setObject:copiedValue forKey:extension]; | |
157 [copiedValue release]; | |
158 } | |
159 } else { | |
160 if (isMessageExtension) { | |
161 GPBMessage *copiedValue = [value copyWithZone:zone]; | |
162 [result setObject:copiedValue forKey:extension]; | |
163 [copiedValue release]; | |
164 } else { | |
165 [result setObject:value forKey:extension]; | |
166 } | |
167 } | |
168 } | |
169 | |
170 return result; | |
171 } | |
172 | |
173 static id CreateArrayForField(GPBFieldDescriptor *field, | |
174 GPBMessage *autocreator) { | |
175 id result; | |
176 GPBDataType fieldDataType = GPBGetFieldDataType(field); | |
177 switch (fieldDataType) { | |
178 case GPBDataTypeBool: | |
179 result = [[GPBBoolArray alloc] init]; | |
180 break; | |
181 case GPBDataTypeFixed32: | |
182 case GPBDataTypeUInt32: | |
183 result = [[GPBUInt32Array alloc] init]; | |
184 break; | |
185 case GPBDataTypeInt32: | |
186 case GPBDataTypeSFixed32: | |
187 case GPBDataTypeSInt32: | |
188 result = [[GPBInt32Array alloc] init]; | |
189 break; | |
190 case GPBDataTypeFixed64: | |
191 case GPBDataTypeUInt64: | |
192 result = [[GPBUInt64Array alloc] init]; | |
193 break; | |
194 case GPBDataTypeInt64: | |
195 case GPBDataTypeSFixed64: | |
196 case GPBDataTypeSInt64: | |
197 result = [[GPBInt64Array alloc] init]; | |
198 break; | |
199 case GPBDataTypeFloat: | |
200 result = [[GPBFloatArray alloc] init]; | |
201 break; | |
202 case GPBDataTypeDouble: | |
203 result = [[GPBDoubleArray alloc] init]; | |
204 break; | |
205 | |
206 case GPBDataTypeEnum: | |
207 result = [[GPBEnumArray alloc] | |
208 initWithValidationFunction:field.enumDescriptor.enumVerifier]; | |
209 break; | |
210 | |
211 case GPBDataTypeBytes: | |
212 case GPBDataTypeGroup: | |
213 case GPBDataTypeMessage: | |
214 case GPBDataTypeString: | |
215 if (autocreator) { | |
216 result = [[GPBAutocreatedArray alloc] init]; | |
217 } else { | |
218 result = [[NSMutableArray alloc] init]; | |
219 } | |
220 break; | |
221 } | |
222 | |
223 if (autocreator) { | |
224 if (GPBDataTypeIsObject(fieldDataType)) { | |
225 GPBAutocreatedArray *autoArray = result; | |
226 autoArray->_autocreator = autocreator; | |
227 } else { | |
228 GPBInt32Array *gpbArray = result; | |
229 gpbArray->_autocreator = autocreator; | |
230 } | |
231 } | |
232 | |
233 return result; | |
234 } | |
235 | |
236 static id CreateMapForField(GPBFieldDescriptor *field, | |
237 GPBMessage *autocreator) { | |
238 id result; | |
239 GPBDataType keyDataType = field.mapKeyDataType; | |
240 GPBDataType valueDataType = GPBGetFieldDataType(field); | |
241 switch (keyDataType) { | |
242 case GPBDataTypeBool: | |
243 switch (valueDataType) { | |
244 case GPBDataTypeBool: | |
245 result = [[GPBBoolBoolDictionary alloc] init]; | |
246 break; | |
247 case GPBDataTypeFixed32: | |
248 case GPBDataTypeUInt32: | |
249 result = [[GPBBoolUInt32Dictionary alloc] init]; | |
250 break; | |
251 case GPBDataTypeInt32: | |
252 case GPBDataTypeSFixed32: | |
253 case GPBDataTypeSInt32: | |
254 result = [[GPBBoolInt32Dictionary alloc] init]; | |
255 break; | |
256 case GPBDataTypeFixed64: | |
257 case GPBDataTypeUInt64: | |
258 result = [[GPBBoolUInt64Dictionary alloc] init]; | |
259 break; | |
260 case GPBDataTypeInt64: | |
261 case GPBDataTypeSFixed64: | |
262 case GPBDataTypeSInt64: | |
263 result = [[GPBBoolInt64Dictionary alloc] init]; | |
264 break; | |
265 case GPBDataTypeFloat: | |
266 result = [[GPBBoolFloatDictionary alloc] init]; | |
267 break; | |
268 case GPBDataTypeDouble: | |
269 result = [[GPBBoolDoubleDictionary alloc] init]; | |
270 break; | |
271 case GPBDataTypeEnum: | |
272 result = [[GPBBoolEnumDictionary alloc] | |
273 initWithValidationFunction:field.enumDescriptor.enumVerifier]; | |
274 break; | |
275 case GPBDataTypeBytes: | |
276 case GPBDataTypeMessage: | |
277 case GPBDataTypeString: | |
278 result = [[GPBBoolObjectDictionary alloc] init]; | |
279 break; | |
280 case GPBDataTypeGroup: | |
281 NSCAssert(NO, @"shouldn't happen"); | |
282 return nil; | |
283 } | |
284 break; | |
285 case GPBDataTypeFixed32: | |
286 case GPBDataTypeUInt32: | |
287 switch (valueDataType) { | |
288 case GPBDataTypeBool: | |
289 result = [[GPBUInt32BoolDictionary alloc] init]; | |
290 break; | |
291 case GPBDataTypeFixed32: | |
292 case GPBDataTypeUInt32: | |
293 result = [[GPBUInt32UInt32Dictionary alloc] init]; | |
294 break; | |
295 case GPBDataTypeInt32: | |
296 case GPBDataTypeSFixed32: | |
297 case GPBDataTypeSInt32: | |
298 result = [[GPBUInt32Int32Dictionary alloc] init]; | |
299 break; | |
300 case GPBDataTypeFixed64: | |
301 case GPBDataTypeUInt64: | |
302 result = [[GPBUInt32UInt64Dictionary alloc] init]; | |
303 break; | |
304 case GPBDataTypeInt64: | |
305 case GPBDataTypeSFixed64: | |
306 case GPBDataTypeSInt64: | |
307 result = [[GPBUInt32Int64Dictionary alloc] init]; | |
308 break; | |
309 case GPBDataTypeFloat: | |
310 result = [[GPBUInt32FloatDictionary alloc] init]; | |
311 break; | |
312 case GPBDataTypeDouble: | |
313 result = [[GPBUInt32DoubleDictionary alloc] init]; | |
314 break; | |
315 case GPBDataTypeEnum: | |
316 result = [[GPBUInt32EnumDictionary alloc] | |
317 initWithValidationFunction:field.enumDescriptor.enumVerifier]; | |
318 break; | |
319 case GPBDataTypeBytes: | |
320 case GPBDataTypeMessage: | |
321 case GPBDataTypeString: | |
322 result = [[GPBUInt32ObjectDictionary alloc] init]; | |
323 break; | |
324 case GPBDataTypeGroup: | |
325 NSCAssert(NO, @"shouldn't happen"); | |
326 return nil; | |
327 } | |
328 break; | |
329 case GPBDataTypeInt32: | |
330 case GPBDataTypeSFixed32: | |
331 case GPBDataTypeSInt32: | |
332 switch (valueDataType) { | |
333 case GPBDataTypeBool: | |
334 result = [[GPBInt32BoolDictionary alloc] init]; | |
335 break; | |
336 case GPBDataTypeFixed32: | |
337 case GPBDataTypeUInt32: | |
338 result = [[GPBInt32UInt32Dictionary alloc] init]; | |
339 break; | |
340 case GPBDataTypeInt32: | |
341 case GPBDataTypeSFixed32: | |
342 case GPBDataTypeSInt32: | |
343 result = [[GPBInt32Int32Dictionary alloc] init]; | |
344 break; | |
345 case GPBDataTypeFixed64: | |
346 case GPBDataTypeUInt64: | |
347 result = [[GPBInt32UInt64Dictionary alloc] init]; | |
348 break; | |
349 case GPBDataTypeInt64: | |
350 case GPBDataTypeSFixed64: | |
351 case GPBDataTypeSInt64: | |
352 result = [[GPBInt32Int64Dictionary alloc] init]; | |
353 break; | |
354 case GPBDataTypeFloat: | |
355 result = [[GPBInt32FloatDictionary alloc] init]; | |
356 break; | |
357 case GPBDataTypeDouble: | |
358 result = [[GPBInt32DoubleDictionary alloc] init]; | |
359 break; | |
360 case GPBDataTypeEnum: | |
361 result = [[GPBInt32EnumDictionary alloc] | |
362 initWithValidationFunction:field.enumDescriptor.enumVerifier]; | |
363 break; | |
364 case GPBDataTypeBytes: | |
365 case GPBDataTypeMessage: | |
366 case GPBDataTypeString: | |
367 result = [[GPBInt32ObjectDictionary alloc] init]; | |
368 break; | |
369 case GPBDataTypeGroup: | |
370 NSCAssert(NO, @"shouldn't happen"); | |
371 return nil; | |
372 } | |
373 break; | |
374 case GPBDataTypeFixed64: | |
375 case GPBDataTypeUInt64: | |
376 switch (valueDataType) { | |
377 case GPBDataTypeBool: | |
378 result = [[GPBUInt64BoolDictionary alloc] init]; | |
379 break; | |
380 case GPBDataTypeFixed32: | |
381 case GPBDataTypeUInt32: | |
382 result = [[GPBUInt64UInt32Dictionary alloc] init]; | |
383 break; | |
384 case GPBDataTypeInt32: | |
385 case GPBDataTypeSFixed32: | |
386 case GPBDataTypeSInt32: | |
387 result = [[GPBUInt64Int32Dictionary alloc] init]; | |
388 break; | |
389 case GPBDataTypeFixed64: | |
390 case GPBDataTypeUInt64: | |
391 result = [[GPBUInt64UInt64Dictionary alloc] init]; | |
392 break; | |
393 case GPBDataTypeInt64: | |
394 case GPBDataTypeSFixed64: | |
395 case GPBDataTypeSInt64: | |
396 result = [[GPBUInt64Int64Dictionary alloc] init]; | |
397 break; | |
398 case GPBDataTypeFloat: | |
399 result = [[GPBUInt64FloatDictionary alloc] init]; | |
400 break; | |
401 case GPBDataTypeDouble: | |
402 result = [[GPBUInt64DoubleDictionary alloc] init]; | |
403 break; | |
404 case GPBDataTypeEnum: | |
405 result = [[GPBUInt64EnumDictionary alloc] | |
406 initWithValidationFunction:field.enumDescriptor.enumVerifier]; | |
407 break; | |
408 case GPBDataTypeBytes: | |
409 case GPBDataTypeMessage: | |
410 case GPBDataTypeString: | |
411 result = [[GPBUInt64ObjectDictionary alloc] init]; | |
412 break; | |
413 case GPBDataTypeGroup: | |
414 NSCAssert(NO, @"shouldn't happen"); | |
415 return nil; | |
416 } | |
417 break; | |
418 case GPBDataTypeInt64: | |
419 case GPBDataTypeSFixed64: | |
420 case GPBDataTypeSInt64: | |
421 switch (valueDataType) { | |
422 case GPBDataTypeBool: | |
423 result = [[GPBInt64BoolDictionary alloc] init]; | |
424 break; | |
425 case GPBDataTypeFixed32: | |
426 case GPBDataTypeUInt32: | |
427 result = [[GPBInt64UInt32Dictionary alloc] init]; | |
428 break; | |
429 case GPBDataTypeInt32: | |
430 case GPBDataTypeSFixed32: | |
431 case GPBDataTypeSInt32: | |
432 result = [[GPBInt64Int32Dictionary alloc] init]; | |
433 break; | |
434 case GPBDataTypeFixed64: | |
435 case GPBDataTypeUInt64: | |
436 result = [[GPBInt64UInt64Dictionary alloc] init]; | |
437 break; | |
438 case GPBDataTypeInt64: | |
439 case GPBDataTypeSFixed64: | |
440 case GPBDataTypeSInt64: | |
441 result = [[GPBInt64Int64Dictionary alloc] init]; | |
442 break; | |
443 case GPBDataTypeFloat: | |
444 result = [[GPBInt64FloatDictionary alloc] init]; | |
445 break; | |
446 case GPBDataTypeDouble: | |
447 result = [[GPBInt64DoubleDictionary alloc] init]; | |
448 break; | |
449 case GPBDataTypeEnum: | |
450 result = [[GPBInt64EnumDictionary alloc] | |
451 initWithValidationFunction:field.enumDescriptor.enumVerifier]; | |
452 break; | |
453 case GPBDataTypeBytes: | |
454 case GPBDataTypeMessage: | |
455 case GPBDataTypeString: | |
456 result = [[GPBInt64ObjectDictionary alloc] init]; | |
457 break; | |
458 case GPBDataTypeGroup: | |
459 NSCAssert(NO, @"shouldn't happen"); | |
460 return nil; | |
461 } | |
462 break; | |
463 case GPBDataTypeString: | |
464 switch (valueDataType) { | |
465 case GPBDataTypeBool: | |
466 result = [[GPBStringBoolDictionary alloc] init]; | |
467 break; | |
468 case GPBDataTypeFixed32: | |
469 case GPBDataTypeUInt32: | |
470 result = [[GPBStringUInt32Dictionary alloc] init]; | |
471 break; | |
472 case GPBDataTypeInt32: | |
473 case GPBDataTypeSFixed32: | |
474 case GPBDataTypeSInt32: | |
475 result = [[GPBStringInt32Dictionary alloc] init]; | |
476 break; | |
477 case GPBDataTypeFixed64: | |
478 case GPBDataTypeUInt64: | |
479 result = [[GPBStringUInt64Dictionary alloc] init]; | |
480 break; | |
481 case GPBDataTypeInt64: | |
482 case GPBDataTypeSFixed64: | |
483 case GPBDataTypeSInt64: | |
484 result = [[GPBStringInt64Dictionary alloc] init]; | |
485 break; | |
486 case GPBDataTypeFloat: | |
487 result = [[GPBStringFloatDictionary alloc] init]; | |
488 break; | |
489 case GPBDataTypeDouble: | |
490 result = [[GPBStringDoubleDictionary alloc] init]; | |
491 break; | |
492 case GPBDataTypeEnum: | |
493 result = [[GPBStringEnumDictionary alloc] | |
494 initWithValidationFunction:field.enumDescriptor.enumVerifier]; | |
495 break; | |
496 case GPBDataTypeBytes: | |
497 case GPBDataTypeMessage: | |
498 case GPBDataTypeString: | |
499 if (autocreator) { | |
500 result = [[GPBAutocreatedDictionary alloc] init]; | |
501 } else { | |
502 result = [[NSMutableDictionary alloc] init]; | |
503 } | |
504 break; | |
505 case GPBDataTypeGroup: | |
506 NSCAssert(NO, @"shouldn't happen"); | |
507 return nil; | |
508 } | |
509 break; | |
510 | |
511 case GPBDataTypeFloat: | |
512 case GPBDataTypeDouble: | |
513 case GPBDataTypeEnum: | |
514 case GPBDataTypeBytes: | |
515 case GPBDataTypeGroup: | |
516 case GPBDataTypeMessage: | |
517 NSCAssert(NO, @"shouldn't happen"); | |
518 return nil; | |
519 } | |
520 | |
521 if (autocreator) { | |
522 if ((keyDataType == GPBDataTypeString) && | |
523 GPBDataTypeIsObject(valueDataType)) { | |
524 GPBAutocreatedDictionary *autoDict = result; | |
525 autoDict->_autocreator = autocreator; | |
526 } else { | |
527 GPBInt32Int32Dictionary *gpbDict = result; | |
528 gpbDict->_autocreator = autocreator; | |
529 } | |
530 } | |
531 | |
532 return result; | |
533 } | |
534 | |
535 #if !defined(__clang_analyzer__) | |
536 // These functions are blocked from the analyzer because the analyzer sees the | |
537 // GPBSetRetainedObjectIvarWithFieldInternal() call as consuming the array/map, | |
538 // so use of the array/map after the call returns is flagged as a use after | |
539 // free. | |
540 // But GPBSetRetainedObjectIvarWithFieldInternal() is "consuming" the retain | |
541 // count be holding onto the object (it is transfering it), the object is | |
542 // still valid after returning from the call. The other way to avoid this | |
543 // would be to add a -retain/-autorelease, but that would force every | |
544 // repeated/map field parsed into the autorelease pool which is both a memory | |
545 // and performance hit. | |
546 | |
547 static id GetOrCreateArrayIvarWithField(GPBMessage *self, | |
548 GPBFieldDescriptor *field, | |
549 GPBFileSyntax syntax) { | |
550 id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
551 if (!array) { | |
552 // No lock needed, this is called from places expecting to mutate | |
553 // so no threading protection is needed. | |
554 array = CreateArrayForField(field, nil); | |
555 GPBSetRetainedObjectIvarWithFieldInternal(self, field, array, syntax); | |
556 } | |
557 return array; | |
558 } | |
559 | |
560 // This is like GPBGetObjectIvarWithField(), but for arrays, it should | |
561 // only be used to wire the method into the class. | |
562 static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { | |
563 id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
564 if (!array) { | |
565 // Check again after getting the lock. | |
566 OSSpinLockLock(&self->readOnlyMutex_); | |
567 array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
568 if (!array) { | |
569 array = CreateArrayForField(field, self); | |
570 GPBSetAutocreatedRetainedObjectIvarWithField(self, field, array); | |
571 } | |
572 OSSpinLockUnlock(&self->readOnlyMutex_); | |
573 } | |
574 return array; | |
575 } | |
576 | |
577 static id GetOrCreateMapIvarWithField(GPBMessage *self, | |
578 GPBFieldDescriptor *field, | |
579 GPBFileSyntax syntax) { | |
580 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
581 if (!dict) { | |
582 // No lock needed, this is called from places expecting to mutate | |
583 // so no threading protection is needed. | |
584 dict = CreateMapForField(field, nil); | |
585 GPBSetRetainedObjectIvarWithFieldInternal(self, field, dict, syntax); | |
586 } | |
587 return dict; | |
588 } | |
589 | |
590 // This is like GPBGetObjectIvarWithField(), but for maps, it should | |
591 // only be used to wire the method into the class. | |
592 static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { | |
593 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
594 if (!dict) { | |
595 // Check again after getting the lock. | |
596 OSSpinLockLock(&self->readOnlyMutex_); | |
597 dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
598 if (!dict) { | |
599 dict = CreateMapForField(field, self); | |
600 GPBSetAutocreatedRetainedObjectIvarWithField(self, field, dict); | |
601 } | |
602 OSSpinLockUnlock(&self->readOnlyMutex_); | |
603 } | |
604 return dict; | |
605 } | |
606 | |
607 #endif // !defined(__clang_analyzer__) | |
608 | |
609 GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, | |
610 GPBMessage *autocreator, | |
611 GPBFieldDescriptor *field) { | |
612 GPBMessage *message = [[msgClass alloc] init]; | |
613 message->autocreator_ = autocreator; | |
614 message->autocreatorField_ = [field retain]; | |
615 return message; | |
616 } | |
617 | |
618 static GPBMessage *CreateMessageWithAutocreatorForExtension( | |
619 Class msgClass, GPBMessage *autocreator, GPBExtensionDescriptor *extension) | |
620 __attribute__((ns_returns_retained)); | |
621 | |
622 static GPBMessage *CreateMessageWithAutocreatorForExtension( | |
623 Class msgClass, GPBMessage *autocreator, | |
624 GPBExtensionDescriptor *extension) { | |
625 GPBMessage *message = [[msgClass alloc] init]; | |
626 message->autocreator_ = autocreator; | |
627 message->autocreatorExtension_ = [extension retain]; | |
628 return message; | |
629 } | |
630 | |
631 BOOL GPBWasMessageAutocreatedBy(GPBMessage *message, GPBMessage *parent) { | |
632 return (message->autocreator_ == parent); | |
633 } | |
634 | |
635 void GPBBecomeVisibleToAutocreator(GPBMessage *self) { | |
636 // Message objects that are implicitly created by accessing a message field | |
637 // are initially not visible via the hasX selector. This method makes them | |
638 // visible. | |
639 if (self->autocreator_) { | |
640 // This will recursively make all parent messages visible until it reaches a | |
641 // super-creator that's visible. | |
642 if (self->autocreatorField_) { | |
643 GPBFileSyntax syntax = [self->autocreator_ descriptor].file.syntax; | |
644 GPBSetObjectIvarWithFieldInternal(self->autocreator_, | |
645 self->autocreatorField_, self, syntax); | |
646 } else { | |
647 [self->autocreator_ setExtension:self->autocreatorExtension_ value:self]; | |
648 } | |
649 } | |
650 } | |
651 | |
652 void GPBAutocreatedArrayModified(GPBMessage *self, id array) { | |
653 // When one of our autocreated arrays adds elements, make it visible. | |
654 GPBDescriptor *descriptor = [[self class] descriptor]; | |
655 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
656 if (field.fieldType == GPBFieldTypeRepeated) { | |
657 id curArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
658 if (curArray == array) { | |
659 if (GPBFieldDataTypeIsObject(field)) { | |
660 GPBAutocreatedArray *autoArray = array; | |
661 autoArray->_autocreator = nil; | |
662 } else { | |
663 GPBInt32Array *gpbArray = array; | |
664 gpbArray->_autocreator = nil; | |
665 } | |
666 GPBBecomeVisibleToAutocreator(self); | |
667 return; | |
668 } | |
669 } | |
670 } | |
671 NSCAssert(NO, @"Unknown autocreated %@ for %@.", [array class], self); | |
672 } | |
673 | |
674 void GPBAutocreatedDictionaryModified(GPBMessage *self, id dictionary) { | |
675 // When one of our autocreated dicts adds elements, make it visible. | |
676 GPBDescriptor *descriptor = [[self class] descriptor]; | |
677 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
678 if (field.fieldType == GPBFieldTypeMap) { | |
679 id curDict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
680 if (curDict == dictionary) { | |
681 if ((field.mapKeyDataType == GPBDataTypeString) && | |
682 GPBFieldDataTypeIsObject(field)) { | |
683 GPBAutocreatedDictionary *autoDict = dictionary; | |
684 autoDict->_autocreator = nil; | |
685 } else { | |
686 GPBInt32Int32Dictionary *gpbDict = dictionary; | |
687 gpbDict->_autocreator = nil; | |
688 } | |
689 GPBBecomeVisibleToAutocreator(self); | |
690 return; | |
691 } | |
692 } | |
693 } | |
694 NSCAssert(NO, @"Unknown autocreated %@ for %@.", [dictionary class], self); | |
695 } | |
696 | |
697 void GPBClearMessageAutocreator(GPBMessage *self) { | |
698 if ((self == nil) || !self->autocreator_) { | |
699 return; | |
700 } | |
701 | |
702 #if DEBUG && !defined(NS_BLOCK_ASSERTIONS) | |
703 // Either the autocreator must have its "has" flag set to YES, or it must be | |
704 // NO and not equal to ourselves. | |
705 BOOL autocreatorHas = | |
706 (self->autocreatorField_ | |
707 ? GPBGetHasIvarField(self->autocreator_, self->autocreatorField_) | |
708 : [self->autocreator_ hasExtension:self->autocreatorExtension_]); | |
709 GPBMessage *autocreatorFieldValue = | |
710 (self->autocreatorField_ | |
711 ? GPBGetObjectIvarWithFieldNoAutocreate(self->autocreator_, | |
712 self->autocreatorField_) | |
713 : [self->autocreator_->autocreatedExtensionMap_ | |
714 objectForKey:self->autocreatorExtension_]); | |
715 NSCAssert(autocreatorHas || autocreatorFieldValue != self, | |
716 @"Cannot clear autocreator because it still refers to self, self: %@
.", | |
717 self); | |
718 | |
719 #endif // DEBUG && !defined(NS_BLOCK_ASSERTIONS) | |
720 | |
721 self->autocreator_ = nil; | |
722 [self->autocreatorField_ release]; | |
723 self->autocreatorField_ = nil; | |
724 [self->autocreatorExtension_ release]; | |
725 self->autocreatorExtension_ = nil; | |
726 } | |
727 | |
728 static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { | |
729 if (!self->unknownFields_) { | |
730 self->unknownFields_ = [[GPBUnknownFieldSet alloc] init]; | |
731 GPBBecomeVisibleToAutocreator(self); | |
732 } | |
733 return self->unknownFields_; | |
734 } | |
735 | |
736 @implementation GPBMessage | |
737 | |
738 + (void)initialize { | |
739 Class pbMessageClass = [GPBMessage class]; | |
740 if ([self class] == pbMessageClass) { | |
741 // This is here to start up the "base" class descriptor. | |
742 [self descriptor]; | |
743 // Message shares extension method resolving with GPBRootObject so insure | |
744 // it is started up at the same time. | |
745 (void)[GPBRootObject class]; | |
746 } else if ([self superclass] == pbMessageClass) { | |
747 // This is here to start up all the "message" subclasses. Just needs to be | |
748 // done for the messages, not any of the subclasses. | |
749 // This must be done in initialize to enforce thread safety of start up of | |
750 // the protocol buffer library. | |
751 // Note: The generated code for -descriptor calls | |
752 // +[GPBDescriptor allocDescriptorForClass:...], passing the GPBRootObject | |
753 // subclass for the file. That call chain is what ensures that *Root class | |
754 // is started up to support extension resolution off the message class | |
755 // (+resolveClassMethod: below) in a thread safe manner. | |
756 [self descriptor]; | |
757 } | |
758 } | |
759 | |
760 + (instancetype)allocWithZone:(NSZone *)zone { | |
761 // Override alloc to allocate our classes with the additional storage | |
762 // required for the instance variables. | |
763 GPBDescriptor *descriptor = [self descriptor]; | |
764 return NSAllocateObject(self, descriptor->storageSize_, zone); | |
765 } | |
766 | |
767 + (instancetype)alloc { | |
768 return [self allocWithZone:nil]; | |
769 } | |
770 | |
771 + (GPBDescriptor *)descriptor { | |
772 // This is thread safe because it is called from +initialize. | |
773 static GPBDescriptor *descriptor = NULL; | |
774 static GPBFileDescriptor *fileDescriptor = NULL; | |
775 if (!descriptor) { | |
776 // Use a dummy file that marks it as proto2 syntax so when used generically | |
777 // it supports unknowns/etc. | |
778 fileDescriptor = | |
779 [[GPBFileDescriptor alloc] initWithPackage:@"internal" | |
780 syntax:GPBFileSyntaxProto2]; | |
781 | |
782 descriptor = [GPBDescriptor allocDescriptorForClass:[GPBMessage class] | |
783 rootClass:Nil | |
784 file:fileDescriptor | |
785 fields:NULL | |
786 fieldCount:0 | |
787 oneofs:NULL | |
788 oneofCount:0 | |
789 enums:NULL | |
790 enumCount:0 | |
791 ranges:NULL | |
792 rangeCount:0 | |
793 storageSize:0 | |
794 wireFormat:NO]; | |
795 } | |
796 return descriptor; | |
797 } | |
798 | |
799 + (instancetype)message { | |
800 return [[[self alloc] init] autorelease]; | |
801 } | |
802 | |
803 - (instancetype)init { | |
804 if ((self = [super init])) { | |
805 messageStorage_ = (GPBMessage_StoragePtr)( | |
806 ((uint8_t *)self) + class_getInstanceSize([self class])); | |
807 | |
808 readOnlyMutex_ = OS_SPINLOCK_INIT; | |
809 } | |
810 | |
811 return self; | |
812 } | |
813 | |
814 - (instancetype)initWithData:(NSData *)data error:(NSError **)errorPtr { | |
815 return [self initWithData:data extensionRegistry:nil error:errorPtr]; | |
816 } | |
817 | |
818 - (instancetype)initWithData:(NSData *)data | |
819 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry | |
820 error:(NSError **)errorPtr { | |
821 if ((self = [self init])) { | |
822 @try { | |
823 [self mergeFromData:data extensionRegistry:extensionRegistry]; | |
824 if (errorPtr) { | |
825 *errorPtr = nil; | |
826 } | |
827 } | |
828 @catch (NSException *exception) { | |
829 [self release]; | |
830 self = nil; | |
831 if (errorPtr) { | |
832 *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData, | |
833 exception.reason); | |
834 } | |
835 } | |
836 #ifdef DEBUG | |
837 if (self && !self.initialized) { | |
838 [self release]; | |
839 self = nil; | |
840 if (errorPtr) { | |
841 *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil); | |
842 } | |
843 } | |
844 #endif | |
845 } | |
846 return self; | |
847 } | |
848 | |
849 - (instancetype)initWithCodedInputStream:(GPBCodedInputStream *)input | |
850 extensionRegistry: | |
851 (GPBExtensionRegistry *)extensionRegistry | |
852 error:(NSError **)errorPtr { | |
853 if ((self = [self init])) { | |
854 @try { | |
855 [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry]
; | |
856 if (errorPtr) { | |
857 *errorPtr = nil; | |
858 } | |
859 } | |
860 @catch (NSException *exception) { | |
861 [self release]; | |
862 self = nil; | |
863 if (errorPtr) { | |
864 *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData, | |
865 exception.reason); | |
866 } | |
867 } | |
868 #ifdef DEBUG | |
869 if (self && !self.initialized) { | |
870 [self release]; | |
871 self = nil; | |
872 if (errorPtr) { | |
873 *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil); | |
874 } | |
875 } | |
876 #endif | |
877 } | |
878 return self; | |
879 } | |
880 | |
881 - (void)dealloc { | |
882 [self internalClear:NO]; | |
883 NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc."); | |
884 [super dealloc]; | |
885 } | |
886 | |
887 - (void)copyFieldsInto:(GPBMessage *)message | |
888 zone:(NSZone *)zone | |
889 descriptor:(GPBDescriptor *)descriptor { | |
890 // Copy all the storage... | |
891 memcpy(message->messageStorage_, messageStorage_, descriptor->storageSize_); | |
892 | |
893 GPBFileSyntax syntax = descriptor.file.syntax; | |
894 | |
895 // Loop over the fields doing fixup... | |
896 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
897 if (GPBFieldIsMapOrArray(field)) { | |
898 id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
899 if (value) { | |
900 // We need to copy the array/map, but the catch is for message fields, | |
901 // we also need to ensure all the messages as those need copying also. | |
902 id newValue; | |
903 if (GPBFieldDataTypeIsMessage(field)) { | |
904 if (field.fieldType == GPBFieldTypeRepeated) { | |
905 NSArray *existingArray = (NSArray *)value; | |
906 NSMutableArray *newArray = | |
907 [[NSMutableArray alloc] initWithCapacity:existingArray.count]; | |
908 newValue = newArray; | |
909 for (GPBMessage *msg in existingArray) { | |
910 GPBMessage *copiedMsg = [msg copyWithZone:zone]; | |
911 [newArray addObject:copiedMsg]; | |
912 [copiedMsg release]; | |
913 } | |
914 } else { | |
915 if (field.mapKeyDataType == GPBDataTypeString) { | |
916 // Map is an NSDictionary. | |
917 NSDictionary *existingDict = value; | |
918 NSMutableDictionary *newDict = [[NSMutableDictionary alloc] | |
919 initWithCapacity:existingDict.count]; | |
920 newValue = newDict; | |
921 [existingDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, | |
922 GPBMessage *msg, | |
923 BOOL *stop) { | |
924 #pragma unused(stop) | |
925 GPBMessage *copiedMsg = [msg copyWithZone:zone]; | |
926 [newDict setObject:copiedMsg forKey:key]; | |
927 [copiedMsg release]; | |
928 }]; | |
929 } else { | |
930 // Is one of the GPB*ObjectDictionary classes. Type doesn't | |
931 // matter, just need one to invoke the selector. | |
932 GPBInt32ObjectDictionary *existingDict = value; | |
933 newValue = [existingDict deepCopyWithZone:zone]; | |
934 } | |
935 } | |
936 } else { | |
937 // Not messages (but is a map/array)... | |
938 if (field.fieldType == GPBFieldTypeRepeated) { | |
939 if (GPBFieldDataTypeIsObject(field)) { | |
940 // NSArray | |
941 newValue = [value mutableCopyWithZone:zone]; | |
942 } else { | |
943 // GPB*Array | |
944 newValue = [value copyWithZone:zone]; | |
945 } | |
946 } else { | |
947 if (field.mapKeyDataType == GPBDataTypeString) { | |
948 // NSDictionary | |
949 newValue = [value mutableCopyWithZone:zone]; | |
950 } else { | |
951 // Is one of the GPB*Dictionary classes. Type doesn't matter, | |
952 // just need one to invoke the selector. | |
953 GPBInt32Int32Dictionary *existingDict = value; | |
954 newValue = [existingDict copyWithZone:zone]; | |
955 } | |
956 } | |
957 } | |
958 // We retain here because the memcpy picked up the pointer value and | |
959 // the next call to SetRetainedObject... will release the current value. | |
960 [value retain]; | |
961 GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue, | |
962 syntax); | |
963 } | |
964 } else if (GPBFieldDataTypeIsMessage(field)) { | |
965 // For object types, if we have a value, copy it. If we don't, | |
966 // zero it to remove the pointer to something that was autocreated | |
967 // (and the ptr just got memcpyed). | |
968 if (GPBGetHasIvarField(self, field)) { | |
969 GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
970 GPBMessage *newValue = [value copyWithZone:zone]; | |
971 // We retain here because the memcpy picked up the pointer value and | |
972 // the next call to SetRetainedObject... will release the current value. | |
973 [value retain]; | |
974 GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue, | |
975 syntax); | |
976 } else { | |
977 uint8_t *storage = (uint8_t *)message->messageStorage_; | |
978 id *typePtr = (id *)&storage[field->description_->offset]; | |
979 *typePtr = NULL; | |
980 } | |
981 } else if (GPBFieldDataTypeIsObject(field) && | |
982 GPBGetHasIvarField(self, field)) { | |
983 // A set string/data value (message picked off above), copy it. | |
984 id value = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
985 id newValue = [value copyWithZone:zone]; | |
986 // We retain here because the memcpy picked up the pointer value and | |
987 // the next call to SetRetainedObject... will release the current value. | |
988 [value retain]; | |
989 GPBSetRetainedObjectIvarWithFieldInternal(message, field, newValue, | |
990 syntax); | |
991 } else { | |
992 // memcpy took care of the rest of the primitive fields if they were set. | |
993 } | |
994 } // for (field in descriptor->fields_) | |
995 } | |
996 | |
997 - (id)copyWithZone:(NSZone *)zone { | |
998 GPBDescriptor *descriptor = [self descriptor]; | |
999 GPBMessage *result = [[descriptor.messageClass allocWithZone:zone] init]; | |
1000 | |
1001 [self copyFieldsInto:result zone:zone descriptor:descriptor]; | |
1002 // Make immutable copies of the extra bits. | |
1003 result->unknownFields_ = [unknownFields_ copyWithZone:zone]; | |
1004 result->extensionMap_ = CloneExtensionMap(extensionMap_, zone); | |
1005 return result; | |
1006 } | |
1007 | |
1008 - (void)clear { | |
1009 [self internalClear:YES]; | |
1010 } | |
1011 | |
1012 - (void)internalClear:(BOOL)zeroStorage { | |
1013 GPBDescriptor *descriptor = [self descriptor]; | |
1014 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
1015 if (GPBFieldIsMapOrArray(field)) { | |
1016 id arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1017 if (arrayOrMap) { | |
1018 if (field.fieldType == GPBFieldTypeRepeated) { | |
1019 if (GPBFieldDataTypeIsObject(field)) { | |
1020 GPBAutocreatedArray *autoArray = arrayOrMap; | |
1021 if (autoArray->_autocreator == self) { | |
1022 autoArray->_autocreator = nil; | |
1023 } | |
1024 } else { | |
1025 // Type doesn't matter, it is a GPB*Array. | |
1026 GPBInt32Array *gpbArray = arrayOrMap; | |
1027 if (gpbArray->_autocreator == self) { | |
1028 gpbArray->_autocreator = nil; | |
1029 } | |
1030 } | |
1031 } else { | |
1032 if ((field.mapKeyDataType == GPBDataTypeString) && | |
1033 GPBFieldDataTypeIsObject(field)) { | |
1034 GPBAutocreatedDictionary *autoDict = arrayOrMap; | |
1035 if (autoDict->_autocreator == self) { | |
1036 autoDict->_autocreator = nil; | |
1037 } | |
1038 } else { | |
1039 // Type doesn't matter, it is a GPB*Dictionary. | |
1040 GPBInt32Int32Dictionary *gpbDict = arrayOrMap; | |
1041 if (gpbDict->_autocreator == self) { | |
1042 gpbDict->_autocreator = nil; | |
1043 } | |
1044 } | |
1045 } | |
1046 [arrayOrMap release]; | |
1047 } | |
1048 } else if (GPBFieldDataTypeIsMessage(field)) { | |
1049 GPBClearAutocreatedMessageIvarWithField(self, field); | |
1050 GPBMessage *value = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1051 [value release]; | |
1052 } else if (GPBFieldDataTypeIsObject(field) && | |
1053 GPBGetHasIvarField(self, field)) { | |
1054 id value = GPBGetObjectIvarWithField(self, field); | |
1055 [value release]; | |
1056 } | |
1057 } | |
1058 | |
1059 // GPBClearMessageAutocreator() expects that its caller has already been | |
1060 // removed from autocreatedExtensionMap_ so we set to nil first. | |
1061 NSArray *autocreatedValues = [autocreatedExtensionMap_ allValues]; | |
1062 [autocreatedExtensionMap_ release]; | |
1063 autocreatedExtensionMap_ = nil; | |
1064 | |
1065 // Since we're clearing all of our extensions, make sure that we clear the | |
1066 // autocreator on any that we've created so they no longer refer to us. | |
1067 for (GPBMessage *value in autocreatedValues) { | |
1068 NSCAssert(GPBWasMessageAutocreatedBy(value, self), | |
1069 @"Autocreated extension does not refer back to self."); | |
1070 GPBClearMessageAutocreator(value); | |
1071 } | |
1072 | |
1073 [extensionMap_ release]; | |
1074 extensionMap_ = nil; | |
1075 [unknownFields_ release]; | |
1076 unknownFields_ = nil; | |
1077 | |
1078 // Note that clearing does not affect autocreator_. If we are being cleared | |
1079 // because of a dealloc, then autocreator_ should be nil anyway. If we are | |
1080 // being cleared because someone explicitly clears us, we don't want to | |
1081 // sever our relationship with our autocreator. | |
1082 | |
1083 if (zeroStorage) { | |
1084 memset(messageStorage_, 0, descriptor->storageSize_); | |
1085 } | |
1086 } | |
1087 | |
1088 - (BOOL)isInitialized { | |
1089 GPBDescriptor *descriptor = [self descriptor]; | |
1090 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
1091 if (field.isRequired) { | |
1092 if (!GPBGetHasIvarField(self, field)) { | |
1093 return NO; | |
1094 } | |
1095 } | |
1096 if (GPBFieldDataTypeIsMessage(field)) { | |
1097 GPBFieldType fieldType = field.fieldType; | |
1098 if (fieldType == GPBFieldTypeSingle) { | |
1099 if (field.isRequired) { | |
1100 GPBMessage *message = GPBGetMessageMessageField(self, field); | |
1101 if (!message.initialized) { | |
1102 return NO; | |
1103 } | |
1104 } else { | |
1105 NSAssert(field.isOptional, | |
1106 @"%@: Single message field %@ not required or optional?", | |
1107 [self class], field.name); | |
1108 if (GPBGetHasIvarField(self, field)) { | |
1109 GPBMessage *message = GPBGetMessageMessageField(self, field); | |
1110 if (!message.initialized) { | |
1111 return NO; | |
1112 } | |
1113 } | |
1114 } | |
1115 } else if (fieldType == GPBFieldTypeRepeated) { | |
1116 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1117 for (GPBMessage *message in array) { | |
1118 if (!message.initialized) { | |
1119 return NO; | |
1120 } | |
1121 } | |
1122 } else { // fieldType == GPBFieldTypeMap | |
1123 if (field.mapKeyDataType == GPBDataTypeString) { | |
1124 NSDictionary *map = | |
1125 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1126 if (map && !GPBDictionaryIsInitializedInternalHelper(map, field)) { | |
1127 return NO; | |
1128 } | |
1129 } else { | |
1130 // Real type is GPB*ObjectDictionary, exact type doesn't matter. | |
1131 GPBInt32ObjectDictionary *map = | |
1132 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1133 if (map && ![map isInitialized]) { | |
1134 return NO; | |
1135 } | |
1136 } | |
1137 } | |
1138 } | |
1139 } | |
1140 | |
1141 __block BOOL result = YES; | |
1142 [extensionMap_ | |
1143 enumerateKeysAndObjectsUsingBlock:^(GPBExtensionDescriptor *extension, | |
1144 id obj, | |
1145 BOOL *stop) { | |
1146 if (GPBExtensionIsMessage(extension)) { | |
1147 if (extension.isRepeated) { | |
1148 for (GPBMessage *msg in obj) { | |
1149 if (!msg.initialized) { | |
1150 result = NO; | |
1151 *stop = YES; | |
1152 break; | |
1153 } | |
1154 } | |
1155 } else { | |
1156 GPBMessage *asMsg = obj; | |
1157 if (!asMsg.initialized) { | |
1158 result = NO; | |
1159 *stop = YES; | |
1160 } | |
1161 } | |
1162 } | |
1163 }]; | |
1164 return result; | |
1165 } | |
1166 | |
1167 - (GPBDescriptor *)descriptor { | |
1168 return [[self class] descriptor]; | |
1169 } | |
1170 | |
1171 - (NSData *)data { | |
1172 #ifdef DEBUG | |
1173 if (!self.initialized) { | |
1174 return nil; | |
1175 } | |
1176 #endif | |
1177 NSMutableData *data = [NSMutableData dataWithLength:[self serializedSize]]; | |
1178 GPBCodedOutputStream *stream = | |
1179 [[GPBCodedOutputStream alloc] initWithData:data]; | |
1180 @try { | |
1181 [self writeToCodedOutputStream:stream]; | |
1182 } | |
1183 @catch (NSException *exception) { | |
1184 // This really shouldn't happen. The only way writeToCodedOutputStream: | |
1185 // could throw is if something in the library has a bug and the | |
1186 // serializedSize was wrong. | |
1187 #ifdef DEBUG | |
1188 NSLog(@"%@: Internal exception while building message data: %@", | |
1189 [self class], exception); | |
1190 #endif | |
1191 data = nil; | |
1192 } | |
1193 [stream release]; | |
1194 return data; | |
1195 } | |
1196 | |
1197 - (NSData *)delimitedData { | |
1198 size_t serializedSize = [self serializedSize]; | |
1199 size_t varintSize = GPBComputeRawVarint32SizeForInteger(serializedSize); | |
1200 NSMutableData *data = | |
1201 [NSMutableData dataWithLength:(serializedSize + varintSize)]; | |
1202 GPBCodedOutputStream *stream = | |
1203 [[GPBCodedOutputStream alloc] initWithData:data]; | |
1204 @try { | |
1205 [self writeDelimitedToCodedOutputStream:stream]; | |
1206 } | |
1207 @catch (NSException *exception) { | |
1208 // This really shouldn't happen. The only way writeToCodedOutputStream: | |
1209 // could throw is if something in the library has a bug and the | |
1210 // serializedSize was wrong. | |
1211 #ifdef DEBUG | |
1212 NSLog(@"%@: Internal exception while building message delimitedData: %@", | |
1213 [self class], exception); | |
1214 #endif | |
1215 data = nil; | |
1216 } | |
1217 [stream release]; | |
1218 return data; | |
1219 } | |
1220 | |
1221 - (void)writeToOutputStream:(NSOutputStream *)output { | |
1222 GPBCodedOutputStream *stream = | |
1223 [[GPBCodedOutputStream alloc] initWithOutputStream:output]; | |
1224 [self writeToCodedOutputStream:stream]; | |
1225 [stream release]; | |
1226 } | |
1227 | |
1228 - (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output { | |
1229 GPBDescriptor *descriptor = [self descriptor]; | |
1230 NSArray *fieldsArray = descriptor->fields_; | |
1231 NSUInteger fieldCount = fieldsArray.count; | |
1232 const GPBExtensionRange *extensionRanges = descriptor.extensionRanges; | |
1233 NSUInteger extensionRangesCount = descriptor.extensionRangesCount; | |
1234 for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) { | |
1235 if (i == fieldCount) { | |
1236 [self writeExtensionsToCodedOutputStream:output | |
1237 range:extensionRanges[j++]]; | |
1238 } else if (j == extensionRangesCount || | |
1239 GPBFieldNumber(fieldsArray[i]) < extensionRanges[j].start) { | |
1240 [self writeField:fieldsArray[i++] toCodedOutputStream:output]; | |
1241 } else { | |
1242 [self writeExtensionsToCodedOutputStream:output | |
1243 range:extensionRanges[j++]]; | |
1244 } | |
1245 } | |
1246 if (descriptor.isWireFormat) { | |
1247 [unknownFields_ writeAsMessageSetTo:output]; | |
1248 } else { | |
1249 [unknownFields_ writeToCodedOutputStream:output]; | |
1250 } | |
1251 } | |
1252 | |
1253 - (void)writeDelimitedToOutputStream:(NSOutputStream *)output { | |
1254 GPBCodedOutputStream *codedOutput = | |
1255 [[GPBCodedOutputStream alloc] initWithOutputStream:output]; | |
1256 [self writeDelimitedToCodedOutputStream:codedOutput]; | |
1257 [codedOutput release]; | |
1258 } | |
1259 | |
1260 - (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output { | |
1261 [output writeRawVarintSizeTAs32:[self serializedSize]]; | |
1262 [self writeToCodedOutputStream:output]; | |
1263 } | |
1264 | |
1265 - (void)writeField:(GPBFieldDescriptor *)field | |
1266 toCodedOutputStream:(GPBCodedOutputStream *)output { | |
1267 GPBFieldType fieldType = field.fieldType; | |
1268 if (fieldType == GPBFieldTypeSingle) { | |
1269 BOOL has = GPBGetHasIvarField(self, field); | |
1270 if (!has) { | |
1271 return; | |
1272 } | |
1273 } | |
1274 uint32_t fieldNumber = GPBFieldNumber(field); | |
1275 | |
1276 //%PDDM-DEFINE FIELD_CASE(TYPE, REAL_TYPE) | |
1277 //%FIELD_CASE_FULL(TYPE, REAL_TYPE, REAL_TYPE) | |
1278 //%PDDM-DEFINE FIELD_CASE_FULL(TYPE, REAL_TYPE, ARRAY_TYPE) | |
1279 //% case GPBDataType##TYPE: | |
1280 //% if (fieldType == GPBFieldTypeRepeated) { | |
1281 //% uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1282 //% GPB##ARRAY_TYPE##Array *array = | |
1283 //% GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1284 //% [output write##TYPE##Array:fieldNumber values:array tag:tag]; | |
1285 //% } else if (fieldType == GPBFieldTypeSingle) { | |
1286 //% [output write##TYPE:fieldNumber | |
1287 //% TYPE$S value:GPBGetMessage##REAL_TYPE##Field(self, field)]; | |
1288 //% } else { // fieldType == GPBFieldTypeMap | |
1289 //% // Exact type here doesn't matter. | |
1290 //% GPBInt32##ARRAY_TYPE##Dictionary *dict = | |
1291 //% GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1292 //% [dict writeToCodedOutputStream:output asField:field]; | |
1293 //% } | |
1294 //% break; | |
1295 //% | |
1296 //%PDDM-DEFINE FIELD_CASE2(TYPE) | |
1297 //% case GPBDataType##TYPE: | |
1298 //% if (fieldType == GPBFieldTypeRepeated) { | |
1299 //% NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1300 //% [output write##TYPE##Array:fieldNumber values:array]; | |
1301 //% } else if (fieldType == GPBFieldTypeSingle) { | |
1302 //% // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check | |
1303 //% // again. | |
1304 //% [output write##TYPE:fieldNumber | |
1305 //% TYPE$S value:GPBGetObjectIvarWithFieldNoAutocreate(self, field
)]; | |
1306 //% } else { // fieldType == GPBFieldTypeMap | |
1307 //% // Exact type here doesn't matter. | |
1308 //% id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1309 //% GPBDataType mapKeyDataType = field.mapKeyDataType; | |
1310 //% if (mapKeyDataType == GPBDataTypeString) { | |
1311 //% GPBDictionaryWriteToStreamInternalHelper(output, dict, field); | |
1312 //% } else { | |
1313 //% [dict writeToCodedOutputStream:output asField:field]; | |
1314 //% } | |
1315 //% } | |
1316 //% break; | |
1317 //% | |
1318 | |
1319 switch (GPBGetFieldDataType(field)) { | |
1320 | |
1321 //%PDDM-EXPAND FIELD_CASE(Bool, Bool) | |
1322 // This block of code is generated, do not edit it directly. | |
1323 | |
1324 case GPBDataTypeBool: | |
1325 if (fieldType == GPBFieldTypeRepeated) { | |
1326 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1327 GPBBoolArray *array = | |
1328 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1329 [output writeBoolArray:fieldNumber values:array tag:tag]; | |
1330 } else if (fieldType == GPBFieldTypeSingle) { | |
1331 [output writeBool:fieldNumber | |
1332 value:GPBGetMessageBoolField(self, field)]; | |
1333 } else { // fieldType == GPBFieldTypeMap | |
1334 // Exact type here doesn't matter. | |
1335 GPBInt32BoolDictionary *dict = | |
1336 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1337 [dict writeToCodedOutputStream:output asField:field]; | |
1338 } | |
1339 break; | |
1340 | |
1341 //%PDDM-EXPAND FIELD_CASE(Fixed32, UInt32) | |
1342 // This block of code is generated, do not edit it directly. | |
1343 | |
1344 case GPBDataTypeFixed32: | |
1345 if (fieldType == GPBFieldTypeRepeated) { | |
1346 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1347 GPBUInt32Array *array = | |
1348 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1349 [output writeFixed32Array:fieldNumber values:array tag:tag]; | |
1350 } else if (fieldType == GPBFieldTypeSingle) { | |
1351 [output writeFixed32:fieldNumber | |
1352 value:GPBGetMessageUInt32Field(self, field)]; | |
1353 } else { // fieldType == GPBFieldTypeMap | |
1354 // Exact type here doesn't matter. | |
1355 GPBInt32UInt32Dictionary *dict = | |
1356 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1357 [dict writeToCodedOutputStream:output asField:field]; | |
1358 } | |
1359 break; | |
1360 | |
1361 //%PDDM-EXPAND FIELD_CASE(SFixed32, Int32) | |
1362 // This block of code is generated, do not edit it directly. | |
1363 | |
1364 case GPBDataTypeSFixed32: | |
1365 if (fieldType == GPBFieldTypeRepeated) { | |
1366 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1367 GPBInt32Array *array = | |
1368 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1369 [output writeSFixed32Array:fieldNumber values:array tag:tag]; | |
1370 } else if (fieldType == GPBFieldTypeSingle) { | |
1371 [output writeSFixed32:fieldNumber | |
1372 value:GPBGetMessageInt32Field(self, field)]; | |
1373 } else { // fieldType == GPBFieldTypeMap | |
1374 // Exact type here doesn't matter. | |
1375 GPBInt32Int32Dictionary *dict = | |
1376 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1377 [dict writeToCodedOutputStream:output asField:field]; | |
1378 } | |
1379 break; | |
1380 | |
1381 //%PDDM-EXPAND FIELD_CASE(Float, Float) | |
1382 // This block of code is generated, do not edit it directly. | |
1383 | |
1384 case GPBDataTypeFloat: | |
1385 if (fieldType == GPBFieldTypeRepeated) { | |
1386 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1387 GPBFloatArray *array = | |
1388 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1389 [output writeFloatArray:fieldNumber values:array tag:tag]; | |
1390 } else if (fieldType == GPBFieldTypeSingle) { | |
1391 [output writeFloat:fieldNumber | |
1392 value:GPBGetMessageFloatField(self, field)]; | |
1393 } else { // fieldType == GPBFieldTypeMap | |
1394 // Exact type here doesn't matter. | |
1395 GPBInt32FloatDictionary *dict = | |
1396 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1397 [dict writeToCodedOutputStream:output asField:field]; | |
1398 } | |
1399 break; | |
1400 | |
1401 //%PDDM-EXPAND FIELD_CASE(Fixed64, UInt64) | |
1402 // This block of code is generated, do not edit it directly. | |
1403 | |
1404 case GPBDataTypeFixed64: | |
1405 if (fieldType == GPBFieldTypeRepeated) { | |
1406 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1407 GPBUInt64Array *array = | |
1408 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1409 [output writeFixed64Array:fieldNumber values:array tag:tag]; | |
1410 } else if (fieldType == GPBFieldTypeSingle) { | |
1411 [output writeFixed64:fieldNumber | |
1412 value:GPBGetMessageUInt64Field(self, field)]; | |
1413 } else { // fieldType == GPBFieldTypeMap | |
1414 // Exact type here doesn't matter. | |
1415 GPBInt32UInt64Dictionary *dict = | |
1416 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1417 [dict writeToCodedOutputStream:output asField:field]; | |
1418 } | |
1419 break; | |
1420 | |
1421 //%PDDM-EXPAND FIELD_CASE(SFixed64, Int64) | |
1422 // This block of code is generated, do not edit it directly. | |
1423 | |
1424 case GPBDataTypeSFixed64: | |
1425 if (fieldType == GPBFieldTypeRepeated) { | |
1426 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1427 GPBInt64Array *array = | |
1428 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1429 [output writeSFixed64Array:fieldNumber values:array tag:tag]; | |
1430 } else if (fieldType == GPBFieldTypeSingle) { | |
1431 [output writeSFixed64:fieldNumber | |
1432 value:GPBGetMessageInt64Field(self, field)]; | |
1433 } else { // fieldType == GPBFieldTypeMap | |
1434 // Exact type here doesn't matter. | |
1435 GPBInt32Int64Dictionary *dict = | |
1436 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1437 [dict writeToCodedOutputStream:output asField:field]; | |
1438 } | |
1439 break; | |
1440 | |
1441 //%PDDM-EXPAND FIELD_CASE(Double, Double) | |
1442 // This block of code is generated, do not edit it directly. | |
1443 | |
1444 case GPBDataTypeDouble: | |
1445 if (fieldType == GPBFieldTypeRepeated) { | |
1446 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1447 GPBDoubleArray *array = | |
1448 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1449 [output writeDoubleArray:fieldNumber values:array tag:tag]; | |
1450 } else if (fieldType == GPBFieldTypeSingle) { | |
1451 [output writeDouble:fieldNumber | |
1452 value:GPBGetMessageDoubleField(self, field)]; | |
1453 } else { // fieldType == GPBFieldTypeMap | |
1454 // Exact type here doesn't matter. | |
1455 GPBInt32DoubleDictionary *dict = | |
1456 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1457 [dict writeToCodedOutputStream:output asField:field]; | |
1458 } | |
1459 break; | |
1460 | |
1461 //%PDDM-EXPAND FIELD_CASE(Int32, Int32) | |
1462 // This block of code is generated, do not edit it directly. | |
1463 | |
1464 case GPBDataTypeInt32: | |
1465 if (fieldType == GPBFieldTypeRepeated) { | |
1466 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1467 GPBInt32Array *array = | |
1468 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1469 [output writeInt32Array:fieldNumber values:array tag:tag]; | |
1470 } else if (fieldType == GPBFieldTypeSingle) { | |
1471 [output writeInt32:fieldNumber | |
1472 value:GPBGetMessageInt32Field(self, field)]; | |
1473 } else { // fieldType == GPBFieldTypeMap | |
1474 // Exact type here doesn't matter. | |
1475 GPBInt32Int32Dictionary *dict = | |
1476 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1477 [dict writeToCodedOutputStream:output asField:field]; | |
1478 } | |
1479 break; | |
1480 | |
1481 //%PDDM-EXPAND FIELD_CASE(Int64, Int64) | |
1482 // This block of code is generated, do not edit it directly. | |
1483 | |
1484 case GPBDataTypeInt64: | |
1485 if (fieldType == GPBFieldTypeRepeated) { | |
1486 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1487 GPBInt64Array *array = | |
1488 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1489 [output writeInt64Array:fieldNumber values:array tag:tag]; | |
1490 } else if (fieldType == GPBFieldTypeSingle) { | |
1491 [output writeInt64:fieldNumber | |
1492 value:GPBGetMessageInt64Field(self, field)]; | |
1493 } else { // fieldType == GPBFieldTypeMap | |
1494 // Exact type here doesn't matter. | |
1495 GPBInt32Int64Dictionary *dict = | |
1496 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1497 [dict writeToCodedOutputStream:output asField:field]; | |
1498 } | |
1499 break; | |
1500 | |
1501 //%PDDM-EXPAND FIELD_CASE(SInt32, Int32) | |
1502 // This block of code is generated, do not edit it directly. | |
1503 | |
1504 case GPBDataTypeSInt32: | |
1505 if (fieldType == GPBFieldTypeRepeated) { | |
1506 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1507 GPBInt32Array *array = | |
1508 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1509 [output writeSInt32Array:fieldNumber values:array tag:tag]; | |
1510 } else if (fieldType == GPBFieldTypeSingle) { | |
1511 [output writeSInt32:fieldNumber | |
1512 value:GPBGetMessageInt32Field(self, field)]; | |
1513 } else { // fieldType == GPBFieldTypeMap | |
1514 // Exact type here doesn't matter. | |
1515 GPBInt32Int32Dictionary *dict = | |
1516 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1517 [dict writeToCodedOutputStream:output asField:field]; | |
1518 } | |
1519 break; | |
1520 | |
1521 //%PDDM-EXPAND FIELD_CASE(SInt64, Int64) | |
1522 // This block of code is generated, do not edit it directly. | |
1523 | |
1524 case GPBDataTypeSInt64: | |
1525 if (fieldType == GPBFieldTypeRepeated) { | |
1526 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1527 GPBInt64Array *array = | |
1528 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1529 [output writeSInt64Array:fieldNumber values:array tag:tag]; | |
1530 } else if (fieldType == GPBFieldTypeSingle) { | |
1531 [output writeSInt64:fieldNumber | |
1532 value:GPBGetMessageInt64Field(self, field)]; | |
1533 } else { // fieldType == GPBFieldTypeMap | |
1534 // Exact type here doesn't matter. | |
1535 GPBInt32Int64Dictionary *dict = | |
1536 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1537 [dict writeToCodedOutputStream:output asField:field]; | |
1538 } | |
1539 break; | |
1540 | |
1541 //%PDDM-EXPAND FIELD_CASE(UInt32, UInt32) | |
1542 // This block of code is generated, do not edit it directly. | |
1543 | |
1544 case GPBDataTypeUInt32: | |
1545 if (fieldType == GPBFieldTypeRepeated) { | |
1546 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1547 GPBUInt32Array *array = | |
1548 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1549 [output writeUInt32Array:fieldNumber values:array tag:tag]; | |
1550 } else if (fieldType == GPBFieldTypeSingle) { | |
1551 [output writeUInt32:fieldNumber | |
1552 value:GPBGetMessageUInt32Field(self, field)]; | |
1553 } else { // fieldType == GPBFieldTypeMap | |
1554 // Exact type here doesn't matter. | |
1555 GPBInt32UInt32Dictionary *dict = | |
1556 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1557 [dict writeToCodedOutputStream:output asField:field]; | |
1558 } | |
1559 break; | |
1560 | |
1561 //%PDDM-EXPAND FIELD_CASE(UInt64, UInt64) | |
1562 // This block of code is generated, do not edit it directly. | |
1563 | |
1564 case GPBDataTypeUInt64: | |
1565 if (fieldType == GPBFieldTypeRepeated) { | |
1566 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1567 GPBUInt64Array *array = | |
1568 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1569 [output writeUInt64Array:fieldNumber values:array tag:tag]; | |
1570 } else if (fieldType == GPBFieldTypeSingle) { | |
1571 [output writeUInt64:fieldNumber | |
1572 value:GPBGetMessageUInt64Field(self, field)]; | |
1573 } else { // fieldType == GPBFieldTypeMap | |
1574 // Exact type here doesn't matter. | |
1575 GPBInt32UInt64Dictionary *dict = | |
1576 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1577 [dict writeToCodedOutputStream:output asField:field]; | |
1578 } | |
1579 break; | |
1580 | |
1581 //%PDDM-EXPAND FIELD_CASE_FULL(Enum, Int32, Enum) | |
1582 // This block of code is generated, do not edit it directly. | |
1583 | |
1584 case GPBDataTypeEnum: | |
1585 if (fieldType == GPBFieldTypeRepeated) { | |
1586 uint32_t tag = field.isPackable ? GPBFieldTag(field) : 0; | |
1587 GPBEnumArray *array = | |
1588 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1589 [output writeEnumArray:fieldNumber values:array tag:tag]; | |
1590 } else if (fieldType == GPBFieldTypeSingle) { | |
1591 [output writeEnum:fieldNumber | |
1592 value:GPBGetMessageInt32Field(self, field)]; | |
1593 } else { // fieldType == GPBFieldTypeMap | |
1594 // Exact type here doesn't matter. | |
1595 GPBInt32EnumDictionary *dict = | |
1596 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1597 [dict writeToCodedOutputStream:output asField:field]; | |
1598 } | |
1599 break; | |
1600 | |
1601 //%PDDM-EXPAND FIELD_CASE2(Bytes) | |
1602 // This block of code is generated, do not edit it directly. | |
1603 | |
1604 case GPBDataTypeBytes: | |
1605 if (fieldType == GPBFieldTypeRepeated) { | |
1606 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1607 [output writeBytesArray:fieldNumber values:array]; | |
1608 } else if (fieldType == GPBFieldTypeSingle) { | |
1609 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check | |
1610 // again. | |
1611 [output writeBytes:fieldNumber | |
1612 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]; | |
1613 } else { // fieldType == GPBFieldTypeMap | |
1614 // Exact type here doesn't matter. | |
1615 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1616 GPBDataType mapKeyDataType = field.mapKeyDataType; | |
1617 if (mapKeyDataType == GPBDataTypeString) { | |
1618 GPBDictionaryWriteToStreamInternalHelper(output, dict, field); | |
1619 } else { | |
1620 [dict writeToCodedOutputStream:output asField:field]; | |
1621 } | |
1622 } | |
1623 break; | |
1624 | |
1625 //%PDDM-EXPAND FIELD_CASE2(String) | |
1626 // This block of code is generated, do not edit it directly. | |
1627 | |
1628 case GPBDataTypeString: | |
1629 if (fieldType == GPBFieldTypeRepeated) { | |
1630 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1631 [output writeStringArray:fieldNumber values:array]; | |
1632 } else if (fieldType == GPBFieldTypeSingle) { | |
1633 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check | |
1634 // again. | |
1635 [output writeString:fieldNumber | |
1636 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]; | |
1637 } else { // fieldType == GPBFieldTypeMap | |
1638 // Exact type here doesn't matter. | |
1639 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1640 GPBDataType mapKeyDataType = field.mapKeyDataType; | |
1641 if (mapKeyDataType == GPBDataTypeString) { | |
1642 GPBDictionaryWriteToStreamInternalHelper(output, dict, field); | |
1643 } else { | |
1644 [dict writeToCodedOutputStream:output asField:field]; | |
1645 } | |
1646 } | |
1647 break; | |
1648 | |
1649 //%PDDM-EXPAND FIELD_CASE2(Message) | |
1650 // This block of code is generated, do not edit it directly. | |
1651 | |
1652 case GPBDataTypeMessage: | |
1653 if (fieldType == GPBFieldTypeRepeated) { | |
1654 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1655 [output writeMessageArray:fieldNumber values:array]; | |
1656 } else if (fieldType == GPBFieldTypeSingle) { | |
1657 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check | |
1658 // again. | |
1659 [output writeMessage:fieldNumber | |
1660 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]
; | |
1661 } else { // fieldType == GPBFieldTypeMap | |
1662 // Exact type here doesn't matter. | |
1663 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1664 GPBDataType mapKeyDataType = field.mapKeyDataType; | |
1665 if (mapKeyDataType == GPBDataTypeString) { | |
1666 GPBDictionaryWriteToStreamInternalHelper(output, dict, field); | |
1667 } else { | |
1668 [dict writeToCodedOutputStream:output asField:field]; | |
1669 } | |
1670 } | |
1671 break; | |
1672 | |
1673 //%PDDM-EXPAND FIELD_CASE2(Group) | |
1674 // This block of code is generated, do not edit it directly. | |
1675 | |
1676 case GPBDataTypeGroup: | |
1677 if (fieldType == GPBFieldTypeRepeated) { | |
1678 NSArray *array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1679 [output writeGroupArray:fieldNumber values:array]; | |
1680 } else if (fieldType == GPBFieldTypeSingle) { | |
1681 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has check | |
1682 // again. | |
1683 [output writeGroup:fieldNumber | |
1684 value:GPBGetObjectIvarWithFieldNoAutocreate(self, field)]; | |
1685 } else { // fieldType == GPBFieldTypeMap | |
1686 // Exact type here doesn't matter. | |
1687 id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
1688 GPBDataType mapKeyDataType = field.mapKeyDataType; | |
1689 if (mapKeyDataType == GPBDataTypeString) { | |
1690 GPBDictionaryWriteToStreamInternalHelper(output, dict, field); | |
1691 } else { | |
1692 [dict writeToCodedOutputStream:output asField:field]; | |
1693 } | |
1694 } | |
1695 break; | |
1696 | |
1697 //%PDDM-EXPAND-END (18 expansions) | |
1698 } | |
1699 } | |
1700 | |
1701 #pragma mark - Extensions | |
1702 | |
1703 - (id)getExtension:(GPBExtensionDescriptor *)extension { | |
1704 CheckExtension(self, extension); | |
1705 id value = [extensionMap_ objectForKey:extension]; | |
1706 if (value != nil) { | |
1707 return value; | |
1708 } | |
1709 | |
1710 // No default for repeated. | |
1711 if (extension.isRepeated) { | |
1712 return nil; | |
1713 } | |
1714 // Non messages get their default. | |
1715 if (!GPBExtensionIsMessage(extension)) { | |
1716 return extension.defaultValue; | |
1717 } | |
1718 | |
1719 // Check for an autocreated value. | |
1720 OSSpinLockLock(&readOnlyMutex_); | |
1721 value = [autocreatedExtensionMap_ objectForKey:extension]; | |
1722 if (!value) { | |
1723 // Auto create the message extensions to match normal fields. | |
1724 value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self, | |
1725 extension); | |
1726 | |
1727 if (autocreatedExtensionMap_ == nil) { | |
1728 autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init]; | |
1729 } | |
1730 | |
1731 // We can't simply call setExtension here because that would clear the new | |
1732 // value's autocreator. | |
1733 [autocreatedExtensionMap_ setObject:value forKey:extension]; | |
1734 [value release]; | |
1735 } | |
1736 | |
1737 OSSpinLockUnlock(&readOnlyMutex_); | |
1738 return value; | |
1739 } | |
1740 | |
1741 - (id)getExistingExtension:(GPBExtensionDescriptor *)extension { | |
1742 // This is an internal method so we don't need to call CheckExtension(). | |
1743 return [extensionMap_ objectForKey:extension]; | |
1744 } | |
1745 | |
1746 - (BOOL)hasExtension:(GPBExtensionDescriptor *)extension { | |
1747 #if DEBUG | |
1748 CheckExtension(self, extension); | |
1749 #endif // DEBUG | |
1750 return nil != [extensionMap_ objectForKey:extension]; | |
1751 } | |
1752 | |
1753 - (NSArray *)extensionsCurrentlySet { | |
1754 return [extensionMap_ allKeys]; | |
1755 } | |
1756 | |
1757 - (void)writeExtensionsToCodedOutputStream:(GPBCodedOutputStream *)output | |
1758 range:(GPBExtensionRange)range { | |
1759 NSArray *sortedExtensions = [[extensionMap_ allKeys] | |
1760 sortedArrayUsingSelector:@selector(compareByFieldNumber:)]; | |
1761 uint32_t start = range.start; | |
1762 uint32_t end = range.end; | |
1763 for (GPBExtensionDescriptor *extension in sortedExtensions) { | |
1764 uint32_t fieldNumber = extension.fieldNumber; | |
1765 if (fieldNumber >= start && fieldNumber < end) { | |
1766 id value = [extensionMap_ objectForKey:extension]; | |
1767 GPBWriteExtensionValueToOutputStream(extension, value, output); | |
1768 } | |
1769 } | |
1770 } | |
1771 | |
1772 - (NSArray *)sortedExtensionsInUse { | |
1773 return [[extensionMap_ allKeys] | |
1774 sortedArrayUsingSelector:@selector(compareByFieldNumber:)]; | |
1775 } | |
1776 | |
1777 - (void)setExtension:(GPBExtensionDescriptor *)extension value:(id)value { | |
1778 if (!value) { | |
1779 [self clearExtension:extension]; | |
1780 return; | |
1781 } | |
1782 | |
1783 CheckExtension(self, extension); | |
1784 | |
1785 if (extension.repeated) { | |
1786 [NSException raise:NSInvalidArgumentException | |
1787 format:@"Must call addExtension() for repeated types."]; | |
1788 } | |
1789 | |
1790 if (extensionMap_ == nil) { | |
1791 extensionMap_ = [[NSMutableDictionary alloc] init]; | |
1792 } | |
1793 | |
1794 [extensionMap_ setObject:value forKey:extension]; | |
1795 | |
1796 GPBExtensionDescriptor *descriptor = extension; | |
1797 | |
1798 if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) { | |
1799 GPBMessage *autocreatedValue = | |
1800 [[autocreatedExtensionMap_ objectForKey:extension] retain]; | |
1801 // Must remove from the map before calling GPBClearMessageAutocreator() so | |
1802 // that GPBClearMessageAutocreator() knows its safe to clear. | |
1803 [autocreatedExtensionMap_ removeObjectForKey:extension]; | |
1804 GPBClearMessageAutocreator(autocreatedValue); | |
1805 [autocreatedValue release]; | |
1806 } | |
1807 | |
1808 GPBBecomeVisibleToAutocreator(self); | |
1809 } | |
1810 | |
1811 - (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value { | |
1812 CheckExtension(self, extension); | |
1813 | |
1814 if (!extension.repeated) { | |
1815 [NSException raise:NSInvalidArgumentException | |
1816 format:@"Must call setExtension() for singular types."]; | |
1817 } | |
1818 | |
1819 if (extensionMap_ == nil) { | |
1820 extensionMap_ = [[NSMutableDictionary alloc] init]; | |
1821 } | |
1822 NSMutableArray *list = [extensionMap_ objectForKey:extension]; | |
1823 if (list == nil) { | |
1824 list = [NSMutableArray array]; | |
1825 [extensionMap_ setObject:list forKey:extension]; | |
1826 } | |
1827 | |
1828 [list addObject:value]; | |
1829 GPBBecomeVisibleToAutocreator(self); | |
1830 } | |
1831 | |
1832 - (void)setExtension:(GPBExtensionDescriptor *)extension | |
1833 index:(NSUInteger)idx | |
1834 value:(id)value { | |
1835 CheckExtension(self, extension); | |
1836 | |
1837 if (!extension.repeated) { | |
1838 [NSException raise:NSInvalidArgumentException | |
1839 format:@"Must call setExtension() for singular types."]; | |
1840 } | |
1841 | |
1842 if (extensionMap_ == nil) { | |
1843 extensionMap_ = [[NSMutableDictionary alloc] init]; | |
1844 } | |
1845 | |
1846 NSMutableArray *list = [extensionMap_ objectForKey:extension]; | |
1847 | |
1848 [list replaceObjectAtIndex:idx withObject:value]; | |
1849 GPBBecomeVisibleToAutocreator(self); | |
1850 } | |
1851 | |
1852 - (void)clearExtension:(GPBExtensionDescriptor *)extension { | |
1853 CheckExtension(self, extension); | |
1854 | |
1855 // Only become visible if there was actually a value to clear. | |
1856 if ([extensionMap_ objectForKey:extension]) { | |
1857 [extensionMap_ removeObjectForKey:extension]; | |
1858 GPBBecomeVisibleToAutocreator(self); | |
1859 } | |
1860 } | |
1861 | |
1862 #pragma mark - mergeFrom | |
1863 | |
1864 - (void)mergeFromData:(NSData *)data | |
1865 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { | |
1866 GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data]; | |
1867 [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry]; | |
1868 [input checkLastTagWas:0]; | |
1869 [input release]; | |
1870 } | |
1871 | |
1872 #pragma mark - mergeDelimitedFrom | |
1873 | |
1874 - (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input | |
1875 extensionRegistry:(GPBExtensionRegistry *)extensionRegi
stry { | |
1876 GPBCodedInputStreamState *state = &input->state_; | |
1877 if (GPBCodedInputStreamIsAtEnd(state)) { | |
1878 return; | |
1879 } | |
1880 NSData *data = GPBCodedInputStreamReadRetainedBytesNoCopy(state); | |
1881 if (data == nil) { | |
1882 return; | |
1883 } | |
1884 [self mergeFromData:data extensionRegistry:extensionRegistry]; | |
1885 [data release]; | |
1886 } | |
1887 | |
1888 #pragma mark - Parse From Data Support | |
1889 | |
1890 + (instancetype)parseFromData:(NSData *)data error:(NSError **)errorPtr { | |
1891 return [self parseFromData:data extensionRegistry:nil error:errorPtr]; | |
1892 } | |
1893 | |
1894 + (instancetype)parseFromData:(NSData *)data | |
1895 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry | |
1896 error:(NSError **)errorPtr { | |
1897 return [[[self alloc] initWithData:data | |
1898 extensionRegistry:extensionRegistry | |
1899 error:errorPtr] autorelease]; | |
1900 } | |
1901 | |
1902 + (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input | |
1903 extensionRegistry:(GPBExtensionRegistry *)extensionRegis
try | |
1904 error:(NSError **)errorPtr { | |
1905 return | |
1906 [[[self alloc] initWithCodedInputStream:input | |
1907 extensionRegistry:extensionRegistry | |
1908 error:errorPtr] autorelease]; | |
1909 } | |
1910 | |
1911 #pragma mark - Parse Delimited From Data Support | |
1912 | |
1913 + (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input | |
1914 extensionRegistry: | |
1915 (GPBExtensionRegistry *)extensionRegistry | |
1916 error:(NSError **)errorPtr { | |
1917 GPBMessage *message = [[[self alloc] init] autorelease]; | |
1918 @try { | |
1919 [message mergeDelimitedFromCodedInputStream:input | |
1920 extensionRegistry:extensionRegistry]; | |
1921 if (errorPtr) { | |
1922 *errorPtr = nil; | |
1923 } | |
1924 } | |
1925 @catch (NSException *exception) { | |
1926 [message release]; | |
1927 message = nil; | |
1928 if (errorPtr) { | |
1929 *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData, | |
1930 exception.reason); | |
1931 } | |
1932 } | |
1933 #ifdef DEBUG | |
1934 if (message && !message.initialized) { | |
1935 [message release]; | |
1936 message = nil; | |
1937 if (errorPtr) { | |
1938 *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil); | |
1939 } | |
1940 } | |
1941 #endif | |
1942 return message; | |
1943 } | |
1944 | |
1945 #pragma mark - Unknown Field Support | |
1946 | |
1947 - (GPBUnknownFieldSet *)unknownFields { | |
1948 return unknownFields_; | |
1949 } | |
1950 | |
1951 - (void)setUnknownFields:(GPBUnknownFieldSet *)unknownFields { | |
1952 if (unknownFields != unknownFields_) { | |
1953 [unknownFields_ release]; | |
1954 unknownFields_ = [unknownFields copy]; | |
1955 GPBBecomeVisibleToAutocreator(self); | |
1956 } | |
1957 } | |
1958 | |
1959 - (void)parseMessageSet:(GPBCodedInputStream *)input | |
1960 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { | |
1961 uint32_t typeId = 0; | |
1962 NSData *rawBytes = nil; | |
1963 GPBExtensionDescriptor *extension = nil; | |
1964 GPBCodedInputStreamState *state = &input->state_; | |
1965 while (true) { | |
1966 uint32_t tag = GPBCodedInputStreamReadTag(state); | |
1967 if (tag == 0) { | |
1968 break; | |
1969 } | |
1970 | |
1971 if (tag == GPBWireFormatMessageSetTypeIdTag) { | |
1972 typeId = GPBCodedInputStreamReadUInt32(state); | |
1973 if (typeId != 0) { | |
1974 extension = [extensionRegistry extensionForDescriptor:[self descriptor] | |
1975 fieldNumber:typeId]; | |
1976 } | |
1977 } else if (tag == GPBWireFormatMessageSetMessageTag) { | |
1978 rawBytes = | |
1979 [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease]; | |
1980 } else { | |
1981 if (![input skipField:tag]) { | |
1982 break; | |
1983 } | |
1984 } | |
1985 } | |
1986 | |
1987 [input checkLastTagWas:GPBWireFormatMessageSetItemEndTag]; | |
1988 | |
1989 if (rawBytes != nil && typeId != 0) { | |
1990 if (extension != nil) { | |
1991 GPBCodedInputStream *newInput = | |
1992 [[GPBCodedInputStream alloc] initWithData:rawBytes]; | |
1993 GPBExtensionMergeFromInputStream(extension, | |
1994 extension.packable, | |
1995 newInput, | |
1996 extensionRegistry, | |
1997 self); | |
1998 [newInput release]; | |
1999 } else { | |
2000 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); | |
2001 [unknownFields mergeMessageSetMessage:typeId data:rawBytes]; | |
2002 } | |
2003 } | |
2004 } | |
2005 | |
2006 - (BOOL)parseUnknownField:(GPBCodedInputStream *)input | |
2007 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry | |
2008 tag:(uint32_t)tag { | |
2009 GPBWireFormat wireType = GPBWireFormatGetTagWireType(tag); | |
2010 int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag); | |
2011 | |
2012 GPBDescriptor *descriptor = [self descriptor]; | |
2013 GPBExtensionDescriptor *extension = | |
2014 [extensionRegistry extensionForDescriptor:descriptor | |
2015 fieldNumber:fieldNumber]; | |
2016 if (extension == nil) { | |
2017 if (descriptor.wireFormat && GPBWireFormatMessageSetItemTag == tag) { | |
2018 [self parseMessageSet:input extensionRegistry:extensionRegistry]; | |
2019 return YES; | |
2020 } | |
2021 } else { | |
2022 if (extension.wireType == wireType) { | |
2023 GPBExtensionMergeFromInputStream(extension, | |
2024 extension.packable, | |
2025 input, | |
2026 extensionRegistry, | |
2027 self); | |
2028 return YES; | |
2029 } | |
2030 // Primitive, repeated types can be packed on unpacked on the wire, and are | |
2031 // parsed either way. | |
2032 if ([extension isRepeated] && | |
2033 !GPBDataTypeIsObject(extension->description_->dataType) && | |
2034 (extension.alternateWireType == wireType)) { | |
2035 GPBExtensionMergeFromInputStream(extension, | |
2036 !extension.packable, | |
2037 input, | |
2038 extensionRegistry, | |
2039 self); | |
2040 return YES; | |
2041 } | |
2042 } | |
2043 if ([GPBUnknownFieldSet isFieldTag:tag]) { | |
2044 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); | |
2045 return [unknownFields mergeFieldFrom:tag input:input]; | |
2046 } else { | |
2047 return NO; | |
2048 } | |
2049 } | |
2050 | |
2051 - (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data { | |
2052 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); | |
2053 [unknownFields addUnknownMapEntry:fieldNum value:data]; | |
2054 } | |
2055 | |
2056 #pragma mark - MergeFromCodedInputStream Support | |
2057 | |
2058 static void MergeSingleFieldFromCodedInputStream( | |
2059 GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, | |
2060 GPBCodedInputStream *input, GPBExtensionRegistry *extensionRegistry) { | |
2061 GPBDataType fieldDataType = GPBGetFieldDataType(field); | |
2062 switch (fieldDataType) { | |
2063 #define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \ | |
2064 case GPBDataType##NAME: { \ | |
2065 TYPE val = GPBCodedInputStreamRead##NAME(&input->state_); \ | |
2066 GPBSet##FUNC_TYPE##IvarWithFieldInternal(self, field, val, syntax); \ | |
2067 break; \ | |
2068 } | |
2069 #define CASE_SINGLE_OBJECT(NAME) \ | |
2070 case GPBDataType##NAME: { \ | |
2071 id val = GPBCodedInputStreamReadRetained##NAME(&input->state_); \ | |
2072 GPBSetRetainedObjectIvarWithFieldInternal(self, field, val, syntax); \ | |
2073 break; \ | |
2074 } | |
2075 CASE_SINGLE_POD(Bool, BOOL, Bool) | |
2076 CASE_SINGLE_POD(Fixed32, uint32_t, UInt32) | |
2077 CASE_SINGLE_POD(SFixed32, int32_t, Int32) | |
2078 CASE_SINGLE_POD(Float, float, Float) | |
2079 CASE_SINGLE_POD(Fixed64, uint64_t, UInt64) | |
2080 CASE_SINGLE_POD(SFixed64, int64_t, Int64) | |
2081 CASE_SINGLE_POD(Double, double, Double) | |
2082 CASE_SINGLE_POD(Int32, int32_t, Int32) | |
2083 CASE_SINGLE_POD(Int64, int64_t, Int64) | |
2084 CASE_SINGLE_POD(SInt32, int32_t, Int32) | |
2085 CASE_SINGLE_POD(SInt64, int64_t, Int64) | |
2086 CASE_SINGLE_POD(UInt32, uint32_t, UInt32) | |
2087 CASE_SINGLE_POD(UInt64, uint64_t, UInt64) | |
2088 CASE_SINGLE_OBJECT(Bytes) | |
2089 CASE_SINGLE_OBJECT(String) | |
2090 #undef CASE_SINGLE_POD | |
2091 #undef CASE_SINGLE_OBJECT | |
2092 | |
2093 case GPBDataTypeMessage: { | |
2094 if (GPBGetHasIvarField(self, field)) { | |
2095 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has | |
2096 // check again. | |
2097 GPBMessage *message = | |
2098 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
2099 [input readMessage:message extensionRegistry:extensionRegistry]; | |
2100 } else { | |
2101 GPBMessage *message = [[field.msgClass alloc] init]; | |
2102 [input readMessage:message extensionRegistry:extensionRegistry]; | |
2103 GPBSetRetainedObjectIvarWithFieldInternal(self, field, message, syntax); | |
2104 } | |
2105 break; | |
2106 } | |
2107 | |
2108 case GPBDataTypeGroup: { | |
2109 if (GPBGetHasIvarField(self, field)) { | |
2110 // GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has | |
2111 // check again. | |
2112 GPBMessage *message = | |
2113 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
2114 [input readGroup:GPBFieldNumber(field) | |
2115 message:message | |
2116 extensionRegistry:extensionRegistry]; | |
2117 } else { | |
2118 GPBMessage *message = [[field.msgClass alloc] init]; | |
2119 [input readGroup:GPBFieldNumber(field) | |
2120 message:message | |
2121 extensionRegistry:extensionRegistry]; | |
2122 GPBSetRetainedObjectIvarWithFieldInternal(self, field, message, syntax); | |
2123 } | |
2124 break; | |
2125 } | |
2126 | |
2127 case GPBDataTypeEnum: { | |
2128 int32_t val = GPBCodedInputStreamReadEnum(&input->state_); | |
2129 if (GPBHasPreservingUnknownEnumSemantics(syntax) || | |
2130 [field isValidEnumValue:val]) { | |
2131 GPBSetInt32IvarWithFieldInternal(self, field, val, syntax); | |
2132 } else { | |
2133 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); | |
2134 [unknownFields mergeVarintField:GPBFieldNumber(field) value:val]; | |
2135 } | |
2136 } | |
2137 } // switch | |
2138 } | |
2139 | |
2140 static void MergeRepeatedPackedFieldFromCodedInputStream( | |
2141 GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, | |
2142 GPBCodedInputStream *input) { | |
2143 GPBDataType fieldDataType = GPBGetFieldDataType(field); | |
2144 GPBCodedInputStreamState *state = &input->state_; | |
2145 id genericArray = GetOrCreateArrayIvarWithField(self, field, syntax); | |
2146 int32_t length = GPBCodedInputStreamReadInt32(state); | |
2147 size_t limit = GPBCodedInputStreamPushLimit(state, length); | |
2148 while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { | |
2149 switch (fieldDataType) { | |
2150 #define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \ | |
2151 case GPBDataType##NAME: { \ | |
2152 TYPE val = GPBCodedInputStreamRead##NAME(state); \ | |
2153 [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \ | |
2154 break; \ | |
2155 } | |
2156 CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool) | |
2157 CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32) | |
2158 CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32) | |
2159 CASE_REPEATED_PACKED_POD(Float, float, Float) | |
2160 CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64) | |
2161 CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64) | |
2162 CASE_REPEATED_PACKED_POD(Double, double, Double) | |
2163 CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32) | |
2164 CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64) | |
2165 CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32) | |
2166 CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64) | |
2167 CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32) | |
2168 CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64) | |
2169 #undef CASE_REPEATED_PACKED_POD | |
2170 | |
2171 case GPBDataTypeBytes: | |
2172 case GPBDataTypeString: | |
2173 case GPBDataTypeMessage: | |
2174 case GPBDataTypeGroup: | |
2175 NSCAssert(NO, @"Non primitive types can't be packed"); | |
2176 break; | |
2177 | |
2178 case GPBDataTypeEnum: { | |
2179 int32_t val = GPBCodedInputStreamReadEnum(state); | |
2180 if (GPBHasPreservingUnknownEnumSemantics(syntax) || | |
2181 [field isValidEnumValue:val]) { | |
2182 [(GPBEnumArray*)genericArray addRawValue:val]; | |
2183 } else { | |
2184 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); | |
2185 [unknownFields mergeVarintField:GPBFieldNumber(field) value:val]; | |
2186 } | |
2187 break; | |
2188 } | |
2189 } // switch | |
2190 } // while(BytesUntilLimit() > 0) | |
2191 GPBCodedInputStreamPopLimit(state, limit); | |
2192 } | |
2193 | |
2194 static void MergeRepeatedNotPackedFieldFromCodedInputStream( | |
2195 GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, | |
2196 GPBCodedInputStream *input, GPBExtensionRegistry *extensionRegistry) { | |
2197 GPBCodedInputStreamState *state = &input->state_; | |
2198 id genericArray = GetOrCreateArrayIvarWithField(self, field, syntax); | |
2199 switch (GPBGetFieldDataType(field)) { | |
2200 #define CASE_REPEATED_NOT_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \ | |
2201 case GPBDataType##NAME: { \ | |
2202 TYPE val = GPBCodedInputStreamRead##NAME(state); \ | |
2203 [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \ | |
2204 break; \ | |
2205 } | |
2206 #define CASE_REPEATED_NOT_PACKED_OBJECT(NAME) \ | |
2207 case GPBDataType##NAME: { \ | |
2208 id val = GPBCodedInputStreamReadRetained##NAME(state); \ | |
2209 [(NSMutableArray*)genericArray addObject:val]; \ | |
2210 [val release]; \ | |
2211 break; \ | |
2212 } | |
2213 CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool) | |
2214 CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32) | |
2215 CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32) | |
2216 CASE_REPEATED_NOT_PACKED_POD(Float, float, Float) | |
2217 CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64) | |
2218 CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64) | |
2219 CASE_REPEATED_NOT_PACKED_POD(Double, double, Double) | |
2220 CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32) | |
2221 CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64) | |
2222 CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32) | |
2223 CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64) | |
2224 CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32) | |
2225 CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64) | |
2226 CASE_REPEATED_NOT_PACKED_OBJECT(Bytes) | |
2227 CASE_REPEATED_NOT_PACKED_OBJECT(String) | |
2228 #undef CASE_REPEATED_NOT_PACKED_POD | |
2229 #undef CASE_NOT_PACKED_OBJECT | |
2230 case GPBDataTypeMessage: { | |
2231 GPBMessage *message = [[field.msgClass alloc] init]; | |
2232 [input readMessage:message extensionRegistry:extensionRegistry]; | |
2233 [(NSMutableArray*)genericArray addObject:message]; | |
2234 [message release]; | |
2235 break; | |
2236 } | |
2237 case GPBDataTypeGroup: { | |
2238 GPBMessage *message = [[field.msgClass alloc] init]; | |
2239 [input readGroup:GPBFieldNumber(field) | |
2240 message:message | |
2241 extensionRegistry:extensionRegistry]; | |
2242 [(NSMutableArray*)genericArray addObject:message]; | |
2243 [message release]; | |
2244 break; | |
2245 } | |
2246 case GPBDataTypeEnum: { | |
2247 int32_t val = GPBCodedInputStreamReadEnum(state); | |
2248 if (GPBHasPreservingUnknownEnumSemantics(syntax) || | |
2249 [field isValidEnumValue:val]) { | |
2250 [(GPBEnumArray*)genericArray addRawValue:val]; | |
2251 } else { | |
2252 GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); | |
2253 [unknownFields mergeVarintField:GPBFieldNumber(field) value:val]; | |
2254 } | |
2255 break; | |
2256 } | |
2257 } // switch | |
2258 } | |
2259 | |
2260 - (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input | |
2261 extensionRegistry:(GPBExtensionRegistry *)extensionRegistry { | |
2262 GPBDescriptor *descriptor = [self descriptor]; | |
2263 GPBFileSyntax syntax = descriptor.file.syntax; | |
2264 GPBCodedInputStreamState *state = &input->state_; | |
2265 uint32_t tag = 0; | |
2266 NSUInteger startingIndex = 0; | |
2267 NSArray *fields = descriptor->fields_; | |
2268 NSUInteger numFields = fields.count; | |
2269 while (YES) { | |
2270 BOOL merged = NO; | |
2271 tag = GPBCodedInputStreamReadTag(state); | |
2272 for (NSUInteger i = 0; i < numFields; ++i) { | |
2273 if (startingIndex >= numFields) startingIndex = 0; | |
2274 GPBFieldDescriptor *fieldDescriptor = fields[startingIndex]; | |
2275 if (GPBFieldTag(fieldDescriptor) == tag) { | |
2276 GPBFieldType fieldType = fieldDescriptor.fieldType; | |
2277 if (fieldType == GPBFieldTypeSingle) { | |
2278 MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, syntax, | |
2279 input, extensionRegistry); | |
2280 // Well formed protos will only have a single field once, advance | |
2281 // the starting index to the next field. | |
2282 startingIndex += 1; | |
2283 } else if (fieldType == GPBFieldTypeRepeated) { | |
2284 if (fieldDescriptor.isPackable) { | |
2285 MergeRepeatedPackedFieldFromCodedInputStream( | |
2286 self, fieldDescriptor, syntax, input); | |
2287 // Well formed protos will only have a repeated field that is | |
2288 // packed once, advance the starting index to the next field. | |
2289 startingIndex += 1; | |
2290 } else { | |
2291 MergeRepeatedNotPackedFieldFromCodedInputStream( | |
2292 self, fieldDescriptor, syntax, input, extensionRegistry); | |
2293 } | |
2294 } else { // fieldType == GPBFieldTypeMap | |
2295 // GPB*Dictionary or NSDictionary, exact type doesn't matter at this | |
2296 // point. | |
2297 id map = GetOrCreateMapIvarWithField(self, fieldDescriptor, syntax); | |
2298 [input readMapEntry:map | |
2299 extensionRegistry:extensionRegistry | |
2300 field:fieldDescriptor | |
2301 parentMessage:self]; | |
2302 } | |
2303 merged = YES; | |
2304 break; | |
2305 } else { | |
2306 startingIndex += 1; | |
2307 } | |
2308 } // for(i < numFields) | |
2309 | |
2310 if (!merged) { | |
2311 // Primitive, repeated types can be packed on unpacked on the wire, and | |
2312 // are parsed either way. The above loop covered tag in the preferred | |
2313 // for, so this need to check the alternate form. | |
2314 for (NSUInteger i = 0; i < numFields; ++i) { | |
2315 if (startingIndex >= numFields) startingIndex = 0; | |
2316 GPBFieldDescriptor *fieldDescriptor = fields[startingIndex]; | |
2317 if ((fieldDescriptor.fieldType == GPBFieldTypeRepeated) && | |
2318 !GPBFieldDataTypeIsObject(fieldDescriptor) && | |
2319 (GPBFieldAlternateTag(fieldDescriptor) == tag)) { | |
2320 BOOL alternateIsPacked = !fieldDescriptor.isPackable; | |
2321 if (alternateIsPacked) { | |
2322 MergeRepeatedPackedFieldFromCodedInputStream( | |
2323 self, fieldDescriptor, syntax, input); | |
2324 // Well formed protos will only have a repeated field that is | |
2325 // packed once, advance the starting index to the next field. | |
2326 startingIndex += 1; | |
2327 } else { | |
2328 MergeRepeatedNotPackedFieldFromCodedInputStream( | |
2329 self, fieldDescriptor, syntax, input, extensionRegistry); | |
2330 } | |
2331 merged = YES; | |
2332 break; | |
2333 } else { | |
2334 startingIndex += 1; | |
2335 } | |
2336 } | |
2337 } | |
2338 | |
2339 if (!merged) { | |
2340 if (tag == 0) { | |
2341 // zero signals EOF / limit reached | |
2342 return; | |
2343 } else { | |
2344 if (GPBPreserveUnknownFields(syntax)) { | |
2345 if (![self parseUnknownField:input | |
2346 extensionRegistry:extensionRegistry | |
2347 tag:tag]) { | |
2348 // it's an endgroup tag | |
2349 return; | |
2350 } | |
2351 } else { | |
2352 if (![input skipField:tag]) { | |
2353 return; | |
2354 } | |
2355 } | |
2356 } | |
2357 } // if(!merged) | |
2358 | |
2359 } // while(YES) | |
2360 } | |
2361 | |
2362 #pragma mark - MergeFrom Support | |
2363 | |
2364 - (void)mergeFrom:(GPBMessage *)other { | |
2365 Class selfClass = [self class]; | |
2366 Class otherClass = [other class]; | |
2367 if (!([selfClass isSubclassOfClass:otherClass] || | |
2368 [otherClass isSubclassOfClass:selfClass])) { | |
2369 [NSException raise:NSInvalidArgumentException | |
2370 format:@"Classes must match %@ != %@", selfClass, otherClass]; | |
2371 } | |
2372 | |
2373 // We assume something will be done and become visible. | |
2374 GPBBecomeVisibleToAutocreator(self); | |
2375 | |
2376 GPBDescriptor *descriptor = [[self class] descriptor]; | |
2377 GPBFileSyntax syntax = descriptor.file.syntax; | |
2378 | |
2379 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
2380 GPBFieldType fieldType = field.fieldType; | |
2381 if (fieldType == GPBFieldTypeSingle) { | |
2382 int32_t hasIndex = GPBFieldHasIndex(field); | |
2383 uint32_t fieldNumber = GPBFieldNumber(field); | |
2384 if (!GPBGetHasIvar(other, hasIndex, fieldNumber)) { | |
2385 // Other doesn't have the field set, on to the next. | |
2386 continue; | |
2387 } | |
2388 GPBDataType fieldDataType = GPBGetFieldDataType(field); | |
2389 switch (fieldDataType) { | |
2390 case GPBDataTypeBool: | |
2391 GPBSetBoolIvarWithFieldInternal( | |
2392 self, field, GPBGetMessageBoolField(other, field), syntax); | |
2393 break; | |
2394 case GPBDataTypeSFixed32: | |
2395 case GPBDataTypeEnum: | |
2396 case GPBDataTypeInt32: | |
2397 case GPBDataTypeSInt32: | |
2398 GPBSetInt32IvarWithFieldInternal( | |
2399 self, field, GPBGetMessageInt32Field(other, field), syntax); | |
2400 break; | |
2401 case GPBDataTypeFixed32: | |
2402 case GPBDataTypeUInt32: | |
2403 GPBSetUInt32IvarWithFieldInternal( | |
2404 self, field, GPBGetMessageUInt32Field(other, field), syntax); | |
2405 break; | |
2406 case GPBDataTypeSFixed64: | |
2407 case GPBDataTypeInt64: | |
2408 case GPBDataTypeSInt64: | |
2409 GPBSetInt64IvarWithFieldInternal( | |
2410 self, field, GPBGetMessageInt64Field(other, field), syntax); | |
2411 break; | |
2412 case GPBDataTypeFixed64: | |
2413 case GPBDataTypeUInt64: | |
2414 GPBSetUInt64IvarWithFieldInternal( | |
2415 self, field, GPBGetMessageUInt64Field(other, field), syntax); | |
2416 break; | |
2417 case GPBDataTypeFloat: | |
2418 GPBSetFloatIvarWithFieldInternal( | |
2419 self, field, GPBGetMessageFloatField(other, field), syntax); | |
2420 break; | |
2421 case GPBDataTypeDouble: | |
2422 GPBSetDoubleIvarWithFieldInternal( | |
2423 self, field, GPBGetMessageDoubleField(other, field), syntax); | |
2424 break; | |
2425 case GPBDataTypeBytes: | |
2426 case GPBDataTypeString: { | |
2427 id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field); | |
2428 GPBSetObjectIvarWithFieldInternal(self, field, otherVal, syntax); | |
2429 break; | |
2430 } | |
2431 case GPBDataTypeMessage: | |
2432 case GPBDataTypeGroup: { | |
2433 id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field); | |
2434 if (GPBGetHasIvar(self, hasIndex, fieldNumber)) { | |
2435 GPBMessage *message = | |
2436 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
2437 [message mergeFrom:otherVal]; | |
2438 } else { | |
2439 GPBMessage *message = [otherVal copy]; | |
2440 GPBSetRetainedObjectIvarWithFieldInternal(self, field, message, | |
2441 syntax); | |
2442 } | |
2443 break; | |
2444 } | |
2445 } // switch() | |
2446 } else if (fieldType == GPBFieldTypeRepeated) { | |
2447 // In the case of a list, they need to be appended, and there is no | |
2448 // _hasIvar to worry about setting. | |
2449 id otherArray = | |
2450 GPBGetObjectIvarWithFieldNoAutocreate(other, field); | |
2451 if (otherArray) { | |
2452 GPBDataType fieldDataType = field->description_->dataType; | |
2453 if (GPBDataTypeIsObject(fieldDataType)) { | |
2454 NSMutableArray *resultArray = | |
2455 GetOrCreateArrayIvarWithField(self, field, syntax); | |
2456 [resultArray addObjectsFromArray:otherArray]; | |
2457 } else if (fieldDataType == GPBDataTypeEnum) { | |
2458 GPBEnumArray *resultArray = | |
2459 GetOrCreateArrayIvarWithField(self, field, syntax); | |
2460 [resultArray addRawValuesFromArray:otherArray]; | |
2461 } else { | |
2462 // The array type doesn't matter, that all implment | |
2463 // -addValuesFromArray:. | |
2464 GPBInt32Array *resultArray = | |
2465 GetOrCreateArrayIvarWithField(self, field, syntax); | |
2466 [resultArray addValuesFromArray:otherArray]; | |
2467 } | |
2468 } | |
2469 } else { // fieldType = GPBFieldTypeMap | |
2470 // In the case of a map, they need to be merged, and there is no | |
2471 // _hasIvar to worry about setting. | |
2472 id otherDict = GPBGetObjectIvarWithFieldNoAutocreate(other, field); | |
2473 if (otherDict) { | |
2474 GPBDataType keyDataType = field.mapKeyDataType; | |
2475 GPBDataType valueDataType = field->description_->dataType; | |
2476 if (GPBDataTypeIsObject(keyDataType) && | |
2477 GPBDataTypeIsObject(valueDataType)) { | |
2478 NSMutableDictionary *resultDict = | |
2479 GetOrCreateMapIvarWithField(self, field, syntax); | |
2480 [resultDict addEntriesFromDictionary:otherDict]; | |
2481 } else if (valueDataType == GPBDataTypeEnum) { | |
2482 // The exact type doesn't matter, just need to know it is a | |
2483 // GPB*EnumDictionary. | |
2484 GPBInt32EnumDictionary *resultDict = | |
2485 GetOrCreateMapIvarWithField(self, field, syntax); | |
2486 [resultDict addRawEntriesFromDictionary:otherDict]; | |
2487 } else { | |
2488 // The exact type doesn't matter, they all implement | |
2489 // -addEntriesFromDictionary:. | |
2490 GPBInt32Int32Dictionary *resultDict = | |
2491 GetOrCreateMapIvarWithField(self, field, syntax); | |
2492 [resultDict addEntriesFromDictionary:otherDict]; | |
2493 } | |
2494 } | |
2495 } // if (fieldType)..else if...else | |
2496 } // for(fields) | |
2497 | |
2498 // Unknown fields. | |
2499 if (!unknownFields_) { | |
2500 [self setUnknownFields:other.unknownFields]; | |
2501 } else { | |
2502 [unknownFields_ mergeUnknownFields:other.unknownFields]; | |
2503 } | |
2504 | |
2505 // Extensions | |
2506 | |
2507 if (other->extensionMap_.count == 0) { | |
2508 return; | |
2509 } | |
2510 | |
2511 if (extensionMap_ == nil) { | |
2512 extensionMap_ = | |
2513 CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self)); | |
2514 } else { | |
2515 for (GPBExtensionDescriptor *extension in other->extensionMap_) { | |
2516 id otherValue = [other->extensionMap_ objectForKey:extension]; | |
2517 id value = [extensionMap_ objectForKey:extension]; | |
2518 BOOL isMessageExtension = GPBExtensionIsMessage(extension); | |
2519 | |
2520 if (extension.repeated) { | |
2521 NSMutableArray *list = value; | |
2522 if (list == nil) { | |
2523 list = [[NSMutableArray alloc] init]; | |
2524 [extensionMap_ setObject:list forKey:extension]; | |
2525 [list release]; | |
2526 } | |
2527 if (isMessageExtension) { | |
2528 for (GPBMessage *otherListValue in otherValue) { | |
2529 GPBMessage *copiedValue = [otherListValue copy]; | |
2530 [list addObject:copiedValue]; | |
2531 [copiedValue release]; | |
2532 } | |
2533 } else { | |
2534 [list addObjectsFromArray:otherValue]; | |
2535 } | |
2536 } else { | |
2537 if (isMessageExtension) { | |
2538 if (value) { | |
2539 [(GPBMessage *)value mergeFrom:(GPBMessage *)otherValue]; | |
2540 } else { | |
2541 GPBMessage *copiedValue = [otherValue copy]; | |
2542 [extensionMap_ setObject:copiedValue forKey:extension]; | |
2543 [copiedValue release]; | |
2544 } | |
2545 } else { | |
2546 [extensionMap_ setObject:otherValue forKey:extension]; | |
2547 } | |
2548 } | |
2549 | |
2550 if (isMessageExtension && !extension.isRepeated) { | |
2551 GPBMessage *autocreatedValue = | |
2552 [[autocreatedExtensionMap_ objectForKey:extension] retain]; | |
2553 // Must remove from the map before calling GPBClearMessageAutocreator() | |
2554 // so that GPBClearMessageAutocreator() knows its safe to clear. | |
2555 [autocreatedExtensionMap_ removeObjectForKey:extension]; | |
2556 GPBClearMessageAutocreator(autocreatedValue); | |
2557 [autocreatedValue release]; | |
2558 } | |
2559 } | |
2560 } | |
2561 } | |
2562 | |
2563 #pragma mark - isEqual: & hash Support | |
2564 | |
2565 - (BOOL)isEqual:(GPBMessage *)other { | |
2566 if (other == self) { | |
2567 return YES; | |
2568 } | |
2569 if (![other isKindOfClass:[self class]] && | |
2570 ![self isKindOfClass:[other class]]) { | |
2571 return NO; | |
2572 } | |
2573 | |
2574 GPBDescriptor *descriptor = [[self class] descriptor]; | |
2575 uint8_t *selfStorage = (uint8_t *)messageStorage_; | |
2576 uint8_t *otherStorage = (uint8_t *)other->messageStorage_; | |
2577 | |
2578 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
2579 if (GPBFieldIsMapOrArray(field)) { | |
2580 // In the case of a list or map, there is no _hasIvar to worry about. | |
2581 // NOTE: These are NSArray/GPB*Array or NSDictionary/GPB*Dictionary, but | |
2582 // the type doesn't really matter as the objects all support -count and | |
2583 // -isEqual:. | |
2584 NSArray *resultMapOrArray = | |
2585 GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
2586 NSArray *otherMapOrArray = | |
2587 GPBGetObjectIvarWithFieldNoAutocreate(other, field); | |
2588 // nil and empty are equal | |
2589 if (resultMapOrArray.count != 0 || otherMapOrArray.count != 0) { | |
2590 if (![resultMapOrArray isEqual:otherMapOrArray]) { | |
2591 return NO; | |
2592 } | |
2593 } | |
2594 } else { // Single field | |
2595 int32_t hasIndex = GPBFieldHasIndex(field); | |
2596 uint32_t fieldNum = GPBFieldNumber(field); | |
2597 BOOL selfHas = GPBGetHasIvar(self, hasIndex, fieldNum); | |
2598 BOOL otherHas = GPBGetHasIvar(other, hasIndex, fieldNum); | |
2599 if (selfHas != otherHas) { | |
2600 return NO; // Differing has values, not equal. | |
2601 } | |
2602 if (!selfHas) { | |
2603 // Same has values, was no, nothing else to check for this field. | |
2604 continue; | |
2605 } | |
2606 // Now compare the values. | |
2607 GPBDataType fieldDataType = GPBGetFieldDataType(field); | |
2608 size_t fieldOffset = field->description_->offset; | |
2609 switch (fieldDataType) { | |
2610 case GPBDataTypeBool: { | |
2611 BOOL *selfValPtr = (BOOL *)&selfStorage[fieldOffset]; | |
2612 BOOL *otherValPtr = (BOOL *)&otherStorage[fieldOffset]; | |
2613 if (*selfValPtr != *otherValPtr) { | |
2614 return NO; | |
2615 } | |
2616 break; | |
2617 } | |
2618 case GPBDataTypeSFixed32: | |
2619 case GPBDataTypeInt32: | |
2620 case GPBDataTypeSInt32: | |
2621 case GPBDataTypeEnum: | |
2622 case GPBDataTypeFixed32: | |
2623 case GPBDataTypeUInt32: | |
2624 case GPBDataTypeFloat: { | |
2625 _GPBCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits
); | |
2626 // These are all 32bit, signed/unsigned doesn't matter for equality. | |
2627 uint32_t *selfValPtr = (uint32_t *)&selfStorage[fieldOffset]; | |
2628 uint32_t *otherValPtr = (uint32_t *)&otherStorage[fieldOffset]; | |
2629 if (*selfValPtr != *otherValPtr) { | |
2630 return NO; | |
2631 } | |
2632 break; | |
2633 } | |
2634 case GPBDataTypeSFixed64: | |
2635 case GPBDataTypeInt64: | |
2636 case GPBDataTypeSInt64: | |
2637 case GPBDataTypeFixed64: | |
2638 case GPBDataTypeUInt64: | |
2639 case GPBDataTypeDouble: { | |
2640 _GPBCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bi
ts); | |
2641 // These are all 64bit, signed/unsigned doesn't matter for equality. | |
2642 uint64_t *selfValPtr = (uint64_t *)&selfStorage[fieldOffset]; | |
2643 uint64_t *otherValPtr = (uint64_t *)&otherStorage[fieldOffset]; | |
2644 if (*selfValPtr != *otherValPtr) { | |
2645 return NO; | |
2646 } | |
2647 break; | |
2648 } | |
2649 case GPBDataTypeBytes: | |
2650 case GPBDataTypeString: | |
2651 case GPBDataTypeMessage: | |
2652 case GPBDataTypeGroup: { | |
2653 // Type doesn't matter here, they all implement -isEqual:. | |
2654 id *selfValPtr = (id *)&selfStorage[fieldOffset]; | |
2655 id *otherValPtr = (id *)&otherStorage[fieldOffset]; | |
2656 if (![*selfValPtr isEqual:*otherValPtr]) { | |
2657 return NO; | |
2658 } | |
2659 break; | |
2660 } | |
2661 } // switch() | |
2662 } // if(mapOrArray)...else | |
2663 } // for(fields) | |
2664 | |
2665 // nil and empty are equal | |
2666 if (extensionMap_.count != 0 || other->extensionMap_.count != 0) { | |
2667 if (![extensionMap_ isEqual:other->extensionMap_]) { | |
2668 return NO; | |
2669 } | |
2670 } | |
2671 | |
2672 // nil and empty are equal | |
2673 GPBUnknownFieldSet *otherUnknowns = other->unknownFields_; | |
2674 if ([unknownFields_ countOfFields] != 0 || | |
2675 [otherUnknowns countOfFields] != 0) { | |
2676 if (![unknownFields_ isEqual:otherUnknowns]) { | |
2677 return NO; | |
2678 } | |
2679 } | |
2680 | |
2681 return YES; | |
2682 } | |
2683 | |
2684 // It is very difficult to implement a generic hash for ProtoBuf messages that | |
2685 // will perform well. If you need hashing on your ProtoBufs (eg you are using | |
2686 // them as dictionary keys) you will probably want to implement a ProtoBuf | |
2687 // message specific hash as a category on your protobuf class. Do not make it a | |
2688 // category on GPBMessage as you will conflict with this hash, and will possibly | |
2689 // override hash for all generated protobufs. A good implementation of hash will | |
2690 // be really fast, so we would recommend only hashing protobufs that have an | |
2691 // identifier field of some kind that you can easily hash. If you implement | |
2692 // hash, we would strongly recommend overriding isEqual: in your category as | |
2693 // well, as the default implementation of isEqual: is extremely slow, and may | |
2694 // drastically affect performance in large sets. | |
2695 - (NSUInteger)hash { | |
2696 GPBDescriptor *descriptor = [[self class] descriptor]; | |
2697 const NSUInteger prime = 19; | |
2698 uint8_t *storage = (uint8_t *)messageStorage_; | |
2699 | |
2700 // Start with the descriptor and then mix it with some instance info. | |
2701 // Hopefully that will give a spread based on classes and what fields are set. | |
2702 NSUInteger result = (NSUInteger)descriptor; | |
2703 | |
2704 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
2705 if (GPBFieldIsMapOrArray(field)) { | |
2706 // Exact type doesn't matter, just check if there are any elements. | |
2707 NSArray *mapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field); | |
2708 NSUInteger count = mapOrArray.count; | |
2709 if (count) { | |
2710 // NSArray/NSDictionary use count, use the field number and the count. | |
2711 result = prime * result + GPBFieldNumber(field); | |
2712 result = prime * result + count; | |
2713 } | |
2714 } else if (GPBGetHasIvarField(self, field)) { | |
2715 // Just using the field number seemed simple/fast, but then a small | |
2716 // message class where all the same fields are always set (to different | |
2717 // things would end up all with the same hash, so pull in some data). | |
2718 GPBDataType fieldDataType = GPBGetFieldDataType(field); | |
2719 size_t fieldOffset = field->description_->offset; | |
2720 switch (fieldDataType) { | |
2721 case GPBDataTypeBool: { | |
2722 BOOL *valPtr = (BOOL *)&storage[fieldOffset]; | |
2723 result = prime * result + *valPtr; | |
2724 break; | |
2725 } | |
2726 case GPBDataTypeSFixed32: | |
2727 case GPBDataTypeInt32: | |
2728 case GPBDataTypeSInt32: | |
2729 case GPBDataTypeEnum: | |
2730 case GPBDataTypeFixed32: | |
2731 case GPBDataTypeUInt32: | |
2732 case GPBDataTypeFloat: { | |
2733 _GPBCompileAssert(sizeof(float) == sizeof(uint32_t), float_not_32_bits
); | |
2734 // These are all 32bit, just mix it in. | |
2735 uint32_t *valPtr = (uint32_t *)&storage[fieldOffset]; | |
2736 result = prime * result + *valPtr; | |
2737 break; | |
2738 } | |
2739 case GPBDataTypeSFixed64: | |
2740 case GPBDataTypeInt64: | |
2741 case GPBDataTypeSInt64: | |
2742 case GPBDataTypeFixed64: | |
2743 case GPBDataTypeUInt64: | |
2744 case GPBDataTypeDouble: { | |
2745 _GPBCompileAssert(sizeof(double) == sizeof(uint64_t), double_not_64_bi
ts); | |
2746 // These are all 64bit, just mix what fits into an NSUInteger in. | |
2747 uint64_t *valPtr = (uint64_t *)&storage[fieldOffset]; | |
2748 result = prime * result + (NSUInteger)(*valPtr); | |
2749 break; | |
2750 } | |
2751 case GPBDataTypeBytes: | |
2752 case GPBDataTypeString: { | |
2753 // Type doesn't matter here, they both implement -hash:. | |
2754 id *valPtr = (id *)&storage[fieldOffset]; | |
2755 result = prime * result + [*valPtr hash]; | |
2756 break; | |
2757 } | |
2758 | |
2759 case GPBDataTypeMessage: | |
2760 case GPBDataTypeGroup: { | |
2761 GPBMessage **valPtr = (GPBMessage **)&storage[fieldOffset]; | |
2762 // Could call -hash on the sub message, but that could recurse pretty | |
2763 // deep; follow the lead of NSArray/NSDictionary and don't really | |
2764 // recurse for hash, instead use the field number and the descriptor | |
2765 // of the sub message. Yes, this could suck for a bunch of messages | |
2766 // where they all only differ in the sub messages, but if you are | |
2767 // using a message with sub messages for something that needs -hash, | |
2768 // odds are you are also copying them as keys, and that deep copy | |
2769 // will also suck. | |
2770 result = prime * result + GPBFieldNumber(field); | |
2771 result = prime * result + (NSUInteger)[[*valPtr class] descriptor]; | |
2772 break; | |
2773 } | |
2774 } // switch() | |
2775 } | |
2776 } | |
2777 | |
2778 // Unknowns and extensions are not included. | |
2779 | |
2780 return result; | |
2781 } | |
2782 | |
2783 #pragma mark - Description Support | |
2784 | |
2785 - (NSString *)description { | |
2786 NSString *textFormat = GPBTextFormatForMessage(self, @" "); | |
2787 NSString *description = [NSString | |
2788 stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat]; | |
2789 return description; | |
2790 } | |
2791 | |
2792 #if DEBUG | |
2793 | |
2794 // Xcode 5.1 added support for custom quick look info. | |
2795 // https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/CustomC
lassDisplay_in_QuickLook/CH01-quick_look_for_custom_objects/CH01-quick_look_for_
custom_objects.html#//apple_ref/doc/uid/TP40014001-CH2-SW1 | |
2796 - (id)debugQuickLookObject { | |
2797 return GPBTextFormatForMessage(self, nil); | |
2798 } | |
2799 | |
2800 #endif // DEBUG | |
2801 | |
2802 #pragma mark - SerializedSize | |
2803 | |
2804 - (size_t)serializedSize { | |
2805 GPBDescriptor *descriptor = [[self class] descriptor]; | |
2806 size_t result = 0; | |
2807 | |
2808 // Has check is done explicitly, so GPBGetObjectIvarWithFieldNoAutocreate() | |
2809 // avoids doing the has check again. | |
2810 | |
2811 // Fields. | |
2812 for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) { | |
2813 GPBFieldType fieldType = fieldDescriptor.fieldType; | |
2814 GPBDataType fieldDataType = GPBGetFieldDataType(fieldDescriptor); | |
2815 | |
2816 // Single Fields | |
2817 if (fieldType == GPBFieldTypeSingle) { | |
2818 BOOL selfHas = GPBGetHasIvarField(self, fieldDescriptor); | |
2819 if (!selfHas) { | |
2820 continue; // Nothing to do. | |
2821 } | |
2822 | |
2823 uint32_t fieldNumber = GPBFieldNumber(fieldDescriptor); | |
2824 | |
2825 switch (fieldDataType) { | |
2826 #define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \ | |
2827 case GPBDataType##NAME: { \ | |
2828 TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor)
; \ | |
2829 result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \ | |
2830 break; \ | |
2831 } | |
2832 #define CASE_SINGLE_OBJECT(NAME) \ | |
2833 case GPBDataType##NAME: { \ | |
2834 id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescrip
tor); \ | |
2835 result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \ | |
2836 break; \ | |
2837 } | |
2838 CASE_SINGLE_POD(Bool, BOOL, Bool) | |
2839 CASE_SINGLE_POD(Fixed32, uint32_t, UInt32) | |
2840 CASE_SINGLE_POD(SFixed32, int32_t, Int32) | |
2841 CASE_SINGLE_POD(Float, float, Float) | |
2842 CASE_SINGLE_POD(Fixed64, uint64_t, UInt64) | |
2843 CASE_SINGLE_POD(SFixed64, int64_t, Int64) | |
2844 CASE_SINGLE_POD(Double, double, Double) | |
2845 CASE_SINGLE_POD(Int32, int32_t, Int32) | |
2846 CASE_SINGLE_POD(Int64, int64_t, Int64) | |
2847 CASE_SINGLE_POD(SInt32, int32_t, Int32) | |
2848 CASE_SINGLE_POD(SInt64, int64_t, Int64) | |
2849 CASE_SINGLE_POD(UInt32, uint32_t, UInt32) | |
2850 CASE_SINGLE_POD(UInt64, uint64_t, UInt64) | |
2851 CASE_SINGLE_OBJECT(Bytes) | |
2852 CASE_SINGLE_OBJECT(String) | |
2853 CASE_SINGLE_OBJECT(Message) | |
2854 CASE_SINGLE_OBJECT(Group) | |
2855 CASE_SINGLE_POD(Enum, int32_t, Int32) | |
2856 #undef CASE_SINGLE_POD | |
2857 #undef CASE_SINGLE_OBJECT | |
2858 } | |
2859 | |
2860 // Repeated Fields | |
2861 } else if (fieldType == GPBFieldTypeRepeated) { | |
2862 id genericArray = | |
2863 GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); | |
2864 NSUInteger count = [genericArray count]; | |
2865 if (count == 0) { | |
2866 continue; // Nothing to add. | |
2867 } | |
2868 __block size_t dataSize = 0; | |
2869 | |
2870 switch (fieldDataType) { | |
2871 #define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE) \ | |
2872 CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ) | |
2873 #define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME) \ | |
2874 case GPBDataType##NAME: { \ | |
2875 GPB##ARRAY_TYPE##Array *array = genericArray; \ | |
2876 [array enumerate##ARRAY_ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, N
SUInteger idx, BOOL *stop) { \ | |
2877 _Pragma("unused(idx, stop)"); \ | |
2878 dataSize += GPBCompute##NAME##SizeNoTag(value); \ | |
2879 }]; \ | |
2880 break; \ | |
2881 } | |
2882 #define CASE_REPEATED_OBJECT(NAME) \ | |
2883 case GPBDataType##NAME: { \ | |
2884 for (id value in genericArray) { \ | |
2885 dataSize += GPBCompute##NAME##SizeNoTag(value); \ | |
2886 } \ | |
2887 break; \ | |
2888 } | |
2889 CASE_REPEATED_POD(Bool, BOOL, Bool) | |
2890 CASE_REPEATED_POD(Fixed32, uint32_t, UInt32) | |
2891 CASE_REPEATED_POD(SFixed32, int32_t, Int32) | |
2892 CASE_REPEATED_POD(Float, float, Float) | |
2893 CASE_REPEATED_POD(Fixed64, uint64_t, UInt64) | |
2894 CASE_REPEATED_POD(SFixed64, int64_t, Int64) | |
2895 CASE_REPEATED_POD(Double, double, Double) | |
2896 CASE_REPEATED_POD(Int32, int32_t, Int32) | |
2897 CASE_REPEATED_POD(Int64, int64_t, Int64) | |
2898 CASE_REPEATED_POD(SInt32, int32_t, Int32) | |
2899 CASE_REPEATED_POD(SInt64, int64_t, Int64) | |
2900 CASE_REPEATED_POD(UInt32, uint32_t, UInt32) | |
2901 CASE_REPEATED_POD(UInt64, uint64_t, UInt64) | |
2902 CASE_REPEATED_OBJECT(Bytes) | |
2903 CASE_REPEATED_OBJECT(String) | |
2904 CASE_REPEATED_OBJECT(Message) | |
2905 CASE_REPEATED_OBJECT(Group) | |
2906 CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw) | |
2907 #undef CASE_REPEATED_POD | |
2908 #undef CASE_REPEATED_POD_EXTRA | |
2909 #undef CASE_REPEATED_OBJECT | |
2910 } // switch | |
2911 result += dataSize; | |
2912 size_t tagSize = GPBComputeTagSize(GPBFieldNumber(fieldDescriptor)); | |
2913 if (fieldDataType == GPBDataTypeGroup) { | |
2914 // Groups have both a start and an end tag. | |
2915 tagSize *= 2; | |
2916 } | |
2917 if (fieldDescriptor.isPackable) { | |
2918 result += tagSize; | |
2919 result += GPBComputeSizeTSizeAsInt32NoTag(dataSize); | |
2920 } else { | |
2921 result += count * tagSize; | |
2922 } | |
2923 | |
2924 // Map<> Fields | |
2925 } else { // fieldType == GPBFieldTypeMap | |
2926 if (GPBDataTypeIsObject(fieldDataType) && | |
2927 (fieldDescriptor.mapKeyDataType == GPBDataTypeString)) { | |
2928 // If key type was string, then the map is an NSDictionary. | |
2929 NSDictionary *map = | |
2930 GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); | |
2931 if (map) { | |
2932 result += GPBDictionaryComputeSizeInternalHelper(map, fieldDescriptor)
; | |
2933 } | |
2934 } else { | |
2935 // Type will be GPB*GroupDictionary, exact type doesn't matter. | |
2936 GPBInt32Int32Dictionary *map = | |
2937 GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); | |
2938 result += [map computeSerializedSizeAsField:fieldDescriptor]; | |
2939 } | |
2940 } | |
2941 } // for(fields) | |
2942 | |
2943 // Add any unknown fields. | |
2944 if (descriptor.wireFormat) { | |
2945 result += [unknownFields_ serializedSizeAsMessageSet]; | |
2946 } else { | |
2947 result += [unknownFields_ serializedSize]; | |
2948 } | |
2949 | |
2950 // Add any extensions. | |
2951 for (GPBExtensionDescriptor *extension in extensionMap_) { | |
2952 id value = [extensionMap_ objectForKey:extension]; | |
2953 result += GPBComputeExtensionSerializedSizeIncludingTag(extension, value); | |
2954 } | |
2955 | |
2956 return result; | |
2957 } | |
2958 | |
2959 #pragma mark - Resolve Methods Support | |
2960 | |
2961 typedef struct ResolveIvarAccessorMethodResult { | |
2962 IMP impToAdd; | |
2963 SEL encodingSelector; | |
2964 } ResolveIvarAccessorMethodResult; | |
2965 | |
2966 static void ResolveIvarGet(GPBFieldDescriptor *field, | |
2967 ResolveIvarAccessorMethodResult *result) { | |
2968 GPBDataType fieldDataType = GPBGetFieldDataType(field); | |
2969 switch (fieldDataType) { | |
2970 #define CASE_GET(NAME, TYPE, TRUE_NAME) \ | |
2971 case GPBDataType##NAME: { \ | |
2972 result->impToAdd = imp_implementationWithBlock(^(id obj) { \ | |
2973 return GPBGetMessage##TRUE_NAME##Field(obj, field); \ | |
2974 }); \ | |
2975 result->encodingSelector = @selector(get##NAME); \ | |
2976 break; \ | |
2977 } | |
2978 #define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME) \ | |
2979 case GPBDataType##NAME: { \ | |
2980 result->impToAdd = imp_implementationWithBlock(^(id obj) { \ | |
2981 return GPBGetObjectIvarWithField(obj, field); \ | |
2982 }); \ | |
2983 result->encodingSelector = @selector(get##NAME); \ | |
2984 break; \ | |
2985 } | |
2986 CASE_GET(Bool, BOOL, Bool) | |
2987 CASE_GET(Fixed32, uint32_t, UInt32) | |
2988 CASE_GET(SFixed32, int32_t, Int32) | |
2989 CASE_GET(Float, float, Float) | |
2990 CASE_GET(Fixed64, uint64_t, UInt64) | |
2991 CASE_GET(SFixed64, int64_t, Int64) | |
2992 CASE_GET(Double, double, Double) | |
2993 CASE_GET(Int32, int32_t, Int32) | |
2994 CASE_GET(Int64, int64_t, Int64) | |
2995 CASE_GET(SInt32, int32_t, Int32) | |
2996 CASE_GET(SInt64, int64_t, Int64) | |
2997 CASE_GET(UInt32, uint32_t, UInt32) | |
2998 CASE_GET(UInt64, uint64_t, UInt64) | |
2999 CASE_GET_OBJECT(Bytes, id, Object) | |
3000 CASE_GET_OBJECT(String, id, Object) | |
3001 CASE_GET_OBJECT(Message, id, Object) | |
3002 CASE_GET_OBJECT(Group, id, Object) | |
3003 CASE_GET(Enum, int32_t, Enum) | |
3004 #undef CASE_GET | |
3005 } | |
3006 } | |
3007 | |
3008 static void ResolveIvarSet(GPBFieldDescriptor *field, | |
3009 GPBFileSyntax syntax, | |
3010 ResolveIvarAccessorMethodResult *result) { | |
3011 GPBDataType fieldDataType = GPBGetFieldDataType(field); | |
3012 switch (fieldDataType) { | |
3013 #define CASE_SET(NAME, TYPE, TRUE_NAME) \ | |
3014 case GPBDataType##NAME: { \ | |
3015 result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { \ | |
3016 return GPBSet##TRUE_NAME##IvarWithFieldInternal(obj, field, value, synta
x); \ | |
3017 }); \ | |
3018 result->encodingSelector = @selector(set##NAME:); \ | |
3019 break; \ | |
3020 } | |
3021 CASE_SET(Bool, BOOL, Bool) | |
3022 CASE_SET(Fixed32, uint32_t, UInt32) | |
3023 CASE_SET(SFixed32, int32_t, Int32) | |
3024 CASE_SET(Float, float, Float) | |
3025 CASE_SET(Fixed64, uint64_t, UInt64) | |
3026 CASE_SET(SFixed64, int64_t, Int64) | |
3027 CASE_SET(Double, double, Double) | |
3028 CASE_SET(Int32, int32_t, Int32) | |
3029 CASE_SET(Int64, int64_t, Int64) | |
3030 CASE_SET(SInt32, int32_t, Int32) | |
3031 CASE_SET(SInt64, int64_t, Int64) | |
3032 CASE_SET(UInt32, uint32_t, UInt32) | |
3033 CASE_SET(UInt64, uint64_t, UInt64) | |
3034 CASE_SET(Bytes, id, Object) | |
3035 CASE_SET(String, id, Object) | |
3036 CASE_SET(Message, id, Object) | |
3037 CASE_SET(Group, id, Object) | |
3038 CASE_SET(Enum, int32_t, Enum) | |
3039 #undef CASE_SET | |
3040 } | |
3041 } | |
3042 | |
3043 + (BOOL)resolveInstanceMethod:(SEL)sel { | |
3044 const GPBDescriptor *descriptor = [self descriptor]; | |
3045 if (!descriptor) { | |
3046 return NO; | |
3047 } | |
3048 | |
3049 // NOTE: hasOrCountSel_/setHasSel_ will be NULL if the field for the given | |
3050 // message should not have has support (done in GPBDescriptor.m), so there is | |
3051 // no need for checks here to see if has*/setHas* are allowed. | |
3052 | |
3053 ResolveIvarAccessorMethodResult result = {NULL, NULL}; | |
3054 for (GPBFieldDescriptor *field in descriptor->fields_) { | |
3055 BOOL isMapOrArray = GPBFieldIsMapOrArray(field); | |
3056 if (!isMapOrArray) { | |
3057 // Single fields. | |
3058 if (sel == field->getSel_) { | |
3059 ResolveIvarGet(field, &result); | |
3060 break; | |
3061 } else if (sel == field->setSel_) { | |
3062 ResolveIvarSet(field, descriptor.file.syntax, &result); | |
3063 break; | |
3064 } else if (sel == field->hasOrCountSel_) { | |
3065 int32_t index = GPBFieldHasIndex(field); | |
3066 uint32_t fieldNum = GPBFieldNumber(field); | |
3067 result.impToAdd = imp_implementationWithBlock(^(id obj) { | |
3068 return GPBGetHasIvar(obj, index, fieldNum); | |
3069 }); | |
3070 result.encodingSelector = @selector(getBool); | |
3071 break; | |
3072 } else if (sel == field->setHasSel_) { | |
3073 result.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) { | |
3074 if (value) { | |
3075 [NSException raise:NSInvalidArgumentException | |
3076 format:@"%@: %@ can only be set to NO (to clear field)."
, | |
3077 [obj class], | |
3078 NSStringFromSelector(field->setHasSel_)]; | |
3079 } | |
3080 GPBClearMessageField(obj, field); | |
3081 }); | |
3082 result.encodingSelector = @selector(setBool:); | |
3083 break; | |
3084 } else { | |
3085 GPBOneofDescriptor *oneof = field->containingOneof_; | |
3086 if (oneof && (sel == oneof->caseSel_)) { | |
3087 int32_t index = oneof->oneofDescription_->index; | |
3088 result.impToAdd = imp_implementationWithBlock(^(id obj) { | |
3089 return GPBGetHasOneof(obj, index); | |
3090 }); | |
3091 result.encodingSelector = @selector(getEnum); | |
3092 break; | |
3093 } | |
3094 } | |
3095 } else { | |
3096 // map<>/repeated fields. | |
3097 if (sel == field->getSel_) { | |
3098 if (field.fieldType == GPBFieldTypeRepeated) { | |
3099 result.impToAdd = imp_implementationWithBlock(^(id obj) { | |
3100 return GetArrayIvarWithField(obj, field); | |
3101 }); | |
3102 } else { | |
3103 result.impToAdd = imp_implementationWithBlock(^(id obj) { | |
3104 return GetMapIvarWithField(obj, field); | |
3105 }); | |
3106 } | |
3107 result.encodingSelector = @selector(getArray); | |
3108 break; | |
3109 } else if (sel == field->setSel_) { | |
3110 // Local for syntax so the block can directly capture it and not the | |
3111 // full lookup. | |
3112 const GPBFileSyntax syntax = descriptor.file.syntax; | |
3113 result.impToAdd = imp_implementationWithBlock(^(id obj, id value) { | |
3114 return GPBSetObjectIvarWithFieldInternal(obj, field, value, syntax); | |
3115 }); | |
3116 result.encodingSelector = @selector(setArray:); | |
3117 break; | |
3118 } else if (sel == field->hasOrCountSel_) { | |
3119 result.impToAdd = imp_implementationWithBlock(^(id obj) { | |
3120 // Type doesn't matter, all *Array and *Dictionary types support | |
3121 // -count. | |
3122 NSArray *arrayOrMap = | |
3123 GPBGetObjectIvarWithFieldNoAutocreate(obj, field); | |
3124 return [arrayOrMap count]; | |
3125 }); | |
3126 result.encodingSelector = @selector(getArrayCount); | |
3127 break; | |
3128 } | |
3129 } | |
3130 } | |
3131 if (result.impToAdd) { | |
3132 const char *encoding = | |
3133 GPBMessageEncodingForSelector(result.encodingSelector, YES); | |
3134 BOOL methodAdded = class_addMethod(descriptor.messageClass, sel, | |
3135 result.impToAdd, encoding); | |
3136 return methodAdded; | |
3137 } | |
3138 return [super resolveInstanceMethod:sel]; | |
3139 } | |
3140 | |
3141 + (BOOL)resolveClassMethod:(SEL)sel { | |
3142 // Extensions scoped to a Message and looked up via class methods. | |
3143 if (GPBResolveExtensionClassMethod(self, sel)) { | |
3144 return YES; | |
3145 } | |
3146 return [super resolveClassMethod:sel]; | |
3147 } | |
3148 | |
3149 #pragma mark - NSCoding Support | |
3150 | |
3151 + (BOOL)supportsSecureCoding { | |
3152 return YES; | |
3153 } | |
3154 | |
3155 - (instancetype)initWithCoder:(NSCoder *)aDecoder { | |
3156 self = [self init]; | |
3157 if (self) { | |
3158 NSData *data = | |
3159 [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey]; | |
3160 if (data.length) { | |
3161 [self mergeFromData:data extensionRegistry:nil]; | |
3162 } | |
3163 } | |
3164 return self; | |
3165 } | |
3166 | |
3167 - (void)encodeWithCoder:(NSCoder *)aCoder { | |
3168 NSData *data = [self data]; | |
3169 if (data.length) { | |
3170 [aCoder encodeObject:data forKey:kGPBDataCoderKey]; | |
3171 } | |
3172 } | |
3173 | |
3174 #pragma mark - KVC Support | |
3175 | |
3176 + (BOOL)accessInstanceVariablesDirectly { | |
3177 // Make sure KVC doesn't use instance variables. | |
3178 return NO; | |
3179 } | |
3180 | |
3181 @end | |
OLD | NEW |