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