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
46static const void *GPBUnknownFieldSetKeyRetain(CFAllocatorRef allocator,
47                                               const void *value) {
48#pragma unused(allocator)
49  return value;
50}
51
52static void GPBUnknownFieldSetKeyRelease(CFAllocatorRef allocator,
53                                         const void *value) {
54#pragma unused(allocator)
55#pragma unused(value)
56}
57
58static CFStringRef GPBUnknownFieldSetCopyKeyDescription(const void *value) {
59  return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"),
60                                  (int)value);
61}
62
63static Boolean GPBUnknownFieldSetKeyEqual(const void *value1,
64                                          const void *value2) {
65  return value1 == value2;
66}
67
68static CFHashCode GPBUnknownFieldSetKeyHash(const void *value) {
69  return (CFHashCode)value;
70}
71
72#pragma mark Helpers
73
74static 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
86static 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
220static 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
237static 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
253static 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
314static 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
424