]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/SecTransformReadTransform.cpp
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / 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 CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(array, 0);
45
46 // Ensure that indeed we do have a CFReadStreamRef
47 if (NULL == item || CFReadStreamGetTypeID() != CFGetTypeID(item))
48 {
49 return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "The input attribute item was nil or not a read stream");
50 }
51
52 // This now is a safe cast
53 CFReadStreamRef input = (CFReadStreamRef)item;
54
55 // Get the state of the stream
56 CFStreamStatus streamStatus = CFReadStreamGetStatus(input);
57 switch (streamStatus)
58 {
59 case kCFStreamStatusNotOpen:
60 {
61 if (!CFReadStreamOpen(input))
62 {
63 // We didn't open properly. Error out
64 return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "An error occurred while opening the stream.");
65 }
66 }
67 break;
68
69 case kCFStreamStatusError:
70 {
71 return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "The read stream is in an error state");
72 }
73
74 default:
75 // The assumption is that the stream is ready to go as is.
76 break;
77 }
78
79 // allocate the read buffer on the heap
80 u_int8_t* buffer = (u_int8_t*) malloc(blockSize);
81
82 CFIndex bytesRead;
83
84 bytesRead = CFReadStreamRead(input, buffer, blockSize);
85 while (bytesRead > 0)
86 {
87 // make data from what was read
88 CFDataRef value = CFDataCreate(NULL, buffer, bytesRead);
89
90 // send it down the chain
91 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
92
93 // cleanup
94 CFReleaseNull(value);
95
96 bytesRead = CFReadStreamRead(input, buffer, blockSize);
97 }
98
99 free(buffer);
100
101 SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef) NULL);
102
103 return (CFTypeRef) NULL;
104 });
105
106 return result;
107 };
108
109 return Block_copy(instanceBlock);
110 }
111
112
113
114 SecTransformRef SecTransformCreateReadTransformWithReadStream(CFReadStreamRef inputStream)
115 {
116 static dispatch_once_t once = 0;
117
118 __block bool ok = true;
119 __block CFErrorRef result = NULL;
120
121 dispatch_once(&once,
122 ^{
123 ok = SecTransformRegister(kStreamTransformName, &StreamTransformImplementation, &result);
124 });
125
126 if (!ok)
127 {
128 return result;
129 }
130 else
131 {
132
133 SecTransformRef transform = SecTransformCreate(kStreamTransformName, &result);
134 if (NULL != transform)
135 {
136 // if we add the read stream directly to the transform the internal source stream
137 // will take over. This is bad. Instead, we wrap this in a CFArray so that we can
138 // pass through undetected
139 CFTypeRef arrayData[] = {inputStream};
140 CFArrayRef arrayRef = CFArrayCreate(NULL, arrayData, 1, &kCFTypeArrayCallBacks);
141
142 // add the input to the transform
143 SecTransformSetAttribute(transform, kSecTransformInputAttributeName, arrayRef, &result);
144
145 CFReleaseNull(arrayRef);
146 }
147
148 return transform;
149 }
150 }