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