2 * Copyright (c) 2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <utilities/SecCFWrappers.h>
26 #include <utilities/SecBuffer.h>
27 #include <CommonCrypto/CommonCryptor.h>
28 #include <CommonCrypto/CommonRandom.h>
30 CFStringRef kSecDebugFormatOption
= CFSTR("debug");
33 // Global singleton CopyDebugDescription format dictionary getter.
35 CFGiblisGetSingleton(CFDictionaryRef
, SecGetDebugDescriptionFormatOptions
, formatOption
, ^{
36 const void *k
[] = { kSecDebugFormatOption
};
37 const void *v
[] = { kCFBooleanTrue
};
38 *formatOption
= CFDictionaryCreate(kCFAllocatorDefault
, k
, v
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
42 // Smart comparator for strings that matches sorting functions
45 CFComparisonResult
CFStringCompareSafe(const void *val1
, const void *val2
, void *context
) {
47 return kCFCompareLessThan
;
49 return kCFCompareGreaterThan
;
51 return CFStringCompare(val1
, val2
, 0);
54 void CFStringArrayPerformWithDelimiterWithDescription(CFArrayRef strings
, CFStringRef start
, CFStringRef end
, void (^action
)(CFStringRef description
)) {
56 action(CFSTR("null"));
58 __block CFMutableStringRef description
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, start
);
59 __block CFStringRef separator
= CFSTR("");
61 CFArrayForEach(strings
, ^(const void *value
) {
62 CFStringAppendFormat(description
, NULL
, CFSTR("%@%@"), separator
, value
);
63 separator
= CFSTR(", ");
66 CFStringAppend(description
, end
);
70 CFReleaseNull(description
);
75 void CFStringArrayPerformWithDescription(CFArrayRef strings
, void (^action
)(CFStringRef description
)) {
76 CFStringArrayPerformWithDelimiterWithDescription(strings
, CFSTR("["), CFSTR("]"), action
);
80 appendDescriptionToArray(const void *value
, void *context
)
82 CFTypeRef obj
= (CFTypeRef
)value
;
83 CFMutableArrayRef array
= (CFMutableArrayRef
)context
;
86 if (CFGetTypeID(obj
) == CFStringGetTypeID()) {
87 CFArrayAppendValue(array
, obj
);
89 desc
= CFCopyDescription(obj
);
91 CFArrayAppendValue(array
, desc
);
94 CFArrayAppendValue(array
, CFSTR("null"));
99 void CFStringSetPerformWithDescription(CFSetRef set
, void (^action
)(CFStringRef description
)) {
101 action(CFSTR("null"));
103 CFMutableArrayRef keys
= CFArrayCreateMutable(NULL
, CFSetGetCount(set
), &kCFTypeArrayCallBacks
);
105 CFSetApplyFunction(set
, appendDescriptionToArray
, keys
);
107 CFArraySortValues(keys
, CFRangeMake(0, CFArrayGetCount(keys
)), (CFComparatorFunction
)&CFStringCompare
, NULL
);
109 CFStringArrayPerformWithDelimiterWithDescription(keys
, CFSTR("{("), CFSTR(")}"), action
);
116 // Global sigleton Zulu time. Must be serialized since it is really a CFMutableCalendarRef
117 // <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
119 static dispatch_queue_t fqueue_cf
;
120 static CFCalendarRef sZuluCalendar
= NULL
;
122 static dispatch_queue_t
SecCFCalendarGetZuluQueue() {
123 static dispatch_once_t onceToken
;
124 dispatch_once(&onceToken
, ^{
125 fqueue_cf
= dispatch_queue_create("ZuluCalendar", DISPATCH_QUEUE_SERIAL
);
130 static CFCalendarRef
SecCFCalendarGetZulu() {
131 static dispatch_once_t onceToken
;
132 dispatch_once(&onceToken
, ^{
133 sZuluCalendar
= CFCalendarCreateWithIdentifier(kCFAllocatorDefault
, kCFGregorianCalendar
);
134 CFTimeZoneRef tz
= CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault
, 0.0);
135 CFCalendarSetTimeZone(sZuluCalendar
, tz
);
139 return sZuluCalendar
;
142 void SecCFCalendarDoWithZuluCalendar(void(^action
)(CFCalendarRef zuluCalendar
)) {
143 dispatch_sync(SecCFCalendarGetZuluQueue(), ^{
144 action(SecCFCalendarGetZulu());
148 void CFStringPerformWithCStringAndLength(CFStringRef inStr
, void(^operation
)(const char *utf8String
, size_t utf8Length
)) {
149 const char *cstr
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
);
151 operation(cstr
, strlen(cstr
));
153 CFIndex neededLen
= 0;
154 CFRange range
= { 0, CFStringGetLength(inStr
) };
156 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
157 0, FALSE
, NULL
, 0, &neededLen
);
159 // + 1 bytes for the '\0' we're adding.
160 PerformWithBuffer(neededLen
+ 1, ^(size_t size
, uint8_t *buf
) {
163 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
164 0, FALSE
, (UInt8
*)buf
, neededLen
, &usedLen
);
165 assert(usedLen
== neededLen
);
167 operation((const char *) buf
, (size_t)usedLen
);
173 void CFStringPerformWithCString(CFStringRef inStr
, void(^operation
)(const char *utf8String
)) {
174 CFStringPerformWithCStringAndLength(inStr
, ^(const char *utf8String
, size_t utf8Length
) {
175 operation(utf8String
);
179 void CFStringPerformWithUTF8CFData(CFStringRef inStr
, void (^operation
)(CFDataRef stringAsData
)) {
180 CFIndex neededLen
= 0;
181 CFRange range
= { 0, CFStringGetLength(inStr
) };
183 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
184 0, FALSE
, NULL
, 0, &neededLen
);
186 CFMutableDataRef data
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, neededLen
);
189 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
190 0, FALSE
, CFDataGetMutableBytePtr(data
), neededLen
, &usedLen
);
191 assert(usedLen
== neededLen
);
199 CFStringRef
CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary
) {
200 CFStringRef result
= NULL
;
202 CFMutableStringRef compactDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("{"));
203 __block CFStringRef separator
= CFSTR("");
205 CFDictionaryForEach(dictionary
, ^(const void *key
, const void *value
) {
206 CFMutableStringRef valueDescription
= NULL
;
208 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("0x"));
209 CFStringAppendHexData(valueDescription
, (CFDataRef
) value
);
211 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("%@%@:%@"), separator
, key
, valueDescription
? valueDescription
: value
);
212 separator
= CFSTR(", ");
213 CFReleaseNull(valueDescription
);
216 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("}"));
218 result
= compactDescription
;
220 result
= CFCopyDescription(kCFNull
);
226 CFStringRef
CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary
) {
227 CFStringRef result
= NULL
;
229 CFMutableStringRef compactDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("{"));
230 __block CFStringRef separator
= CFSTR("");
232 CFDictionaryForEach(dictionary
, ^(const void *key
, const void *value
) {
233 CFMutableStringRef valueDescription
= NULL
;
236 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("0x"));
237 CFStringAppendHexData(valueDescription
, (CFDataRef
) value
);
238 CFStringDelete(valueDescription
, CFRangeMake(0, 5));
240 else if(isString(value
)){
241 CFStringRef stringValue
= NULL
;
242 if(CFStringGetLength(value
) < 6)
243 stringValue
= CFStringCreateCopy(kCFAllocatorDefault
, value
);
245 stringValue
= CFStringCreateWithSubstring(kCFAllocatorDefault
, value
, CFRangeMake(0, 6));
246 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(stringValue
), stringValue
);
247 CFReleaseNull(stringValue
);
249 else if(isNumber(value
)){
250 CFStringRef stringValue
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@"), (CFNumberRef
)value
);
251 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(stringValue
), stringValue
);
252 CFReleaseNull(stringValue
);
255 UniChar firstCharOfKey
= CFStringGetCharacterAtIndex(key
, 0);
256 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("%c:%@ "), firstCharOfKey
, valueDescription
);
257 separator
= CFSTR(", ");
258 CFReleaseNull(valueDescription
);
261 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("}"));
263 result
= compactDescription
;
265 result
= CFCopyDescription(kCFNull
);
272 CFDataRef
CFDataCreateWithRandomBytes(size_t len
) {
273 __block CFDataRef retval
= NULL
;
274 PerformWithBufferAndClear(len
, ^(size_t size
, uint8_t *buffer
) {
275 CCRandomGenerateBytes(buffer
, size
);
276 retval
= CFDataCreate(NULL
, buffer
, size
);
281 CFDataRef
CFDataCreateWithInitializer(CFAllocatorRef allocator
, CFIndex size
, bool (^operation
)(size_t size
, uint8_t *buffer
)) {
282 __block CFMutableDataRef result
= NULL
;
283 if(!size
) return NULL
;
284 if((result
= CFDataCreateMutableWithScratch(allocator
, size
)) == NULL
) return NULL
;
285 if (!operation(size
, CFDataGetMutableBytePtr(result
))) CFReleaseNull(result
);
291 CFGiblisGetSingleton(CFDateFormatterRef
, GetShortDateFormatter
, sDateFormatter
, ^{
292 CFLocaleRef locale
= CFLocaleCopyCurrent();
293 *sDateFormatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
);
295 CFDateFormatterSetFormat(*sDateFormatter
, CFSTR("yyyy-MM-dd HH:mm"));
296 CFReleaseNull(locale
);
299 CFGiblisGetSingleton(dispatch_queue_t
, GetShortDateFormatterQueue
, sDateFormatQueue
, ^{
300 *sDateFormatQueue
= dispatch_queue_create("Date Formatting", DISPATCH_QUEUE_SERIAL
);
304 // MARK: time formatters
307 static void withShortDateFormatter(void (^action
)(CFDateFormatterRef formatter
)) {
308 dispatch_sync(GetShortDateFormatterQueue(), ^{
309 action(GetShortDateFormatter());
313 void withStringOfAbsoluteTime(CFAbsoluteTime at
, void (^action
)(CFStringRef decription
)) {
314 __block CFStringRef formattedString
= NULL
;
316 withShortDateFormatter(^(CFDateFormatterRef formatter
) {
317 formattedString
= CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault
, formatter
, at
);
319 action(formattedString
);
321 CFReleaseNull(formattedString
);