]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/SecCollectTransform.cpp
Security-59306.11.20.tar.gz
[apple/security.git] / OSX / libsecurity_transform / lib / SecCollectTransform.cpp
1 /*
2 * Copyright (c) 2010-2011 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "Transform.h"
25 #include "SecTransform.h"
26 #include "SecCollectTransform.h"
27 #include "SecCustomTransform.h"
28 #include "misc.h"
29 #include "c++utils.h"
30 #include "Utilities.h"
31
32 static CFStringRef kCollectTransformName = CFSTR("com.apple.security.seccollecttransform");
33
34 static SecTransformInstanceBlock CollectTransform(CFStringRef name,
35 SecTransformRef newTransform,
36 SecTransformImplementationRef ref)
37 {
38 SecTransformInstanceBlock instanceBlock =
39 ^{
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;
45
46 dispatch_block_t no_more_output = ^
47 {
48 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, input_ah, ^(SecTransformStringOrAttributeRef a, CFTypeRef v) { return v; });
49 };
50
51 // Create a block to deal with out of memory errors
52 dispatch_block_t oom = ^
53 {
54 CFTypeRefHolder localErr(GetNoMemoryError());
55 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
56 kSecTransformMetaAttributeValue, localErr.Get());
57 no_more_output();
58 };
59
60 SecTransformSetTransformAction(ref, kSecTransformActionFinalize,
61 ^()
62 {
63 if (NULL != allValues)
64 {
65 CFReleaseNull(allValues);
66 }
67
68 return (CFTypeRef) NULL;
69 });
70
71 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification,
72 input_ah,
73 ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value)
74 {
75 CFIndex len = CFArrayGetCount(allValues);
76
77 #if 0
78 if (NULL == value && 0 == len)
79 {
80 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
81 kSecTransformMetaAttributeValue, NULL);
82 no_more_output();
83 return value;
84 }
85 #endif
86
87 if (value && isSameType && len > 0)
88 {
89 isSameType = CFGetTypeID(CFArrayGetValueAtIndex(allValues, 0)) == CFGetTypeID(value);
90 }
91
92 if (value)
93 {
94
95 if (CFGetTypeID(value) == CFErrorGetTypeID())
96 {
97 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
98 kSecTransformMetaAttributeValue, value);
99 no_more_output();
100 return value;
101 }
102
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())
106 {
107 CFDataRef copy = CFDataCreateCopy(NULL, (CFDataRef)value);
108
109 CFArrayAppendValue(allValues, copy);
110 CFReleaseNull(copy);
111 }
112 else
113 {
114 CFArrayAppendValue(allValues, value);
115 }
116
117 if (CFArrayGetCount(allValues) != len +1)
118 {
119 oom();
120 return value;
121 }
122 }
123 else
124 {
125 if (isSameType)
126 {
127 // Deal with data or no items at all
128 CFTypeID type = CFArrayGetCount(allValues) ?
129 CFGetTypeID(CFArrayGetValueAtIndex(allValues, 0)) : CFDataGetTypeID();
130 if (CFDataGetTypeID() == type)
131 {
132 CFIndex total_len = 0;
133 CFIndex prev_total_len = 0;
134 CFIndex i;
135 const CFIndex n_datas = CFArrayGetCount(allValues);
136
137 for(i = 0; i < n_datas; i++)
138 {
139 total_len +=
140 CFDataGetLength((CFDataRef)CFArrayGetValueAtIndex(allValues, i));
141 if (total_len < prev_total_len)
142 {
143 oom();
144 return value;
145 }
146 prev_total_len = total_len;
147 }
148
149 CFMutableDataRef result = CFDataCreateMutable(NULL, total_len);
150 if (!result)
151 {
152 oom();
153 return value;
154 }
155
156 for(i = 0; i < n_datas; i++)
157 {
158 CFDataRef d = (CFDataRef)CFArrayGetValueAtIndex(allValues, i);
159 CFDataAppendBytes(result, CFDataGetBytePtr(d), CFDataGetLength(d));
160 }
161
162 if (CFDataGetLength(result) != total_len)
163 {
164 oom();
165 CFReleaseNull(result);
166 return value;
167 }
168
169 CFDataRef resultData = CFDataCreateCopy(NULL, result);
170
171 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
172 kSecTransformMetaAttributeValue, (CFTypeRef)resultData);
173
174 CFReleaseNull(resultData);
175
176 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
177 kSecTransformMetaAttributeValue, (CFTypeRef)value);
178 no_more_output();
179
180 CFReleaseNull(result);
181 return value;
182 }
183 else if (CFStringGetTypeID() == type)
184 {
185 // deal with strings
186 CFStringRef resultStr = CFStringCreateByCombiningStrings(NULL, allValues, CFSTR(""));
187
188 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
189 kSecTransformMetaAttributeValue, (CFTypeRef)resultStr);
190 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
191 kSecTransformMetaAttributeValue, (CFTypeRef)value);
192 no_more_output();
193 CFReleaseNull(resultStr);
194
195 return value;
196 }
197 else
198 {
199 // special case the singleton
200 if (1 == CFArrayGetCount(allValues))
201 {
202 CFTypeRef result = (CFTypeRef)CFRetainSafe(CFArrayGetValueAtIndex(allValues, 0));
203
204 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
205 kSecTransformMetaAttributeValue, (CFTypeRef)result);
206 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
207 kSecTransformMetaAttributeValue, (CFTypeRef)value);
208 no_more_output();
209 CFReleaseNull(result);
210
211 return value;
212 }
213 }
214 }
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);
221 no_more_output();
222 CFReleaseNull(resultArray);
223
224 return value;
225 }
226
227 return value;
228
229 });
230
231 return (CFErrorRef)NULL;
232 };
233
234 return Block_copy(instanceBlock);
235 }
236
237 SecTransformRef SecCreateCollectTransform(CFErrorRef* error)
238 {
239 static dispatch_once_t once;
240 __block Boolean ok = TRUE;
241
242 dispatch_block_t aBlock = ^
243 {
244 ok = SecTransformRegister(kCollectTransformName, &CollectTransform, error);
245 };
246
247 dispatch_once(&once, aBlock);
248
249 if (!ok)
250 {
251 return NULL;
252 }
253
254 SecTransformRef yatz = SecTransformCreate(kCollectTransformName, error);
255 return yatz;
256 }