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