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