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