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
); 
 269 CFGiblisGetSingleton(CFDateFormatterRef
, GetShortDateFormatter
, sDateFormatter
, ^{ 
 270     CFLocaleRef locale 
= CFLocaleCopyCurrent(); 
 271     *sDateFormatter 
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
); 
 273     CFDateFormatterSetFormat(*sDateFormatter
, CFSTR("yyyy-MM-dd HH:mm")); 
 274     CFReleaseNull(locale
); 
 277 CFGiblisGetSingleton(dispatch_queue_t
, GetShortDateFormatterQueue
, sDateFormatQueue
, ^{ 
 278     *sDateFormatQueue 
= dispatch_queue_create("Date Formatting", DISPATCH_QUEUE_SERIAL
); 
 282 // MARK: time formatters 
 285 static void withShortDateFormatter(void (^action
)(CFDateFormatterRef formatter
)) { 
 286     dispatch_sync(GetShortDateFormatterQueue(), ^{ 
 287         action(GetShortDateFormatter()); 
 291 void withStringOfAbsoluteTime(CFAbsoluteTime at
, void (^action
)(CFStringRef decription
)) { 
 292     __block CFStringRef formattedString 
= NULL
; 
 294     withShortDateFormatter(^(CFDateFormatterRef formatter
) { 
 295         formattedString 
= CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault
, formatter
, at
); 
 297     action(formattedString
); 
 299     CFReleaseNull(formattedString
);