--- /dev/null
+#include <libkern/OSAtomic.h>
+
+#include "TransformFactory.h"
+#include "NullTransform.h"
+#include "Digest.h"
+#include "EncryptTransform.h"
+#include "GroupTransform.h"
+#include "Utilities.h"
+
+
+void TransformFactory::RegisterTransforms()
+{
+ RegisterTransform_prelocked(NullTransform::MakeTransformFactory(), NULL);
+ RegisterTransform_prelocked(DigestTransform::MakeTransformFactory(), NULL);
+ RegisterTransform_prelocked(EncryptTransform::MakeTransformFactory(), NULL);
+ RegisterTransform_prelocked(DecryptTransform::MakeTransformFactory(), NULL);
+ RegisterTransform_prelocked(GroupTransform::MakeTransformFactory(), NULL);
+}
+
+CFMutableDictionaryRef TransformFactory::gRegistered;
+dispatch_once_t TransformFactory::gSetup;
+dispatch_queue_t TransformFactory::gRegisteredQueue;
+
+bool TransformFactory::RegisterTransform_prelocked(TransformFactory* tf, CFStringRef cfname)
+{
+ if (!CFDictionaryContainsKey(gRegistered, tf->mCFType)) {
+ CFDictionaryAddValue(gRegistered, tf->mCFType, tf);
+ if (!cfname) {
+ CoreFoundationObject::RegisterObject(tf->mCFType, false);
+ } else {
+ if (!CoreFoundationObject::FindObjectType(cfname)) {
+ CoreFoundationObject::RegisterObject(cfname, false);
+ }
+ }
+ }
+
+ return true;
+}
+
+
+void TransformFactory::RegisterTransform(TransformFactory* tf, CFStringRef cfname)
+{
+ dispatch_once_f(&gSetup, NULL, Setup);
+ dispatch_barrier_sync(gRegisteredQueue, ^{
+ RegisterTransform_prelocked(tf, cfname);
+ });
+}
+
+void TransformFactory::Setup(void *)
+{
+ gRegisteredQueue = dispatch_queue_create("com.apple.security.TransformFactory.Registered", DISPATCH_QUEUE_CONCURRENT);
+ gRegistered = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, NULL);
+ RegisterTransforms();
+}
+
+void TransformFactory::Setup()
+{
+ dispatch_once_f(&gSetup, NULL, Setup);
+}
+
+TransformFactory* TransformFactory::FindTransformFactoryByType(CFStringRef name)
+{
+ dispatch_once_f(&gSetup, NULL, Setup);
+ __block TransformFactory *ret;
+ dispatch_barrier_sync(gRegisteredQueue, ^{
+ ret = (TransformFactory*)CFDictionaryGetValue(gRegistered, name);
+ });
+ return ret;
+}
+
+
+
+SecTransformRef TransformFactory::MakeTransformWithType(CFStringRef type, CFErrorRef* baseError)
+{
+ TransformFactory* tf = FindTransformFactoryByType(type);
+ if (!tf)
+ {
+ if (baseError != NULL)
+ {
+#if 0
+ // This version lists out all regestered transform types.
+ // It is useful more for debugging then for anything else,
+ // so it is great to keep around, but normally not so good
+ // to run.
+ dispatch_barrier_sync(gRegisteredQueue, ^(void) {
+ CFMutableStringRef transformNames = CFStringCreateMutable(NULL, 0);
+ CFIndex numberRegistered = CFDictionaryGetCount(gRegistered);
+ CFStringRef names[numberRegistered];
+ CFDictionaryGetKeysAndValues(gRegistered, (const void**)names, NULL);
+ for(int i = 0; i < numberRegistered; i++) {
+ if (i != 0) {
+ CFStringAppend(transformNames, CFSTR(", "));
+ }
+ CFStringAppend(transformNames, names[i]);
+ }
+
+ *baseError = CreateSecTransformErrorRef(kSecTransformTransformIsNotRegistered,
+ "The %s transform is not registered, choose from: %@", type,transformNames);
+
+ });
+#else
+ *baseError = CreateSecTransformErrorRef(kSecTransformTransformIsNotRegistered,
+ "The %s transform is not registered", type);
+#endif
+ }
+
+ return NULL;
+ }
+ else
+ {
+ return tf->Make();
+ }
+}
+
+
+
+TransformFactory::TransformFactory(CFStringRef type, bool registerGlobally, CFStringRef cftype) : mCFType(type)
+{
+ if (registerGlobally)
+ {
+ CoreFoundationObject::RegisterObject(cftype ? cftype : type, false);
+ }
+}