itss: Enlarge buffer to include space for a concatenated value.
[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     struct chmFile *chmfile;
410     WCHAR *path, *p;
411     DWORD len;
412
413     TRACE("%p %s %p %u %p %u %p\n", This, debugstr_w(pwcsName),
414           pstgPriority, grfMode, snbExclude, reserved, ppstg);
415
416     chmfile = chm_dup( This->chmfile );
417     if( !chmfile )
418         return E_FAIL;
419
420     len = strlenW( This->dir ) + strlenW( pwcsName ) + 2; /* need room for a terminating slash */
421     path = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
422     strcpyW( path, This->dir );
423
424     if( pwcsName[0] == '/' || pwcsName[0] == '\\' )
425     {
426         p = &path[strlenW( path ) - 1];
427         while( ( path <= p ) && ( *p == '/' ) )
428             *p-- = 0;
429     }
430     strcatW( path, pwcsName );
431
432     for(p=path; *p; p++) {
433         if(*p == '\\')
434             *p = '/';
435     }
436
437     /* add a terminating slash if one does not already exist */
438     if(*(p-1) != '/')
439     {
440         *p++ = '/';
441         *p = 0;
442     }
443
444     TRACE("Resolving %s\n", debugstr_w(path));
445
446     return ITSS_create_chm_storage(chmfile, path, ppstg);
447 }
448
449 static HRESULT WINAPI ITSS_IStorageImpl_CopyTo(
450     IStorage* iface,
451     DWORD ciidExclude,
452     const IID* rgiidExclude,
453     SNB snbExclude,
454     IStorage* pstgDest)
455 {
456     FIXME("\n");
457     return E_NOTIMPL;
458 }
459
460 static HRESULT WINAPI ITSS_IStorageImpl_MoveElementTo(
461     IStorage* iface,
462     LPCOLESTR pwcsName,
463     IStorage* pstgDest,
464     LPCOLESTR pwcsNewName,
465     DWORD grfFlags)
466 {
467     FIXME("\n");
468     return E_NOTIMPL;
469 }
470
471 static HRESULT WINAPI ITSS_IStorageImpl_Commit(
472     IStorage* iface,
473     DWORD grfCommitFlags)
474 {
475     FIXME("\n");
476     return E_NOTIMPL;
477 }
478
479 static HRESULT WINAPI ITSS_IStorageImpl_Revert(
480     IStorage* iface)
481 {
482     FIXME("\n");
483     return E_NOTIMPL;
484 }
485
486 static int ITSS_chm_enumerator(
487     struct chmFile *h,
488     struct chmUnitInfo *ui,
489     void *context)
490 {
491     struct enum_info *info;
492     IEnumSTATSTG_Impl* stgenum = context;
493
494     TRACE("adding %s to enumeration\n", debugstr_w(ui->path) );
495
496     info = HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info) );
497     info->ui = *ui;
498
499     info->next = NULL;
500     info->prev = stgenum->last;
501     if( stgenum->last )
502         stgenum->last->next = info;
503     else
504         stgenum->first = info;
505     stgenum->last = info;
506     
507     return CHM_ENUMERATOR_CONTINUE;
508 }
509
510 static HRESULT WINAPI ITSS_IStorageImpl_EnumElements(
511     IStorage* iface,
512     DWORD reserved1,
513     void* reserved2,
514     DWORD reserved3,
515     IEnumSTATSTG** ppenum)
516 {
517     ITSS_IStorageImpl *This = impl_from_IStorage(iface);
518     IEnumSTATSTG_Impl* stgenum;
519
520     TRACE("%p %d %p %d %p\n", This, reserved1, reserved2, reserved3, ppenum );
521
522     stgenum = ITSS_create_enum();
523     if( !stgenum )
524         return E_FAIL;
525
526     chm_enumerate_dir(This->chmfile,
527                   This->dir,
528                   CHM_ENUMERATE_ALL,
529                   ITSS_chm_enumerator,
530                   stgenum );
531
532     stgenum->current = stgenum->first;
533
534     *ppenum = &stgenum->IEnumSTATSTG_iface;
535
536     return S_OK;
537 }
538
539 static HRESULT WINAPI ITSS_IStorageImpl_DestroyElement(
540     IStorage* iface,
541     LPCOLESTR pwcsName)
542 {
543     FIXME("\n");
544     return E_NOTIMPL;
545 }
546
547 static HRESULT WINAPI ITSS_IStorageImpl_RenameElement(
548     IStorage* iface,
549     LPCOLESTR pwcsOldName,
550     LPCOLESTR pwcsNewName)
551 {
552     FIXME("\n");
553     return E_NOTIMPL;
554 }
555
556 static HRESULT WINAPI ITSS_IStorageImpl_SetElementTimes(
557     IStorage* iface,
558     LPCOLESTR pwcsName,
559     const FILETIME* pctime,
560     const FILETIME* patime,
561     const FILETIME* pmtime)
562 {
563     FIXME("\n");
564     return E_NOTIMPL;
565 }
566
567 static HRESULT WINAPI ITSS_IStorageImpl_SetClass(
568     IStorage* iface,
569     REFCLSID clsid)
570 {
571     FIXME("\n");
572     return E_NOTIMPL;
573 }
574
575 static HRESULT WINAPI ITSS_IStorageImpl_SetStateBits(
576     IStorage* iface,
577     DWORD grfStateBits,
578     DWORD grfMask)
579 {
580     FIXME("\n");
581     return E_NOTIMPL;
582 }
583
584 static HRESULT WINAPI ITSS_IStorageImpl_Stat(
585     IStorage* iface,
586     STATSTG* pstatstg,
587     DWORD grfStatFlag)
588 {
589     FIXME("\n");
590     return E_NOTIMPL;
591 }
592
593 static const IStorageVtbl ITSS_IStorageImpl_Vtbl =
594 {
595     ITSS_IStorageImpl_QueryInterface,
596     ITSS_IStorageImpl_AddRef,
597     ITSS_IStorageImpl_Release,
598     ITSS_IStorageImpl_CreateStream,
599     ITSS_IStorageImpl_OpenStream,
600     ITSS_IStorageImpl_CreateStorage,
601     ITSS_IStorageImpl_OpenStorage,
602     ITSS_IStorageImpl_CopyTo,
603     ITSS_IStorageImpl_MoveElementTo,
604     ITSS_IStorageImpl_Commit,
605     ITSS_IStorageImpl_Revert,
606     ITSS_IStorageImpl_EnumElements,
607     ITSS_IStorageImpl_DestroyElement,
608     ITSS_IStorageImpl_RenameElement,
609     ITSS_IStorageImpl_SetElementTimes,
610     ITSS_IStorageImpl_SetClass,
611     ITSS_IStorageImpl_SetStateBits,
612     ITSS_IStorageImpl_Stat,
613 };
614
615 static HRESULT ITSS_create_chm_storage(
616       struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen )
617 {
618     ITSS_IStorageImpl *stg;
619     DWORD len;
620
621     TRACE("%p %s\n", chmfile, debugstr_w( dir ) );
622
623     len = strlenW( dir ) + 1;
624     stg = HeapAlloc( GetProcessHeap(), 0, 
625                      sizeof (ITSS_IStorageImpl) + len*sizeof(WCHAR) );
626     stg->IStorage_iface.lpVtbl = &ITSS_IStorageImpl_Vtbl;
627     stg->ref = 1;
628     stg->chmfile = chmfile;
629     strcpyW( stg->dir, dir );
630
631     *ppstgOpen = &stg->IStorage_iface;
632
633     ITSS_LockModule();
634     return S_OK;
635 }
636
637 HRESULT ITSS_StgOpenStorage( 
638     const WCHAR* pwcsName,
639     IStorage* pstgPriority,
640     DWORD grfMode,
641     SNB snbExclude,
642     DWORD reserved,
643     IStorage** ppstgOpen)
644 {
645     struct chmFile *chmfile;
646     static const WCHAR szRoot[] = { '/', 0 };
647
648     TRACE("%s\n", debugstr_w(pwcsName) );
649
650     chmfile = chm_openW( pwcsName );
651     if( !chmfile )
652         return E_FAIL;
653
654     return ITSS_create_chm_storage( chmfile, szRoot, ppstgOpen );
655 }
656
657 /************************************************************************/
658
659 static HRESULT WINAPI ITSS_IStream_QueryInterface(
660     IStream* iface,
661     REFIID riid,
662     void** ppvObject)
663 {
664     IStream_Impl *This = impl_from_IStream(iface);
665
666     if (IsEqualGUID(riid, &IID_IUnknown)
667         || IsEqualGUID(riid, &IID_ISequentialStream)
668         || IsEqualGUID(riid, &IID_IStream))
669     {
670         IStream_AddRef(iface);
671         *ppvObject = This;
672         return S_OK;
673     }
674
675     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
676     return E_NOINTERFACE;
677 }
678
679 static ULONG WINAPI ITSS_IStream_AddRef(
680     IStream* iface)
681 {
682     IStream_Impl *This = impl_from_IStream(iface);
683     return InterlockedIncrement(&This->ref);
684 }
685
686 static ULONG WINAPI ITSS_IStream_Release(
687     IStream* iface)
688 {
689     IStream_Impl *This = impl_from_IStream(iface);
690
691     ULONG ref = InterlockedDecrement(&This->ref);
692
693     if (ref == 0)
694     {
695         IStorage_Release( &This->stg->IStorage_iface );
696         HeapFree(GetProcessHeap(), 0, This);
697         ITSS_UnlockModule();
698     }
699
700     return ref;
701 }
702
703 static HRESULT WINAPI ITSS_IStream_Read(
704         IStream* iface,
705         void* pv,
706         ULONG cb,
707         ULONG* pcbRead)
708 {
709     IStream_Impl *This = impl_from_IStream(iface);
710     ULONG count;
711
712     TRACE("%p %p %u %p\n", This, pv, cb, pcbRead);
713
714     count = chm_retrieve_object(This->stg->chmfile, 
715                           &This->ui, pv, This->addr, cb);
716     This->addr += count;
717     if( pcbRead )
718         *pcbRead = count;
719
720     return count ? S_OK : S_FALSE;
721 }
722
723 static HRESULT WINAPI ITSS_IStream_Write(
724         IStream* iface,
725         const void* pv,
726         ULONG cb,
727         ULONG* pcbWritten)
728 {
729     FIXME("\n");
730     return E_NOTIMPL;
731 }
732
733 static HRESULT WINAPI ITSS_IStream_Seek(
734         IStream* iface,
735         LARGE_INTEGER dlibMove,
736         DWORD dwOrigin,
737         ULARGE_INTEGER* plibNewPosition)
738 {
739     IStream_Impl *This = impl_from_IStream(iface);
740     LONGLONG newpos;
741
742     TRACE("%p %s %u %p\n", This,
743           wine_dbgstr_longlong( dlibMove.QuadPart ), dwOrigin, plibNewPosition );
744
745     newpos = This->addr;
746     switch( dwOrigin )
747     {
748     case STREAM_SEEK_CUR:
749         newpos = This->addr + dlibMove.QuadPart;
750         break;
751     case STREAM_SEEK_SET:
752         newpos = dlibMove.QuadPart;
753         break;
754     case STREAM_SEEK_END:
755         newpos = This->ui.length + dlibMove.QuadPart;
756         break;
757     }
758
759     if( ( newpos < 0 ) || ( newpos > This->ui.length ) )
760         return STG_E_INVALIDPOINTER;
761
762     This->addr = newpos;
763     if( plibNewPosition )
764         plibNewPosition->QuadPart = This->addr;
765
766     return S_OK;
767 }
768
769 static HRESULT WINAPI ITSS_IStream_SetSize(
770         IStream* iface,
771         ULARGE_INTEGER libNewSize)
772 {
773     FIXME("\n");
774     return E_NOTIMPL;
775 }
776
777 static HRESULT WINAPI ITSS_IStream_CopyTo(
778         IStream* iface,
779         IStream* pstm,
780         ULARGE_INTEGER cb,
781         ULARGE_INTEGER* pcbRead,
782         ULARGE_INTEGER* pcbWritten)
783 {
784     FIXME("\n");
785     return E_NOTIMPL;
786 }
787
788 static HRESULT WINAPI ITSS_IStream_Commit(
789         IStream* iface,
790         DWORD grfCommitFlags)
791 {
792     FIXME("\n");
793     return E_NOTIMPL;
794 }
795
796 static HRESULT WINAPI ITSS_IStream_Revert(
797         IStream* iface)
798 {
799     FIXME("\n");
800     return E_NOTIMPL;
801 }
802
803 static HRESULT WINAPI ITSS_IStream_LockRegion(
804         IStream* iface,
805         ULARGE_INTEGER libOffset,
806         ULARGE_INTEGER cb,
807         DWORD dwLockType)
808 {
809     FIXME("\n");
810     return E_NOTIMPL;
811 }
812
813 static HRESULT WINAPI ITSS_IStream_UnlockRegion(
814         IStream* iface,
815         ULARGE_INTEGER libOffset,
816         ULARGE_INTEGER cb,
817         DWORD dwLockType)
818 {
819     FIXME("\n");
820     return E_NOTIMPL;
821 }
822
823 static HRESULT WINAPI ITSS_IStream_Stat(
824         IStream* iface,
825         STATSTG* pstatstg,
826         DWORD grfStatFlag)
827 {
828     IStream_Impl *This = impl_from_IStream(iface);
829
830     TRACE("%p %p %d\n", This, pstatstg, grfStatFlag);
831
832     memset( pstatstg, 0, sizeof *pstatstg );
833     if( !( grfStatFlag & STATFLAG_NONAME ) )
834     {
835         FIXME("copy the name\n");
836     }
837     pstatstg->type = STGTY_STREAM;
838     pstatstg->cbSize.QuadPart = This->ui.length;
839     pstatstg->grfMode = STGM_READ;
840     pstatstg->clsid = CLSID_ITStorage;
841
842     return S_OK;
843 }
844
845 static HRESULT WINAPI ITSS_IStream_Clone(
846         IStream* iface,
847         IStream** ppstm)
848 {
849     FIXME("\n");
850     return E_NOTIMPL;
851 }
852
853 static const IStreamVtbl ITSS_IStream_vtbl =
854 {
855     ITSS_IStream_QueryInterface,
856     ITSS_IStream_AddRef,
857     ITSS_IStream_Release,
858     ITSS_IStream_Read,
859     ITSS_IStream_Write,
860     ITSS_IStream_Seek,
861     ITSS_IStream_SetSize,
862     ITSS_IStream_CopyTo,
863     ITSS_IStream_Commit,
864     ITSS_IStream_Revert,
865     ITSS_IStream_LockRegion,
866     ITSS_IStream_UnlockRegion,
867     ITSS_IStream_Stat,
868     ITSS_IStream_Clone,
869 };
870
871 static IStream_Impl *ITSS_create_stream(
872            ITSS_IStorageImpl *stg, struct chmUnitInfo *ui )
873 {
874     IStream_Impl *stm;
875
876     stm = HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl) );
877     stm->IStream_iface.lpVtbl = &ITSS_IStream_vtbl;
878     stm->ref = 1;
879     stm->addr = 0;
880     stm->ui = *ui;
881     stm->stg = stg;
882     IStorage_AddRef( &stg->IStorage_iface );
883
884     ITSS_LockModule();
885
886     TRACE(" -> %p\n", stm );
887
888     return stm;
889 }