mirror of
https://code.videolan.org/videolan/vlc
synced 2024-07-29 11:58:24 +02:00
559 lines
14 KiB
C++
559 lines
14 KiB
C++
/*****************************************************************************
|
|
* persiststreaminit.cpp: ActiveX control for VLC
|
|
*****************************************************************************
|
|
* Copyright (C) 2005 the VideoLAN team
|
|
*
|
|
* Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
#include "plugin.h"
|
|
#include "persiststreaminit.h"
|
|
|
|
#include "utils.h"
|
|
#include <map>
|
|
|
|
#include <malloc.h>
|
|
#include <wchar.h>
|
|
|
|
using namespace std;
|
|
|
|
class AxVLCVariant
|
|
{
|
|
|
|
public:
|
|
|
|
AxVLCVariant(void)
|
|
{
|
|
VariantInit(&_v);
|
|
};
|
|
|
|
~AxVLCVariant(void)
|
|
{
|
|
VariantClear(&_v);
|
|
}
|
|
|
|
AxVLCVariant(VARIANTARG &v)
|
|
{
|
|
//VariantInit(&_v);
|
|
//VariantCopy(&_v, &v);
|
|
_v = v;
|
|
};
|
|
|
|
AxVLCVariant(VARIANTARG *v)
|
|
{
|
|
VariantInit(&_v);
|
|
VariantCopy(&_v, v);
|
|
};
|
|
|
|
AxVLCVariant(const AxVLCVariant &vv)
|
|
{
|
|
VariantInit(&_v);
|
|
VariantCopy(&_v, const_cast<VARIANTARG *>(&(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<class AxVLCWSTR, class AxVLCVariant> AxVLCPropertyPair;
|
|
typedef map<class AxVLCWSTR, class AxVLCVariant> 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<LPVOID>(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<VARIANTARG*>((*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<AxVLCPropertyMap::iterator, bool> 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<AxVLCPropertyMap::iterator, bool> 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 )
|
|
return E_POINTER;
|
|
|
|
*pClsID = _p_instance->getClassID();
|
|
|
|
return S_OK;
|
|
};
|
|
|
|
STDMETHODIMP VLCPersistStreamInit::InitNew(void)
|
|
{
|
|
return _p_instance->onInit();
|
|
};
|
|
|
|
STDMETHODIMP VLCPersistStreamInit::Load(LPSTREAM pStm)
|
|
{
|
|
HRESULT result = _p_props->Load(pStm);
|
|
if( FAILED(result) )
|
|
return result;
|
|
|
|
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_INVALIDARG;
|
|
|
|
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 _p_instance->isDirty() ? S_OK : S_FALSE;
|
|
};
|
|
|
|
STDMETHODIMP VLCPersistStreamInit::GetSizeMax(ULARGE_INTEGER *pcbSize)
|
|
{
|
|
pcbSize->HighPart = 0UL;
|
|
pcbSize->LowPart = 4096UL; // just a guess
|
|
|
|
return S_OK;
|
|
};
|
|
|