]> git.sesse.net Git - vlc/blob - activex/persiststreaminit.cpp
8d41fb2bff5b8a74869281245a8bfec177580392
[vlc] / activex / persiststreaminit.cpp
1 /*****************************************************************************
2  * persiststreaminit.cpp: ActiveX control for VLC
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  *
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #include "plugin.h"
24 #include "persiststreaminit.h"
25
26 #include "utils.h"
27 #include <map>
28
29 #include <malloc.h>
30 #include <wchar.h>
31
32 using namespace std;
33
34 class AxVLCVariant 
35 {
36
37 public:
38
39     AxVLCVariant(void)
40     {
41         VariantInit(&_v);
42     };
43
44     ~AxVLCVariant(void)
45     {
46         VariantClear(&_v);
47     }
48
49     AxVLCVariant(VARIANTARG &v)
50     {
51         VariantInit(&_v);
52         VariantCopy(&_v, &v);
53     };
54
55     AxVLCVariant(VARIANTARG *v)
56     {
57         VariantInit(&_v);
58         VariantCopy(&_v, v);
59     };
60
61     AxVLCVariant(const AxVLCVariant &vv)
62     {
63         VariantInit(&_v);
64         VariantCopy(&_v, const_cast<VARIANTARG *>(&(vv._v)));
65     };
66
67     AxVLCVariant(int i)
68     {
69         V_VT(&_v) = VT_I4;
70         V_I4(&_v) = i;
71     };
72
73     AxVLCVariant(BSTR bstr)
74     {
75         VARIANT arg;
76         V_VT(&arg) = VT_BSTR;
77         V_BSTR(&arg) = bstr;
78         VariantInit(&_v);
79         VariantCopy(&_v, &arg);
80     };
81
82     inline const VARIANTARG *variantArg(void) const {
83         return &_v;
84     }
85
86     inline void swap(AxVLCVariant &v1, AxVLCVariant &v2)
87     {
88         VARIANTARG tmp = v1._v;
89         v1._v = v2._v;
90         v2._v = tmp;
91     };
92
93 private:
94
95     VARIANTARG _v;
96 };
97
98 class AxVLCWSTR 
99 {
100
101 public:
102
103     AxVLCWSTR(void) : _data(NULL) {};
104
105     virtual ~AxVLCWSTR()
106     {
107         if( NULL != _data )
108         {
109             ULONG refcount = InterlockedDecrement(&(_data->refcount));
110             if( 0 == refcount )
111                 CoTaskMemFree(_data);
112         }
113     };
114
115     AxVLCWSTR(LPCWSTR s)
116     {
117         if( NULL != s )
118         {
119             size_t len = wcslen(s);
120             if( len > 0 )
121             {
122                 size_t size = len*sizeof(WCHAR);
123                 _data = (struct data *)CoTaskMemAlloc(sizeof(struct data)+size);
124                 if( NULL != _data )
125                 {
126                     _data->len = len;
127                     _data->refcount = 1;
128                     memcpy(_data->wstr, s, size);
129                     _data->wstr[len]=L'\0';
130                     return;
131                 }
132             }
133         }
134         _data = NULL;
135     };
136
137     AxVLCWSTR(const AxVLCWSTR &s)
138     {
139         _data = s._data;
140         if( NULL != _data )
141             InterlockedIncrement(&(_data->refcount));
142     };
143
144     inline bool operator<(const AxVLCWSTR &s) const
145     {
146         return compareNoCase(s.wstr()) < 0;
147     };
148
149     inline bool operator<(LPCWSTR s) const
150     {
151         return compareNoCase(s) < 0;
152     };
153
154     inline bool operator==(const AxVLCWSTR &s) const
155     {
156         return size() == s.size() ?
157                     (compareNoCase(s.wstr()) == 0) : false;
158     };
159
160     inline bool operator==(LPCWSTR s) const
161     {
162         return compareNoCase(s) == 0;
163     };
164
165     LPCWSTR wstr(void) const
166     {
167         return (NULL != _data) ? _data->wstr : NULL;
168     };
169
170     size_t size(void) const
171     {
172         return (NULL != _data) ? _data->len : 0;
173     };
174
175 private:
176
177     inline int compareNoCase(LPCWSTR s) const
178     {
179         if( NULL == _data )
180         {
181             return (NULL == s) ? 0 : -1;
182         }
183         if( NULL == s )
184             return 1;
185
186         return _wcsicmp(_data->wstr, s);
187     };
188
189     struct data {
190         size_t  len;
191         LONG    refcount;
192         wchar_t wstr[1];
193     } *_data;
194 };
195
196 typedef pair<class AxVLCWSTR, class AxVLCVariant> AxVLCPropertyPair;
197 typedef map<class AxVLCWSTR, class AxVLCVariant> AxVLCPropertyMap;
198
199 ///////////////////////////
200
201 class VLCPropertyBag : public IPropertyBag
202 {
203
204 public:
205
206     VLCPropertyBag(void) : _i_ref(1) {};
207     virtual ~VLCPropertyBag() {};
208
209     // IUnknown methods
210     STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
211     {
212         if( NULL == ppv )
213             return E_POINTER;
214         if( (IID_IUnknown == riid) 
215          || (IID_IPropertyBag == riid) )
216         {
217             AddRef();
218             *ppv = reinterpret_cast<LPVOID>(this);
219             return NOERROR;
220         }
221         // standalone object
222         return E_NOINTERFACE;
223     };
224
225     STDMETHODIMP_(ULONG) AddRef(void)
226         { return InterlockedIncrement(&_i_ref); };
227
228     STDMETHODIMP_(ULONG) Release(void)
229     {
230         ULONG refcount = InterlockedDecrement(&_i_ref);
231         if( 0 == refcount )
232         {
233             delete this;
234             return 0;
235         }
236         return refcount;
237     };
238
239     // IPropertyBag methods
240
241     STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
242     {
243         if( (NULL == pszPropName) || (NULL == pVar) )
244             return E_POINTER;
245
246         AxVLCPropertyMap::const_iterator notfound = _pm.end();
247         AxVLCPropertyMap::const_iterator iter = _pm.find(pszPropName);
248         if( notfound != iter )
249         {
250             VARTYPE vtype = V_VT(pVar);
251             VARIANTARG v;
252             VariantInit(&v);
253             VariantCopy(&v, const_cast<VARIANTARG*>((*iter).second.variantArg()));
254             if( (V_VT(&v) != vtype) && FAILED(VariantChangeType(&v, &v, 0, vtype)) )
255             {
256                 VariantClear(&v);
257                 return E_FAIL;
258             }
259             *pVar = v;
260             return S_OK;
261         }
262         else
263             return E_INVALIDARG;
264     };
265     
266     STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar)
267     {
268         if( (NULL == pszPropName) || (NULL == pVar) )
269             return E_POINTER;
270
271         AxVLCPropertyPair val(pszPropName, pVar);
272         pair<AxVLCPropertyMap::iterator, bool> p = _pm.insert(val);
273         if( false == p.second )
274             // replace existing key value
275             (*p.first).second = val.second;
276         return S_OK;
277     };
278
279     // custom methods
280
281     HRESULT Load(LPSTREAM pStm)
282     {
283         if( NULL == pStm )
284             return E_INVALIDARG;
285
286         HRESULT result;
287
288         AxVLCPropertyPair *val;
289         result = ReadProperty(pStm, &val);
290         if( SUCCEEDED(result) )
291         {
292             if( (val->first == L"(Count)") && (VT_I4 == V_VT(val->second.variantArg())) )
293             {
294                 size_t count = V_I4(val->second.variantArg());
295                 delete val;
296                 while( count-- )
297                 {
298                     result = ReadProperty(pStm, &val);
299                     if( FAILED(result) )
300                         return result;
301
302                     pair<AxVLCPropertyMap::iterator, bool> p = _pm.insert(*val);
303                     if( false == p.second )
304                         // replace existing key value
305                         (*p.first).second = val->second;
306                     delete val;
307                 }
308             }
309         }
310         return result;
311     };
312
313     HRESULT Save(LPSTREAM pStm)
314     {
315         if( NULL == pStm )
316             return E_INVALIDARG;
317
318         HRESULT result;
319
320         AxVLCPropertyPair header(L"(Count)", _pm.size());
321         result = WriteProperty(pStm, header);
322         if( SUCCEEDED(result) )
323         {
324             AxVLCPropertyMap::const_iterator iter = _pm.begin();
325             AxVLCPropertyMap::const_iterator end  = _pm.end();
326
327             while( iter != end )
328             {
329                 result = WriteProperty(pStm, *(iter++));
330                 if( FAILED(result) )
331                     return result;
332             }
333         }
334         return result;
335     };
336
337     BOOL IsEmpty()
338     {
339         return _pm.size() == 0;
340     }
341
342 private:
343
344     HRESULT WriteProperty(LPSTREAM pStm, const AxVLCPropertyPair &prop)
345     {
346         HRESULT result;
347
348         const AxVLCWSTR propName = prop.first;
349
350         ULONG len = propName.size();
351
352         if( 0 == len )
353             return E_INVALIDARG;
354
355         result = pStm->Write(&len, sizeof(len), NULL);
356         if( FAILED(result) )
357             return result;
358
359         result = pStm->Write(propName.wstr(), len*sizeof(WCHAR), NULL);
360         if( FAILED(result) )
361             return result;
362
363         const VARIANTARG *propValue = prop.second.variantArg();
364         VARTYPE vtype = V_VT(propValue);
365         switch( vtype )
366         {
367             case VT_BOOL:
368                 result = pStm->Write(&vtype, sizeof(vtype), NULL);
369                 if( FAILED(result) )
370                     return result;
371                 result = pStm->Write(&V_BOOL(propValue), sizeof(V_BOOL(propValue)), NULL);
372                 if( FAILED(result) )
373                     return result;
374                 break;
375             case VT_I4:
376                 result = pStm->Write(&vtype, sizeof(vtype), NULL);
377                 if( FAILED(result) )
378                     return result;
379                 result = pStm->Write(&V_I4(propValue), sizeof(V_I4(propValue)), NULL);
380                 if( FAILED(result) )
381                     return result;
382                 break;
383             case VT_BSTR:
384                 result = pStm->Write(&vtype, sizeof(vtype), NULL);
385                 if( FAILED(result) )
386                     return result;
387                 len = SysStringLen(V_BSTR(propValue));
388                 result = pStm->Write(&len, sizeof(len), NULL);
389                 if( FAILED(result) )
390                     return result;
391                 if( len > 0 )
392                 { 
393                     result = pStm->Write(V_BSTR(propValue), len*sizeof(OLECHAR), NULL);
394                     if( FAILED(result) )
395                         return result;
396                 }
397                 break;
398             default:
399                 vtype = VT_EMPTY;
400                 result = pStm->Write(&vtype, sizeof(vtype), NULL);
401                 if( FAILED(result) )
402                     return result;
403         }
404         return result;
405     };
406
407     HRESULT ReadProperty(LPSTREAM pStm, AxVLCPropertyPair **prop)
408     {
409         HRESULT result;
410
411         ULONG len;
412
413         result = pStm->Read(&len, sizeof(len), NULL);
414         if( FAILED(result) )
415             return result;
416
417         if( 0 == len )
418             return E_INVALIDARG;
419
420         LPWSTR propName = (LPOLESTR)::alloca((len+1)*sizeof(WCHAR));
421         if( NULL == propName )
422             return E_OUTOFMEMORY;
423
424         result = pStm->Read(propName, len*sizeof(WCHAR), NULL);
425         if( FAILED(result) )
426             return result;
427
428         propName[len] = L'\0';
429
430         VARIANTARG propValue;
431
432         VARTYPE vtype;
433         result = pStm->Read(&vtype, sizeof(vtype), NULL);
434         if( FAILED(result) )
435             return result;
436
437         switch( vtype )
438         {
439             case VT_BOOL:
440                 V_VT(&propValue) = vtype;
441                 result = pStm->Read(&V_BOOL(&propValue), sizeof(V_BOOL(&propValue)), NULL);
442                 if( FAILED(result) )
443                     return result;
444                 break;
445             case VT_I4:
446                 V_VT(&propValue) = vtype;
447                 result = pStm->Read(&V_I4(&propValue), sizeof(V_I4(&propValue)), NULL);
448                 if( FAILED(result) )
449                     return result;
450                 break;
451             case VT_BSTR:
452                 V_VT(&propValue) = vtype;
453                 result = pStm->Read(&len, sizeof(len), NULL);
454                 if( FAILED(result) )
455                     return result;
456
457                 V_BSTR(&propValue) = NULL;
458                 if( len > 0 )
459                 {
460                     V_BSTR(&propValue) = SysAllocStringLen(NULL, len);
461                     if( NULL == V_BSTR(&propValue) )
462                         return E_OUTOFMEMORY;
463
464                     result = pStm->Read(V_BSTR(&propValue), len*sizeof(OLECHAR), NULL);
465                     if( FAILED(result) )
466                     {
467                         SysFreeString(V_BSTR(&propValue));
468                         return result;
469                     }
470                 }
471                 break;
472             default:
473                 VariantInit(&propValue);
474         }
475
476         *prop = new AxVLCPropertyPair(propName, propValue);
477
478         return S_OK;
479     };
480
481     AxVLCPropertyMap _pm;
482     LONG _i_ref;
483 };
484
485 ///////////////////////////
486
487 VLCPersistStreamInit::VLCPersistStreamInit(VLCPlugin *p_instance) : _p_instance(p_instance)
488 {
489     _p_props = new VLCPropertyBag();
490 };
491
492 VLCPersistStreamInit::~VLCPersistStreamInit()
493 {
494     _p_props->Release();
495 };
496
497 STDMETHODIMP VLCPersistStreamInit::GetClassID(LPCLSID pClsID)
498 {
499     if( NULL == pClsID )
500         return E_POINTER;
501
502     *pClsID = _p_instance->getClassID();
503
504     return S_OK;
505 };
506
507 STDMETHODIMP VLCPersistStreamInit::InitNew(void)
508 {
509     return _p_instance->onInit();
510 };
511
512 STDMETHODIMP VLCPersistStreamInit::Load(LPSTREAM pStm)
513 {
514     HRESULT result = _p_props->Load(pStm);
515     if( FAILED(result) )
516         return result;
517
518     LPPERSISTPROPERTYBAG pPersistPropBag;
519     if( FAILED(QueryInterface(IID_IPersistPropertyBag, (void**)&pPersistPropBag)) )
520         return E_FAIL;
521
522     result = pPersistPropBag->Load(_p_props, NULL);
523     pPersistPropBag->Release();
524
525     return result;
526 };
527
528 STDMETHODIMP VLCPersistStreamInit::Save(LPSTREAM pStm, BOOL fClearDirty)
529 {
530     if( NULL == pStm )
531         return E_INVALIDARG;
532
533     LPPERSISTPROPERTYBAG pPersistPropBag;
534     if( FAILED(QueryInterface(IID_IPersistPropertyBag, (void**)&pPersistPropBag)) )
535         return E_FAIL;
536
537     HRESULT result = pPersistPropBag->Save(_p_props, fClearDirty, _p_props->IsEmpty());
538     pPersistPropBag->Release();
539     if( FAILED(result) )
540         return result;
541
542     return _p_props->Save(pStm);
543 };
544
545 STDMETHODIMP VLCPersistStreamInit::IsDirty(void)
546 {
547     return _p_instance->isDirty() ? S_OK : S_FALSE;
548 };
549
550 STDMETHODIMP VLCPersistStreamInit::GetSizeMax(ULARGE_INTEGER *pcbSize)
551 {
552     pcbSize->HighPart = 0UL;
553     pcbSize->LowPart  = 16384UL; // just a guess
554
555     return S_OK;
556 };
557