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