**** Merged from MCS ****
[mono-project.git] / mcs / class / System / System.Security.Permissions / ResourcePermissionBase.cs
blob8c3e96633a912369c0f4e83a14f4a23735792702
1 //
2 // System.Security.Permissions.ResourcePermissionBase.cs
3 //
4 // Authors:
5 // Jonathan Pryor (jonpryor@vt.edu)
6 // Sebastien Pouliot <sebastien@ximian.com>
7 //
8 // (C) 2002
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Globalization;
34 namespace System.Security.Permissions {
36 [Serializable]
37 public abstract class ResourcePermissionBase : CodeAccessPermission, IUnrestrictedPermission {
39 private const int version = 1;
41 private ArrayList _list;
42 private bool _unrestricted;
43 private Type _type;
44 private string[] _tags;
46 protected ResourcePermissionBase ()
48 _list = new ArrayList ();
51 protected ResourcePermissionBase (PermissionState state) : this ()
53 // there are no validation of the permission state
54 _unrestricted = (state == PermissionState.Unrestricted);
55 // but any invalid value results in a restricted set
58 public const string Any = "*";
59 public const string Local = ".";
61 protected Type PermissionAccessType {
62 get { return _type; }
63 set {
64 if (value == null)
65 throw new ArgumentNullException ("PermissionAccessType");
66 if (!value.IsEnum)
67 throw new ArgumentException ("!Enum", "PermissionAccessType");
68 _type = value;
72 protected string[] TagNames {
73 get { return _tags; }
74 set {
75 if (value == null)
76 throw new ArgumentNullException ("TagNames");
77 if (value.Length == 0)
78 throw new ArgumentException ("Length==0", "TagNames");
79 _tags = value;
83 protected void AddPermissionAccess (ResourcePermissionBaseEntry entry)
85 CheckEntry (entry);
86 if (Exists (entry)) {
87 string msg = Locale.GetText ("Entry already exists.");
88 throw new InvalidOperationException (msg);
91 _list.Add (entry);
94 protected void Clear ()
96 _list.Clear ();
99 public override IPermission Copy ()
101 ResourcePermissionBase copy = CreateFromType (this.GetType (), _unrestricted);
102 if (_tags != null)
103 copy._tags = (string[]) _tags.Clone ();
104 copy._type = _type;
105 // FIXME: shallow or deep copy ?
106 copy._list.AddRange (_list);
107 return copy;
110 [MonoTODO ("incomplete - need more test")]
111 public override void FromXml (SecurityElement securityElement)
113 // duplicate MS behaviour - reported as FDBK15052
114 if (securityElement == null)
115 throw new NullReferenceException ("securityElement");
116 CheckSecurityElement (securityElement, "securityElement", version, version);
117 // Note: we do not (yet) care about the return value
118 // as we only accept version 1 (min/max values)
120 _unrestricted = PermissionHelper.IsUnrestricted (securityElement);
121 // TODO
124 protected ResourcePermissionBaseEntry[] GetPermissionEntries ()
126 ResourcePermissionBaseEntry[] entries = new ResourcePermissionBaseEntry [_list.Count];
127 _list.CopyTo (entries, 0);
128 return entries;
131 public override IPermission Intersect (IPermission target)
133 ResourcePermissionBase rpb = Cast (target);
134 if (rpb == null)
135 return null;
137 bool su = this.IsUnrestricted ();
138 bool tu = rpb.IsUnrestricted ();
140 // if one is empty we return null (unless the other one is unrestricted)
141 if (IsEmpty () && !tu)
142 return null;
143 if (rpb.IsEmpty () && !su)
144 return null;
146 ResourcePermissionBase result = CreateFromType (this.GetType (), (su && tu));
147 foreach (ResourcePermissionBaseEntry entry in _list) {
148 if (tu || rpb.Exists (entry))
149 result.AddPermissionAccess (entry);
151 foreach (ResourcePermissionBaseEntry entry in rpb._list) {
152 // don't add twice
153 if ((su || this.Exists (entry)) && !result.Exists (entry))
154 result.AddPermissionAccess (entry);
156 return result;
159 public override bool IsSubsetOf (IPermission target)
161 // do not use Cast - different permissions return false :-/
162 if (target == null)
163 return true;
164 ResourcePermissionBase rpb = (target as ResourcePermissionBase);
165 if (rpb == null)
166 return false;
167 if (rpb.IsUnrestricted ())
168 return true;
169 if (IsUnrestricted ())
170 return rpb.IsUnrestricted ();
171 foreach (ResourcePermissionBaseEntry entry in _list) {
172 if (!rpb.Exists (entry))
173 return false;
175 return true;
178 public bool IsUnrestricted ()
180 return _unrestricted;
183 protected void RemovePermissionAccess (ResourcePermissionBaseEntry entry)
185 CheckEntry (entry);
186 for (int i = 0; i < _list.Count; i++) {
187 ResourcePermissionBaseEntry rpbe = (ResourcePermissionBaseEntry) _list [i];
188 if (Equals (entry, rpbe)) {
189 _list.RemoveAt (i);
190 return;
193 string msg = Locale.GetText ("Entry doesn't exists.");
194 throw new InvalidOperationException (msg);
197 public override SecurityElement ToXml ()
199 SecurityElement se = PermissionHelper.Element (this.GetType (), version);
200 if (IsUnrestricted ()) {
201 se.AddAttribute ("Unrestricted", "true");
203 else {
204 foreach (ResourcePermissionBaseEntry entry in _list) {
205 SecurityElement container = se;
206 for (int i=0; i < _tags.Length; i++) {
207 SecurityElement child = new SecurityElement (_tags [i]);
208 child.AddAttribute ("name", entry.PermissionAccessPath [i]);
209 container.AddChild (child);
210 child = container;
214 return se;
217 public override IPermission Union (IPermission target)
219 ResourcePermissionBase rpb = Cast (target);
220 if (rpb == null)
221 return Copy ();
222 if (IsEmpty () && rpb.IsEmpty ())
223 return null;
224 if (rpb.IsEmpty ())
225 return Copy ();
226 if (IsEmpty ())
227 return rpb.Copy ();
229 bool unrestricted = (IsUnrestricted () || rpb.IsUnrestricted ());
230 ResourcePermissionBase result = CreateFromType (this.GetType (), unrestricted);
231 // strangely unrestricted union doesn't process the elements (while intersect does)
232 if (!unrestricted) {
233 foreach (ResourcePermissionBaseEntry entry in _list) {
234 result.AddPermissionAccess (entry);
236 foreach (ResourcePermissionBaseEntry entry in rpb._list) {
237 // don't add twice
238 if (!result.Exists (entry))
239 result.AddPermissionAccess (entry);
242 return result;
245 // helpers
247 private bool IsEmpty ()
249 return (!_unrestricted && (_list.Count == 0));
252 private ResourcePermissionBase Cast (IPermission target)
254 if (target == null)
255 return null;
257 ResourcePermissionBase rp = (target as ResourcePermissionBase);
258 if (rp == null) {
259 PermissionHelper.ThrowInvalidPermission (target, typeof (ResourcePermissionBase));
262 return rp;
265 internal void CheckEntry (ResourcePermissionBaseEntry entry)
267 if (entry == null)
268 throw new ArgumentNullException ("entry");
269 if ((entry.PermissionAccessPath == null) || (entry.PermissionAccessPath.Length != _tags.Length)) {
270 string msg = Locale.GetText ("Entry doesn't match TagNames");
271 throw new InvalidOperationException (msg);
275 internal bool Equals (ResourcePermissionBaseEntry entry1, ResourcePermissionBaseEntry entry2)
277 if (entry1.PermissionAccess != entry2.PermissionAccess)
278 return false;
279 if (entry1.PermissionAccessPath.Length != entry2.PermissionAccessPath.Length)
280 return false;
281 for (int i=0; i < entry1.PermissionAccessPath.Length; i++) {
282 if (entry1.PermissionAccessPath [i] != entry2.PermissionAccessPath [i])
283 return false;
285 return true;
288 internal bool Exists (ResourcePermissionBaseEntry entry)
290 if (_list.Count == 0)
291 return false;
292 foreach (ResourcePermissionBaseEntry rpbe in _list) {
293 if (Equals (rpbe, entry))
294 return true;
296 return false;
299 // logic isn't identical to PermissionHelper.CheckSecurityElement
300 // - no throw on version mismatch
301 internal int CheckSecurityElement (SecurityElement se, string parameterName, int minimumVersion, int maximumVersion)
303 if (se == null)
304 throw new ArgumentNullException (parameterName);
306 // Note: we do not care about the class attribute at
307 // this stage (in fact we don't even if the class
308 // attribute is present or not). Anyway the object has
309 // already be created, with success, if we're loading it
311 // we assume minimum version if no version number is supplied
312 int version = minimumVersion;
313 string v = se.Attribute ("version");
314 if (v != null) {
315 try {
316 version = Int32.Parse (v);
318 catch (Exception e) {
319 string msg = Locale.GetText ("Couldn't parse version from '{0}'.");
320 msg = String.Format (msg, v);
321 throw new ArgumentException (msg, parameterName, e);
325 return version;
328 // static helpers
330 private static char[] invalidChars = new char[] { '\t', '\n', '\v', '\f', '\r', ' ', '\\', '\x160' };
332 internal static void ValidateMachineName (string name)
334 // FIXME: maybe other checks are required (but not documented)
335 if ((name == null) || (name.Length == 0) || (name.IndexOfAny (invalidChars) != -1)) {
336 string msg = Locale.GetText ("Invalid machine name '{0}'.");
337 if (name == null)
338 name = "(null)";
339 msg = String.Format (msg, name);
340 throw new ArgumentException (msg, "MachineName");
344 internal static ResourcePermissionBase CreateFromType (Type type, bool unrestricted)
346 object[] parameters = new object [1];
347 parameters [0] = (object) ((unrestricted) ? PermissionState.Unrestricted : PermissionState.None);
348 // we must return the derived type - this is why an empty constructor is required ;-)
349 return (ResourcePermissionBase) Activator.CreateInstance (type, parameters);