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