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