]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_transform/lib/Transform.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_transform / lib / Transform.cpp
diff --git a/Security/libsecurity_transform/lib/Transform.cpp b/Security/libsecurity_transform/lib/Transform.cpp
deleted file mode 100644 (file)
index 20db57f..0000000
+++ /dev/null
@@ -1,1834 +0,0 @@
-#include <CoreServices/CoreServices.h>
-#include <Block.h>
-#include <libkern/OSAtomic.h>
-#include <syslog.h>
-#include "Transform.h"
-#include "StreamSource.h"
-#include "SingleShotSource.h"
-#include "Monitor.h"
-#include "Utilities.h"
-#include "c++utils.h"
-#include "misc.h"
-#include "SecTransformInternal.h"
-#include "GroupTransform.h"
-#include "GroupTransform.h"
-#include <pthread.h>
-
-static const int kMaxPendingTransactions = 20;
-
-static CFTypeID internalID = _kCFRuntimeNotATypeID;
-
-// Use &dispatchQueueToTransformKey as a key to dispatch_get_specific to map from
-// a transforms master, activation, or any attribute queue to the Transform*
-static unsigned char dispatchQueueToTransformKey;
-
-static char RandomChar()
-{
-       return arc4random() % 26 + 'A'; // good enough
-}
-
-
-static CFStringRef ah_set_describe(const void *v) {
-       transform_attribute *ta = ah2ta(static_cast<SecTransformAttributeRef>(const_cast<void*>(v)));
-       return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@=%@ (conn: %@)"), ta->transform->GetName(), ta->name, ta->value ? ta->value : CFSTR("NULL"), ta->connections ? static_cast<CFTypeRef>(ta->connections) : static_cast<CFTypeRef>(CFSTR("NONE")));
-}
-
-static CFStringRef AttributeHandleFormat(CFTypeRef ah, CFDictionaryRef dict) {
-       transform_attribute *ta = ah2ta(ah);
-       return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), ta->transform->GetName(), ta->name);
-}
-
-static CFStringRef AttributeHandleDebugFormat(CFTypeRef ah) {
-       transform_attribute *ta = ah2ta(ah);
-       return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@ (%p)"), ta->transform->GetName(), ta->name, ta);
-}
-
-static void AttributeHandleFinalize(CFTypeRef ah)
-{
-       transform_attribute *ta = ah2ta(ah);
-       if (!ta)
-       {
-               return;
-       }
-
-       if (ta->transform)
-       {
-               // When we release AH's we clear out the transform pointer, so if we get here with transform!=NULL somebody 
-               // has released an AH we are still using and we will crash very very soon (in our code) if we don't abort here
-               syslog(LOG_ERR, "over release of SecTransformAttributeRef at %p\n", ah);
-               abort();
-       }
-       
-       if (ta->value)
-       {
-               CFRelease(ta->value);
-       }
-       
-       // ta->q already released
-       
-       if (ta->connections)
-       {
-               CFRelease(ta->connections);
-       }
-       
-       if (ta->semaphore)
-       {
-               dispatch_release(ta->semaphore);
-       }
-       
-       if (ta->attribute_changed_block)
-       {
-               Block_release(ta->attribute_changed_block);
-       }
-       
-       if (ta->attribute_validate_block)
-       {
-               Block_release(ta->attribute_validate_block);
-       }
-       
-       free(ta);
-}
-
-
-
-static CFHashCode ah_set_hash(const void *v) {
-       return CFHash(ah2ta(static_cast<SecTransformAttributeRef>(const_cast<void*>(v)))->name);
-}
-
-static Boolean ah_set_equal(const void *v1, const void *v2) {
-       return CFEqual(ah2ta(static_cast<SecTransformAttributeRef>(const_cast<void*>(v1)))->name, ah2ta(static_cast<SecTransformAttributeRef>(const_cast<void*>(v2)))->name);
-}
-
-CFTypeID transform_attribute::cftype;
-
-SecTransformAttributeRef Transform::makeAH(transform_attribute *ta) {
-       if (ta) {
-               SecTransformAttributeRef ah = _CFRuntimeCreateInstance(NULL, transform_attribute::cftype, sizeof(struct transform_attribute*), NULL);
-               if (!ah) {
-                       return NULL;
-               }
-               *(struct transform_attribute **)(1 + (CFRuntimeBase*)ah) = ta;
-               return ah;
-       } else {
-               return NULL;
-       }
-}
-
-static pthread_key_t ah_search_key_slot;
-
-static void destroy_ah_search_key(void *ah) {
-       CFRelease(ah);
-       pthread_setspecific(ah_search_key_slot, NULL);
-}
-
-
-
-SecTransformAttributeRef Transform::getAH(SecTransformStringOrAttributeRef attrib, bool create_ok, bool create_underscore_ok)
-{
-       if (CFGetTypeID(attrib) == transform_attribute::cftype)
-       {
-               return (SecTransformAttributeRef)attrib;
-       }
-       
-       CFStringRef label = (CFStringRef)attrib;
-       static dispatch_once_t once = 0;
-       const char *name = (const char *)"SecTransformAttributeRef";
-       static CFRuntimeClass ahclass;
-       static CFSetCallBacks tasetcb;
-       
-       dispatch_once(&once, ^{
-               ahclass.className = name;
-               ahclass.copyFormattingDesc = AttributeHandleFormat;
-               ahclass.copyDebugDesc = AttributeHandleDebugFormat;
-               ahclass.finalize = AttributeHandleFinalize;
-               transform_attribute::cftype = _CFRuntimeRegisterClass(&ahclass);
-               if (transform_attribute::cftype == _kCFRuntimeNotATypeID) {
-                       abort();
-               }
-               
-               tasetcb.equal = ah_set_equal;
-               tasetcb.hash = ah_set_hash;
-               tasetcb.copyDescription = ah_set_describe;
-               
-               pthread_key_create(&ah_search_key_slot, destroy_ah_search_key);
-       });
-       
-       SecTransformAttributeRef search_for = pthread_getspecific(ah_search_key_slot);
-       if (!search_for)
-       {
-               search_for = makeAH((transform_attribute*)malloc(sizeof(transform_attribute)));
-               if (!search_for)
-               {
-                       return NULL;
-               }
-               
-               bzero(ah2ta(search_for), sizeof(transform_attribute));
-               pthread_setspecific(ah_search_key_slot, search_for);
-       }
-       
-       if (!mAttributes)
-       {
-               mAttributes = CFSetCreateMutable(NULL, 0, &tasetcb);
-       }
-       
-       ah2ta(search_for)->name = label;
-       SecTransformAttributeRef ah = static_cast<SecTransformAttributeRef>(const_cast<void*>(CFSetGetValue(mAttributes, search_for)));
-       if (ah == NULL && create_ok)
-       {
-               if (CFStringGetLength(label) && L'_' == CFStringGetCharacterAtIndex(label, 0) && !create_underscore_ok)
-               {
-                       // Attributes with a leading _ belong to the Transform system only, not to random 3rd party transforms.
-                       return NULL;
-               }
-               
-               transform_attribute *ta = static_cast<transform_attribute *>(malloc(sizeof(transform_attribute)));
-               ah = makeAH(ta);
-               if (!ah)
-               {
-                       return NULL;
-               }
-               
-               ta->name = CFStringCreateCopy(NULL, label);
-               if (!ta->name)
-               {
-                       free(ta);
-                       return NULL;
-               }
-               CFIndex cnt = CFSetGetCount(mAttributes);
-               CFSetAddValue(mAttributes, ah);
-               if (CFSetGetCount(mAttributes) != cnt+1)
-               {
-                       CFRelease(ta->name);
-                       free(ta);
-                       return NULL;
-               }
-               
-               CFStringRef qname = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s/%@"), dispatch_queue_get_label(this->mDispatchQueue), label);
-               CFIndex used, sz = 1+CFStringGetMaximumSizeForEncoding(CFStringGetLength(qname), kCFStringEncodingUTF8);
-               UInt8 *qnbuf = (UInt8 *)alloca(sz);
-               CFStringGetBytes(qname, CFRangeMake(0, CFStringGetLength(qname)), kCFStringEncodingUTF8, '?', FALSE, qnbuf, sz, &used);
-               qnbuf[used] = '\0';
-               ta->q = dispatch_queue_create((char*)qnbuf, NULL);
-               CFRelease(qname);
-               ta->semaphore = dispatch_semaphore_create(kMaxPendingTransactions);
-
-               
-               ta->pushback_state = transform_attribute::pb_empty;
-               ta->pushback_value = NULL;
-               ta->value = NULL;
-               ta->connections = NULL;
-               ta->transform = this;
-
-               dispatch_set_target_queue(ta->q, mDispatchQueue);
-               ta->required = 0;
-               ta->requires_outbound_connection = 0;
-               ta->deferred = 0;
-               ta->stream = 0;
-               ta->ignore_while_externalizing = 0;
-               ta->has_incoming_connection = 0;
-               ta->direct_error_handling = 0;
-               ta->allow_external_sets = 0;
-               ta->has_been_deferred = 0;
-               ta->attribute_changed_block = NULL;
-               ta->attribute_validate_block = NULL;
-       }
-
-       return ah;
-}
-
-transform_attribute *Transform::getTA(SecTransformStringOrAttributeRef attrib, bool create_ok)
-{
-       SecTransformAttributeRef ah = getAH(attrib, create_ok);
-       if (ah)
-       {
-               return ah2ta(ah);
-       }
-       else
-       {
-               return NULL;
-       }
-}      
-
-
-
-void Transform::TAGetAll(transform_attribute **attributes) {
-       CFSetGetValues(mAttributes, (const void**)attributes);
-       CFIndex i, n = CFSetGetCount(mAttributes);
-       for(i = 0; i < n; ++i) {
-               attributes[i] = ah2ta(attributes[i]);
-       }
-}
-
-
-
-bool Transform::HasNoOutboundConnections()
-{
-       // make an array big enough to hold all of the attributes
-       CFIndex numAttributes = CFSetGetCount(mAttributes);
-       transform_attribute* attributes[numAttributes];
-       
-       TAGetAll(attributes);
-       
-       // check all of the attributes
-       CFIndex i;
-       for (i = 0; i < numAttributes; ++i)
-       {
-               if (attributes[i]->connections && CFArrayGetCount(attributes[i]->connections) != 0)
-               {
-                       return false;
-               }
-       }
-       
-       return true;
-}
-
-
-
-bool Transform::HasNoInboundConnections()
-{
-       // make an array big enough to hold all of the attributes
-       CFIndex numAttributes = CFSetGetCount(mAttributes);
-       transform_attribute* attributes[numAttributes];
-       
-       TAGetAll(attributes);
-       
-       // check all of the attributes
-       CFIndex i;
-       for (i = 0; i < numAttributes; ++i)
-       {
-               if (attributes[i]->has_incoming_connection)
-               {
-                       return false;
-               }
-       }
-       
-       return true;
-}
-
-
-
-CFIndex Transform::GetAttributeCount()
-{
-       return CFSetGetCount(mAttributes);
-}
-
-Transform::Transform(CFStringRef transformType, CFStringRef CFobjectType) :
-       CoreFoundationObject(CFobjectType), 
-       mIsActive(false),
-       mIsFinalizing(false),
-       mAlwaysSelfNotify(false), 
-       mGroup(NULL), 
-       mAbortError(NULL),
-       mTypeName(CFStringCreateCopy(NULL, transformType))
-{
-       mAttributes = NULL;
-       mPushedback = NULL;
-       mProcessingPushbacks = FALSE;
-       
-       if (internalID == _kCFRuntimeNotATypeID) {
-               (void)SecTransformNoData();
-               internalID = CoreFoundationObject::FindObjectType(gInternalCFObjectName);
-       }
-       
-       // create a name for the transform
-       char rname[10];
-       unsigned i;
-       for (i = 0; i < sizeof(rname) - 1; ++i)
-       {
-               rname[i] = RandomChar();
-       }
-       
-       rname[i] = 0;
-       
-       char *tname = const_cast<char*>(CFStringGetCStringPtr(transformType, kCFStringEncodingUTF8));
-       if (!tname) {
-               CFIndex sz = 1+CFStringGetMaximumSizeForEncoding(CFStringGetLength(transformType), kCFStringEncodingUTF8);
-               tname = static_cast<typeof(tname)>(alloca(sz));
-               if (tname) {
-                       CFStringGetCString(transformType, tname, sz, kCFStringEncodingUTF8);
-               } else {
-                       tname = const_cast<char*>("-");
-               }
-       }
-       
-       char* name;
-       asprintf(&name, "%s-%s", rname, tname);
-
-       char *dqName;
-       asprintf(&dqName, "%s-%s", rname, tname);
-       
-       char *aqName;
-       asprintf(&aqName, "aq-%s-%s", rname, tname);
-
-       mDispatchQueue = dispatch_queue_create(dqName, NULL);
-    dispatch_queue_set_specific(mDispatchQueue, &dispatchQueueToTransformKey, this, NULL);
-       // mActivationQueue's job in life is to be suspended until just after this transform is made active.
-       // It's primary use is when a value flowing across a connection isn't sure if the target transform is active yet.
-       mActivationQueue = dispatch_queue_create(aqName, NULL);
-       dispatch_set_target_queue(mActivationQueue, mDispatchQueue);
-       dispatch_suspend(mActivationQueue);
-       mActivationPending = dispatch_group_create();
-       
-       // set up points for ABORT, DEBUG, INPUT, and OUTPUT
-       AbortAH = getAH(kSecTransformAbortAttributeName, true);
-       transform_attribute *ta = ah2ta(AbortAH);
-       ta->ignore_while_externalizing = 1;
-       CFStringRef attributeName = CFStringCreateWithCStringNoCopy(NULL, name, 0, kCFAllocatorMalloc);
-       SetAttributeNoCallback(kSecTransformTransformName, attributeName);
-       CFRelease(attributeName);
-       
-       free(dqName);
-       free(aqName);
-
-       DebugAH = getAH(kSecTransformDebugAttributeName, true);
-       ah2ta(DebugAH)->ignore_while_externalizing = 1;
-       
-       ta = getTA(kSecTransformInputAttributeName, true);
-       ta->required = ta->deferred = ta->stream = 1;
-       ta->allow_external_sets = 0;
-       ta->value = NULL;
-       ta->has_been_deferred = 0;
-       ta = getTA(kSecTransformOutputAttributeName, true);
-       ta->requires_outbound_connection = ta->stream = 1;
-}
-
-static void run_and_release_finalizer(void *finalizer_block)
-{
-       ((dispatch_block_t)finalizer_block)();
-       Block_release(finalizer_block);
-}
-
-static void set_dispatch_finalizer(dispatch_object_t object, dispatch_block_t finalizer)
-{
-       finalizer = Block_copy(finalizer);
-       dispatch_set_context(object, finalizer);
-       dispatch_set_finalizer_f(object, run_and_release_finalizer);
-}
-
-void Transform::FinalizePhase2()
-{
-       delete this;
-}
-
-void Transform::FinalizeForClang()
-{
-       CFIndex numAttributes = CFSetGetCount(mAttributes);
-       SecTransformAttributeRef handles[numAttributes];
-       CFSetGetValues(mAttributes, (const void**)&handles);
-       
-       for(CFIndex i = 0; i < numAttributes; ++i) {
-               SecTransformAttributeRef ah = handles[i];
-               transform_attribute *ta = ah2ta(ah);
-               
-               set_dispatch_finalizer(ta->q, ^{
-                       // NOTE: not done until all pending use of the attribute queue has ended AND retain count is zero
-                       ta->transform = NULL;
-                       CFRelease(ah);
-               });
-               // If there is a pending pushback the attribute queue will be suspended, and needs a kick before it can be destructed.
-               if (__sync_bool_compare_and_swap(&ta->pushback_state, transform_attribute::pb_value, transform_attribute::pb_discard)) {
-                       dispatch_resume(ta->q);
-               }
-               dispatch_release(ta->q);
-       }
-       
-       // We might be finalizing a transform as it is being activated, make sure that is complete before we do the rest
-    dispatch_group_notify(mActivationPending, mDispatchQueue, ^{
-        if (mActivationQueue != NULL) {
-            // This transform has not been activated (and does not have a activation pending), so we need to resume to activation queue before we can release it
-            dispatch_resume(mActivationQueue);
-            dispatch_release(mActivationQueue);
-        }
-        
-        set_dispatch_finalizer(mDispatchQueue, ^{
-            // NOTE: delayed until all pending work items on the transform's queue are complete, and all of the attribute queues have been finalized, and the retain count is zero
-            FinalizePhase2();
-        });
-        dispatch_release(mDispatchQueue);
-    });
-}
-
-void Transform::Finalize()
-{
-       // When _all_ transforms in the group have been marked as finalizing we can tear down our own context without anyone else in the group sending us values
-       // (NOTE: moved block into member function as clang hits an internal error and declines to compile)
-       dispatch_block_t continue_finalization = ^{ this->FinalizeForClang(); };
-       dispatch_block_t mark_as_finalizing = ^{ this->mIsFinalizing = true; };
-    
-       // Mark the transform as "finalizing" so it knows not to propagate values across connections
-    if (this == dispatch_get_specific(&dispatchQueueToTransformKey)) {
-        mark_as_finalizing();
-    } else {
-        dispatch_sync(mDispatchQueue, mark_as_finalizing);
-    }
-       
-       if (mGroup) {
-        (void)transforms_assume(mGroup->mIsFinalizing);  // under retain?
-        mGroup->AddAllChildrenFinalizedCallback(mDispatchQueue, continue_finalization);
-        mGroup->ChildStartedFinalization(this);
-       } else {
-               // a "bare" transform (normally itself a group) still needs to be deconstructed
-               dispatch_async(mDispatchQueue, continue_finalization);
-       }                       
-}
-
-Transform::~Transform()
-{
-       CFRelease(mAttributes);
-       if (mAbortError) {
-               CFRelease(mAbortError);
-        mAbortError = NULL;
-       }
-       
-       // See if we can catch anything using us after our death
-       mDispatchQueue = (dispatch_queue_t)0xdeadbeef;
-       
-       CFRelease(mTypeName);
-       
-       if (NULL != mPushedback)
-       {
-               CFRelease(mPushedback);
-       }
-       dispatch_release(mActivationPending);
-}
-
-CFStringRef Transform::GetName() {
-       return (CFStringRef)GetAttribute(kSecTransformTransformName);
-}
-
-CFTypeID Transform::GetCFTypeID()
-{
-       return CoreFoundationObject::FindObjectType(CFSTR("SecTransform"));
-}
-
-std::string Transform::DebugDescription()
-{
-       return CoreFoundationObject::DebugDescription() + "|SecTransform|" + StringFromCFString(this->GetName());
-}
-
-CFErrorRef Transform::SendMetaAttribute(SecTransformStringOrAttributeRef key, SecTransformMetaAttributeType type, CFTypeRef value)
-{
-       SecTransformAttributeRef ah = getAH(key, true);
-       transform_attribute *ta = ah2ta(ah);
-       switch (type)
-       {
-               case kSecTransformMetaAttributeRequired:
-                       ta->required = CFBooleanGetValue((CFBooleanRef)value) ? 1 : 0;
-                       break;
-                       
-               case kSecTransformMetaAttributeRequiresOutboundConnection:
-                       ta->requires_outbound_connection = CFBooleanGetValue((CFBooleanRef)value) ? 1 : 0;
-                       break;
-                       
-               case kSecTransformMetaAttributeDeferred:
-                       ta->deferred = CFBooleanGetValue((CFBooleanRef)value) ? 1 : 0;
-                       break;
-                       
-               case kSecTransformMetaAttributeStream:
-                       ta->stream = CFBooleanGetValue((CFBooleanRef)value) ? 1 : 0;
-                       break;
-                       
-               case kSecTransformMetaAttributeHasOutboundConnections:
-                       return CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "Can't set kSecTransformMetaAttributeHasOutboundConnections for %@ (or any other attribute)", ah);
-                       
-               case kSecTransformMetaAttributeHasInboundConnection:
-                       return CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "Can't set kSecTransformMetaAttributeHasInboundConnection for %@ (or any other attribute)", ah);
-                       
-               case kSecTransformMetaAttributeCanCycle:
-                       return CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "kSecTransformMetaAttributeCanCycle not yet supported (%@)", ah);
-                       
-               case kSecTransformMetaAttributeExternalize:
-                       ta->ignore_while_externalizing = CFBooleanGetValue((CFBooleanRef)value) ? 0 : 1;
-                       break;
-                       
-               case kSecTransformMetaAttributeValue:
-                       return SetAttributeNoCallback(ah, value);
-                       
-               case kSecTransformMetaAttributeRef:
-                       return CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "Can't set kSecTransformMetaAttributeRef for %@ (or any other attribute)", ah);
-                       
-               case kSecTransformMetaAttributeName:
-                       return CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "Can't set kSecTransformMetaAttributeName for %@ (or any other attribute)", ah);
-                       
-               default:
-                       return CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "Can't set unknown meta attribute #%d to %@ on %@", type, value, key);
-       }
-       
-       return NULL;
-}
-
-CFTypeRef Transform::GetMetaAttribute(SecTransformStringOrAttributeRef key, SecTransformMetaAttributeType type) {
-       SecTransformAttributeRef ah = getAH(key, true);
-       transform_attribute *ta = ah2ta(ah);
-       switch (type) {
-               case kSecTransformMetaAttributeRequired:
-                       return (CFTypeRef)(ta->required ? kCFBooleanTrue : kCFBooleanFalse);
-               case kSecTransformMetaAttributeRequiresOutboundConnection:
-                       return (CFTypeRef)(ta->requires_outbound_connection ? kCFBooleanTrue : kCFBooleanFalse);
-               case kSecTransformMetaAttributeDeferred:
-                       return (CFTypeRef)(ta->deferred ? kCFBooleanTrue : kCFBooleanFalse);
-               case kSecTransformMetaAttributeStream:
-                       return (CFTypeRef)(ta->stream ? kCFBooleanTrue : kCFBooleanFalse);
-               case kSecTransformMetaAttributeHasOutboundConnections:
-                       return (CFTypeRef)((ta->connections && CFArrayGetCount(ta->connections)) ? kCFBooleanTrue : kCFBooleanFalse);
-               case kSecTransformMetaAttributeHasInboundConnection:
-                       return (CFTypeRef)(ta->has_incoming_connection ? kCFBooleanTrue : kCFBooleanFalse);
-               case kSecTransformMetaAttributeCanCycle:
-                       return (CFTypeRef)kCFBooleanFalse;
-               case kSecTransformMetaAttributeExternalize:
-                       return (CFTypeRef)(ta->ignore_while_externalizing ? kCFBooleanFalse : kCFBooleanTrue);
-               case kSecTransformMetaAttributeRef:
-                       return ah;
-               case kSecTransformMetaAttributeValue:
-                       return ta->value;
-               case kSecTransformMetaAttributeName:
-                       return ta->name;
-               default:
-                       return CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "Can't get unknown meta attribute #%d from %@", type, key);
-                       break;
-       }
-       
-       return NULL;
-}
-
-
-
-CFErrorRef Transform::RefactorErrorToIncludeAbortingTransform(CFErrorRef sourceError)
-{
-       // pull apart the error
-       CFIndex code = CFErrorGetCode(sourceError);
-       CFStringRef domain = CFErrorGetDomain(sourceError);
-       CFDictionaryRef oldUserInfo = CFErrorCopyUserInfo(sourceError);
-       CFMutableDictionaryRef userInfo = CFDictionaryCreateMutableCopy(NULL, 0, oldUserInfo);
-       CFRelease(oldUserInfo);
-       
-       // add the new key and value to the dictionary
-       CFDictionaryAddValue(userInfo, kSecTransformAbortOriginatorKey, GetCFObject());
-       
-       // make a new CFError
-       CFErrorRef newError = CFErrorCreate(NULL, domain, code, userInfo);
-       CFRelease(userInfo);
-       return newError;
-}
-
-// NOTE: If called prior to execution will schedule a later call to AbortAllTransforms
-void Transform::AbortJustThisTransform(CFErrorRef abortErr)
-{
-    (void)transforms_assume(abortErr);
-    (void)transforms_assume(dispatch_get_specific(&dispatchQueueToTransformKey) == this);
-    
-    Boolean wasActive = mIsActive;
-
-    if (OSAtomicCompareAndSwapPtr(NULL, (void *)abortErr, (void**)&mAbortError)) {
-               // send an abort message to the attribute so that it can shut down
-               // note that this bypasses the normal processes.  The message sent is a notification
-               // that things aren't working well any more, the transform cannot make any other assumption.
-
-        // mAbortError is released in the destructor which is triggered (in part)
-        // by the dispatch queue finalizer so we don't need a retain/release of
-        // abortErr for the abortAction block, but we do need to retain it
-        // here to match with the release by the destructor.
-        CFRetain(abortErr);
-        
-               dispatch_block_t abortAction = ^{
-            // This actually makes the abort happen, it needs to run on the transform's queue while the
-            // transform is executing.
-            
-            if (!wasActive) {
-                // When this abort was first processed we were not executing, so
-                // additional transforms may have been added to our group (indeed,
-                // we may not have had a group at all), so we need to let everyone
-                // know about the problem.   This will end up letting ourself (and
-                // maybe some others) know an additional time, but the CompareAndSwap
-                // prevents that from being an issue.
-                this->AbortAllTransforms(abortErr);
-            }
-            
-            SecTransformAttributeRef GCC_BUG_WORKAROUND inputAttributeHandle = getAH(kSecTransformInputAttributeName, false);
-            // Calling AttributeChanged directly lets an error "skip ahead" of the input queue,
-            // and even execute if the input queue is suspended pending pushback retries.
-            AttributeChanged(inputAttributeHandle, abortErr);
-            try_pushbacks();
-        };
-        
-        if (mIsActive) {
-            // This transform is running, so we use the normal queue (which we are
-            // already executing on)
-            abortAction();
-        } else {
-            // This transform hasn't run yet, do the work on the activation queue
-            // so it happens as soon as the transforms starts executing.
-            dispatch_async(mActivationQueue, abortAction);
-        }
-       } else {
-        Debug("%@ set to %@ while processing ABORT=%@, this extra set will be ignored", AbortAH, abortErr, mAbortError);
-    }
-}
-
-// abort all transforms in the root group & below
-void Transform::AbortAllTransforms(CFTypeRef err)
-{
-       Debug("%@ set to %@, aborting\n", AbortAH, err);
-       CFErrorRef error = NULL;
-       
-       CFTypeRef replacementErr = NULL;
-       
-       if (CFGetTypeID(err) != CFErrorGetTypeID())
-       {
-               replacementErr = err = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "ABORT set to a %@ (%@) not a %@", CFCopyTypeIDDescription(CFGetTypeID(err)), err, CFCopyTypeIDDescription(CFErrorGetTypeID()));
-       }
-       
-       error = RefactorErrorToIncludeAbortingTransform((CFErrorRef)err);
-
-       if (replacementErr)
-       {
-               CFRelease(replacementErr);
-       }
-       
-    GroupTransform *root = GetRootGroup();
-       if (root)
-       {
-               // tell everyone in the (root) group to "AbortJustThisTransform"
-        dispatch_group_t all_aborted = dispatch_group_create();
-        root->ForAllNodesAsync(false, all_aborted, ^(Transform* t){
-            t->AbortJustThisTransform(error);
-        });
-        dispatch_group_notify(all_aborted, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) {
-            CFRelease(error);
-            dispatch_release(all_aborted);
-        });
-       }
-       else
-       {
-               // We are everyone so we AbortJustThisTransform "directly"
-        // NOTE: this can only happen prior to execution (execution always happens in a group)
-        (void)transforms_assume_zero(mIsActive);
-               this->AbortJustThisTransform(error);
-       }
-}
-
-
-
-CFErrorRef Transform::Disconnect(Transform* destinationTransform, CFStringRef myKey, CFStringRef hisKey)
-{
-       //CFTypeRef thisTransform = (SecTransformRef) GetCFObject();
-       
-       // find this transform in the backlinks for the destination
-       CFIndex i;
-
-       // now remove the link in the transform dictionary
-       transform_attribute *src = getTA(myKey, true);
-       SecTransformAttributeRef dst = destinationTransform->getAH(hisKey);
-       
-       if (src->connections == NULL)
-       {
-               return CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "Cannot find transform in destination.");
-       }
-       
-       CFIndex numConnections = CFArrayGetCount(src->connections);
-       for (i = 0; i < numConnections; ++i)
-       {
-               if (CFArrayGetValueAtIndex(src->connections, i) == dst)
-               {
-                       CFArrayRemoveValueAtIndex(src->connections, i);
-                       numConnections = CFArrayGetCount(src->connections);
-               }
-               
-               // clear the has_incoming_connection bit in the destination.  We can do this because inputs can have only one connection.
-               transform_attribute* dstTA = ah2ta(dst);
-               dstTA->has_incoming_connection = false;
-       }
-       
-       if (HasNoInboundConnections() && HasNoOutboundConnections())
-       {
-               // we have been orphaned, just remove us
-               mGroup->RemoveMemberFromGroup(GetCFObject());
-               mGroup = NULL;
-       }
-       
-       return NULL;
-}
-
-
-
-CFErrorRef Transform::Connect(GroupTransform *group, Transform* destinationTransform, CFStringRef destAttr, CFStringRef srcAttr)
-{
-       if (group == NULL) 
-       {
-               CFErrorRef err = CreateSecTransformErrorRef(kSecTransformErrorInvalidConnection, "Can not make connections without a specific group (do not call with group = NULL)");
-               return err;
-       }
-    
-    GroupTransform *newSourceGroup = mGroup;
-    GroupTransform *newDestinationGroup = destinationTransform->mGroup;
-       
-       if (mGroup == NULL || mGroup == this) 
-       {
-               newSourceGroup = group;
-       }
-       
-       if (destinationTransform->mGroup == NULL || destinationTransform->mGroup == destinationTransform) 
-       {
-               newDestinationGroup = group;
-       }
-       
-       if (newSourceGroup != newDestinationGroup && mGroup) 
-       {
-        CFErrorRef err = CreateSecTransformErrorRef(kSecTransformErrorInvalidConnection, "Can not make connections between transforms in different groups (%@ is in %@, %@ is in %@)", GetName(), newSourceGroup->GetName(), destinationTransform->GetName(), newDestinationGroup->GetName());
-               return err;
-       }
-    
-    if (!validConnectionPoint(srcAttr)) {
-        CFErrorRef err = CreateSecTransformErrorRef(kSecTransformErrorInvalidConnection, "Can not make a connection from non-exported attribute %@ of %@", srcAttr, this->GetName());
-        return err;
-    }
-    if (!destinationTransform->validConnectionPoint(destAttr)) {
-        CFErrorRef err = CreateSecTransformErrorRef(kSecTransformErrorInvalidConnection, "Can not make a connection to non-exported attribute %@ of %@", destAttr, destinationTransform->GetName());
-        return err;
-    }
-    
-    mGroup = newSourceGroup;
-    destinationTransform->mGroup = newDestinationGroup;
-               
-       // NOTE: this fails on OOM
-       group->AddMemberToGroup(this->GetCFObject());
-       group->AddMemberToGroup(destinationTransform->GetCFObject());
-       
-       transform_attribute *src = this->getTA(srcAttr, true);
-       SecTransformAttributeRef dst = destinationTransform->getAH(destAttr);
-       
-       if (!src->connections) 
-       {
-               src->connections = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       }
-       CFArrayAppendValue(src->connections, dst);
-       
-       ah2ta(dst)->has_incoming_connection = 1;
-       
-       return NULL;
-}
-
-
-bool Transform::validConnectionPoint(CFStringRef attributeName)
-{
-    return true;
-}
-
-// NoCallback == don't call this transform's Do function, but DO call the Do functions of connected attributes
-// SetAttribute eventually calls SetAttributeNoCallback
-CFErrorRef Transform::SetAttributeNoCallback(SecTransformStringOrAttributeRef key, CFTypeRef value)
-{
-       SecTransformAttributeRef ah = getAH(key, true);
-       if (!ah) 
-       {
-               abort();
-       }
-       transform_attribute *ta = ah2ta(ah);
-       
-       if (ah == AbortAH && value && (mIsActive || !ta->deferred))
-       {
-               AbortAllTransforms(value);
-               return CreateSecTransformErrorRef(kSecTransformErrorAbortInProgress, "Abort started");
-       }
-       
-       bool do_propagate = true;
-       
-       if (!ta->has_been_deferred)
-       {
-               bool doNotRetain = false;
-
-               if (value) 
-               {
-                       CFStringRef name = ta->name;
-                       if (CFGetTypeID(value) == CFReadStreamGetTypeID()) 
-                       {
-                               CFTypeRef src = StreamSource::Make((CFReadStreamRef) value, this, name);
-                               value = src;
-                               do_propagate = false;
-                               ta->has_been_deferred = 1;
-                               doNotRetain = true;
-                       }
-                       else if (ta->deferred && !mIsActive)
-                       {
-                               if (ta->deferred)
-                               {
-                                       Debug("%@ deferred value=%p\n", ah, value);
-                               }
-                               
-                               CFTypeRef src = SingleShotSource::Make(value, this, name);
-                               ta->has_been_deferred = 1;
-                               
-                               // the old value will be release when Transform::Do terminates
-                               
-                               value = src;
-                               do_propagate = false;
-                               doNotRetain = true;
-                       }
-                       else
-                       {
-                               ta->has_been_deferred = 0;
-                       }
-               }
-               
-               if (ta->value != value) {
-                       if (value && !doNotRetain) {
-                               CFRetain(value);
-                       }
-                       if (ta->value) {
-                               CFRelease(ta->value);
-                       }
-               }
-               
-               ta->value = value;
-       }
-       
-       // propagate the changes out to all connections
-       if (ta->connections && mIsActive && do_propagate && !(mAbortError || mIsFinalizing))
-       {
-               Debug("Propagating from %@ to %@\n", ah, ta->connections);
-               CFIndex i, numConnections = CFArrayGetCount(ta->connections);
-               for(i = 0; i < numConnections; ++i) {
-                       SecTransformAttributeRef ah = static_cast<SecTransformAttributeRef>(const_cast<void *>(CFArrayGetValueAtIndex(ta->connections, i)));
-                       Transform *tt = ah2ta(ah)->transform;
-                       if (NULL != tt)
-                       {
-                               if (tt->mIsActive)
-                               {
-                                       tt->SetAttribute(ah, value);
-                               }
-                               else
-                               {
-                                       dispatch_block_t setAttribute = ^{
-                        tt->SetAttribute(ah, value);
-                    };
-                    // Here the target queue might not be activated yet, we can't
-                    // look directly at the other transform's ActivationQueue as
-                    // it might activate (or Finalize!) as we look, so just ask
-                    // the other transform to deal with it.
-                    dispatch_async(ah2ta(ah)->q, ^(void) {
-                        // This time we are on the right queue to know this is the real deal
-                        if (tt->mIsActive) {
-                            setAttribute();
-                        } else {
-                            dispatch_async(ah2ta(ah)->transform->mActivationQueue, setAttribute);
-                        }
-                    });
-                               }
-                       }
-               }
-       }
-
-       return NULL;
-}
-
-// external sets normally fail if the transform is running
-CFErrorRef Transform::ExternalSetAttribute(CFTypeRef key, CFTypeRef value)
-{
-       if (!mIsActive)
-       {
-               return this->SetAttribute(key, value);
-       }
-       else
-       {
-               SecTransformAttributeRef ah = getAH(key, false);
-               if (ah != NULL && ah2ta(ah)->allow_external_sets)
-               {
-                       return this->SetAttribute(static_cast<CFTypeRef>(ah), value);
-               }
-               else
-               {
-                       return CreateSecTransformErrorRef(kSecTransformTransformIsExecuting, "%@ can not be set while %@ is executing", ah, this->GetName());
-               }
-       }
-}
-
-
-// queue up the setting of the key and value
-CFErrorRef Transform::SetAttribute(CFTypeRef key, CFTypeRef value)
-{
-       if (mAbortError)
-       {
-               return CreateSecTransformErrorRef(kSecTransformErrorAborted, "ABORT has been sent to the transform (%@)", mAbortError);
-       }
-       
-       // queue up the setting of the key and value
-       SecTransformAttributeRef ah;
-       if (CFGetTypeID(key) == transform_attribute::cftype) 
-       {
-               ah = key;
-       }
-       else if (CFGetTypeID(key) == CFStringGetTypeID())
-       {
-               ah = getAH(static_cast<CFStringRef>(key));
-               if (!ah)
-               {
-                       return CreateSecTransformErrorRef(kSecTransformErrorUnsupportedAttribute, "Can't set attribute %@ in transform %@", key, GetName());
-               }
-       }
-       else
-       {
-               return CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "Transform::SetAttribute called with %@, requires a string or an AttributeHandle", key);
-       }
-       
-       // Do this after the error check above so we don't leak
-       if (value != NULL)
-       {
-               CFRetain(value); // if we use dispatch_async we need to own the value (the matching release is in the set block)
-       }
-
-       
-       transform_attribute *ta = ah2ta(ah);
-
-       dispatch_block_t set = ^{
-               Do(ah, value);
-
-               dispatch_semaphore_signal(ta->semaphore);
-
-               if (value != NULL)
-               {
-                       CFRelease(value);
-               }
-       };
-       
-       
-       // when the transform is active, set attributes asynchronously.  Otherwise, we are doing
-       // initialization and must wait for the operation to complete.
-       if (mIsActive)
-       {
-               dispatch_async(ta->q, set);
-       }
-       else
-       {
-               dispatch_sync(ta->q, set);
-       }
-       if (dispatch_semaphore_wait(ta->semaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC))) {
-               Debug("Send from %@ to %@ is still waiting\n", GetName(), ah);
-               dispatch_semaphore_wait(ta->semaphore, DISPATCH_TIME_FOREVER);
-       }
-       
-       // Return the best available status (which will be NULL if we haven't aborted, or stated an
-       // intent to abort when execution starts)
-       //
-       // The value of the ABORT attribute can differ from mAbortError, first if a transform is aborted
-       // prior to running the general abort mechanic is deferred until execution.   Second during
-       // execution the abort logic avoids most of the normal processing.   Third, and most importantly
-       // during an abort the exact error that gets generated will differ from the value sent to ABORT
-       // (for example if a non-CFError was sent...plus even if it was a CFError we annotate that error).
-
-       return mAbortError;
-}
-
-CFErrorRef Transform::SendAttribute(SecTransformStringOrAttributeRef key, CFTypeRef value)
-{
-       return SetAttributeNoCallback(key, value);
-}
-
-
-
-CFTypeRef Transform::GetAttribute(SecTransformStringOrAttributeRef key)
-{
-       struct transform_attribute *ta = getTA(key, false);
-       if (ta == NULL || ta->value == NULL) {
-               return NULL;
-       }
-       
-       if (CFGetTypeID(ta->value) == internalID)
-       {
-               // this is one of our internal objects, so get the value from it
-               Source* source = (Source*) CoreFoundationHolder::ObjectFromCFType(ta->value);
-               return source->GetValue();
-       }
-       else
-       {
-               return ta->value;
-       }
-}
-
-CFErrorRef Transform::Pushback(SecTransformAttributeRef ah, CFTypeRef value) 
-{
-       CFErrorRef result = NULL;
-       transform_attribute *ta = ah2ta(ah);
-       if (!(ta->pushback_state == transform_attribute::pb_empty || ta->pushback_state == transform_attribute::pb_repush))
-       {
-               CFErrorRef error = fancy_error(kSecTransformErrorDomain, kSecTransformErrorInvalidOperation, CFSTR("Can not pushback new value until old value has been processed"));
-               SetAttribute(kSecTransformAbortAttributeName, error);
-               return error;
-       }
-       if (value == NULL && ta->pushback_value == NULL && ta->pushback_state == transform_attribute::pb_repush) 
-       {
-               ta->pushback_state = transform_attribute::pb_presented_once;
-       } else 
-       {
-               ta->pushback_state = transform_attribute::pb_value;
-       }
-       if (value) 
-       {
-               CFRetain(value);
-       }
-       ta->pushback_value = value;
-       dispatch_suspend(ta->q);
-       if (!mPushedback) 
-       {
-               mPushedback = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       }
-       CFArrayAppendValue(mPushedback, ah);
-       return result;
-}
-
-void Transform::try_pushbacks() {
-       if (!mPushedback || !CFArrayGetCount(mPushedback)) {
-               mProcessingPushbacks = FALSE;
-               return;
-       }
-       
-       CFArrayRef pb = (CFArrayRef)mPushedback;
-       mPushedback = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       CFIndex i, n = CFArrayGetCount(pb);
-       int succeeded = 0;
-       for(i = 0; i < n; ++i) 
-       {
-               SecTransformAttributeRef ah = CFArrayGetValueAtIndex(pb, i);
-               transform_attribute *ta = ah2ta(ah);
-               ta->pushback_state = transform_attribute::pb_repush;
-               CFTypeRef v = ta->pushback_value;
-               ta->pushback_value = NULL;
-               Do(ah, v);
-               if (v) 
-               {
-                       CFRelease(v);
-               }
-               if (ta->pushback_state == transform_attribute::pb_repush) {
-                       ta->pushback_state = transform_attribute::pb_empty;
-                       succeeded++;
-               }
-               // NOTE: a successful repush needs the queue unsuspended so it can run.
-               // A failed repush has suspended the queue an additional time, so we
-               // still need to resume it.
-               dispatch_resume(ta->q);
-       }
-       
-       CFRelease(pb);
-       
-       if (succeeded && CFArrayGetCount(mPushedback)) {
-               // some attribute changed while we proceeded the last batch of pushbacks, so any "new" pushbacks are eligible to run again.
-               // In theory the ones that were pushed after the last success don't need to be re-run but that isn't a big deal.
-               dispatch_async(mDispatchQueue, ^{ try_pushbacks(); });
-       } else {
-               mProcessingPushbacks = FALSE;
-       }
-}
-
-void Transform::Debug(const char *cfmt, ...) {
-       CFTypeRef d = ah2ta(DebugAH)->value;
-       if (d) {
-               CFWriteStreamRef out = NULL;
-               if (CFGetTypeID(d) == CFWriteStreamGetTypeID()) {
-                       out = (CFWriteStreamRef)d;
-               } else {
-                       static dispatch_once_t once;
-                       static CFWriteStreamRef StdErrWriteStream;
-                       dispatch_once(&once, ^{
-                               auto GCC_BUG_WORKAROUND CFURLRef GCC_BUG_WORKAROUND p = CFURLCreateWithFileSystemPath(NULL, CFSTR("/dev/stderr"), kCFURLPOSIXPathStyle, FALSE);
-                               StdErrWriteStream = CFWriteStreamCreateWithFile(NULL, p);
-                               CFWriteStreamOpen(StdErrWriteStream);
-                               CFRelease(p);
-                       });
-                       out = StdErrWriteStream;
-               }
-               
-               va_list ap;
-               va_start(ap, cfmt);
-               
-               CFStringRef fmt = CFStringCreateWithCString(NULL, cfmt, kCFStringEncodingUTF8);
-               CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, ap);
-               CFRelease(fmt);
-               va_end(ap);
-
-               
-               CFIndex sz = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
-               sz += 1;
-               CFIndex used = 0;
-               unsigned char *buf;
-               bool needs_free = true;
-               buf = (unsigned char*)malloc(sz);
-               if (buf) {
-                       CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, '?', FALSE, buf, sz, &used);
-               } else {
-                       buf = (unsigned char *)"malloc failure during Transform::Debug\n";
-                       needs_free = false;
-               }
-               
-               static dispatch_once_t once;
-               static dispatch_queue_t print_q;
-               dispatch_once(&once, ^{
-                       print_q = dispatch_queue_create("com.apple.security.debug.print_queue", 0);
-                       dispatch_set_target_queue((dispatch_object_t)print_q, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));
-               });
-               
-               dispatch_async(print_q, ^{
-                       CFWriteStreamWrite(out, buf, used);
-                       if (needs_free) {
-                               free(buf);
-                       }
-               });
-               
-               CFRelease(str);
-       }
-}
-
-void Transform::Do(SecTransformAttributeRef ah, CFTypeRef value)
-{
-       transform_attribute *ta = ah2ta(ah);
-       if (ta->pushback_state == transform_attribute::pb_discard)
-       {
-               return;
-       }
-       (void)transforms_assume(dispatch_get_current_queue() == ((ta->pushback_state == transform_attribute::pb_repush) ? mDispatchQueue : ta->q));
-       
-       if (mIsFinalizing)
-       {
-               Debug("Ignoring value %p sent to %@ (on queue %s) during finalization", value, ah, dispatch_queue_get_label(dispatch_get_current_queue()));
-               return;
-       }
-       
-       SetAttributeNoCallback(ah, value);
-    // While an abort is in progress things can get into bad
-    // states if we allow normal processing so we throw anything
-    // on the floor except CFErrorRef or NULL vales sent to
-    // ABORT or INPUT (we need to process them to let the
-    // transform shut down correctly)
-       if (mAbortError && (!(ah == this->AbortAH || ah == getTA(CFSTR("INPUT"), true)) && (value == NULL || CFGetTypeID(value) != CFErrorGetTypeID())))
-       {
-               if (value) {
-            Debug("Ignoring value (%@) sent to %@ during abort\n", value, ah);            
-        } else {
-            Debug("Ignoring NULL sent to %@ during abort\n", ah);            
-        }
-               return;
-       }
-       
-       if (mIsActive || (mAlwaysSelfNotify && !ta->deferred)) 
-       {
-               Debug("AttributeChanged: %@ (%s) = %@\n", ah, mIsActive ? "is executing" : "self notify set", value ? value : (CFTypeRef)CFSTR("(NULL)"));
-               AttributeChanged(ah, value);
-       } 
-       
-       if (mPushedback && CFArrayGetCount(mPushedback) && !mProcessingPushbacks) 
-       {
-               Debug("will process pushbacks (%@) later\n", mPushedback);
-               mProcessingPushbacks = TRUE;
-               dispatch_async(mDispatchQueue, ^{ try_pushbacks(); });
-       }
-       
-       return;
-}
-
-
-void Transform::AttributeChanged(CFStringRef name, CFTypeRef value)
-{
-}
-
-void Transform::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value)
-{
-       AttributeChanged(ah2ta(ah)->name, value);
-}
-
-CFArrayRef Transform::GetAllAH() {
-       CFIndex cnt = CFSetGetCount(mAttributes);
-       const void **values = (const void **)alloca(sizeof(void*)*cnt);
-       CFSetGetValues(mAttributes, values);
-       return CFArrayCreate(NULL, values, cnt, &kCFTypeArrayCallBacks);
-}
-
-CFTypeRef Transform::Execute(dispatch_queue_t deliveryQueue, SecMessageBlock deliveryBlock, CFErrorRef* errorRef)
-{
-       if (!mGroup)
-       {
-               CFTypeRef g = GroupTransform::Make();
-               mGroup = (GroupTransform*)CoreFoundationHolder::ObjectFromCFType(g);
-               mGroup->AddMemberToGroup(this->GetCFObject());
-               SecMessageBlock smb = ^(CFTypeRef message, CFErrorRef error, Boolean isFinal)
-               {
-                       deliveryBlock(message, error, isFinal);
-                       if (isFinal)
-                       {
-                               dispatch_async(this->mDispatchQueue, ^{
-                                       CFRelease(g);
-                               });
-                       }
-               };
-               
-               CFTypeRef ret = this->Execute(deliveryQueue, deliveryBlock ? smb : (SecMessageBlock) NULL, errorRef);
-               
-               if (!deliveryBlock)
-               {
-                       CFRelease(g);
-               }
-               
-               return ret;
-       }
-
-       if (mIsActive)
-       {
-               if (errorRef)
-               {
-                       *errorRef = CreateSecTransformErrorRef(kSecTransformTransformIsExecuting, "The %@ transform has already executed, it may not be executed again.", GetName());
-               }
-               
-               return NULL;
-       }
-
-       // Do a retain on our parent since we are using it
-    GroupTransform *rootGroup = GetRootGroup();
-       CFRetain(rootGroup->GetCFObject());
-
-       CFTypeRef result = NULL;
-       
-       CFTypeRef monitorRef =  BlockMonitor::Make(deliveryQueue, deliveryBlock);
-       
-       __block CFStringRef outputAttached = NULL;
-       
-       dispatch_queue_t p2 = dispatch_queue_create("activate phase2", NULL);
-       dispatch_queue_t p3 = dispatch_queue_create("activate phase3", NULL);
-       dispatch_suspend(p2);
-       dispatch_suspend(p3);
-       // walk the transform, doing phase1 activating as we go, and queueing phase2 and phase3 work
-       CFErrorRef temp = TraverseTransform(NULL, ^(Transform *t){
-        return t->ExecuteOperation(outputAttached, (SecMonitorRef)monitorRef, p2, p3);
-       });
-       // ExecuteOperation is not called for the outer group, so we need to manually set mISActive for it.
-       rootGroup->mIsActive = true;
-    rootGroup->StartingExecutionInGroup();
-       dispatch_resume(p2);
-       dispatch_sync(p2, ^{ dispatch_resume(p3); });
-       dispatch_sync(p3, ^{ dispatch_release(p2); });
-       dispatch_release(p3);
-       
-       if (errorRef)
-       {
-               *errorRef = temp;
-       }
-       if (temp) {
-        // It is safe to keep the monitors attached, because it is invalid to try to execute again, BUT
-        // we do need to release the reference to the group that the monitor would normally release
-        // when it processes the final message.
-        CFRelease(rootGroup->GetCFObject());
-        CFRelease(monitorRef);
-        rootGroup->StartedExecutionInGroup(false);
-        return NULL;
-       }
-       
-       dispatch_group_t initialized = dispatch_group_create();
-       rootGroup->ForAllNodesAsync(true, initialized, ^(Transform*t) {
-        t->Initialize();
-       });
-       
-       dispatch_group_notify(initialized, rootGroup->mDispatchQueue, ^{
-               dispatch_release(initialized);
-               dispatch_group_t activated = dispatch_group_create();
-               dispatch_group_enter(activated);
-               dispatch_async(rootGroup->mDispatchQueue, ^{
-                       rootGroup->ForAllNodesAsync(true, activated, ^(Transform*t) {
-                               t->ActivateInputs();
-                       });
-                       dispatch_group_leave(activated);
-               });
-               dispatch_group_notify(activated, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-                       dispatch_release(activated);
-                       // once we have been activated (but not before!), the monitor belongs to the group, and we can drop our claim
-                       CFRelease(monitorRef);
-                       rootGroup->StartedExecutionInGroup(true);
-               });
-       });
-       
-       return result;
-}
-
-
-void Transform::Initialize()
-{
-}
-
-static void ActivateInputs_set(const void *v, void *unused) {
-       transform_attribute *ta = static_cast<transform_attribute *>(ah2ta(const_cast<void *>(v)));
-       if (ta->value && internalID == CFGetTypeID(ta->value)) {
-               Source* s = (Source*) CoreFoundationHolder::ObjectFromCFType(ta->value);
-               s->Activate();
-       }
-}
-
-void Transform::ActivateInputs()
-{
-       (void)transforms_assume_zero(mIsActive && this != dispatch_get_specific(&dispatchQueueToTransformKey));
-       
-       // now run all of the forward links
-       if (!mIsFinalizing) {
-               CFSetApplyFunction(mAttributes, ActivateInputs_set, NULL);
-       }
-}
-
-CFErrorRef Transform::ForAllNodes(bool parallel, bool includeOwningGroup, Transform::TransformOperation op)
-{
-    GroupTransform *g = GetRootGroup();
-       if (g) {
-               return g->ForAllNodes(parallel, includeOwningGroup, op);
-       } else {
-               return op(this);
-       }
-}
-
-CFErrorRef Transform::TraverseTransform(CFMutableSetRef visited, TransformOperation t)
-{
-       return ForAllNodes(true, true, t);
-}
-
-CFErrorRef Transform::ExecuteOperation(CFStringRef &outputAttached, SecMonitorRef output, dispatch_queue_t phase2, dispatch_queue_t phase3)
-{
-       if (!mGroup) {
-        // top level groups are special, and don't go through this path.
-        return NULL;
-    }
-    
-    if (!TransformCanExecute())
-       {
-               // oops, this transform isn't ready to go
-               return CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "The transform %@ was not ready for execution.", GetName());
-       }
-       
-       // check to see if required attributes are connected or set
-       CFIndex i, numAttributes = CFSetGetCount(mAttributes);
-       transform_attribute **attributes = (transform_attribute **)alloca(numAttributes * sizeof(transform_attribute *));
-       TAGetAll(attributes);
-       CFMutableArrayRef still_need = NULL;
-       for(i = 0; i < numAttributes; ++i) {
-               transform_attribute *ta = attributes[i];
-               if (ta->required && ta->value == NULL && !ta->has_incoming_connection) {
-                       if (!still_need) {
-                               still_need = CFArrayCreateMutable(NULL, i, &kCFTypeArrayCallBacks);
-                       }
-                       CFArrayAppendValue(still_need, ta->name);
-               }
-       }
-       if (still_need) {
-               CFStringRef elist = CFStringCreateByCombiningStrings(NULL, still_need, CFSTR(", "));
-               CFErrorRef err = CreateSecTransformErrorRef(kSecTransformErrorMissingParameter, "Can not execute %@, missing required attributes: %@", GetName(), elist);
-               CFRelease(elist);
-               CFRelease(still_need);
-               return err;
-       }               
-
-       // see if we can attach our output here (note mAttributes may have changed)
-       numAttributes = CFSetGetCount(mAttributes);
-       attributes = (transform_attribute **)alloca(numAttributes * sizeof(transform_attribute *));
-       TAGetAll(attributes);   
-       for (i = 0; i < numAttributes; ++i)
-       {
-               transform_attribute *ta = attributes[i];
-               CFIndex arraySize = ta->connections ? CFArrayGetCount(ta->connections) : 0;
-               if (arraySize == 0 && ta->requires_outbound_connection)
-               {
-                       if (CFStringCompare(ta->name, kSecTransformOutputAttributeName, 0) == kCFCompareEqualTo) {
-                               // this is a place where we can hook up our output -- maybe
-                               if (outputAttached)
-                               {
-                                       // oops, we've already done that.
-                                       return CreateSecTransformErrorRef(kSecTransformErrorMoreThanOneOutput, "Both %@ and %@ have loose outputs, attach one to something", outputAttached, ta->transform->GetName());
-                               }
-                               // Delay the connect until after ForAllNodes returns
-                               dispatch_async(phase2, ^{
-                                       SecTransformConnectTransformsInternal(mGroup->GetCFObject(),
-                                                                                                                 GetCFObject(), kSecTransformOutputAttributeName,
-                                                                                                                 output, kSecTransformInputAttributeName);
-                               });
-                               outputAttached = ta->transform->GetName();
-                               
-                               // activate the attached monitor
-                               Monitor* m = (Monitor*) CoreFoundationHolder::ObjectFromCFType(output);
-                               m->mIsActive = true;
-                               
-                               // add the monitor to the output so that it doesn't get activated twice
-                       } else {
-                               return CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "Attribute %@ (in %@) requires an outbound connection and doesn't have one", ta->name, GetName());
-                       }
-                       
-                       break;
-               }
-       }
-       
-       // Delay activation until after the Monitor is connected
-       dispatch_async(phase3, ^{
-               phase3Activation();
-       });
-       
-       return NULL;
-}
-
-
-
-void Transform::DoPhase3Activation()
-{
-    this->mIsActive = true;
-    // execution has now truly started ("mIsActive is true")
-    CFErrorRef initError = TransformStartingExecution();
-    if (initError)
-    {
-        // Oops, now execution is about to grind to a halt
-        this->SendAttribute(AbortAH, initError);
-    }
-
-    dispatch_resume(this->mActivationQueue);
-    dispatch_group_async(this->mActivationPending, this->mActivationQueue, ^{
-        dispatch_release(this->mActivationQueue);
-        this->mActivationQueue = NULL;
-    });
-}
-
-
-
-// This would be best expressed as a block, but we seem to run into compiler errors
-void Transform::phase3Activation()
-{
-    dispatch_async(this->mDispatchQueue, ^
-    {
-        DoPhase3Activation();
-    });
-}
-
-
-Boolean Transform::TransformCanExecute()
-{
-       return true;
-}
-
-
-
-CFErrorRef Transform::TransformStartingExecution()
-{
-       return NULL;
-}
-
-
-
-bool Transform::IsExternalizable()
-{
-       return true;
-}
-
-static const void *CFTypeOrNULLRetain(CFAllocatorRef allocator, const void *value) {
-       if (value != NULL) {
-               return CFRetain(value);
-       } else {
-               return value;
-       }
-}
-
-static void CFTypeOrNULLRelease(CFAllocatorRef allocator, const void *value) {
-       if (value != NULL) {
-               CFRelease(value);
-       }
-}
-
-static CFStringRef CFTypeOrNULLCopyDescription (const void *value) {
-       if (value != NULL) {
-               return CFCopyDescription(value);
-       } else {
-               return CFSTR("NULL");
-       }
-}
-
-static Boolean CFTypeOrNULLEqual(const void *value1, const void *value2) {
-       if (value1 == NULL && value2 == NULL) {
-               return TRUE;
-       } else {
-               if (value1 == NULL || value2 == NULL) {
-                       return FALSE;
-               } else {
-                       return CFEqual(value1, value2);
-               }
-       }
-}
-
-// Returns a dictionary of all the meta attributes that will need to be reset on a RestoreState
-CFDictionaryRef Transform::GetAHDictForSaveState(SecTransformStringOrAttributeRef key)
-{
-       SecTransformMetaAttributeType types[] =
-       {
-               kSecTransformMetaAttributeRequired,
-               kSecTransformMetaAttributeRequiresOutboundConnection,
-               kSecTransformMetaAttributeDeferred,
-               kSecTransformMetaAttributeStream,
-               kSecTransformMetaAttributeCanCycle,
-               kSecTransformMetaAttributeValue
-       };
-       
-       CFIndex i, cnt = sizeof(types)/sizeof(SecTransformMetaAttributeType);
-       CFTypeRef values[cnt];
-       CFNumberRef keys[cnt];
-       key = getAH(key);
-       
-       // NOTE: we save meta attributes that are in their "default" state on purpose because the
-       // default may change in the future and we definitely want to restore the default values at
-       // time of save (i.e. if "stream=1" is the 10.7 default, but "stream=0" becomes the 10.8
-       // default we want to load all old transforms with stream=1, the simplest way to do that is
-       // to store all values, not just non-default values)
-       for(i = 0; i < cnt; ++i)
-       {
-               values[i] = GetMetaAttribute(key, types[i]);
-               int tmp = (int)types[i];
-               keys[i] = CFNumberCreate(NULL, kCFNumberIntType, &tmp);
-       }
-       
-       static CFDictionaryValueCallBacks CFTypeOrNULL;
-       static dispatch_once_t once;
-       dispatch_block_t b =
-       ^{
-               CFTypeOrNULL.version = 0;
-               CFTypeOrNULL.retain = CFTypeOrNULLRetain;
-               CFTypeOrNULL.release = CFTypeOrNULLRelease;
-               CFTypeOrNULL.copyDescription = CFTypeOrNULLCopyDescription;
-               CFTypeOrNULL.equal = CFTypeOrNULLEqual;
-       };
-       dispatch_once(&once, b);
-       
-       CFDictionaryRef ret = CFDictionaryCreate(NULL, (const void**)&keys, (const void**)&values, cnt, &kCFTypeDictionaryKeyCallBacks, &CFTypeOrNULL);
-       
-       for(i = 0; i < cnt; ++i)
-       {
-               CFRelease(keys[i]);
-       }
-       
-       return ret;
-}
-
-// return everything that doesn't have ignore_while_externalizing set
-CFDictionaryRef Transform::CopyState()
-{
-       CFIndex i, j, cnt = CFSetGetCount(mAttributes);
-       transform_attribute *attrs[cnt];
-       CFStringRef names[cnt];
-       CFDictionaryRef values[cnt];
-       TAGetAll(attrs);
-       for(i = j = 0; i < cnt; ++i)
-       {
-               transform_attribute *ta = attrs[i];
-               if (!ta->ignore_while_externalizing)
-               {
-                       names[j] = ta->name;
-                       values[j++] = GetAHDictForSaveState(ta->name);
-               }
-       }
-       
-       CFDictionaryRef result = CFDictionaryCreate(NULL, (const void**)&names, (const void**)&values, j, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-       
-       for(i = j = 0; i < cnt; ++i)
-       {
-               transform_attribute *ta = attrs[i];
-               if (!ta->ignore_while_externalizing)
-               {
-                       CFRelease(values[j++]);
-               }
-       }
-       
-       return result;
-}
-
-
-
-void Transform::RestoreState(CFDictionaryRef state)
-{
-       CFIndex i, cnt = CFDictionaryGetCount(state);
-       const void
-               **keys = (const void **)alloca(sizeof(void*)*cnt),
-               **values = (const void **)alloca(sizeof(void*)*cnt);
-
-       CFDictionaryGetKeysAndValues(state, keys, values);
-       
-       // Open issue -- do we need to do anything to values that are already set, but are not in "state"?
-       // this isn't an issue right now, which is only used on the SecTransformCopyExternalRepresentation path which starts with brand new objects,
-       // it only becomes an issue if we add a ResetFromState, or use it internally in that role.
-       
-       for(i = 0; i < cnt; i++)
-       {
-               SecTransformAttributeRef ah = getAH(keys[i]);
-               
-               if (NULL == ah)
-               {
-                       continue;
-               }
-               
-               CFIndex j, meta_cnt = CFDictionaryGetCount((CFDictionaryRef)values[i]);
-               const void **types = (const void**)alloca(sizeof(void*)*meta_cnt), **meta_values = (const void**)alloca(sizeof(void*)*meta_cnt);
-               CFDictionaryGetKeysAndValues((CFDictionaryRef)values[i], types, meta_values);
-               
-               int t;
-               for(j = 0; j < meta_cnt; ++j)
-               {
-                       CFNumberGetValue((CFNumberRef)types[j], kCFNumberIntType, &t);
-                       if (t == kSecTransformMetaAttributeValue)
-                       {
-                               if (meta_values[j]) {
-                    // SendMetaAttribute doesn't activate the callbacks 
-                    SetAttribute(ah, meta_values[j]);
-                }
-                       }
-                       else
-                       {
-                               CFErrorRef result = SendMetaAttribute(ah, (SecTransformMetaAttributeType)t, meta_values[j]);
-                               if (result)
-                               {
-                                       CFRelease(result); // see <rdar://problem/8741628> Transform::RestoreState is ignoring error returns
-                               }
-                       }
-               }
-               
-               CFErrorRef result = SendMetaAttribute(ah, kSecTransformMetaAttributeExternalize, kCFBooleanTrue);
-               if (result)
-               {
-                       CFRelease(result); // see <rdar://problem/8741628> Transform::RestoreState is ignoring error returns
-               }
-       }
-}
-
-GroupTransform* Transform::GetRootGroup()
-{
-    GroupTransform *g = mGroup;
-       if (g) {
-        while (g->mGroup) {
-            g = g->mGroup;
-        }
-    } else {
-        if (CFGetTypeID(this->GetCFObject()) == SecGroupTransformGetTypeID()) {
-            return (GroupTransform *)this;
-        }
-    }
-    return g;
-}
-
-CFDictionaryRef Transform::GetCustomExternalData()
-{
-       return NULL;
-}
-
-void Transform::SetCustomExternalData(CFDictionaryRef customData)
-{
-       return;
-}
-
-CFDictionaryRef Transform::Externalize(CFErrorRef* error)
-{
-       if (mIsActive) 
-       {
-               return (CFDictionaryRef)CreateSecTransformErrorRef(kSecTransformTransformIsExecuting, "The %@ transform is executing, you need to externalize it prior to execution", GetName());
-       }
-       
-       // make arrays to hold the transforms and the connections
-       __block CFMutableArrayRef transforms = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       __block CFMutableArrayRef connections = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-       GroupTransform *root = GetRootGroup();
-       
-       CFErrorRef err = ForAllNodes(false, true, ^(Transform *t) {
-        if (t != root) {
-            return t->ProcessExternalize(transforms, connections);
-        }
-        return (CFErrorRef)NULL;
-       });
-       
-       if (NULL != err)
-       {
-               // Really?  This just seems like a bad idea
-               if (NULL != error)
-               {
-                       *error = err;
-               }
-               return NULL;
-
-       }
-       
-       // make a dictionary to hold the output
-       CFMutableDictionaryRef output = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-       CFDictionaryAddValue(output, EXTERN_TRANSFORM_TRANSFORM_ARRAY, transforms);
-       CFDictionaryAddValue(output, EXTERN_TRANSFORM_CONNECTION_ARRAY, connections);
-               
-       // clean up
-       CFRelease(connections);
-       CFRelease(transforms);
-       
-       return output;
-}
-
-CFErrorRef Transform::ProcessExternalize(CFMutableArrayRef transforms, CFMutableArrayRef connections)
-{      
-       if (!IsExternalizable()) {
-               return NULL;
-       }
-       
-       CFDictionaryRef state = CopyState();
-       if (state && CFGetTypeID(state) == CFErrorGetTypeID()) {
-               return (CFErrorRef)state;
-       }
-       
-       // make a dictionary to hold the name, type, and state of this node
-       CFMutableDictionaryRef node = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-       CFDictionaryAddValue(node, EXTERN_TRANSFORM_NAME, GetName());
-       
-       CFTypeRef type = CFStringCreateCopy(NULL, mTypeName);
-       CFDictionaryAddValue(node, EXTERN_TRANSFORM_TYPE, type);
-       CFRelease(type);
-       
-       if (state != NULL)
-       {
-               CFDictionaryAddValue(node, EXTERN_TRANSFORM_STATE, state);
-               CFRelease(state);
-       }
-       
-       CFDictionaryRef customItems = GetCustomExternalData();
-       if (NULL != customItems)
-       {
-               CFDictionaryAddValue(node, EXTERN_TRANSFORM_CUSTOM_EXPORTS_DICTIONARY, customItems);
-               CFRelease(customItems);
-       }
-       
-       // append the resulting dictionary to the node list
-       CFArrayAppendValue(transforms, node);
-       CFRelease(node);
-       
-       // now walk the attribute list
-       CFIndex numAttributes = CFSetGetCount(mAttributes);
-       transform_attribute *attributes[numAttributes];
-       TAGetAll(attributes);
-       
-       CFIndex i;
-               
-       // walk the forward links
-       for (i = 0; i < numAttributes; ++i)
-       {
-               CFIndex arraySize = attributes[i]->connections ? CFArrayGetCount(attributes[i]->connections) : 0;
-               if (arraySize != 0)
-               {
-                       CFIndex j;
-                       for (j = 0; j < arraySize; ++j)
-                       {
-                               transform_attribute *ta = ah2ta((SecTransformAttributeRef)CFArrayGetValueAtIndex(attributes[i]->connections, j));
-                               
-                               if (!ta->transform->IsExternalizable()) {
-                                       // just pretend non-externalizable transforms don't even exist.   Don't write out connections, and don't talk to them about externalizing.
-                                       continue;
-                               }
-                               
-                               // add this forward connection to the array -- make a dictionary
-                               CFMutableDictionaryRef connection =
-                               CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-                               
-                               CFDictionaryAddValue(connection, EXTERN_TRANSFORM_FROM_NAME, GetName());
-                               CFDictionaryAddValue(connection, EXTERN_TRANSFORM_FROM_ATTRIBUTE, attributes[i]->name);
-                               CFDictionaryAddValue(connection, EXTERN_TRANSFORM_TO_NAME, ta->transform->GetName());
-                               CFDictionaryAddValue(connection, EXTERN_TRANSFORM_TO_ATTRIBUTE, ta->name);
-                               
-                               CFArrayAppendValue(connections, connection);
-                               CFRelease(connection);
-                       }
-               }
-       }
-       
-       return NULL;
-}