fa9e01eb236502c13c6119be09e7ae2bc7f5d937
[mono.git] / mcs / class / referencesource / mscorlib / system / runtime / interopservices / windowsruntime / listtobindablevectoradapter.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 //
7 // <OWNER>GPaperin</OWNER>
8 // <OWNER>Microsoft</OWNER>
9
10 using System;
11 using System.Security;
12 using System.Reflection;
13 using System.Collections;
14 using System.Collections.Generic;
15 using System.Collections.ObjectModel;
16 using System.Diagnostics.Contracts;
17 using System.Runtime.InteropServices;
18 using System.Runtime.CompilerServices;
19
20 namespace System.Runtime.InteropServices.WindowsRuntime
21 {
22     // This is a set of stub methods implementing the support for the IBindableVector interface on managed
23     // objects that implement IList. Used by the interop mashaling infrastructure.
24     //
25     // The methods on this class must be written VERY carefully to avoid introducing security holes.
26     // That's because they are invoked with special "this"! The "this" object
27     // for all of these methods are not ListToBindableVectorAdapter objects. Rather, they are of type
28     // IList. No actual ListToVectorBindableAdapter object is ever instantiated. Thus, you will
29     // see a lot of expressions that cast "this" to "IList". 
30     internal sealed class ListToBindableVectorAdapter
31     {
32         private ListToBindableVectorAdapter()
33         {
34             Contract.Assert(false, "This class is never instantiated");
35         }
36
37         // object GetAt(uint index)
38         [SecurityCritical]
39         internal object GetAt(uint index)
40         {
41             IList _this = JitHelpers.UnsafeCast<IList>(this);
42             EnsureIndexInt32(index, _this.Count);        
43
44             try
45             {
46                 return _this[(Int32)index];
47             }
48             catch (ArgumentOutOfRangeException ex)
49             {
50                 throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_BOUNDS, ex, "ArgumentOutOfRange_IndexOutOfRange");
51             }
52         }
53
54         // uint Size { get }
55         [SecurityCritical]
56         internal uint Size()
57         {
58             IList _this = JitHelpers.UnsafeCast<IList>(this);
59             return (uint)_this.Count;
60         }
61
62         // IBindableVectorView GetView()
63         [SecurityCritical]
64         internal IBindableVectorView GetView()
65         {
66             IList _this = JitHelpers.UnsafeCast<IList>(this);
67             return new ListToBindableVectorViewAdapter(_this);
68         }
69
70         // bool IndexOf(object value, out uint index)
71         [SecurityCritical]
72         internal bool IndexOf(object value, out uint index)
73         {
74             IList _this = JitHelpers.UnsafeCast<IList>(this);
75             int ind = _this.IndexOf(value);
76
77             if (-1 == ind)
78             {
79                 index = 0;
80                 return false;
81             }
82
83             index = (uint)ind;
84             return true;
85         }
86
87         // void SetAt(uint index, object value)
88         [SecurityCritical]
89         internal void SetAt(uint index, object value)
90         {
91             IList _this = JitHelpers.UnsafeCast<IList>(this);
92             EnsureIndexInt32(index, _this.Count);
93
94             try
95             {
96                 _this[(int)index] = value;
97             }
98             catch (ArgumentOutOfRangeException ex)
99             {
100                 throw WindowsRuntimeMarshal.GetExceptionForHR(__HResults.E_BOUNDS, ex, "ArgumentOutOfRange_IndexOutOfRange");
101             }
102         }
103
104         // void InsertAt(uint index, object value)
105         [SecurityCritical]
106         internal void InsertAt(uint index, object value)
107         {
108             IList _this = JitHelpers.UnsafeCast<IList>(this);
109
110             // Inserting at an index one past the end of the list is equivalent to appending
111             // so we need to ensure that we're within (0, count + 1).
112             EnsureIndexInt32(index, _this.Count + 1);
113
114             try
115             {
116                 _this.Insert((int)index, value);
117             }
118             catch (ArgumentOutOfRangeException ex)
119             {
120                 // Change error code to match what WinRT expects
121                 ex.SetErrorCode(__HResults.E_BOUNDS);
122                 throw;
123             }
124         }
125
126         // void RemoveAt(uint index)
127         [SecurityCritical]
128         internal void RemoveAt(uint index)
129         {
130             IList _this = JitHelpers.UnsafeCast<IList>(this);
131             EnsureIndexInt32(index, _this.Count); 
132
133             try
134             {
135                 _this.RemoveAt((Int32)index);
136             }
137             catch (ArgumentOutOfRangeException ex)
138             {
139                 // Change error code to match what WinRT expects
140                 ex.SetErrorCode(__HResults.E_BOUNDS);
141                 throw;
142             }
143         }
144
145         // void Append(object value)
146         [SecurityCritical]
147         internal void Append(object value)
148         {
149             IList _this = JitHelpers.UnsafeCast<IList>(this);
150             _this.Add(value);
151         }
152
153         // void RemoveAtEnd()
154         [SecurityCritical]
155         internal void RemoveAtEnd()
156         {
157             IList _this = JitHelpers.UnsafeCast<IList>(this);
158             if (_this.Count == 0)
159             {
160                 Exception e = new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotRemoveLastFromEmptyCollection"));
161                 e.SetErrorCode(__HResults.E_BOUNDS);
162                 throw e;
163             }
164
165             uint size = (uint)_this.Count;
166             RemoveAt(size - 1);
167         }
168
169         // void Clear()
170         [SecurityCritical]
171         internal void Clear()
172         {
173             IList _this = JitHelpers.UnsafeCast<IList>(this);
174             _this.Clear();
175         }
176
177         // Helpers:
178
179         private static void EnsureIndexInt32(uint index, int listCapacity)
180         {
181             // We use '<=' and not '<' becasue Int32.MaxValue == index would imply
182             // that Size > Int32.MaxValue:
183             if (((uint)Int32.MaxValue) <= index || index >= (uint)listCapacity)
184             {
185                 Exception e = new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_IndexLargerThanMaxValue"));
186                 e.SetErrorCode(__HResults.E_BOUNDS);
187                 throw e;
188             }
189         }
190     }
191 }