• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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