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 struct chmFile *chmfile;
413 TRACE("%p %s %p %u %p %u %p\n", This, debugstr_w(pwcsName),
414 pstgPriority, grfMode, snbExclude, reserved, ppstg);
416 chmfile = chm_dup( This->chmfile );
420 len = strlenW( This->dir ) + strlenW( pwcsName ) + 2; /* need room for a terminating slash */
421 path = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
422 strcpyW( path, This->dir );
424 if( pwcsName[0] == '/' || pwcsName[0] == '\\' )
426 p = &path[strlenW( path ) - 1];
427 while( ( path <= p ) && ( *p == '/' ) )
430 strcatW( path, pwcsName );
432 for(p=path; *p; p++) {
437 /* add a terminating slash if one does not already exist */
444 TRACE("Resolving %s\n", debugstr_w(path));
446 return ITSS_create_chm_storage(chmfile, path, ppstg);
449 static HRESULT WINAPI ITSS_IStorageImpl_CopyTo(
452 const IID* rgiidExclude,
460 static HRESULT WINAPI ITSS_IStorageImpl_MoveElementTo(
464 LPCOLESTR pwcsNewName,
471 static HRESULT WINAPI ITSS_IStorageImpl_Commit(
473 DWORD grfCommitFlags)
479 static HRESULT WINAPI ITSS_IStorageImpl_Revert(
486 static int ITSS_chm_enumerator(
488 struct chmUnitInfo *ui,
491 struct enum_info *info;
492 IEnumSTATSTG_Impl* stgenum = context;
494 TRACE("adding %s to enumeration\n", debugstr_w(ui->path) );
496 info = HeapAlloc( GetProcessHeap(), 0, sizeof (struct enum_info) );
500 info->prev = stgenum->last;
502 stgenum->last->next = info;
504 stgenum->first = info;
505 stgenum->last = info;
507 return CHM_ENUMERATOR_CONTINUE;
510 static HRESULT WINAPI ITSS_IStorageImpl_EnumElements(
515 IEnumSTATSTG** ppenum)
517 ITSS_IStorageImpl *This = impl_from_IStorage(iface);
518 IEnumSTATSTG_Impl* stgenum;
520 TRACE("%p %d %p %d %p\n", This, reserved1, reserved2, reserved3, ppenum );
522 stgenum = ITSS_create_enum();
526 chm_enumerate_dir(This->chmfile,
532 stgenum->current = stgenum->first;
534 *ppenum = &stgenum->IEnumSTATSTG_iface;
539 static HRESULT WINAPI ITSS_IStorageImpl_DestroyElement(
547 static HRESULT WINAPI ITSS_IStorageImpl_RenameElement(
549 LPCOLESTR pwcsOldName,
550 LPCOLESTR pwcsNewName)
556 static HRESULT WINAPI ITSS_IStorageImpl_SetElementTimes(
559 const FILETIME* pctime,
560 const FILETIME* patime,
561 const FILETIME* pmtime)
567 static HRESULT WINAPI ITSS_IStorageImpl_SetClass(
575 static HRESULT WINAPI ITSS_IStorageImpl_SetStateBits(
584 static HRESULT WINAPI ITSS_IStorageImpl_Stat(
593 static const IStorageVtbl ITSS_IStorageImpl_Vtbl =
595 ITSS_IStorageImpl_QueryInterface,
596 ITSS_IStorageImpl_AddRef,
597 ITSS_IStorageImpl_Release,
598 ITSS_IStorageImpl_CreateStream,
599 ITSS_IStorageImpl_OpenStream,
600 ITSS_IStorageImpl_CreateStorage,
601 ITSS_IStorageImpl_OpenStorage,
602 ITSS_IStorageImpl_CopyTo,
603 ITSS_IStorageImpl_MoveElementTo,
604 ITSS_IStorageImpl_Commit,
605 ITSS_IStorageImpl_Revert,
606 ITSS_IStorageImpl_EnumElements,
607 ITSS_IStorageImpl_DestroyElement,
608 ITSS_IStorageImpl_RenameElement,
609 ITSS_IStorageImpl_SetElementTimes,
610 ITSS_IStorageImpl_SetClass,
611 ITSS_IStorageImpl_SetStateBits,
612 ITSS_IStorageImpl_Stat,
615 static HRESULT ITSS_create_chm_storage(
616 struct chmFile *chmfile, const WCHAR *dir, IStorage** ppstgOpen )
618 ITSS_IStorageImpl *stg;
621 TRACE("%p %s\n", chmfile, debugstr_w( dir ) );
623 len = strlenW( dir ) + 1;
624 stg = HeapAlloc( GetProcessHeap(), 0,
625 sizeof (ITSS_IStorageImpl) + len*sizeof(WCHAR) );
626 stg->IStorage_iface.lpVtbl = &ITSS_IStorageImpl_Vtbl;
628 stg->chmfile = chmfile;
629 strcpyW( stg->dir, dir );
631 *ppstgOpen = &stg->IStorage_iface;
637 HRESULT ITSS_StgOpenStorage(
638 const WCHAR* pwcsName,
639 IStorage* pstgPriority,
643 IStorage** ppstgOpen)
645 struct chmFile *chmfile;
646 static const WCHAR szRoot[] = { '/', 0 };
648 TRACE("%s\n", debugstr_w(pwcsName) );
650 chmfile = chm_openW( pwcsName );
654 return ITSS_create_chm_storage( chmfile, szRoot, ppstgOpen );
657 /************************************************************************/
659 static HRESULT WINAPI ITSS_IStream_QueryInterface(
664 IStream_Impl *This = impl_from_IStream(iface);
666 if (IsEqualGUID(riid, &IID_IUnknown)
667 || IsEqualGUID(riid, &IID_ISequentialStream)
668 || IsEqualGUID(riid, &IID_IStream))
670 IStream_AddRef(iface);
675 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
676 return E_NOINTERFACE;
679 static ULONG WINAPI ITSS_IStream_AddRef(
682 IStream_Impl *This = impl_from_IStream(iface);
683 return InterlockedIncrement(&This->ref);
686 static ULONG WINAPI ITSS_IStream_Release(
689 IStream_Impl *This = impl_from_IStream(iface);
691 ULONG ref = InterlockedDecrement(&This->ref);
695 IStorage_Release( &This->stg->IStorage_iface );
696 HeapFree(GetProcessHeap(), 0, This);
703 static HRESULT WINAPI ITSS_IStream_Read(
709 IStream_Impl *This = impl_from_IStream(iface);
712 TRACE("%p %p %u %p\n", This, pv, cb, pcbRead);
714 count = chm_retrieve_object(This->stg->chmfile,
715 &This->ui, pv, This->addr, cb);
720 return count ? S_OK : S_FALSE;
723 static HRESULT WINAPI ITSS_IStream_Write(
733 static HRESULT WINAPI ITSS_IStream_Seek(
735 LARGE_INTEGER dlibMove,
737 ULARGE_INTEGER* plibNewPosition)
739 IStream_Impl *This = impl_from_IStream(iface);
742 TRACE("%p %s %u %p\n", This,
743 wine_dbgstr_longlong( dlibMove.QuadPart ), dwOrigin, plibNewPosition );
748 case STREAM_SEEK_CUR:
749 newpos = This->addr + dlibMove.QuadPart;
751 case STREAM_SEEK_SET:
752 newpos = dlibMove.QuadPart;
754 case STREAM_SEEK_END:
755 newpos = This->ui.length + dlibMove.QuadPart;
759 if( ( newpos < 0 ) || ( newpos > This->ui.length ) )
760 return STG_E_INVALIDPOINTER;
763 if( plibNewPosition )
764 plibNewPosition->QuadPart = This->addr;
769 static HRESULT WINAPI ITSS_IStream_SetSize(
771 ULARGE_INTEGER libNewSize)
777 static HRESULT WINAPI ITSS_IStream_CopyTo(
781 ULARGE_INTEGER* pcbRead,
782 ULARGE_INTEGER* pcbWritten)
788 static HRESULT WINAPI ITSS_IStream_Commit(
790 DWORD grfCommitFlags)
796 static HRESULT WINAPI ITSS_IStream_Revert(
803 static HRESULT WINAPI ITSS_IStream_LockRegion(
805 ULARGE_INTEGER libOffset,
813 static HRESULT WINAPI ITSS_IStream_UnlockRegion(
815 ULARGE_INTEGER libOffset,
823 static HRESULT WINAPI ITSS_IStream_Stat(
828 IStream_Impl *This = impl_from_IStream(iface);
830 TRACE("%p %p %d\n", This, pstatstg, grfStatFlag);
832 memset( pstatstg, 0, sizeof *pstatstg );
833 if( !( grfStatFlag & STATFLAG_NONAME ) )
835 FIXME("copy the name\n");
837 pstatstg->type = STGTY_STREAM;
838 pstatstg->cbSize.QuadPart = This->ui.length;
839 pstatstg->grfMode = STGM_READ;
840 pstatstg->clsid = CLSID_ITStorage;
845 static HRESULT WINAPI ITSS_IStream_Clone(
853 static const IStreamVtbl ITSS_IStream_vtbl =
855 ITSS_IStream_QueryInterface,
857 ITSS_IStream_Release,
861 ITSS_IStream_SetSize,
865 ITSS_IStream_LockRegion,
866 ITSS_IStream_UnlockRegion,
871 static IStream_Impl *ITSS_create_stream(
872 ITSS_IStorageImpl *stg, struct chmUnitInfo *ui )
876 stm = HeapAlloc( GetProcessHeap(), 0, sizeof (IStream_Impl) );
877 stm->IStream_iface.lpVtbl = &ITSS_IStream_vtbl;
882 IStorage_AddRef( &stg->IStorage_iface );
886 TRACE(" -> %p\n", stm );