2 * Copyright (c) 2010-2011 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
)
65 CFReleaseNull(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
)
165 CFReleaseNull(result
);
169 CFDataRef resultData
= CFDataCreateCopy(NULL
, result
);
171 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,
172 kSecTransformMetaAttributeValue
, (CFTypeRef
)resultData
);
174 CFReleaseNull(resultData
);
176 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,
177 kSecTransformMetaAttributeValue
, (CFTypeRef
)value
);
180 CFReleaseNull(result
);
183 else if (CFStringGetTypeID() == type
)
186 CFStringRef resultStr
= CFStringCreateByCombiningStrings(NULL
, allValues
, CFSTR(""));
188 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,
189 kSecTransformMetaAttributeValue
, (CFTypeRef
)resultStr
);
190 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,
191 kSecTransformMetaAttributeValue
, (CFTypeRef
)value
);
193 CFReleaseNull(resultStr
);
199 // special case the singleton
200 if (1 == CFArrayGetCount(allValues
))
202 CFTypeRef result
= (CFTypeRef
)CFRetainSafe(CFArrayGetValueAtIndex(allValues
, 0));
204 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,
205 kSecTransformMetaAttributeValue
, (CFTypeRef
)result
);
206 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,
207 kSecTransformMetaAttributeValue
, (CFTypeRef
)value
);
209 CFReleaseNull(result
);
215 // Fall through for non-homogenous or un-mergable type
216 CFArrayRef resultArray
= CFArrayCreateCopy(kCFAllocatorDefault
, allValues
);
217 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,
218 kSecTransformMetaAttributeValue
, (CFTypeRef
)resultArray
);
219 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
,
220 kSecTransformMetaAttributeValue
, (CFTypeRef
)value
);
222 CFReleaseNull(resultArray
);
231 return (CFErrorRef
)NULL
;
234 return Block_copy(instanceBlock
);
237 SecTransformRef
SecCreateCollectTransform(CFErrorRef
* error
)
239 static dispatch_once_t once
;
240 __block Boolean ok
= TRUE
;
242 dispatch_block_t aBlock
= ^
244 ok
= SecTransformRegister(kCollectTransformName
, &CollectTransform
, error
);
247 dispatch_once(&once
, aBlock
);
254 SecTransformRef yatz
= SecTransformCreate(kCollectTransformName
, error
);