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