2 * ITSS Storage implementation
4 * Copyright 2004 Mike McCormack
6 * see http://bonedaddy.net/pabs3/hhm/#chmspec
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.
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.
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
37 #include "wine/itss.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(itss
);
42 /************************************************************************/
44 typedef struct _ITSS_IStorageImpl
46 IStorage IStorage_iface
;
48 struct chmFile
*chmfile
;
54 struct enum_info
*next
, *prev
;
55 struct chmUnitInfo ui
;
58 typedef struct _IEnumSTATSTG_Impl
60 IEnumSTATSTG IEnumSTATSTG_iface
;
62 struct enum_info
*first
, *last
, *current
;
65 typedef struct _IStream_Impl
67 IStream IStream_iface
;
69 ITSS_IStorageImpl
*stg
;
71 struct chmUnitInfo ui
;
74 static inline ITSS_IStorageImpl
*impl_from_IStorage(IStorage
*iface
)
76 return CONTAINING_RECORD(iface
, ITSS_IStorageImpl
, IStorage_iface
);
79 static inline IEnumSTATSTG_Impl
*impl_from_IEnumSTATSTG(IEnumSTATSTG
*iface
)
81 return CONTAINING_RECORD(iface
, IEnumSTATSTG_Impl
, IEnumSTATSTG_iface
);
84 static inline IStream_Impl
*impl_from_IStream(IStream
*iface
)
86 return CONTAINING_RECORD(iface
, IStream_Impl
, IStream_iface
);
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
);
94 /************************************************************************/
96 static HRESULT WINAPI
ITSS_IEnumSTATSTG_QueryInterface(
101 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
103 if (IsEqualGUID(riid
, &IID_IUnknown
)
104 || IsEqualGUID(riid
, &IID_IEnumSTATSTG
))
106 IEnumSTATSTG_AddRef(iface
);
107 *ppvObject
= &This
->IEnumSTATSTG_iface
;
111 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
112 return E_NOINTERFACE
;
115 static ULONG WINAPI
ITSS_IEnumSTATSTG_AddRef(
118 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
119 return InterlockedIncrement(&This
->ref
);
122 static ULONG WINAPI
ITSS_IEnumSTATSTG_Release(
125 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
127 ULONG ref
= InterlockedDecrement(&This
->ref
);
133 struct enum_info
*t
= This
->first
->next
;
134 HeapFree( GetProcessHeap(), 0, This
->first
);
137 HeapFree(GetProcessHeap(), 0, This
);
144 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Next(
150 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
152 struct enum_info
*cur
;
154 TRACE("%p %u %p %p\n", This
, celt
, rgelt
, pceltFetched
);
158 while( (n
<celt
) && cur
)
162 memset( rgelt
, 0, sizeof *rgelt
);
168 len
= lstrlenW( str
) + 1;
169 rgelt
->pwcsName
= CoTaskMemAlloc( len
*sizeof(WCHAR
) );
170 lstrcpyW( rgelt
->pwcsName
, str
);
172 /* determine the type */
173 if( rgelt
->pwcsName
[len
-2] == '/' )
175 rgelt
->pwcsName
[len
-2] = 0;
176 rgelt
->type
= STGTY_STORAGE
;
179 rgelt
->type
= STGTY_STREAM
;
182 rgelt
->cbSize
.QuadPart
= cur
->ui
.length
;
184 /* advance to the next item if it exists */
198 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Skip(
202 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
204 struct enum_info
*cur
;
206 TRACE("%p %u\n", This
, celt
);
210 while( (n
<celt
) && cur
)
223 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Reset(
226 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
228 TRACE("%p\n", This
);
230 This
->current
= This
->first
;
235 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Clone(
237 IEnumSTATSTG
** ppenum
)
243 static const IEnumSTATSTGVtbl IEnumSTATSTG_vtbl
=
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
254 static IEnumSTATSTG_Impl
*ITSS_create_enum( void )
256 IEnumSTATSTG_Impl
*stgenum
;
258 stgenum
= HeapAlloc( GetProcessHeap(), 0, sizeof (IEnumSTATSTG_Impl
) );
259 stgenum
->IEnumSTATSTG_iface
.lpVtbl
= &IEnumSTATSTG_vtbl
;
261 stgenum
->first
= NULL
;
262 stgenum
->last
= NULL
;
263 stgenum
->current
= NULL
;
266 TRACE(" -> %p\n", stgenum
);
271 /************************************************************************/
273 static HRESULT WINAPI
ITSS_IStorageImpl_QueryInterface(
278 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
280 if (IsEqualGUID(riid
, &IID_IUnknown
)
281 || IsEqualGUID(riid
, &IID_IStorage
))
283 IStorage_AddRef(iface
);
284 *ppvObject
= &This
->IStorage_iface
;
288 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
289 return E_NOINTERFACE
;
292 static ULONG WINAPI
ITSS_IStorageImpl_AddRef(
295 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
296 return InterlockedIncrement(&This
->ref
);
299 static ULONG WINAPI
ITSS_IStorageImpl_Release(
302 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
304 ULONG ref
= InterlockedDecrement(&This
->ref
);
308 chm_close(This
->chmfile
);
309 HeapFree(GetProcessHeap(), 0, This
);
316 static HRESULT WINAPI
ITSS_IStorageImpl_CreateStream(
328 static HRESULT WINAPI
ITSS_IStorageImpl_OpenStream(
336 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
339 struct chmUnitInfo ui
;
343 TRACE("%p %s %p %u %u %p\n", This
, debugstr_w(pwcsName
),
344 reserved1
, grfMode
, reserved2
, ppstm
);
346 len
= lstrlenW( This
->dir
) + lstrlenW( pwcsName
) + 1;
347 path
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
348 lstrcpyW( path
, This
->dir
);
350 if( pwcsName
[0] == '/' || pwcsName
[0] == '\\' )
352 p
= &path
[lstrlenW( path
) - 1];
353 while( ( path
<= p
) && ( *p
== '/' ) )
356 lstrcatW( path
, pwcsName
);
358 for(p
=path
; *p
; p
++) {
366 TRACE("Resolving %s\n", debugstr_w(path
));
368 r
= chm_resolve_object(This
->chmfile
, path
, &ui
);
369 HeapFree( GetProcessHeap(), 0, path
);
371 if( r
!= CHM_RESOLVE_SUCCESS
) {
372 WARN("Could not resolve object\n");
373 return STG_E_FILENOTFOUND
;
376 stm
= ITSS_create_stream( This
, &ui
);
380 *ppstm
= &stm
->IStream_iface
;
385 static HRESULT WINAPI
ITSS_IStorageImpl_CreateStorage(
397 static HRESULT WINAPI
ITSS_IStorageImpl_OpenStorage(
400 IStorage
* pstgPriority
,
406 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
407 struct chmFile
*chmfile
;
411 TRACE("%p %s %p %u %p %u %p\n", This
, debugstr_w(pwcsName
),
412 pstgPriority
, grfMode
, snbExclude
, reserved
, ppstg
);
414 chmfile
= chm_dup( This
->chmfile
);
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
);
422 if( pwcsName
[0] == '/' || pwcsName
[0] == '\\' )
424 p
= &path
[lstrlenW( path
) - 1];
425 while( ( path
<= p
) && ( *p
== '/' ) )
428 lstrcatW( path
, pwcsName
);
430 for(p
=path
; *p
; p
++) {
435 /* add a terminating slash if one does not already exist */
442 TRACE("Resolving %s\n", debugstr_w(path
));
444 return ITSS_create_chm_storage(chmfile
, path
, ppstg
);
447 static HRESULT WINAPI
ITSS_IStorageImpl_CopyTo(
450 const IID
* rgiidExclude
,
458 static HRESULT WINAPI
ITSS_IStorageImpl_MoveElementTo(
462 LPCOLESTR pwcsNewName
,
469 static HRESULT WINAPI
ITSS_IStorageImpl_Commit(
471 DWORD grfCommitFlags
)
477 static HRESULT WINAPI
ITSS_IStorageImpl_Revert(
484 static int ITSS_chm_enumerator(
486 struct chmUnitInfo
*ui
,
489 struct enum_info
*info
;
490 IEnumSTATSTG_Impl
* stgenum
= context
;
492 TRACE("adding %s to enumeration\n", debugstr_w(ui
->path
) );
494 info
= HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info
) );
498 info
->prev
= stgenum
->last
;
500 stgenum
->last
->next
= info
;
502 stgenum
->first
= info
;
503 stgenum
->last
= info
;
505 return CHM_ENUMERATOR_CONTINUE
;
508 static HRESULT WINAPI
ITSS_IStorageImpl_EnumElements(
513 IEnumSTATSTG
** ppenum
)
515 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
516 IEnumSTATSTG_Impl
* stgenum
;
518 TRACE("%p %d %p %d %p\n", This
, reserved1
, reserved2
, reserved3
, ppenum
);
520 stgenum
= ITSS_create_enum();
524 chm_enumerate_dir(This
->chmfile
,
530 stgenum
->current
= stgenum
->first
;
532 *ppenum
= &stgenum
->IEnumSTATSTG_iface
;
537 static HRESULT WINAPI
ITSS_IStorageImpl_DestroyElement(
545 static HRESULT WINAPI
ITSS_IStorageImpl_RenameElement(
547 LPCOLESTR pwcsOldName
,
548 LPCOLESTR pwcsNewName
)
554 static HRESULT WINAPI
ITSS_IStorageImpl_SetElementTimes(
557 const FILETIME
* pctime
,
558 const FILETIME
* patime
,
559 const FILETIME
* pmtime
)
565 static HRESULT WINAPI
ITSS_IStorageImpl_SetClass(
573 static HRESULT WINAPI
ITSS_IStorageImpl_SetStateBits(
582 static HRESULT WINAPI
ITSS_IStorageImpl_Stat(
591 static const IStorageVtbl ITSS_IStorageImpl_Vtbl
=
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
,
613 static HRESULT
ITSS_create_chm_storage(
614 struct chmFile
*chmfile
, const WCHAR
*dir
, IStorage
** ppstgOpen
)
616 ITSS_IStorageImpl
*stg
;
618 TRACE("%p %s\n", chmfile
, debugstr_w( dir
) );
620 stg
= HeapAlloc( GetProcessHeap(), 0,
621 FIELD_OFFSET( ITSS_IStorageImpl
, dir
[lstrlenW( dir
) + 1] ));
622 stg
->IStorage_iface
.lpVtbl
= &ITSS_IStorageImpl_Vtbl
;
624 stg
->chmfile
= chmfile
;
625 lstrcpyW( stg
->dir
, dir
);
627 *ppstgOpen
= &stg
->IStorage_iface
;
633 HRESULT
ITSS_StgOpenStorage(
634 const WCHAR
* pwcsName
,
635 IStorage
* pstgPriority
,
639 IStorage
** ppstgOpen
)
641 struct chmFile
*chmfile
;
642 static const WCHAR szRoot
[] = { '/', 0 };
644 TRACE("%s\n", debugstr_w(pwcsName
) );
646 chmfile
= chm_openW( pwcsName
);
650 return ITSS_create_chm_storage( chmfile
, szRoot
, ppstgOpen
);
653 /************************************************************************/
655 static HRESULT WINAPI
ITSS_IStream_QueryInterface(
660 IStream_Impl
*This
= impl_from_IStream(iface
);
662 if (IsEqualGUID(riid
, &IID_IUnknown
)
663 || IsEqualGUID(riid
, &IID_ISequentialStream
)
664 || IsEqualGUID(riid
, &IID_IStream
))
666 IStream_AddRef(iface
);
667 *ppvObject
= &This
->IStream_iface
;
671 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
672 return E_NOINTERFACE
;
675 static ULONG WINAPI
ITSS_IStream_AddRef(
678 IStream_Impl
*This
= impl_from_IStream(iface
);
679 return InterlockedIncrement(&This
->ref
);
682 static ULONG WINAPI
ITSS_IStream_Release(
685 IStream_Impl
*This
= impl_from_IStream(iface
);
687 ULONG ref
= InterlockedDecrement(&This
->ref
);
691 IStorage_Release( &This
->stg
->IStorage_iface
);
692 HeapFree(GetProcessHeap(), 0, This
);
699 static HRESULT WINAPI
ITSS_IStream_Read(
705 IStream_Impl
*This
= impl_from_IStream(iface
);
708 TRACE("%p %p %u %p\n", This
, pv
, cb
, pcbRead
);
710 count
= chm_retrieve_object(This
->stg
->chmfile
,
711 &This
->ui
, pv
, This
->addr
, cb
);
716 return count
? S_OK
: S_FALSE
;
719 static HRESULT WINAPI
ITSS_IStream_Write(
729 static HRESULT WINAPI
ITSS_IStream_Seek(
731 LARGE_INTEGER dlibMove
,
733 ULARGE_INTEGER
* plibNewPosition
)
735 IStream_Impl
*This
= impl_from_IStream(iface
);
738 TRACE("%p %s %u %p\n", This
,
739 wine_dbgstr_longlong( dlibMove
.QuadPart
), dwOrigin
, plibNewPosition
);
744 case STREAM_SEEK_CUR
:
745 newpos
= This
->addr
+ dlibMove
.QuadPart
;
747 case STREAM_SEEK_SET
:
748 newpos
= dlibMove
.QuadPart
;
750 case STREAM_SEEK_END
:
751 newpos
= This
->ui
.length
+ dlibMove
.QuadPart
;
755 if( ( newpos
< 0 ) || ( newpos
> This
->ui
.length
) )
756 return STG_E_INVALIDPOINTER
;
759 if( plibNewPosition
)
760 plibNewPosition
->QuadPart
= This
->addr
;
765 static HRESULT WINAPI
ITSS_IStream_SetSize(
767 ULARGE_INTEGER libNewSize
)
773 static HRESULT WINAPI
ITSS_IStream_CopyTo(
777 ULARGE_INTEGER
* pcbRead
,
778 ULARGE_INTEGER
* pcbWritten
)
784 static HRESULT WINAPI
ITSS_IStream_Commit(
786 DWORD grfCommitFlags
)
792 static HRESULT WINAPI
ITSS_IStream_Revert(
799 static HRESULT WINAPI
ITSS_IStream_LockRegion(
801 ULARGE_INTEGER libOffset
,
809 static HRESULT WINAPI
ITSS_IStream_UnlockRegion(
811 ULARGE_INTEGER libOffset
,
819 static HRESULT WINAPI
ITSS_IStream_Stat(
824 IStream_Impl
*This
= impl_from_IStream(iface
);
826 TRACE("%p %p %d\n", This
, pstatstg
, grfStatFlag
);
828 memset( pstatstg
, 0, sizeof *pstatstg
);
829 if( !( grfStatFlag
& STATFLAG_NONAME
) )
831 FIXME("copy the name\n");
833 pstatstg
->type
= STGTY_STREAM
;
834 pstatstg
->cbSize
.QuadPart
= This
->ui
.length
;
835 pstatstg
->grfMode
= STGM_READ
;
836 pstatstg
->clsid
= CLSID_ITStorage
;
841 static HRESULT WINAPI
ITSS_IStream_Clone(
849 static const IStreamVtbl ITSS_IStream_vtbl
=
851 ITSS_IStream_QueryInterface
,
853 ITSS_IStream_Release
,
857 ITSS_IStream_SetSize
,
861 ITSS_IStream_LockRegion
,
862 ITSS_IStream_UnlockRegion
,
867 static IStream_Impl
*ITSS_create_stream(
868 ITSS_IStorageImpl
*stg
, struct chmUnitInfo
*ui
)
872 stm
= HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl
) );
873 stm
->IStream_iface
.lpVtbl
= &ITSS_IStream_vtbl
;
878 IStorage_AddRef( &stg
->IStorage_iface
);
882 TRACE(" -> %p\n", stm
);