| // Protocol Buffers - Google's data interchange format | 
 | // Copyright 2008 Google Inc.  All rights reserved. | 
 | // https://developers.google.com/protocol-buffers/ | 
 | // | 
 | // Redistribution and use in source and binary forms, with or without | 
 | // modification, are permitted provided that the following conditions are | 
 | // met: | 
 | // | 
 | //     * Redistributions of source code must retain the above copyright | 
 | // notice, this list of conditions and the following disclaimer. | 
 | //     * Redistributions in binary form must reproduce the above | 
 | // copyright notice, this list of conditions and the following disclaimer | 
 | // in the documentation and/or other materials provided with the | 
 | // distribution. | 
 | //     * Neither the name of Google Inc. nor the names of its | 
 | // contributors may be used to endorse or promote products derived from | 
 | // this software without specific prior written permission. | 
 | // | 
 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | #import "GPBUnknownFieldSet_PackagePrivate.h" | 
 |  | 
 | #import "GPBCodedInputStream_PackagePrivate.h" | 
 | #import "GPBCodedOutputStream.h" | 
 | #import "GPBUnknownField_PackagePrivate.h" | 
 | #import "GPBUtilities.h" | 
 | #import "GPBWireFormat.h" | 
 |  | 
 | #pragma mark Helpers | 
 |  | 
 | static void checkNumber(int32_t number) { | 
 |   if (number == 0) { | 
 |     [NSException raise:NSInvalidArgumentException | 
 |                 format:@"Zero is not a valid field number."]; | 
 |   } | 
 | } | 
 |  | 
 | @implementation GPBUnknownFieldSet { | 
 |  @package | 
 |   CFMutableDictionaryRef fields_; | 
 | } | 
 |  | 
 | static void CopyWorker(const void *key, const void *value, void *context) { | 
 | #pragma unused(key) | 
 |   GPBUnknownField *field = value; | 
 |   GPBUnknownFieldSet *result = context; | 
 |  | 
 |   GPBUnknownField *copied = [field copy]; | 
 |   [result addField:copied]; | 
 |   [copied release]; | 
 | } | 
 |  | 
 | // Direct access is use for speed, to avoid even internally declaring things | 
 | // read/write, etc. The warning is enabled in the project to ensure code calling | 
 | // protos can turn on -Wdirect-ivar-access without issues. | 
 | #pragma clang diagnostic push | 
 | #pragma clang diagnostic ignored "-Wdirect-ivar-access" | 
 |  | 
 | - (id)copyWithZone:(NSZone *)zone { | 
 |   GPBUnknownFieldSet *result = [[GPBUnknownFieldSet allocWithZone:zone] init]; | 
 |   if (fields_) { | 
 |     CFDictionaryApplyFunction(fields_, CopyWorker, result); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | - (void)dealloc { | 
 |   if (fields_) { | 
 |     CFRelease(fields_); | 
 |   } | 
 |   [super dealloc]; | 
 | } | 
 |  | 
 | - (BOOL)isEqual:(id)object { | 
 |   BOOL equal = NO; | 
 |   if ([object isKindOfClass:[GPBUnknownFieldSet class]]) { | 
 |     GPBUnknownFieldSet *set = (GPBUnknownFieldSet *)object; | 
 |     if ((fields_ == NULL) && (set->fields_ == NULL)) { | 
 |       equal = YES; | 
 |     } else if ((fields_ != NULL) && (set->fields_ != NULL)) { | 
 |       equal = CFEqual(fields_, set->fields_); | 
 |     } | 
 |   } | 
 |   return equal; | 
 | } | 
 |  | 
 | - (NSUInteger)hash { | 
 |   // Return the hash of the fields dictionary (or just some value). | 
 |   if (fields_) { | 
 |     return CFHash(fields_); | 
 |   } | 
 |   return (NSUInteger)[GPBUnknownFieldSet class]; | 
 | } | 
 |  | 
 | #pragma mark - Public Methods | 
 |  | 
 | - (BOOL)hasField:(int32_t)number { | 
 |   ssize_t key = number; | 
 |   return fields_ ? (CFDictionaryGetValue(fields_, (void *)key) != nil) : NO; | 
 | } | 
 |  | 
 | - (GPBUnknownField *)getField:(int32_t)number { | 
 |   ssize_t key = number; | 
 |   GPBUnknownField *result = | 
 |       fields_ ? CFDictionaryGetValue(fields_, (void *)key) : nil; | 
 |   return result; | 
 | } | 
 |  | 
 | - (NSUInteger)countOfFields { | 
 |   return fields_ ? CFDictionaryGetCount(fields_) : 0; | 
 | } | 
 |  | 
 | - (NSArray *)sortedFields { | 
 |   if (!fields_) return [NSArray array]; | 
 |   size_t count = CFDictionaryGetCount(fields_); | 
 |   ssize_t keys[count]; | 
 |   GPBUnknownField *values[count]; | 
 |   CFDictionaryGetKeysAndValues(fields_, (const void **)keys, | 
 |                                (const void **)values); | 
 |   struct GPBFieldPair { | 
 |     ssize_t key; | 
 |     GPBUnknownField *value; | 
 |   } pairs[count]; | 
 |   for (size_t i = 0; i < count; ++i) { | 
 |     pairs[i].key = keys[i]; | 
 |     pairs[i].value = values[i]; | 
 |   }; | 
 |   qsort_b(pairs, count, sizeof(struct GPBFieldPair), | 
 |           ^(const void *first, const void *second) { | 
 |             const struct GPBFieldPair *a = first; | 
 |             const struct GPBFieldPair *b = second; | 
 |             return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1); | 
 |           }); | 
 |   for (size_t i = 0; i < count; ++i) { | 
 |     values[i] = pairs[i].value; | 
 |   }; | 
 |   return [NSArray arrayWithObjects:values count:count]; | 
 | } | 
 |  | 
 | #pragma mark - Internal Methods | 
 |  | 
 | - (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output { | 
 |   if (!fields_) return; | 
 |   size_t count = CFDictionaryGetCount(fields_); | 
 |   ssize_t keys[count]; | 
 |   GPBUnknownField *values[count]; | 
 |   CFDictionaryGetKeysAndValues(fields_, (const void **)keys, | 
 |                                (const void **)values); | 
 |   if (count > 1) { | 
 |     struct GPBFieldPair { | 
 |       ssize_t key; | 
 |       GPBUnknownField *value; | 
 |     } pairs[count]; | 
 |  | 
 |     for (size_t i = 0; i < count; ++i) { | 
 |       pairs[i].key = keys[i]; | 
 |       pairs[i].value = values[i]; | 
 |     }; | 
 |     qsort_b(pairs, count, sizeof(struct GPBFieldPair), | 
 |             ^(const void *first, const void *second) { | 
 |               const struct GPBFieldPair *a = first; | 
 |               const struct GPBFieldPair *b = second; | 
 |               return (a->key > b->key) ? 1 : ((a->key == b->key) ? 0 : -1); | 
 |             }); | 
 |     for (size_t i = 0; i < count; ++i) { | 
 |       GPBUnknownField *value = pairs[i].value; | 
 |       [value writeToOutput:output]; | 
 |     } | 
 |   } else { | 
 |     [values[0] writeToOutput:output]; | 
 |   } | 
 | } | 
 |  | 
 | - (NSString *)description { | 
 |   NSMutableString *description = [NSMutableString | 
 |       stringWithFormat:@"<%@ %p>: TextFormat: {\n", [self class], self]; | 
 |   NSString *textFormat = GPBTextFormatForUnknownFieldSet(self, @"  "); | 
 |   [description appendString:textFormat]; | 
 |   [description appendString:@"}"]; | 
 |   return description; | 
 | } | 
 |  | 
 | static void GPBUnknownFieldSetSerializedSize(const void *key, const void *value, | 
 |                                              void *context) { | 
 | #pragma unused(key) | 
 |   GPBUnknownField *field = value; | 
 |   size_t *result = context; | 
 |   *result += [field serializedSize]; | 
 | } | 
 |  | 
 | - (size_t)serializedSize { | 
 |   size_t result = 0; | 
 |   if (fields_) { | 
 |     CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetSerializedSize, | 
 |                               &result); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | static void GPBUnknownFieldSetWriteAsMessageSetTo(const void *key, | 
 |                                                   const void *value, | 
 |                                                   void *context) { | 
 | #pragma unused(key) | 
 |   GPBUnknownField *field = value; | 
 |   GPBCodedOutputStream *output = context; | 
 |   [field writeAsMessageSetExtensionToOutput:output]; | 
 | } | 
 |  | 
 | - (void)writeAsMessageSetTo:(GPBCodedOutputStream *)output { | 
 |   if (fields_) { | 
 |     CFDictionaryApplyFunction(fields_, GPBUnknownFieldSetWriteAsMessageSetTo, | 
 |                               output); | 
 |   } | 
 | } | 
 |  | 
 | static void GPBUnknownFieldSetSerializedSizeAsMessageSet(const void *key, | 
 |                                                          const void *value, | 
 |                                                          void *context) { | 
 | #pragma unused(key) | 
 |   GPBUnknownField *field = value; | 
 |   size_t *result = context; | 
 |   *result += [field serializedSizeAsMessageSetExtension]; | 
 | } | 
 |  | 
 | - (size_t)serializedSizeAsMessageSet { | 
 |   size_t result = 0; | 
 |   if (fields_) { | 
 |     CFDictionaryApplyFunction( | 
 |         fields_, GPBUnknownFieldSetSerializedSizeAsMessageSet, &result); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | - (NSData *)data { | 
 |   NSMutableData *data = [NSMutableData dataWithLength:self.serializedSize]; | 
 |   GPBCodedOutputStream *output = | 
 |       [[GPBCodedOutputStream alloc] initWithData:data]; | 
 |   [self writeToCodedOutputStream:output]; | 
 |   [output release]; | 
 |   return data; | 
 | } | 
 |  | 
 | + (BOOL)isFieldTag:(int32_t)tag { | 
 |   return GPBWireFormatGetTagWireType(tag) != GPBWireFormatEndGroup; | 
 | } | 
 |  | 
 | - (void)addField:(GPBUnknownField *)field { | 
 |   int32_t number = [field number]; | 
 |   checkNumber(number); | 
 |   if (!fields_) { | 
 |     // Use a custom dictionary here because the keys are numbers and conversion | 
 |     // back and forth from NSNumber isn't worth the cost. | 
 |     fields_ = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, | 
 |                                         &kCFTypeDictionaryValueCallBacks); | 
 |   } | 
 |   ssize_t key = number; | 
 |   CFDictionarySetValue(fields_, (const void *)key, field); | 
 | } | 
 |  | 
 | - (GPBUnknownField *)mutableFieldForNumber:(int32_t)number create:(BOOL)create { | 
 |   ssize_t key = number; | 
 |   GPBUnknownField *existing = | 
 |       fields_ ? CFDictionaryGetValue(fields_, (const void *)key) : nil; | 
 |   if (!existing && create) { | 
 |     existing = [[GPBUnknownField alloc] initWithNumber:number]; | 
 |     // This retains existing. | 
 |     [self addField:existing]; | 
 |     [existing release]; | 
 |   } | 
 |   return existing; | 
 | } | 
 |  | 
 | static void GPBUnknownFieldSetMergeUnknownFields(const void *key, | 
 |                                                  const void *value, | 
 |                                                  void *context) { | 
 | #pragma unused(key) | 
 |   GPBUnknownField *field = value; | 
 |   GPBUnknownFieldSet *self = context; | 
 |  | 
 |   int32_t number = [field number]; | 
 |   checkNumber(number); | 
 |   GPBUnknownField *oldField = [self mutableFieldForNumber:number create:NO]; | 
 |   if (oldField) { | 
 |     [oldField mergeFromField:field]; | 
 |   } else { | 
 |     // Merge only comes from GPBMessage's mergeFrom:, so it means we are on | 
 |     // mutable message and are an mutable instance, so make sure we need | 
 |     // mutable fields. | 
 |     GPBUnknownField *fieldCopy = [field copy]; | 
 |     [self addField:fieldCopy]; | 
 |     [fieldCopy release]; | 
 |   } | 
 | } | 
 |  | 
 | - (void)mergeUnknownFields:(GPBUnknownFieldSet *)other { | 
 |   if (other && other->fields_) { | 
 |     CFDictionaryApplyFunction(other->fields_, | 
 |                               GPBUnknownFieldSetMergeUnknownFields, self); | 
 |   } | 
 | } | 
 |  | 
 | - (void)mergeFromData:(NSData *)data { | 
 |   GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data]; | 
 |   [self mergeFromCodedInputStream:input]; | 
 |   [input checkLastTagWas:0]; | 
 |   [input release]; | 
 | } | 
 |  | 
 | - (void)mergeVarintField:(int32_t)number value:(int32_t)value { | 
 |   checkNumber(number); | 
 |   [[self mutableFieldForNumber:number create:YES] addVarint:value]; | 
 | } | 
 |  | 
 | - (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input { | 
 |   NSAssert(GPBWireFormatIsValidTag(tag), @"Got passed an invalid tag"); | 
 |   int32_t number = GPBWireFormatGetTagFieldNumber(tag); | 
 |   GPBCodedInputStreamState *state = &input->state_; | 
 |   switch (GPBWireFormatGetTagWireType(tag)) { | 
 |     case GPBWireFormatVarint: { | 
 |       GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | 
 |       [field addVarint:GPBCodedInputStreamReadInt64(state)]; | 
 |       return YES; | 
 |     } | 
 |     case GPBWireFormatFixed64: { | 
 |       GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | 
 |       [field addFixed64:GPBCodedInputStreamReadFixed64(state)]; | 
 |       return YES; | 
 |     } | 
 |     case GPBWireFormatLengthDelimited: { | 
 |       NSData *data = GPBCodedInputStreamReadRetainedBytes(state); | 
 |       GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | 
 |       [field addLengthDelimited:data]; | 
 |       [data release]; | 
 |       return YES; | 
 |     } | 
 |     case GPBWireFormatStartGroup: { | 
 |       GPBUnknownFieldSet *unknownFieldSet = [[GPBUnknownFieldSet alloc] init]; | 
 |       [input readUnknownGroup:number message:unknownFieldSet]; | 
 |       GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | 
 |       [field addGroup:unknownFieldSet]; | 
 |       [unknownFieldSet release]; | 
 |       return YES; | 
 |     } | 
 |     case GPBWireFormatEndGroup: | 
 |       return NO; | 
 |     case GPBWireFormatFixed32: { | 
 |       GPBUnknownField *field = [self mutableFieldForNumber:number create:YES]; | 
 |       [field addFixed32:GPBCodedInputStreamReadFixed32(state)]; | 
 |       return YES; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | - (void)mergeMessageSetMessage:(int32_t)number data:(NSData *)messageData { | 
 |   [[self mutableFieldForNumber:number create:YES] | 
 |       addLengthDelimited:messageData]; | 
 | } | 
 |  | 
 | - (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data { | 
 |   GPBUnknownField *field = [self mutableFieldForNumber:fieldNum create:YES]; | 
 |   [field addLengthDelimited:data]; | 
 | } | 
 |  | 
 | - (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input { | 
 |   while (YES) { | 
 |     int32_t tag = GPBCodedInputStreamReadTag(&input->state_); | 
 |     if (tag == 0 || ![self mergeFieldFrom:tag input:input]) { | 
 |       break; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | - (void)getTags:(int32_t *)tags { | 
 |   if (!fields_) return; | 
 |   size_t count = CFDictionaryGetCount(fields_); | 
 |   ssize_t keys[count]; | 
 |   CFDictionaryGetKeysAndValues(fields_, (const void **)keys, NULL); | 
 |   for (size_t i = 0; i < count; ++i) { | 
 |     tags[i] = (int32_t)keys[i]; | 
 |   } | 
 | } | 
 |  | 
 | #pragma clang diagnostic pop | 
 |  | 
 | @end |