| // 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 |