]> git.saurik.com Git - apple/security.git/blob - libsecurity_transform/lib/SecTransformReadTransform.cpp
902bfb1dc4f1fb81456e80e30963cb5df3477034
[apple/security.git] / libsecurity_transform / lib / SecTransformReadTransform.cpp
1 #include "SecTransformReadTransform.h"
2 #include "SecCustomTransform.h"
3 #include "Utilities.h"
4
5 static CFStringRef kStreamTransformName = CFSTR("SecReadStreamTransform");
6 static CFStringRef kStreamMaxSize = CFSTR("MAX_READSIZE");
7
8 static SecTransformInstanceBlock StreamTransformImplementation(CFStringRef name,
9 SecTransformRef newTransform,
10 SecTransformImplementationRef ref)
11 {
12 SecTransformInstanceBlock instanceBlock =
13 ^{
14 CFErrorRef result = NULL;
15
16 if (NULL == name || NULL == newTransform)
17 {
18 }
19
20 // define the storage for our block
21 __block CFIndex blockSize = 4096; // make a default block size
22
23 // it's not necessary to set the input stream size
24 SecTransformCustomSetAttribute(ref, kStreamMaxSize, kSecTransformMetaAttributeRequired, kCFBooleanFalse);
25
26 // define the action if we change the max read size
27 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kStreamMaxSize,
28 ^(SecTransformAttributeRef attribute, CFTypeRef value)
29 {
30 CFNumberGetValue((CFNumberRef) value, kCFNumberCFIndexType, &blockSize);
31 return value;
32 });
33
34 // define for our input action
35 SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName,
36 ^(SecTransformAttributeRef attribute, CFTypeRef value)
37 {
38 if (value == NULL)
39 {
40 return (CFTypeRef) NULL;
41 }
42
43 CFArrayRef array = (CFArrayRef) value;
44 CFReadStreamRef input = (CFReadStreamRef) CFArrayGetValueAtIndex(array, 0);
45
46 // open the stream
47 if (!CFReadStreamOpen(input))
48 {
49 // We didn't open properly. Error out
50 return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "An error occurred while opening the stream.");
51 }
52
53 // allocate the read buffer on the heap
54 u_int8_t* buffer = (u_int8_t*) malloc(blockSize);
55
56 CFIndex bytesRead;
57
58 bytesRead = CFReadStreamRead(input, buffer, blockSize);
59 while (bytesRead > 0)
60 {
61 // make data from what was read
62 CFDataRef value = CFDataCreate(NULL, buffer, bytesRead);
63
64 // send it down the chain
65 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
66
67 // cleanup
68 CFRelease(value);
69
70 bytesRead = CFReadStreamRead(input, buffer, blockSize);
71 }
72
73 free(buffer);
74
75 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef) NULL);
76
77 return (CFTypeRef) NULL;
78 });
79
80 return result;
81 };
82
83 return Block_copy(instanceBlock);
84 }
85
86
87
88 SecTransformRef SecTransformCreateReadTransformWithReadStream(CFReadStreamRef inputStream)
89 {
90 static dispatch_once_t once = 0;
91
92 __block bool ok = true;
93 __block CFErrorRef result = NULL;
94
95 dispatch_once(&once,
96 ^{
97 ok = SecTransformRegister(kStreamTransformName, &StreamTransformImplementation, &result);
98 });
99
100 if (!ok)
101 {
102 return result;
103 }
104 else
105 {
106
107 SecTransformRef transform = SecTransformCreate(kStreamTransformName, &result);
108 if (NULL != transform)
109 {
110 // if we add the read stream directly to the transform the internal source stream
111 // will take over. This is bad. Instead, we wrap this in a CFArray so that we can
112 // pass through undetected
113 CFTypeRef arrayData[] = {inputStream};
114 CFArrayRef arrayRef = CFArrayCreate(NULL, arrayData, 1, &kCFTypeArrayCallBacks);
115
116 // add the input to the transform
117 SecTransformSetAttribute(transform, kSecTransformInputAttributeName, arrayRef, &result);
118
119 CFRelease(arrayRef);
120 }
121
122 return transform;
123 }
124 }