]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | //CoreFoundation related utilities | |
27 | // | |
28 | #ifndef _H_CFUTILITIES | |
29 | #define _H_CFUTILITIES | |
30 | ||
31 | #include <security_utilities/utilities.h> | |
32 | #include <security_utilities/globalizer.h> | |
33 | #include <CoreFoundation/CoreFoundation.h> | |
34 | #include <algorithm> | |
35 | #include <Security/SecBase.h> | |
36 | #undef check | |
37 | ||
38 | ||
39 | namespace Security { | |
40 | ||
41 | ||
42 | // | |
43 | // Traits of popular CF types | |
44 | // | |
45 | template <class CFType> struct CFTraits { }; | |
46 | ||
47 | template <> struct CFTraits<CFTypeRef> { | |
48 | static bool check(CFTypeRef ref) { return true; } | |
49 | }; | |
50 | ||
51 | #define __SEC_CFTYPE(name) \ | |
52 | template <> struct CFTraits<name##Ref> { \ | |
53 | static CFTypeID cfid() { return name##GetTypeID(); } \ | |
54 | static bool check(CFTypeRef ref) { return CFGetTypeID(ref) == cfid(); } \ | |
55 | }; | |
56 | ||
57 | __SEC_CFTYPE(CFNull) | |
58 | __SEC_CFTYPE(CFBoolean) | |
59 | __SEC_CFTYPE(CFNumber) | |
60 | __SEC_CFTYPE(CFString) | |
61 | __SEC_CFTYPE(CFData) | |
62 | __SEC_CFTYPE(CFDate) | |
63 | __SEC_CFTYPE(CFURL) | |
64 | __SEC_CFTYPE(CFBundle) | |
65 | __SEC_CFTYPE(CFArray) | |
66 | __SEC_CFTYPE(CFDictionary) | |
67 | __SEC_CFTYPE(CFSet) | |
68 | ||
69 | ||
70 | // | |
71 | // Initialize-only self-releasing CF object handler (lightweight). | |
72 | // | |
73 | template <class CFType> class CFRef { | |
74 | public: | |
75 | CFRef() : mRef(NULL) { } | |
76 | CFRef(CFType ref) : mRef(ref) { } | |
77 | ~CFRef() { this->release(); } | |
78 | CFRef(const CFRef &ref) : mRef(ref) {} | |
79 | template <class _T> CFRef(const CFRef<_T> &ref) : mRef(ref) {} | |
80 | ||
81 | CFRef(CFTypeRef ref, OSStatus err) | |
82 | : mRef(CFType(ref)) | |
83 | { | |
84 | if (ref && !CFTraits<CFType>::check(ref)) | |
85 | MacOSError::throwMe(err); | |
86 | } | |
87 | ||
88 | CFRef &take(CFType ref) | |
89 | { this->release(); mRef = ref; return *this; } | |
90 | ||
91 | CFType yield() | |
92 | { CFType r = mRef; mRef = NULL; return r; } | |
93 | ||
94 | CFRef &operator = (CFType ref) | |
95 | { if (ref) CFRetain(ref); return take(ref); } | |
96 | ||
97 | CFRef &operator = (const CFRef &ref) | |
98 | { if (ref) CFRetain(ref); return take(ref); } | |
99 | ||
100 | // take variant for when newly created CFType is returned | |
101 | // via a ptr-to-CFType argument. | |
102 | CFType *take() | |
103 | { if (mRef) CFRelease(mRef); mRef = NULL; return &mRef; } | |
104 | ||
105 | operator CFType () const { return mRef; } | |
106 | operator bool () const { return mRef != NULL; } | |
107 | bool operator ! () const { return mRef == NULL; } | |
108 | ||
109 | CFType get() const { return mRef; } | |
110 | ||
111 | CFType &aref() | |
112 | { take(NULL); return mRef; } | |
113 | ||
114 | CFType retain() const | |
115 | { if (mRef) CFRetain(mRef); return mRef; } | |
116 | ||
117 | void release() const | |
118 | { if (mRef) CFRelease(mRef); } | |
119 | ||
120 | template <class NewType> | |
121 | bool is() const { return CFTraits<NewType>::check(mRef); } | |
122 | ||
123 | template <class OldType> | |
124 | static CFType check(OldType cf, OSStatus err) | |
125 | { | |
126 | if (cf && !CFTraits<CFType>::check(cf)) | |
127 | MacOSError::throwMe(err); | |
128 | return CFType(cf); | |
129 | } | |
130 | ||
131 | template <class NewType> | |
132 | NewType as() const { return NewType(mRef); } | |
133 | ||
134 | template <class NewType> | |
135 | NewType as(OSStatus err) const { return CFRef<NewType>::check(mRef, err); } | |
136 | ||
137 | private: | |
138 | CFType mRef; | |
139 | }; | |
140 | ||
141 | ||
142 | template <class CFType> class CFCopyRef : public CFRef<CFType> { | |
143 | typedef CFRef<CFType> _Base; | |
144 | public: | |
145 | CFCopyRef() { } | |
146 | CFCopyRef(CFType ref) : _Base(ref) { this->retain(); } | |
147 | CFCopyRef(const CFCopyRef &ref) : _Base(ref) { this->retain(); } | |
148 | template <class _T> CFCopyRef(const CFRef<_T> &ref) : _Base(ref) { this->retain(); } | |
149 | CFCopyRef(CFTypeRef ref, OSStatus err) : _Base(ref, err) { this->retain(); } | |
150 | ||
151 | CFCopyRef &take(CFType ref) | |
152 | { _Base::take(ref); return *this; } | |
153 | ||
154 | CFCopyRef &operator = (CFType ref) | |
155 | { if (ref) CFRetain(ref); return take(ref); } | |
156 | ||
157 | CFCopyRef &operator = (const CFCopyRef &ref) | |
158 | { _Base::operator = (ref); return *this; } | |
159 | ||
160 | template <class _T> CFCopyRef &operator = (const CFRef<_T> &ref) | |
161 | { _Base::operator = (ref); return *this; } | |
162 | }; | |
163 | ||
164 | ||
165 | // | |
166 | // A simple function that turns a non-array CFTypeRef into | |
167 | // an array of one with that element. This will retain its argument | |
168 | // (directly or indirectly). | |
169 | // | |
170 | inline CFArrayRef cfArrayize(CFTypeRef arrayOrItem) | |
171 | { | |
172 | if (arrayOrItem == NULL) | |
173 | return NULL; // NULL is NULL | |
174 | else if (CFGetTypeID(arrayOrItem) == CFArrayGetTypeID()) { | |
175 | CFRetain(arrayOrItem); | |
176 | return CFArrayRef(arrayOrItem); // already an array | |
177 | } else { | |
178 | return CFArrayCreate(NULL, | |
179 | (const void **)&arrayOrItem, 1, &kCFTypeArrayCallBacks); | |
180 | } | |
181 | } | |
182 | ||
183 | ||
184 | // | |
185 | // An empty CFArray. | |
186 | // Since CFArrays are type-neutral, a single immutable empty array will | |
187 | // serve for all uses. So keep it. | |
188 | // | |
189 | struct CFEmptyArray { | |
190 | operator CFArrayRef () { return mArray; } | |
191 | CFEmptyArray(); | |
192 | private: | |
193 | CFArrayRef mArray; | |
194 | }; | |
195 | ||
196 | extern ModuleNexus<CFEmptyArray> cfEmptyArray; | |
197 | ||
198 | ||
199 | // | |
200 | // Translate CFStringRef or CFURLRef to (UTF8-encoded) C++ string. | |
201 | // If release==true, a CFRelease will be performed on the CFWhatever argument | |
202 | // whether the call succeeds or not(!). | |
203 | // | |
204 | string cfString(CFStringRef str); // extract UTF8 string | |
205 | string cfString(CFURLRef url); // path of file: URL (only) | |
206 | string cfString(CFBundleRef bundle); // path to bundle root | |
207 | ||
208 | string cfStringRelease(CFStringRef str CF_CONSUMED); // extract UTF8 string | |
209 | string cfStringRelease(CFURLRef url CF_CONSUMED); // path of file: URL (only) | |
210 | string cfStringRelease(CFBundleRef bundle CF_CONSUMED); // path to bundle root | |
211 | ||
212 | ||
213 | string cfString(CFTypeRef anything, OSStatus err); // dynamic form; throws err on NULL | |
214 | ||
215 | ||
216 | // | |
217 | // Handle CFNumberRefs. | |
218 | // This is nasty because CFNumber does not support unsigned types, and there's really no portably-safe | |
219 | // way of working around this. So the handling of unsigned numbers is "almost correct." | |
220 | // | |
221 | template <class Number> | |
222 | struct CFNumberTraits; | |
223 | ||
224 | template <> struct CFNumberTraits<char> { | |
225 | static const CFNumberType cfnType = kCFNumberCharType; | |
226 | typedef char ValueType; | |
227 | }; | |
228 | template <> struct CFNumberTraits<short> { | |
229 | static const CFNumberType cfnType = kCFNumberShortType; | |
230 | typedef short ValueType; | |
231 | }; | |
232 | template <> struct CFNumberTraits<int> { | |
233 | static const CFNumberType cfnType = kCFNumberIntType; | |
234 | typedef int ValueType; | |
235 | }; | |
236 | template <> struct CFNumberTraits<long> { | |
237 | static const CFNumberType cfnType = kCFNumberLongType; | |
238 | typedef long ValueType; | |
239 | }; | |
240 | template <> struct CFNumberTraits<long long> { | |
241 | static const CFNumberType cfnType = kCFNumberLongLongType; | |
242 | typedef long long ValueType; | |
243 | }; | |
244 | template <> struct CFNumberTraits<float> { | |
245 | static const CFNumberType cfnType = kCFNumberFloatType; | |
246 | typedef float ValueType; | |
247 | }; | |
248 | template <> struct CFNumberTraits<double> { | |
249 | static const CFNumberType cfnType = kCFNumberDoubleType; | |
250 | typedef double ValueType; | |
251 | }; | |
252 | ||
253 | template <> struct CFNumberTraits<unsigned char> { | |
254 | static const CFNumberType cfnType = kCFNumberIntType; | |
255 | typedef int ValueType; | |
256 | }; | |
257 | template <> struct CFNumberTraits<unsigned short> { | |
258 | static const CFNumberType cfnType = kCFNumberIntType; | |
259 | typedef int ValueType; | |
260 | }; | |
261 | template <> struct CFNumberTraits<unsigned int> { | |
262 | static const CFNumberType cfnType = kCFNumberLongLongType; | |
263 | typedef long long ValueType; | |
264 | }; | |
265 | template <> struct CFNumberTraits<unsigned long> { | |
266 | static const CFNumberType cfnType = kCFNumberLongLongType; | |
267 | typedef long long ValueType; | |
268 | }; | |
269 | template <> struct CFNumberTraits<unsigned long long> { | |
270 | static const CFNumberType cfnType = kCFNumberLongLongType; | |
271 | typedef long long ValueType; | |
272 | }; | |
273 | ||
274 | template <class Number> | |
275 | Number cfNumber(CFNumberRef number) | |
276 | { | |
277 | typename CFNumberTraits<Number>::ValueType value; | |
278 | if (CFNumberGetValue(number, CFNumberTraits<Number>::cfnType, &value)) | |
279 | return (Number)value; | |
280 | else | |
281 | CFError::throwMe(); | |
282 | } | |
283 | ||
284 | template <class Number> | |
285 | Number cfNumber(CFNumberRef number, Number defaultValue) | |
286 | { | |
287 | typename CFNumberTraits<Number>::ValueType value; | |
288 | if (CFNumberGetValue(number, CFNumberTraits<Number>::cfnType, &value)) | |
289 | return value; | |
290 | else | |
291 | return defaultValue; | |
292 | } | |
293 | ||
294 | template <class Number> | |
295 | CFNumberRef makeCFNumber(Number value) | |
296 | { | |
297 | typename CFNumberTraits<Number>::ValueType cfValue = value; | |
298 | return CFNumberCreate(NULL, CFNumberTraits<Number>::cfnType, &cfValue); | |
299 | } | |
300 | ||
301 | // legacy form | |
302 | inline uint32_t cfNumber(CFNumberRef number) { return cfNumber<uint32_t>(number); } | |
303 | ||
304 | ||
305 | // | |
306 | // Translate strings into CFStrings | |
307 | // | |
308 | inline CFStringRef makeCFString(const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8) | |
309 | { | |
310 | return s ? CFStringCreateWithCString(NULL, s, encoding) : NULL; | |
311 | } | |
312 | ||
313 | inline CFStringRef makeCFString(const string &s, CFStringEncoding encoding = kCFStringEncodingUTF8) | |
314 | { | |
315 | return CFStringCreateWithCString(NULL, s.c_str(), encoding); | |
316 | } | |
317 | ||
318 | inline CFStringRef makeCFString(CFDataRef data, CFStringEncoding encoding = kCFStringEncodingUTF8) | |
319 | { | |
320 | return CFStringCreateFromExternalRepresentation(NULL, data, encoding); | |
321 | } | |
322 | ||
323 | ||
324 | // | |
325 | // Create CFURL objects from various sources | |
326 | // | |
327 | CFURLRef makeCFURL(const char *s, bool isDirectory = false, CFURLRef base = NULL); | |
328 | CFURLRef makeCFURL(CFStringRef s, bool isDirectory = false, CFURLRef base = NULL); | |
329 | ||
330 | inline CFURLRef makeCFURL(const string &s, bool isDirectory = false, CFURLRef base = NULL) | |
331 | { | |
332 | return makeCFURL(s.c_str(), isDirectory, base); | |
333 | } | |
334 | ||
335 | ||
336 | // | |
337 | // Make temporary CF objects. | |
338 | // | |
339 | class CFTempString : public CFRef<CFStringRef> { | |
340 | public: | |
341 | template <class Source> | |
342 | CFTempString(Source s) : CFRef<CFStringRef>(makeCFString(s)) { } | |
343 | }; | |
344 | ||
345 | class CFTempURL : public CFRef<CFURLRef> { | |
346 | public: | |
347 | template <class Source> | |
348 | CFTempURL(Source s, bool isDirectory = false, CFURLRef base = NULL) | |
349 | : CFRef<CFURLRef>(makeCFURL(s, isDirectory, base)) { } | |
350 | }; | |
351 | ||
352 | ||
353 | // | |
354 | // A temporary CFNumber | |
355 | // | |
356 | class CFTempNumber : public CFRef<CFNumberRef> { | |
357 | public: | |
358 | template <class Value> | |
359 | CFTempNumber(Value value) : CFRef<CFNumberRef>(makeCFNumber(value)) { } | |
360 | }; | |
361 | ||
362 | ||
363 | // | |
364 | // A temporary CFData. | |
365 | // | |
366 | class CFTempData : public CFRef<CFDataRef> { | |
367 | public: | |
368 | CFTempData(const void *data, size_t length) | |
369 | : CFRef<CFDataRef>(CFDataCreate(NULL, (const UInt8 *)data, length)) { } | |
370 | ||
371 | template <class Dataoid> | |
372 | CFTempData(const Dataoid &dataoid) | |
373 | : CFRef<CFDataRef>(CFDataCreate(NULL, (const UInt8 *)dataoid.data(), dataoid.length())) { } | |
374 | }; | |
375 | ||
376 | class CFTempDataWrap : public CFRef<CFDataRef> { | |
377 | public: | |
378 | CFTempDataWrap(const void *data, size_t length) | |
379 | : CFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)data, length, kCFAllocatorNull)) { } | |
380 | ||
381 | template <class Dataoid> | |
382 | CFTempDataWrap(const Dataoid &dataoid) | |
383 | : CFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)dataoid.data(), dataoid.length(), kCFAllocatorNull)) { } | |
384 | }; | |
385 | ||
386 | ||
387 | // | |
388 | // Create CFData objects from various sources. | |
389 | // | |
390 | inline CFDataRef makeCFData(const void *data, size_t size) | |
391 | { | |
392 | return CFDataCreate(NULL, (const UInt8 *)data, size); | |
393 | } | |
394 | ||
395 | inline CFDataRef makeCFData(CFDictionaryRef dictionary) | |
396 | { | |
397 | return CFPropertyListCreateXMLData(NULL, dictionary); | |
398 | } | |
399 | ||
400 | template <class Data> | |
401 | inline CFDataRef makeCFData(const Data &source) | |
402 | { | |
403 | return CFDataCreate(NULL, reinterpret_cast<const UInt8 *>(source.data()), source.length()); | |
404 | } | |
405 | ||
406 | inline CFDataRef makeCFDataMalloc(const void *data, size_t size) | |
407 | { | |
408 | return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)data, size, kCFAllocatorMalloc); | |
409 | } | |
410 | ||
411 | template <class Data> | |
412 | inline CFDataRef makeCFDataMalloc(const Data &source) | |
413 | { | |
414 | return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)source.data(), source.length(), kCFAllocatorMalloc); | |
415 | } | |
416 | ||
417 | ||
418 | // | |
419 | // Create a CFDataRef from malloc'ed data, exception-safely | |
420 | // | |
421 | class CFMallocData { | |
422 | public: | |
423 | CFMallocData(size_t size) | |
424 | : mData(::malloc(size)), mSize(size) | |
425 | { | |
426 | if (!mData) | |
427 | UnixError::throwMe(); | |
428 | } | |
429 | ||
430 | ~CFMallocData() | |
431 | { | |
432 | if (mData) | |
433 | ::free(mData); | |
434 | } | |
435 | ||
436 | template <class T> | |
437 | operator T * () | |
438 | { return static_cast<T *>(mData); } | |
439 | ||
440 | operator CFDataRef (); | |
441 | ||
442 | void *data() { return mData; } | |
443 | const void *data() const { return mData; } | |
444 | size_t length() const { return mSize; } | |
445 | ||
446 | private: | |
447 | void *mData; | |
448 | size_t mSize; | |
449 | }; | |
450 | ||
451 | ||
452 | // | |
453 | // Make CFDictionaries from stuff | |
454 | // | |
455 | CFDictionaryRef makeCFDictionary(unsigned count, ...); // key/value pairs | |
456 | CFMutableDictionaryRef makeCFMutableDictionary(); // empty | |
457 | CFMutableDictionaryRef makeCFMutableDictionary(unsigned count, ...); // (count) key/value pairs | |
458 | CFMutableDictionaryRef makeCFMutableDictionary(CFDictionaryRef dict); // copy of dictionary | |
459 | ||
460 | CFDictionaryRef makeCFDictionaryFrom(CFDataRef data) CF_RETURNS_RETAINED;// interpret plist form | |
461 | CFDictionaryRef makeCFDictionaryFrom(const void *data, size_t length) CF_RETURNS_RETAINED; // ditto | |
462 | ||
463 | ||
464 | // | |
465 | // Parsing out a CFDictionary without losing your lunch | |
466 | // | |
467 | class CFDictionary : public CFCopyRef<CFDictionaryRef> { | |
468 | typedef CFCopyRef<CFDictionaryRef> _Base; | |
469 | public: | |
470 | CFDictionary(CFDictionaryRef ref, OSStatus error) : _Base(ref), mDefaultError(error) | |
471 | { if (!ref) MacOSError::throwMe(error); } | |
472 | CFDictionary(CFTypeRef ref, OSStatus error) : _Base(ref, error), mDefaultError(error) | |
473 | { if (!ref) MacOSError::throwMe(error); } | |
474 | CFDictionary(OSStatus error) : _Base(NULL), mDefaultError(error) { } | |
475 | ||
476 | using CFCopyRef<CFDictionaryRef>::get; | |
477 | ||
478 | CFTypeRef get(CFStringRef key) { return CFDictionaryGetValue(*this, key); } | |
479 | CFTypeRef get(const char *key) { return CFDictionaryGetValue(*this, CFTempString(key)); } | |
480 | ||
481 | template <class CFType> | |
482 | CFType get(CFStringRef key, OSStatus err = errSecSuccess) const | |
483 | { | |
484 | CFTypeRef elem = CFDictionaryGetValue(*this, key); | |
485 | return CFRef<CFType>::check(elem, err ? err : mDefaultError); | |
486 | } | |
487 | ||
488 | template <class CFType> | |
489 | CFType get(const char *key, OSStatus err = errSecSuccess) const | |
490 | { return get<CFType>(CFTempString(key), err); } | |
491 | ||
492 | void apply(CFDictionaryApplierFunction func, void *context) | |
493 | { return CFDictionaryApplyFunction(*this, func, context); } | |
494 | ||
495 | private: | |
496 | template <class T> | |
497 | struct Applier { | |
498 | T *object; | |
499 | void (T::*func)(CFTypeRef key, CFTypeRef value); | |
500 | static void apply(CFTypeRef key, CFTypeRef value, void *context) | |
501 | { Applier *me = (Applier *)context; return ((me->object)->*(me->func))(key, value); } | |
502 | }; | |
503 | ||
504 | template <class Key, class Value> | |
505 | struct BlockApplier { | |
506 | void (^action)(Key key, Value value); | |
507 | static void apply(CFTypeRef key, CFTypeRef value, void* context) | |
508 | { BlockApplier *me = (BlockApplier *)context; return me->action(Key(key), Value(value)); } | |
509 | }; | |
510 | ||
511 | public: | |
512 | template <class T> | |
513 | void apply(T *object, void (T::*func)(CFTypeRef key, CFTypeRef value)) | |
514 | { Applier<T> app; app.object = object; app.func = func; return apply(app.apply, &app); } | |
515 | ||
516 | template <class Key = CFTypeRef, class Value = CFTypeRef> | |
517 | void apply(void (^action)(Key key, Value value)) | |
518 | { BlockApplier<Key, Value> app; app.action = action; return apply(app.apply, &app); } | |
519 | ||
520 | private: | |
521 | OSStatus mDefaultError; | |
522 | }; | |
523 | ||
524 | ||
525 | // | |
526 | // Apply a block to a dictionary | |
527 | // | |
528 | typedef void (^CFDictionaryApplierBlock)(const void *, const void *); | |
529 | void cfDictionaryApplyBlock(CFDictionaryRef source, CFDictionaryApplierBlock block); | |
530 | ||
531 | ||
532 | ||
533 | // | |
534 | // CFURLAccess wrappers for specific purposes | |
535 | // | |
536 | CFDataRef cfLoadFile(CFURLRef url); | |
537 | CFDataRef cfLoadFile(int fd, size_t bytes); | |
538 | inline CFDataRef cfLoadFile(CFStringRef path) { return cfLoadFile(CFTempURL(path)); } | |
539 | inline CFDataRef cfLoadFile(const std::string &path) { return cfLoadFile(CFTempURL(path)); } | |
540 | inline CFDataRef cfLoadFile(const char *path) { return cfLoadFile(CFTempURL(path)); } | |
541 | ||
542 | ||
543 | // | |
544 | // Internally used STL adapters. Should probably be in utilities.h. | |
545 | // | |
546 | template <class Self> | |
547 | Self projectPair(const Self &me) | |
548 | { return me; } | |
549 | ||
550 | template <class First, class Second> | |
551 | Second projectPair(const pair<First, Second> &me) | |
552 | { return me.second; } | |
553 | ||
554 | ||
555 | // | |
556 | // A CFToVector turns a CFArrayRef of items into a flat | |
557 | // C vector of some type, using a conversion function | |
558 | // (from CFTypeRef) specified. As a special bonus, if | |
559 | // you provide a CFTypeRef (other than CFArrayRef), it | |
560 | // will be transparently handled as an array-of-one. | |
561 | // The array will be automatically released on destruction | |
562 | // of the CFToVector object. Any internal structure shared | |
563 | // with the CFTypeRef inputs will be left alone. | |
564 | // | |
565 | template <class VectorBase, class CFRefType, VectorBase convert(CFRefType)> | |
566 | class CFToVector { | |
567 | public: | |
568 | CFToVector(CFArrayRef arrayRef); | |
569 | ~CFToVector() { delete[] mVector; } | |
570 | operator UInt32 () const { return mCount; } | |
571 | operator VectorBase *() const { return mVector; } | |
572 | bool empty() const { return mCount == 0; } | |
573 | ||
574 | VectorBase *begin() const { return mVector; } | |
575 | VectorBase *end() const { return mVector + mCount; } | |
576 | ||
577 | VectorBase &operator [] (UInt32 ix) const { assert(ix < mCount); return mVector[ix]; } | |
578 | ||
579 | private: | |
580 | VectorBase *mVector; | |
581 | UInt32 mCount; | |
582 | }; | |
583 | ||
584 | template <class VectorBase, class CFRefType, VectorBase convert(CFRefType)> | |
585 | CFToVector<VectorBase, CFRefType, convert>::CFToVector(CFArrayRef arrayRef) | |
586 | { | |
587 | if (arrayRef == NULL) { | |
588 | mCount = 0; | |
589 | mVector = NULL; | |
590 | } else { | |
591 | mCount = (UInt32)CFArrayGetCount(arrayRef); | |
592 | mVector = new VectorBase[mCount]; | |
593 | for (UInt32 n = 0; n < mCount; n++) | |
594 | mVector[n] = convert(CFRefType(CFArrayGetValueAtIndex(arrayRef, n))); | |
595 | } | |
596 | } | |
597 | ||
598 | ||
599 | // | |
600 | // Make CFArrays from stuff. | |
601 | // | |
602 | template <class Iterator, class Generator> | |
603 | inline CFArrayRef makeCFArray(Generator &generate, Iterator first, Iterator last) | |
604 | { | |
605 | // how many elements? | |
606 | size_t size = distance(first, last); | |
607 | ||
608 | // do the CFArrayCreate tango | |
609 | auto_array<CFTypeRef> vec(size); | |
610 | for (UInt32 n = 0; n < size; n++) | |
611 | vec[n] = generate(projectPair(*first++)); | |
612 | assert(first == last); | |
613 | return CFArrayCreate(NULL, (const void **)vec.get(), size, &kCFTypeArrayCallBacks); | |
614 | } | |
615 | ||
616 | template <class Container, class Generator> | |
617 | inline CFArrayRef makeCFArray(Generator &generate, const Container &container) | |
618 | { | |
619 | return makeCFArray(generate, container.begin(), container.end()); | |
620 | } | |
621 | ||
622 | CFArrayRef makeCFArray(CFIndex count, ...) CF_RETURNS_RETAINED; | |
623 | CFMutableArrayRef makeCFMutableArray(CFIndex count, ...) CF_RETURNS_RETAINED; | |
624 | ||
625 | ||
626 | // | |
627 | // Apply a block to aa array | |
628 | // | |
629 | typedef void (^CFArrayApplierBlock)(const void *value); | |
630 | void cfArrayApplyBlock(CFArrayRef array, CFRange range, CFArrayApplierBlock block); | |
631 | void cfArrayApplyBlock(CFArrayRef array, CFArrayApplierBlock block); | |
632 | ||
633 | ||
634 | } // end namespace Security | |
635 | ||
636 | #endif //_H_CFUTILITIES |