Nullable: System.Runtime.InteropServices.CustomMarshalers/WindowsRuntime (#23930)
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / src / System / Runtime / InteropServices / WindowsRuntime / BindableVectorToCollectionAdapter.cs
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 #nullable enable
6 using System.Diagnostics;
7 using Internal.Runtime.CompilerServices;
8
9 namespace System.Runtime.InteropServices.WindowsRuntime
10 {
11     // This is a set of stub methods implementing the support for the ICollection interface on WinRT
12     // objects that support IBindableVector. Used by the interop mashaling infrastructure.
13     //
14     // The methods on this class must be written VERY carefully to avoid introducing security holes.
15     // That's because they are invoked with special "this"! The "this" object
16     // for all of these methods are not BindableVectorToCollectionAdapter objects. Rather, they are
17     // of type IBindableVector. No actual BindableVectorToCollectionAdapter object is ever instantiated.
18     // Thus, you will see a lot of expressions that cast "this" to "IBindableVector".
19     internal sealed class BindableVectorToCollectionAdapter
20     {
21         private BindableVectorToCollectionAdapter()
22         {
23             Debug.Fail("This class is never instantiated");
24         }
25
26         // int Count { get }
27         internal int Count()
28         {
29             IBindableVector _this = Unsafe.As<IBindableVector>(this);
30             uint size = _this.Size;
31             if (((uint)int.MaxValue) < size)
32             {
33                 throw new InvalidOperationException(SR.InvalidOperation_CollectionBackingListTooLarge);
34             }
35
36             return (int)size;
37         }
38
39         // bool IsSynchronized { get }
40         internal bool IsSynchronized()
41         {
42             return false;
43         }
44
45         // object SyncRoot { get }
46         internal object SyncRoot()
47         {
48             return this;
49         }
50
51         // void CopyTo(Array array, int index)
52         internal void CopyTo(Array array, int arrayIndex)
53         {
54             if (array == null)
55                 throw new ArgumentNullException(nameof(array));
56
57             // ICollection expects the destination array to be single-dimensional.
58             if (array.Rank != 1)
59                 throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
60
61             int destLB = array.GetLowerBound(0);
62
63             int srcLen = Count();
64             int destLen = array.GetLength(0);
65
66             if (arrayIndex < destLB)
67                 throw new ArgumentOutOfRangeException(nameof(arrayIndex));
68
69             // Does the dimension in question have sufficient space to copy the expected number of entries?
70             // We perform this check before valid index check to ensure the exception message is in sync with
71             // the following snippet that uses regular framework code:
72             //
73             // ArrayList list = new ArrayList();
74             // list.Add(1);
75             // Array items = Array.CreateInstance(typeof(object), new int[] { 1 }, new int[] { -1 });
76             // list.CopyTo(items, 0);
77
78             if (srcLen > (destLen - (arrayIndex - destLB)))
79                 throw new ArgumentException(SR.Argument_InsufficientSpaceToCopyCollection);
80
81             if (arrayIndex - destLB > destLen)
82                 throw new ArgumentException(SR.Argument_IndexOutOfArrayBounds);
83
84             // We need to verify the index as we;
85             IBindableVector _this = Unsafe.As<IBindableVector>(this);
86
87             for (uint i = 0; i < srcLen; i++)
88             {
89                 array.SetValue(_this.GetAt(i), i + arrayIndex);
90             }
91         }
92     }
93 }