Home | History | Annotate | Download | only in objectivec
      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 "GPBExtensionInternals.h"
     32 
     33 #import <objc/runtime.h>
     34 
     35 #import "GPBCodedInputStream_PackagePrivate.h"
     36 #import "GPBCodedOutputStream_PackagePrivate.h"
     37 #import "GPBDescriptor_PackagePrivate.h"
     38 #import "GPBMessage_PackagePrivate.h"
     39 #import "GPBUtilities_PackagePrivate.h"
     40 
     41 static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension,
     42                                         GPBCodedInputStream *input,
     43                                         GPBExtensionRegistry *extensionRegistry,
     44                                         GPBMessage *existingValue)
     45     __attribute__((ns_returns_retained));
     46 
     47 GPB_INLINE size_t DataTypeSize(GPBDataType dataType) {
     48   switch (dataType) {
     49     case GPBDataTypeBool:
     50       return 1;
     51     case GPBDataTypeFixed32:
     52     case GPBDataTypeSFixed32:
     53     case GPBDataTypeFloat:
     54       return 4;
     55     case GPBDataTypeFixed64:
     56     case GPBDataTypeSFixed64:
     57     case GPBDataTypeDouble:
     58       return 8;
     59     default:
     60       return 0;
     61   }
     62 }
     63 
     64 static size_t ComputePBSerializedSizeNoTagOfObject(GPBDataType dataType, id object) {
     65 #define FIELD_CASE(TYPE, ACCESSOR)                                     \
     66   case GPBDataType##TYPE:                                              \
     67     return GPBCompute##TYPE##SizeNoTag([(NSNumber *)object ACCESSOR]);
     68 #define FIELD_CASE2(TYPE)                                              \
     69   case GPBDataType##TYPE:                                              \
     70     return GPBCompute##TYPE##SizeNoTag(object);
     71   switch (dataType) {
     72     FIELD_CASE(Bool, boolValue)
     73     FIELD_CASE(Float, floatValue)
     74     FIELD_CASE(Double, doubleValue)
     75     FIELD_CASE(Int32, intValue)
     76     FIELD_CASE(SFixed32, intValue)
     77     FIELD_CASE(SInt32, intValue)
     78     FIELD_CASE(Enum, intValue)
     79     FIELD_CASE(Int64, longLongValue)
     80     FIELD_CASE(SInt64, longLongValue)
     81     FIELD_CASE(SFixed64, longLongValue)
     82     FIELD_CASE(UInt32, unsignedIntValue)
     83     FIELD_CASE(Fixed32, unsignedIntValue)
     84     FIELD_CASE(UInt64, unsignedLongLongValue)
     85     FIELD_CASE(Fixed64, unsignedLongLongValue)
     86     FIELD_CASE2(Bytes)
     87     FIELD_CASE2(String)
     88     FIELD_CASE2(Message)
     89     FIELD_CASE2(Group)
     90   }
     91 #undef FIELD_CASE
     92 #undef FIELD_CASE2
     93 }
     94 
     95 static size_t ComputeSerializedSizeIncludingTagOfObject(
     96     GPBExtensionDescription *description, id object) {
     97 #define FIELD_CASE(TYPE, ACCESSOR)                                   \
     98   case GPBDataType##TYPE:                                            \
     99     return GPBCompute##TYPE##Size(description->fieldNumber,          \
    100                                   [(NSNumber *)object ACCESSOR]);
    101 #define FIELD_CASE2(TYPE)                                            \
    102   case GPBDataType##TYPE:                                            \
    103     return GPBCompute##TYPE##Size(description->fieldNumber, object);
    104   switch (description->dataType) {
    105     FIELD_CASE(Bool, boolValue)
    106     FIELD_CASE(Float, floatValue)
    107     FIELD_CASE(Double, doubleValue)
    108     FIELD_CASE(Int32, intValue)
    109     FIELD_CASE(SFixed32, intValue)
    110     FIELD_CASE(SInt32, intValue)
    111     FIELD_CASE(Enum, intValue)
    112     FIELD_CASE(Int64, longLongValue)
    113     FIELD_CASE(SInt64, longLongValue)
    114     FIELD_CASE(SFixed64, longLongValue)
    115     FIELD_CASE(UInt32, unsignedIntValue)
    116     FIELD_CASE(Fixed32, unsignedIntValue)
    117     FIELD_CASE(UInt64, unsignedLongLongValue)
    118     FIELD_CASE(Fixed64, unsignedLongLongValue)
    119     FIELD_CASE2(Bytes)
    120     FIELD_CASE2(String)
    121     FIELD_CASE2(Group)
    122     case GPBDataTypeMessage:
    123       if (GPBExtensionIsWireFormat(description)) {
    124         return GPBComputeMessageSetExtensionSize(description->fieldNumber,
    125                                                  object);
    126       } else {
    127         return GPBComputeMessageSize(description->fieldNumber, object);
    128       }
    129   }
    130 #undef FIELD_CASE
    131 #undef FIELD_CASE2
    132 }
    133 
    134 static size_t ComputeSerializedSizeIncludingTagOfArray(
    135     GPBExtensionDescription *description, NSArray *values) {
    136   if (GPBExtensionIsPacked(description)) {
    137     size_t size = 0;
    138     size_t typeSize = DataTypeSize(description->dataType);
    139     if (typeSize != 0) {
    140       size = values.count * typeSize;
    141     } else {
    142       for (id value in values) {
    143         size +=
    144             ComputePBSerializedSizeNoTagOfObject(description->dataType, value);
    145       }
    146     }
    147     return size + GPBComputeTagSize(description->fieldNumber) +
    148            GPBComputeRawVarint32SizeForInteger(size);
    149   } else {
    150     size_t size = 0;
    151     for (id value in values) {
    152       size += ComputeSerializedSizeIncludingTagOfObject(description, value);
    153     }
    154     return size;
    155   }
    156 }
    157 
    158 static void WriteObjectIncludingTagToCodedOutputStream(
    159     id object, GPBExtensionDescription *description,
    160     GPBCodedOutputStream *output) {
    161 #define FIELD_CASE(TYPE, ACCESSOR)                      \
    162   case GPBDataType##TYPE:                               \
    163     [output write##TYPE:description->fieldNumber        \
    164                   value:[(NSNumber *)object ACCESSOR]]; \
    165     return;
    166 #define FIELD_CASE2(TYPE)                                       \
    167   case GPBDataType##TYPE:                                       \
    168     [output write##TYPE:description->fieldNumber value:object]; \
    169     return;
    170   switch (description->dataType) {
    171     FIELD_CASE(Bool, boolValue)
    172     FIELD_CASE(Float, floatValue)
    173     FIELD_CASE(Double, doubleValue)
    174     FIELD_CASE(Int32, intValue)
    175     FIELD_CASE(SFixed32, intValue)
    176     FIELD_CASE(SInt32, intValue)
    177     FIELD_CASE(Enum, intValue)
    178     FIELD_CASE(Int64, longLongValue)
    179     FIELD_CASE(SInt64, longLongValue)
    180     FIELD_CASE(SFixed64, longLongValue)
    181     FIELD_CASE(UInt32, unsignedIntValue)
    182     FIELD_CASE(Fixed32, unsignedIntValue)
    183     FIELD_CASE(UInt64, unsignedLongLongValue)
    184     FIELD_CASE(Fixed64, unsignedLongLongValue)
    185     FIELD_CASE2(Bytes)
    186     FIELD_CASE2(String)
    187     FIELD_CASE2(Group)
    188     case GPBDataTypeMessage:
    189       if (GPBExtensionIsWireFormat(description)) {
    190         [output writeMessageSetExtension:description->fieldNumber value:object];
    191       } else {
    192         [output writeMessage:description->fieldNumber value:object];
    193       }
    194       return;
    195   }
    196 #undef FIELD_CASE
    197 #undef FIELD_CASE2
    198 }
    199 
    200 static void WriteObjectNoTagToCodedOutputStream(
    201     id object, GPBExtensionDescription *description,
    202     GPBCodedOutputStream *output) {
    203 #define FIELD_CASE(TYPE, ACCESSOR)                             \
    204   case GPBDataType##TYPE:                                      \
    205     [output write##TYPE##NoTag:[(NSNumber *)object ACCESSOR]]; \
    206     return;
    207 #define FIELD_CASE2(TYPE)               \
    208   case GPBDataType##TYPE:               \
    209     [output write##TYPE##NoTag:object]; \
    210     return;
    211   switch (description->dataType) {
    212     FIELD_CASE(Bool, boolValue)
    213     FIELD_CASE(Float, floatValue)
    214     FIELD_CASE(Double, doubleValue)
    215     FIELD_CASE(Int32, intValue)
    216     FIELD_CASE(SFixed32, intValue)
    217     FIELD_CASE(SInt32, intValue)
    218     FIELD_CASE(Enum, intValue)
    219     FIELD_CASE(Int64, longLongValue)
    220     FIELD_CASE(SInt64, longLongValue)
    221     FIELD_CASE(SFixed64, longLongValue)
    222     FIELD_CASE(UInt32, unsignedIntValue)
    223     FIELD_CASE(Fixed32, unsignedIntValue)
    224     FIELD_CASE(UInt64, unsignedLongLongValue)
    225     FIELD_CASE(Fixed64, unsignedLongLongValue)
    226     FIELD_CASE2(Bytes)
    227     FIELD_CASE2(String)
    228     FIELD_CASE2(Message)
    229     case GPBDataTypeGroup:
    230       [output writeGroupNoTag:description->fieldNumber value:object];
    231       return;
    232   }
    233 #undef FIELD_CASE
    234 #undef FIELD_CASE2
    235 }
    236 
    237 static void WriteArrayIncludingTagsToCodedOutputStream(
    238     NSArray *values, GPBExtensionDescription *description,
    239     GPBCodedOutputStream *output) {
    240   if (GPBExtensionIsPacked(description)) {
    241     [output writeTag:description->fieldNumber
    242               format:GPBWireFormatLengthDelimited];
    243     size_t dataSize = 0;
    244     size_t typeSize = DataTypeSize(description->dataType);
    245     if (typeSize != 0) {
    246       dataSize = values.count * typeSize;
    247     } else {
    248       for (id value in values) {
    249         dataSize +=
    250             ComputePBSerializedSizeNoTagOfObject(description->dataType, value);
    251       }
    252     }
    253     [output writeRawVarintSizeTAs32:dataSize];
    254     for (id value in values) {
    255       WriteObjectNoTagToCodedOutputStream(value, description, output);
    256     }
    257   } else {
    258     for (id value in values) {
    259       WriteObjectIncludingTagToCodedOutputStream(value, description, output);
    260     }
    261   }
    262 }
    263 
    264 void GPBExtensionMergeFromInputStream(GPBExtensionDescriptor *extension,
    265                                       BOOL isPackedOnStream,
    266                                       GPBCodedInputStream *input,
    267                                       GPBExtensionRegistry *extensionRegistry,
    268                                       GPBMessage *message) {
    269   GPBExtensionDescription *description = extension->description_;
    270   GPBCodedInputStreamState *state = &input->state_;
    271   if (isPackedOnStream) {
    272     NSCAssert(GPBExtensionIsRepeated(description),
    273               @"How was it packed if it isn't repeated?");
    274     int32_t length = GPBCodedInputStreamReadInt32(state);
    275     size_t limit = GPBCodedInputStreamPushLimit(state, length);
    276     while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
    277       id value = NewSingleValueFromInputStream(extension,
    278                                                input,
    279                                                extensionRegistry,
    280                                                nil);
    281       [message addExtension:extension value:value];
    282       [value release];
    283     }
    284     GPBCodedInputStreamPopLimit(state, limit);
    285   } else {
    286     id existingValue = nil;
    287     BOOL isRepeated = GPBExtensionIsRepeated(description);
    288     if (!isRepeated && GPBDataTypeIsMessage(description->dataType)) {
    289       existingValue = [message getExistingExtension:extension];
    290     }
    291     id value = NewSingleValueFromInputStream(extension,
    292                                              input,
    293                                              extensionRegistry,
    294                                              existingValue);
    295     if (isRepeated) {
    296       [message addExtension:extension value:value];
    297     } else {
    298       [message setExtension:extension value:value];
    299     }
    300     [value release];
    301   }
    302 }
    303 
    304 void GPBWriteExtensionValueToOutputStream(GPBExtensionDescriptor *extension,
    305                                           id value,
    306                                           GPBCodedOutputStream *output) {
    307   GPBExtensionDescription *description = extension->description_;
    308   if (GPBExtensionIsRepeated(description)) {
    309     WriteArrayIncludingTagsToCodedOutputStream(value, description, output);
    310   } else {
    311     WriteObjectIncludingTagToCodedOutputStream(value, description, output);
    312   }
    313 }
    314 
    315 size_t GPBComputeExtensionSerializedSizeIncludingTag(
    316     GPBExtensionDescriptor *extension, id value) {
    317   GPBExtensionDescription *description = extension->description_;
    318   if (GPBExtensionIsRepeated(description)) {
    319     return ComputeSerializedSizeIncludingTagOfArray(description, value);
    320   } else {
    321     return ComputeSerializedSizeIncludingTagOfObject(description, value);
    322   }
    323 }
    324 
    325 // Note that this returns a retained value intentionally.
    326 static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension,
    327                                         GPBCodedInputStream *input,
    328                                         GPBExtensionRegistry *extensionRegistry,
    329                                         GPBMessage *existingValue) {
    330   GPBExtensionDescription *description = extension->description_;
    331   GPBCodedInputStreamState *state = &input->state_;
    332   switch (description->dataType) {
    333     case GPBDataTypeBool:     return [[NSNumber alloc] initWithBool:GPBCodedInputStreamReadBool(state)];
    334     case GPBDataTypeFixed32:  return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadFixed32(state)];
    335     case GPBDataTypeSFixed32: return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSFixed32(state)];
    336     case GPBDataTypeFloat:    return [[NSNumber alloc] initWithFloat:GPBCodedInputStreamReadFloat(state)];
    337     case GPBDataTypeFixed64:  return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadFixed64(state)];
    338     case GPBDataTypeSFixed64: return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSFixed64(state)];
    339     case GPBDataTypeDouble:   return [[NSNumber alloc] initWithDouble:GPBCodedInputStreamReadDouble(state)];
    340     case GPBDataTypeInt32:    return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadInt32(state)];
    341     case GPBDataTypeInt64:    return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadInt64(state)];
    342     case GPBDataTypeSInt32:   return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSInt32(state)];
    343     case GPBDataTypeSInt64:   return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSInt64(state)];
    344     case GPBDataTypeUInt32:   return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadUInt32(state)];
    345     case GPBDataTypeUInt64:   return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadUInt64(state)];
    346     case GPBDataTypeBytes:    return GPBCodedInputStreamReadRetainedBytes(state);
    347     case GPBDataTypeString:   return GPBCodedInputStreamReadRetainedString(state);
    348     case GPBDataTypeEnum:     return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadEnum(state)];
    349     case GPBDataTypeGroup:
    350     case GPBDataTypeMessage: {
    351       GPBMessage *message;
    352       if (existingValue) {
    353         message = [existingValue retain];
    354       } else {
    355         GPBDescriptor *decriptor = [extension.msgClass descriptor];
    356         message = [[decriptor.messageClass alloc] init];
    357       }
    358 
    359       if (description->dataType == GPBDataTypeGroup) {
    360         [input readGroup:description->fieldNumber
    361                  message:message
    362             extensionRegistry:extensionRegistry];
    363       } else {
    364         // description->dataType == GPBDataTypeMessage
    365         if (GPBExtensionIsWireFormat(description)) {
    366           // For MessageSet fields the message length will have already been
    367           // read.
    368           [message mergeFromCodedInputStream:input
    369                            extensionRegistry:extensionRegistry];
    370         } else {
    371           [input readMessage:message extensionRegistry:extensionRegistry];
    372         }
    373       }
    374 
    375       return message;
    376     }
    377   }
    378 
    379   return nil;
    380 }
    381