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