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
)
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
);