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
impl_from_IStorage(IStorage * iface)74 static inline ITSS_IStorageImpl *impl_from_IStorage(IStorage *iface)
75 {
76 return CONTAINING_RECORD(iface, ITSS_IStorageImpl, IStorage_iface);
77 }
78
impl_from_IEnumSTATSTG(IEnumSTATSTG * iface)79 static inline IEnumSTATSTG_Impl *impl_from_IEnumSTATSTG(IEnumSTATSTG *iface)
80 {
81 return CONTAINING_RECORD(iface, IEnumSTATSTG_Impl, IEnumSTATSTG_iface);
82 }
83
impl_from_IStream(IStream * iface)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
ITSS_IEnumSTATSTG_QueryInterface(IEnumSTATSTG * iface,REFIID riid,void ** ppvObject)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
ITSS_IEnumSTATSTG_AddRef(IEnumSTATSTG * iface)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
ITSS_IEnumSTATSTG_Release(IEnumSTATSTG * iface)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
ITSS_IEnumSTATSTG_Next(IEnumSTATSTG * iface,ULONG celt,STATSTG * rgelt,ULONG * pceltFetched)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
ITSS_IEnumSTATSTG_Skip(IEnumSTATSTG * iface,ULONG celt)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
ITSS_IEnumSTATSTG_Reset(IEnumSTATSTG * iface)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
ITSS_IEnumSTATSTG_Clone(IEnumSTATSTG * iface,IEnumSTATSTG ** ppenum)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
ITSS_create_enum(void)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
ITSS_IStorageImpl_QueryInterface(IStorage * iface,REFIID riid,void ** ppvObject)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
ITSS_IStorageImpl_AddRef(IStorage * iface)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
ITSS_IStorageImpl_Release(IStorage * iface)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
ITSS_IStorageImpl_CreateStream(IStorage * iface,LPCOLESTR pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2,IStream ** ppstm)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
ITSS_IStorageImpl_OpenStream(IStorage * iface,LPCOLESTR pwcsName,void * reserved1,DWORD grfMode,DWORD reserved2,IStream ** ppstm)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
ITSS_IStorageImpl_CreateStorage(IStorage * iface,LPCOLESTR pwcsName,DWORD grfMode,DWORD dwStgFmt,DWORD reserved2,IStorage ** ppstg)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
ITSS_IStorageImpl_OpenStorage(IStorage * iface,LPCOLESTR pwcsName,IStorage * pstgPriority,DWORD grfMode,SNB snbExclude,DWORD reserved,IStorage ** ppstg)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
ITSS_IStorageImpl_CopyTo(IStorage * iface,DWORD ciidExclude,const IID * rgiidExclude,SNB snbExclude,IStorage * pstgDest)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
ITSS_IStorageImpl_MoveElementTo(IStorage * iface,LPCOLESTR pwcsName,IStorage * pstgDest,LPCOLESTR pwcsNewName,DWORD grfFlags)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
ITSS_IStorageImpl_Commit(IStorage * iface,DWORD grfCommitFlags)469 static HRESULT WINAPI ITSS_IStorageImpl_Commit(
470 IStorage* iface,
471 DWORD grfCommitFlags)
472 {
473 FIXME("\n");
474 return E_NOTIMPL;
475 }
476
ITSS_IStorageImpl_Revert(IStorage * iface)477 static HRESULT WINAPI ITSS_IStorageImpl_Revert(
478 IStorage* iface)
479 {
480 FIXME("\n");
481 return E_NOTIMPL;
482 }
483
ITSS_chm_enumerator(struct chmFile * h,struct chmUnitInfo * ui,void * context)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
ITSS_IStorageImpl_EnumElements(IStorage * iface,DWORD reserved1,void * reserved2,DWORD reserved3,IEnumSTATSTG ** ppenum)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
ITSS_IStorageImpl_DestroyElement(IStorage * iface,LPCOLESTR pwcsName)537 static HRESULT WINAPI ITSS_IStorageImpl_DestroyElement(
538 IStorage* iface,
539 LPCOLESTR pwcsName)
540 {
541 FIXME("\n");
542 return E_NOTIMPL;
543 }
544
ITSS_IStorageImpl_RenameElement(IStorage * iface,LPCOLESTR pwcsOldName,LPCOLESTR pwcsNewName)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
ITSS_IStorageImpl_SetElementTimes(IStorage * iface,LPCOLESTR pwcsName,const FILETIME * pctime,const FILETIME * patime,const FILETIME * pmtime)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
ITSS_IStorageImpl_SetClass(IStorage * iface,REFCLSID clsid)565 static HRESULT WINAPI ITSS_IStorageImpl_SetClass(
566 IStorage* iface,
567 REFCLSID clsid)
568 {
569 FIXME("\n");
570 return E_NOTIMPL;
571 }
572
ITSS_IStorageImpl_SetStateBits(IStorage * iface,DWORD grfStateBits,DWORD grfMask)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
ITSS_IStorageImpl_Stat(IStorage * iface,STATSTG * pstatstg,DWORD grfStatFlag)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
ITSS_create_chm_storage(struct chmFile * chmfile,const WCHAR * dir,IStorage ** ppstgOpen)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
ITSS_StgOpenStorage(const WCHAR * pwcsName,IStorage * pstgPriority,DWORD grfMode,SNB snbExclude,DWORD reserved,IStorage ** ppstgOpen)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
ITSS_IStream_QueryInterface(IStream * iface,REFIID riid,void ** ppvObject)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
ITSS_IStream_AddRef(IStream * iface)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
ITSS_IStream_Release(IStream * iface)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
ITSS_IStream_Read(IStream * iface,void * pv,ULONG cb,ULONG * pcbRead)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
ITSS_IStream_Write(IStream * iface,const void * pv,ULONG cb,ULONG * pcbWritten)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
ITSS_IStream_Seek(IStream * iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER * plibNewPosition)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
ITSS_IStream_SetSize(IStream * iface,ULARGE_INTEGER libNewSize)765 static HRESULT WINAPI ITSS_IStream_SetSize(
766 IStream* iface,
767 ULARGE_INTEGER libNewSize)
768 {
769 FIXME("\n");
770 return E_NOTIMPL;
771 }
772
ITSS_IStream_CopyTo(IStream * iface,IStream * pstm,ULARGE_INTEGER cb,ULARGE_INTEGER * pcbRead,ULARGE_INTEGER * pcbWritten)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
ITSS_IStream_Commit(IStream * iface,DWORD grfCommitFlags)784 static HRESULT WINAPI ITSS_IStream_Commit(
785 IStream* iface,
786 DWORD grfCommitFlags)
787 {
788 FIXME("\n");
789 return E_NOTIMPL;
790 }
791
ITSS_IStream_Revert(IStream * iface)792 static HRESULT WINAPI ITSS_IStream_Revert(
793 IStream* iface)
794 {
795 FIXME("\n");
796 return E_NOTIMPL;
797 }
798
ITSS_IStream_LockRegion(IStream * iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)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
ITSS_IStream_UnlockRegion(IStream * iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)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
ITSS_IStream_Stat(IStream * iface,STATSTG * pstatstg,DWORD grfStatFlag)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
ITSS_IStream_Clone(IStream * iface,IStream ** ppstm)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
ITSS_create_stream(ITSS_IStorageImpl * stg,struct chmUnitInfo * ui)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