dmloader: Declare some functions static.
[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         HeapFree(GetProcessHeap(), 0, This);
300         ITSS_UnlockModule();
301     }
302
303     return ref;
304 }
305
306 static HRESULT WINAPI ITSS_IStorageImpl_CreateStream(
307     IStorage* iface,
308     LPCOLESTR pwcsName,
309     DWORD grfMode,
310     DWORD reserved1,
311     DWORD reserved2,
312     IStream** ppstm)
313 {
314     FIXME("\n");
315     return E_NOTIMPL;
316 }
317
318 static HRESULT WINAPI ITSS_IStorageImpl_OpenStream(
319     IStorage* iface,
320     LPCOLESTR pwcsName,
321     void* reserved1,
322     DWORD grfMode,
323     DWORD reserved2,
324     IStream** ppstm)
325 {
326     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
327     IStream_Impl *stm;
328     DWORD len;
329     struct chmUnitInfo ui;
330     int r;
331     WCHAR *path;
332
333     TRACE("%p %s %p %u %u %p\n", This, debugstr_w(pwcsName),
334           reserved1, grfMode, reserved2, ppstm );
335
336     len = strlenW( This->dir ) + strlenW( pwcsName ) + 1;
337     path = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
338     strcpyW( path, This->dir );
339     if( pwcsName[0] == '/' )
340     {
341         WCHAR *p = &path[strlenW( path ) - 1];
342         while( ( path <= p ) && ( *p == '/' ) )
343             *p-- = 0;
344     }
345     strcatW( path, pwcsName );
346
347     TRACE("Resolving %s\n", debugstr_w(path));
348
349     r = chm_resolve_object(This->chmfile, path, &ui);
350     HeapFree( GetProcessHeap(), 0, path );
351
352     if( r != CHM_RESOLVE_SUCCESS )
353         return STG_E_FILENOTFOUND;
354
355     stm = ITSS_create_stream( This, &ui );
356     if( !stm )
357         return E_FAIL;
358
359     *ppstm = (IStream*) stm;
360
361     return S_OK;
362 }
363
364 static HRESULT WINAPI ITSS_IStorageImpl_CreateStorage(
365     IStorage* iface,
366     LPCOLESTR pwcsName,
367     DWORD grfMode,
368     DWORD dwStgFmt,
369     DWORD reserved2,
370     IStorage** ppstg)
371 {
372     FIXME("\n");
373     return E_NOTIMPL;
374 }
375
376 static HRESULT WINAPI ITSS_IStorageImpl_OpenStorage(
377     IStorage* iface,
378     LPCOLESTR pwcsName,
379     IStorage* pstgPriority,
380     DWORD grfMode,
381     SNB snbExclude,
382     DWORD reserved,
383     IStorage** ppstg)
384 {
385     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
386
387     FIXME("%p %s %p %u %p %u %p\n", This, debugstr_w(pwcsName),
388           pstgPriority, grfMode, snbExclude, reserved, ppstg);
389     return E_NOTIMPL;
390 }
391
392 static HRESULT WINAPI ITSS_IStorageImpl_CopyTo(
393     IStorage* iface,
394     DWORD ciidExclude,
395     const IID* rgiidExclude,
396     SNB snbExclude,
397     IStorage* pstgDest)
398 {
399     FIXME("\n");
400     return E_NOTIMPL;
401 }
402
403 static HRESULT WINAPI ITSS_IStorageImpl_MoveElementTo(
404     IStorage* iface,
405     LPCOLESTR pwcsName,
406     IStorage* pstgDest,
407     LPCOLESTR pwcsNewName,
408     DWORD grfFlags)
409 {
410     FIXME("\n");
411     return E_NOTIMPL;
412 }
413
414 static HRESULT WINAPI ITSS_IStorageImpl_Commit(
415     IStorage* iface,
416     DWORD grfCommitFlags)
417 {
418     FIXME("\n");
419     return E_NOTIMPL;
420 }
421
422 static HRESULT WINAPI ITSS_IStorageImpl_Revert(
423     IStorage* iface)
424 {
425     FIXME("\n");
426     return E_NOTIMPL;
427 }
428
429 static int ITSS_chm_enumerator(
430     struct chmFile *h,
431     struct chmUnitInfo *ui,
432     void *context)
433 {
434     struct enum_info *info;
435     IEnumSTATSTG_Impl* stgenum = context;
436
437     TRACE("adding %s to enumeration\n", debugstr_w(ui->path) );
438
439     info = HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info) );
440     memcpy( &info->ui, ui, sizeof info->ui );
441
442     info->next = NULL;
443     info->prev = stgenum->last;
444     if( stgenum->last )
445         stgenum->last->next = info;
446     else
447         stgenum->first = info;
448     stgenum->last = info;
449     
450     return CHM_ENUMERATOR_CONTINUE;
451 }
452
453 static HRESULT WINAPI ITSS_IStorageImpl_EnumElements(
454     IStorage* iface,
455     DWORD reserved1,
456     void* reserved2,
457     DWORD reserved3,
458     IEnumSTATSTG** ppenum)
459 {
460     ITSS_IStorageImpl *This = (ITSS_IStorageImpl *)iface;
461     IEnumSTATSTG_Impl* stgenum;
462
463     TRACE("%p %d %p %d %p\n", This, reserved1, reserved2, reserved3, ppenum );
464
465     stgenum = ITSS_create_enum();
466     if( !stgenum )
467         return E_FAIL;
468
469     chm_enumerate_dir(This->chmfile,
470                   This->dir,
471                   CHM_ENUMERATE_ALL,
472                   ITSS_chm_enumerator,
473                   stgenum );
474
475     stgenum->current = stgenum->first;
476
477     *ppenum = (IEnumSTATSTG*) stgenum;
478
479     return S_OK;
480 }
481
482 static HRESULT WINAPI ITSS_IStorageImpl_DestroyElement(
483     IStorage* iface,
484     LPCOLESTR pwcsName)
485 {
486     FIXME("\n");
487     return E_NOTIMPL;
488 }
489
490 static HRESULT WINAPI ITSS_IStorageImpl_RenameElement(
491     IStorage* iface,
492     LPCOLESTR pwcsOldName,
493     LPCOLESTR pwcsNewName)
494 {
495     FIXME("\n");
496     return E_NOTIMPL;
497 }
498
499 static HRESULT WINAPI ITSS_IStorageImpl_SetElementTimes(
500     IStorage* iface,
501     LPCOLESTR pwcsName,
502     const FILETIME* pctime,
503     const FILETIME* patime,
504     const FILETIME* pmtime)
505 {
506     FIXME("\n");
507     return E_NOTIMPL;
508 }
509
510 static HRESULT WINAPI ITSS_IStorageImpl_SetClass(
511     IStorage* iface,
512     REFCLSID clsid)
513 {
514     FIXME("\n");
515     return E_NOTIMPL;
516 }
517
518 static HRESULT WINAPI ITSS_IStorageImpl_SetStateBits(
519     IStorage* iface,
520     DWORD grfStateBits,
521     DWORD grfMask)
522 {
523     FIXME("\n");
524     return E_NOTIMPL;
525 }
526
527 static HRESULT WINAPI ITSS_IStorageImpl_Stat(
528     IStorage* iface,
529     STATSTG* pstatstg,
530     DWORD grfStatFlag)
531 {
532     FIXME("\n");
533     return E_NOTIMPL;
534 }
535
536 static const IStorageVtbl ITSS_IStorageImpl_Vtbl =
537 {
538     ITSS_IStorageImpl_QueryInterface,
539     ITSS_IStorageImpl_AddRef,
540     ITSS_IStorageImpl_Release,
541     ITSS_IStorageImpl_CreateStream,
542     ITSS_IStorageImpl_OpenStream,
543     ITSS_IStorageImpl_CreateStorage,
544     ITSS_IStorageImpl_OpenStorage,
545     ITSS_IStorageImpl_CopyTo,
546     ITSS_IStorageImpl_MoveElementTo,
547     ITSS_IStorageImpl_Commit,
548     ITSS_IStorageImpl_Revert,
549     ITSS_IStorageImpl_EnumElements,
550     ITSS_IStorageImpl_DestroyElement,
551     ITSS_IStorageImpl_RenameElement,
552     ITSS_IStorageImpl_SetElementTimes,
553     ITSS_IStorageImpl_SetClass,
554     ITSS_IStorageImpl_SetStateBits,
555     ITSS_IStorageImpl_Stat,
556 };
557
558 static HRESULT ITSS_create_chm_storage(
559       struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen )
560 {
561     ITSS_IStorageImpl *stg;
562     DWORD len;
563
564     TRACE("%p %s\n", chmfile, debugstr_w( dir ) );
565
566     len = strlenW( dir ) + 1;
567     stg = HeapAlloc( GetProcessHeap(), 0, 
568                      sizeof (ITSS_IStorageImpl) + len*sizeof(WCHAR) );
569     stg->vtbl_IStorage = &ITSS_IStorageImpl_Vtbl;
570     stg->ref = 1;
571     stg->chmfile = chmfile;
572     strcpyW( stg->dir, dir );
573
574     *ppstgOpen = (IStorage*) stg;
575
576     ITSS_LockModule();
577     return S_OK;
578 }
579
580 HRESULT ITSS_StgOpenStorage( 
581     const WCHAR* pwcsName,
582     IStorage* pstgPriority,
583     DWORD grfMode,
584     SNB snbExclude,
585     DWORD reserved,
586     IStorage** ppstgOpen)
587 {
588     struct chmFile *chmfile;
589     static const WCHAR szRoot[] = { '/', 0 };
590
591     TRACE("%s\n", debugstr_w(pwcsName) );
592
593     chmfile = chm_openW( pwcsName );
594     if( !chmfile )
595         return E_FAIL;
596
597     return ITSS_create_chm_storage( chmfile, szRoot, ppstgOpen );
598 }
599
600 /************************************************************************/
601
602 static HRESULT WINAPI ITSS_IStream_QueryInterface(
603     IStream* iface,
604     REFIID riid,
605     void** ppvObject)
606 {
607     IStream_Impl *This = (IStream_Impl *)iface;
608
609     if (IsEqualGUID(riid, &IID_IUnknown)
610         || IsEqualGUID(riid, &IID_ISequentialStream)
611         || IsEqualGUID(riid, &IID_IStream))
612     {
613         IStream_AddRef(iface);
614         *ppvObject = This;
615         return S_OK;
616     }
617
618     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
619     return E_NOINTERFACE;
620 }
621
622 static ULONG WINAPI ITSS_IStream_AddRef(
623     IStream* iface)
624 {
625     IStream_Impl *This = (IStream_Impl *)iface;
626     return InterlockedIncrement(&This->ref);
627 }
628
629 static ULONG WINAPI ITSS_IStream_Release(
630     IStream* iface)
631 {
632     IStream_Impl *This = (IStream_Impl *)iface;
633
634     ULONG ref = InterlockedDecrement(&This->ref);
635
636     if (ref == 0)
637     {
638         IStorage_Release( (IStorage*) This->stg );
639         HeapFree(GetProcessHeap(), 0, This);
640         ITSS_UnlockModule();
641     }
642
643     return ref;
644 }
645
646 static HRESULT WINAPI ITSS_IStream_Read(
647         IStream* iface,
648         void* pv,
649         ULONG cb,
650         ULONG* pcbRead)
651 {
652     IStream_Impl *This = (IStream_Impl *)iface;
653     ULONG count;
654
655     TRACE("%p %p %u %p\n", This, pv, cb, pcbRead);
656
657     count = chm_retrieve_object(This->stg->chmfile, 
658                           &This->ui, pv, This->addr, cb);
659     This->addr += count;
660     if( pcbRead )
661         *pcbRead = count;
662     
663     return S_OK;
664 }
665
666 static HRESULT WINAPI ITSS_IStream_Write(
667         IStream* iface,
668         const void* pv,
669         ULONG cb,
670         ULONG* pcbWritten)
671 {
672     FIXME("\n");
673     return E_NOTIMPL;
674 }
675
676 static HRESULT WINAPI ITSS_IStream_Seek(
677         IStream* iface,
678         LARGE_INTEGER dlibMove,
679         DWORD dwOrigin,
680         ULARGE_INTEGER* plibNewPosition)
681 {
682     IStream_Impl *This = (IStream_Impl *)iface;
683     LONGLONG newpos;
684
685     TRACE("%p %s %u %p\n", This,
686           wine_dbgstr_longlong( dlibMove.QuadPart ), dwOrigin, plibNewPosition );
687
688     newpos = This->addr;
689     switch( dwOrigin )
690     {
691     case STREAM_SEEK_CUR:
692         newpos = This->addr + dlibMove.QuadPart;
693         break;
694     case STREAM_SEEK_SET:
695         newpos = dlibMove.QuadPart;
696         break;
697     case STREAM_SEEK_END:
698         newpos = This->ui.length + dlibMove.QuadPart;
699         break;
700     }
701
702     if( ( newpos < 0 ) || ( newpos > This->ui.length ) )
703         return STG_E_INVALIDPOINTER;
704
705     This->addr = newpos;
706     if( plibNewPosition )
707         plibNewPosition->QuadPart = This->addr;
708
709     return S_OK;
710 }
711
712 static HRESULT WINAPI ITSS_IStream_SetSize(
713         IStream* iface,
714         ULARGE_INTEGER libNewSize)
715 {
716     FIXME("\n");
717     return E_NOTIMPL;
718 }
719
720 static HRESULT WINAPI ITSS_IStream_CopyTo(
721         IStream* iface,
722         IStream* pstm,
723         ULARGE_INTEGER cb,
724         ULARGE_INTEGER* pcbRead,
725         ULARGE_INTEGER* pcbWritten)
726 {
727     FIXME("\n");
728     return E_NOTIMPL;
729 }
730
731 static HRESULT WINAPI ITSS_IStream_Commit(
732         IStream* iface,
733         DWORD grfCommitFlags)
734 {
735     FIXME("\n");
736     return E_NOTIMPL;
737 }
738
739 static HRESULT WINAPI ITSS_IStream_Revert(
740         IStream* iface)
741 {
742     FIXME("\n");
743     return E_NOTIMPL;
744 }
745
746 static HRESULT WINAPI ITSS_IStream_LockRegion(
747         IStream* iface,
748         ULARGE_INTEGER libOffset,
749         ULARGE_INTEGER cb,
750         DWORD dwLockType)
751 {
752     FIXME("\n");
753     return E_NOTIMPL;
754 }
755
756 static HRESULT WINAPI ITSS_IStream_UnlockRegion(
757         IStream* iface,
758         ULARGE_INTEGER libOffset,
759         ULARGE_INTEGER cb,
760         DWORD dwLockType)
761 {
762     FIXME("\n");
763     return E_NOTIMPL;
764 }
765
766 static HRESULT WINAPI ITSS_IStream_Stat(
767         IStream* iface,
768         STATSTG* pstatstg,
769         DWORD grfStatFlag)
770 {
771     IStream_Impl *This = (IStream_Impl *)iface;
772
773     TRACE("%p %p %d\n", This, pstatstg, grfStatFlag);
774
775     memset( pstatstg, 0, sizeof *pstatstg );
776     if( !( grfStatFlag & STATFLAG_NONAME ) )
777     {
778         FIXME("copy the name\n");
779     }
780     pstatstg->type = STGTY_STREAM;
781     pstatstg->cbSize.QuadPart = This->ui.length;
782     pstatstg->grfMode = STGM_READ;
783     memcpy( &pstatstg->clsid, &CLSID_ITStorage, sizeof (CLSID) );
784
785     return S_OK;
786 }
787
788 static HRESULT WINAPI ITSS_IStream_Clone(
789         IStream* iface,
790         IStream** ppstm)
791 {
792     FIXME("\n");
793     return E_NOTIMPL;
794 }
795
796 static const IStreamVtbl ITSS_IStream_vtbl =
797 {
798     ITSS_IStream_QueryInterface,
799     ITSS_IStream_AddRef,
800     ITSS_IStream_Release,
801     ITSS_IStream_Read,
802     ITSS_IStream_Write,
803     ITSS_IStream_Seek,
804     ITSS_IStream_SetSize,
805     ITSS_IStream_CopyTo,
806     ITSS_IStream_Commit,
807     ITSS_IStream_Revert,
808     ITSS_IStream_LockRegion,
809     ITSS_IStream_UnlockRegion,
810     ITSS_IStream_Stat,
811     ITSS_IStream_Clone,
812 };
813
814 static IStream_Impl *ITSS_create_stream(
815            ITSS_IStorageImpl *stg, struct chmUnitInfo *ui )
816 {
817     IStream_Impl *stm;
818
819     stm = HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl) );
820     stm->vtbl_IStream = &ITSS_IStream_vtbl;
821     stm->ref = 1;
822     stm->addr = 0;
823     memcpy( &stm->ui, ui, sizeof stm->ui );
824     stm->stg = stg;
825     IStorage_AddRef( (IStorage*) stg );
826
827     ITSS_LockModule();
828
829     TRACE(" -> %p\n", stm );
830
831     return stm;
832 }