|  | // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/win/scoped_variant.h" | 
|  |  | 
|  | #include "base/logging.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace win { | 
|  |  | 
|  | // Global, const instance of an empty variant. | 
|  | const VARIANT ScopedVariant::kEmptyVariant = {{{VT_EMPTY}}}; | 
|  |  | 
|  | ScopedVariant::~ScopedVariant() { | 
|  | static_assert(sizeof(ScopedVariant) == sizeof(VARIANT), "ScopedVariantSize"); | 
|  | ::VariantClear(&var_); | 
|  | } | 
|  |  | 
|  | ScopedVariant::ScopedVariant(const wchar_t* str) { | 
|  | var_.vt = VT_EMPTY; | 
|  | Set(str); | 
|  | } | 
|  |  | 
|  | ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) { | 
|  | var_.vt = VT_BSTR; | 
|  | var_.bstrVal = ::SysAllocStringLen(str, length); | 
|  | } | 
|  |  | 
|  | ScopedVariant::ScopedVariant(int value, VARTYPE vt) { | 
|  | var_.vt = vt; | 
|  | var_.lVal = value; | 
|  | } | 
|  |  | 
|  | ScopedVariant::ScopedVariant(double value, VARTYPE vt) { | 
|  | DCHECK(vt == VT_R8 || vt == VT_DATE); | 
|  | var_.vt = vt; | 
|  | var_.dblVal = value; | 
|  | } | 
|  |  | 
|  | ScopedVariant::ScopedVariant(IDispatch* dispatch) { | 
|  | var_.vt = VT_EMPTY; | 
|  | Set(dispatch); | 
|  | } | 
|  |  | 
|  | ScopedVariant::ScopedVariant(IUnknown* unknown) { | 
|  | var_.vt = VT_EMPTY; | 
|  | Set(unknown); | 
|  | } | 
|  |  | 
|  | ScopedVariant::ScopedVariant(SAFEARRAY* safearray) { | 
|  | var_.vt = VT_EMPTY; | 
|  | Set(safearray); | 
|  | } | 
|  |  | 
|  | ScopedVariant::ScopedVariant(const VARIANT& var) { | 
|  | var_.vt = VT_EMPTY; | 
|  | Set(var); | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Reset(const VARIANT& var) { | 
|  | if (&var != &var_) { | 
|  | ::VariantClear(&var_); | 
|  | var_ = var; | 
|  | } | 
|  | } | 
|  |  | 
|  | VARIANT ScopedVariant::Release() { | 
|  | VARIANT var = var_; | 
|  | var_.vt = VT_EMPTY; | 
|  | return var; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Swap(ScopedVariant& var) { | 
|  | VARIANT tmp = var_; | 
|  | var_ = var.var_; | 
|  | var.var_ = tmp; | 
|  | } | 
|  |  | 
|  | VARIANT* ScopedVariant::Receive() { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt; | 
|  | return &var_; | 
|  | } | 
|  |  | 
|  | VARIANT ScopedVariant::Copy() const { | 
|  | VARIANT ret = {{{VT_EMPTY}}}; | 
|  | ::VariantCopy(&ret, &var_); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const { | 
|  | ULONG flags = ignore_case ? NORM_IGNORECASE : 0; | 
|  | HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var), | 
|  | LOCALE_USER_DEFAULT, flags); | 
|  | int ret = 0; | 
|  |  | 
|  | switch (hr) { | 
|  | case VARCMP_LT: | 
|  | ret = -1; | 
|  | break; | 
|  |  | 
|  | case VARCMP_GT: | 
|  | case VARCMP_NULL: | 
|  | ret = 1; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | // Equal. | 
|  | break; | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(const wchar_t* str) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_BSTR; | 
|  | var_.bstrVal = ::SysAllocString(str); | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(int8_t i8) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_I1; | 
|  | var_.cVal = i8; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(uint8_t ui8) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_UI1; | 
|  | var_.bVal = ui8; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(int16_t i16) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_I2; | 
|  | var_.iVal = i16; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(uint16_t ui16) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_UI2; | 
|  | var_.uiVal = ui16; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(int32_t i32) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_I4; | 
|  | var_.lVal = i32; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(uint32_t ui32) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_UI4; | 
|  | var_.ulVal = ui32; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(int64_t i64) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_I8; | 
|  | var_.llVal = i64; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(uint64_t ui64) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_UI8; | 
|  | var_.ullVal = ui64; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(float r32) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_R4; | 
|  | var_.fltVal = r32; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(double r64) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_R8; | 
|  | var_.dblVal = r64; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::SetDate(DATE date) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_DATE; | 
|  | var_.date = date; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(IDispatch* disp) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_DISPATCH; | 
|  | var_.pdispVal = disp; | 
|  | if (disp) | 
|  | disp->AddRef(); | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(bool b) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_BOOL; | 
|  | var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE; | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(IUnknown* unk) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | var_.vt = VT_UNKNOWN; | 
|  | var_.punkVal = unk; | 
|  | if (unk) | 
|  | unk->AddRef(); | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(SAFEARRAY* array) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) { | 
|  | var_.vt |= VT_ARRAY; | 
|  | var_.parray = array; | 
|  | } else { | 
|  | DCHECK(!array) << "Unable to determine safearray vartype"; | 
|  | var_.vt = VT_EMPTY; | 
|  | } | 
|  | } | 
|  |  | 
|  | void ScopedVariant::Set(const VARIANT& var) { | 
|  | DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; | 
|  | if (FAILED(::VariantCopy(&var_, &var))) { | 
|  | DLOG(ERROR) << "VariantCopy failed"; | 
|  | var_.vt = VT_EMPTY; | 
|  | } | 
|  | } | 
|  |  | 
|  | ScopedVariant& ScopedVariant::operator=(const VARIANT& var) { | 
|  | if (&var != &var_) { | 
|  | VariantClear(&var_); | 
|  | Set(var); | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | bool ScopedVariant::IsLeakableVarType(VARTYPE vt) { | 
|  | bool leakable = false; | 
|  | switch (vt & VT_TYPEMASK) { | 
|  | case VT_BSTR: | 
|  | case VT_DISPATCH: | 
|  | // we treat VT_VARIANT as leakable to err on the safe side. | 
|  | case VT_VARIANT: | 
|  | case VT_UNKNOWN: | 
|  | case VT_SAFEARRAY: | 
|  |  | 
|  | // very rarely used stuff (if ever): | 
|  | case VT_VOID: | 
|  | case VT_PTR: | 
|  | case VT_CARRAY: | 
|  | case VT_USERDEFINED: | 
|  | case VT_LPSTR: | 
|  | case VT_LPWSTR: | 
|  | case VT_RECORD: | 
|  | case VT_INT_PTR: | 
|  | case VT_UINT_PTR: | 
|  | case VT_FILETIME: | 
|  | case VT_BLOB: | 
|  | case VT_STREAM: | 
|  | case VT_STORAGE: | 
|  | case VT_STREAMED_OBJECT: | 
|  | case VT_STORED_OBJECT: | 
|  | case VT_BLOB_OBJECT: | 
|  | case VT_VERSIONED_STREAM: | 
|  | case VT_BSTR_BLOB: | 
|  | leakable = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!leakable && (vt & VT_ARRAY) != 0) { | 
|  | leakable = true; | 
|  | } | 
|  |  | 
|  | return leakable; | 
|  | } | 
|  |  | 
|  | }  // namespace win | 
|  | }  // namespace base |