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