• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3//
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file or at
6// https://developers.google.com/open-source/licenses/bsd
7
8#import "GPBExtensionInternals.h"
9
10#import <objc/runtime.h>
11
12#import "GPBCodedInputStream.h"
13#import "GPBCodedInputStream_PackagePrivate.h"
14#import "GPBCodedOutputStream.h"
15#import "GPBCodedOutputStream_PackagePrivate.h"
16#import "GPBDescriptor.h"
17#import "GPBDescriptor_PackagePrivate.h"
18#import "GPBMessage.h"
19#import "GPBMessage_PackagePrivate.h"
20#import "GPBUtilities.h"
21#import "GPBUtilities_PackagePrivate.h"
22
23GPB_INLINE size_t DataTypeSize(GPBDataType dataType) {
24#pragma clang diagnostic push
25#pragma clang diagnostic ignored "-Wswitch-enum"
26  switch (dataType) {
27    case GPBDataTypeBool:
28      return 1;
29    case GPBDataTypeFixed32:
30    case GPBDataTypeSFixed32:
31    case GPBDataTypeFloat:
32      return 4;
33    case GPBDataTypeFixed64:
34    case GPBDataTypeSFixed64:
35    case GPBDataTypeDouble:
36      return 8;
37    default:
38      return 0;
39  }
40#pragma clang diagnostic pop
41}
42
43static size_t ComputePBSerializedSizeNoTagOfObject(GPBDataType dataType, id object) {
44#define FIELD_CASE(TYPE, ACCESSOR) \
45  case GPBDataType##TYPE:          \
46    return GPBCompute##TYPE##SizeNoTag([(NSNumber *)object ACCESSOR]);
47#define FIELD_CASE2(TYPE) \
48  case GPBDataType##TYPE: \
49    return GPBCompute##TYPE##SizeNoTag(object);
50  switch (dataType) {
51    FIELD_CASE(Bool, boolValue)
52    FIELD_CASE(Float, floatValue)
53    FIELD_CASE(Double, doubleValue)
54    FIELD_CASE(Int32, intValue)
55    FIELD_CASE(SFixed32, intValue)
56    FIELD_CASE(SInt32, intValue)
57    FIELD_CASE(Enum, intValue)
58    FIELD_CASE(Int64, longLongValue)
59    FIELD_CASE(SInt64, longLongValue)
60    FIELD_CASE(SFixed64, longLongValue)
61    FIELD_CASE(UInt32, unsignedIntValue)
62    FIELD_CASE(Fixed32, unsignedIntValue)
63    FIELD_CASE(UInt64, unsignedLongLongValue)
64    FIELD_CASE(Fixed64, unsignedLongLongValue)
65    FIELD_CASE2(Bytes)
66    FIELD_CASE2(String)
67    FIELD_CASE2(Message)
68    FIELD_CASE2(Group)
69  }
70#undef FIELD_CASE
71#undef FIELD_CASE2
72}
73
74static size_t ComputeSerializedSizeIncludingTagOfObject(GPBExtensionDescription *description,
75                                                        id object) {
76#define FIELD_CASE(TYPE, ACCESSOR) \
77  case GPBDataType##TYPE:          \
78    return GPBCompute##TYPE##Size(description->fieldNumber, [(NSNumber *)object ACCESSOR]);
79#define FIELD_CASE2(TYPE) \
80  case GPBDataType##TYPE: \
81    return GPBCompute##TYPE##Size(description->fieldNumber, object);
82  switch (description->dataType) {
83    FIELD_CASE(Bool, boolValue)
84    FIELD_CASE(Float, floatValue)
85    FIELD_CASE(Double, doubleValue)
86    FIELD_CASE(Int32, intValue)
87    FIELD_CASE(SFixed32, intValue)
88    FIELD_CASE(SInt32, intValue)
89    FIELD_CASE(Enum, intValue)
90    FIELD_CASE(Int64, longLongValue)
91    FIELD_CASE(SInt64, longLongValue)
92    FIELD_CASE(SFixed64, longLongValue)
93    FIELD_CASE(UInt32, unsignedIntValue)
94    FIELD_CASE(Fixed32, unsignedIntValue)
95    FIELD_CASE(UInt64, unsignedLongLongValue)
96    FIELD_CASE(Fixed64, unsignedLongLongValue)
97    FIELD_CASE2(Bytes)
98    FIELD_CASE2(String)
99    FIELD_CASE2(Group)
100    case GPBDataTypeMessage:
101      if (GPBExtensionIsWireFormat(description)) {
102        return GPBComputeMessageSetExtensionSize(description->fieldNumber, object);
103      } else {
104        return GPBComputeMessageSize(description->fieldNumber, object);
105      }
106  }
107#undef FIELD_CASE
108#undef FIELD_CASE2
109}
110
111static size_t ComputeSerializedSizeIncludingTagOfArray(GPBExtensionDescription *description,
112                                                       NSArray *values) {
113  if (GPBExtensionIsPacked(description)) {
114    size_t size = 0;
115    size_t typeSize = DataTypeSize(description->dataType);
116    if (typeSize != 0) {
117      size = values.count * typeSize;
118    } else {
119      for (id value in values) {
120        size += ComputePBSerializedSizeNoTagOfObject(description->dataType, value);
121      }
122    }
123    return size + GPBComputeTagSize(description->fieldNumber) +
124           GPBComputeRawVarint32SizeForInteger(size);
125  } else {
126    size_t size = 0;
127    for (id value in values) {
128      size += ComputeSerializedSizeIncludingTagOfObject(description, value);
129    }
130    return size;
131  }
132}
133
134static void WriteObjectIncludingTagToCodedOutputStream(id object,
135                                                       GPBExtensionDescription *description,
136                                                       GPBCodedOutputStream *output) {
137#define FIELD_CASE(TYPE, ACCESSOR)                                                     \
138  case GPBDataType##TYPE:                                                              \
139    [output write##TYPE:description->fieldNumber value:[(NSNumber *)object ACCESSOR]]; \
140    return;
141#define FIELD_CASE2(TYPE)                                       \
142  case GPBDataType##TYPE:                                       \
143    [output write##TYPE:description->fieldNumber value:object]; \
144    return;
145  switch (description->dataType) {
146    FIELD_CASE(Bool, boolValue)
147    FIELD_CASE(Float, floatValue)
148    FIELD_CASE(Double, doubleValue)
149    FIELD_CASE(Int32, intValue)
150    FIELD_CASE(SFixed32, intValue)
151    FIELD_CASE(SInt32, intValue)
152    FIELD_CASE(Enum, intValue)
153    FIELD_CASE(Int64, longLongValue)
154    FIELD_CASE(SInt64, longLongValue)
155    FIELD_CASE(SFixed64, longLongValue)
156    FIELD_CASE(UInt32, unsignedIntValue)
157    FIELD_CASE(Fixed32, unsignedIntValue)
158    FIELD_CASE(UInt64, unsignedLongLongValue)
159    FIELD_CASE(Fixed64, unsignedLongLongValue)
160    FIELD_CASE2(Bytes)
161    FIELD_CASE2(String)
162    FIELD_CASE2(Group)
163    case GPBDataTypeMessage:
164      if (GPBExtensionIsWireFormat(description)) {
165        [output writeMessageSetExtension:description->fieldNumber value:object];
166      } else {
167        [output writeMessage:description->fieldNumber value:object];
168      }
169      return;
170  }
171#undef FIELD_CASE
172#undef FIELD_CASE2
173}
174
175static void WriteObjectNoTagToCodedOutputStream(id object, GPBExtensionDescription *description,
176                                                GPBCodedOutputStream *output) {
177#define FIELD_CASE(TYPE, ACCESSOR)                             \
178  case GPBDataType##TYPE:                                      \
179    [output write##TYPE##NoTag:[(NSNumber *)object ACCESSOR]]; \
180    return;
181#define FIELD_CASE2(TYPE)               \
182  case GPBDataType##TYPE:               \
183    [output write##TYPE##NoTag:object]; \
184    return;
185  switch (description->dataType) {
186    FIELD_CASE(Bool, boolValue)
187    FIELD_CASE(Float, floatValue)
188    FIELD_CASE(Double, doubleValue)
189    FIELD_CASE(Int32, intValue)
190    FIELD_CASE(SFixed32, intValue)
191    FIELD_CASE(SInt32, intValue)
192    FIELD_CASE(Enum, intValue)
193    FIELD_CASE(Int64, longLongValue)
194    FIELD_CASE(SInt64, longLongValue)
195    FIELD_CASE(SFixed64, longLongValue)
196    FIELD_CASE(UInt32, unsignedIntValue)
197    FIELD_CASE(Fixed32, unsignedIntValue)
198    FIELD_CASE(UInt64, unsignedLongLongValue)
199    FIELD_CASE(Fixed64, unsignedLongLongValue)
200    FIELD_CASE2(Bytes)
201    FIELD_CASE2(String)
202    FIELD_CASE2(Message)
203    case GPBDataTypeGroup:
204      [output writeGroupNoTag:description->fieldNumber value:object];
205      return;
206  }
207#undef FIELD_CASE
208#undef FIELD_CASE2
209}
210
211static void WriteArrayIncludingTagsToCodedOutputStream(NSArray *values,
212                                                       GPBExtensionDescription *description,
213                                                       GPBCodedOutputStream *output) {
214  if (GPBExtensionIsPacked(description)) {
215    [output writeTag:description->fieldNumber format:GPBWireFormatLengthDelimited];
216    size_t dataSize = 0;
217    size_t typeSize = DataTypeSize(description->dataType);
218    if (typeSize != 0) {
219      dataSize = values.count * typeSize;
220    } else {
221      for (id value in values) {
222        dataSize += ComputePBSerializedSizeNoTagOfObject(description->dataType, value);
223      }
224    }
225    [output writeRawVarintSizeTAs32:dataSize];
226    for (id value in values) {
227      WriteObjectNoTagToCodedOutputStream(value, description, output);
228    }
229  } else {
230    for (id value in values) {
231      WriteObjectIncludingTagToCodedOutputStream(value, description, output);
232    }
233  }
234}
235
236// Direct access is use for speed, to avoid even internally declaring things
237// read/write, etc. The warning is enabled in the project to ensure code calling
238// protos can turn on -Wdirect-ivar-access without issues.
239#pragma clang diagnostic push
240#pragma clang diagnostic ignored "-Wdirect-ivar-access"
241
242void GPBWriteExtensionValueToOutputStream(GPBExtensionDescriptor *extension, id value,
243                                          GPBCodedOutputStream *output) {
244  GPBExtensionDescription *description = extension->description_;
245  if (GPBExtensionIsRepeated(description)) {
246    WriteArrayIncludingTagsToCodedOutputStream(value, description, output);
247  } else {
248    WriteObjectIncludingTagToCodedOutputStream(value, description, output);
249  }
250}
251
252size_t GPBComputeExtensionSerializedSizeIncludingTag(GPBExtensionDescriptor *extension, id value) {
253  GPBExtensionDescription *description = extension->description_;
254  if (GPBExtensionIsRepeated(description)) {
255    return ComputeSerializedSizeIncludingTagOfArray(description, value);
256  } else {
257    return ComputeSerializedSizeIncludingTagOfObject(description, value);
258  }
259}
260
261#pragma clang diagnostic pop
262