4 #include <CoreFoundation/CFError.h>
5 #include "CoreFoundationBasics.h"
6 #include "SecTransform.h"
7 #include "SecCustomTransform.h"
8 #include <dispatch/dispatch.h>
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
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")
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")
30 #define GCC_BUG_WORKAROUND ::
32 #define GCC_BUG_WORKAROUND
37 typedef CFTypeRef SecMonitorRef
;
39 struct transform_attribute
{
42 CFMutableArrayRef connections
;
43 // NOTE: this does NOT have a reference.
44 class Transform
*transform
;
45 static CFTypeID cftype
;
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)
53 enum pushback_states
{ pb_empty
, pb_value
, pb_repush
, pb_presented_once
, pb_discard
} pushback_state
;
54 CFTypeRef pushback_value
;
56 // (for pushback support; also need pushback state & value)
58 dispatch_semaphore_t semaphore
;
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;
79 void *attribute_changed_block
;
80 void *attribute_validate_block
;
83 typedef void (^ActivityMonitor
)(CFStringRef name
, CFTypeRef value
);
85 class GroupTransform
; // Forward reference so we do not have to include
86 // the header and break a circular dependency
89 class Transform
: public CoreFoundationObject
91 friend CFTypeRef
SecTransformExecute(SecTransformRef tranformRef
, CFErrorRef
* errorRef
);
92 friend CFTypeRef
SecTransformGetAttribute(SecTransformRef transformRef
, CFStringRef key
);
93 friend class BlockMonitor
;
95 dispatch_queue_t mDispatchQueue
, mActivationQueue
;
96 dispatch_group_t mActivationPending
;
97 CFMutableSetRef mAttributes
;
98 CFMutableArrayRef mPushedback
;
100 Boolean mIsFinalizing
;
101 Boolean mAlwaysSelfNotify
, mProcessingPushbacks
;
102 GroupTransform
*mGroup
;
103 CFErrorRef mAbortError
;
104 CFStringRef mTypeName
;
106 SecTransformAttributeRef AbortAH
, DebugAH
;
108 Transform(CFStringRef transformType
, CFStringRef CFobjectType
= CFSTR("SecTransform"));
110 transform_attribute
*getTA(SecTransformStringOrAttributeRef attr
, bool create_ok
);
111 void TAGetAll(transform_attribute
**attributes
);
112 CFIndex
GetAttributeCount();
114 CFDictionaryRef
GetAHDictForSaveState(SecTransformStringOrAttributeRef key
);
116 CFTypeRef
ValueForNewAttribute(CFStringRef key
, CFTypeRef value
);
117 CFMutableDictionaryRef
AddNewAttribute(CFStringRef key
, CFTypeRef value
);
118 CFErrorRef
SetAttributeNoCallback(SecTransformStringOrAttributeRef key
, CFTypeRef value
);
120 CFErrorRef
ProcessExecute(CFStringRef
&outputAttached
, SecMonitorRef monitor
);
121 typedef void (^AccumulateDictonary
)(CFDictionaryRef d
);
122 CFErrorRef
ProcessExternalize(CFMutableArrayRef transforms
, CFMutableArrayRef connections
);
124 void FinalizeForClang();
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
);
132 void try_pushbacks();
136 void ActivateInputs();
138 virtual std::string
DebugDescription();
140 typedef CFErrorRef (^TransformOperation
)(Transform
*);
141 typedef void (^TransformAsyncOperation
)(Transform
*);
142 CFErrorRef
ForAllNodes(bool parallel
, bool includeOwningGroup
, TransformOperation op
);
144 CFErrorRef
TraverseTransform(CFMutableSetRef visited
, TransformOperation t
);
147 CFErrorRef
SendAttribute(SecTransformStringOrAttributeRef key
, CFTypeRef value
);
148 CFErrorRef
SendMetaAttribute(SecTransformStringOrAttributeRef key
, SecTransformMetaAttributeType type
, CFTypeRef value
);
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
);
156 void phase3Activation();
157 void DoPhase3Activation();
159 bool HasNoInboundConnections();
160 bool HasNoOutboundConnections();
163 CFErrorRef
ExecuteOperation(CFStringRef
&outputAttached
, SecMonitorRef output
, dispatch_queue_t phase2
, dispatch_queue_t phase3
);
164 SecTransformAttributeRef
makeAH(transform_attribute
*ta
);
168 static CFTypeID
GetCFTypeID();
170 // these functions are overloaded to implement the functionality of your transform
171 virtual ~Transform();
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
);
178 // overload to return true if your transform can be externalized (generally true unless you are a monitor)
179 virtual bool IsExternalizable();
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();
188 // overload to restore the state of your transform
189 virtual void RestoreState(CFDictionaryRef state
);
190 virtual void SetCustomExternalData(CFDictionaryRef customData
);
192 virtual Boolean
TransformCanExecute();
193 virtual CFErrorRef
TransformStartingExecution();
195 SecTransformAttributeRef
getAH(SecTransformStringOrAttributeRef attr
, bool create_ok
=true, bool create_undesrscore_ok
=false);
196 CFArrayRef
GetAllAH();
198 CFStringRef
GetName();
200 // Output debugging information if the DEBUG attribute is set for this transform
201 void Debug(const char *fmt
, ...);
203 CFErrorRef
RefactorErrorToIncludeAbortingTransform(CFErrorRef sourceError
);
206 CFErrorRef
Connect(GroupTransform
*group
, Transform
* destinationTransform
, CFStringRef myKey
, CFStringRef hisKey
);
207 CFErrorRef
Disconnect(Transform
* destinationTransform
, CFStringRef myKey
, CFStringRef hisKey
);
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
);
214 CFErrorRef
Pushback(SecTransformAttributeRef ah
, CFTypeRef value
);
216 void Do(SecTransformAttributeRef name
, CFTypeRef value
);
218 CFTypeRef
Execute(dispatch_queue_t deliveryQueue
, SecMessageBlock deliveryBlock
, CFErrorRef
* errorRef
);
220 // set to get notified every time this transform does something -- used for debugging
221 void SetActivityMonitor(ActivityMonitor am
);
223 virtual CFDictionaryRef
Externalize(CFErrorRef
*error
);
225 // Returns NULL if not in a group; can return this
226 GroupTransform
* GetRootGroup();
228 friend class GroupTransform
;
229 friend Transform::TransformOperation
makeIdleOp(dispatch_group_t idle_group
);
231 void SetGroup(GroupTransform
* group
) {mGroup
= group
;}
232 CFDictionaryRef
GetCustomExternalData();
236 inline 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
);