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
38 #include "wine/itss.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(itss
);
44 /************************************************************************/
46 typedef struct _ITSS_IStorageImpl
48 IStorage IStorage_iface
;
50 struct chmFile
*chmfile
;
56 struct enum_info
*next
, *prev
;
57 struct chmUnitInfo ui
;
60 typedef struct _IEnumSTATSTG_Impl
62 IEnumSTATSTG IEnumSTATSTG_iface
;
64 struct enum_info
*first
, *last
, *current
;
67 typedef struct _IStream_Impl
69 IStream IStream_iface
;
71 ITSS_IStorageImpl
*stg
;
73 struct chmUnitInfo ui
;
76 static inline ITSS_IStorageImpl
*impl_from_IStorage(IStorage
*iface
)
78 return CONTAINING_RECORD(iface
, ITSS_IStorageImpl
, IStorage_iface
);
81 static inline IEnumSTATSTG_Impl
*impl_from_IEnumSTATSTG(IEnumSTATSTG
*iface
)
83 return CONTAINING_RECORD(iface
, IEnumSTATSTG_Impl
, IEnumSTATSTG_iface
);
86 static inline IStream_Impl
*impl_from_IStream(IStream
*iface
)
88 return CONTAINING_RECORD(iface
, IStream_Impl
, IStream_iface
);
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
);
96 /************************************************************************/
98 static HRESULT WINAPI
ITSS_IEnumSTATSTG_QueryInterface(
103 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
105 if (IsEqualGUID(riid
, &IID_IUnknown
)
106 || IsEqualGUID(riid
, &IID_IEnumSTATSTG
))
108 IEnumSTATSTG_AddRef(iface
);
113 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
114 return E_NOINTERFACE
;
117 static ULONG WINAPI
ITSS_IEnumSTATSTG_AddRef(
120 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
121 return InterlockedIncrement(&This
->ref
);
124 static ULONG WINAPI
ITSS_IEnumSTATSTG_Release(
127 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
129 ULONG ref
= InterlockedDecrement(&This
->ref
);
135 struct enum_info
*t
= This
->first
->next
;
136 HeapFree( GetProcessHeap(), 0, This
->first
);
139 HeapFree(GetProcessHeap(), 0, This
);
146 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Next(
152 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
154 struct enum_info
*cur
;
156 TRACE("%p %u %p %p\n", This
, celt
, rgelt
, pceltFetched
);
160 while( (n
<celt
) && cur
)
164 memset( rgelt
, 0, sizeof *rgelt
);
170 len
= strlenW( str
) + 1;
171 rgelt
->pwcsName
= CoTaskMemAlloc( len
*sizeof(WCHAR
) );
172 strcpyW( rgelt
->pwcsName
, str
);
174 /* determine the type */
175 if( rgelt
->pwcsName
[len
-2] == '/' )
177 rgelt
->pwcsName
[len
-2] = 0;
178 rgelt
->type
= STGTY_STORAGE
;
181 rgelt
->type
= STGTY_STREAM
;
184 rgelt
->cbSize
.QuadPart
= cur
->ui
.length
;
186 /* advance to the next item if it exists */
200 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Skip(
204 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
206 struct enum_info
*cur
;
208 TRACE("%p %u\n", This
, celt
);
212 while( (n
<celt
) && cur
)
225 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Reset(
228 IEnumSTATSTG_Impl
*This
= impl_from_IEnumSTATSTG(iface
);
230 TRACE("%p\n", This
);
232 This
->current
= This
->first
;
237 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Clone(
239 IEnumSTATSTG
** ppenum
)
245 static const IEnumSTATSTGVtbl IEnumSTATSTG_vtbl
=
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
256 static IEnumSTATSTG_Impl
*ITSS_create_enum( void )
258 IEnumSTATSTG_Impl
*stgenum
;
260 stgenum
= HeapAlloc( GetProcessHeap(), 0, sizeof (IEnumSTATSTG_Impl
) );
261 stgenum
->IEnumSTATSTG_iface
.lpVtbl
= &IEnumSTATSTG_vtbl
;
263 stgenum
->first
= NULL
;
264 stgenum
->last
= NULL
;
265 stgenum
->current
= NULL
;
268 TRACE(" -> %p\n", stgenum
);
273 /************************************************************************/
275 static HRESULT WINAPI
ITSS_IStorageImpl_QueryInterface(
280 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
282 if (IsEqualGUID(riid
, &IID_IUnknown
)
283 || IsEqualGUID(riid
, &IID_IStorage
))
285 IStorage_AddRef(iface
);
290 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
291 return E_NOINTERFACE
;
294 static ULONG WINAPI
ITSS_IStorageImpl_AddRef(
297 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
298 return InterlockedIncrement(&This
->ref
);
301 static ULONG WINAPI
ITSS_IStorageImpl_Release(
304 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
306 ULONG ref
= InterlockedDecrement(&This
->ref
);
310 chm_close(This
->chmfile
);
311 HeapFree(GetProcessHeap(), 0, This
);
318 static HRESULT WINAPI
ITSS_IStorageImpl_CreateStream(
330 static HRESULT WINAPI
ITSS_IStorageImpl_OpenStream(
338 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
341 struct chmUnitInfo ui
;
345 TRACE("%p %s %p %u %u %p\n", This
, debugstr_w(pwcsName
),
346 reserved1
, grfMode
, reserved2
, ppstm
);
348 len
= strlenW( This
->dir
) + strlenW( pwcsName
) + 1;
349 path
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
350 strcpyW( path
, This
->dir
);
352 if( pwcsName
[0] == '/' || pwcsName
[0] == '\\' )
354 p
= &path
[strlenW( path
) - 1];
355 while( ( path
<= p
) && ( *p
== '/' ) )
358 strcatW( path
, pwcsName
);
360 for(p
=path
; *p
; p
++) {
368 TRACE("Resolving %s\n", debugstr_w(path
));
370 r
= chm_resolve_object(This
->chmfile
, path
, &ui
);
371 HeapFree( GetProcessHeap(), 0, path
);
373 if( r
!= CHM_RESOLVE_SUCCESS
) {
374 WARN("Could not resolve object\n");
375 return STG_E_FILENOTFOUND
;
378 stm
= ITSS_create_stream( This
, &ui
);
382 *ppstm
= &stm
->IStream_iface
;
387 static HRESULT WINAPI
ITSS_IStorageImpl_CreateStorage(
399 static HRESULT WINAPI
ITSS_IStorageImpl_OpenStorage(
402 IStorage
* pstgPriority
,
408 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
409 static const WCHAR szRoot
[] = { '/', 0 };
410 struct chmFile
*chmfile
;
414 TRACE("%p %s %p %u %p %u %p\n", This
, debugstr_w(pwcsName
),
415 pstgPriority
, grfMode
, snbExclude
, reserved
, ppstg
);
417 chmfile
= chm_dup( This
->chmfile
);
421 len
= strlenW( This
->dir
) + strlenW( pwcsName
) + 1;
422 path
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
423 strcpyW( path
, This
->dir
);
425 if( pwcsName
[0] == '/' || pwcsName
[0] == '\\' )
427 p
= &path
[strlenW( path
) - 1];
428 while( ( path
<= p
) && ( *p
== '/' ) )
431 strcatW( path
, pwcsName
);
433 for(p
=path
; *p
; p
++) {
441 strcatW( path
, szRoot
);
443 TRACE("Resolving %s\n", debugstr_w(path
));
445 return ITSS_create_chm_storage(chmfile
, path
, ppstg
);
448 static HRESULT WINAPI
ITSS_IStorageImpl_CopyTo(
451 const IID
* rgiidExclude
,
459 static HRESULT WINAPI
ITSS_IStorageImpl_MoveElementTo(
463 LPCOLESTR pwcsNewName
,
470 static HRESULT WINAPI
ITSS_IStorageImpl_Commit(
472 DWORD grfCommitFlags
)
478 static HRESULT WINAPI
ITSS_IStorageImpl_Revert(
485 static int ITSS_chm_enumerator(
487 struct chmUnitInfo
*ui
,
490 struct enum_info
*info
;
491 IEnumSTATSTG_Impl
* stgenum
= context
;
493 TRACE("adding %s to enumeration\n", debugstr_w(ui
->path
) );
495 info
= HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info
) );
499 info
->prev
= stgenum
->last
;
501 stgenum
->last
->next
= info
;
503 stgenum
->first
= info
;
504 stgenum
->last
= info
;
506 return CHM_ENUMERATOR_CONTINUE
;
509 static HRESULT WINAPI
ITSS_IStorageImpl_EnumElements(
514 IEnumSTATSTG
** ppenum
)
516 ITSS_IStorageImpl
*This
= impl_from_IStorage(iface
);
517 IEnumSTATSTG_Impl
* stgenum
;
519 TRACE("%p %d %p %d %p\n", This
, reserved1
, reserved2
, reserved3
, ppenum
);
521 stgenum
= ITSS_create_enum();
525 chm_enumerate_dir(This
->chmfile
,
531 stgenum
->current
= stgenum
->first
;
533 *ppenum
= &stgenum
->IEnumSTATSTG_iface
;
538 static HRESULT WINAPI
ITSS_IStorageImpl_DestroyElement(
546 static HRESULT WINAPI
ITSS_IStorageImpl_RenameElement(
548 LPCOLESTR pwcsOldName
,
549 LPCOLESTR pwcsNewName
)
555 static HRESULT WINAPI
ITSS_IStorageImpl_SetElementTimes(
558 const FILETIME
* pctime
,
559 const FILETIME
* patime
,
560 const FILETIME
* pmtime
)
566 static HRESULT WINAPI
ITSS_IStorageImpl_SetClass(
574 static HRESULT WINAPI
ITSS_IStorageImpl_SetStateBits(
583 static HRESULT WINAPI
ITSS_IStorageImpl_Stat(
592 static const IStorageVtbl ITSS_IStorageImpl_Vtbl
=
594 ITSS_IStorageImpl_QueryInterface
,
595 ITSS_IStorageImpl_AddRef
,
596 ITSS_IStorageImpl_Release
,
597 ITSS_IStorageImpl_CreateStream
,
598 ITSS_IStorageImpl_OpenStream
,
599 ITSS_IStorageImpl_CreateStorage
,
600 ITSS_IStorageImpl_OpenStorage
,
601 ITSS_IStorageImpl_CopyTo
,
602 ITSS_IStorageImpl_MoveElementTo
,
603 ITSS_IStorageImpl_Commit
,
604 ITSS_IStorageImpl_Revert
,
605 ITSS_IStorageImpl_EnumElements
,
606 ITSS_IStorageImpl_DestroyElement
,
607 ITSS_IStorageImpl_RenameElement
,
608 ITSS_IStorageImpl_SetElementTimes
,
609 ITSS_IStorageImpl_SetClass
,
610 ITSS_IStorageImpl_SetStateBits
,
611 ITSS_IStorageImpl_Stat
,
614 static HRESULT
ITSS_create_chm_storage(
615 struct chmFile
*chmfile
, const WCHAR
*dir
, IStorage
** ppstgOpen
)
617 ITSS_IStorageImpl
*stg
;
620 TRACE("%p %s\n", chmfile
, debugstr_w( dir
) );
622 len
= strlenW( dir
) + 1;
623 stg
= HeapAlloc( GetProcessHeap(), 0,
624 sizeof (ITSS_IStorageImpl
) + len
*sizeof(WCHAR
) );
625 stg
->IStorage_iface
.lpVtbl
= &ITSS_IStorageImpl_Vtbl
;
627 stg
->chmfile
= chmfile
;
628 strcpyW( stg
->dir
, dir
);
630 *ppstgOpen
= &stg
->IStorage_iface
;
636 HRESULT
ITSS_StgOpenStorage(
637 const WCHAR
* pwcsName
,
638 IStorage
* pstgPriority
,
642 IStorage
** ppstgOpen
)
644 struct chmFile
*chmfile
;
645 static const WCHAR szRoot
[] = { '/', 0 };
647 TRACE("%s\n", debugstr_w(pwcsName
) );
649 chmfile
= chm_openW( pwcsName
);
653 return ITSS_create_chm_storage( chmfile
, szRoot
, ppstgOpen
);
656 /************************************************************************/
658 static HRESULT WINAPI
ITSS_IStream_QueryInterface(
663 IStream_Impl
*This
= impl_from_IStream(iface
);
665 if (IsEqualGUID(riid
, &IID_IUnknown
)
666 || IsEqualGUID(riid
, &IID_ISequentialStream
)
667 || IsEqualGUID(riid
, &IID_IStream
))
669 IStream_AddRef(iface
);
674 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
675 return E_NOINTERFACE
;
678 static ULONG WINAPI
ITSS_IStream_AddRef(
681 IStream_Impl
*This
= impl_from_IStream(iface
);
682 return InterlockedIncrement(&This
->ref
);
685 static ULONG WINAPI
ITSS_IStream_Release(
688 IStream_Impl
*This
= impl_from_IStream(iface
);
690 ULONG ref
= InterlockedDecrement(&This
->ref
);
694 IStorage_Release( &This
->stg
->IStorage_iface
);
695 HeapFree(GetProcessHeap(), 0, This
);
702 static HRESULT WINAPI
ITSS_IStream_Read(
708 IStream_Impl
*This
= impl_from_IStream(iface
);
711 TRACE("%p %p %u %p\n", This
, pv
, cb
, pcbRead
);
713 count
= chm_retrieve_object(This
->stg
->chmfile
,
714 &This
->ui
, pv
, This
->addr
, cb
);
719 return count
? S_OK
: S_FALSE
;
722 static HRESULT WINAPI
ITSS_IStream_Write(
732 static HRESULT WINAPI
ITSS_IStream_Seek(
734 LARGE_INTEGER dlibMove
,
736 ULARGE_INTEGER
* plibNewPosition
)
738 IStream_Impl
*This
= impl_from_IStream(iface
);
741 TRACE("%p %s %u %p\n", This
,
742 wine_dbgstr_longlong( dlibMove
.QuadPart
), dwOrigin
, plibNewPosition
);
747 case STREAM_SEEK_CUR
:
748 newpos
= This
->addr
+ dlibMove
.QuadPart
;
750 case STREAM_SEEK_SET
:
751 newpos
= dlibMove
.QuadPart
;
753 case STREAM_SEEK_END
:
754 newpos
= This
->ui
.length
+ dlibMove
.QuadPart
;
758 if( ( newpos
< 0 ) || ( newpos
> This
->ui
.length
) )
759 return STG_E_INVALIDPOINTER
;
762 if( plibNewPosition
)
763 plibNewPosition
->QuadPart
= This
->addr
;
768 static HRESULT WINAPI
ITSS_IStream_SetSize(
770 ULARGE_INTEGER libNewSize
)
776 static HRESULT WINAPI
ITSS_IStream_CopyTo(
780 ULARGE_INTEGER
* pcbRead
,
781 ULARGE_INTEGER
* pcbWritten
)
787 static HRESULT WINAPI
ITSS_IStream_Commit(
789 DWORD grfCommitFlags
)
795 static HRESULT WINAPI
ITSS_IStream_Revert(
802 static HRESULT WINAPI
ITSS_IStream_LockRegion(
804 ULARGE_INTEGER libOffset
,
812 static HRESULT WINAPI
ITSS_IStream_UnlockRegion(
814 ULARGE_INTEGER libOffset
,
822 static HRESULT WINAPI
ITSS_IStream_Stat(
827 IStream_Impl
*This
= impl_from_IStream(iface
);
829 TRACE("%p %p %d\n", This
, pstatstg
, grfStatFlag
);
831 memset( pstatstg
, 0, sizeof *pstatstg
);
832 if( !( grfStatFlag
& STATFLAG_NONAME
) )
834 FIXME("copy the name\n");
836 pstatstg
->type
= STGTY_STREAM
;
837 pstatstg
->cbSize
.QuadPart
= This
->ui
.length
;
838 pstatstg
->grfMode
= STGM_READ
;
839 pstatstg
->clsid
= CLSID_ITStorage
;
844 static HRESULT WINAPI
ITSS_IStream_Clone(
852 static const IStreamVtbl ITSS_IStream_vtbl
=
854 ITSS_IStream_QueryInterface
,
856 ITSS_IStream_Release
,
860 ITSS_IStream_SetSize
,
864 ITSS_IStream_LockRegion
,
865 ITSS_IStream_UnlockRegion
,
870 static IStream_Impl
*ITSS_create_stream(
871 ITSS_IStorageImpl
*stg
, struct chmUnitInfo
*ui
)
875 stm
= HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl
) );
876 stm
->IStream_iface
.lpVtbl
= &ITSS_IStream_vtbl
;
881 IStorage_AddRef( &stg
->IStorage_iface
);
885 TRACE(" -> %p\n", stm
);