2  * Copyright (c) 2010 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@ 
  24 #include "Transform.h" 
  25 #include "SecTransform.h" 
  26 #include "SecCollectTransform.h" 
  27 #include "SecCustomTransform.h" 
  30 #include "Utilities.h" 
  32 static CFStringRef kCollectTransformName 
= CFSTR("com.apple.security.seccollecttransform"); 
  34 static SecTransformInstanceBlock 
CollectTransform(CFStringRef name
,  
  35                                                         SecTransformRef newTransform
,  
  36                                                         SecTransformImplementationRef ref
) 
  38         SecTransformInstanceBlock instanceBlock 
=  
  40                 __block CFMutableArrayRef allValues 
=  
  41                         CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
  42                 __block Boolean isSameType 
= TRUE
; 
  43                 CFTypeRef input_ah 
= SecTranformCustomGetAttribute(ref
, kSecTransformInputAttributeName
, kSecTransformMetaAttributeRef
); 
  44                 ah2ta(input_ah
)->direct_error_handling 
= 1; 
  46                 dispatch_block_t no_more_output 
= ^ 
  48                         SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, input_ah
, ^(SecTransformStringOrAttributeRef a
, CFTypeRef v
) { return v
; }); 
  51                 // Create a block to deal with out of memory errors 
  52                 dispatch_block_t oom 
= ^  
  54                         CFTypeRefHolder 
localErr(GetNoMemoryError()); 
  55                         SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
  56                                         kSecTransformMetaAttributeValue
, localErr
.Get()); 
  60                 SecTransformSetTransformAction(ref
, kSecTransformActionFinalize
, 
  63                                         if (NULL 
!= allValues
) 
  68                                         return (CFTypeRef
) NULL
; 
  71                 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, 
  73                         ^(SecTransformStringOrAttributeRef attribute
, CFTypeRef value
) 
  75                                 CFIndex len 
= CFArrayGetCount(allValues
); 
  78                                 if (NULL 
== value 
&& 0 == len
) 
  80                                         SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, 
  81                                         kSecTransformMetaAttributeValue
, NULL
); 
  87                                 if (value 
&& isSameType 
&& len 
> 0) 
  89                                         isSameType 
= CFGetTypeID(CFArrayGetValueAtIndex(allValues
, 0)) == CFGetTypeID(value
); 
  95                                         if (CFGetTypeID(value
) == CFErrorGetTypeID())  
  97                                                 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
  98                                                                 kSecTransformMetaAttributeValue
, value
); 
 103                                         // For mutable types, we want an immutable copy.    
 104                                         /// XXX: write a more general CFImutableCopy and use it here. 
 105                                         if (CFGetTypeID(value
) == CFDataGetTypeID())  
 107                                                 CFDataRef copy 
= CFDataCreateCopy(NULL
, (CFDataRef
)value
); 
 109                                                 CFArrayAppendValue(allValues
, copy
); 
 114                                                 CFArrayAppendValue(allValues
, value
); 
 117                                         if (CFArrayGetCount(allValues
) != len 
+1)  
 127                                                 // Deal with data or no items at all 
 128                                                 CFTypeID type 
= CFArrayGetCount(allValues
) ?  
 129                                                         CFGetTypeID(CFArrayGetValueAtIndex(allValues
, 0)) : CFDataGetTypeID(); 
 130                                                 if (CFDataGetTypeID() == type
)  
 132                                                         CFIndex total_len 
= 0; 
 133                                                         CFIndex prev_total_len 
= 0; 
 135                                                         const CFIndex n_datas 
= CFArrayGetCount(allValues
); 
 137                                                         for(i 
= 0; i 
< n_datas
; i
++)  
 140                                                                         CFDataGetLength((CFDataRef
)CFArrayGetValueAtIndex(allValues
, i
)); 
 141                                                                 if (total_len 
< prev_total_len
)  
 146                                                                 prev_total_len 
= total_len
; 
 149                                                         CFMutableDataRef result 
= CFDataCreateMutable(NULL
, total_len
); 
 156                                                         for(i 
= 0; i 
< n_datas
; i
++)  
 158                                                                 CFDataRef d 
= (CFDataRef
)CFArrayGetValueAtIndex(allValues
, i
); 
 159                                                                 CFDataAppendBytes(result
, CFDataGetBytePtr(d
), CFDataGetLength(d
)); 
 162                                                         if (CFDataGetLength(result
) != total_len
)  
 168                                                         CFDataRef resultData 
= CFDataCreateCopy(NULL
, result
); 
 170                                                         SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
 171                                                                         kSecTransformMetaAttributeValue
, (CFTypeRef
)resultData
); 
 173                                                         CFRelease(resultData
); 
 175                                                         SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
 176                                                                         kSecTransformMetaAttributeValue
, (CFTypeRef
)value
); 
 182                                                 else if (CFStringGetTypeID() == type
)  
 185                                                         CFStringRef resultStr 
= CFStringCreateByCombiningStrings(NULL
, allValues
, CFSTR("")); 
 187                                                         SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
 188                                                                         kSecTransformMetaAttributeValue
, (CFTypeRef
)resultStr
); 
 189                                                         SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
 190                                                                         kSecTransformMetaAttributeValue
, (CFTypeRef
)value
); 
 197                                                         // special case the singleton 
 198                                                         if (1 == CFArrayGetCount(allValues
)) 
 200                                                                 CFTypeRef result 
=  (CFTypeRef
)CFRetain(CFArrayGetValueAtIndex(allValues
, 0)); 
 202                                                                 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
 203                                                                                 kSecTransformMetaAttributeValue
, (CFTypeRef
)result
); 
 204                                                                 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
 205                                                                                 kSecTransformMetaAttributeValue
, (CFTypeRef
)value
); 
 212                                         // Fall through for non-homogenous or un-mergable type 
 213                                         CFArrayRef resultArray 
= CFArrayCreateCopy(kCFAllocatorDefault
, allValues
); 
 214                                         SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
 215                                                         kSecTransformMetaAttributeValue
, (CFTypeRef
)resultArray
); 
 216                                         SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,  
 217                                                         kSecTransformMetaAttributeValue
, (CFTypeRef
)value
); 
 227                 return (CFErrorRef
)NULL
; 
 230         return Block_copy(instanceBlock
);        
 233 SecTransformRef 
SecCreateCollectTransform(CFErrorRef
* error
)  
 235         static dispatch_once_t once
; 
 236         __block Boolean ok 
= TRUE
; 
 238         dispatch_block_t aBlock 
= ^ 
 240                 ok 
= SecTransformRegister(kCollectTransformName
, &CollectTransform
, error
); 
 243         dispatch_once(&once
, aBlock
); 
 250         SecTransformRef yatz 
= SecTransformCreate(kCollectTransformName
, error
);