1 #include "SecTransformReadTransform.h"
2 #include "SecCustomTransform.h"
5 static CFStringRef kStreamTransformName
= CFSTR("SecReadStreamTransform");
6 static CFStringRef kStreamMaxSize
= CFSTR("MAX_READSIZE");
8 static SecTransformInstanceBlock
StreamTransformImplementation(CFStringRef name
,
9 SecTransformRef newTransform
,
10 SecTransformImplementationRef ref
)
12 SecTransformInstanceBlock instanceBlock
=
14 CFErrorRef result
= NULL
;
16 if (NULL
== name
|| NULL
== newTransform
)
20 // define the storage for our block
21 __block CFIndex blockSize
= 4096; // make a default block size
23 // it's not necessary to set the input stream size
24 SecTransformCustomSetAttribute(ref
, kStreamMaxSize
, kSecTransformMetaAttributeRequired
, kCFBooleanFalse
);
26 // define the action if we change the max read size
27 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kStreamMaxSize
,
28 ^(SecTransformAttributeRef attribute
, CFTypeRef value
)
30 CFNumberGetValue((CFNumberRef
) value
, kCFNumberCFIndexType
, &blockSize
);
34 // define for our input action
35 SecTransformSetAttributeAction(ref
, kSecTransformActionAttributeNotification
, kSecTransformInputAttributeName
,
36 ^(SecTransformAttributeRef attribute
, CFTypeRef value
)
40 return (CFTypeRef
) NULL
;
43 CFArrayRef array
= (CFArrayRef
) value
;
44 CFTypeRef item
= (CFTypeRef
) CFArrayGetValueAtIndex(array
, 0);
46 // Ensure that indeed we do have a CFReadStreamRef
47 if (NULL
== item
|| CFReadStreamGetTypeID() != CFGetTypeID(item
))
49 return (CFTypeRef
) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "The input attribute item was nil or not a read stream");
52 // This now is a safe cast
53 CFReadStreamRef input
= (CFReadStreamRef
)item
;
55 // Get the state of the stream
56 CFStreamStatus streamStatus
= CFReadStreamGetStatus(input
);
59 case kCFStreamStatusNotOpen
:
61 if (!CFReadStreamOpen(input
))
63 // We didn't open properly. Error out
64 return (CFTypeRef
) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "An error occurred while opening the stream.");
69 case kCFStreamStatusError
:
71 return (CFTypeRef
) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
, "The read stream is in an error state");
75 // The assumption is that the stream is ready to go as is.
79 // allocate the read buffer on the heap
80 u_int8_t
* buffer
= (u_int8_t
*) malloc(blockSize
);
84 bytesRead
= CFReadStreamRead(input
, buffer
, blockSize
);
87 // make data from what was read
88 CFDataRef value
= CFDataCreate(NULL
, buffer
, bytesRead
);
90 // send it down the chain
91 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, value
);
96 bytesRead
= CFReadStreamRead(input
, buffer
, blockSize
);
101 SecTransformCustomSetAttribute(ref
, kSecTransformOutputAttributeName
, kSecTransformMetaAttributeValue
, (CFTypeRef
) NULL
);
103 return (CFTypeRef
) NULL
;
109 return Block_copy(instanceBlock
);
114 SecTransformRef
SecTransformCreateReadTransformWithReadStream(CFReadStreamRef inputStream
)
116 static dispatch_once_t once
= 0;
118 __block
bool ok
= true;
119 __block CFErrorRef result
= NULL
;
123 ok
= SecTransformRegister(kStreamTransformName
, &StreamTransformImplementation
, &result
);
133 SecTransformRef transform
= SecTransformCreate(kStreamTransformName
, &result
);
134 if (NULL
!= transform
)
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
);
142 // add the input to the transform
143 SecTransformSetAttribute(transform
, kSecTransformInputAttributeName
, arrayRef
, &result
);
145 CFReleaseNull(arrayRef
);