OLD | NEW |
| (Empty) |
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.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 obje
ct) { | |
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:GPBCodedInpu
tStreamReadBool(state)]; | |
334 case GPBDataTypeFixed32: return [[NSNumber alloc] initWithUnsignedInt:GPBCo
dedInputStreamReadFixed32(state)]; | |
335 case GPBDataTypeSFixed32: return [[NSNumber alloc] initWithInt:GPBCodedInput
StreamReadSFixed32(state)]; | |
336 case GPBDataTypeFloat: return [[NSNumber alloc] initWithFloat:GPBCodedInp
utStreamReadFloat(state)]; | |
337 case GPBDataTypeFixed64: return [[NSNumber alloc] initWithUnsignedLongLong:
GPBCodedInputStreamReadFixed64(state)]; | |
338 case GPBDataTypeSFixed64: return [[NSNumber alloc] initWithLongLong:GPBCoded
InputStreamReadSFixed64(state)]; | |
339 case GPBDataTypeDouble: return [[NSNumber alloc] initWithDouble:GPBCodedIn
putStreamReadDouble(state)]; | |
340 case GPBDataTypeInt32: return [[NSNumber alloc] initWithInt:GPBCodedInput
StreamReadInt32(state)]; | |
341 case GPBDataTypeInt64: return [[NSNumber alloc] initWithLongLong:GPBCoded
InputStreamReadInt64(state)]; | |
342 case GPBDataTypeSInt32: return [[NSNumber alloc] initWithInt:GPBCodedInput
StreamReadSInt32(state)]; | |
343 case GPBDataTypeSInt64: return [[NSNumber alloc] initWithLongLong:GPBCoded
InputStreamReadSInt64(state)]; | |
344 case GPBDataTypeUInt32: return [[NSNumber alloc] initWithUnsignedInt:GPBCo
dedInputStreamReadUInt32(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:GPBCodedInput
StreamReadEnum(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 } | |
OLD | NEW |