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 const IStorageVtbl
*vtbl_IStorage
;
50 struct chmFile
*chmfile
;
56 struct enum_info
*next
, *prev
;
57 struct chmUnitInfo ui
;
60 typedef struct _IEnumSTATSTG_Impl
62 const IEnumSTATSTGVtbl
*vtbl_IEnumSTATSTG
;
64 struct enum_info
*first
, *last
, *current
;
67 typedef struct _IStream_Impl
69 const IStreamVtbl
*vtbl_IStream
;
71 ITSS_IStorageImpl
*stg
;
73 struct chmUnitInfo ui
;
76 static HRESULT
ITSS_create_chm_storage(
77 struct chmFile
*chmfile
, const WCHAR
*dir
, IStorage
** ppstgOpen
);
78 static IStream_Impl
* ITSS_create_stream(
79 ITSS_IStorageImpl
*stg
, struct chmUnitInfo
*ui
);
81 /************************************************************************/
83 static HRESULT WINAPI
ITSS_IEnumSTATSTG_QueryInterface(
88 IEnumSTATSTG_Impl
*This
= (IEnumSTATSTG_Impl
*)iface
;
90 if (IsEqualGUID(riid
, &IID_IUnknown
)
91 || IsEqualGUID(riid
, &IID_IEnumSTATSTG
))
93 IEnumSTATSTG_AddRef(iface
);
98 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
102 static ULONG WINAPI
ITSS_IEnumSTATSTG_AddRef(
105 IEnumSTATSTG_Impl
*This
= (IEnumSTATSTG_Impl
*)iface
;
106 return InterlockedIncrement(&This
->ref
);
109 static ULONG WINAPI
ITSS_IEnumSTATSTG_Release(
112 IEnumSTATSTG_Impl
*This
= (IEnumSTATSTG_Impl
*)iface
;
114 ULONG ref
= InterlockedDecrement(&This
->ref
);
120 struct enum_info
*t
= This
->first
->next
;
121 HeapFree( GetProcessHeap(), 0, This
->first
);
124 HeapFree(GetProcessHeap(), 0, This
);
131 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Next(
137 IEnumSTATSTG_Impl
*This
= (IEnumSTATSTG_Impl
*)iface
;
139 struct enum_info
*cur
;
141 TRACE("%p %u %p %p\n", This
, celt
, rgelt
, pceltFetched
);
145 while( (n
<celt
) && cur
)
149 memset( rgelt
, 0, sizeof *rgelt
);
155 len
= strlenW( str
) + 1;
156 rgelt
->pwcsName
= CoTaskMemAlloc( len
*sizeof(WCHAR
) );
157 strcpyW( rgelt
->pwcsName
, str
);
159 /* determine the type */
160 if( rgelt
->pwcsName
[len
-2] == '/' )
162 rgelt
->pwcsName
[len
-2] = 0;
163 rgelt
->type
= STGTY_STORAGE
;
166 rgelt
->type
= STGTY_STREAM
;
169 rgelt
->cbSize
.QuadPart
= cur
->ui
.length
;
171 /* advance to the next item if it exists */
185 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Skip(
189 IEnumSTATSTG_Impl
*This
= (IEnumSTATSTG_Impl
*)iface
;
191 struct enum_info
*cur
;
193 TRACE("%p %u\n", This
, celt
);
197 while( (n
<celt
) && cur
)
210 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Reset(
213 IEnumSTATSTG_Impl
*This
= (IEnumSTATSTG_Impl
*)iface
;
215 TRACE("%p\n", This
);
217 This
->current
= This
->first
;
222 static HRESULT WINAPI
ITSS_IEnumSTATSTG_Clone(
224 IEnumSTATSTG
** ppenum
)
230 static const IEnumSTATSTGVtbl IEnumSTATSTG_vtbl
=
232 ITSS_IEnumSTATSTG_QueryInterface
,
233 ITSS_IEnumSTATSTG_AddRef
,
234 ITSS_IEnumSTATSTG_Release
,
235 ITSS_IEnumSTATSTG_Next
,
236 ITSS_IEnumSTATSTG_Skip
,
237 ITSS_IEnumSTATSTG_Reset
,
238 ITSS_IEnumSTATSTG_Clone
241 static IEnumSTATSTG_Impl
*ITSS_create_enum( void )
243 IEnumSTATSTG_Impl
*stgenum
;
245 stgenum
= HeapAlloc( GetProcessHeap(), 0, sizeof (IEnumSTATSTG_Impl
) );
246 stgenum
->vtbl_IEnumSTATSTG
= &IEnumSTATSTG_vtbl
;
248 stgenum
->first
= NULL
;
249 stgenum
->last
= NULL
;
250 stgenum
->current
= NULL
;
253 TRACE(" -> %p\n", stgenum
);
258 /************************************************************************/
260 static HRESULT WINAPI
ITSS_IStorageImpl_QueryInterface(
265 ITSS_IStorageImpl
*This
= (ITSS_IStorageImpl
*)iface
;
267 if (IsEqualGUID(riid
, &IID_IUnknown
)
268 || IsEqualGUID(riid
, &IID_IStorage
))
270 IStorage_AddRef(iface
);
275 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
276 return E_NOINTERFACE
;
279 static ULONG WINAPI
ITSS_IStorageImpl_AddRef(
282 ITSS_IStorageImpl
*This
= (ITSS_IStorageImpl
*)iface
;
283 return InterlockedIncrement(&This
->ref
);
286 static ULONG WINAPI
ITSS_IStorageImpl_Release(
289 ITSS_IStorageImpl
*This
= (ITSS_IStorageImpl
*)iface
;
291 ULONG ref
= InterlockedDecrement(&This
->ref
);
295 chm_close(This
->chmfile
);
296 HeapFree(GetProcessHeap(), 0, This
);
303 static HRESULT WINAPI
ITSS_IStorageImpl_CreateStream(
315 static HRESULT WINAPI
ITSS_IStorageImpl_OpenStream(
323 ITSS_IStorageImpl
*This
= (ITSS_IStorageImpl
*)iface
;
326 struct chmUnitInfo ui
;
330 TRACE("%p %s %p %u %u %p\n", This
, debugstr_w(pwcsName
),
331 reserved1
, grfMode
, reserved2
, ppstm
);
333 len
= strlenW( This
->dir
) + strlenW( pwcsName
) + 1;
334 path
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
335 strcpyW( path
, This
->dir
);
337 if( pwcsName
[0] == '/' || pwcsName
[0] == '\\' )
339 p
= &path
[strlenW( path
) - 1];
340 while( ( path
<= p
) && ( *p
== '/' ) )
343 strcatW( path
, pwcsName
);
345 for(p
=path
; *p
; p
++) {
353 TRACE("Resolving %s\n", debugstr_w(path
));
355 r
= chm_resolve_object(This
->chmfile
, path
, &ui
);
356 HeapFree( GetProcessHeap(), 0, path
);
358 if( r
!= CHM_RESOLVE_SUCCESS
) {
359 WARN("Could not resolve object\n");
360 return STG_E_FILENOTFOUND
;
363 stm
= ITSS_create_stream( This
, &ui
);
367 *ppstm
= (IStream
*) stm
;
372 static HRESULT WINAPI
ITSS_IStorageImpl_CreateStorage(
384 static HRESULT WINAPI
ITSS_IStorageImpl_OpenStorage(
387 IStorage
* pstgPriority
,
393 ITSS_IStorageImpl
*This
= (ITSS_IStorageImpl
*)iface
;
394 static const WCHAR szRoot
[] = { '/', 0 };
395 struct chmFile
*chmfile
;
399 TRACE("%p %s %p %u %p %u %p\n", This
, debugstr_w(pwcsName
),
400 pstgPriority
, grfMode
, snbExclude
, reserved
, ppstg
);
402 chmfile
= chm_dup( This
->chmfile
);
406 len
= strlenW( This
->dir
) + strlenW( pwcsName
) + 1;
407 path
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
408 strcpyW( path
, This
->dir
);
410 if( pwcsName
[0] == '/' || pwcsName
[0] == '\\' )
412 p
= &path
[strlenW( path
) - 1];
413 while( ( path
<= p
) && ( *p
== '/' ) )
416 strcatW( path
, pwcsName
);
418 for(p
=path
; *p
; p
++) {
426 strcatW( path
, szRoot
);
428 TRACE("Resolving %s\n", debugstr_w(path
));
430 return ITSS_create_chm_storage(chmfile
, path
, ppstg
);
433 static HRESULT WINAPI
ITSS_IStorageImpl_CopyTo(
436 const IID
* rgiidExclude
,
444 static HRESULT WINAPI
ITSS_IStorageImpl_MoveElementTo(
448 LPCOLESTR pwcsNewName
,
455 static HRESULT WINAPI
ITSS_IStorageImpl_Commit(
457 DWORD grfCommitFlags
)
463 static HRESULT WINAPI
ITSS_IStorageImpl_Revert(
470 static int ITSS_chm_enumerator(
472 struct chmUnitInfo
*ui
,
475 struct enum_info
*info
;
476 IEnumSTATSTG_Impl
* stgenum
= context
;
478 TRACE("adding %s to enumeration\n", debugstr_w(ui
->path
) );
480 info
= HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info
) );
484 info
->prev
= stgenum
->last
;
486 stgenum
->last
->next
= info
;
488 stgenum
->first
= info
;
489 stgenum
->last
= info
;
491 return CHM_ENUMERATOR_CONTINUE
;
494 static HRESULT WINAPI
ITSS_IStorageImpl_EnumElements(
499 IEnumSTATSTG
** ppenum
)
501 ITSS_IStorageImpl
*This
= (ITSS_IStorageImpl
*)iface
;
502 IEnumSTATSTG_Impl
* stgenum
;
504 TRACE("%p %d %p %d %p\n", This
, reserved1
, reserved2
, reserved3
, ppenum
);
506 stgenum
= ITSS_create_enum();
510 chm_enumerate_dir(This
->chmfile
,
516 stgenum
->current
= stgenum
->first
;
518 *ppenum
= (IEnumSTATSTG
*) stgenum
;
523 static HRESULT WINAPI
ITSS_IStorageImpl_DestroyElement(
531 static HRESULT WINAPI
ITSS_IStorageImpl_RenameElement(
533 LPCOLESTR pwcsOldName
,
534 LPCOLESTR pwcsNewName
)
540 static HRESULT WINAPI
ITSS_IStorageImpl_SetElementTimes(
543 const FILETIME
* pctime
,
544 const FILETIME
* patime
,
545 const FILETIME
* pmtime
)
551 static HRESULT WINAPI
ITSS_IStorageImpl_SetClass(
559 static HRESULT WINAPI
ITSS_IStorageImpl_SetStateBits(
568 static HRESULT WINAPI
ITSS_IStorageImpl_Stat(
577 static const IStorageVtbl ITSS_IStorageImpl_Vtbl
=
579 ITSS_IStorageImpl_QueryInterface
,
580 ITSS_IStorageImpl_AddRef
,
581 ITSS_IStorageImpl_Release
,
582 ITSS_IStorageImpl_CreateStream
,
583 ITSS_IStorageImpl_OpenStream
,
584 ITSS_IStorageImpl_CreateStorage
,
585 ITSS_IStorageImpl_OpenStorage
,
586 ITSS_IStorageImpl_CopyTo
,
587 ITSS_IStorageImpl_MoveElementTo
,
588 ITSS_IStorageImpl_Commit
,
589 ITSS_IStorageImpl_Revert
,
590 ITSS_IStorageImpl_EnumElements
,
591 ITSS_IStorageImpl_DestroyElement
,
592 ITSS_IStorageImpl_RenameElement
,
593 ITSS_IStorageImpl_SetElementTimes
,
594 ITSS_IStorageImpl_SetClass
,
595 ITSS_IStorageImpl_SetStateBits
,
596 ITSS_IStorageImpl_Stat
,
599 static HRESULT
ITSS_create_chm_storage(
600 struct chmFile
*chmfile
, const WCHAR
*dir
, IStorage
** ppstgOpen
)
602 ITSS_IStorageImpl
*stg
;
605 TRACE("%p %s\n", chmfile
, debugstr_w( dir
) );
607 len
= strlenW( dir
) + 1;
608 stg
= HeapAlloc( GetProcessHeap(), 0,
609 sizeof (ITSS_IStorageImpl
) + len
*sizeof(WCHAR
) );
610 stg
->vtbl_IStorage
= &ITSS_IStorageImpl_Vtbl
;
612 stg
->chmfile
= chmfile
;
613 strcpyW( stg
->dir
, dir
);
615 *ppstgOpen
= (IStorage
*) stg
;
621 HRESULT
ITSS_StgOpenStorage(
622 const WCHAR
* pwcsName
,
623 IStorage
* pstgPriority
,
627 IStorage
** ppstgOpen
)
629 struct chmFile
*chmfile
;
630 static const WCHAR szRoot
[] = { '/', 0 };
632 TRACE("%s\n", debugstr_w(pwcsName
) );
634 chmfile
= chm_openW( pwcsName
);
638 return ITSS_create_chm_storage( chmfile
, szRoot
, ppstgOpen
);
641 /************************************************************************/
643 static HRESULT WINAPI
ITSS_IStream_QueryInterface(
648 IStream_Impl
*This
= (IStream_Impl
*)iface
;
650 if (IsEqualGUID(riid
, &IID_IUnknown
)
651 || IsEqualGUID(riid
, &IID_ISequentialStream
)
652 || IsEqualGUID(riid
, &IID_IStream
))
654 IStream_AddRef(iface
);
659 WARN("(%p)->(%s,%p),not found\n",This
,debugstr_guid(riid
),ppvObject
);
660 return E_NOINTERFACE
;
663 static ULONG WINAPI
ITSS_IStream_AddRef(
666 IStream_Impl
*This
= (IStream_Impl
*)iface
;
667 return InterlockedIncrement(&This
->ref
);
670 static ULONG WINAPI
ITSS_IStream_Release(
673 IStream_Impl
*This
= (IStream_Impl
*)iface
;
675 ULONG ref
= InterlockedDecrement(&This
->ref
);
679 IStorage_Release( (IStorage
*) This
->stg
);
680 HeapFree(GetProcessHeap(), 0, This
);
687 static HRESULT WINAPI
ITSS_IStream_Read(
693 IStream_Impl
*This
= (IStream_Impl
*)iface
;
696 TRACE("%p %p %u %p\n", This
, pv
, cb
, pcbRead
);
698 count
= chm_retrieve_object(This
->stg
->chmfile
,
699 &This
->ui
, pv
, This
->addr
, cb
);
704 return count
? S_OK
: S_FALSE
;
707 static HRESULT WINAPI
ITSS_IStream_Write(
717 static HRESULT WINAPI
ITSS_IStream_Seek(
719 LARGE_INTEGER dlibMove
,
721 ULARGE_INTEGER
* plibNewPosition
)
723 IStream_Impl
*This
= (IStream_Impl
*)iface
;
726 TRACE("%p %s %u %p\n", This
,
727 wine_dbgstr_longlong( dlibMove
.QuadPart
), dwOrigin
, plibNewPosition
);
732 case STREAM_SEEK_CUR
:
733 newpos
= This
->addr
+ dlibMove
.QuadPart
;
735 case STREAM_SEEK_SET
:
736 newpos
= dlibMove
.QuadPart
;
738 case STREAM_SEEK_END
:
739 newpos
= This
->ui
.length
+ dlibMove
.QuadPart
;
743 if( ( newpos
< 0 ) || ( newpos
> This
->ui
.length
) )
744 return STG_E_INVALIDPOINTER
;
747 if( plibNewPosition
)
748 plibNewPosition
->QuadPart
= This
->addr
;
753 static HRESULT WINAPI
ITSS_IStream_SetSize(
755 ULARGE_INTEGER libNewSize
)
761 static HRESULT WINAPI
ITSS_IStream_CopyTo(
765 ULARGE_INTEGER
* pcbRead
,
766 ULARGE_INTEGER
* pcbWritten
)
772 static HRESULT WINAPI
ITSS_IStream_Commit(
774 DWORD grfCommitFlags
)
780 static HRESULT WINAPI
ITSS_IStream_Revert(
787 static HRESULT WINAPI
ITSS_IStream_LockRegion(
789 ULARGE_INTEGER libOffset
,
797 static HRESULT WINAPI
ITSS_IStream_UnlockRegion(
799 ULARGE_INTEGER libOffset
,
807 static HRESULT WINAPI
ITSS_IStream_Stat(
812 IStream_Impl
*This
= (IStream_Impl
*)iface
;
814 TRACE("%p %p %d\n", This
, pstatstg
, grfStatFlag
);
816 memset( pstatstg
, 0, sizeof *pstatstg
);
817 if( !( grfStatFlag
& STATFLAG_NONAME
) )
819 FIXME("copy the name\n");
821 pstatstg
->type
= STGTY_STREAM
;
822 pstatstg
->cbSize
.QuadPart
= This
->ui
.length
;
823 pstatstg
->grfMode
= STGM_READ
;
824 pstatstg
->clsid
= CLSID_ITStorage
;
829 static HRESULT WINAPI
ITSS_IStream_Clone(
837 static const IStreamVtbl ITSS_IStream_vtbl
=
839 ITSS_IStream_QueryInterface
,
841 ITSS_IStream_Release
,
845 ITSS_IStream_SetSize
,
849 ITSS_IStream_LockRegion
,
850 ITSS_IStream_UnlockRegion
,
855 static IStream_Impl
*ITSS_create_stream(
856 ITSS_IStorageImpl
*stg
, struct chmUnitInfo
*ui
)
860 stm
= HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl
) );
861 stm
->vtbl_IStream
= &ITSS_IStream_vtbl
;
866 IStorage_AddRef( (IStorage
*) stg
);
870 TRACE(" -> %p\n", stm
);