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
25 /************************************************************************/
27 typedef struct _ITSS_IStorageImpl
29 IStorage IStorage_iface
;
31 struct chmFile
*chmfile
;
37 struct enum_info
*next
, *prev
;
38 struct chmUnitInfo ui
;
41 typedef struct _IEnumSTATSTG_Impl
43 IEnumSTATSTG IEnumSTATSTG_iface
;
45 struct enum_info
*first
, *last
, *current
;
48 typedef struct _IStream_Impl
50 IStream IStream_iface
;
52 ITSS_IStorageImpl
*stg
;
54 struct chmUnitInfo ui
;
57 static inline ITSS_IStorageImpl
*impl_from_IStorage(IStorage
*iface
)
59 return CONTAINING_RECORD(iface
, ITSS_IStorageImpl
, IStorage_iface
);
62 static inline IEnumSTATSTG_Impl
*impl_from_IEnumSTATSTG(IEnumSTATSTG
*iface
)
64 return CONTAINING_RECORD(iface
, IEnumSTATSTG_Impl
, IEnumSTATSTG_iface
);
67 static inline IStream_Impl
*impl_from_IStream(IStream
*iface
)
69 return CONTAINING_RECORD(iface
, IStream_Impl
, IStream_iface
);
72 static HRESULT
ITSS_create_chm_storage(
73 struct chmFile
*chmfile
, const WCHAR
*dir
, IStorage
** ppstgOpen
);
74 static IStream_Impl
* ITSS_create_stream(
75 ITSS_IStorageImpl
*stg
, struct chmUnitInfo
*ui
);
77 /************************************************************************/
79 static HRESULT WINAPI
ITSS_IEnumSTATSTG_QueryInterface(
84 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
86 if (IsEqualGUID(riid
, &IID_IUnknown
)
87 || IsEqualGUID(riid
, &IID_IEnumSTATSTG
))
89 IEnumSTATSTG_AddRef(iface
);
94 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
98 static ULONG WINAPI
ITSS_IEnumSTATSTG_AddRef(
101 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
102 return InterlockedIncrement(&This
->ref
);
105 static ULONG WINAPI
ITSS_IEnumSTATSTG_Release(
108 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
110 ULONG ref
= InterlockedDecrement(&This
->ref
);
116 struct enum_info
*t
= This
->first
->next
;
117 HeapFree( GetProcessHeap(), 0, This
->first
);
120 HeapFree(GetProcessHeap(), 0, This
);
127 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Next(
133 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
135 struct enum_info
*cur
;
137 TRACE("%p %u %p %p\n", This
, celt
, rgelt
, pceltFetched
);
141 while( (n
<celt
) && cur
)
145 memset( rgelt
, 0, sizeof *rgelt
);
151 len
= strlenW( str
) + 1;
152 rgelt
->pwcsName
= CoTaskMemAlloc( len
*sizeof(WCHAR
) );
153 strcpyW( rgelt
->pwcsName
, str
);
155 /* determine the type */
156 if( rgelt
->pwcsName
[len
-2] == '/' )
158 rgelt
->pwcsName
[len
-2] = 0;
159 rgelt
->type
= STGTY_STORAGE
;
162 rgelt
->type
= STGTY_STREAM
;
165 rgelt
->cbSize
.QuadPart
= cur
->ui
.length
;
167 /* advance to the next item if it exists */
181 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Skip(
185 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
187 struct enum_info
*cur
;
189 TRACE("%p %u\n", This
, celt
);
193 while( (n
<celt
) && cur
)
206 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Reset(
209 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
211 TRACE("%p\n", This
);
213 This
->current
= This
->first
;
218 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Clone(
220 IEnumSTATSTG
** ppenum
)
226 static const IEnumSTATSTGVtbl IEnumSTATSTG_vtbl
=
228 ITSS_IEnumSTATSTG_QueryInterface
,
229 ITSS_IEnumSTATSTG_AddRef
,
230 ITSS_IEnumSTATSTG_Release
,
231 ITSS_IEnumSTATSTG_Next
,
232 ITSS_IEnumSTATSTG_Skip
,
233 ITSS_IEnumSTATSTG_Reset
,
234 ITSS_IEnumSTATSTG_Clone
237 static IEnumSTATSTG_Impl
*ITSS_create_enum( void )
239 IEnumSTATSTG_Impl
*stgenum
;
241 stgenum
= HeapAlloc( GetProcessHeap(), 0, sizeof (IEnumSTATSTG_Impl
) );
242 stgenum
->IEnumSTATSTG_iface
.lpVtbl
= &IEnumSTATSTG_vtbl
;
244 stgenum
->first
= NULL
;
245 stgenum
->last
= NULL
;
246 stgenum
->current
= NULL
;
249 TRACE(" -> %p\n", stgenum
);
254 /************************************************************************/
256 static HRESULT WINAPI
ITSS_IStorageImpl_QueryInterface(
261 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
263 if (IsEqualGUID(riid
, &IID_IUnknown
)
264 || IsEqualGUID(riid
, &IID_IStorage
))
266 IStorage_AddRef(iface
);
271 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
272 return E_NOINTERFACE
;
275 static ULONG WINAPI
ITSS_IStorageImpl_AddRef(
278 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
279 return InterlockedIncrement(&This
->ref
);
282 static ULONG WINAPI
ITSS_IStorageImpl_Release(
285 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
287 ULONG ref
= InterlockedDecrement(&This
->ref
);
291 chm_close(This
->chmfile
);
292 HeapFree(GetProcessHeap(), 0, This
);
299 static HRESULT WINAPI
ITSS_IStorageImpl_CreateStream(
311 static HRESULT WINAPI
ITSS_IStorageImpl_OpenStream(
319 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
322 struct chmUnitInfo ui
;
326 TRACE("%p %s %p %u %u %p\n", This
, debugstr_w(pwcsName
),
327 reserved1
, grfMode
, reserved2
, ppstm
);
329 len
= strlenW( This
->dir
) + strlenW( pwcsName
) + 1;
330 path
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
331 strcpyW( path
, This
->dir
);
333 if( pwcsName
[0] == '/' || pwcsName
[0] == '\\' )
335 p
= &path
[strlenW( path
) - 1];
336 while( ( path
<= p
) && ( *p
== '/' ) )
339 strcatW( path
, pwcsName
);
341 for(p
=path
; *p
; p
++) {
349 TRACE("Resolving %s\n", debugstr_w(path
));
351 r
= chm_resolve_object(This
->chmfile
, path
, &ui
);
352 HeapFree( GetProcessHeap(), 0, path
);
354 if( r
!= CHM_RESOLVE_SUCCESS
) {
355 WARN("Could not resolve object\n");
356 return STG_E_FILENOTFOUND
;
359 stm
= ITSS_create_stream( This
, &ui
);
363 *ppstm
= &stm
->IStream_iface
;
368 static HRESULT WINAPI
ITSS_IStorageImpl_CreateStorage(
380 static HRESULT WINAPI
ITSS_IStorageImpl_OpenStorage(
383 IStorage
* pstgPriority
,
389 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
390 struct chmFile
*chmfile
;
394 TRACE("%p %s %p %u %p %u %p\n", This
, debugstr_w(pwcsName
),
395 pstgPriority
, grfMode
, snbExclude
, reserved
, ppstg
);
397 chmfile
= chm_dup( This
->chmfile
);
401 len
= strlenW( This
->dir
) + strlenW( pwcsName
) + 2; /* need room for a terminating slash */
402 path
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
403 strcpyW( path
, This
->dir
);
405 if( pwcsName
[0] == '/' || pwcsName
[0] == '\\' )
407 p
= &path
[strlenW( path
) - 1];
408 while( ( path
<= p
) && ( *p
== '/' ) )
411 strcatW( path
, pwcsName
);
413 for(p
=path
; *p
; p
++) {
418 /* add a terminating slash if one does not already exist */
425 TRACE("Resolving %s\n", debugstr_w(path
));
427 return ITSS_create_chm_storage(chmfile
, path
, ppstg
);
430 static HRESULT WINAPI
ITSS_IStorageImpl_CopyTo(
433 const IID
* rgiidExclude
,
441 static HRESULT WINAPI
ITSS_IStorageImpl_MoveElementTo(
445 LPCOLESTR pwcsNewName
,
452 static HRESULT WINAPI
ITSS_IStorageImpl_Commit(
454 DWORD grfCommitFlags
)
460 static HRESULT WINAPI
ITSS_IStorageImpl_Revert(
467 static int ITSS_chm_enumerator(
469 struct chmUnitInfo
*ui
,
472 struct enum_info
*info
;
473 IEnumSTATSTG_Impl
* stgenum
= context
;
475 TRACE("adding %s to enumeration\n", debugstr_w(ui
->path
) );
477 info
= HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info
) );
481 info
->prev
= stgenum
->last
;
483 stgenum
->last
->next
= info
;
485 stgenum
->first
= info
;
486 stgenum
->last
= info
;
488 return CHM_ENUMERATOR_CONTINUE
;
491 static HRESULT WINAPI
ITSS_IStorageImpl_EnumElements(
496 IEnumSTATSTG
** ppenum
)
498 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
499 IEnumSTATSTG_Impl
* stgenum
;
501 TRACE("%p %d %p %d %p\n", This
, reserved1
, reserved2
, reserved3
, ppenum
);
503 stgenum
= ITSS_create_enum();
507 chm_enumerate_dir(This
->chmfile
,
513 stgenum
->current
= stgenum
->first
;
515 *ppenum
= &stgenum
->IEnumSTATSTG_iface
;
520 static HRESULT WINAPI
ITSS_IStorageImpl_DestroyElement(
528 static HRESULT WINAPI
ITSS_IStorageImpl_RenameElement(
530 LPCOLESTR pwcsOldName
,
531 LPCOLESTR pwcsNewName
)
537 static HRESULT WINAPI
ITSS_IStorageImpl_SetElementTimes(
540 const FILETIME
* pctime
,
541 const FILETIME
* patime
,
542 const FILETIME
* pmtime
)
548 static HRESULT WINAPI
ITSS_IStorageImpl_SetClass(
556 static HRESULT WINAPI
ITSS_IStorageImpl_SetStateBits(
565 static HRESULT WINAPI
ITSS_IStorageImpl_Stat(
574 static const IStorageVtbl ITSS_IStorageImpl_Vtbl
=
576 ITSS_IStorageImpl_QueryInterface
,
577 ITSS_IStorageImpl_AddRef
,
578 ITSS_IStorageImpl_Release
,
579 ITSS_IStorageImpl_CreateStream
,
580 ITSS_IStorageImpl_OpenStream
,
581 ITSS_IStorageImpl_CreateStorage
,
582 ITSS_IStorageImpl_OpenStorage
,
583 ITSS_IStorageImpl_CopyTo
,
584 ITSS_IStorageImpl_MoveElementTo
,
585 ITSS_IStorageImpl_Commit
,
586 ITSS_IStorageImpl_Revert
,
587 ITSS_IStorageImpl_EnumElements
,
588 ITSS_IStorageImpl_DestroyElement
,
589 ITSS_IStorageImpl_RenameElement
,
590 ITSS_IStorageImpl_SetElementTimes
,
591 ITSS_IStorageImpl_SetClass
,
592 ITSS_IStorageImpl_SetStateBits
,
593 ITSS_IStorageImpl_Stat
,
596 static HRESULT
ITSS_create_chm_storage(
597 struct chmFile
*chmfile
, const WCHAR
*dir
, IStorage
** ppstgOpen
)
599 ITSS_IStorageImpl
*stg
;
601 TRACE("%p %s\n", chmfile
, debugstr_w( dir
) );
603 stg
= HeapAlloc( GetProcessHeap(), 0,
604 FIELD_OFFSET( ITSS_IStorageImpl
, dir
[strlenW( dir
) + 1] ));
605 stg
->IStorage_iface
.lpVtbl
= &ITSS_IStorageImpl_Vtbl
;
607 stg
->chmfile
= chmfile
;
608 strcpyW( stg
->dir
, dir
);
610 *ppstgOpen
= &stg
->IStorage_iface
;
616 HRESULT
ITSS_StgOpenStorage(
617 const WCHAR
* pwcsName
,
618 IStorage
* pstgPriority
,
622 IStorage
** ppstgOpen
)
624 struct chmFile
*chmfile
;
625 static const WCHAR szRoot
[] = { '/', 0 };
627 TRACE("%s\n", debugstr_w(pwcsName
) );
629 chmfile
= chm_openW( pwcsName
);
633 return ITSS_create_chm_storage( chmfile
, szRoot
, ppstgOpen
);
636 /************************************************************************/
638 static HRESULT WINAPI
ITSS_IStream_QueryInterface(
643 IStream_Impl
*This
= impl_from_IStream(iface
);
645 if (IsEqualGUID(riid
, &IID_IUnknown
)
646 || IsEqualGUID(riid
, &IID_ISequentialStream
)
647 || IsEqualGUID(riid
, &IID_IStream
))
649 IStream_AddRef(iface
);
654 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
655 return E_NOINTERFACE
;
658 static ULONG WINAPI
ITSS_IStream_AddRef(
661 IStream_Impl
*This
= impl_from_IStream(iface
);
662 return InterlockedIncrement(&This
->ref
);
665 static ULONG WINAPI
ITSS_IStream_Release(
668 IStream_Impl
*This
= impl_from_IStream(iface
);
670 ULONG ref
= InterlockedDecrement(&This
->ref
);
674 IStorage_Release( &This
->stg
->IStorage_iface
);
675 HeapFree(GetProcessHeap(), 0, This
);
682 static HRESULT WINAPI
ITSS_IStream_Read(
688 IStream_Impl
*This
= impl_from_IStream(iface
);
691 TRACE("%p %p %u %p\n", This
, pv
, cb
, pcbRead
);
693 count
= chm_retrieve_object(This
->stg
->chmfile
,
694 &This
->ui
, pv
, This
->addr
, cb
);
699 return count
? S_OK
: S_FALSE
;
702 static HRESULT WINAPI
ITSS_IStream_Write(
712 static HRESULT WINAPI
ITSS_IStream_Seek(
714 LARGE_INTEGER dlibMove
,
716 ULARGE_INTEGER
* plibNewPosition
)
718 IStream_Impl
*This
= impl_from_IStream(iface
);
721 TRACE("%p %s %u %p\n", This
,
722 wine_dbgstr_longlong( dlibMove
.QuadPart
), dwOrigin
, plibNewPosition
);
727 case STREAM_SEEK_CUR
:
728 newpos
= This
->addr
+ dlibMove
.QuadPart
;
730 case STREAM_SEEK_SET
:
731 newpos
= dlibMove
.QuadPart
;
733 case STREAM_SEEK_END
:
734 newpos
= This
->ui
.length
+ dlibMove
.QuadPart
;
738 if( ( newpos
< 0 ) || ( newpos
> This
->ui
.length
) )
739 return STG_E_INVALIDPOINTER
;
742 if( plibNewPosition
)
743 plibNewPosition
->QuadPart
= This
->addr
;
748 static HRESULT WINAPI
ITSS_IStream_SetSize(
750 ULARGE_INTEGER libNewSize
)
756 static HRESULT WINAPI
ITSS_IStream_CopyTo(
760 ULARGE_INTEGER
* pcbRead
,
761 ULARGE_INTEGER
* pcbWritten
)
767 static HRESULT WINAPI
ITSS_IStream_Commit(
769 DWORD grfCommitFlags
)
775 static HRESULT WINAPI
ITSS_IStream_Revert(
782 static HRESULT WINAPI
ITSS_IStream_LockRegion(
784 ULARGE_INTEGER libOffset
,
792 static HRESULT WINAPI
ITSS_IStream_UnlockRegion(
794 ULARGE_INTEGER libOffset
,
802 static HRESULT WINAPI
ITSS_IStream_Stat(
807 IStream_Impl
*This
= impl_from_IStream(iface
);
809 TRACE("%p %p %d\n", This
, pstatstg
, grfStatFlag
);
811 memset( pstatstg
, 0, sizeof *pstatstg
);
812 if( !( grfStatFlag
& STATFLAG_NONAME
) )
814 FIXME("copy the name\n");
816 pstatstg
->type
= STGTY_STREAM
;
817 pstatstg
->cbSize
.QuadPart
= This
->ui
.length
;
818 pstatstg
->grfMode
= STGM_READ
;
819 pstatstg
->clsid
= CLSID_ITStorage
;
824 static HRESULT WINAPI
ITSS_IStream_Clone(
832 static const IStreamVtbl ITSS_IStream_vtbl
=
834 ITSS_IStream_QueryInterface
,
836 ITSS_IStream_Release
,
840 ITSS_IStream_SetSize
,
844 ITSS_IStream_LockRegion
,
845 ITSS_IStream_UnlockRegion
,
850 static IStream_Impl
*ITSS_create_stream(
851 ITSS_IStorageImpl
*stg
, struct chmUnitInfo
*ui
)
855 stm
= HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl
) );
856 stm
->IStream_iface
.lpVtbl
= &ITSS_IStream_vtbl
;
861 IStorage_AddRef( &stg
->IStorage_iface
);
865 TRACE(" -> %p\n", stm
);