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