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