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 comparitor for strings that matchies 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 CFStringArrayPerfromWithDelimeterWithDescription(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 CFStringArrayPerfromWithDescription(CFArrayRef strings
, void (^action
)(CFStringRef description
)) {
76 CFStringArrayPerfromWithDelimeterWithDescription(strings
, CFSTR("["), CFSTR("]"), action
);
79 void CFStringSetPerformWithDescription(CFSetRef set
, void (^action
)(CFStringRef description
)) {
81 action(CFSTR("null"));
83 CFMutableArrayRef keys
= CFSetCopyValues(set
);
85 CFArraySortValues(keys
, CFRangeMake(0, CFArrayGetCount(keys
)), (CFComparatorFunction
)&CFStringCompare
, NULL
);
87 CFStringArrayPerfromWithDelimeterWithDescription(keys
, CFSTR("{("), CFSTR(")}"), action
);
94 // Global sigleton Zulu time. Must be serialized since it is really a CFMutableCalendarRef
95 // <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
97 static dispatch_queue_t fqueue_cf
;
98 static CFCalendarRef sZuluCalendar
= NULL
;
100 static dispatch_queue_t
SecCFCalendarGetZuluQueue() {
101 static dispatch_once_t onceToken
;
102 dispatch_once(&onceToken
, ^{
103 fqueue_cf
= dispatch_queue_create("ZuluCalendar", DISPATCH_QUEUE_SERIAL
);
108 static CFCalendarRef
SecCFCalendarGetZulu() {
109 static dispatch_once_t onceToken
;
110 dispatch_once(&onceToken
, ^{
111 sZuluCalendar
= CFCalendarCreateWithIdentifier(kCFAllocatorDefault
, kCFGregorianCalendar
);
112 CFTimeZoneRef tz
= CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault
, 0.0);
113 CFCalendarSetTimeZone(sZuluCalendar
, tz
);
117 return sZuluCalendar
;
120 void SecCFCalendarDoWithZuluCalendar(void(^action
)(CFCalendarRef zuluCalendar
)) {
121 dispatch_sync(SecCFCalendarGetZuluQueue(), ^{
122 action(SecCFCalendarGetZulu());
126 void CFStringPerformWithCStringAndLength(CFStringRef inStr
, void(^operation
)(const char *utf8String
, size_t utf8Length
)) {
127 const char *cstr
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
);
129 operation(cstr
, strlen(cstr
));
131 CFIndex neededLen
= 0;
132 CFRange range
= { 0, CFStringGetLength(inStr
) };
134 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
135 0, FALSE
, NULL
, 0, &neededLen
);
137 // + 1 bytes for the '\0' we're adding.
138 PerformWithBuffer(neededLen
+ 1, ^(size_t size
, uint8_t *buf
) {
141 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
142 0, FALSE
, (UInt8
*)buf
, neededLen
, &usedLen
);
143 assert(usedLen
== neededLen
);
145 operation((const char *) buf
, (size_t)usedLen
);
151 void CFStringPerformWithCString(CFStringRef inStr
, void(^operation
)(const char *utf8String
)) {
152 CFStringPerformWithCStringAndLength(inStr
, ^(const char *utf8String
, size_t utf8Length
) {
153 operation(utf8String
);
157 void CFStringPerformWithUTF8CFData(CFStringRef inStr
, void (^operation
)(CFDataRef stringAsData
)) {
158 CFIndex neededLen
= 0;
159 CFRange range
= { 0, CFStringGetLength(inStr
) };
161 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
162 0, FALSE
, NULL
, 0, &neededLen
);
164 CFMutableDataRef data
= CFDataCreateMutableWithScratch(kCFAllocatorDefault
, neededLen
);
167 CFStringGetBytes(inStr
, range
, kCFStringEncodingUTF8
,
168 0, FALSE
, CFDataGetMutableBytePtr(data
), neededLen
, &usedLen
);
169 assert(usedLen
== neededLen
);
177 CFStringRef
CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary
) {
178 CFStringRef result
= NULL
;
180 CFMutableStringRef compactDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("{"));
181 __block CFStringRef separator
= CFSTR("");
183 CFDictionaryForEach(dictionary
, ^(const void *key
, const void *value
) {
184 CFMutableStringRef valueDescription
= NULL
;
186 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("0x"));
187 CFStringAppendHexData(valueDescription
, (CFDataRef
) value
);
189 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("%@%@:%@"), separator
, key
, valueDescription
? valueDescription
: value
);
190 separator
= CFSTR(", ");
191 CFReleaseNull(valueDescription
);
194 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("}"));
196 result
= compactDescription
;
198 result
= CFCopyDescription(kCFNull
);
204 CFStringRef
CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary
) {
205 CFStringRef result
= NULL
;
207 CFMutableStringRef compactDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("{"));
208 __block CFStringRef separator
= CFSTR("");
210 CFDictionaryForEach(dictionary
, ^(const void *key
, const void *value
) {
211 CFMutableStringRef valueDescription
= NULL
;
214 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("0x"));
215 CFStringAppendHexData(valueDescription
, (CFDataRef
) value
);
216 CFStringDelete(valueDescription
, CFRangeMake(0, 5));
218 else if(isString(value
)){
219 CFStringRef stringValue
= NULL
;
220 if(CFStringGetLength(value
) < 6)
221 stringValue
= CFStringCreateCopy(kCFAllocatorDefault
, value
);
223 stringValue
= CFStringCreateWithSubstring(kCFAllocatorDefault
, value
, CFRangeMake(0, 6));
224 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(stringValue
), stringValue
);
225 CFReleaseNull(stringValue
);
227 else if(isNumber(value
)){
228 CFStringRef stringValue
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@"), (CFNumberRef
)value
);
229 valueDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(stringValue
), stringValue
);
230 CFReleaseNull(stringValue
);
233 UniChar firstCharOfKey
= CFStringGetCharacterAtIndex(key
, 0);
234 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("%c:%@ "), firstCharOfKey
, valueDescription
);
235 separator
= CFSTR(", ");
236 CFReleaseNull(valueDescription
);
239 CFStringAppendFormat(compactDescription
, NULL
, CFSTR("}"));
241 result
= compactDescription
;
243 result
= CFCopyDescription(kCFNull
);
250 CFDataRef
CFDataCreateWithRandomBytes(size_t len
) {
251 __block CFDataRef retval
= NULL
;
252 PerformWithBufferAndClear(len
, ^(size_t size
, uint8_t *buffer
) {
253 CCRandomGenerateBytes(buffer
, size
);
254 retval
= CFDataCreate(NULL
, buffer
, size
);
259 CFDataRef
CFDataCreateWithInitializer(CFAllocatorRef allocator
, CFIndex size
, bool (^operation
)(size_t size
, uint8_t *buffer
)) {
260 __block CFMutableDataRef result
= NULL
;
261 if(!size
) return NULL
;
262 if((result
= CFDataCreateMutableWithScratch(allocator
, size
)) == NULL
) return NULL
;
263 if (!operation(size
, CFDataGetMutableBytePtr(result
))) CFReleaseNull(result
);
270 CFGiblisGetSingleton(CFDateFormatterRef
, GetShortDateFormatter
, sDateFormatter
, ^{
271 CFLocaleRef locale
= CFLocaleCopyCurrent();
272 *sDateFormatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
);
274 CFDateFormatterSetFormat(*sDateFormatter
, CFSTR("yyyy-MM-dd HH:mm"));
275 CFReleaseNull(locale
);
278 CFGiblisGetSingleton(dispatch_queue_t
, GetShortDateFormatterQueue
, sDateFormatQueue
, ^{
279 *sDateFormatQueue
= dispatch_queue_create("Date Formatting", DISPATCH_QUEUE_SERIAL
);
283 // MARK: time formatters
286 static void withShortDateFormatter(void (^action
)(CFDateFormatterRef formatter
)) {
287 dispatch_sync(GetShortDateFormatterQueue(), ^{
288 action(GetShortDateFormatter());
292 void withStringOfAbsoluteTime(CFAbsoluteTime at
, void (^action
)(CFStringRef decription
)) {
293 __block CFStringRef formattedString
= NULL
;
295 withShortDateFormatter(^(CFDateFormatterRef formatter
) {
296 formattedString
= CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault
, formatter
, at
);
298 action(formattedString
);
300 CFReleaseNull(formattedString
);