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