msi: Only insert entries into listbox if property value matches.
[wine] / dlls / itss / storage.c
1 /*
2  *    ITSS Storage implementation
3  *
4  * Copyright 2004 Mike McCormack
5  *
6  *  see http://bonedaddy.net/pabs3/hhm/#chmspec
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library 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 GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #define COBJMACROS
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "ole2.h"
36
37 #include "uuids.h"
38
39 #include "chm_lib.h"
40 #include "itsstor.h"
41
42 #include "wine/itss.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(itss);
47
48 /************************************************************************/
49
50 typedef struct _ITSS_IStorageImpl
51 {
52     const IStorageVtbl *vtbl_IStorage;
53     LONG ref;
54     struct chmFile *chmfile;
55     WCHAR dir[1];
56 } ITSS_IStorageImpl;
57
58 struct enum_info
59 {
60     struct enum_info *next, *prev;
61     struct chmUnitInfo ui;
62 };
63
64 typedef struct _IEnumSTATSTG_Impl
65 {
66     const IEnumSTATSTGVtbl *vtbl_IEnumSTATSTG;
67     LONG ref;
68     struct enum_info *first, *last, *current;
69 } IEnumSTATSTG_Impl;
70
71 typedef struct _IStream_Impl
72 {
73     const IStreamVtbl *vtbl_IStream;
74     LONG ref;
75     ITSS_IStorageImpl *stg;
76     ULONGLONG addr;
77     struct chmUnitInfo ui;
78 } IStream_Impl;
79
80 static HRESULT ITSS_create_chm_storage(
81            struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen );
82 static IStream_Impl* ITSS_create_stream( 
83            ITSS_IStorageImpl *stg, struct chmUnitInfo *ui );
84
85 /************************************************************************/
86
87 static HRESULT WINAPI ITSS_IEnumSTATSTG_QueryInterface(
88     IEnumSTATSTG* iface,
89     REFIID riid,
90     void** ppvObject)
91 {
92     IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
93
94     if (IsEqualGUID(riid, &IID_IUnknown)
95         || IsEqualGUID(riid, &IID_IEnumSTATSTG))
96     {
97         IEnumSTATSTG_AddRef(iface);
98         *ppvObject = This;
99         return S_OK;
100     }
101
102     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
103     return E_NOINTERFACE;
104 }
105
106 static ULONG WINAPI ITSS_IEnumSTATSTG_AddRef(
107     IEnumSTATSTG* iface)
108 {
109     IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
110     return InterlockedIncrement(&This->ref);
111 }
112
113 static ULONG WINAPI ITSS_IEnumSTATSTG_Release(
114     IEnumSTATSTG* iface)
115 {
116     IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
117
118     ULONG ref = InterlockedDecrement(&This->ref);
119
120     if (ref == 0)
121     {
122         while( This->first )
123         {
124             struct enum_info *t = This->first->next;
125             HeapFree( GetProcessHeap(), 0, This->first );
126             This->first = t;
127         }
128         HeapFree(GetProcessHeap(), 0, This);
129         ITSS_UnlockModule();
130     }
131
132     return ref;
133 }
134
135 static HRESULT WINAPI ITSS_IEnumSTATSTG_Next(
136         IEnumSTATSTG* iface,
137         ULONG celt,
138         STATSTG* rgelt,
139         ULONG* pceltFetched)
140 {
141     IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
142     DWORD len, n;
143     struct enum_info *cur;
144
145     TRACE("%p %u %p %p\n", This, celt, rgelt, pceltFetched );
146
147     cur = This->current;
148     n = 0;
149     while( (n<celt) && cur) 
150     {
151         WCHAR *str;
152
153         memset( rgelt, 0, sizeof *rgelt );
154
155         /* copy the name */
156         str = cur->ui.path;
157         if( *str == '/' )
158             str++;
159         len = strlenW( str ) + 1;
160         rgelt->pwcsName = CoTaskMemAlloc( len*sizeof(WCHAR) );
161         strcpyW( rgelt->pwcsName, str );
162
163         /* determine the type */
164         if( rgelt->pwcsName[len-2] == '/' )
165         {
166             rgelt->pwcsName[len-2] = 0;
167             rgelt->type = STGTY_STORAGE;
168         }
169         else
170             rgelt->type = STGTY_STREAM;
171
172         /* copy the size */
173         rgelt->cbSize.QuadPart = cur->ui.length;
174
175         /* advance to the next item if it exists */
176         n++;
177         cur = cur->next;
178     }
179
180     This->current = cur;
181     *pceltFetched = n;
182
183     if( n < celt )
184         return S_FALSE;
185
186     return S_OK;
187 }
188
189 static HRESULT WINAPI ITSS_IEnumSTATSTG_Skip(
190         IEnumSTATSTG* iface,
191         ULONG celt)
192 {
193     IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
194     DWORD n;
195     struct enum_info *cur;
196
197     TRACE("%p %u\n", This, celt );
198
199     cur = This->current;
200     n = 0;
201     while( (n<celt) && cur) 
202     {
203         n++;
204         cur = cur->next;
205     }
206     This->current = cur;
207
208     if( n < celt )
209         return S_FALSE;
210
211     return S_OK;
212 }
213
214 static HRESULT WINAPI ITSS_IEnumSTATSTG_Reset(
215         IEnumSTATSTG* iface)
216 {
217     IEnumSTATSTG_Impl *This = (IEnumSTATSTG_Impl *)iface;
218
219     TRACE("%p\n", This );
220
221     This->current = This->first;
222
223     return S_OK;
224 }
225
226 static HRESULT WINAPI ITSS_IEnumSTATSTG_Clone(
227         IEnumSTATSTG* iface,
228         IEnumSTATSTG** ppenum)
229 {
230     FIXME("\n");
231     return E_NOTIMPL;
232 }
233
234 static const IEnumSTATSTGVtbl IEnumSTATSTG_vtbl =
235 {
236     ITSS_IEnumSTATSTG_QueryInterface,
237     ITSS_IEnumSTATSTG_AddRef,
238     ITSS_IEnumSTATSTG_Release,
239     ITSS_IEnumSTATSTG_Next,
240     ITSS_IEnumSTATSTG_Skip,
241     ITSS_IEnumSTATSTG_Reset,
242     ITSS_IEnumSTATSTG_Clone
243 };
244
245 static IEnumSTATSTG_Impl *ITSS_create_enum( void )
246 {
247     IEnumSTATSTG_Impl *stgenum;
248
249     stgenum = HeapAlloc( GetProcessHeap(), 0, sizeof (IEnumSTATSTG_Impl) );
250     stgenum->vtbl_IEnumSTATSTG = &IEnumSTATSTG_vtbl;
251     stgenum->ref = 1;
252     stgenum->first = NULL;
253     stgenum->last = NULL;
254     stgenum->current = NULL;
255
256     ITSS_LockModule();
257     TRACE(" -> %p\n", stgenum );
258
259     return stgenum;
260 }
261
262 /************************************************************************/
263
264 static HRESULT WINAPI ITSS_IStorageImpl_QueryInterface(
265     IStorage* iface,
266     REFIID riid,
267     void** ppvObject)
268 {
269     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
270
271     if (IsEqualGUID(riid, &IID_IUnknown)
272         || IsEqualGUID(riid, &IID_IStorage))
273     {
274         IStorage_AddRef(iface);
275         *ppvObject = This;
276         return S_OK;
277     }
278
279     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
280     return E_NOINTERFACE;
281 }
282
283 static ULONG WINAPI ITSS_IStorageImpl_AddRef(
284     IStorage* iface)
285 {
286     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
287     return InterlockedIncrement(&This->ref);
288 }
289
290 static ULONG WINAPI ITSS_IStorageImpl_Release(
291     IStorage* iface)
292 {
293     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
294
295     ULONG ref = InterlockedDecrement(&This->ref);
296
297     if (ref == 0)
298     {
299         chm_close(This->chmfile);
300         HeapFree(GetProcessHeap(), 0, This);
301         ITSS_UnlockModule();
302     }
303
304     return ref;
305 }
306
307 static HRESULT WINAPI ITSS_IStorageImpl_CreateStream(
308     IStorage* iface,
309     LPCOLESTR pwcsName,
310     DWORD grfMode,
311     DWORD reserved1,
312     DWORD reserved2,
313     IStream** ppstm)
314 {
315     FIXME("\n");
316     return E_NOTIMPL;
317 }
318
319 static HRESULT WINAPI ITSS_IStorageImpl_OpenStream(
320     IStorage* iface,
321     LPCOLESTR pwcsName,
322     void* reserved1,
323     DWORD grfMode,
324     DWORD reserved2,
325     IStream** ppstm)
326 {
327     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
328     IStream_Impl *stm;
329     DWORD len;
330     struct chmUnitInfo ui;
331     int r;
332     WCHAR *path;
333
334     TRACE("%p %s %p %u %u %p\n", This, debugstr_w(pwcsName),
335           reserved1, grfMode, reserved2, ppstm );
336
337     len = strlenW( This->dir ) + strlenW( pwcsName ) + 1;
338     path = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
339     strcpyW( path, This->dir );
340     if( pwcsName[0] == '/' )
341     {
342         WCHAR *p = &path[strlenW( path ) - 1];
343         while( ( path <= p ) && ( *p == '/' ) )
344             *p-- = 0;
345     }
346     strcatW( path, pwcsName );
347
348     TRACE("Resolving %s\n", debugstr_w(path));
349
350     r = chm_resolve_object(This->chmfile, path, &ui);
351     HeapFree( GetProcessHeap(), 0, path );
352
353     if( r != CHM_RESOLVE_SUCCESS )
354         return STG_E_FILENOTFOUND;
355
356     stm = ITSS_create_stream( This, &ui );
357     if( !stm )
358         return E_FAIL;
359
360     *ppstm = (IStream*) stm;
361
362     return S_OK;
363 }
364
365 static HRESULT WINAPI ITSS_IStorageImpl_CreateStorage(
366     IStorage* iface,
367     LPCOLESTR pwcsName,
368     DWORD grfMode,
369     DWORD dwStgFmt,
370     DWORD reserved2,
371     IStorage** ppstg)
372 {
373     FIXME("\n");
374     return E_NOTIMPL;
375 }
376
377 static HRESULT WINAPI ITSS_IStorageImpl_OpenStorage(
378     IStorage* iface,
379     LPCOLESTR pwcsName,
380     IStorage* pstgPriority,
381     DWORD grfMode,
382     SNB snbExclude,
383     DWORD reserved,
384     IStorage** ppstg)
385 {
386     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
387
388     FIXME("%p %s %p %u %p %u %p\n", This, debugstr_w(pwcsName),
389           pstgPriority, grfMode, snbExclude, reserved, ppstg);
390     return E_NOTIMPL;
391 }
392
393 static HRESULT WINAPI ITSS_IStorageImpl_CopyTo(
394     IStorage* iface,
395     DWORD ciidExclude,
396     const IID* rgiidExclude,
397     SNB snbExclude,
398     IStorage* pstgDest)
399 {
400     FIXME("\n");
401     return E_NOTIMPL;
402 }
403
404 static HRESULT WINAPI ITSS_IStorageImpl_MoveElementTo(
405     IStorage* iface,
406     LPCOLESTR pwcsName,
407     IStorage* pstgDest,
408     LPCOLESTR pwcsNewName,
409     DWORD grfFlags)
410 {
411     FIXME("\n");
412     return E_NOTIMPL;
413 }
414
415 static HRESULT WINAPI ITSS_IStorageImpl_Commit(
416     IStorage* iface,
417     DWORD grfCommitFlags)
418 {
419     FIXME("\n");
420     return E_NOTIMPL;
421 }
422
423 static HRESULT WINAPI ITSS_IStorageImpl_Revert(
424     IStorage* iface)
425 {
426     FIXME("\n");
427     return E_NOTIMPL;
428 }
429
430 static int ITSS_chm_enumerator(
431     struct chmFile *h,
432     struct chmUnitInfo *ui,
433     void *context)
434 {
435     struct enum_info *info;
436     IEnumSTATSTG_Impl* stgenum = context;
437
438     TRACE("adding %s to enumeration\n", debugstr_w(ui->path) );
439
440     info = HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info) );
441     memcpy( &info->ui, ui, sizeof info->ui );
442
443     info->next = NULL;
444     info->prev = stgenum->last;
445     if( stgenum->last )
446         stgenum->last->next = info;
447     else
448         stgenum->first = info;
449     stgenum->last = info;
450     
451     return CHM_ENUMERATOR_CONTINUE;
452 }
453
454 static HRESULT WINAPI ITSS_IStorageImpl_EnumElements(
455     IStorage* iface,
456     DWORD reserved1,
457     void* reserved2,
458     DWORD reserved3,
459     IEnumSTATSTG** ppenum)
460 {
461     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
462     IEnumSTATSTG_Impl* stgenum;
463
464     TRACE("%p %d %p %d %p\n", This, reserved1, reserved2, reserved3, ppenum );
465
466     stgenum = ITSS_create_enum();
467     if( !stgenum )
468         return E_FAIL;
469
470     chm_enumerate_dir(This->chmfile,
471                   This->dir,
472                   CHM_ENUMERATE_ALL,
473                   ITSS_chm_enumerator,
474                   stgenum );
475
476     stgenum->current = stgenum->first;
477
478     *ppenum = (IEnumSTATSTG*) stgenum;
479
480     return S_OK;
481 }
482
483 static HRESULT WINAPI ITSS_IStorageImpl_DestroyElement(
484     IStorage* iface,
485     LPCOLESTR pwcsName)
486 {
487     FIXME("\n");
488     return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI ITSS_IStorageImpl_RenameElement(
492     IStorage* iface,
493     LPCOLESTR pwcsOldName,
494     LPCOLESTR pwcsNewName)
495 {
496     FIXME("\n");
497     return E_NOTIMPL;
498 }
499
500 static HRESULT WINAPI ITSS_IStorageImpl_SetElementTimes(
501     IStorage* iface,
502     LPCOLESTR pwcsName,
503     const FILETIME* pctime,
504     const FILETIME* patime,
505     const FILETIME* pmtime)
506 {
507     FIXME("\n");
508     return E_NOTIMPL;
509 }
510
511 static HRESULT WINAPI ITSS_IStorageImpl_SetClass(
512     IStorage* iface,
513     REFCLSID clsid)
514 {
515     FIXME("\n");
516     return E_NOTIMPL;
517 }
518
519 static HRESULT WINAPI ITSS_IStorageImpl_SetStateBits(
520     IStorage* iface,
521     DWORD grfStateBits,
522     DWORD grfMask)
523 {
524     FIXME("\n");
525     return E_NOTIMPL;
526 }
527
528 static HRESULT WINAPI ITSS_IStorageImpl_Stat(
529     IStorage* iface,
530     STATSTG* pstatstg,
531     DWORD grfStatFlag)
532 {
533     FIXME("\n");
534     return E_NOTIMPL;
535 }
536
537 static const IStorageVtbl ITSS_IStorageImpl_Vtbl =
538 {
539     ITSS_IStorageImpl_QueryInterface,
540     ITSS_IStorageImpl_AddRef,
541     ITSS_IStorageImpl_Release,
542     ITSS_IStorageImpl_CreateStream,
543     ITSS_IStorageImpl_OpenStream,
544     ITSS_IStorageImpl_CreateStorage,
545     ITSS_IStorageImpl_OpenStorage,
546     ITSS_IStorageImpl_CopyTo,
547     ITSS_IStorageImpl_MoveElementTo,
548     ITSS_IStorageImpl_Commit,
549     ITSS_IStorageImpl_Revert,
550     ITSS_IStorageImpl_EnumElements,
551     ITSS_IStorageImpl_DestroyElement,
552     ITSS_IStorageImpl_RenameElement,
553     ITSS_IStorageImpl_SetElementTimes,
554     ITSS_IStorageImpl_SetClass,
555     ITSS_IStorageImpl_SetStateBits,
556     ITSS_IStorageImpl_Stat,
557 };
558
559 static HRESULT ITSS_create_chm_storage(
560       struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen )
561 {
562     ITSS_IStorageImpl *stg;
563     DWORD len;
564
565     TRACE("%p %s\n", chmfile, debugstr_w( dir ) );
566
567     len = strlenW( dir ) + 1;
568     stg = HeapAlloc( GetProcessHeap(), 0, 
569                      sizeof (ITSS_IStorageImpl) + len*sizeof(WCHAR) );
570     stg->vtbl_IStorage = &ITSS_IStorageImpl_Vtbl;
571     stg->ref = 1;
572     stg->chmfile = chmfile;
573     strcpyW( stg->dir, dir );
574
575     *ppstgOpen = (IStorage*) stg;
576
577     ITSS_LockModule();
578     return S_OK;
579 }
580
581 HRESULT ITSS_StgOpenStorage( 
582     const WCHAR* pwcsName,
583     IStorage* pstgPriority,
584     DWORD grfMode,
585     SNB snbExclude,
586     DWORD reserved,
587     IStorage** ppstgOpen)
588 {
589     struct chmFile *chmfile;
590     static const WCHAR szRoot[] = { '/', 0 };
591
592     TRACE("%s\n", debugstr_w(pwcsName) );
593
594     chmfile = chm_openW( pwcsName );
595     if( !chmfile )
596         return E_FAIL;
597
598     return ITSS_create_chm_storage( chmfile, szRoot, ppstgOpen );
599 }
600
601 /************************************************************************/
602
603 static HRESULT WINAPI ITSS_IStream_QueryInterface(
604     IStream* iface,
605     REFIID riid,
606     void** ppvObject)
607 {
608     IStream_Impl *This = (IStream_Impl *)iface;
609
610     if (IsEqualGUID(riid, &IID_IUnknown)
611         || IsEqualGUID(riid, &IID_ISequentialStream)
612         || IsEqualGUID(riid, &IID_IStream))
613     {
614         IStream_AddRef(iface);
615         *ppvObject = This;
616         return S_OK;
617     }
618
619     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
620     return E_NOINTERFACE;
621 }
622
623 static ULONG WINAPI ITSS_IStream_AddRef(
624     IStream* iface)
625 {
626     IStream_Impl *This = (IStream_Impl *)iface;
627     return InterlockedIncrement(&This->ref);
628 }
629
630 static ULONG WINAPI ITSS_IStream_Release(
631     IStream* iface)
632 {
633     IStream_Impl *This = (IStream_Impl *)iface;
634
635     ULONG ref = InterlockedDecrement(&This->ref);
636
637     if (ref == 0)
638     {
639         IStorage_Release( (IStorage*) This->stg );
640         HeapFree(GetProcessHeap(), 0, This);
641         ITSS_UnlockModule();
642     }
643
644     return ref;
645 }
646
647 static HRESULT WINAPI ITSS_IStream_Read(
648         IStream* iface,
649         void* pv,
650         ULONG cb,
651         ULONG* pcbRead)
652 {
653     IStream_Impl *This = (IStream_Impl *)iface;
654     ULONG count;
655
656     TRACE("%p %p %u %p\n", This, pv, cb, pcbRead);
657
658     count = chm_retrieve_object(This->stg->chmfile, 
659                           &This->ui, pv, This->addr, cb);
660     This->addr += count;
661     if( pcbRead )
662         *pcbRead = count;
663     
664     return count ? S_OK : S_FALSE;
665 }
666
667 static HRESULT WINAPI ITSS_IStream_Write(
668         IStream* iface,
669         const void* pv,
670         ULONG cb,
671         ULONG* pcbWritten)
672 {
673     FIXME("\n");
674     return E_NOTIMPL;
675 }
676
677 static HRESULT WINAPI ITSS_IStream_Seek(
678         IStream* iface,
679         LARGE_INTEGER dlibMove,
680         DWORD dwOrigin,
681         ULARGE_INTEGER* plibNewPosition)
682 {
683     IStream_Impl *This = (IStream_Impl *)iface;
684     LONGLONG newpos;
685
686     TRACE("%p %s %u %p\n", This,
687           wine_dbgstr_longlong( dlibMove.QuadPart ), dwOrigin, plibNewPosition );
688
689     newpos = This->addr;
690     switch( dwOrigin )
691     {
692     case STREAM_SEEK_CUR:
693         newpos = This->addr + dlibMove.QuadPart;
694         break;
695     case STREAM_SEEK_SET:
696         newpos = dlibMove.QuadPart;
697         break;
698     case STREAM_SEEK_END:
699         newpos = This->ui.length + dlibMove.QuadPart;
700         break;
701     }
702
703     if( ( newpos < 0 ) || ( newpos > This->ui.length ) )
704         return STG_E_INVALIDPOINTER;
705
706     This->addr = newpos;
707     if( plibNewPosition )
708         plibNewPosition->QuadPart = This->addr;
709
710     return S_OK;
711 }
712
713 static HRESULT WINAPI ITSS_IStream_SetSize(
714         IStream* iface,
715         ULARGE_INTEGER libNewSize)
716 {
717     FIXME("\n");
718     return E_NOTIMPL;
719 }
720
721 static HRESULT WINAPI ITSS_IStream_CopyTo(
722         IStream* iface,
723         IStream* pstm,
724         ULARGE_INTEGER cb,
725         ULARGE_INTEGER* pcbRead,
726         ULARGE_INTEGER* pcbWritten)
727 {
728     FIXME("\n");
729     return E_NOTIMPL;
730 }
731
732 static HRESULT WINAPI ITSS_IStream_Commit(
733         IStream* iface,
734         DWORD grfCommitFlags)
735 {
736     FIXME("\n");
737     return E_NOTIMPL;
738 }
739
740 static HRESULT WINAPI ITSS_IStream_Revert(
741         IStream* iface)
742 {
743     FIXME("\n");
744     return E_NOTIMPL;
745 }
746
747 static HRESULT WINAPI ITSS_IStream_LockRegion(
748         IStream* iface,
749         ULARGE_INTEGER libOffset,
750         ULARGE_INTEGER cb,
751         DWORD dwLockType)
752 {
753     FIXME("\n");
754     return E_NOTIMPL;
755 }
756
757 static HRESULT WINAPI ITSS_IStream_UnlockRegion(
758         IStream* iface,
759         ULARGE_INTEGER libOffset,
760         ULARGE_INTEGER cb,
761         DWORD dwLockType)
762 {
763     FIXME("\n");
764     return E_NOTIMPL;
765 }
766
767 static HRESULT WINAPI ITSS_IStream_Stat(
768         IStream* iface,
769         STATSTG* pstatstg,
770         DWORD grfStatFlag)
771 {
772     IStream_Impl *This = (IStream_Impl *)iface;
773
774     TRACE("%p %p %d\n", This, pstatstg, grfStatFlag);
775
776     memset( pstatstg, 0, sizeof *pstatstg );
777     if( !( grfStatFlag & STATFLAG_NONAME ) )
778     {
779         FIXME("copy the name\n");
780     }
781     pstatstg->type = STGTY_STREAM;
782     pstatstg->cbSize.QuadPart = This->ui.length;
783     pstatstg->grfMode = STGM_READ;
784     memcpy( &pstatstg->clsid, &CLSID_ITStorage, sizeof (CLSID) );
785
786     return S_OK;
787 }
788
789 static HRESULT WINAPI ITSS_IStream_Clone(
790         IStream* iface,
791         IStream** ppstm)
792 {
793     FIXME("\n");
794     return E_NOTIMPL;
795 }
796
797 static const IStreamVtbl ITSS_IStream_vtbl =
798 {
799     ITSS_IStream_QueryInterface,
800     ITSS_IStream_AddRef,
801     ITSS_IStream_Release,
802     ITSS_IStream_Read,
803     ITSS_IStream_Write,
804     ITSS_IStream_Seek,
805     ITSS_IStream_SetSize,
806     ITSS_IStream_CopyTo,
807     ITSS_IStream_Commit,
808     ITSS_IStream_Revert,
809     ITSS_IStream_LockRegion,
810     ITSS_IStream_UnlockRegion,
811     ITSS_IStream_Stat,
812     ITSS_IStream_Clone,
813 };
814
815 static IStream_Impl *ITSS_create_stream(
816            ITSS_IStorageImpl *stg, struct chmUnitInfo *ui )
817 {
818     IStream_Impl *stm;
819
820     stm = HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl) );
821     stm->vtbl_IStream = &ITSS_IStream_vtbl;
822     stm->ref = 1;
823     stm->addr = 0;
824     memcpy( &stm->ui, ui, sizeof stm->ui );
825     stm->stg = stg;
826     IStorage_AddRef( (IStorage*) stg );
827
828     ITSS_LockModule();
829
830     TRACE(" -> %p\n", stm );
831
832     return stm;
833 }