• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "base/win/variant_vector.h"
11 
12 #include <optional>
13 
14 #include "base/check_op.h"
15 #include "base/notreached.h"
16 #include "base/numerics/checked_math.h"
17 #include "base/process/memory.h"
18 #include "base/win/scoped_safearray.h"
19 #include "base/win/scoped_variant.h"
20 
21 namespace base {
22 namespace win {
23 
24 namespace {
25 
26 // Lexicographical comparison between the contents of |vector| and |safearray|.
27 template <VARTYPE ElementVartype>
CompareAgainstSafearray(const std::vector<ScopedVariant> & vector,const ScopedSafearray & safearray,bool ignore_case)28 int CompareAgainstSafearray(const std::vector<ScopedVariant>& vector,
29                             const ScopedSafearray& safearray,
30                             bool ignore_case) {
31   std::optional<ScopedSafearray::LockScope<ElementVartype>> lock_scope =
32       safearray.CreateLockScope<ElementVartype>();
33   // If we fail to create a lock scope, then arbitrarily treat |this| as
34   // greater. This should only happen when the SAFEARRAY fails to be locked,
35   // so we cannot compare the contents of the SAFEARRAY.
36   if (!lock_scope)
37     return 1;
38 
39   // Create a temporary VARIANT which does not own its contents, and is
40   // populated with values from the |lock_scope| so it can be compared against.
41   VARIANT non_owning_temp;
42   V_VT(&non_owning_temp) = ElementVartype;
43 
44   auto vector_iter = vector.begin();
45   auto scope_iter = lock_scope->begin();
46   for (; vector_iter != vector.end() && scope_iter != lock_scope->end();
47        ++vector_iter, ++scope_iter) {
48     internal::VariantConverter<ElementVartype>::RawSet(&non_owning_temp,
49                                                        *scope_iter);
50     int compare_result = vector_iter->Compare(non_owning_temp, ignore_case);
51     // If there is a difference in values, return the difference.
52     if (compare_result)
53       return compare_result;
54   }
55   // There are more elements in |vector|, so |vector| is
56   // greater than |safearray|.
57   if (vector_iter != vector.end())
58     return 1;
59   // There are more elements in |safearray|, so |vector| is
60   // less than |safearray|.
61   if (scope_iter != lock_scope->end())
62     return -1;
63   return 0;
64 }
65 
66 }  // namespace
67 
68 VariantVector::VariantVector() = default;
69 
VariantVector(VariantVector && other)70 VariantVector::VariantVector(VariantVector&& other)
71     : vartype_(std::exchange(other.vartype_, VT_EMPTY)),
72       vector_(std::move(other.vector_)) {}
73 
operator =(VariantVector && other)74 VariantVector& VariantVector::operator=(VariantVector&& other) {
75   DCHECK_NE(this, &other);
76   vartype_ = std::exchange(other.vartype_, VT_EMPTY);
77   vector_ = std::move(other.vector_);
78   return *this;
79 }
80 
~VariantVector()81 VariantVector::~VariantVector() {
82   Reset();
83 }
84 
operator ==(const VariantVector & other) const85 bool VariantVector::operator==(const VariantVector& other) const {
86   return !Compare(other);
87 }
88 
operator !=(const VariantVector & other) const89 bool VariantVector::operator!=(const VariantVector& other) const {
90   return !VariantVector::operator==(other);
91 }
92 
Reset()93 void VariantVector::Reset() {
94   vector_.clear();
95   vartype_ = VT_EMPTY;
96 }
97 
ReleaseAsScalarVariant()98 VARIANT VariantVector::ReleaseAsScalarVariant() {
99   ScopedVariant scoped_variant;
100 
101   if (!Empty()) {
102     DCHECK_EQ(Size(), 1U);
103     scoped_variant = std::move(vector_[0]);
104     Reset();
105   }
106 
107   return scoped_variant.Release();
108 }
109 
ReleaseAsSafearrayVariant()110 VARIANT VariantVector::ReleaseAsSafearrayVariant() {
111   ScopedVariant scoped_variant;
112 
113   switch (Type()) {
114     case VT_EMPTY:
115       break;
116     case VT_BOOL:
117       scoped_variant.Set(CreateAndPopulateSafearray<VT_BOOL>());
118       break;
119     case VT_I1:
120       scoped_variant.Set(CreateAndPopulateSafearray<VT_I1>());
121       break;
122     case VT_UI1:
123       scoped_variant.Set(CreateAndPopulateSafearray<VT_UI1>());
124       break;
125     case VT_I2:
126       scoped_variant.Set(CreateAndPopulateSafearray<VT_I2>());
127       break;
128     case VT_UI2:
129       scoped_variant.Set(CreateAndPopulateSafearray<VT_UI2>());
130       break;
131     case VT_I4:
132       scoped_variant.Set(CreateAndPopulateSafearray<VT_I4>());
133       break;
134     case VT_UI4:
135       scoped_variant.Set(CreateAndPopulateSafearray<VT_UI4>());
136       break;
137     case VT_I8:
138       scoped_variant.Set(CreateAndPopulateSafearray<VT_I8>());
139       break;
140     case VT_UI8:
141       scoped_variant.Set(CreateAndPopulateSafearray<VT_UI8>());
142       break;
143     case VT_R4:
144       scoped_variant.Set(CreateAndPopulateSafearray<VT_R4>());
145       break;
146     case VT_R8:
147       scoped_variant.Set(CreateAndPopulateSafearray<VT_R8>());
148       break;
149     case VT_DATE:
150       scoped_variant.Set(CreateAndPopulateSafearray<VT_DATE>());
151       break;
152     case VT_BSTR:
153       scoped_variant.Set(CreateAndPopulateSafearray<VT_BSTR>());
154       break;
155     case VT_DISPATCH:
156       scoped_variant.Set(CreateAndPopulateSafearray<VT_DISPATCH>());
157       break;
158     case VT_UNKNOWN:
159       scoped_variant.Set(CreateAndPopulateSafearray<VT_UNKNOWN>());
160       break;
161     // The default case shouldn't be reachable, but if we added support for more
162     // VARTYPEs to base::win::internal::VariantConverter<> and they were
163     // inserted into a VariantVector then it would be possible to reach the
164     // default case for those new types until implemented.
165     //
166     // Because the switch is against VARTYPE (unsigned short) and not VARENUM,
167     // removing the default case will not result in build warnings/errors if
168     // there are missing cases. It is important that this uses VARTYPE rather
169     // than VARENUM, because in the future we may want to support complex
170     // VARTYPES. For example a value within VT_TYPEMASK that's joined something
171     // outside the typemask like VT_ARRAY or VT_BYREF.
172     default:
173       NOTREACHED();
174   }
175 
176   // CreateAndPopulateSafearray handles resetting |this| to VT_EMPTY because it
177   // transfers ownership of each element to the SAFEARRAY.
178   return scoped_variant.Release();
179 }
180 
Compare(const VARIANT & other,bool ignore_case) const181 int VariantVector::Compare(const VARIANT& other, bool ignore_case) const {
182   // If the element variant types are different, compare against the types.
183   if (Type() != (V_VT(&other) & VT_TYPEMASK))
184     return (Type() < (V_VT(&other) & VT_TYPEMASK)) ? (-1) : 1;
185 
186   // Both have an empty variant type so they are the same.
187   if (Type() == VT_EMPTY)
188     return 0;
189 
190   int compare_result = 0;
191   if (V_ISARRAY(&other)) {
192     compare_result = Compare(V_ARRAY(&other), ignore_case);
193   } else {
194     compare_result = vector_[0].Compare(other, ignore_case);
195     // If the first element is equal to |other|, and |vector_|
196     // has more than one element, then |vector_| is greater.
197     if (!compare_result && Size() > 1)
198       compare_result = 1;
199   }
200   return compare_result;
201 }
202 
Compare(const VariantVector & other,bool ignore_case) const203 int VariantVector::Compare(const VariantVector& other, bool ignore_case) const {
204   // If the element variant types are different, compare against the types.
205   if (Type() != other.Type())
206     return (Type() < other.Type()) ? (-1) : 1;
207 
208   // Both have an empty variant type so they are the same.
209   if (Type() == VT_EMPTY)
210     return 0;
211 
212   auto iter1 = vector_.begin();
213   auto iter2 = other.vector_.begin();
214   for (; (iter1 != vector_.end()) && (iter2 != other.vector_.end());
215        ++iter1, ++iter2) {
216     int compare_result = iter1->Compare(*iter2, ignore_case);
217     if (compare_result)
218       return compare_result;
219   }
220   // There are more elements in |this|, so |this| is greater than |other|.
221   if (iter1 != vector_.end())
222     return 1;
223   // There are more elements in |other|, so |this| is less than |other|.
224   if (iter2 != other.vector_.end())
225     return -1;
226   return 0;
227 }
228 
Compare(SAFEARRAY * safearray,bool ignore_case) const229 int VariantVector::Compare(SAFEARRAY* safearray, bool ignore_case) const {
230   VARTYPE safearray_vartype;
231   // If we fail to get the element variant type for the SAFEARRAY, then
232   // arbitrarily treat |this| as greater.
233   if (FAILED(SafeArrayGetVartype(safearray, &safearray_vartype)))
234     return 1;
235 
236   // If the element variant types are different, compare against the types.
237   if (Type() != safearray_vartype)
238     return (Type() < safearray_vartype) ? (-1) : 1;
239 
240   ScopedSafearray scoped_safearray(safearray);
241   int compare_result = 0;
242   switch (Type()) {
243     case VT_BOOL:
244       compare_result = CompareAgainstSafearray<VT_BOOL>(
245           vector_, scoped_safearray, ignore_case);
246       break;
247     case VT_I1:
248       compare_result = CompareAgainstSafearray<VT_I1>(vector_, scoped_safearray,
249                                                       ignore_case);
250       break;
251     case VT_UI1:
252       compare_result = CompareAgainstSafearray<VT_UI1>(
253           vector_, scoped_safearray, ignore_case);
254       break;
255     case VT_I2:
256       compare_result = CompareAgainstSafearray<VT_I2>(vector_, scoped_safearray,
257                                                       ignore_case);
258       break;
259     case VT_UI2:
260       compare_result = CompareAgainstSafearray<VT_UI2>(
261           vector_, scoped_safearray, ignore_case);
262       break;
263     case VT_I4:
264       compare_result = CompareAgainstSafearray<VT_I4>(vector_, scoped_safearray,
265                                                       ignore_case);
266       break;
267     case VT_UI4:
268       compare_result = CompareAgainstSafearray<VT_UI4>(
269           vector_, scoped_safearray, ignore_case);
270       break;
271     case VT_I8:
272       compare_result = CompareAgainstSafearray<VT_I8>(vector_, scoped_safearray,
273                                                       ignore_case);
274       break;
275     case VT_UI8:
276       compare_result = CompareAgainstSafearray<VT_UI8>(
277           vector_, scoped_safearray, ignore_case);
278       break;
279     case VT_R4:
280       compare_result = CompareAgainstSafearray<VT_R4>(vector_, scoped_safearray,
281                                                       ignore_case);
282       break;
283     case VT_R8:
284       compare_result = CompareAgainstSafearray<VT_R8>(vector_, scoped_safearray,
285                                                       ignore_case);
286       break;
287     case VT_DATE:
288       compare_result = CompareAgainstSafearray<VT_DATE>(
289           vector_, scoped_safearray, ignore_case);
290       break;
291     case VT_BSTR:
292       compare_result = CompareAgainstSafearray<VT_BSTR>(
293           vector_, scoped_safearray, ignore_case);
294       break;
295     case VT_DISPATCH:
296       compare_result = CompareAgainstSafearray<VT_DISPATCH>(
297           vector_, scoped_safearray, ignore_case);
298       break;
299     case VT_UNKNOWN:
300       compare_result = CompareAgainstSafearray<VT_UNKNOWN>(
301           vector_, scoped_safearray, ignore_case);
302       break;
303     // The default case shouldn't be reachable, but if we added support for more
304     // VARTYPEs to base::win::internal::VariantConverter<> and they were
305     // inserted into a VariantVector then it would be possible to reach the
306     // default case for those new types until implemented.
307     //
308     // Because the switch is against VARTYPE (unsigned short) and not VARENUM,
309     // removing the default case will not result in build warnings/errors if
310     // there are missing cases. It is important that this uses VARTYPE rather
311     // than VARENUM, because in the future we may want to support complex
312     // VARTYPES. For example a value within VT_TYPEMASK that's joined something
313     // outside the typemask like VT_ARRAY or VT_BYREF.
314     default:
315       NOTREACHED();
316   }
317 
318   scoped_safearray.Release();
319   return compare_result;
320 }
321 
322 template <VARTYPE ElementVartype>
CreateAndPopulateSafearray()323 SAFEARRAY* VariantVector::CreateAndPopulateSafearray() {
324   DCHECK(!Empty());
325 
326   ScopedSafearray scoped_safearray(
327       SafeArrayCreateVector(ElementVartype, 0, checked_cast<ULONG>(Size())));
328   if (!scoped_safearray.Get()) {
329     constexpr size_t kElementSize =
330         sizeof(typename internal::VariantConverter<ElementVartype>::Type);
331     base::TerminateBecauseOutOfMemory(sizeof(SAFEARRAY) +
332                                       (Size() * kElementSize));
333   }
334 
335   std::optional<ScopedSafearray::LockScope<ElementVartype>> lock_scope =
336       scoped_safearray.CreateLockScope<ElementVartype>();
337   DCHECK(lock_scope);
338 
339   for (size_t i = 0; i < Size(); ++i) {
340     VARIANT element = vector_[i].Release();
341     (*lock_scope)[i] =
342         internal::VariantConverter<ElementVartype>::RawGet(element);
343   }
344   Reset();
345 
346   return scoped_safearray.Release();
347 }
348 
349 }  // namespace win
350 }  // namespace base
351