]> git.sesse.net Git - vlc/blob - activex/persiststreaminit.cpp
all: make sure that the plugin use that registry for plugin path
[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., 59 Temple Place - Suite 330, Boston, MA  02111, 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         _v = v;
54     };
55
56     AxVLCVariant(VARIANTARG *v)
57     {
58         VariantInit(&_v);
59         VariantCopy(&_v, v);
60     };
61
62     AxVLCVariant(const AxVLCVariant &vv)
63     {
64         VariantInit(&_v);
65         VariantCopy(&_v, const_cast<VARIANTARG *>(&(vv._v)));
66     };
67
68     AxVLCVariant(int i)
69     {
70         V_VT(&_v) = VT_I4;
71         V_I4(&_v) = i;
72     };
73
74     AxVLCVariant(BSTR bstr)
75     {
76         VARIANT arg;
77         V_VT(&arg) = VT_BSTR;
78         V_BSTR(&arg) = bstr;
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 compareNoCase(s.wstr()) == 0;
157     };
158
159     inline bool operator==(LPCWSTR s) const
160     {
161         return compareNoCase(s) == 0;
162     };
163
164     LPCWSTR wstr(void) const
165     {
166         return (NULL != _data) ? _data->wstr : NULL;
167     };
168
169     size_t size(void) const
170     {
171         return (NULL != _data) ? _data->len : 0;
172     };
173
174 private:
175
176     inline int compareNoCase(LPCWSTR s) const
177     {
178         if( NULL == _data )
179         {
180             return (NULL == s) ? 0 : -1;
181         }
182         if( NULL == s )
183             return 1;
184
185         return _wcsicmp(_data->wstr, s);
186     };
187
188     struct data {
189         size_t  len;
190         LONG    refcount;
191         wchar_t wstr[1];
192     } *_data;
193 };
194
195 typedef pair<class AxVLCWSTR, class AxVLCVariant> AxVLCPropertyPair;
196 typedef map<class AxVLCWSTR, class AxVLCVariant> AxVLCPropertyMap;
197
198 ///////////////////////////
199
200 class VLCPropertyBag : public IPropertyBag
201 {
202
203 public:
204
205     VLCPropertyBag(void) : _i_ref(1) {};
206     virtual ~VLCPropertyBag() {};
207
208     // IUnknown methods
209     STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
210     {
211         if( NULL == ppv )
212             return E_POINTER;
213         if( (IID_IUnknown == riid) 
214          && (IID_IPropertyBag == riid) )
215         {
216             AddRef();
217             *ppv = reinterpret_cast<LPVOID>(this);
218             return NOERROR;
219         }
220         // standalone object
221         return E_NOINTERFACE;
222     };
223
224     STDMETHODIMP_(ULONG) AddRef(void)
225         { return InterlockedIncrement(&_i_ref); };
226
227     STDMETHODIMP_(ULONG) Release(void)
228     {
229         ULONG refcount = InterlockedDecrement(&_i_ref);
230         if( 0 == refcount )
231         {
232             delete this;
233             return 0;
234         }
235         return refcount;
236     };
237
238     // IPropertyBag methods
239
240     STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
241     {
242         if( (NULL == pszPropName) || (NULL == pVar) )
243             return E_POINTER;
244
245         AxVLCPropertyMap::const_iterator notfound = _pm.end();
246         AxVLCPropertyMap::const_iterator iter = _pm.find(pszPropName);
247         if( notfound != iter )
248         {
249             VARTYPE vtype = V_VT(pVar);
250             VariantCopy(pVar, const_cast<VARIANTARG*>((*iter).second.variantArg()));
251             if( (V_VT(pVar) != vtype) && FAILED(VariantChangeType(pVar, pVar, 0, vtype)) )
252             {
253                 VariantClear(pVar);
254                 return E_FAIL;
255             }
256             return S_OK;
257         }
258         else
259             return E_INVALIDARG;
260     };
261     
262     STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar)
263     {
264         if( (NULL == pszPropName) || (NULL == pVar) )
265             return E_POINTER;
266
267         AxVLCPropertyPair val(pszPropName, pVar);
268         pair<AxVLCPropertyMap::iterator, bool> p = _pm.insert(val);
269         if( false == p.second )
270             // replace existing key value
271             (*p.first).second = val.second;
272         return S_OK;
273     };
274    
275     // custom methods
276
277     HRESULT Load(LPSTREAM pStm)
278     {
279         if( NULL == pStm )
280             return E_INVALIDARG;
281
282         HRESULT result;
283
284         AxVLCPropertyPair *val;
285         result = ReadProperty(pStm, &val);
286         if( SUCCEEDED(result) )
287         {
288             if( (val->first == L"(Count)") && (VT_I4 == V_VT(val->second.variantArg())) )
289             {
290                 size_t count =  V_I4(val->second.variantArg());
291                 delete val;
292                 while( count-- )
293                 {
294                     result = ReadProperty(pStm, &val);
295                     if( FAILED(result) )
296                         return result;
297
298                     pair<AxVLCPropertyMap::iterator, bool> p = _pm.insert(*val);
299                     if( false == p.second )
300                         // replace existing key value
301                         (*p.first).second = val->second;
302                     delete val;
303                 }
304             }
305         }
306         return result;
307     };
308
309     HRESULT Save(LPSTREAM pStm)
310     {
311         if( NULL == pStm )
312             return E_INVALIDARG;
313
314         HRESULT result;
315
316         AxVLCPropertyPair header(L"(Count)", _pm.size());
317         result = WriteProperty(pStm, header);
318         if( SUCCEEDED(result) )
319         {
320             AxVLCPropertyMap::const_iterator iter = _pm.begin();
321             AxVLCPropertyMap::const_iterator end  = _pm.end();
322
323             while( iter != end )
324             {
325                 result = WriteProperty(pStm, *(iter++));
326                 if( FAILED(result) )
327                     return result;
328             }
329         }
330         return result;
331     };
332
333     BOOL IsEmpty()
334     {
335         return _pm.size() == 0;
336     }
337
338 private:
339
340     HRESULT WriteProperty(LPSTREAM pStm, const AxVLCPropertyPair &prop)
341     {
342         HRESULT result;
343
344         const AxVLCWSTR propName = prop.first;
345
346         ULONG len = propName.size();
347
348         if( 0 == len )
349             return E_INVALIDARG;
350
351         result = pStm->Write(&len, sizeof(len), NULL);
352         if( FAILED(result) )
353             return result;
354
355         result = pStm->Write(propName.wstr(), len*sizeof(WCHAR), NULL);
356         if( FAILED(result) )
357             return result;
358
359         const VARIANTARG *propValue = prop.second.variantArg();
360         VARTYPE vtype = V_VT(propValue);
361         switch( vtype )
362         {
363             case VT_BOOL:
364                 result = pStm->Write(&vtype, sizeof(vtype), NULL);
365                 if( FAILED(result) )
366                     return result;
367                 result = pStm->Write(&V_BOOL(propValue), sizeof(V_BOOL(propValue)), NULL);
368                 if( FAILED(result) )
369                     return result;
370                 break;
371             case VT_I4:
372                 result = pStm->Write(&vtype, sizeof(vtype), NULL);
373                 if( FAILED(result) )
374                     return result;
375                 result = pStm->Write(&V_I4(propValue), sizeof(V_I4(propValue)), NULL);
376                 if( FAILED(result) )
377                     return result;
378                 break;
379             case VT_BSTR:
380                 result = pStm->Write(&vtype, sizeof(vtype), NULL);
381                 if( FAILED(result) )
382                     return result;
383                 len = SysStringLen(V_BSTR(propValue));
384                 result = pStm->Write(&len, sizeof(len), NULL);
385                 if( FAILED(result) )
386                     return result;
387                 if( len > 0 )
388                 { 
389                     result = pStm->Write(V_BSTR(propValue), len*sizeof(OLECHAR), NULL);
390                     if( FAILED(result) )
391                         return result;
392                 }
393                 break;
394             default:
395                 vtype = VT_EMPTY;
396                 result = pStm->Write(&vtype, sizeof(vtype), NULL);
397                 if( FAILED(result) )
398                     return result;
399         }
400         return result;
401     };
402
403     static HRESULT ReadProperty(LPSTREAM pStm, AxVLCPropertyPair **prop)
404     {
405         HRESULT result;
406
407         ULONG len;
408
409         result = pStm->Read(&len, sizeof(len), NULL);
410         if( FAILED(result) )
411             return result;
412
413         if( 0 == len )
414             return E_INVALIDARG;
415
416         LPWSTR propName = (LPOLESTR)::alloca((len+1)*sizeof(WCHAR));
417         if( NULL == propName )
418             return E_OUTOFMEMORY;
419
420         result = pStm->Read(propName, len*sizeof(WCHAR), NULL);
421         if( FAILED(result) )
422             return result;
423
424         propName[len] = L'\0';
425
426         VARIANTARG propValue;
427
428         VARTYPE vtype;
429         result = pStm->Read(&vtype, sizeof(vtype), NULL);
430         if( FAILED(result) )
431             return result;
432
433         switch( vtype )
434         {
435             case VT_BOOL:
436                 V_VT(&propValue) = vtype;
437                 result = pStm->Read(&V_BOOL(&propValue), sizeof(V_BOOL(&propValue)), NULL);
438                 if( FAILED(result) )
439                     return result;
440                 break;
441             case VT_I4:
442                 V_VT(&propValue) = vtype;
443                 result = pStm->Read(&V_I4(&propValue), sizeof(V_I4(&propValue)), NULL);
444                 if( FAILED(result) )
445                     return result;
446                 break;
447             case VT_BSTR:
448                 V_VT(&propValue) = vtype;
449                 result = pStm->Read(&len, sizeof(len), NULL);
450                 if( FAILED(result) )
451                     return result;
452
453                 V_BSTR(&propValue) = NULL;
454                 if( len > 0 )
455                 {
456                     V_BSTR(&propValue) = SysAllocStringLen(NULL, len);
457                     if( NULL == V_BSTR(&propValue) )
458                         return E_OUTOFMEMORY;
459
460                     result = pStm->Read(V_BSTR(&propValue), len*sizeof(OLECHAR), NULL);
461                     if( FAILED(result) )
462                     {
463                         SysFreeString(V_BSTR(&propValue));
464                         return result;
465                     }
466                 }
467                 break;
468             default:
469                 VariantInit(&propValue);
470         }
471
472         *prop = new AxVLCPropertyPair(propName, propValue);
473
474         return S_OK;
475     };
476
477     AxVLCPropertyMap _pm;
478     LONG _i_ref;
479 };
480
481 ///////////////////////////
482
483 VLCPersistStreamInit::VLCPersistStreamInit(VLCPlugin *p_instance) : _p_instance(p_instance)
484 {
485     _p_props = new VLCPropertyBag();
486 };
487
488 VLCPersistStreamInit::~VLCPersistStreamInit()
489 {
490     _p_props->Release();
491 };
492
493 STDMETHODIMP VLCPersistStreamInit::GetClassID(LPCLSID pClsID)
494 {
495     if( NULL == pClsID )
496         return E_POINTER;
497
498     *pClsID = _p_instance->getClassID();
499
500     return S_OK;
501 };
502
503 STDMETHODIMP VLCPersistStreamInit::InitNew(void)
504 {
505     return _p_instance->onInit();
506 };
507
508 STDMETHODIMP VLCPersistStreamInit::Load(LPSTREAM pStm)
509 {
510     HRESULT result = _p_props->Load(pStm);
511     if( FAILED(result) )
512         return result;
513
514     LPPERSISTPROPERTYBAG pPersistPropBag;
515     if( FAILED(QueryInterface(IID_IPersistPropertyBag, (void**)&pPersistPropBag)) )
516         return E_FAIL;
517
518     result = pPersistPropBag->Load(_p_props, NULL);
519     pPersistPropBag->Release();
520
521     return result;
522 };
523
524 STDMETHODIMP VLCPersistStreamInit::Save(LPSTREAM pStm, BOOL fClearDirty)
525 {
526     if( NULL == pStm )
527         return E_INVALIDARG;
528
529     LPPERSISTPROPERTYBAG pPersistPropBag;
530     if( FAILED(QueryInterface(IID_IPersistPropertyBag, (void**)&pPersistPropBag)) )
531         return E_FAIL;
532
533     HRESULT result = pPersistPropBag->Save(_p_props, fClearDirty, _p_props->IsEmpty());
534     pPersistPropBag->Release();
535     if( FAILED(result) )
536         return result;
537
538     return _p_props->Save(pStm);
539 };
540
541 STDMETHODIMP VLCPersistStreamInit::IsDirty(void)
542 {
543     return _p_instance->isDirty() ? S_OK : S_FALSE;
544 };
545
546 STDMETHODIMP VLCPersistStreamInit::GetSizeMax(ULARGE_INTEGER *pcbSize)
547 {
548     pcbSize->HighPart = 0UL;
549     pcbSize->LowPart  = 4096UL; // just a guess
550
551     return S_OK;
552 };
553