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 41static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension, 42 GPBCodedInputStream *input, 43 GPBExtensionRegistry *extensionRegistry, 44 GPBMessage *existingValue) 45 __attribute__((ns_returns_retained)); 46 47GPB_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 64static 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 95static 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 134static 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 158static 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 200static 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 237static 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 264void 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 304void 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 315size_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. 326static 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