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 "GPBUnknownFieldSet_PackagePrivate.h" | |
32 | |
33 #import "GPBCodedInputStream_PackagePrivate.h" | |
34 #import "GPBCodedOutputStream.h" | |
35 #import "GPBUnknownField_PackagePrivate.h" | |
36 #import "GPBUtilities.h" | |
37 #import "GPBWireFormat.h" | |
38 | |
39 #pragma mark CFDictionaryKeyCallBacks | |
40 | |
41 // We use a custom dictionary here because our keys are numbers and | |
42 // conversion back and forth from NSNumber was costing us performance. | |
43 // If/when we move to C++ this could be done using a std::map and some | |
44 // careful retain/release calls. | |
45 | |
46 static const void *GPBUnknownFieldSetKeyRetain(CFAllocatorRef allocator, | |
47 const void *value) { | |
48 #pragma unused(allocator) | |
49 return value; | |
50 } | |
51 | |
52 static void GPBUnknownFieldSetKeyRelease(CFAllocatorRef allocator, | |
53 const void *value) { | |
54 #pragma unused(allocator) | |
55 #pragma unused(value) | |
56 } | |
57 | |
58 static CFStringRef GPBUnknownFieldSetCopyKeyDescription(const void *value) { | |
59 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), | |
60 (int)value); | |
61 } | |
62 | |
63 static Boolean GPBUnknownFieldSetKeyEqual(const void *value1, | |
64 const void *value2) { | |
65 return value1 == value2; | |
66 } | |
67 | |
68 static CFHashCode GPBUnknownFieldSetKeyHash(const void *value) { | |
69 return (CFHashCode)value; | |
70 } | |
71 | |
72 #pragma mark Helpers | |
73 | |
74 static void checkNumber(int32_t number) { | |
75 if (number == 0) { | |
76 [NSException raise:NSInvalidArgumentException | |
77 format:@"Zero is not a valid field number."]; | |
78 } | |
79 } | |
80 | |
81 @implementation GPBUnknownFieldSet { | |
82 @package | |
83 CFMutableDictionaryRef fields_; | |
84 } | |
85 | |
86 static void CopyWorker(const void *key, const void *value, void *context) { | |
87 #pragma unused(key) | |
88 GPBUnknownField *field = value; | |
89 GPBUnknownFieldSet *result = context; | |
90 | |
91 GPBUnknownField *copied = [field copy]; | |
92 [result addField:copied]; | |
93 [copied release]; | |
94 } | |
95 | |
96 - (id)copyWithZone:(NSZone *)zone { | |
97 GPBUnknownFieldSet *result = [[GPBUnknownFieldSet allocWithZone:zone] init]; | |
98 if (fields_) { | |
99 CFDictionaryApplyFunction(fields_, CopyWorker, result); | |
100 } | |
101 return result; | |
102 } | |
103 | |
104 - (void)dealloc { | |
105 if (fields_) { | |
106 CFRelease(fields_); | |
107 } | |
108 [super dealloc]; | |
109 } | |
110 | |
111 - (BOOL)isEqual:(id)object { | |
112 BOOL equal = NO; | |
113 if ([object isKindOfClass:[GPBUnknownFieldSet class]]) { | |
114 GPBUnknownFieldSet *set = (GPBUnknownFieldSet *)object; | |
115 if ((fields_ == NULL) && (set->fields_ == NULL)) { | |
116 equal = YES; | |
117 } else if ((fields_ != NULL) && (set->fields_ != NULL)) { | |
118 equal = CFEqual(fields_, set->fields_); | |
119 } | |
120 } | |
121 return equal; | |
122 } | |
123 | |
124 - (NSUInteger)hash { | |
125 // Return the hash of the fields dictionary (or just some value). | |
126 if (fields_) { | |
127 return CFHash(fields_); | |
128 } | |
129 return (NSUInteger)[GPBUnknownFieldSet class]; | |
130 } | |
131 | |
132 #pragma mark - Public Methods | |
133 | |
134 - (BOOL)hasField:(int32_t)number { | |
135 ssize_t key = number; | |
136 return fields_ ? (CFDictionaryGetValue(fields_, (void *)key) != nil) : NO; | |
137 } | |
138 | |
139 - (GPBUnknownField *)getField:(int32_t)number { | |
140 ssize_t key = number; | |
141 GPBUnknownField *result = | |
142 fields_ ? CFDictionaryGetValue(fields_, (void *)key) : nil; | |
143 return result; | |
144 } | |
145 | |
146 - (NSUInteger)countOfFields { | |
147 return fields_ ? CFDictionaryGetCount(fields_) : 0; | |
148 } | |
149 | |
150 - (NSArray *)sortedFields { | |
151 if (!fields_) return nil; | |
152 size_t count = CFDictionaryGetCount(fields_); | |
153 ssize_t keys[count]; | |
154 GPBUnknownField *values[count]; | |
155 CFDictionaryGetKeysAndValues(fields_, (const void **)keys, | |
156 (const void **)values); | |
157 struct GPBFieldPair { | |
158 ssize_t key; | |
159 GPBUnknownField *value; | |
160 } pairs[count]; | |
161 for (size_t i = 0; i < count; ++i) { | |
162 pairs[i].key = keys[i]; | |
163 pairs[i].value = values[i]; | |
164 }; | |
165 qsort_b(pairs, count, sizeof(struct GPBFieldPair), | |
166 ^(const void *first, const void *second) { | |
167 const struct GPBFieldPair *a = first; | |
168 const struct GPBFieldPair *b = second; | |
169 return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1); | |
170 }); | |
171 for (size_t i = 0; i < count; ++i) { | |
172 values[i] = pairs[i].value; | |
173 }; | |
174 return [NSArray arrayWithObjects:values count:count]; | |
175 } | |
176 | |
177 #pragma mark - Internal Methods | |
178 | |
179 - (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output { | |
180 if (!fields_) return; | |
181 size_t count = CFDictionaryGetCount(fields_); | |
182 ssize_t keys[count]; | |
183 GPBUnknownField *values[count]; | |
184 CFDictionaryGetKeysAndValues(fields_, (const void **)keys, | |
185 (const void **)values); | |
186 if (count > 1) { | |
187 struct GPBFieldPair { | |
188 ssize_t key; | |
189 GPBUnknownField *value; | |
190 } pairs[count]; | |
191 | |
192 for (size_t i = 0; i < count; ++i) { | |
193 pairs[i].key = keys[i]; | |
194 pairs[i].value = values[i]; | |
195 }; | |
196 qsort_b(pairs, count, sizeof(struct GPBFieldPair), | |
197 ^(const void *first, const void *second) { | |
198 const struct GPBFieldPair *a = first; | |
199 const struct GPBFieldPair *b = second; | |
200 return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1); | |
201 }); | |
202 for (size_t i = 0; i < count; ++i) { | |
203 GPBUnknownField *value = pairs[i].value; | |
204 [value writeToOutput:output]; | |
205 } | |
206 } else { | |
207 [values[0] writeToOutput:output]; | |
208 } | |
209 } | |
210 | |
211 - (NSString *)description { | |
212 NSMutableString *description = [NSMutableString | |
213 stringWithFormat:@"<%@ %p>: TextFormat: {\n", [self class], self]; | |
214 NSString *textFormat = GPBTextFormatForUnknownFieldSet(self, @" "); | |
215 [description appendString:textFormat]; | |
216 [description appendString:@"}"]; | |
217 return description; | |
218 } | |
219 | |
220 static void GPBUnknownFieldSetSerializedSize(const void *key, const void *value, | |
221 void *context) { | |
222 #pragma unused(key) | |
223 GPBUnknownField *field = value; | |
224 size_t *result = context; | |
225 *result += [field serializedSize]; | |
226 } | |
227 | |
228 - (size_t)serializedSize { | |
229 size_t result = 0; | |
230 if (fields_) { | |
231 CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetSerializedSize, | |
232 &result); | |
233 } | |
234 return result; | |
235 } | |
236 | |
237 static void GPBUnknownFieldSetWriteAsMessageSetTo(const void *key, | |
238 const void *value, | |
239 void *context) { | |
240 #pragma unused(key) | |
241 GPBUnknownField *field = value; | |
242 GPBCodedOutputStream *output = context; | |
243 [field writeAsMessageSetExtensionToOutput:output]; | |
244 } | |
245 | |
246 - (void)writeAsMessageSetTo:(GPBCodedOutputStream *)output { | |
247 if (fields_) { | |
248 CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetWriteAsMessageSetTo, | |
249 output); | |
250 } | |
251 } | |
252 | |
253 static void GPBUnknownFieldSetSerializedSizeAsMessageSet(const void *key, | |
254 const void *value, | |
255 void *context) { | |
256 #pragma unused(key) | |
257 GPBUnknownField *field = value; | |
258 size_t *result = context; | |
259 *result += [field serializedSizeAsMessageSetExtension]; | |
260 } | |
261 | |
262 - (size_t)serializedSizeAsMessageSet { | |
263 size_t result = 0; | |
264 if (fields_) { | |
265 CFDictionaryApplyFunction( | |
266 fields_, GPBUnknownFieldSetSerializedSizeAsMessageSet, &result); | |
267 } | |
268 return result; | |
269 } | |
270 | |
271 - (NSData *)data { | |
272 NSMutableData *data = [NSMutableData dataWithLength:self.serializedSize]; | |
273 GPBCodedOutputStream *output = | |
274 [[GPBCodedOutputStream alloc] initWithData:data]; | |
275 [self writeToCodedOutputStream:output]; | |
276 [output release]; | |
277 return data; | |
278 } | |
279 | |
280 + (BOOL)isFieldTag:(int32_t)tag { | |
281 return GPBWireFormatGetTagWireType(tag) != GPBWireFormatEndGroup; | |
282 } | |
283 | |
284 - (void)addField:(GPBUnknownField *)field { | |
285 int32_t number = [field number]; | |
286 checkNumber(number); | |
287 if (!fields_) { | |
288 CFDictionaryKeyCallBacks keyCallBacks = { | |
289 // See description above for reason for using custom dictionary. | |
290 0, GPBUnknownFieldSetKeyRetain, GPBUnknownFieldSetKeyRelease, | |
291 GPBUnknownFieldSetCopyKeyDescription, GPBUnknownFieldSetKeyEqual, | |
292 GPBUnknownFieldSetKeyHash, | |
293 }; | |
294 fields_ = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &keyCallBacks, | |
295 &kCFTypeDictionaryValueCallBacks); | |
296 } | |
297 ssize_t key = number; | |
298 CFDictionarySetValue(fields_, (const void *)key, field); | |
299 } | |
300 | |
301 - (GPBUnknownField *)mutableFieldForNumber:(int32_t)number create:(BOOL)create { | |
302 ssize_t key = number; | |
303 GPBUnknownField *existing = | |
304 fields_ ? CFDictionaryGetValue(fields_, (const void *)key) : nil; | |
305 if (!existing && create) { | |
306 existing = [[GPBUnknownField alloc] initWithNumber:number]; | |
307 // This retains existing. | |
308 [self addField:existing]; | |
309 [existing release]; | |
310 } | |
311 return existing; | |
312 } | |
313 | |
314 static void GPBUnknownFieldSetMergeUnknownFields(const void *key, | |
315 const void *value, | |
316 void *context) { | |
317 #pragma unused(key) | |
318 GPBUnknownField *field = value; | |
319 GPBUnknownFieldSet *self = context; | |
320 | |
321 int32_t number = [field number]; | |
322 checkNumber(number); | |
323 GPBUnknownField *oldField = [self mutableFieldForNumber:number create:NO]; | |
324 if (oldField) { | |
325 [oldField mergeFromField:field]; | |
326 } else { | |
327 // Merge only comes from GPBMessage's mergeFrom:, so it means we are on | |
328 // mutable message and are an mutable instance, so make sure we need | |
329 // mutable fields. | |
330 GPBUnknownField *fieldCopy = [field copy]; | |
331 [self addField:fieldCopy]; | |
332 [fieldCopy release]; | |
333 } | |
334 } | |
335 | |
336 - (void)mergeUnknownFields:(GPBUnknownFieldSet *)other { | |
337 if (other && other->fields_) { | |
338 CFDictionaryApplyFunction(other->fields_, | |
339 GPBUnknownFieldSetMergeUnknownFields, self); | |
340 } | |
341 } | |
342 | |
343 - (void)mergeFromData:(NSData *)data { | |
344 GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data]; | |
345 [self mergeFromCodedInputStream:input]; | |
346 [input checkLastTagWas:0]; | |
347 [input release]; | |
348 } | |
349 | |
350 - (void)mergeVarintField:(int32_t)number value:(int32_t)value { | |
351 checkNumber(number); | |
352 [[self mutableFieldForNumber:number create:YES] addVarint:value]; | |
353 } | |
354 | |
355 - (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input { | |
356 int32_t number = GPBWireFormatGetTagFieldNumber(tag); | |
357 GPBCodedInputStreamState *state = &input->state_; | |
358 switch (GPBWireFormatGetTagWireType(tag)) { | |
359 case GPBWireFormatVarint: { | |
360 GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | |
361 [field addVarint:GPBCodedInputStreamReadInt64(state)]; | |
362 return YES; | |
363 } | |
364 case GPBWireFormatFixed64: { | |
365 GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | |
366 [field addFixed64:GPBCodedInputStreamReadFixed64(state)]; | |
367 return YES; | |
368 } | |
369 case GPBWireFormatLengthDelimited: { | |
370 NSData *data = GPBCodedInputStreamReadRetainedBytes(state); | |
371 GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | |
372 [field addLengthDelimited:data]; | |
373 [data release]; | |
374 return YES; | |
375 } | |
376 case GPBWireFormatStartGroup: { | |
377 GPBUnknownFieldSet *unknownFieldSet = [[GPBUnknownFieldSet alloc] init]; | |
378 [input readUnknownGroup:number message:unknownFieldSet]; | |
379 GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | |
380 [field addGroup:unknownFieldSet]; | |
381 [unknownFieldSet release]; | |
382 return YES; | |
383 } | |
384 case GPBWireFormatEndGroup: | |
385 return NO; | |
386 case GPBWireFormatFixed32: { | |
387 GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | |
388 [field addFixed32:GPBCodedInputStreamReadFixed32(state)]; | |
389 return YES; | |
390 } | |
391 } | |
392 } | |
393 | |
394 - (void)mergeMessageSetMessage:(int32_t)number data:(NSData *)messageData { | |
395 [[self mutableFieldForNumber:number create:YES] | |
396 addLengthDelimited:messageData]; | |
397 } | |
398 | |
399 - (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data { | |
400 GPBUnknownField *field = [self mutableFieldForNumber:fieldNum create:YES]; | |
401 [field addLengthDelimited:data]; | |
402 } | |
403 | |
404 - (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input { | |
405 while (YES) { | |
406 int32_t tag = GPBCodedInputStreamReadTag(&input->state_); | |
407 if (tag == 0 || ![self mergeFieldFrom:tag input:input]) { | |
408 break; | |
409 } | |
410 } | |
411 } | |
412 | |
413 - (void)getTags:(int32_t *)tags { | |
414 if (!fields_) return; | |
415 size_t count = CFDictionaryGetCount(fields_); | |
416 ssize_t keys[count]; | |
417 CFDictionaryGetKeysAndValues(fields_, (const void **)keys, NULL); | |
418 for (size_t i = 0; i < count; ++i) { | |
419 tags[i] = (int32_t)keys[i]; | |
420 } | |
421 } | |
422 | |
423 @end | |
OLD | NEW |