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 );