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