]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_transform/lib/SecTransformReadTransform.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_transform / lib / SecTransformReadTransform.cpp
diff --git a/Security/libsecurity_transform/lib/SecTransformReadTransform.cpp b/Security/libsecurity_transform/lib/SecTransformReadTransform.cpp
new file mode 100644 (file)
index 0000000..5d998cf
--- /dev/null
@@ -0,0 +1,151 @@
+#include "SecTransformReadTransform.h"
+#include "SecCustomTransform.h"
+#include "Utilities.h"
+
+static CFStringRef kStreamTransformName = CFSTR("SecReadStreamTransform");
+static CFStringRef kStreamMaxSize = CFSTR("MAX_READSIZE");
+
+static SecTransformInstanceBlock StreamTransformImplementation(CFStringRef name,
+                                                                                                                          SecTransformRef newTransform,
+                                                                                                                          SecTransformImplementationRef ref)
+{
+       SecTransformInstanceBlock instanceBlock =
+       ^{
+               CFErrorRef result = NULL;
+               
+               if (NULL == name || NULL == newTransform)
+               {
+               }
+               
+               // define the storage for our block
+               __block CFIndex blockSize = 4096;  // make a default block size
+               
+               // it's not necessary to set the input stream size
+               SecTransformCustomSetAttribute(ref, kStreamMaxSize, kSecTransformMetaAttributeRequired, kCFBooleanFalse);
+               
+               // define the action if we change the max read size
+               SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kStreamMaxSize,
+               ^(SecTransformAttributeRef attribute, CFTypeRef value)
+               {
+                       CFNumberGetValue((CFNumberRef) value, kCFNumberCFIndexType, &blockSize);
+                       return value;
+               });
+               
+               // define for our input action
+               SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecTransformInputAttributeName,
+               ^(SecTransformAttributeRef attribute, CFTypeRef value)
+               {
+                       if (value == NULL)
+                       {
+                               return (CFTypeRef) NULL;
+                       }
+                       
+                       CFArrayRef array = (CFArrayRef) value;
+                       CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(array, 0);
+
+                       // Ensure that indeed we do have a CFReadStreamRef
+                       if (NULL == item || CFReadStreamGetTypeID() != CFGetTypeID(item))
+                       {
+                               return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "The input attribute item was nil or not a read stream");
+                       }
+                       
+                       // This now is a safe cast
+                       CFReadStreamRef input = (CFReadStreamRef)item;
+
+                       // Get the state of the stream
+                       CFStreamStatus streamStatus = CFReadStreamGetStatus(input);
+                       switch (streamStatus)
+                       {
+                               case kCFStreamStatusNotOpen:
+                               {
+                                       if (!CFReadStreamOpen(input))
+                                       {
+                                               // We didn't open properly.  Error out
+                                               return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "An error occurred while opening the stream.");
+                                       }
+                               }
+                               break;
+
+                               case kCFStreamStatusError:
+                               {
+                                       return (CFTypeRef) CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "The read stream is in an error state");
+                               }
+                               break;
+
+                               default:
+                                       // The assumption is that the stream is ready to go as is.
+                               break;
+                       }               
+                       
+                       // allocate the read buffer on the heap
+                       u_int8_t* buffer = (u_int8_t*) malloc(blockSize);
+                       
+                       CFIndex bytesRead;
+                       
+                       bytesRead = CFReadStreamRead(input, buffer, blockSize);
+                       while (bytesRead > 0)
+                       {
+                               // make data from what was read
+                               CFDataRef value = CFDataCreate(NULL, buffer, bytesRead);
+                               
+                               // send it down the chain
+                               SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value);
+                               
+                               // cleanup
+                               CFRelease(value);
+                               
+                               bytesRead = CFReadStreamRead(input, buffer, blockSize);
+                       }
+                       
+                       free(buffer);
+                       
+                       SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef) NULL);
+                       
+                       return (CFTypeRef) NULL;
+               });
+               
+               return result;
+       };
+       
+       return Block_copy(instanceBlock);
+}
+
+
+
+SecTransformRef SecTransformCreateReadTransformWithReadStream(CFReadStreamRef inputStream)
+{
+       static dispatch_once_t once = 0;
+       
+       __block bool ok = true;
+       __block CFErrorRef result = NULL;
+       
+       dispatch_once(&once,
+       ^{
+               ok = SecTransformRegister(kStreamTransformName, &StreamTransformImplementation, &result);
+       });
+       
+       if (!ok)
+       {
+               return result;
+       }
+       else
+       {
+       
+               SecTransformRef transform = SecTransformCreate(kStreamTransformName, &result);
+               if (NULL != transform)
+               {
+                       // if we add the read stream directly to the transform the internal source stream
+                       // will take over. This is bad.  Instead, we wrap this in a CFArray so that we can
+                       // pass through undetected
+                       CFTypeRef arrayData[] = {inputStream};
+                       CFArrayRef arrayRef = CFArrayCreate(NULL, arrayData, 1, &kCFTypeArrayCallBacks);
+
+                       // add the input to the transform
+                       SecTransformSetAttribute(transform, kSecTransformInputAttributeName, arrayRef, &result);
+                       
+                       CFRelease(arrayRef);
+               }
+               
+               return transform;
+       }
+}