Flutter Engine
The Flutter Engine
scoped_variant.cc
Go to the documentation of this file.
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <propvarutil.h>
8#include <wrl/client.h>
9
10#include <algorithm>
11#include <functional>
12
13#include "base/logging.h"
16
17namespace base {
18namespace win {
19
20// Global, const instance of an empty variant.
21const VARIANT ScopedVariant::kEmptyVariant = {{{VT_EMPTY}}};
22
24 var_.vt = VT_EMPTY;
25 Reset(var.Release());
26}
27
29 static_assert(sizeof(ScopedVariant) == sizeof(VARIANT), "ScopedVariantSize");
30 ::VariantClear(&var_);
31}
32
33ScopedVariant::ScopedVariant(const wchar_t* str) {
34 var_.vt = VT_EMPTY;
35 Set(str);
36}
37
39 var_.vt = VT_BSTR;
40 var_.bstrVal = ::SysAllocStringLen(str, length);
41}
42
44 var_.vt = vt;
45 var_.lVal = value;
46}
47
49 var_.vt = VT_I4;
50 var_.lVal = value;
51}
52
54 var_.vt = VT_BOOL;
55 var_.boolVal = value ? VARIANT_TRUE : VARIANT_FALSE;
56}
57
59 BASE_DCHECK(vt == VT_R8 || vt == VT_DATE);
60 var_.vt = vt;
61 var_.dblVal = value;
62}
63
64ScopedVariant::ScopedVariant(IDispatch* dispatch) {
65 var_.vt = VT_EMPTY;
66 Set(dispatch);
67}
68
69ScopedVariant::ScopedVariant(IUnknown* unknown) {
70 var_.vt = VT_EMPTY;
71 Set(unknown);
72}
73
74ScopedVariant::ScopedVariant(SAFEARRAY* safearray) {
75 var_.vt = VT_EMPTY;
76 Set(safearray);
77}
78
80 var_.vt = VT_EMPTY;
81 Set(var);
82}
83
84void ScopedVariant::Reset(const VARIANT& var) {
85 if (&var != &var_) {
86 ::VariantClear(&var_);
87 var_ = var;
88 }
89}
90
92 VARIANT var = var_;
93 var_.vt = VT_EMPTY;
94 return var;
95}
96
98 VARIANT tmp = var_;
99 var_ = var.var_;
100 var.var_ = tmp;
101}
102
104 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt;
105 return &var_;
106}
107
109 VARIANT ret = {{{VT_EMPTY}}};
110 ::VariantCopy(&ret, &var_);
111 return ret;
112}
113
114int ScopedVariant::Compare(const VARIANT& other, bool ignore_case) const {
115 BASE_DCHECK(!V_ISARRAY(&var_))
116 << "Comparison is not supported when |this| owns a SAFEARRAY";
117 BASE_DCHECK(!V_ISARRAY(&other))
118 << "Comparison is not supported when |other| owns a SAFEARRAY";
119
120 const bool this_is_empty = var_.vt == VT_EMPTY || var_.vt == VT_NULL;
121 const bool other_is_empty = other.vt == VT_EMPTY || other.vt == VT_NULL;
122
123 // 1. VT_NULL and VT_EMPTY is always considered less-than any other VARTYPE.
124 if (this_is_empty)
125 return other_is_empty ? 0 : -1;
126 if (other_is_empty)
127 return 1;
128
129 // 2. If both VARIANTS have either VT_UNKNOWN or VT_DISPATCH even if the
130 // VARTYPEs do not match, the address of its IID_IUnknown is compared to
131 // guarantee a logical ordering even though it is not a meaningful order.
132 // e.g. (a.Compare(b) != b.Compare(a)) unless (a == b).
133 const bool this_is_unknown = var_.vt == VT_UNKNOWN || var_.vt == VT_DISPATCH;
134 const bool other_is_unknown =
135 other.vt == VT_UNKNOWN || other.vt == VT_DISPATCH;
136 if (this_is_unknown && other_is_unknown) {
137 // https://docs.microsoft.com/en-us/windows/win32/com/rules-for-implementing-queryinterface
138 // Query IID_IUnknown to determine whether the two variants point
139 // to the same instance of an object
140 Microsoft::WRL::ComPtr<IUnknown> this_unknown;
141 Microsoft::WRL::ComPtr<IUnknown> other_unknown;
142 V_UNKNOWN(&var_)->QueryInterface(IID_PPV_ARGS(&this_unknown));
143 V_UNKNOWN(&other)->QueryInterface(IID_PPV_ARGS(&other_unknown));
144 if (this_unknown.Get() == other_unknown.Get())
145 return 0;
146 // std::less for any pointer type yields a strict total order even if the
147 // built-in operator< does not.
148 return std::less<>{}(this_unknown.Get(), other_unknown.Get()) ? -1 : 1;
149 }
150
151 // 3. If the VARTYPEs do not match, then the value of the VARTYPE is compared.
152 if (V_VT(&var_) != V_VT(&other))
153 return (V_VT(&var_) < V_VT(&other)) ? -1 : 1;
154
155 const VARTYPE shared_vartype = V_VT(&var_);
156 // 4. Comparing VT_BSTR values is a lexicographical comparison of the contents
157 // of the BSTR, taking into account |ignore_case|.
158 if (shared_vartype == VT_BSTR) {
159 ULONG flags = ignore_case ? NORM_IGNORECASE : 0;
160 HRESULT hr =
161 ::VarBstrCmp(V_BSTR(&var_), V_BSTR(&other), LOCALE_USER_DEFAULT, flags);
162 BASE_DCHECK(SUCCEEDED(hr) && hr != VARCMP_NULL)
163 << "unsupported variant comparison: " << var_.vt << " and " << other.vt;
164
165 switch (hr) {
166 case VARCMP_LT:
167 return -1;
168 case VARCMP_GT:
169 case VARCMP_NULL:
170 return 1;
171 default:
172 return 0;
173 }
174 }
175
176 // 5. Otherwise returns the lexicographical comparison of the values held by
177 // the two VARIANTS that share the same VARTYPE.
178 return ::VariantCompare(var_, other);
179}
180
181void ScopedVariant::Set(const wchar_t* str) {
182 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
183 var_.vt = VT_BSTR;
184 var_.bstrVal = ::SysAllocString(str);
185}
186
187void ScopedVariant::Set(int8_t i8) {
188 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
189 var_.vt = VT_I1;
190 var_.cVal = i8;
191}
192
193void ScopedVariant::Set(uint8_t ui8) {
194 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
195 var_.vt = VT_UI1;
196 var_.bVal = ui8;
197}
198
199void ScopedVariant::Set(int16_t i16) {
200 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
201 var_.vt = VT_I2;
202 var_.iVal = i16;
203}
204
205void ScopedVariant::Set(uint16_t ui16) {
206 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
207 var_.vt = VT_UI2;
208 var_.uiVal = ui16;
209}
210
211void ScopedVariant::Set(int32_t i32) {
212 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
213 var_.vt = VT_I4;
214 var_.lVal = i32;
215}
216
217void ScopedVariant::Set(uint32_t ui32) {
218 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
219 var_.vt = VT_UI4;
220 var_.ulVal = ui32;
221}
222
223void ScopedVariant::Set(int64_t i64) {
224 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
225 var_.vt = VT_I8;
226 var_.llVal = i64;
227}
228
229void ScopedVariant::Set(uint64_t ui64) {
230 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
231 var_.vt = VT_UI8;
232 var_.ullVal = ui64;
233}
234
235void ScopedVariant::Set(float r32) {
236 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
237 var_.vt = VT_R4;
238 var_.fltVal = r32;
239}
240
241void ScopedVariant::Set(double r64) {
242 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
243 var_.vt = VT_R8;
244 var_.dblVal = r64;
245}
246
247void ScopedVariant::SetDate(DATE date) {
248 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
249 var_.vt = VT_DATE;
250 var_.date = date;
251}
252
253void ScopedVariant::Set(IDispatch* disp) {
254 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
255 var_.vt = VT_DISPATCH;
256 var_.pdispVal = disp;
257 if (disp)
258 disp->AddRef();
259}
260
262 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
263 var_.vt = VT_BOOL;
264 var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
265}
266
267void ScopedVariant::Set(IUnknown* unk) {
268 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
269 var_.vt = VT_UNKNOWN;
270 var_.punkVal = unk;
271 if (unk)
272 unk->AddRef();
273}
274
275void ScopedVariant::Set(SAFEARRAY* array) {
276 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
277 if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) {
278 var_.vt |= VT_ARRAY;
279 var_.parray = array;
280 } else {
281 BASE_DCHECK(!array) << "Unable to determine safearray vartype";
282 var_.vt = VT_EMPTY;
283 }
284}
285
286void ScopedVariant::Set(const VARIANT& var) {
287 BASE_DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
288 if (FAILED(::VariantCopy(&var_, &var))) {
289 BASE_DLOG() << "Error: VariantCopy failed";
290 var_.vt = VT_EMPTY;
291 }
292}
293
295 if (var.ptr() != &var_)
296 Reset(var.Release());
297 return *this;
298}
299
301 if (&var != &var_) {
302 VariantClear(&var_);
303 Set(var);
304 }
305 return *this;
306}
307
309 bool leakable = false;
310 switch (vt & VT_TYPEMASK) {
311 case VT_BSTR:
312 case VT_DISPATCH:
313 // we treat VT_VARIANT as leakable to err on the safe side.
314 case VT_VARIANT:
315 case VT_UNKNOWN:
316 case VT_SAFEARRAY:
317
318 // very rarely used stuff (if ever):
319 case VT_VOID:
320 case VT_PTR:
321 case VT_CARRAY:
322 case VT_USERDEFINED:
323 case VT_LPSTR:
324 case VT_LPWSTR:
325 case VT_RECORD:
326 case VT_INT_PTR:
327 case VT_UINT_PTR:
328 case VT_FILETIME:
329 case VT_BLOB:
330 case VT_STREAM:
331 case VT_STORAGE:
332 case VT_STREAMED_OBJECT:
333 case VT_STORED_OBJECT:
334 case VT_BLOB_OBJECT:
335 case VT_VERSIONED_STREAM:
336 case VT_BSTR_BLOB:
337 leakable = true;
338 break;
339 }
340
341 if (!leakable && (vt & VT_ARRAY) != 0) {
342 leakable = true;
343 }
344
345 return leakable;
346}
347
348} // namespace win
349} // namespace base
static const VARIANT kEmptyVariant
ScopedVariant & operator=(ScopedVariant &&var)
static bool IsLeakableVarType(VARTYPE vt)
void Set(const wchar_t *str)
void Reset(const VARIANT &var=kEmptyVariant)
int Compare(const VARIANT &other, bool ignore_case=false) const
void Swap(ScopedVariant &var)
static bool b
FlutterSemanticsFlag flags
uint8_t value
size_t length
#define BASE_DCHECK(condition)
Definition: logging.h:63
#define BASE_DLOG()
Definition: logging.h:62
#define SUCCEEDED(hr)
unsigned int UINT
Definition: windows_types.h:32
DWORD ULONG
Definition: windows_types.h:40
#define FAILED(hr)