]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/SecCollectTransform.cpp
Security-57336.1.9.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 CFRelease(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 CFRelease(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 return value;
166 }
167
168 CFDataRef resultData = CFDataCreateCopy(NULL, result);
169
170 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
171 kSecTransformMetaAttributeValue, (CFTypeRef)resultData);
172
173 CFRelease(resultData);
174
175 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
176 kSecTransformMetaAttributeValue, (CFTypeRef)value);
177 no_more_output();
178
179 CFRelease(result);
180 return value;
181 }
182 else if (CFStringGetTypeID() == type)
183 {
184 // deal with strings
185 CFStringRef resultStr = CFStringCreateByCombiningStrings(NULL, allValues, CFSTR(""));
186
187 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
188 kSecTransformMetaAttributeValue, (CFTypeRef)resultStr);
189 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
190 kSecTransformMetaAttributeValue, (CFTypeRef)value);
191 no_more_output();
192
193 return value;
194 }
195 else
196 {
197 // special case the singleton
198 if (1 == CFArrayGetCount(allValues))
199 {
200 CFTypeRef result = (CFTypeRef)CFRetain(CFArrayGetValueAtIndex(allValues, 0));
201
202 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
203 kSecTransformMetaAttributeValue, (CFTypeRef)result);
204 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName,
205 kSecTransformMetaAttributeValue, (CFTypeRef)value);
206 no_more_output();
207
208 return value;
209 }
210 }
211 }
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);
218 no_more_output();
219
220 return value;
221 }
222
223 return value;
224
225 });
226
227 return (CFErrorRef)NULL;
228 };
229
230 return Block_copy(instanceBlock);
231 }
232
233 SecTransformRef SecCreateCollectTransform(CFErrorRef* error)
234 {
235 static dispatch_once_t once;
236 __block Boolean ok = TRUE;
237
238 dispatch_block_t aBlock = ^
239 {
240 ok = SecTransformRegister(kCollectTransformName, &CollectTransform, error);
241 };
242
243 dispatch_once(&once, aBlock);
244
245 if (!ok)
246 {
247 return NULL;
248 }
249
250 SecTransformRef yatz = SecTransformCreate(kCollectTransformName, error);
251 return yatz;
252 }