X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=activex%2Fpersiststreaminit.cpp;h=8d41fb2bff5b8a74869281245a8bfec177580392;hb=889d3ddb3dbbd4d4f46f81e0fd5aa97b8f84d8de;hp=0940b29d4880ad1cb9486d1cc1582e37870cb2c4;hpb=1591dec08cacf0168d6008b41671d265264a7a4d;p=vlc diff --git a/activex/persiststreaminit.cpp b/activex/persiststreaminit.cpp index 0940b29d48..8d41fb2bff 100644 --- a/activex/persiststreaminit.cpp +++ b/activex/persiststreaminit.cpp @@ -1,7 +1,7 @@ /***************************************************************************** * persiststreaminit.cpp: ActiveX control for VLC ***************************************************************************** - * Copyright (C) 2005 VideoLAN + * Copyright (C) 2005 the VideoLAN team * * Authors: Damien Fouilleul * @@ -17,14 +17,483 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #include "plugin.h" #include "persiststreaminit.h" +#include "utils.h" +#include + +#include +#include + using namespace std; +class AxVLCVariant +{ + +public: + + AxVLCVariant(void) + { + VariantInit(&_v); + }; + + ~AxVLCVariant(void) + { + VariantClear(&_v); + } + + AxVLCVariant(VARIANTARG &v) + { + VariantInit(&_v); + VariantCopy(&_v, &v); + }; + + AxVLCVariant(VARIANTARG *v) + { + VariantInit(&_v); + VariantCopy(&_v, v); + }; + + AxVLCVariant(const AxVLCVariant &vv) + { + VariantInit(&_v); + VariantCopy(&_v, const_cast(&(vv._v))); + }; + + AxVLCVariant(int i) + { + V_VT(&_v) = VT_I4; + V_I4(&_v) = i; + }; + + AxVLCVariant(BSTR bstr) + { + VARIANT arg; + V_VT(&arg) = VT_BSTR; + V_BSTR(&arg) = bstr; + VariantInit(&_v); + VariantCopy(&_v, &arg); + }; + + inline const VARIANTARG *variantArg(void) const { + return &_v; + } + + inline void swap(AxVLCVariant &v1, AxVLCVariant &v2) + { + VARIANTARG tmp = v1._v; + v1._v = v2._v; + v2._v = tmp; + }; + +private: + + VARIANTARG _v; +}; + +class AxVLCWSTR +{ + +public: + + AxVLCWSTR(void) : _data(NULL) {}; + + virtual ~AxVLCWSTR() + { + if( NULL != _data ) + { + ULONG refcount = InterlockedDecrement(&(_data->refcount)); + if( 0 == refcount ) + CoTaskMemFree(_data); + } + }; + + AxVLCWSTR(LPCWSTR s) + { + if( NULL != s ) + { + size_t len = wcslen(s); + if( len > 0 ) + { + size_t size = len*sizeof(WCHAR); + _data = (struct data *)CoTaskMemAlloc(sizeof(struct data)+size); + if( NULL != _data ) + { + _data->len = len; + _data->refcount = 1; + memcpy(_data->wstr, s, size); + _data->wstr[len]=L'\0'; + return; + } + } + } + _data = NULL; + }; + + AxVLCWSTR(const AxVLCWSTR &s) + { + _data = s._data; + if( NULL != _data ) + InterlockedIncrement(&(_data->refcount)); + }; + + inline bool operator<(const AxVLCWSTR &s) const + { + return compareNoCase(s.wstr()) < 0; + }; + + inline bool operator<(LPCWSTR s) const + { + return compareNoCase(s) < 0; + }; + + inline bool operator==(const AxVLCWSTR &s) const + { + return size() == s.size() ? + (compareNoCase(s.wstr()) == 0) : false; + }; + + inline bool operator==(LPCWSTR s) const + { + return compareNoCase(s) == 0; + }; + + LPCWSTR wstr(void) const + { + return (NULL != _data) ? _data->wstr : NULL; + }; + + size_t size(void) const + { + return (NULL != _data) ? _data->len : 0; + }; + +private: + + inline int compareNoCase(LPCWSTR s) const + { + if( NULL == _data ) + { + return (NULL == s) ? 0 : -1; + } + if( NULL == s ) + return 1; + + return _wcsicmp(_data->wstr, s); + }; + + struct data { + size_t len; + LONG refcount; + wchar_t wstr[1]; + } *_data; +}; + +typedef pair AxVLCPropertyPair; +typedef map AxVLCPropertyMap; + +/////////////////////////// + +class VLCPropertyBag : public IPropertyBag +{ + +public: + + VLCPropertyBag(void) : _i_ref(1) {}; + virtual ~VLCPropertyBag() {}; + + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, void **ppv) + { + if( NULL == ppv ) + return E_POINTER; + if( (IID_IUnknown == riid) + || (IID_IPropertyBag == riid) ) + { + AddRef(); + *ppv = reinterpret_cast(this); + return NOERROR; + } + // standalone object + return E_NOINTERFACE; + }; + + STDMETHODIMP_(ULONG) AddRef(void) + { return InterlockedIncrement(&_i_ref); }; + + STDMETHODIMP_(ULONG) Release(void) + { + ULONG refcount = InterlockedDecrement(&_i_ref); + if( 0 == refcount ) + { + delete this; + return 0; + } + return refcount; + }; + + // IPropertyBag methods + + STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog) + { + if( (NULL == pszPropName) || (NULL == pVar) ) + return E_POINTER; + + AxVLCPropertyMap::const_iterator notfound = _pm.end(); + AxVLCPropertyMap::const_iterator iter = _pm.find(pszPropName); + if( notfound != iter ) + { + VARTYPE vtype = V_VT(pVar); + VARIANTARG v; + VariantInit(&v); + VariantCopy(&v, const_cast((*iter).second.variantArg())); + if( (V_VT(&v) != vtype) && FAILED(VariantChangeType(&v, &v, 0, vtype)) ) + { + VariantClear(&v); + return E_FAIL; + } + *pVar = v; + return S_OK; + } + else + return E_INVALIDARG; + }; + + STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar) + { + if( (NULL == pszPropName) || (NULL == pVar) ) + return E_POINTER; + + AxVLCPropertyPair val(pszPropName, pVar); + pair p = _pm.insert(val); + if( false == p.second ) + // replace existing key value + (*p.first).second = val.second; + return S_OK; + }; + + // custom methods + + HRESULT Load(LPSTREAM pStm) + { + if( NULL == pStm ) + return E_INVALIDARG; + + HRESULT result; + + AxVLCPropertyPair *val; + result = ReadProperty(pStm, &val); + if( SUCCEEDED(result) ) + { + if( (val->first == L"(Count)") && (VT_I4 == V_VT(val->second.variantArg())) ) + { + size_t count = V_I4(val->second.variantArg()); + delete val; + while( count-- ) + { + result = ReadProperty(pStm, &val); + if( FAILED(result) ) + return result; + + pair p = _pm.insert(*val); + if( false == p.second ) + // replace existing key value + (*p.first).second = val->second; + delete val; + } + } + } + return result; + }; + + HRESULT Save(LPSTREAM pStm) + { + if( NULL == pStm ) + return E_INVALIDARG; + + HRESULT result; + + AxVLCPropertyPair header(L"(Count)", _pm.size()); + result = WriteProperty(pStm, header); + if( SUCCEEDED(result) ) + { + AxVLCPropertyMap::const_iterator iter = _pm.begin(); + AxVLCPropertyMap::const_iterator end = _pm.end(); + + while( iter != end ) + { + result = WriteProperty(pStm, *(iter++)); + if( FAILED(result) ) + return result; + } + } + return result; + }; + + BOOL IsEmpty() + { + return _pm.size() == 0; + } + +private: + + HRESULT WriteProperty(LPSTREAM pStm, const AxVLCPropertyPair &prop) + { + HRESULT result; + + const AxVLCWSTR propName = prop.first; + + ULONG len = propName.size(); + + if( 0 == len ) + return E_INVALIDARG; + + result = pStm->Write(&len, sizeof(len), NULL); + if( FAILED(result) ) + return result; + + result = pStm->Write(propName.wstr(), len*sizeof(WCHAR), NULL); + if( FAILED(result) ) + return result; + + const VARIANTARG *propValue = prop.second.variantArg(); + VARTYPE vtype = V_VT(propValue); + switch( vtype ) + { + case VT_BOOL: + result = pStm->Write(&vtype, sizeof(vtype), NULL); + if( FAILED(result) ) + return result; + result = pStm->Write(&V_BOOL(propValue), sizeof(V_BOOL(propValue)), NULL); + if( FAILED(result) ) + return result; + break; + case VT_I4: + result = pStm->Write(&vtype, sizeof(vtype), NULL); + if( FAILED(result) ) + return result; + result = pStm->Write(&V_I4(propValue), sizeof(V_I4(propValue)), NULL); + if( FAILED(result) ) + return result; + break; + case VT_BSTR: + result = pStm->Write(&vtype, sizeof(vtype), NULL); + if( FAILED(result) ) + return result; + len = SysStringLen(V_BSTR(propValue)); + result = pStm->Write(&len, sizeof(len), NULL); + if( FAILED(result) ) + return result; + if( len > 0 ) + { + result = pStm->Write(V_BSTR(propValue), len*sizeof(OLECHAR), NULL); + if( FAILED(result) ) + return result; + } + break; + default: + vtype = VT_EMPTY; + result = pStm->Write(&vtype, sizeof(vtype), NULL); + if( FAILED(result) ) + return result; + } + return result; + }; + + HRESULT ReadProperty(LPSTREAM pStm, AxVLCPropertyPair **prop) + { + HRESULT result; + + ULONG len; + + result = pStm->Read(&len, sizeof(len), NULL); + if( FAILED(result) ) + return result; + + if( 0 == len ) + return E_INVALIDARG; + + LPWSTR propName = (LPOLESTR)::alloca((len+1)*sizeof(WCHAR)); + if( NULL == propName ) + return E_OUTOFMEMORY; + + result = pStm->Read(propName, len*sizeof(WCHAR), NULL); + if( FAILED(result) ) + return result; + + propName[len] = L'\0'; + + VARIANTARG propValue; + + VARTYPE vtype; + result = pStm->Read(&vtype, sizeof(vtype), NULL); + if( FAILED(result) ) + return result; + + switch( vtype ) + { + case VT_BOOL: + V_VT(&propValue) = vtype; + result = pStm->Read(&V_BOOL(&propValue), sizeof(V_BOOL(&propValue)), NULL); + if( FAILED(result) ) + return result; + break; + case VT_I4: + V_VT(&propValue) = vtype; + result = pStm->Read(&V_I4(&propValue), sizeof(V_I4(&propValue)), NULL); + if( FAILED(result) ) + return result; + break; + case VT_BSTR: + V_VT(&propValue) = vtype; + result = pStm->Read(&len, sizeof(len), NULL); + if( FAILED(result) ) + return result; + + V_BSTR(&propValue) = NULL; + if( len > 0 ) + { + V_BSTR(&propValue) = SysAllocStringLen(NULL, len); + if( NULL == V_BSTR(&propValue) ) + return E_OUTOFMEMORY; + + result = pStm->Read(V_BSTR(&propValue), len*sizeof(OLECHAR), NULL); + if( FAILED(result) ) + { + SysFreeString(V_BSTR(&propValue)); + return result; + } + } + break; + default: + VariantInit(&propValue); + } + + *prop = new AxVLCPropertyPair(propName, propValue); + + return S_OK; + }; + + AxVLCPropertyMap _pm; + LONG _i_ref; +}; + +/////////////////////////// + +VLCPersistStreamInit::VLCPersistStreamInit(VLCPlugin *p_instance) : _p_instance(p_instance) +{ + _p_props = new VLCPropertyBag(); +}; + +VLCPersistStreamInit::~VLCPersistStreamInit() +{ + _p_props->Release(); +}; + STDMETHODIMP VLCPersistStreamInit::GetClassID(LPCLSID pClsID) { if( NULL == pClsID ) @@ -37,33 +506,51 @@ STDMETHODIMP VLCPersistStreamInit::GetClassID(LPCLSID pClsID) STDMETHODIMP VLCPersistStreamInit::InitNew(void) { - return _p_instance->onInit(TRUE); + return _p_instance->onInit(); }; STDMETHODIMP VLCPersistStreamInit::Load(LPSTREAM pStm) { - if( NULL == pStm ) - return E_POINTER; + HRESULT result = _p_props->Load(pStm); + if( FAILED(result) ) + return result; - return _p_instance->onInit(TRUE); + LPPERSISTPROPERTYBAG pPersistPropBag; + if( FAILED(QueryInterface(IID_IPersistPropertyBag, (void**)&pPersistPropBag)) ) + return E_FAIL; + + result = pPersistPropBag->Load(_p_props, NULL); + pPersistPropBag->Release(); + + return result; }; STDMETHODIMP VLCPersistStreamInit::Save(LPSTREAM pStm, BOOL fClearDirty) { if( NULL == pStm ) - return E_POINTER; + return E_INVALIDARG; - return S_OK; + LPPERSISTPROPERTYBAG pPersistPropBag; + if( FAILED(QueryInterface(IID_IPersistPropertyBag, (void**)&pPersistPropBag)) ) + return E_FAIL; + + HRESULT result = pPersistPropBag->Save(_p_props, fClearDirty, _p_props->IsEmpty()); + pPersistPropBag->Release(); + if( FAILED(result) ) + return result; + + return _p_props->Save(pStm); }; STDMETHODIMP VLCPersistStreamInit::IsDirty(void) { - return S_FALSE; + return _p_instance->isDirty() ? S_OK : S_FALSE; }; STDMETHODIMP VLCPersistStreamInit::GetSizeMax(ULARGE_INTEGER *pcbSize) { - pcbSize->QuadPart = 0ULL; + pcbSize->HighPart = 0UL; + pcbSize->LowPart = 16384UL; // just a guess return S_OK; };