1 /*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "ArgumentCodersCF.h"
28
29 #include "ArgumentDecoder.h"
30 #include "ArgumentEncoder.h"
31 #include "DataReference.h"
32 #include <wtf/Vector.h>
33
34 namespace CoreIPC {
35
tokenNullTypeRef()36 CFTypeRef tokenNullTypeRef()
37 {
38 static CFStringRef tokenNullType = CFSTR("WKNull");
39 return tokenNullType;
40 }
41
42 enum CFType {
43 CFArray,
44 CFBoolean,
45 CFData,
46 CFDictionary,
47 CFNull,
48 CFNumber,
49 CFString,
50 CFURL,
51 #if PLATFORM(MAC)
52 SecCertificate,
53 #endif
54 Null,
55 Unknown,
56 };
57
typeFromCFTypeRef(CFTypeRef type)58 static CFType typeFromCFTypeRef(CFTypeRef type)
59 {
60 ASSERT(type);
61
62 if (type == tokenNullTypeRef())
63 return Null;
64
65 CFTypeID typeID = CFGetTypeID(type);
66 if (typeID == CFArrayGetTypeID())
67 return CFArray;
68 if (typeID == CFBooleanGetTypeID())
69 return CFBoolean;
70 if (typeID == CFDataGetTypeID())
71 return CFData;
72 if (typeID == CFDictionaryGetTypeID())
73 return CFDictionary;
74 if (typeID == CFNullGetTypeID())
75 return CFNull;
76 if (typeID == CFNumberGetTypeID())
77 return CFNumber;
78 if (typeID == CFStringGetTypeID())
79 return CFString;
80 if (typeID == CFURLGetTypeID())
81 return CFURL;
82 #if PLATFORM(MAC)
83 if (typeID == SecCertificateGetTypeID())
84 return SecCertificate;
85 #endif
86
87 ASSERT_NOT_REACHED();
88 return Unknown;
89 }
90
encode(ArgumentEncoder * encoder,CFTypeRef typeRef)91 static void encode(ArgumentEncoder* encoder, CFTypeRef typeRef)
92 {
93 CFType type = typeFromCFTypeRef(typeRef);
94 encoder->encodeEnum(type);
95
96 switch (type) {
97 case CFArray:
98 encode(encoder, static_cast<CFArrayRef>(typeRef));
99 return;
100 case CFBoolean:
101 encode(encoder, static_cast<CFBooleanRef>(typeRef));
102 return;
103 case CFData:
104 encode(encoder, static_cast<CFDataRef>(typeRef));
105 return;
106 case CFDictionary:
107 encode(encoder, static_cast<CFDictionaryRef>(typeRef));
108 return;
109 case CFNull:
110 return;
111 case CFNumber:
112 encode(encoder, static_cast<CFNumberRef>(typeRef));
113 return;
114 case CFString:
115 encode(encoder, static_cast<CFStringRef>(typeRef));
116 return;
117 case CFURL:
118 encode(encoder, static_cast<CFURLRef>(typeRef));
119 return;
120 #if PLATFORM(MAC)
121 case SecCertificate:
122 encode(encoder, (SecCertificateRef)typeRef);
123 return;
124 #endif
125 case Null:
126 return;
127 case Unknown:
128 break;
129 }
130
131 ASSERT_NOT_REACHED();
132 }
133
decode(ArgumentDecoder * decoder,RetainPtr<CFTypeRef> & result)134 static bool decode(ArgumentDecoder* decoder, RetainPtr<CFTypeRef>& result)
135 {
136 CFType type;
137 if (!decoder->decodeEnum(type))
138 return false;
139
140 switch (type) {
141 case CFArray: {
142 RetainPtr<CFArrayRef> array;
143 if (!decode(decoder, array))
144 return false;
145 result.adoptCF(array.leakRef());
146 return true;
147 }
148 case CFBoolean: {
149 RetainPtr<CFBooleanRef> boolean;
150 if (!decode(decoder, boolean))
151 return false;
152 result.adoptCF(boolean.leakRef());
153 return true;
154 }
155 case CFData: {
156 RetainPtr<CFDataRef> data;
157 if (!decode(decoder, data))
158 return false;
159 result.adoptCF(data.leakRef());
160 return true;
161 }
162 case CFDictionary: {
163 RetainPtr<CFDictionaryRef> dictionary;
164 if (!decode(decoder, dictionary))
165 return false;
166 result.adoptCF(dictionary.leakRef());
167 return true;
168 }
169 case CFNull:
170 result.adoptCF(kCFNull);
171 return true;
172 case CFNumber: {
173 RetainPtr<CFNumberRef> number;
174 if (!decode(decoder, number))
175 return false;
176 result.adoptCF(number.leakRef());
177 return true;
178 }
179 case CFString: {
180 RetainPtr<CFStringRef> string;
181 if (!decode(decoder, string))
182 return false;
183 result.adoptCF(string.leakRef());
184 return true;
185 }
186 case CFURL: {
187 RetainPtr<CFURLRef> url;
188 if (!decode(decoder, url))
189 return false;
190 result.adoptCF(url.leakRef());
191 return true;
192 }
193 #if PLATFORM(MAC)
194 case SecCertificate: {
195 RetainPtr<SecCertificateRef> certificate;
196 if (!decode(decoder, certificate))
197 return false;
198 result.adoptCF(certificate.leakRef());
199 return true;
200 }
201 #endif
202 case Null:
203 result = tokenNullTypeRef();
204 return true;
205 case Unknown:
206 ASSERT_NOT_REACHED();
207 return false;
208 }
209
210 return false;
211 }
212
encode(ArgumentEncoder * encoder,CFArrayRef array)213 void encode(ArgumentEncoder* encoder, CFArrayRef array)
214 {
215 CFIndex size = CFArrayGetCount(array);
216 Vector<CFTypeRef, 32> values(size);
217
218 CFArrayGetValues(array, CFRangeMake(0, size), values.data());
219
220 encoder->encodeUInt64(size);
221 for (CFIndex i = 0; i < size; ++i) {
222 ASSERT(values[i]);
223
224 encode(encoder, values[i]);
225 }
226 }
227
decode(ArgumentDecoder * decoder,RetainPtr<CFArrayRef> & result)228 bool decode(ArgumentDecoder* decoder, RetainPtr<CFArrayRef>& result)
229 {
230 uint64_t size;
231 if (!decoder->decodeUInt64(size))
232 return false;
233
234 RetainPtr<CFMutableArrayRef> array(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks));
235
236 for (size_t i = 0; i < size; ++i) {
237 RetainPtr<CFTypeRef> element;
238 if (!decode(decoder, element))
239 return false;
240
241 CFArrayAppendValue(array.get(), element.get());
242 }
243
244 result.adoptCF(array.leakRef());
245 return true;
246 }
247
encode(ArgumentEncoder * encoder,CFBooleanRef boolean)248 void encode(ArgumentEncoder* encoder, CFBooleanRef boolean)
249 {
250 encoder->encodeBool(CFBooleanGetValue(boolean));
251 }
252
decode(ArgumentDecoder * decoder,RetainPtr<CFBooleanRef> & result)253 bool decode(ArgumentDecoder* decoder, RetainPtr<CFBooleanRef>& result)
254 {
255 bool boolean;
256 if (!decoder->decode(boolean))
257 return false;
258
259 result.adoptCF(boolean ? kCFBooleanTrue : kCFBooleanFalse);
260 return true;
261 }
262
encode(ArgumentEncoder * encoder,CFDataRef data)263 void encode(ArgumentEncoder* encoder, CFDataRef data)
264 {
265 CFIndex length = CFDataGetLength(data);
266 const UInt8* bytePtr = CFDataGetBytePtr(data);
267
268 encoder->encodeBytes(bytePtr, length);
269 }
270
decode(ArgumentDecoder * decoder,RetainPtr<CFDataRef> & result)271 bool decode(ArgumentDecoder* decoder, RetainPtr<CFDataRef>& result)
272 {
273 CoreIPC::DataReference dataReference;
274 if (!decoder->decode(dataReference))
275 return false;
276
277 result.adoptCF(CFDataCreate(0, dataReference.data(), dataReference.size()));
278 return true;
279 }
280
encode(ArgumentEncoder * encoder,CFDictionaryRef dictionary)281 void encode(ArgumentEncoder* encoder, CFDictionaryRef dictionary)
282 {
283 CFIndex size = CFDictionaryGetCount(dictionary);
284 Vector<CFTypeRef, 32> keys(size);
285 Vector<CFTypeRef, 32> values(size);
286
287 CFDictionaryGetKeysAndValues(dictionary, keys.data(), values.data());
288
289 encoder->encodeUInt64(size);
290
291 for (CFIndex i = 0; i < size; ++i) {
292 ASSERT(keys[i]);
293 ASSERT(CFGetTypeID(keys[i]) == CFStringGetTypeID());
294 ASSERT(values[i]);
295
296 // Ignore values we don't recognize.
297 if (typeFromCFTypeRef(values[i]) == Unknown)
298 continue;
299
300 encode(encoder, static_cast<CFStringRef>(keys[i]));
301 encode(encoder, values[i]);
302 }
303 }
304
decode(ArgumentDecoder * decoder,RetainPtr<CFDictionaryRef> & result)305 bool decode(ArgumentDecoder* decoder, RetainPtr<CFDictionaryRef>& result)
306 {
307 uint64_t size;
308 if (!decoder->decodeUInt64(size))
309 return false;
310
311 RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
312 for (uint64_t i = 0; i < size; ++i) {
313 // Try to decode the key name.
314 RetainPtr<CFStringRef> key;
315 if (!decode(decoder, key))
316 return false;
317
318 RetainPtr<CFTypeRef> value;
319 if (!decode(decoder, value))
320 return false;
321
322 CFDictionarySetValue(dictionary.get(), key.get(), value.get());
323 }
324
325 result.adoptCF(dictionary.releaseRef());
326 return true;
327 }
328
encode(ArgumentEncoder * encoder,CFNumberRef number)329 void encode(ArgumentEncoder* encoder, CFNumberRef number)
330 {
331 CFNumberType numberType = CFNumberGetType(number);
332
333 Vector<uint8_t> buffer(CFNumberGetByteSize(number));
334 bool result = CFNumberGetValue(number, numberType, buffer.data());
335 ASSERT_UNUSED(result, result);
336
337 encoder->encodeEnum(numberType);
338 encoder->encodeBytes(buffer.data(), buffer.size());
339 }
340
sizeForNumberType(CFNumberType numberType)341 static size_t sizeForNumberType(CFNumberType numberType)
342 {
343 switch (numberType) {
344 case kCFNumberSInt8Type:
345 return sizeof(SInt8);
346 case kCFNumberSInt16Type:
347 return sizeof(SInt16);
348 case kCFNumberSInt32Type:
349 return sizeof(SInt32);
350 case kCFNumberSInt64Type:
351 return sizeof(SInt64);
352 case kCFNumberFloat32Type:
353 return sizeof(Float32);
354 case kCFNumberFloat64Type:
355 return sizeof(Float64);
356 case kCFNumberCharType:
357 return sizeof(char);
358 case kCFNumberShortType:
359 return sizeof(short);
360 case kCFNumberIntType:
361 return sizeof(int);
362 case kCFNumberLongType:
363 return sizeof(long);
364 case kCFNumberLongLongType:
365 return sizeof(long long);
366 case kCFNumberFloatType:
367 return sizeof(float);
368 case kCFNumberDoubleType:
369 return sizeof(double);
370 case kCFNumberCFIndexType:
371 return sizeof(CFIndex);
372 case kCFNumberNSIntegerType:
373 #ifdef __LP64__
374 return sizeof(long);
375 #else
376 return sizeof(int);
377 #endif
378 case kCFNumberCGFloatType:
379 #ifdef __LP64__
380 return sizeof(double);
381 #else
382 return sizeof(float);
383 #endif
384 }
385
386 return 0;
387 }
388
decode(ArgumentDecoder * decoder,RetainPtr<CFNumberRef> & result)389 bool decode(ArgumentDecoder* decoder, RetainPtr<CFNumberRef>& result)
390 {
391 CFNumberType numberType;
392 if (!decoder->decodeEnum(numberType))
393 return false;
394
395 CoreIPC::DataReference dataReference;
396 if (!decoder->decode(dataReference))
397 return false;
398
399 size_t neededBufferSize = sizeForNumberType(numberType);
400 if (!neededBufferSize || dataReference.size() != neededBufferSize)
401 return false;
402
403 ASSERT(dataReference.data());
404 CFNumberRef number = CFNumberCreate(0, numberType, dataReference.data());
405 result.adoptCF(number);
406
407 return true;
408 }
409
encode(ArgumentEncoder * encoder,CFStringRef string)410 void encode(ArgumentEncoder* encoder, CFStringRef string)
411 {
412 CFIndex length = CFStringGetLength(string);
413 CFStringEncoding encoding = CFStringGetFastestEncoding(string);
414
415 CFRange range = CFRangeMake(0, length);
416 CFIndex bufferLength = 0;
417
418 CFIndex numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, 0, 0, &bufferLength);
419 ASSERT(numConvertedBytes == length);
420
421 Vector<UInt8, 128> buffer(bufferLength);
422 numConvertedBytes = CFStringGetBytes(string, range, encoding, 0, false, buffer.data(), buffer.size(), &bufferLength);
423 ASSERT(numConvertedBytes == length);
424
425 encoder->encodeEnum(encoding);
426 encoder->encodeBytes(buffer.data(), bufferLength);
427 }
428
decode(ArgumentDecoder * decoder,RetainPtr<CFStringRef> & result)429 bool decode(ArgumentDecoder* decoder, RetainPtr<CFStringRef>& result)
430 {
431 CFStringEncoding encoding;
432 if (!decoder->decodeEnum(encoding))
433 return false;
434
435 if (!CFStringIsEncodingAvailable(encoding))
436 return false;
437
438 CoreIPC::DataReference dataReference;
439 if (!decoder->decode(dataReference))
440 return false;
441
442 CFStringRef string = CFStringCreateWithBytes(0, dataReference.data(), dataReference.size(), encoding, false);
443 if (!string)
444 return false;
445
446 result.adoptCF(string);
447 return true;
448 }
449
encode(ArgumentEncoder * encoder,CFURLRef url)450 void encode(ArgumentEncoder* encoder, CFURLRef url)
451 {
452 CFURLRef baseURL = CFURLGetBaseURL(url);
453 encoder->encodeBool(baseURL);
454 if (baseURL)
455 encode(encoder, baseURL);
456
457 encode(encoder, CFURLGetString(url));
458 }
459
decode(ArgumentDecoder * decoder,RetainPtr<CFURLRef> & result)460 bool decode(ArgumentDecoder* decoder, RetainPtr<CFURLRef>& result)
461 {
462 RetainPtr<CFURLRef> baseURL;
463 bool hasBaseURL;
464 if (!decoder->decodeBool(hasBaseURL))
465 return false;
466 if (hasBaseURL) {
467 if (!decode(decoder, baseURL))
468 return false;
469 }
470
471 RetainPtr<CFStringRef> string;
472 if (!decode(decoder, string))
473 return false;
474
475 CFURLRef url = CFURLCreateWithString(0, string.get(), baseURL.get());
476 if (!url)
477 return false;
478
479 result.adoptCF(url);
480 return true;
481 }
482
483 #if PLATFORM(MAC)
encode(ArgumentEncoder * encoder,SecCertificateRef certificate)484 void encode(ArgumentEncoder* encoder, SecCertificateRef certificate)
485 {
486 RetainPtr<CFDataRef> data(AdoptCF, SecCertificateCopyData(certificate));
487 encode(encoder, data.get());
488 }
489
decode(ArgumentDecoder * decoder,RetainPtr<SecCertificateRef> & result)490 bool decode(ArgumentDecoder* decoder, RetainPtr<SecCertificateRef>& result)
491 {
492 RetainPtr<CFDataRef> data;
493 if (!decode(decoder, data))
494 return false;
495
496 result.adoptCF(SecCertificateCreateWithData(0, data.get()));
497 return true;
498 }
499 #endif
500
501 } // namespace CoreIPC
502