3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>Microsoft</OWNER>
13 namespace System
.Security
.Util
16 using System
.Collections
;
17 using System
.Security
.Permissions
;
18 using System
.Runtime
.Serialization
;
19 using System
.Threading
;
20 using System
.Diagnostics
.Contracts
;
21 using System
.Diagnostics
.CodeAnalysis
;
24 internal class TokenBasedSet
28 // Following 3 fields are used only for serialization compat purposes: DO NOT USE THESE EVER!
29 #pragma warning disable 414
30 private int m_initSize
= 24;
31 private int m_increment
= 8;
32 #pragma warning restore 414
33 private Object
[] m_objSet
;
34 // END -> Serialization only fields
36 [OptionalField(VersionAdded
= 2)]
37 private volatile Object m_Obj
;
38 [OptionalField(VersionAdded
= 2)]
39 private volatile Object
[] m_Set
;
42 private volatile int m_maxIndex
;
46 private void OnDeserialized(StreamingContext ctx
)
48 OnDeserializedInternal();
50 private void OnDeserializedInternal()
52 if (m_objSet
!= null) //v1.x case
55 m_Obj
= m_objSet
[m_maxIndex
];
60 // Nothing to do for the v2.0 and beyond case
64 private void OnSerializing(StreamingContext ctx
)
67 if ((ctx
.State
& ~
(StreamingContextStates
.Clone
|StreamingContextStates
.CrossAppDomain
)) != 0)
69 //Nothing special for the v2 and beyond case
71 // for the v1.x case, we need to create m_objSet if necessary
74 m_objSet
= new Object
[m_maxIndex
+1];
75 m_objSet
[m_maxIndex
] = m_Obj
;
86 private void OnSerialized(StreamingContext ctx
)
88 if ((ctx
.State
& ~
(StreamingContextStates
.Clone
|StreamingContextStates
.CrossAppDomain
)) != 0)
96 internal bool MoveNext(ref TokenBasedSetEnumerator e
)
106 e
.Index
= m_maxIndex
;
112 e
.Index
= (short)(m_maxIndex
+1);
118 while (++e
.Index
<= m_maxIndex
)
120 e
.Current
= Volatile
.Read(ref m_Set
[e
.Index
]);
122 if (e
.Current
!= null)
131 internal TokenBasedSet()
136 [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification
= "Reviewed for thread safety")]
137 internal TokenBasedSet(TokenBasedSet tbSet
)
145 if (tbSet
.m_cElt
> 1)
147 Object
[] aObj
= tbSet
.m_Set
;
148 int aLen
= aObj
.Length
;
150 Object
[] aNew
= new Object
[aLen
];
151 System
.Array
.Copy(aObj
, 0, aNew
, 0, aLen
);
160 m_cElt
= tbSet
.m_cElt
;
161 m_maxIndex
= tbSet
.m_maxIndex
;
164 internal void Reset()
172 internal void SetItem(int index
, Object item
)
174 Object
[] aObj
= null;
185 // on the first item, we don't create an array, we merely remember it's index and value
186 // this this the 99% case
188 m_maxIndex
= (short)index
;
193 // we have to decide if a 2nd item has indeed been added and create the array
195 if (index
== m_maxIndex
)
197 // replacing the one existing item
202 // adding a second distinct permission
203 Object objSaved
= m_Obj
;
204 int iMax
= Math
.Max(m_maxIndex
, index
);
206 aObj
= new Object
[iMax
+1];
207 aObj
[m_maxIndex
] = objSaved
;
209 m_maxIndex
= (short)iMax
;
217 // this is the general case code for when there is really an array
221 // we are now adding an item, check if we need to grow
223 if (index
>= aObj
.Length
)
225 Object
[] newset
= new Object
[index
+1];
226 System
.Array
.Copy(aObj
, 0, newset
, 0, m_maxIndex
+1);
227 m_maxIndex
= (short)index
;
228 newset
[index
] = item
;
234 if (aObj
[index
] == null)
239 if (index
> m_maxIndex
)
240 m_maxIndex
= (short)index
;
246 [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification
= "Reviewed for thread-safety")]
247 internal Object
GetItem(int index
)
255 if (index
== m_maxIndex
)
260 if (index
< m_Set
.Length
)
261 return Volatile
.Read(ref m_Set
[index
]);
267 internal Object
RemoveItem(int index
)
278 if (index
!= m_maxIndex
)
280 // removing a permission we don't have ignore it
285 // removing the permission we have at the moment
292 // this is the general case code for when there is really an array
294 // we are removing an item
295 if (index
< m_Set
.Length
&& (ret
= Volatile
.Read(ref m_Set
[index
])) != null)
297 // ok we really deleted something at this point
299 Volatile
.Write(ref m_Set
[index
], null);
302 if (index
== m_maxIndex
)
303 ResetMaxIndex(m_Set
);
305 // collapse the array
308 m_Obj
= Volatile
.Read(ref m_Set
[m_maxIndex
]);
318 private void ResetMaxIndex(Object
[] aObj
)
322 // Start at the end of the array, and
323 // scan backwards for the first non-null
324 // slot. That is the new maxIndex.
325 for (i
= aObj
.Length
- 1; i
>= 0; i
--)
329 m_maxIndex
= (short)i
;
336 internal int GetStartingIndex()
342 internal int GetCount()
347 internal int GetMaxUsedIndex()
352 internal bool FastIsEmpty()
357 // Used to merge two distinct TokenBasedSets (used currently only in PermissionSet Deserialization)
358 internal TokenBasedSet
SpecialUnion(TokenBasedSet other
)
360 // This gets called from PermissionSet.OnDeserialized and it's possible that the TokenBasedSets have
361 // not been subjected to VTS callbacks yet
362 OnDeserializedInternal();
363 TokenBasedSet unionSet
= new TokenBasedSet();
367 other
.OnDeserializedInternal();
368 maxMax
= this.GetMaxUsedIndex() > other
.GetMaxUsedIndex() ? this.GetMaxUsedIndex() : other
.GetMaxUsedIndex();
371 maxMax
= this.GetMaxUsedIndex();
373 for (int i
= 0; i
<= maxMax
; ++i
)
375 Object thisObj
= this.GetItem( i
);
376 IPermission thisPerm
= thisObj
as IPermission
;
377 #if FEATURE_CAS_POLICY
378 ISecurityElementFactory thisElem
= thisObj
as ISecurityElementFactory
;
379 #endif // FEATURE_CAS_POLICY
381 Object otherObj
= (other
!= null)?other
.GetItem( i
):null;
382 IPermission otherPerm
= otherObj
as IPermission
;
383 #if FEATURE_CAS_POLICY
384 ISecurityElementFactory otherElem
= otherObj
as ISecurityElementFactory
;
385 #endif // FEATURE_CAS_POLICY
387 if (thisObj
== null && otherObj
== null)
393 #if FEATURE_CAS_POLICY
394 if (otherElem
!= null)
396 otherPerm
= PermissionSet
.CreatePerm(otherElem
, false);
398 #endif // FEATURE_CAS_POLICY
400 PermissionToken token
= PermissionToken
.GetToken(otherPerm
);
404 throw new SerializationException(Environment
.GetResourceString("Serialization_InsufficientState"));
407 unionSet
.SetItem(token
.m_index
, otherPerm
);
409 else if (otherObj
== null)
411 #if FEATURE_CAS_POLICY
412 if (thisElem
!= null)
414 thisPerm
= PermissionSet
.CreatePerm(thisElem
, false);
416 #endif // FEATURE_CAS_POLICY
418 PermissionToken token
= PermissionToken
.GetToken(thisPerm
);
421 throw new SerializationException(Environment
.GetResourceString("Serialization_InsufficientState"));
423 unionSet
.SetItem( token
.m_index
, thisPerm
);
427 Contract
.Assert( (thisObj
== null || otherObj
== null), "Permission cannot be in both TokenBasedSets" );
433 internal void SpecialSplit(ref TokenBasedSet unrestrictedPermSet
, ref TokenBasedSet normalPermSet
, bool ignoreTypeLoadFailures
)
435 int maxIndex
= GetMaxUsedIndex();
437 for (int i
= GetStartingIndex(); i
<= maxIndex
; ++i
)
439 Object obj
= GetItem( i
);
442 IPermission perm
= obj
as IPermission
;
443 #if FEATURE_CAS_POLICY
445 perm
= PermissionSet
.CreatePerm(obj
, ignoreTypeLoadFailures
);
446 #endif // FEATURE_CAS_POLICY
447 PermissionToken token
= PermissionToken
.GetToken(perm
);
449 if (perm
== null || token
== null)
452 if (perm
is IUnrestrictedPermission
)
454 // Add to unrestrictedPermSet
455 if (unrestrictedPermSet
== null)
456 unrestrictedPermSet
= new TokenBasedSet();
457 unrestrictedPermSet
.SetItem(token
.m_index
, perm
);
461 // Add to normalPermSet
462 if (normalPermSet
== null)
463 normalPermSet
= new TokenBasedSet();
464 normalPermSet
.SetItem(token
.m_index
, perm
);