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