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 
5 #include "base/win/scoped_variant.h"
6 
7 #include "base/logging.h"
8 
9 namespace base {
10 namespace win {
11 
12 // Global, const instance of an empty variant.
13 const VARIANT ScopedVariant::kEmptyVariant = {{{VT_EMPTY}}};
14 
ScopedVariant(ScopedVariant && var)15 ScopedVariant::ScopedVariant(ScopedVariant&& var) {
16   var_.vt = VT_EMPTY;
17   Reset(var.Release());
18 }
19 
~ScopedVariant()20 ScopedVariant::~ScopedVariant() {
21   static_assert(sizeof(ScopedVariant) == sizeof(VARIANT), "ScopedVariantSize");
22   ::VariantClear(&var_);
23 }
24 
ScopedVariant(const wchar_t * str)25 ScopedVariant::ScopedVariant(const wchar_t* str) {
26   var_.vt = VT_EMPTY;
27   Set(str);
28 }
29 
ScopedVariant(const wchar_t * str,UINT length)30 ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) {
31   var_.vt = VT_BSTR;
32   var_.bstrVal = ::SysAllocStringLen(str, length);
33 }
34 
ScopedVariant(long value,VARTYPE vt)35 ScopedVariant::ScopedVariant(long value, VARTYPE vt) {
36   var_.vt = vt;
37   var_.lVal = value;
38 }
39 
ScopedVariant(int value)40 ScopedVariant::ScopedVariant(int value) {
41   var_.vt = VT_I4;
42   var_.lVal = value;
43 }
44 
ScopedVariant(bool value)45 ScopedVariant::ScopedVariant(bool value) {
46   var_.vt = VT_BOOL;
47   var_.boolVal = value ? VARIANT_TRUE : VARIANT_FALSE;
48 }
49 
ScopedVariant(double value,VARTYPE vt)50 ScopedVariant::ScopedVariant(double value, VARTYPE vt) {
51   DCHECK(vt == VT_R8 || vt == VT_DATE);
52   var_.vt = vt;
53   var_.dblVal = value;
54 }
55 
ScopedVariant(IDispatch * dispatch)56 ScopedVariant::ScopedVariant(IDispatch* dispatch) {
57   var_.vt = VT_EMPTY;
58   Set(dispatch);
59 }
60 
ScopedVariant(IUnknown * unknown)61 ScopedVariant::ScopedVariant(IUnknown* unknown) {
62   var_.vt = VT_EMPTY;
63   Set(unknown);
64 }
65 
ScopedVariant(SAFEARRAY * safearray)66 ScopedVariant::ScopedVariant(SAFEARRAY* safearray) {
67   var_.vt = VT_EMPTY;
68   Set(safearray);
69 }
70 
ScopedVariant(const VARIANT & var)71 ScopedVariant::ScopedVariant(const VARIANT& var) {
72   var_.vt = VT_EMPTY;
73   Set(var);
74 }
75 
Reset(const VARIANT & var)76 void ScopedVariant::Reset(const VARIANT& var) {
77   if (&var != &var_) {
78     ::VariantClear(&var_);
79     var_ = var;
80   }
81 }
82 
Release()83 VARIANT ScopedVariant::Release() {
84   VARIANT var = var_;
85   var_.vt = VT_EMPTY;
86   return var;
87 }
88 
Swap(ScopedVariant & var)89 void ScopedVariant::Swap(ScopedVariant& var) {
90   VARIANT tmp = var_;
91   var_ = var.var_;
92   var.var_ = tmp;
93 }
94 
Receive()95 VARIANT* ScopedVariant::Receive() {
96   DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt;
97   return &var_;
98 }
99 
Copy() const100 VARIANT ScopedVariant::Copy() const {
101   VARIANT ret = {{{VT_EMPTY}}};
102   ::VariantCopy(&ret, &var_);
103   return ret;
104 }
105 
Compare(const VARIANT & var,bool ignore_case) const106 int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const {
107   ULONG flags = ignore_case ? NORM_IGNORECASE : 0;
108   HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var),
109                         LOCALE_USER_DEFAULT, flags);
110   DCHECK(SUCCEEDED(hr) && hr != VARCMP_NULL)
111       << "unsupported variant comparison: " << var_.vt << " and " << var.vt;
112 
113   switch (hr) {
114     case VARCMP_LT:
115       return -1;
116     case VARCMP_GT:
117     case VARCMP_NULL:
118       return 1;
119     default:
120       return 0;
121   }
122 }
123 
Set(const wchar_t * str)124 void ScopedVariant::Set(const wchar_t* str) {
125   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
126   var_.vt = VT_BSTR;
127   var_.bstrVal = ::SysAllocString(str);
128 }
129 
Set(int8_t i8)130 void ScopedVariant::Set(int8_t i8) {
131   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
132   var_.vt = VT_I1;
133   var_.cVal = i8;
134 }
135 
Set(uint8_t ui8)136 void ScopedVariant::Set(uint8_t ui8) {
137   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
138   var_.vt = VT_UI1;
139   var_.bVal = ui8;
140 }
141 
Set(int16_t i16)142 void ScopedVariant::Set(int16_t i16) {
143   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
144   var_.vt = VT_I2;
145   var_.iVal = i16;
146 }
147 
Set(uint16_t ui16)148 void ScopedVariant::Set(uint16_t ui16) {
149   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
150   var_.vt = VT_UI2;
151   var_.uiVal = ui16;
152 }
153 
Set(int32_t i32)154 void ScopedVariant::Set(int32_t i32) {
155   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
156   var_.vt = VT_I4;
157   var_.lVal = i32;
158 }
159 
Set(uint32_t ui32)160 void ScopedVariant::Set(uint32_t ui32) {
161   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
162   var_.vt = VT_UI4;
163   var_.ulVal = ui32;
164 }
165 
Set(int64_t i64)166 void ScopedVariant::Set(int64_t i64) {
167   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
168   var_.vt = VT_I8;
169   var_.llVal = i64;
170 }
171 
Set(uint64_t ui64)172 void ScopedVariant::Set(uint64_t ui64) {
173   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
174   var_.vt = VT_UI8;
175   var_.ullVal = ui64;
176 }
177 
Set(float r32)178 void ScopedVariant::Set(float r32) {
179   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
180   var_.vt = VT_R4;
181   var_.fltVal = r32;
182 }
183 
Set(double r64)184 void ScopedVariant::Set(double r64) {
185   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
186   var_.vt = VT_R8;
187   var_.dblVal = r64;
188 }
189 
SetDate(DATE date)190 void ScopedVariant::SetDate(DATE date) {
191   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
192   var_.vt = VT_DATE;
193   var_.date = date;
194 }
195 
Set(IDispatch * disp)196 void ScopedVariant::Set(IDispatch* disp) {
197   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
198   var_.vt = VT_DISPATCH;
199   var_.pdispVal = disp;
200   if (disp)
201     disp->AddRef();
202 }
203 
Set(bool b)204 void ScopedVariant::Set(bool b) {
205   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
206   var_.vt = VT_BOOL;
207   var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
208 }
209 
Set(IUnknown * unk)210 void ScopedVariant::Set(IUnknown* unk) {
211   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
212   var_.vt = VT_UNKNOWN;
213   var_.punkVal = unk;
214   if (unk)
215     unk->AddRef();
216 }
217 
Set(SAFEARRAY * array)218 void ScopedVariant::Set(SAFEARRAY* array) {
219   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
220   if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) {
221     var_.vt |= VT_ARRAY;
222     var_.parray = array;
223   } else {
224     DCHECK(!array) << "Unable to determine safearray vartype";
225     var_.vt = VT_EMPTY;
226   }
227 }
228 
Set(const VARIANT & var)229 void ScopedVariant::Set(const VARIANT& var) {
230   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
231   if (FAILED(::VariantCopy(&var_, &var))) {
232     DLOG(ERROR) << "VariantCopy failed";
233     var_.vt = VT_EMPTY;
234   }
235 }
236 
operator =(ScopedVariant && var)237 ScopedVariant& ScopedVariant::operator=(ScopedVariant&& var) {
238   if (var.ptr() != &var_)
239     Reset(var.Release());
240   return *this;
241 }
242 
operator =(const VARIANT & var)243 ScopedVariant& ScopedVariant::operator=(const VARIANT& var) {
244   if (&var != &var_) {
245     VariantClear(&var_);
246     Set(var);
247   }
248   return *this;
249 }
250 
IsLeakableVarType(VARTYPE vt)251 bool ScopedVariant::IsLeakableVarType(VARTYPE vt) {
252   bool leakable = false;
253   switch (vt & VT_TYPEMASK) {
254     case VT_BSTR:
255     case VT_DISPATCH:
256     // we treat VT_VARIANT as leakable to err on the safe side.
257     case VT_VARIANT:
258     case VT_UNKNOWN:
259     case VT_SAFEARRAY:
260 
261     // very rarely used stuff (if ever):
262     case VT_VOID:
263     case VT_PTR:
264     case VT_CARRAY:
265     case VT_USERDEFINED:
266     case VT_LPSTR:
267     case VT_LPWSTR:
268     case VT_RECORD:
269     case VT_INT_PTR:
270     case VT_UINT_PTR:
271     case VT_FILETIME:
272     case VT_BLOB:
273     case VT_STREAM:
274     case VT_STORAGE:
275     case VT_STREAMED_OBJECT:
276     case VT_STORED_OBJECT:
277     case VT_BLOB_OBJECT:
278     case VT_VERSIONED_STREAM:
279     case VT_BSTR_BLOB:
280       leakable = true;
281       break;
282   }
283 
284   if (!leakable && (vt & VT_ARRAY) != 0) {
285     leakable = true;
286   }
287 
288   return leakable;
289 }
290 
291 }  // namespace win
292 }  // namespace base
293