]> git.saurik.com Git - apple/security.git/blob - utilities/src/SecCFWrappers.h
Security-55471.tar.gz
[apple/security.git] / utilities / src / SecCFWrappers.h
1 //
2 // SecCFWrappers.h
3 //
4 // Created by Mitch Adler on 1/27/11.
5 // Copyright 2011 Apple Inc. All rights reserved.
6 //
7
8 #ifndef _SECCFWRAPPERS_H_
9 #define _SECCFWRAPPERS_H_
10
11 #include <CoreFoundation/CFRuntime.h>
12 #include <CoreFoundation/CFNumber.h>
13 #include <CoreFoundation/CFData.h>
14 #include <CoreFoundation/CFDate.h>
15 #include <CoreFoundation/CFString.h>
16 #include <CoreFoundation/CFPropertyList.h>
17
18 #include <utilities/SecCFRelease.h>
19 #include <utilities/debugging.h>
20
21 #include <assert.h>
22 #include <dispatch/dispatch.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26
27
28 //
29 // Convenience routines.
30 //
31
32 //
33 // Macros for the pattern
34 //
35 // typedef struct _privateNewClass* NewClassRef;
36 //
37 // struct _privateNewClass {
38 // CFRuntimeBase _base;
39 // ... class additions
40 // };
41 //
42 // kClassNameRegisterClass
43 // kClassNameTypeID
44 //
45 // ClassNameGetTypeID()
46 //
47 // CFGiblisFor(NewClass);
48 //
49 // .. define NewClassDestroy
50 // .. define NewClassCopyDescription
51 //
52 // .. use CFTypeAllocate(NewClass, _privateNewClass, allocator);
53 //
54 //
55
56 #define CFGiblisWithFunctions(gibliClassName, describe_func, destroy_func, compare_func, hash_func) \
57 CFTypeID gibliClassName##GetTypeID(void); \
58 CFTypeID gibliClassName##GetTypeID(void) { \
59 static dispatch_once_t k##gibliClassName##RegisterClass; \
60 static CFTypeID k##gibliClassName##TypeID = _kCFRuntimeNotATypeID; \
61 \
62 dispatch_once(&k##gibliClassName##RegisterClass, ^{ \
63 static const CFRuntimeClass k##gibliClassName##Class = { \
64 .className = #gibliClassName, \
65 .finalize = destroy_func, \
66 .copyDebugDesc = describe_func, \
67 .equal = compare_func, \
68 .hash = hash_func, \
69 }; \
70 \
71 k##gibliClassName##TypeID = _CFRuntimeRegisterClass(&k##gibliClassName##Class); \
72 }); \
73 return k##gibliClassName##TypeID; \
74 }
75
76
77 #define CFGiblisWithHashFor(gibliClassName) \
78 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf); \
79 static void gibliClassName##Destroy(CFTypeRef cf); \
80 static Boolean gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
81 static CFHashCode gibliClassName##Hash(CFTypeRef cf); \
82 \
83 CFGiblisWithFunctions(gibliClassName, gibliClassName##CopyDescription, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash)
84
85 #define CFGiblisWithCompareFor(gibliClassName) \
86 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf); \
87 static void gibliClassName##Destroy(CFTypeRef cf); \
88 static Boolean gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
89 \
90 CFGiblisWithFunctions(gibliClassName, gibliClassName##CopyDescription, gibliClassName##Destroy, gibliClassName##Compare, NULL)
91
92
93 #define CFGiblisFor(gibliClassName) \
94 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf); \
95 static void gibliClassName##Destroy(CFTypeRef cf); \
96 \
97 CFGiblisWithFunctions(gibliClassName, gibliClassName##CopyDescription, gibliClassName##Destroy, NULL, NULL)
98
99 #define CFTypeAllocate(classType, internalType, allocator) \
100 (classType##Ref) _CFRuntimeCreateInstance(allocator, classType##GetTypeID(), \
101 sizeof(internalType) - sizeof(CFRuntimeBase), \
102 NULL)
103
104 __BEGIN_DECLS
105
106 //
107 // Call block function
108 //
109
110 static void apply_block_1(const void *value, void *context)
111 {
112 return ((void (^)(const void *value))context)(value);
113 }
114
115 static void apply_block_2(const void *key, const void *value, void *context)
116 {
117 return ((void (^)(const void *key, const void *value))context)(key, value);
118 }
119
120 //
121 // CFEqual Helpers
122 //
123
124 static inline bool CFEqualSafe(CFTypeRef left, CFTypeRef right)
125 {
126 if (left == NULL || right == NULL)
127 return left == right;
128 else
129 return CFEqual(left, right);
130 }
131
132 //
133 // CFNumber Helpers
134 //
135
136 static inline CFNumberRef CFNumberCreateWithCFIndex(CFAllocatorRef allocator, CFIndex value)
137 {
138 return CFNumberCreate(allocator, kCFNumberCFIndexType, &value);
139 }
140
141 //
142 // CFData Helpers
143 //
144
145 static inline CFMutableDataRef CFDataCreateMutableWithScratch(CFAllocatorRef allocator, CFIndex size) {
146 CFMutableDataRef result = CFDataCreateMutable(allocator, 0);
147 CFDataSetLength(result, size);
148
149 return result;
150 }
151
152 static inline void CFDataAppend(CFMutableDataRef appendTo, CFDataRef dataToAppend)
153 {
154 CFDataAppendBytes(appendTo, CFDataGetBytePtr(dataToAppend), CFDataGetLength(dataToAppend));
155 }
156
157 static inline CFDataRef CFDataCreateReferenceFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
158 {
159 return CFDataCreateWithBytesNoCopy(allocator,
160 CFDataGetBytePtr(sourceData) + range.location, range.length,
161 kCFAllocatorNull);
162 }
163
164 static inline CFDataRef CFDataCreateCopyFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
165 {
166 return CFDataCreate(allocator, CFDataGetBytePtr(sourceData) + range.location, range.length);
167 }
168
169 static inline uint8_t* CFDataIncreaseLengthAndGetMutableBytes(CFMutableDataRef data, CFIndex extraLength)
170 {
171 CFIndex startOffset = CFDataGetLength(data);
172
173 CFDataIncreaseLength(data, extraLength);
174
175 return CFDataGetMutableBytePtr(data) + startOffset;
176 }
177
178 static inline uint8_t* CFDataGetMutablePastEndPtr(CFMutableDataRef theData)
179 {
180 return CFDataGetMutableBytePtr(theData) + CFDataGetLength(theData);
181 }
182
183 static inline const uint8_t* CFDataGetPastEndPtr(CFDataRef theData) {
184 return CFDataGetBytePtr(theData) + CFDataGetLength(theData);
185 }
186
187 static inline CFComparisonResult CFDataCompare(CFDataRef left, CFDataRef right)
188 {
189 const size_t left_size = CFDataGetLength(left);
190 const size_t right_size = CFDataGetLength(right);
191 const size_t shortest = (left_size <= right_size) ? left_size : right_size;
192
193 int comparison = memcmp(CFDataGetBytePtr(left), CFDataGetBytePtr(right), shortest);
194
195 if (comparison > 0 || (comparison == 0 && left_size > right_size))
196 return kCFCompareGreaterThan;
197 else if (comparison < 0 || (comparison == 0 && left_size < right_size))
198 return kCFCompareLessThan;
199 else
200 return kCFCompareEqualTo;
201 }
202
203
204 //
205 // CFString Helpers
206 //
207
208 //
209 // Turn a CFString into an allocated UTF8-encoded C string.
210 //
211 static inline char *CFStringToCString(CFStringRef inStr)
212 {
213 if (!inStr)
214 return (char *)strdup("");
215 CFRetain(inStr); // compensate for release on exit
216
217 // need to extract into buffer
218 CFIndex length = CFStringGetLength(inStr); // in 16-bit character units
219 size_t len = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
220 char *buffer = (char *)malloc(len); // pessimistic
221 if (!CFStringGetCString(inStr, buffer, len, kCFStringEncodingUTF8))
222 buffer[0] = 0;
223
224 CFRelease(inStr);
225 return buffer;
226 }
227
228 // runs operation with inStr as a zero terminated C string
229 // in utf8 encoding passed to the operation block.
230 void CFStringPerformWithCString(CFStringRef inStr, void(^operation)(const char *utf8Str));
231
232 // runs operation with inStr as a zero terminated C string
233 // in utf8 passed to the operation block, the length of
234 // the string is also provided to the block.
235 void CFStringPerformWithCStringAndLength(CFStringRef inStr, void(^operation)(const char *utf8Str, size_t utf8Length));
236
237 #include <CommonNumerics/CommonCRC.h>
238
239 static inline void CFStringAppendEncryptedData(CFMutableStringRef s, CFDataRef edata)
240 {
241 const uint8_t *bytes = CFDataGetBytePtr(edata);
242 CFIndex len = CFDataGetLength(edata);
243 CFStringAppendFormat(s, 0, CFSTR("%04lx:"), len);
244 if(len<=8) {
245 for (CFIndex ix = 0; ix < len; ++ix) {
246 CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
247 }
248 } else {
249 uint64_t crc = 0;
250 CNCRC(kCN_CRC_64_ECMA_182, bytes+8, len-8, &crc);
251 for (CFIndex ix = 0; ix < 8; ++ix) {
252 CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
253 }
254 CFStringAppendFormat(s, 0, CFSTR("...|%08llx"), crc);
255 }
256 }
257
258 static inline void CFStringAppendHexData(CFMutableStringRef s, CFDataRef data) {
259 const uint8_t *bytes = CFDataGetBytePtr(data);
260 CFIndex len = CFDataGetLength(data);
261 for (CFIndex ix = 0; ix < len; ++ix) {
262 CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
263 }
264 }
265
266 static inline CFStringRef CFDataCopyHexString(CFDataRef data) {
267 CFMutableStringRef hexString = CFStringCreateMutable(kCFAllocatorDefault, 2 * CFDataGetLength(data));
268 CFStringAppendHexData(hexString, data);
269 return hexString;
270 }
271
272 static inline void CFDataPerformWithHexString(CFDataRef data, void (^operation)(CFStringRef dataString)) {
273 CFStringRef hexString = CFDataCopyHexString(data);
274 operation(hexString);
275 CFRelease(hexString);
276 }
277
278 static inline void BufferPerformWithHexString(const UInt8 *bytes, CFIndex length, void (^operation)(CFStringRef dataString)) {
279 CFDataRef bufferAsData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorNull);
280
281 CFDataPerformWithHexString(bufferAsData, operation);
282
283 CFReleaseNull(bufferAsData);
284 }
285
286
287
288 static inline void CFStringWriteToFile(CFStringRef inStr, FILE* file)
289 {
290 CFStringPerformWithCStringAndLength(inStr, ^(const char *utf8Str, size_t utf8Length) {
291 fwrite(utf8Str, 1, utf8Length, file);
292 });
293 }
294
295 static inline void CFStringWriteToFileWithNewline(CFStringRef inStr, FILE* file)
296 {
297 CFStringWriteToFile(inStr, file);
298 fputc('\n', file);
299 }
300
301 //
302 // MARK: CFArray Helpers
303 //
304
305 static inline CFIndex CFArrayRemoveAllValue(CFMutableArrayRef array, const void* value)
306 {
307 CFIndex position = kCFNotFound;
308 CFIndex numberRemoved = 0;
309
310 position = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value);
311 while (position != kCFNotFound) {
312 CFArrayRemoveValueAtIndex(array, position);
313 ++numberRemoved;
314 position = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value);
315 }
316
317 return numberRemoved;
318 }
319
320 static inline void CFArrayForEach(CFArrayRef array, void (^operation)(const void *value)) {
321 CFArrayApplyFunction(array, CFRangeMake(0, CFArrayGetCount(array)), apply_block_1, operation);
322 }
323
324 static inline void CFArrayForEachReverse(CFArrayRef array, void (^operation)(const void *value)) {
325 for(CFIndex count = CFArrayGetCount(array); count > 0; --count) {
326 operation(CFArrayGetValueAtIndex(array, count - 1));
327 }
328 }
329
330 static inline const void *CFArrayGetValueMatching(CFArrayRef array, bool (^match)(const void *value)) {
331 CFIndex i, n = CFArrayGetCount(array);
332 for (i = 0; i < n; ++i) {
333 const void *value = CFArrayGetValueAtIndex(array, i);
334 if (match(value)) {
335 return value;
336 }
337 }
338 return NULL;
339 }
340
341 static inline bool CFArrayHasValueMatching(CFArrayRef array, bool (^match)(const void *value)) {
342 return CFArrayGetValueMatching(array, match) != NULL;
343 }
344
345 static inline void CFMutableArrayModifyValues(CFMutableArrayRef array, const void * (^process)(const void *value)) {
346 CFIndex i, n = CFArrayGetCount(array);
347 for (i = 0; i < n; ++i) {
348 const void *value = CFArrayGetValueAtIndex(array, i);
349 CFArraySetValueAtIndex(array, i, process(value));
350 }
351 }
352
353 //
354 // MARK: CFArray creatino Var args helper functions.
355 //
356 static inline CFArrayRef CFArrayCreateCountedForVC(CFAllocatorRef allocator, const CFArrayCallBacks *cbs, CFIndex entries, va_list args)
357 {
358 const void *values[entries];
359
360 for(CFIndex currentValue = 0; currentValue < entries; ++currentValue)
361 {
362 values[currentValue] = va_arg(args, void*);
363
364 if (values[currentValue] == NULL)
365 values[currentValue] = kCFNull;
366 }
367
368 return CFArrayCreate(allocator, values, entries, cbs);
369 }
370
371 static inline CFArrayRef CFArrayCreateForVC(CFAllocatorRef allocator, const CFArrayCallBacks *cbs, va_list args)
372 {
373 va_list count;
374 va_copy(count, args);
375
376 CFIndex entries = 0;
377 while (NULL != va_arg(count, void*)) {
378 entries += 1;
379 }
380
381 return CFArrayCreateCountedForVC(allocator, cbs, entries, args);
382
383 }
384
385 //
386 // MARK: CFArray of CFTypes support
387 //
388
389 static inline CFMutableArrayRef CFArrayCreateMutableForCFTypes(CFAllocatorRef allocator)
390 {
391 return CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
392 }
393
394 static inline CFArrayRef CFArrayCreateForCFTypes(CFAllocatorRef allocator, ...)
395 {
396 va_list args;
397 va_start(args, allocator);
398
399 return CFArrayCreateForVC(allocator, &kCFTypeArrayCallBacks, args);
400
401 }
402
403 static inline CFArrayRef CFArrayCreateCountedForCFTypes(CFAllocatorRef allocator, CFIndex entries, ...)
404 {
405 va_list args;
406 va_start(args, entries);
407
408 return CFArrayCreateCountedForVC(allocator, &kCFTypeArrayCallBacks, entries, args);
409 }
410
411 static inline CFArrayRef CFArrayCreateCountedForCFTypesV(CFAllocatorRef allocator, CFIndex entries, va_list args)
412 {
413 return CFArrayCreateCountedForVC(allocator, &kCFTypeArrayCallBacks, entries, args);
414 }
415
416 //
417 // MARK: CFDictionary of CFTypes helpers
418 //
419
420 static inline CFDictionaryRef CFDictionaryCreateCountedForCFTypesV(CFAllocatorRef allocator, CFIndex entries, va_list args)
421 {
422 const void *keys[entries];
423 const void *values[entries];
424
425 for(CFIndex currentValue = 0; currentValue < entries; ++currentValue)
426 {
427 keys[currentValue] = va_arg(args, void*);
428 values[currentValue] = va_arg(args, void*);
429
430 if (values[currentValue] == NULL)
431 values[currentValue] = kCFNull;
432 }
433
434 return CFDictionaryCreate(allocator, keys, values, entries,
435 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
436 }
437
438 static inline CFDictionaryRef CFDictionaryCreateForCFTypes(CFAllocatorRef allocator, ...)
439 {
440 va_list args;
441 va_start(args, allocator);
442
443 CFIndex entries = 0;
444 while (NULL != va_arg(args, void*)) {
445 entries += 2;
446 (void) va_arg(args, void*);
447 }
448
449 entries /= 2;
450
451 va_start(args, allocator);
452
453 return CFDictionaryCreateCountedForCFTypesV(allocator, entries, args);
454
455 }
456
457 static inline CFDictionaryRef CFDictionaryCreateCountedForCFTypes(CFAllocatorRef allocator, CFIndex entries, ...)
458 {
459 va_list args;
460 va_start(args, entries);
461
462 return CFDictionaryCreateCountedForCFTypesV(allocator, entries, args);
463 }
464
465 static inline CFMutableDictionaryRef CFDictionaryCreateMutableForCFTypes(CFAllocatorRef allocator)
466 {
467 return CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
468 }
469
470 static inline CFMutableDictionaryRef CFDictionaryCreateMutableForCFTypesWith(CFAllocatorRef allocator, ...)
471 {
472 CFMutableDictionaryRef result = CFDictionaryCreateMutableForCFTypes(allocator);
473
474 va_list args;
475 va_start(args, allocator);
476
477 void* key = va_arg(args, void*);
478
479 while (key != NULL) {
480 CFDictionarySetValue(result, key, va_arg(args, void*));
481 key = va_arg(args, void*);
482 };
483
484 return result;
485 }
486
487 //
488 // MARK: CFDictionary Helpers
489 //
490
491 static inline void CFDictionaryForEach(CFDictionaryRef dictionary, void (^operation)(const void *key, const void *value)) {
492 CFDictionaryApplyFunction(dictionary, apply_block_2, operation);
493 }
494
495 //
496 // Type checking
497 //
498
499 static inline bool isArray(CFTypeRef cfType) {
500 return cfType && CFGetTypeID(cfType) == CFArrayGetTypeID();
501 }
502
503 static inline bool isData(CFTypeRef cfType) {
504 return cfType && CFGetTypeID(cfType) == CFDataGetTypeID();
505 }
506
507 static inline bool isDate(CFTypeRef cfType) {
508 return cfType && CFGetTypeID(cfType) == CFDateGetTypeID();
509 }
510
511 static inline bool isDictionary(CFTypeRef cfType) {
512 return cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID();
513 }
514
515 static inline bool isNumber(CFTypeRef cfType) {
516 return cfType && CFGetTypeID(cfType) == CFNumberGetTypeID();
517 }
518
519 static inline bool isNumberOfType(CFTypeRef cfType, CFNumberType number) {
520 return isNumber(cfType) && CFNumberGetType((CFNumberRef)cfType) == number;
521 }
522
523 static inline bool isString(CFTypeRef cfType) {
524 return cfType && CFGetTypeID(cfType) == CFStringGetTypeID();
525 }
526
527 static inline bool isBoolean(CFTypeRef cfType) {
528 return cfType && CFGetTypeID(cfType) == CFBooleanGetTypeID();
529 }
530
531 static inline bool isNull(CFTypeRef cfType) {
532 return cfType && CFGetTypeID(cfType) == CFNullGetTypeID();
533 }
534
535
536 //
537 // MARK: PropertyList Helpers
538 //
539
540 //
541 // Crazy reading and writing stuff
542 //
543
544 static inline void CFPropertyListWriteToFile(CFPropertyListRef plist, CFURLRef file)
545 {
546 CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, file);
547 CFErrorRef error = NULL;
548
549 CFWriteStreamOpen(writeStream);
550 CFPropertyListWrite(plist, writeStream, kCFPropertyListBinaryFormat_v1_0, 0, &error);
551 if (error)
552 secerror("Can't write plist: %@", error);
553
554 CFReleaseNull(error);
555 CFReleaseNull(writeStream);
556 }
557
558 static inline CF_RETURNS_RETAINED CFPropertyListRef CFPropertyListReadFromFile(CFURLRef file)
559 {
560 CFPropertyListRef result = NULL;
561 CFErrorRef error = NULL;
562 CFBooleanRef isRegularFile;
563 if (!CFURLCopyResourcePropertyForKey(file, kCFURLIsRegularFileKey, &isRegularFile, &error)) {
564 secerror("file %@: %@", file, error);
565 } else if (CFBooleanGetValue(isRegularFile)) {
566 CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, file);
567 if (readStream) {
568 if (CFReadStreamOpen(readStream)) {
569 CFPropertyListFormat format;
570 result = CFPropertyListCreateWithStream(kCFAllocatorDefault, readStream, 0, kCFPropertyListMutableContainers, &format, &error);
571 if (!result) {
572 secerror("read plist from %@: %@", file, error);
573 }
574 }
575 CFRelease(readStream);
576 }
577 }
578 CFReleaseNull(error);
579
580 return result;
581 }
582
583 __END_DECLS
584
585 #endif