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