1#ifndef __TRANSFORM__ 2#define __TRANSFORM__ 3 4#include <CoreFoundation/CFError.h> 5#include "CoreFoundationBasics.h" 6#include "SecTransform.h" 7#include "SecCustomTransform.h" 8#include <dispatch/dispatch.h> 9#include "misc.h" 10 11// Since we are doing everything in CF, we just define an 12// attribute as a CFDictionary containing a value and 13// a CFArray of objects which need notification when that 14// value changes 15 16// defines for transform externalization 17#define EXTERN_TRANSFORM_TRANSFORM_ARRAY CFSTR("TRANSFORMS") 18#define EXTERN_TRANSFORM_CONNECTION_ARRAY CFSTR("ARRAY") 19#define EXTERN_TRANSFORM_CUSTOM_EXPORTS_DICTIONARY CFSTR("CUSTOM_EXPORTS") 20 21#define EXTERN_TRANSFORM_NAME CFSTR("NAME") 22#define EXTERN_TRANSFORM_TYPE CFSTR("TYPE") 23#define EXTERN_TRANSFORM_STATE CFSTR("STATE") 24#define EXTERN_TRANSFORM_FROM_NAME CFSTR("FROM_NAME") 25#define EXTERN_TRANSFORM_FROM_ATTRIBUTE CFSTR("FROM_ATTRIBUTE") 26#define EXTERN_TRANSFORM_TO_NAME CFSTR("TO_NAME") 27#define EXTERN_TRANSFORM_TO_ATTRIBUTE CFSTR("TO_ATTRIBUTE") 28 29#ifndef __clang__ 30#define GCC_BUG_WORKAROUND :: 31#else 32#define GCC_BUG_WORKAROUND 33#endif 34 35 36class Monitor; 37typedef CFTypeRef SecMonitorRef; 38 39struct transform_attribute { 40 CFStringRef name; 41 CFTypeRef value; 42 CFMutableArrayRef connections; 43 // NOTE: this does NOT have a reference. 44 class Transform *transform; 45 static CFTypeID cftype; 46 47 // NOTE: NULL is a valid value to pushback, so we can't just use pushback_value==NULL for "nothing pushed back" 48 // pb_empty => no value currently pushed back 49 // pb_value => we have a value, we havn't presented it yet (if pushback_value==NULL we won't present again until another attribute changes) 50 // pb_repush => pushed back value currently being re-processed 51 // pb_presented_once => we have a value, and tried to process it and got it back again (don't present until another attribute changes) 52 // 53 enum pushback_states { pb_empty, pb_value, pb_repush, pb_presented_once, pb_discard } pushback_state; 54 CFTypeRef pushback_value; 55 56 // (for pushback support; also need pushback state & value) 57 dispatch_queue_t q; 58 dispatch_semaphore_t semaphore; 59 60 // This attribute needs a value set, or to have something connected to it before running the transform 61 unsigned int required:1; 62 // This attribute needs to have an outgoing connection before running the transform 63 unsigned int requires_outbound_connection:1; 64 // This attribute should not be presented to the transform until after execution starts 65 unsigned int deferred:1; 66 // This attribute comes in N chunks followed by a NULL 67 unsigned int stream:1; 68 // This attribute should be saved when externalizing 69 unsigned int ignore_while_externalizing:1; 70 // Set by Transform::Connect 71 unsigned int has_incoming_connection:1; 72 // CustomTransform should't special case CFErrors for this attribute 73 unsigned int direct_error_handling:1; 74 // External sets are problematic, I think they should be disallowed full stop, but 7947393 says we need them sometimes 75 unsigned int allow_external_sets:1; 76 // Value has been created as a source (therefore deferred), give it special treatment 77 unsigned int has_been_deferred:1; 78 79 void *attribute_changed_block; 80 void *attribute_validate_block; 81}; 82 83typedef void (^ActivityMonitor)(CFStringRef name, CFTypeRef value); 84 85class GroupTransform; // Forward reference so we do not have to include 86 // the header and break a circular dependency 87class BlockMonitor; 88 89class Transform : public CoreFoundationObject 90{ 91 friend CFTypeRef SecTransformExecute(SecTransformRef tranformRef, CFErrorRef* errorRef); 92 friend CFTypeRef SecTransformGetAttribute(SecTransformRef transformRef, CFStringRef key); 93 friend class BlockMonitor; 94protected: 95 dispatch_queue_t mDispatchQueue, mActivationQueue; 96 dispatch_group_t mActivationPending; 97 CFMutableSetRef mAttributes; 98 CFMutableArrayRef mPushedback; 99 Boolean mIsActive; 100 Boolean mIsFinalizing; 101 Boolean mAlwaysSelfNotify, mProcessingPushbacks; 102 GroupTransform *mGroup; 103 CFErrorRef mAbortError; 104 CFStringRef mTypeName; 105 106 SecTransformAttributeRef AbortAH, DebugAH; 107 108 Transform(CFStringRef transformType, CFStringRef CFobjectType = CFSTR("SecTransform")); 109 110 transform_attribute *getTA(SecTransformStringOrAttributeRef attr, bool create_ok); 111 void TAGetAll(transform_attribute **attributes); 112 CFIndex GetAttributeCount(); 113 114 CFDictionaryRef GetAHDictForSaveState(SecTransformStringOrAttributeRef key); 115 116 CFTypeRef ValueForNewAttribute(CFStringRef key, CFTypeRef value); 117 CFMutableDictionaryRef AddNewAttribute(CFStringRef key, CFTypeRef value); 118 CFErrorRef SetAttributeNoCallback(SecTransformStringOrAttributeRef key, CFTypeRef value); 119 120 CFErrorRef ProcessExecute(CFStringRef &outputAttached, SecMonitorRef monitor); 121 typedef void (^AccumulateDictonary)(CFDictionaryRef d); 122 CFErrorRef ProcessExternalize(CFMutableArrayRef transforms, CFMutableArrayRef connections); 123 124 void FinalizeForClang(); 125 126 virtual void Finalize(); 127 // subclasses with non-trivial finalization can implement this (default: delete this) 128 virtual void FinalizePhase2(); 129 // subclasses that want to reject some connections can use this 130 virtual bool validConnectionPoint(CFStringRef attributeName); 131 132 void try_pushbacks(); 133 134 void Initialize(); 135 136 void ActivateInputs(); 137 138 virtual std::string DebugDescription(); 139 140 typedef CFErrorRef (^TransformOperation)(Transform*); 141 typedef void (^TransformAsyncOperation)(Transform*); 142 CFErrorRef ForAllNodes(bool parallel, bool includeOwningGroup, TransformOperation op); 143 144 CFErrorRef TraverseTransform(CFMutableSetRef visited, TransformOperation t); 145 146 147 CFErrorRef SendAttribute(SecTransformStringOrAttributeRef key, CFTypeRef value); 148 CFErrorRef SendMetaAttribute(SecTransformStringOrAttributeRef key, SecTransformMetaAttributeType type, CFTypeRef value); 149 150 // Abort all transforms in this transform's RootGroup, including this transform 151 virtual void AbortAllTransforms(CFTypeRef error); 152 // Abort just this transform (and maybe schedule a later call to AbortAllTransforms), should only be 153 // called via AbortAllTransforms 154 virtual void AbortJustThisTransform(CFErrorRef abortMsg); 155 156 void phase3Activation(); 157 void DoPhase3Activation(); 158 159 bool HasNoInboundConnections(); 160 bool HasNoOutboundConnections(); 161 162private: 163 CFErrorRef ExecuteOperation(CFStringRef &outputAttached, SecMonitorRef output, dispatch_queue_t phase2, dispatch_queue_t phase3); 164 SecTransformAttributeRef makeAH(transform_attribute *ta); 165 166public: 167 168 static CFTypeID GetCFTypeID(); 169 170 // these functions are overloaded to implement the functionality of your transform 171 virtual ~Transform(); 172 173 // this is called when one of your attributes (e.g. input) changes 174 virtual void AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value); 175 // this is for backwards compatibility only (XXX: convert all existing Transform subclasses to not use it then remove) 176 virtual void AttributeChanged(CFStringRef name, CFTypeRef value); 177 178 // overload to return true if your transform can be externalized (generally true unless you are a monitor) 179 virtual bool IsExternalizable(); 180 181 // Base implementation saves all attributes that have kSecTransformMetaAttributeExternalize TRUE (which is the default). 182 // If that isn't useful for your transform overload to return a CFDictionary that contains the state of 183 // your transform. Values returned should be serializable. Remember that this state will be restored 184 // before SecTransformExecute is called. Do not include the transform name in your state (this will be 185 // done for you by SecTransformCopyExternalRep). 186 virtual CFDictionaryRef CopyState(); 187 188 // overload to restore the state of your transform 189 virtual void RestoreState(CFDictionaryRef state); 190 virtual void SetCustomExternalData(CFDictionaryRef customData); 191 192 virtual Boolean TransformCanExecute(); 193 virtual CFErrorRef TransformStartingExecution(); 194 195 SecTransformAttributeRef getAH(SecTransformStringOrAttributeRef attr, bool create_ok =true, bool create_undesrscore_ok =false); 196 CFArrayRef GetAllAH(); 197 198 CFStringRef GetName(); 199 200 // Output debugging information if the DEBUG attribute is set for this transform 201 void Debug(const char *fmt, ...); 202 203 CFErrorRef RefactorErrorToIncludeAbortingTransform(CFErrorRef sourceError); 204 205public: 206 CFErrorRef Connect(GroupTransform *group, Transform* destinationTransform, CFStringRef myKey, CFStringRef hisKey); 207 CFErrorRef Disconnect(Transform* destinationTransform, CFStringRef myKey, CFStringRef hisKey); 208 209 CFErrorRef ExternalSetAttribute(SecTransformStringOrAttributeRef key, CFTypeRef value); 210 CFErrorRef SetAttribute(SecTransformStringOrAttributeRef key, CFTypeRef value); 211 CFTypeRef GetAttribute(SecTransformStringOrAttributeRef key); 212 CFTypeRef GetMetaAttribute(SecTransformStringOrAttributeRef key, SecTransformMetaAttributeType type); 213 214 CFErrorRef Pushback(SecTransformAttributeRef ah, CFTypeRef value); 215 216 void Do(SecTransformAttributeRef name, CFTypeRef value); 217 218 CFTypeRef Execute(dispatch_queue_t deliveryQueue, SecMessageBlock deliveryBlock, CFErrorRef* errorRef); 219 220 // set to get notified every time this transform does something -- used for debugging 221 void SetActivityMonitor(ActivityMonitor am); 222 223 virtual CFDictionaryRef Externalize(CFErrorRef *error); 224 225 // Returns NULL if not in a group; can return this 226 GroupTransform* GetRootGroup(); 227 228 friend class GroupTransform; 229 friend Transform::TransformOperation makeIdleOp(dispatch_group_t idle_group); 230 231 void SetGroup(GroupTransform* group) {mGroup = group;} 232 CFDictionaryRef GetCustomExternalData(); 233}; 234 235 236inline struct transform_attribute *ah2ta(SecTransformAttributeRef ah) { 237 // CF stores our data just after the CFRuntimeBase, we just have a single pointer there. 238 return *(struct transform_attribute **)(1 + (CFRuntimeBase*)ah); 239} 240 241#endif 242