xref: /aosp_15_r20/external/protobuf/objectivec/GPBUnknownFieldSet.m (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker// Protocol Buffers - Google's data interchange format
2*1b3f573fSAndroid Build Coastguard Worker// Copyright 2008 Google Inc.  All rights reserved.
3*1b3f573fSAndroid Build Coastguard Worker// https://developers.google.com/protocol-buffers/
4*1b3f573fSAndroid Build Coastguard Worker//
5*1b3f573fSAndroid Build Coastguard Worker// Redistribution and use in source and binary forms, with or without
6*1b3f573fSAndroid Build Coastguard Worker// modification, are permitted provided that the following conditions are
7*1b3f573fSAndroid Build Coastguard Worker// met:
8*1b3f573fSAndroid Build Coastguard Worker//
9*1b3f573fSAndroid Build Coastguard Worker//     * Redistributions of source code must retain the above copyright
10*1b3f573fSAndroid Build Coastguard Worker// notice, this list of conditions and the following disclaimer.
11*1b3f573fSAndroid Build Coastguard Worker//     * Redistributions in binary form must reproduce the above
12*1b3f573fSAndroid Build Coastguard Worker// copyright notice, this list of conditions and the following disclaimer
13*1b3f573fSAndroid Build Coastguard Worker// in the documentation and/or other materials provided with the
14*1b3f573fSAndroid Build Coastguard Worker// distribution.
15*1b3f573fSAndroid Build Coastguard Worker//     * Neither the name of Google Inc. nor the names of its
16*1b3f573fSAndroid Build Coastguard Worker// contributors may be used to endorse or promote products derived from
17*1b3f573fSAndroid Build Coastguard Worker// this software without specific prior written permission.
18*1b3f573fSAndroid Build Coastguard Worker//
19*1b3f573fSAndroid Build Coastguard Worker// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*1b3f573fSAndroid Build Coastguard Worker// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*1b3f573fSAndroid Build Coastguard Worker// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*1b3f573fSAndroid Build Coastguard Worker// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*1b3f573fSAndroid Build Coastguard Worker// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*1b3f573fSAndroid Build Coastguard Worker// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*1b3f573fSAndroid Build Coastguard Worker// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*1b3f573fSAndroid Build Coastguard Worker// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*1b3f573fSAndroid Build Coastguard Worker// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*1b3f573fSAndroid Build Coastguard Worker// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*1b3f573fSAndroid Build Coastguard Worker// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*1b3f573fSAndroid Build Coastguard Worker
31*1b3f573fSAndroid Build Coastguard Worker#import "GPBUnknownFieldSet_PackagePrivate.h"
32*1b3f573fSAndroid Build Coastguard Worker
33*1b3f573fSAndroid Build Coastguard Worker#import "GPBCodedInputStream_PackagePrivate.h"
34*1b3f573fSAndroid Build Coastguard Worker#import "GPBCodedOutputStream.h"
35*1b3f573fSAndroid Build Coastguard Worker#import "GPBUnknownField_PackagePrivate.h"
36*1b3f573fSAndroid Build Coastguard Worker#import "GPBUtilities.h"
37*1b3f573fSAndroid Build Coastguard Worker#import "GPBWireFormat.h"
38*1b3f573fSAndroid Build Coastguard Worker
39*1b3f573fSAndroid Build Coastguard Worker#pragma mark Helpers
40*1b3f573fSAndroid Build Coastguard Worker
41*1b3f573fSAndroid Build Coastguard Workerstatic void checkNumber(int32_t number) {
42*1b3f573fSAndroid Build Coastguard Worker  if (number == 0) {
43*1b3f573fSAndroid Build Coastguard Worker    [NSException raise:NSInvalidArgumentException
44*1b3f573fSAndroid Build Coastguard Worker                format:@"Zero is not a valid field number."];
45*1b3f573fSAndroid Build Coastguard Worker  }
46*1b3f573fSAndroid Build Coastguard Worker}
47*1b3f573fSAndroid Build Coastguard Worker
48*1b3f573fSAndroid Build Coastguard Worker@implementation GPBUnknownFieldSet {
49*1b3f573fSAndroid Build Coastguard Worker @package
50*1b3f573fSAndroid Build Coastguard Worker  CFMutableDictionaryRef fields_;
51*1b3f573fSAndroid Build Coastguard Worker}
52*1b3f573fSAndroid Build Coastguard Worker
53*1b3f573fSAndroid Build Coastguard Workerstatic void CopyWorker(const void *key, const void *value, void *context) {
54*1b3f573fSAndroid Build Coastguard Worker#pragma unused(key)
55*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *field = value;
56*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownFieldSet *result = context;
57*1b3f573fSAndroid Build Coastguard Worker
58*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *copied = [field copy];
59*1b3f573fSAndroid Build Coastguard Worker  [result addField:copied];
60*1b3f573fSAndroid Build Coastguard Worker  [copied release];
61*1b3f573fSAndroid Build Coastguard Worker}
62*1b3f573fSAndroid Build Coastguard Worker
63*1b3f573fSAndroid Build Coastguard Worker// Direct access is use for speed, to avoid even internally declaring things
64*1b3f573fSAndroid Build Coastguard Worker// read/write, etc. The warning is enabled in the project to ensure code calling
65*1b3f573fSAndroid Build Coastguard Worker// protos can turn on -Wdirect-ivar-access without issues.
66*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic push
67*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Wdirect-ivar-access"
68*1b3f573fSAndroid Build Coastguard Worker
69*1b3f573fSAndroid Build Coastguard Worker- (id)copyWithZone:(NSZone *)zone {
70*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownFieldSet *result = [[GPBUnknownFieldSet allocWithZone:zone] init];
71*1b3f573fSAndroid Build Coastguard Worker  if (fields_) {
72*1b3f573fSAndroid Build Coastguard Worker    CFDictionaryApplyFunction(fields_, CopyWorker, result);
73*1b3f573fSAndroid Build Coastguard Worker  }
74*1b3f573fSAndroid Build Coastguard Worker  return result;
75*1b3f573fSAndroid Build Coastguard Worker}
76*1b3f573fSAndroid Build Coastguard Worker
77*1b3f573fSAndroid Build Coastguard Worker- (void)dealloc {
78*1b3f573fSAndroid Build Coastguard Worker  if (fields_) {
79*1b3f573fSAndroid Build Coastguard Worker    CFRelease(fields_);
80*1b3f573fSAndroid Build Coastguard Worker  }
81*1b3f573fSAndroid Build Coastguard Worker  [super dealloc];
82*1b3f573fSAndroid Build Coastguard Worker}
83*1b3f573fSAndroid Build Coastguard Worker
84*1b3f573fSAndroid Build Coastguard Worker- (BOOL)isEqual:(id)object {
85*1b3f573fSAndroid Build Coastguard Worker  BOOL equal = NO;
86*1b3f573fSAndroid Build Coastguard Worker  if ([object isKindOfClass:[GPBUnknownFieldSet class]]) {
87*1b3f573fSAndroid Build Coastguard Worker    GPBUnknownFieldSet *set = (GPBUnknownFieldSet *)object;
88*1b3f573fSAndroid Build Coastguard Worker    if ((fields_ == NULL) && (set->fields_ == NULL)) {
89*1b3f573fSAndroid Build Coastguard Worker      equal = YES;
90*1b3f573fSAndroid Build Coastguard Worker    } else if ((fields_ != NULL) && (set->fields_ != NULL)) {
91*1b3f573fSAndroid Build Coastguard Worker      equal = CFEqual(fields_, set->fields_);
92*1b3f573fSAndroid Build Coastguard Worker    }
93*1b3f573fSAndroid Build Coastguard Worker  }
94*1b3f573fSAndroid Build Coastguard Worker  return equal;
95*1b3f573fSAndroid Build Coastguard Worker}
96*1b3f573fSAndroid Build Coastguard Worker
97*1b3f573fSAndroid Build Coastguard Worker- (NSUInteger)hash {
98*1b3f573fSAndroid Build Coastguard Worker  // Return the hash of the fields dictionary (or just some value).
99*1b3f573fSAndroid Build Coastguard Worker  if (fields_) {
100*1b3f573fSAndroid Build Coastguard Worker    return CFHash(fields_);
101*1b3f573fSAndroid Build Coastguard Worker  }
102*1b3f573fSAndroid Build Coastguard Worker  return (NSUInteger)[GPBUnknownFieldSet class];
103*1b3f573fSAndroid Build Coastguard Worker}
104*1b3f573fSAndroid Build Coastguard Worker
105*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Public Methods
106*1b3f573fSAndroid Build Coastguard Worker
107*1b3f573fSAndroid Build Coastguard Worker- (BOOL)hasField:(int32_t)number {
108*1b3f573fSAndroid Build Coastguard Worker  ssize_t key = number;
109*1b3f573fSAndroid Build Coastguard Worker  return fields_ ? (CFDictionaryGetValue(fields_, (void *)key) != nil) : NO;
110*1b3f573fSAndroid Build Coastguard Worker}
111*1b3f573fSAndroid Build Coastguard Worker
112*1b3f573fSAndroid Build Coastguard Worker- (GPBUnknownField *)getField:(int32_t)number {
113*1b3f573fSAndroid Build Coastguard Worker  ssize_t key = number;
114*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *result =
115*1b3f573fSAndroid Build Coastguard Worker      fields_ ? CFDictionaryGetValue(fields_, (void *)key) : nil;
116*1b3f573fSAndroid Build Coastguard Worker  return result;
117*1b3f573fSAndroid Build Coastguard Worker}
118*1b3f573fSAndroid Build Coastguard Worker
119*1b3f573fSAndroid Build Coastguard Worker- (NSUInteger)countOfFields {
120*1b3f573fSAndroid Build Coastguard Worker  return fields_ ? CFDictionaryGetCount(fields_) : 0;
121*1b3f573fSAndroid Build Coastguard Worker}
122*1b3f573fSAndroid Build Coastguard Worker
123*1b3f573fSAndroid Build Coastguard Worker- (NSArray *)sortedFields {
124*1b3f573fSAndroid Build Coastguard Worker  if (!fields_) return [NSArray array];
125*1b3f573fSAndroid Build Coastguard Worker  size_t count = CFDictionaryGetCount(fields_);
126*1b3f573fSAndroid Build Coastguard Worker  ssize_t keys[count];
127*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *values[count];
128*1b3f573fSAndroid Build Coastguard Worker  CFDictionaryGetKeysAndValues(fields_, (const void **)keys,
129*1b3f573fSAndroid Build Coastguard Worker                               (const void **)values);
130*1b3f573fSAndroid Build Coastguard Worker  struct GPBFieldPair {
131*1b3f573fSAndroid Build Coastguard Worker    ssize_t key;
132*1b3f573fSAndroid Build Coastguard Worker    GPBUnknownField *value;
133*1b3f573fSAndroid Build Coastguard Worker  } pairs[count];
134*1b3f573fSAndroid Build Coastguard Worker  for (size_t i = 0; i < count; ++i) {
135*1b3f573fSAndroid Build Coastguard Worker    pairs[i].key = keys[i];
136*1b3f573fSAndroid Build Coastguard Worker    pairs[i].value = values[i];
137*1b3f573fSAndroid Build Coastguard Worker  };
138*1b3f573fSAndroid Build Coastguard Worker  qsort_b(pairs, count, sizeof(struct GPBFieldPair),
139*1b3f573fSAndroid Build Coastguard Worker          ^(const void *first, const void *second) {
140*1b3f573fSAndroid Build Coastguard Worker            const struct GPBFieldPair *a = first;
141*1b3f573fSAndroid Build Coastguard Worker            const struct GPBFieldPair *b = second;
142*1b3f573fSAndroid Build Coastguard Worker            return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1);
143*1b3f573fSAndroid Build Coastguard Worker          });
144*1b3f573fSAndroid Build Coastguard Worker  for (size_t i = 0; i < count; ++i) {
145*1b3f573fSAndroid Build Coastguard Worker    values[i] = pairs[i].value;
146*1b3f573fSAndroid Build Coastguard Worker  };
147*1b3f573fSAndroid Build Coastguard Worker  return [NSArray arrayWithObjects:values count:count];
148*1b3f573fSAndroid Build Coastguard Worker}
149*1b3f573fSAndroid Build Coastguard Worker
150*1b3f573fSAndroid Build Coastguard Worker#pragma mark - Internal Methods
151*1b3f573fSAndroid Build Coastguard Worker
152*1b3f573fSAndroid Build Coastguard Worker- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output {
153*1b3f573fSAndroid Build Coastguard Worker  if (!fields_) return;
154*1b3f573fSAndroid Build Coastguard Worker  size_t count = CFDictionaryGetCount(fields_);
155*1b3f573fSAndroid Build Coastguard Worker  ssize_t keys[count];
156*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *values[count];
157*1b3f573fSAndroid Build Coastguard Worker  CFDictionaryGetKeysAndValues(fields_, (const void **)keys,
158*1b3f573fSAndroid Build Coastguard Worker                               (const void **)values);
159*1b3f573fSAndroid Build Coastguard Worker  if (count > 1) {
160*1b3f573fSAndroid Build Coastguard Worker    struct GPBFieldPair {
161*1b3f573fSAndroid Build Coastguard Worker      ssize_t key;
162*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownField *value;
163*1b3f573fSAndroid Build Coastguard Worker    } pairs[count];
164*1b3f573fSAndroid Build Coastguard Worker
165*1b3f573fSAndroid Build Coastguard Worker    for (size_t i = 0; i < count; ++i) {
166*1b3f573fSAndroid Build Coastguard Worker      pairs[i].key = keys[i];
167*1b3f573fSAndroid Build Coastguard Worker      pairs[i].value = values[i];
168*1b3f573fSAndroid Build Coastguard Worker    };
169*1b3f573fSAndroid Build Coastguard Worker    qsort_b(pairs, count, sizeof(struct GPBFieldPair),
170*1b3f573fSAndroid Build Coastguard Worker            ^(const void *first, const void *second) {
171*1b3f573fSAndroid Build Coastguard Worker              const struct GPBFieldPair *a = first;
172*1b3f573fSAndroid Build Coastguard Worker              const struct GPBFieldPair *b = second;
173*1b3f573fSAndroid Build Coastguard Worker              return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1);
174*1b3f573fSAndroid Build Coastguard Worker            });
175*1b3f573fSAndroid Build Coastguard Worker    for (size_t i = 0; i < count; ++i) {
176*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownField *value = pairs[i].value;
177*1b3f573fSAndroid Build Coastguard Worker      [value writeToOutput:output];
178*1b3f573fSAndroid Build Coastguard Worker    }
179*1b3f573fSAndroid Build Coastguard Worker  } else {
180*1b3f573fSAndroid Build Coastguard Worker    [values[0] writeToOutput:output];
181*1b3f573fSAndroid Build Coastguard Worker  }
182*1b3f573fSAndroid Build Coastguard Worker}
183*1b3f573fSAndroid Build Coastguard Worker
184*1b3f573fSAndroid Build Coastguard Worker- (NSString *)description {
185*1b3f573fSAndroid Build Coastguard Worker  NSMutableString *description = [NSMutableString
186*1b3f573fSAndroid Build Coastguard Worker      stringWithFormat:@"<%@ %p>: TextFormat: {\n", [self class], self];
187*1b3f573fSAndroid Build Coastguard Worker  NSString *textFormat = GPBTextFormatForUnknownFieldSet(self, @"  ");
188*1b3f573fSAndroid Build Coastguard Worker  [description appendString:textFormat];
189*1b3f573fSAndroid Build Coastguard Worker  [description appendString:@"}"];
190*1b3f573fSAndroid Build Coastguard Worker  return description;
191*1b3f573fSAndroid Build Coastguard Worker}
192*1b3f573fSAndroid Build Coastguard Worker
193*1b3f573fSAndroid Build Coastguard Workerstatic void GPBUnknownFieldSetSerializedSize(const void *key, const void *value,
194*1b3f573fSAndroid Build Coastguard Worker                                             void *context) {
195*1b3f573fSAndroid Build Coastguard Worker#pragma unused(key)
196*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *field = value;
197*1b3f573fSAndroid Build Coastguard Worker  size_t *result = context;
198*1b3f573fSAndroid Build Coastguard Worker  *result += [field serializedSize];
199*1b3f573fSAndroid Build Coastguard Worker}
200*1b3f573fSAndroid Build Coastguard Worker
201*1b3f573fSAndroid Build Coastguard Worker- (size_t)serializedSize {
202*1b3f573fSAndroid Build Coastguard Worker  size_t result = 0;
203*1b3f573fSAndroid Build Coastguard Worker  if (fields_) {
204*1b3f573fSAndroid Build Coastguard Worker    CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetSerializedSize,
205*1b3f573fSAndroid Build Coastguard Worker                              &result);
206*1b3f573fSAndroid Build Coastguard Worker  }
207*1b3f573fSAndroid Build Coastguard Worker  return result;
208*1b3f573fSAndroid Build Coastguard Worker}
209*1b3f573fSAndroid Build Coastguard Worker
210*1b3f573fSAndroid Build Coastguard Workerstatic void GPBUnknownFieldSetWriteAsMessageSetTo(const void *key,
211*1b3f573fSAndroid Build Coastguard Worker                                                  const void *value,
212*1b3f573fSAndroid Build Coastguard Worker                                                  void *context) {
213*1b3f573fSAndroid Build Coastguard Worker#pragma unused(key)
214*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *field = value;
215*1b3f573fSAndroid Build Coastguard Worker  GPBCodedOutputStream *output = context;
216*1b3f573fSAndroid Build Coastguard Worker  [field writeAsMessageSetExtensionToOutput:output];
217*1b3f573fSAndroid Build Coastguard Worker}
218*1b3f573fSAndroid Build Coastguard Worker
219*1b3f573fSAndroid Build Coastguard Worker- (void)writeAsMessageSetTo:(GPBCodedOutputStream *)output {
220*1b3f573fSAndroid Build Coastguard Worker  if (fields_) {
221*1b3f573fSAndroid Build Coastguard Worker    CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetWriteAsMessageSetTo,
222*1b3f573fSAndroid Build Coastguard Worker                              output);
223*1b3f573fSAndroid Build Coastguard Worker  }
224*1b3f573fSAndroid Build Coastguard Worker}
225*1b3f573fSAndroid Build Coastguard Worker
226*1b3f573fSAndroid Build Coastguard Workerstatic void GPBUnknownFieldSetSerializedSizeAsMessageSet(const void *key,
227*1b3f573fSAndroid Build Coastguard Worker                                                         const void *value,
228*1b3f573fSAndroid Build Coastguard Worker                                                         void *context) {
229*1b3f573fSAndroid Build Coastguard Worker#pragma unused(key)
230*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *field = value;
231*1b3f573fSAndroid Build Coastguard Worker  size_t *result = context;
232*1b3f573fSAndroid Build Coastguard Worker  *result += [field serializedSizeAsMessageSetExtension];
233*1b3f573fSAndroid Build Coastguard Worker}
234*1b3f573fSAndroid Build Coastguard Worker
235*1b3f573fSAndroid Build Coastguard Worker- (size_t)serializedSizeAsMessageSet {
236*1b3f573fSAndroid Build Coastguard Worker  size_t result = 0;
237*1b3f573fSAndroid Build Coastguard Worker  if (fields_) {
238*1b3f573fSAndroid Build Coastguard Worker    CFDictionaryApplyFunction(
239*1b3f573fSAndroid Build Coastguard Worker        fields_, GPBUnknownFieldSetSerializedSizeAsMessageSet, &result);
240*1b3f573fSAndroid Build Coastguard Worker  }
241*1b3f573fSAndroid Build Coastguard Worker  return result;
242*1b3f573fSAndroid Build Coastguard Worker}
243*1b3f573fSAndroid Build Coastguard Worker
244*1b3f573fSAndroid Build Coastguard Worker- (NSData *)data {
245*1b3f573fSAndroid Build Coastguard Worker  NSMutableData *data = [NSMutableData dataWithLength:self.serializedSize];
246*1b3f573fSAndroid Build Coastguard Worker  GPBCodedOutputStream *output =
247*1b3f573fSAndroid Build Coastguard Worker      [[GPBCodedOutputStream alloc] initWithData:data];
248*1b3f573fSAndroid Build Coastguard Worker  [self writeToCodedOutputStream:output];
249*1b3f573fSAndroid Build Coastguard Worker  [output release];
250*1b3f573fSAndroid Build Coastguard Worker  return data;
251*1b3f573fSAndroid Build Coastguard Worker}
252*1b3f573fSAndroid Build Coastguard Worker
253*1b3f573fSAndroid Build Coastguard Worker+ (BOOL)isFieldTag:(int32_t)tag {
254*1b3f573fSAndroid Build Coastguard Worker  return GPBWireFormatGetTagWireType(tag) != GPBWireFormatEndGroup;
255*1b3f573fSAndroid Build Coastguard Worker}
256*1b3f573fSAndroid Build Coastguard Worker
257*1b3f573fSAndroid Build Coastguard Worker- (void)addField:(GPBUnknownField *)field {
258*1b3f573fSAndroid Build Coastguard Worker  int32_t number = [field number];
259*1b3f573fSAndroid Build Coastguard Worker  checkNumber(number);
260*1b3f573fSAndroid Build Coastguard Worker  if (!fields_) {
261*1b3f573fSAndroid Build Coastguard Worker    // Use a custom dictionary here because the keys are numbers and conversion
262*1b3f573fSAndroid Build Coastguard Worker    // back and forth from NSNumber isn't worth the cost.
263*1b3f573fSAndroid Build Coastguard Worker    fields_ = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL,
264*1b3f573fSAndroid Build Coastguard Worker                                        &kCFTypeDictionaryValueCallBacks);
265*1b3f573fSAndroid Build Coastguard Worker  }
266*1b3f573fSAndroid Build Coastguard Worker  ssize_t key = number;
267*1b3f573fSAndroid Build Coastguard Worker  CFDictionarySetValue(fields_, (const void *)key, field);
268*1b3f573fSAndroid Build Coastguard Worker}
269*1b3f573fSAndroid Build Coastguard Worker
270*1b3f573fSAndroid Build Coastguard Worker- (GPBUnknownField *)mutableFieldForNumber:(int32_t)number create:(BOOL)create {
271*1b3f573fSAndroid Build Coastguard Worker  ssize_t key = number;
272*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *existing =
273*1b3f573fSAndroid Build Coastguard Worker      fields_ ? CFDictionaryGetValue(fields_, (const void *)key) : nil;
274*1b3f573fSAndroid Build Coastguard Worker  if (!existing && create) {
275*1b3f573fSAndroid Build Coastguard Worker    existing = [[GPBUnknownField alloc] initWithNumber:number];
276*1b3f573fSAndroid Build Coastguard Worker    // This retains existing.
277*1b3f573fSAndroid Build Coastguard Worker    [self addField:existing];
278*1b3f573fSAndroid Build Coastguard Worker    [existing release];
279*1b3f573fSAndroid Build Coastguard Worker  }
280*1b3f573fSAndroid Build Coastguard Worker  return existing;
281*1b3f573fSAndroid Build Coastguard Worker}
282*1b3f573fSAndroid Build Coastguard Worker
283*1b3f573fSAndroid Build Coastguard Workerstatic void GPBUnknownFieldSetMergeUnknownFields(const void *key,
284*1b3f573fSAndroid Build Coastguard Worker                                                 const void *value,
285*1b3f573fSAndroid Build Coastguard Worker                                                 void *context) {
286*1b3f573fSAndroid Build Coastguard Worker#pragma unused(key)
287*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *field = value;
288*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownFieldSet *self = context;
289*1b3f573fSAndroid Build Coastguard Worker
290*1b3f573fSAndroid Build Coastguard Worker  int32_t number = [field number];
291*1b3f573fSAndroid Build Coastguard Worker  checkNumber(number);
292*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *oldField = [self mutableFieldForNumber:number create:NO];
293*1b3f573fSAndroid Build Coastguard Worker  if (oldField) {
294*1b3f573fSAndroid Build Coastguard Worker    [oldField mergeFromField:field];
295*1b3f573fSAndroid Build Coastguard Worker  } else {
296*1b3f573fSAndroid Build Coastguard Worker    // Merge only comes from GPBMessage's mergeFrom:, so it means we are on
297*1b3f573fSAndroid Build Coastguard Worker    // mutable message and are an mutable instance, so make sure we need
298*1b3f573fSAndroid Build Coastguard Worker    // mutable fields.
299*1b3f573fSAndroid Build Coastguard Worker    GPBUnknownField *fieldCopy = [field copy];
300*1b3f573fSAndroid Build Coastguard Worker    [self addField:fieldCopy];
301*1b3f573fSAndroid Build Coastguard Worker    [fieldCopy release];
302*1b3f573fSAndroid Build Coastguard Worker  }
303*1b3f573fSAndroid Build Coastguard Worker}
304*1b3f573fSAndroid Build Coastguard Worker
305*1b3f573fSAndroid Build Coastguard Worker- (void)mergeUnknownFields:(GPBUnknownFieldSet *)other {
306*1b3f573fSAndroid Build Coastguard Worker  if (other && other->fields_) {
307*1b3f573fSAndroid Build Coastguard Worker    CFDictionaryApplyFunction(other->fields_,
308*1b3f573fSAndroid Build Coastguard Worker                              GPBUnknownFieldSetMergeUnknownFields, self);
309*1b3f573fSAndroid Build Coastguard Worker  }
310*1b3f573fSAndroid Build Coastguard Worker}
311*1b3f573fSAndroid Build Coastguard Worker
312*1b3f573fSAndroid Build Coastguard Worker- (void)mergeFromData:(NSData *)data {
313*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
314*1b3f573fSAndroid Build Coastguard Worker  [self mergeFromCodedInputStream:input];
315*1b3f573fSAndroid Build Coastguard Worker  [input checkLastTagWas:0];
316*1b3f573fSAndroid Build Coastguard Worker  [input release];
317*1b3f573fSAndroid Build Coastguard Worker}
318*1b3f573fSAndroid Build Coastguard Worker
319*1b3f573fSAndroid Build Coastguard Worker- (void)mergeVarintField:(int32_t)number value:(int32_t)value {
320*1b3f573fSAndroid Build Coastguard Worker  checkNumber(number);
321*1b3f573fSAndroid Build Coastguard Worker  [[self mutableFieldForNumber:number create:YES] addVarint:value];
322*1b3f573fSAndroid Build Coastguard Worker}
323*1b3f573fSAndroid Build Coastguard Worker
324*1b3f573fSAndroid Build Coastguard Worker- (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input {
325*1b3f573fSAndroid Build Coastguard Worker  NSAssert(GPBWireFormatIsValidTag(tag), @"Got passed an invalid tag");
326*1b3f573fSAndroid Build Coastguard Worker  int32_t number = GPBWireFormatGetTagFieldNumber(tag);
327*1b3f573fSAndroid Build Coastguard Worker  GPBCodedInputStreamState *state = &input->state_;
328*1b3f573fSAndroid Build Coastguard Worker  switch (GPBWireFormatGetTagWireType(tag)) {
329*1b3f573fSAndroid Build Coastguard Worker    case GPBWireFormatVarint: {
330*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
331*1b3f573fSAndroid Build Coastguard Worker      [field addVarint:GPBCodedInputStreamReadInt64(state)];
332*1b3f573fSAndroid Build Coastguard Worker      return YES;
333*1b3f573fSAndroid Build Coastguard Worker    }
334*1b3f573fSAndroid Build Coastguard Worker    case GPBWireFormatFixed64: {
335*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
336*1b3f573fSAndroid Build Coastguard Worker      [field addFixed64:GPBCodedInputStreamReadFixed64(state)];
337*1b3f573fSAndroid Build Coastguard Worker      return YES;
338*1b3f573fSAndroid Build Coastguard Worker    }
339*1b3f573fSAndroid Build Coastguard Worker    case GPBWireFormatLengthDelimited: {
340*1b3f573fSAndroid Build Coastguard Worker      NSData *data = GPBCodedInputStreamReadRetainedBytes(state);
341*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
342*1b3f573fSAndroid Build Coastguard Worker      [field addLengthDelimited:data];
343*1b3f573fSAndroid Build Coastguard Worker      [data release];
344*1b3f573fSAndroid Build Coastguard Worker      return YES;
345*1b3f573fSAndroid Build Coastguard Worker    }
346*1b3f573fSAndroid Build Coastguard Worker    case GPBWireFormatStartGroup: {
347*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownFieldSet *unknownFieldSet = [[GPBUnknownFieldSet alloc] init];
348*1b3f573fSAndroid Build Coastguard Worker      [input readUnknownGroup:number message:unknownFieldSet];
349*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
350*1b3f573fSAndroid Build Coastguard Worker      [field addGroup:unknownFieldSet];
351*1b3f573fSAndroid Build Coastguard Worker      [unknownFieldSet release];
352*1b3f573fSAndroid Build Coastguard Worker      return YES;
353*1b3f573fSAndroid Build Coastguard Worker    }
354*1b3f573fSAndroid Build Coastguard Worker    case GPBWireFormatEndGroup:
355*1b3f573fSAndroid Build Coastguard Worker      return NO;
356*1b3f573fSAndroid Build Coastguard Worker    case GPBWireFormatFixed32: {
357*1b3f573fSAndroid Build Coastguard Worker      GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
358*1b3f573fSAndroid Build Coastguard Worker      [field addFixed32:GPBCodedInputStreamReadFixed32(state)];
359*1b3f573fSAndroid Build Coastguard Worker      return YES;
360*1b3f573fSAndroid Build Coastguard Worker    }
361*1b3f573fSAndroid Build Coastguard Worker  }
362*1b3f573fSAndroid Build Coastguard Worker}
363*1b3f573fSAndroid Build Coastguard Worker
364*1b3f573fSAndroid Build Coastguard Worker- (void)mergeMessageSetMessage:(int32_t)number data:(NSData *)messageData {
365*1b3f573fSAndroid Build Coastguard Worker  [[self mutableFieldForNumber:number create:YES]
366*1b3f573fSAndroid Build Coastguard Worker      addLengthDelimited:messageData];
367*1b3f573fSAndroid Build Coastguard Worker}
368*1b3f573fSAndroid Build Coastguard Worker
369*1b3f573fSAndroid Build Coastguard Worker- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data {
370*1b3f573fSAndroid Build Coastguard Worker  GPBUnknownField *field = [self mutableFieldForNumber:fieldNum create:YES];
371*1b3f573fSAndroid Build Coastguard Worker  [field addLengthDelimited:data];
372*1b3f573fSAndroid Build Coastguard Worker}
373*1b3f573fSAndroid Build Coastguard Worker
374*1b3f573fSAndroid Build Coastguard Worker- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input {
375*1b3f573fSAndroid Build Coastguard Worker  while (YES) {
376*1b3f573fSAndroid Build Coastguard Worker    int32_t tag = GPBCodedInputStreamReadTag(&input->state_);
377*1b3f573fSAndroid Build Coastguard Worker    if (tag == 0 || ![self mergeFieldFrom:tag input:input]) {
378*1b3f573fSAndroid Build Coastguard Worker      break;
379*1b3f573fSAndroid Build Coastguard Worker    }
380*1b3f573fSAndroid Build Coastguard Worker  }
381*1b3f573fSAndroid Build Coastguard Worker}
382*1b3f573fSAndroid Build Coastguard Worker
383*1b3f573fSAndroid Build Coastguard Worker- (void)getTags:(int32_t *)tags {
384*1b3f573fSAndroid Build Coastguard Worker  if (!fields_) return;
385*1b3f573fSAndroid Build Coastguard Worker  size_t count = CFDictionaryGetCount(fields_);
386*1b3f573fSAndroid Build Coastguard Worker  ssize_t keys[count];
387*1b3f573fSAndroid Build Coastguard Worker  CFDictionaryGetKeysAndValues(fields_, (const void **)keys, NULL);
388*1b3f573fSAndroid Build Coastguard Worker  for (size_t i = 0; i < count; ++i) {
389*1b3f573fSAndroid Build Coastguard Worker    tags[i] = (int32_t)keys[i];
390*1b3f573fSAndroid Build Coastguard Worker  }
391*1b3f573fSAndroid Build Coastguard Worker}
392*1b3f573fSAndroid Build Coastguard Worker
393*1b3f573fSAndroid Build Coastguard Worker#pragma clang diagnostic pop
394*1b3f573fSAndroid Build Coastguard Worker
395*1b3f573fSAndroid Build Coastguard Worker@end
396