From f4fa6270ae46ff44b8068d12abc71b250f274434 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Wed, 10 Mar 2010 14:28:56 +0000 Subject: [PATCH] [OLE32] - Sync to Wine-1.1.40. Along with improvements, it provides many memory corruption fixes. svn path=/trunk/; revision=46056 --- reactos/dll/win32/ole32/clipboard.c | 14 +- reactos/dll/win32/ole32/compobj.c | 51 +- reactos/dll/win32/ole32/compobj_private.h | 3 + reactos/dll/win32/ole32/compositemoniker.c | 2 +- reactos/dll/win32/ole32/datacache.c | 6 + reactos/dll/win32/ole32/defaulthandler.c | 96 + reactos/dll/win32/ole32/errorinfo.c | 4 + reactos/dll/win32/ole32/filemoniker.c | 69 +- reactos/dll/win32/ole32/hglobalstream.c | 21 +- reactos/dll/win32/ole32/itemmoniker.c | 361 +- reactos/dll/win32/ole32/marshal.c | 8 +- reactos/dll/win32/ole32/moniker.c | 22 +- reactos/dll/win32/ole32/ole2.c | 7 +- reactos/dll/win32/ole32/ole32.spec | 2 +- reactos/dll/win32/ole32/ole32res.rc | 14 +- reactos/dll/win32/ole32/oleproxy.c | 8 +- reactos/dll/win32/ole32/regsvr.c | 64 +- reactos/dll/win32/ole32/rpc.c | 2 +- reactos/dll/win32/ole32/stg_prop.c | 54 +- reactos/dll/win32/ole32/stg_stream.c | 346 +- reactos/dll/win32/ole32/storage32.c | 3916 +++++++++++--------- reactos/dll/win32/ole32/storage32.h | 239 +- reactos/dll/win32/ole32/stubmanager.c | 8 +- reactos/dll/win32/ole32/usrmarshal.c | 10 +- 24 files changed, 2857 insertions(+), 2470 deletions(-) diff --git a/reactos/dll/win32/ole32/clipboard.c b/reactos/dll/win32/ole32/clipboard.c index 7f19d1638a4..2afc77e35f0 100644 --- a/reactos/dll/win32/ole32/clipboard.c +++ b/reactos/dll/win32/ole32/clipboard.c @@ -1608,6 +1608,8 @@ void OLEClipbrd_UnInitialize(void) } IStream_Release(clipbrd->marshal_data); + if (clipbrd->src_data) IDataObject_Release(clipbrd->src_data); + HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum); HeapFree(GetProcessHeap(), 0, clipbrd); theOleClipboard = NULL; } @@ -1699,7 +1701,11 @@ static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data) td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd); GlobalUnlock(priv_data_handle); - SetClipboardData(ole_private_data_clipboard_format, priv_data_handle); + if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle)) + { + GlobalFree(priv_data_handle); + return CLIPBRD_E_CANT_SET; + } return S_OK; } @@ -1757,7 +1763,11 @@ static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *d if(!h) return E_OUTOFMEMORY; - SetClipboardData(wine_marshal_clipboard_format, h); + if(!SetClipboardData(wine_marshal_clipboard_format, h)) + { + GlobalFree(h); + return CLIPBRD_E_CANT_SET; + } return S_OK; } diff --git a/reactos/dll/win32/ole32/compobj.c b/reactos/dll/win32/ole32/compobj.c index b2013cfbfa3..583a9cbcd00 100644 --- a/reactos/dll/win32/ole32/compobj.c +++ b/reactos/dll/win32/ole32/compobj.c @@ -828,6 +828,16 @@ static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *v if (keytype == REG_EXPAND_SZ) { if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA; } else { + const WCHAR *quote_start; + quote_start = strchrW(src, '\"'); + if (quote_start) { + const WCHAR *quote_end = strchrW(quote_start + 1, '\"'); + if (quote_end) { + memmove(src, quote_start + 1, + (quote_end - quote_start - 1) * sizeof(WCHAR)); + src[quote_end - quote_start - 1] = '\0'; + } + } lstrcpynW(dst, src, dstlen); } } @@ -1621,7 +1631,7 @@ INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax) '%','0','4','X','-','%','0','2','X','%','0','2','X','-', '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X', '%','0','2','X','%','0','2','X','}',0 }; - if (cmax < CHARS_IN_GUID) return 0; + if (!id || cmax < CHARS_IN_GUID) return 0; sprintfW( str, formatW, id->Data1, id->Data2, id->Data3, id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); @@ -2052,6 +2062,7 @@ HRESULT WINAPI CoRegisterClassObject( DWORD flags, LPDWORD lpdwRegister) { + static LONG next_cookie; RegisteredClass* newClass; LPUNKNOWN foundObject; HRESULT hr; @@ -2105,11 +2116,8 @@ HRESULT WINAPI CoRegisterClassObject( newClass->pMarshaledData = NULL; newClass->RpcRegistration = NULL; - /* - * Use the address of the chain node as the cookie since we are sure it's - * unique. FIXME: not on 64-bit platforms. - */ - newClass->dwCookie = (DWORD)newClass; + if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie ))) + newClass->dwCookie = InterlockedIncrement( &next_cookie ); /* * Since we're making a copy of the object pointer, we have to increase its @@ -2130,7 +2138,7 @@ HRESULT WINAPI CoRegisterClassObject( FIXME("Failed to create stream on hglobal, %x\n", hr); return hr; } - hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory, + hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown, newClass->classObject, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); if (hr) { @@ -2380,7 +2388,7 @@ HRESULT WINAPI CoGetClassObject( if (CLSCTX_REMOTE_SERVER & dwClsContext) { FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); - hres = E_NOINTERFACE; + hres = REGDB_E_CLASSNOTREG; } if (FAILED(hres)) @@ -4106,6 +4114,33 @@ HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) return S_OK; } +HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; + HKEY hkey; + HRESULT hres; + + hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); + if (SUCCEEDED(hres)) + { + WCHAR dllpath[MAX_PATH+1]; + + if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS) + { + static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; + if (!strcmpiW(dllpath, wszOle32)) + { + RegCloseKey(hkey); + return HandlerCF_Create(rclsid, riid, ppv); + } + } + else + WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath)); + RegCloseKey(hkey); + } + + return CLASS_E_CLASSNOTAVAILABLE; +} /*********************************************************************** * DllMain (OLE32.@) diff --git a/reactos/dll/win32/ole32/compobj_private.h b/reactos/dll/win32/ole32/compobj_private.h index fb059349f8c..076d845c85a 100644 --- a/reactos/dll/win32/ole32/compobj_private.h +++ b/reactos/dll/win32/ole32/compobj_private.h @@ -313,6 +313,9 @@ extern HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID extern HRESULT WINAPI OLE32_DllRegisterServer(void) DECLSPEC_HIDDEN; extern HRESULT WINAPI OLE32_DllUnregisterServer(void) DECLSPEC_HIDDEN; +extern HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv); +extern HRESULT HandlerCF_Create(REFCLSID rclsid, REFIID riid, LPVOID *ppv); + /* Exported non-interface Data Advise Holder functions */ HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate); void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface); diff --git a/reactos/dll/win32/ole32/compositemoniker.c b/reactos/dll/win32/ole32/compositemoniker.c index 5535a97681b..7402b8edbbf 100644 --- a/reactos/dll/win32/ole32/compositemoniker.c +++ b/reactos/dll/win32/ole32/compositemoniker.c @@ -670,7 +670,7 @@ CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, else{ if (pbc==NULL) - return E_POINTER; + return E_INVALIDARG; /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */ /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */ diff --git a/reactos/dll/win32/ole32/datacache.c b/reactos/dll/win32/ole32/datacache.c index a2589808322..ead53fe83c3 100644 --- a/reactos/dll/win32/ole32/datacache.c +++ b/reactos/dll/win32/ole32/datacache.c @@ -234,6 +234,12 @@ static void DataCache_Destroy( LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry) DataCacheEntry_Destroy(cache_entry); + if (ptrToDestroy->presentationStorage != NULL) + { + IStorage_Release(ptrToDestroy->presentationStorage); + ptrToDestroy->presentationStorage = NULL; + } + /* * Free the datacache pointer. */ diff --git a/reactos/dll/win32/ole32/defaulthandler.c b/reactos/dll/win32/ole32/defaulthandler.c index 4102d50845b..5130513d57f 100644 --- a/reactos/dll/win32/ole32/defaulthandler.c +++ b/reactos/dll/win32/ole32/defaulthandler.c @@ -1960,9 +1960,21 @@ static DefaultHandler* DefaultHandler_Construct( &IID_IUnknown, (void**)&This->dataCache); if(SUCCEEDED(hr)) + { hr = IUnknown_QueryInterface(This->dataCache, &IID_IPersistStorage, (void**)&This->dataCache_PersistStg); + /* keeping a reference to This->dataCache_PersistStg causes us to keep a + * reference on the outer object */ + if (SUCCEEDED(hr)) + IUnknown_Release(This->outerUnknown); + else + IUnknown_Release(This->dataCache); + } if(FAILED(hr)) + { ERR("Unexpected error creating data cache\n"); + HeapFree(GetProcessHeap(), 0, This); + return NULL; + } This->clsid = *clsid; This->clientSite = NULL; @@ -2009,6 +2021,13 @@ static DefaultHandler* DefaultHandler_Construct( static void DefaultHandler_Destroy( DefaultHandler* This) { + TRACE("(%p)\n", This); + + /* AddRef/Release may be called on this object during destruction. + * Prevent the object being destroyed recursively by artificially raising + * the reference count. */ + This->ref = 10000; + /* release delegates */ DefaultHandler_Stop(This); release_delegates(This); @@ -2020,6 +2039,9 @@ static void DefaultHandler_Destroy( if (This->dataCache) { + /* to balance out the release of dataCache_PersistStg which will result + * in a reference being released from the outer unknown */ + IUnknown_AddRef(This->outerUnknown); IPersistStorage_Release(This->dataCache_PersistStg); IUnknown_Release(This->dataCache); This->dataCache_PersistStg = NULL; @@ -2122,3 +2144,77 @@ HRESULT WINAPI OleCreateDefaultHandler(REFCLSID clsid, LPUNKNOWN pUnkOuter, return OleCreateEmbeddingHelper(clsid, pUnkOuter, EMBDHLP_INPROC_HANDLER | EMBDHLP_CREATENOW, NULL, riid, ppvObj); } + +typedef struct HandlerCF +{ + const IClassFactoryVtbl *lpVtbl; + LONG refs; + CLSID clsid; +} HandlerCF; + +static HRESULT WINAPI +HandlerCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid,&IID_IUnknown) || + IsEqualIID(riid,&IID_IClassFactory)) + { + *ppv = iface; + IClassFactory_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI HandlerCF_AddRef(LPCLASSFACTORY iface) +{ + HandlerCF *This = (HandlerCF *)iface; + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI HandlerCF_Release(LPCLASSFACTORY iface) +{ + HandlerCF *This = (HandlerCF *)iface; + ULONG refs = InterlockedDecrement(&This->refs); + if (!refs) + HeapFree(GetProcessHeap(), 0, This); + return refs; +} + +static HRESULT WINAPI +HandlerCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pUnk, + REFIID riid, LPVOID *ppv) +{ + HandlerCF *This = (HandlerCF *)iface; + return OleCreateDefaultHandler(&This->clsid, pUnk, riid, ppv); +} + +static HRESULT WINAPI HandlerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl HandlerClassFactoryVtbl = { + HandlerCF_QueryInterface, + HandlerCF_AddRef, + HandlerCF_Release, + HandlerCF_CreateInstance, + HandlerCF_LockServer +}; + +HRESULT HandlerCF_Create(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + HRESULT hr; + HandlerCF *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) return E_OUTOFMEMORY; + This->lpVtbl = &HandlerClassFactoryVtbl; + This->refs = 0; + This->clsid = *rclsid; + + hr = IUnknown_QueryInterface((IUnknown *)&This->lpVtbl, riid, ppv); + if (FAILED(hr)) + HeapFree(GetProcessHeap(), 0, This); + + return hr; +} diff --git a/reactos/dll/win32/ole32/errorinfo.c b/reactos/dll/win32/ole32/errorinfo.c index f69635bc493..39751ab6551 100644 --- a/reactos/dll/win32/ole32/errorinfo.c +++ b/reactos/dll/win32/ole32/errorinfo.c @@ -237,6 +237,10 @@ static ULONG WINAPI IErrorInfoImpl_Release( if (!ref) { TRACE("-- destroying IErrorInfo(%p)\n",This); + + ERRORINFO_SysFreeString(This->bstrSource); + ERRORINFO_SysFreeString(This->bstrDescription); + ERRORINFO_SysFreeString(This->bstrHelpFile); HeapFree(GetProcessHeap(),0,This); return 0; } diff --git a/reactos/dll/win32/ole32/filemoniker.c b/reactos/dll/win32/ole32/filemoniker.c index e9fd4cacfe9..72f59136f78 100644 --- a/reactos/dll/win32/ole32/filemoniker.c +++ b/reactos/dll/win32/ole32/filemoniker.c @@ -198,9 +198,9 @@ FileMonikerImpl_Load(IMoniker* iface, IStream* pStm) TRACE("(%p,%p)\n",iface,pStm); - /* first WORD must be 0 */ + /* first WORD */ res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); - if (bread!=sizeof(WORD) || wbuffer!=0) + if (bread!=sizeof(WORD)) { WARN("Couldn't read 0 word\n"); goto fail; @@ -229,18 +229,26 @@ FileMonikerImpl_Load(IMoniker* iface, IStream* pStm) goto fail; } - /* read the first constant */ - IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); - if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF) + /* read the unknown value */ + IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); + if (bread != sizeof(WORD)) { - WARN("Couldn't read 0xDEADFFFF constant\n"); + WARN("Couldn't read unknown value\n"); + goto fail; + } + + /* read the DEAD constant */ + IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); + if (bread != sizeof(WORD)) + { + WARN("Couldn't read DEAD constant\n"); goto fail; } for(i=0;i<5;i++) { res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); - if (bread!=sizeof(DWORD) || dwbuffer!=0) + if (bread!=sizeof(DWORD)) { WARN("Couldn't read 0 padding\n"); goto fail; @@ -320,18 +328,20 @@ FileMonikerImpl_Load(IMoniker* iface, IStream* pStm) * of Windows have minor variations. * * Data which must be written on stream is: - * 1) WORD constant:zero + * 1) WORD constant: zero (not validated by Windows) * 2) length of the path string ("\0" included) * 3) path string type A - * 4) DWORD constant : 0xDEADFFFF - * 5) five DWORD constant: zero - * 6) If we're only writing the multibyte version, + * 4) Unknown WORD value: Frequently 0xFFFF, but not always. If set very large, + * Windows returns E_OUTOFMEMORY + * 5) WORD Constant: 0xDEAD (not validated by Windows) + * 6) five DWORD constant: zero (not validated by Windows) + * 7) If we're only writing the multibyte version, * write a zero DWORD and finish. * - * 7) DWORD: double-length of the path string type W ("\0" not + * 8) DWORD: double-length of the path string type W ("\0" not * included) - * 8) WORD constant: 0x3 - * 9) filePath unicode string. + * 9) WORD constant: 0x3 + * 10) filePath unicode string. * */ static HRESULT WINAPI @@ -344,7 +354,8 @@ FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty) CHAR* filePathA; DWORD bytesA, bytesW, len; - static const DWORD DEADFFFF = 0xDEADFFFF; /* Constants */ + static const WORD FFFF = 0xFFFF; /* Constants */ + static const WORD DEAD = 0xDEAD; static const DWORD ZERO = 0; static const WORD THREE = 0x3; @@ -374,8 +385,12 @@ FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty) HeapFree(GetProcessHeap(),0,filePathA); if (FAILED(res)) return res; - /* write a DWORD 0xDEADFFFF */ - res=IStream_Write(pStm,&DEADFFFF,sizeof(DWORD),NULL); + /* write a WORD 0xFFFF */ + res=IStream_Write(pStm,&FFFF,sizeof(WORD),NULL); + if (FAILED(res)) return res; + + /* write a WORD 0xDEAD */ + res=IStream_Write(pStm,&DEAD,sizeof(WORD),NULL); if (FAILED(res)) return res; /* write 5 zero DWORDs */ @@ -945,20 +960,32 @@ FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** p if(mkSys==MKSYS_FILEMONIKER){ HRESULT ret; - CreateBindCtx(0,&pbind); + ret = CreateBindCtx(0,&pbind); + if (FAILED(ret)) + return ret; /* create a string based on common part of the two paths */ - IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis); - IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther); + ret = IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis); + if (FAILED(ret)) + return ret; + ret = IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther); + if (FAILED(ret)) + return ret; nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1); + if (FAILED(nb1)) + return nb1; nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2); + if (FAILED(nb2)) + return nb2; if (nb1==0 || nb2==0) return MK_E_NOPREFIX; commonPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1)); + if (!commonPath) + return E_OUTOFMEMORY; *commonPath=0; @@ -1021,7 +1048,7 @@ int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable) TRACE("%s, %p\n", debugstr_w(str), *stringTable); - strgtable = CoTaskMemAlloc(len*sizeof(WCHAR)); + strgtable = CoTaskMemAlloc((len + 1)*sizeof(*strgtable)); if (strgtable==NULL) return E_OUTOFMEMORY; diff --git a/reactos/dll/win32/ole32/hglobalstream.c b/reactos/dll/win32/ole32/hglobalstream.c index c43d499bb4e..5742f99619a 100644 --- a/reactos/dll/win32/ole32/hglobalstream.c +++ b/reactos/dll/win32/ole32/hglobalstream.c @@ -365,11 +365,18 @@ static HRESULT WINAPI HGLOBALStreamImpl_Seek( { HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - ULARGE_INTEGER newPosition; + ULARGE_INTEGER newPosition = This->currentPosition; + HRESULT hr = S_OK; TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition); + if (dlibMove.u.LowPart >= 0x80000000) + { + hr = STG_E_SEEKERROR; + goto end; + } + /* * The file pointer is moved depending on the given "function" * parameter. @@ -381,13 +388,13 @@ static HRESULT WINAPI HGLOBALStreamImpl_Seek( newPosition.u.LowPart = 0; break; case STREAM_SEEK_CUR: - newPosition = This->currentPosition; break; case STREAM_SEEK_END: newPosition = This->streamSize; break; default: - return STG_E_INVALIDFUNCTION; + hr = STG_E_SEEKERROR; + goto end; } /* @@ -395,14 +402,14 @@ static HRESULT WINAPI HGLOBALStreamImpl_Seek( * If the file pointer ends-up after the end of the stream, the next Write operation will * make the file larger. This is how it is documented. */ - if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart) return STG_E_INVALIDFUNCTION; - - newPosition.QuadPart += dlibMove.QuadPart; + newPosition.u.HighPart = 0; + newPosition.u.LowPart += dlibMove.QuadPart; +end: if (plibNewPosition) *plibNewPosition = newPosition; This->currentPosition = newPosition; - return S_OK; + return hr; } /*** diff --git a/reactos/dll/win32/ole32/itemmoniker.c b/reactos/dll/win32/ole32/itemmoniker.c index 816533d42c0..ff8f9b481e3 100644 --- a/reactos/dll/win32/ole32/itemmoniker.c +++ b/reactos/dll/win32/ole32/itemmoniker.c @@ -62,99 +62,12 @@ static inline IMoniker *impl_from_IROTData( IROTData *iface ) return (IMoniker *)((char*)iface - FIELD_OFFSET(ItemMonikerImpl, lpvtbl2)); } -/********************************************************************************/ -/* ItemMoniker prototype functions : */ - -/* IUnknown prototype functions */ -static HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject); -static ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface); -static ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface); - -/* IPersist prototype functions */ -static HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID); - -/* IPersistStream prototype functions */ -static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface); -static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface, IStream* pStm); -static HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty); -static HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize); - -/* IMoniker prototype functions */ -static HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult); -static HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult); -static HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced); -static HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite); -static HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker); -static HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker); -static HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash); -static HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning); -static HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pItemTime); -static HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk); -static HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix); -static HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath); -static HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName); -static HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut); -static HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys); - -/* Local function used by ItemMoniker implementation */ -static HRESULT ItemMonikerImpl_Construct(ItemMonikerImpl* iface, LPCOLESTR lpszDelim,LPCOLESTR lpszPathName); static HRESULT ItemMonikerImpl_Destroy(ItemMonikerImpl* iface); -/********************************************************************************/ -/* IROTData prototype functions */ - -/* IUnknown prototype functions */ -static HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData* iface,REFIID riid,VOID** ppvObject); -static ULONG WINAPI ItemMonikerROTDataImpl_AddRef(IROTData* iface); -static ULONG WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface); - -/* IROTData prototype function */ -static HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData); - -/********************************************************************************/ -/* Virtual function table for the ItemMonikerImpl class which include IPersist,*/ -/* IPersistStream and IMoniker functions. */ -static const IMonikerVtbl VT_ItemMonikerImpl = - { - ItemMonikerImpl_QueryInterface, - ItemMonikerImpl_AddRef, - ItemMonikerImpl_Release, - ItemMonikerImpl_GetClassID, - ItemMonikerImpl_IsDirty, - ItemMonikerImpl_Load, - ItemMonikerImpl_Save, - ItemMonikerImpl_GetSizeMax, - ItemMonikerImpl_BindToObject, - ItemMonikerImpl_BindToStorage, - ItemMonikerImpl_Reduce, - ItemMonikerImpl_ComposeWith, - ItemMonikerImpl_Enum, - ItemMonikerImpl_IsEqual, - ItemMonikerImpl_Hash, - ItemMonikerImpl_IsRunning, - ItemMonikerImpl_GetTimeOfLastChange, - ItemMonikerImpl_Inverse, - ItemMonikerImpl_CommonPrefixWith, - ItemMonikerImpl_RelativePathTo, - ItemMonikerImpl_GetDisplayName, - ItemMonikerImpl_ParseDisplayName, - ItemMonikerImpl_IsSystemMoniker -}; - -/********************************************************************************/ -/* Virtual function table for the IROTData class. */ -static const IROTDataVtbl VT_ROTDataImpl = -{ - ItemMonikerROTDataImpl_QueryInterface, - ItemMonikerROTDataImpl_AddRef, - ItemMonikerROTDataImpl_Release, - ItemMonikerROTDataImpl_GetComparisonData -}; - /******************************************************************************* * ItemMoniker_QueryInterface *******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) +static HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; @@ -192,7 +105,7 @@ HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** return E_NOINTERFACE; /* Query Interface always increases the reference count by one when it is successful */ - ItemMonikerImpl_AddRef(iface); + IMoniker_AddRef(iface); return S_OK; } @@ -200,7 +113,7 @@ HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** /****************************************************************************** * ItemMoniker_AddRef ******************************************************************************/ -ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface) +static ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; @@ -212,7 +125,7 @@ ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface) /****************************************************************************** * ItemMoniker_Release ******************************************************************************/ -ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface) +static ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; ULONG ref; @@ -230,7 +143,7 @@ ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface) /****************************************************************************** * ItemMoniker_GetClassID ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) +static HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) { TRACE("(%p,%p)\n",iface,pClassID); @@ -245,7 +158,7 @@ HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) /****************************************************************************** * ItemMoniker_IsDirty ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface) +static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface) { /* Note that the OLE-provided implementations of the IPersistStream::IsDirty method in the OLE-provided moniker interfaces always return S_FALSE because @@ -259,7 +172,7 @@ HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface) /****************************************************************************** * ItemMoniker_Load ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm) +static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; @@ -328,9 +241,9 @@ HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm) /****************************************************************************** * ItemMoniker_Save ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, - IStream* pStm,/* pointer to the stream where the object is to be saved */ - BOOL fClearDirty)/* Specifies whether to clear the dirty flag */ +static HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, + IStream* pStm,/* pointer to the stream where the object is to be saved */ + BOOL fClearDirty)/* Specifies whether to clear the dirty flag */ { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; HRESULT res; @@ -364,8 +277,8 @@ HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, /****************************************************************************** * ItemMoniker_GetSizeMax ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, - ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */ +static HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, + ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */ { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; DWORD delimiterLength=lstrlenW(This->itemDelimiter)+1; @@ -388,67 +301,14 @@ HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, return S_OK; } -/****************************************************************************** - * ItemMoniker_Construct (local function) - *******************************************************************************/ -static HRESULT ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDelim,LPCOLESTR lpszItem) -{ - - int sizeStr1=lstrlenW(lpszItem), sizeStr2; - static const OLECHAR emptystr[1]; - LPCOLESTR delim; - - TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszDelim),debugstr_w(lpszItem)); - - /* Initialize the virtual function table. */ - This->lpvtbl1 = &VT_ItemMonikerImpl; - This->lpvtbl2 = &VT_ROTDataImpl; - This->ref = 0; - This->pMarshal = NULL; - - This->itemName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr1+1)); - if (!This->itemName) - return E_OUTOFMEMORY; - lstrcpyW(This->itemName,lpszItem); - - if (!lpszDelim) - FIXME("lpszDelim is NULL. Using empty string which is possibly wrong.\n"); - - delim = lpszDelim ? lpszDelim : emptystr; - - sizeStr2=lstrlenW(delim); - This->itemDelimiter=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr2+1)); - if (!This->itemDelimiter) { - HeapFree(GetProcessHeap(),0,This->itemName); - return E_OUTOFMEMORY; - } - lstrcpyW(This->itemDelimiter,delim); - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_Destroy (local function) - *******************************************************************************/ -static HRESULT ItemMonikerImpl_Destroy(ItemMonikerImpl* This) -{ - TRACE("(%p)\n",This); - - if (This->pMarshal) IUnknown_Release(This->pMarshal); - HeapFree(GetProcessHeap(),0,This->itemName); - HeapFree(GetProcessHeap(),0,This->itemDelimiter); - HeapFree(GetProcessHeap(),0,This); - - return S_OK; -} - /****************************************************************************** * ItemMoniker_BindToObject ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - REFIID riid, - VOID** ppvResult) +static HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + REFIID riid, + VOID** ppvResult) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; @@ -481,11 +341,11 @@ HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface, /****************************************************************************** * ItemMoniker_BindToStorage ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - REFIID riid, - VOID** ppvResult) +static HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + REFIID riid, + VOID** ppvResult) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; @@ -514,11 +374,11 @@ HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface, /****************************************************************************** * ItemMoniker_Reduce ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface, - IBindCtx* pbc, - DWORD dwReduceHowFar, - IMoniker** ppmkToLeft, - IMoniker** ppmkReduced) +static HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface, + IBindCtx* pbc, + DWORD dwReduceHowFar, + IMoniker** ppmkToLeft, + IMoniker** ppmkReduced) { TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); @@ -534,10 +394,10 @@ HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface, /****************************************************************************** * ItemMoniker_ComposeWith ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface, - IMoniker* pmkRight, - BOOL fOnlyIfNotGeneric, - IMoniker** ppmkComposite) +static HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface, + IMoniker* pmkRight, + BOOL fOnlyIfNotGeneric, + IMoniker** ppmkComposite) { HRESULT res=S_OK; DWORD mkSys,mkSys2; @@ -609,7 +469,7 @@ HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface, /****************************************************************************** * ItemMoniker_Enum ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) +static HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) { TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); @@ -624,7 +484,7 @@ HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker* /****************************************************************************** * ItemMoniker_IsEqual ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) +static HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) { CLSID clsid; @@ -657,7 +517,7 @@ HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker /****************************************************************************** * ItemMoniker_Hash ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) +static HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; DWORD h = 0; @@ -682,10 +542,10 @@ HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) /****************************************************************************** * ItemMoniker_IsRunning ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - IMoniker* pmkNewlyRunning) +static HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + IMoniker* pmkNewlyRunning) { IRunningObjectTable* rot; HRESULT res; @@ -701,7 +561,7 @@ HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface, return S_OK; else { if (pbc==NULL) - return E_POINTER; + return E_INVALIDARG; res=IBindCtx_GetRunningObjectTable(pbc,&rot); @@ -734,10 +594,10 @@ HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface, /****************************************************************************** * ItemMoniker_GetTimeOfLastChange ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - FILETIME* pItemTime) +static HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + FILETIME* pItemTime) { IRunningObjectTable* rot; HRESULT res; @@ -775,7 +635,7 @@ HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, /****************************************************************************** * ItemMoniker_Inverse ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) +static HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) { TRACE("(%p,%p)\n",iface,ppmk); @@ -788,7 +648,7 @@ HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) /****************************************************************************** * ItemMoniker_CommonPrefixWith ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) +static HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) { DWORD mkSys; @@ -815,7 +675,7 @@ HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOth /****************************************************************************** * ItemMoniker_RelativePathTo ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) +static HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) { TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath); @@ -830,10 +690,10 @@ HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, /****************************************************************************** * ItemMoniker_GetDisplayName ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - LPOLESTR *ppszDisplayName) +static HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + LPOLESTR *ppszDisplayName) { ItemMonikerImpl *This = (ItemMonikerImpl *)iface; @@ -862,12 +722,12 @@ HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface, /****************************************************************************** * ItemMoniker_ParseDisplayName ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - LPOLESTR pszDisplayName, - ULONG* pchEaten, - IMoniker** ppmkOut) +static HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + LPOLESTR pszDisplayName, + ULONG* pchEaten, + IMoniker** ppmkOut) { IOleItemContainer* poic=0; IParseDisplayName* ppdn=0; @@ -906,7 +766,7 @@ HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface, /****************************************************************************** * ItemMoniker_IsSystemMoniker ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) +static HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) { TRACE("(%p,%p)\n",iface,pwdMksys); @@ -921,7 +781,7 @@ HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) /******************************************************************************* * ItemMonikerIROTData_QueryInterface *******************************************************************************/ -HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) +static HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) { IMoniker *This = impl_from_IROTData(iface); @@ -934,7 +794,7 @@ HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid /*********************************************************************** * ItemMonikerIROTData_AddRef */ -ULONG WINAPI ItemMonikerROTDataImpl_AddRef(IROTData *iface) +static ULONG WINAPI ItemMonikerROTDataImpl_AddRef(IROTData *iface) { IMoniker *This = impl_from_IROTData(iface); @@ -946,7 +806,7 @@ ULONG WINAPI ItemMonikerROTDataImpl_AddRef(IROTData *iface) /*********************************************************************** * ItemMonikerIROTData_Release */ -ULONG WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface) +static ULONG WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface) { IMoniker *This = impl_from_IROTData(iface); @@ -958,10 +818,10 @@ ULONG WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface) /****************************************************************************** * ItemMonikerIROTData_GetComparisonData ******************************************************************************/ -HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface, - BYTE* pbData, - ULONG cbMax, - ULONG* pcbData) +static HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface, + BYTE* pbData, + ULONG cbMax, + ULONG* pcbData) { IMoniker *This = impl_from_IROTData(iface); ItemMonikerImpl *This1 = (ItemMonikerImpl *)This; @@ -989,6 +849,99 @@ HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface, return S_OK; } +/********************************************************************************/ +/* Virtual function table for the ItemMonikerImpl class which include IPersist,*/ +/* IPersistStream and IMoniker functions. */ +static const IMonikerVtbl VT_ItemMonikerImpl = + { + ItemMonikerImpl_QueryInterface, + ItemMonikerImpl_AddRef, + ItemMonikerImpl_Release, + ItemMonikerImpl_GetClassID, + ItemMonikerImpl_IsDirty, + ItemMonikerImpl_Load, + ItemMonikerImpl_Save, + ItemMonikerImpl_GetSizeMax, + ItemMonikerImpl_BindToObject, + ItemMonikerImpl_BindToStorage, + ItemMonikerImpl_Reduce, + ItemMonikerImpl_ComposeWith, + ItemMonikerImpl_Enum, + ItemMonikerImpl_IsEqual, + ItemMonikerImpl_Hash, + ItemMonikerImpl_IsRunning, + ItemMonikerImpl_GetTimeOfLastChange, + ItemMonikerImpl_Inverse, + ItemMonikerImpl_CommonPrefixWith, + ItemMonikerImpl_RelativePathTo, + ItemMonikerImpl_GetDisplayName, + ItemMonikerImpl_ParseDisplayName, + ItemMonikerImpl_IsSystemMoniker +}; + +/********************************************************************************/ +/* Virtual function table for the IROTData class. */ +static const IROTDataVtbl VT_ROTDataImpl = +{ + ItemMonikerROTDataImpl_QueryInterface, + ItemMonikerROTDataImpl_AddRef, + ItemMonikerROTDataImpl_Release, + ItemMonikerROTDataImpl_GetComparisonData +}; + +/****************************************************************************** + * ItemMoniker_Construct (local function) + *******************************************************************************/ +static HRESULT ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDelim,LPCOLESTR lpszItem) +{ + + int sizeStr1=lstrlenW(lpszItem), sizeStr2; + static const OLECHAR emptystr[1]; + LPCOLESTR delim; + + TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszDelim),debugstr_w(lpszItem)); + + /* Initialize the virtual function table. */ + This->lpvtbl1 = &VT_ItemMonikerImpl; + This->lpvtbl2 = &VT_ROTDataImpl; + This->ref = 0; + This->pMarshal = NULL; + + This->itemName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr1+1)); + if (!This->itemName) + return E_OUTOFMEMORY; + lstrcpyW(This->itemName,lpszItem); + + if (!lpszDelim) + FIXME("lpszDelim is NULL. Using empty string which is possibly wrong.\n"); + + delim = lpszDelim ? lpszDelim : emptystr; + + sizeStr2=lstrlenW(delim); + This->itemDelimiter=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr2+1)); + if (!This->itemDelimiter) { + HeapFree(GetProcessHeap(),0,This->itemName); + return E_OUTOFMEMORY; + } + lstrcpyW(This->itemDelimiter,delim); + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_Destroy (local function) + *******************************************************************************/ +static HRESULT ItemMonikerImpl_Destroy(ItemMonikerImpl* This) +{ + TRACE("(%p)\n",This); + + if (This->pMarshal) IUnknown_Release(This->pMarshal); + HeapFree(GetProcessHeap(),0,This->itemName); + HeapFree(GetProcessHeap(),0,This->itemDelimiter); + HeapFree(GetProcessHeap(),0,This); + + return S_OK; +} + /****************************************************************************** * CreateItemMoniker [OLE32.@] ******************************************************************************/ diff --git a/reactos/dll/win32/ole32/marshal.c b/reactos/dll/win32/ole32/marshal.c index 3703de9f2b8..54a3a87b2b6 100644 --- a/reactos/dll/win32/ole32/marshal.c +++ b/reactos/dll/win32/ole32/marshal.c @@ -553,9 +553,9 @@ static HRESULT WINAPI ProxyCliSec_SetBlanket(IClientSecurity *iface, void *pAuthInfo, DWORD Capabilities) { - FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc, - AuthzSvc, debugstr_w(pServerPrincName), AuthnLevel, ImpLevel, - pAuthInfo, Capabilities); + FIXME("(%p, %d, %d, %s, %d, %d, %p, 0x%x): stub\n", pProxy, AuthnSvc, AuthzSvc, + pServerPrincName == COLE_DEFAULT_PRINCIPAL ? "" : debugstr_w(pServerPrincName), + AuthnLevel, ImpLevel, pAuthInfo, Capabilities); return E_NOTIMPL; } @@ -1336,7 +1336,7 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v /* unref the ifstub. FIXME: only do this on success? */ if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid)) - stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, TRUE); + stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE); stub_manager_int_release(stubmgr); return hres; diff --git a/reactos/dll/win32/ole32/moniker.c b/reactos/dll/win32/ole32/moniker.c index f65fe8fe728..a7c5a11c98b 100644 --- a/reactos/dll/win32/ole32/moniker.c +++ b/reactos/dll/win32/ole32/moniker.c @@ -124,30 +124,18 @@ static BOOL start_rpcss(void) { PROCESS_INFORMATION pi; STARTUPINFOW si; - static WCHAR cmd[6]; - static const WCHAR rpcss[] = {'r','p','c','s','s',0}; + WCHAR cmd[MAX_PATH]; + static const WCHAR rpcss[] = {'\\','r','p','c','s','s','.','e','x','e',0}; BOOL rslt; TRACE("\n"); - ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFOA)); si.cb = sizeof(STARTUPINFOA); + GetSystemDirectoryW( cmd, MAX_PATH - sizeof(rpcss)/sizeof(WCHAR) ); + strcatW( cmd, rpcss ); - memcpy(cmd, rpcss, sizeof(rpcss)); - - rslt = CreateProcessW( - NULL, /* executable */ - cmd, /* command line */ - NULL, /* process security attributes */ - NULL, /* primary thread security attributes */ - FALSE, /* inherit handles */ - 0, /* creation flags */ - NULL, /* use parent's environment */ - NULL, /* use parent's current directory */ - &si, /* STARTUPINFO pointer */ - &pi /* PROCESS_INFORMATION */ - ); + rslt = CreateProcessW( cmd, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ); if (rslt) { diff --git a/reactos/dll/win32/ole32/ole2.c b/reactos/dll/win32/ole32/ole2.c index 3b87aacd6a6..6bf79fdb507 100644 --- a/reactos/dll/win32/ole32/ole2.c +++ b/reactos/dll/win32/ole32/ole2.c @@ -190,6 +190,9 @@ HRESULT WINAPI OleInitialize(LPVOID reserved) if (FAILED(hr)) return hr; + if (!COM_CurrentInfo()->ole_inits) + hr = S_OK; + /* * Then, it has to initialize the OLE specific modules. * This includes: @@ -1140,8 +1143,8 @@ HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCl return hres; } - else - return E_INVALIDARG; + + return S_OK; } diff --git a/reactos/dll/win32/ole32/ole32.spec b/reactos/dll/win32/ole32/ole32.spec index 79e7686c11d..273ddbaa846 100644 --- a/reactos/dll/win32/ole32/ole32.spec +++ b/reactos/dll/win32/ole32/ole32.spec @@ -70,7 +70,7 @@ @ stdcall CoRevokeClassObject(long) @ stdcall CoRevokeInitializeSpy(double) @ stdcall CoRevokeMallocSpy() -@ stdcall CoSetProxyBlanket(ptr long long wstr long long ptr long) +@ stdcall CoSetProxyBlanket(ptr long long ptr long long ptr long) @ stdcall CoSetState(ptr) @ stdcall CoSuspendClassObjects() @ stdcall CoSwitchCallContext(ptr ptr) diff --git a/reactos/dll/win32/ole32/ole32res.rc b/reactos/dll/win32/ole32/ole32res.rc index 0a649a62819..60887a5ec50 100644 --- a/reactos/dll/win32/ole32/ole32res.rc +++ b/reactos/dll/win32/ole32/ole32res.rc @@ -23,7 +23,10 @@ #include "winuser.h" #include "winnls.h" -#include "version.rc" +#define WINE_OLESELFREGISTER +#define WINE_FILENAME_STR "ole32.dll" + +#include /* * Everything that does not depend on language, @@ -44,12 +47,3 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL /* @makedep: drag_link.cur */ 3 CURSOR drag_link.cur - - -/* - * Everything specific to any language goes - * in one of the specific files. - * Note that you can and may override resources - * which also have a neutral version. This is to - * get localized bitmaps for example. - */ diff --git a/reactos/dll/win32/ole32/oleproxy.c b/reactos/dll/win32/ole32/oleproxy.c index 11a3ad12d8b..184aca13437 100644 --- a/reactos/dll/win32/ole32/oleproxy.c +++ b/reactos/dll/win32/ole32/oleproxy.c @@ -46,6 +46,8 @@ */ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) { + HRESULT hr; + *ppv = NULL; if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&( IsEqualIID(iid,&IID_IClassFactory) || @@ -70,5 +72,9 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) if (IsEqualGUID(rclsid, &CLSID_StdComponentCategoriesMgr)) return ComCatCF_Create(iid, ppv); - return OLE32_DllGetClassObject(rclsid, iid, ppv); + hr = OLE32_DllGetClassObject(rclsid, iid, ppv); + if (SUCCEEDED(hr)) + return hr; + + return Handler_DllGetClassObject(rclsid, iid, ppv); } diff --git a/reactos/dll/win32/ole32/regsvr.c b/reactos/dll/win32/ole32/regsvr.c index 17e78eff0fe..b124a1686c9 100644 --- a/reactos/dll/win32/ole32/regsvr.c +++ b/reactos/dll/win32/ole32/regsvr.c @@ -408,9 +408,6 @@ static GUID const CLSID_StdOleLink = { static GUID const CLSID_PackagerMoniker = { 0x00000308, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; -static GUID const CLSID_PSFactoryBuffer_actxprxy = { - 0xB8DA6310, 0xE19B, 0x11D0, {0x93,0x3C,0x00,0xA0,0xC9,0x0D,0xCA,0xA9} }; - extern GUID const CLSID_Picture_Metafile; extern GUID const CLSID_Picture_Dib; @@ -510,42 +507,35 @@ static struct regsvr_coclass const coclass_list[] = { * interface list */ -#define INTERFACE_ENTRY(interface, base, clsid32) { &IID_##interface, #interface, base, sizeof(interface##Vtbl)/sizeof(void*), NULL, clsid32 } -#define BAS_INTERFACE_ENTRY(interface, base) INTERFACE_ENTRY(interface, &IID_##base, NULL) -#define ACTX_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer_actxprxy) -#define LCL_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, NULL) +#define INTERFACE_ENTRY(interface, base) { &IID_##interface, #interface, base, sizeof(interface##Vtbl)/sizeof(void*), NULL, NULL } static const struct regsvr_interface interface_list[] = { - LCL_INTERFACE_ENTRY(IUnknown), - LCL_INTERFACE_ENTRY(IMalloc), - LCL_INTERFACE_ENTRY(IMarshal), - BAS_INTERFACE_ENTRY(IMoniker, IPersistStream), - LCL_INTERFACE_ENTRY(IMessageFilter), - LCL_INTERFACE_ENTRY(IStdMarshalInfo), - LCL_INTERFACE_ENTRY(IExternalConnection), - LCL_INTERFACE_ENTRY(IMallocSpy), - LCL_INTERFACE_ENTRY(IMultiQI), - BAS_INTERFACE_ENTRY(IPersistStream, IPersist), - BAS_INTERFACE_ENTRY(IPersistStorage, IPersist), - BAS_INTERFACE_ENTRY(IPersistFile, IPersist), - LCL_INTERFACE_ENTRY(IDataAdviseHolder), - LCL_INTERFACE_ENTRY(IOleAdviseHolder), - BAS_INTERFACE_ENTRY(IOleInPlaceObject, IOleWindow), - BAS_INTERFACE_ENTRY(IOleInPlaceUIWindow, IOleWindow), - BAS_INTERFACE_ENTRY(IOleInPlaceActiveObject, IOleWindow), - BAS_INTERFACE_ENTRY(IOleInPlaceSite, IOleWindow), - BAS_INTERFACE_ENTRY(IOleContainer, IParseDisplayName), - BAS_INTERFACE_ENTRY(IOleItemContainer, IOleContainer), - LCL_INTERFACE_ENTRY(IDropSource), - BAS_INTERFACE_ENTRY(IAdviseSink2, IAdviseSink), - BAS_INTERFACE_ENTRY(IViewObject2, IViewObject), - BAS_INTERFACE_ENTRY(IOleCache2, IOleCache), - LCL_INTERFACE_ENTRY(IClientSecurity), - LCL_INTERFACE_ENTRY(IServerSecurity), - ACTX_INTERFACE_ENTRY(IEnumGUID), - ACTX_INTERFACE_ENTRY(IEnumCATEGORYINFO), - ACTX_INTERFACE_ENTRY(ICatRegister), - ACTX_INTERFACE_ENTRY(ICatInformation), + INTERFACE_ENTRY( IUnknown, NULL ), + INTERFACE_ENTRY( IMalloc, NULL ), + INTERFACE_ENTRY( IMarshal, NULL ), + INTERFACE_ENTRY( IMoniker, &IID_IPersistStream ), + INTERFACE_ENTRY( IMessageFilter, NULL ), + INTERFACE_ENTRY( IStdMarshalInfo, NULL ), + INTERFACE_ENTRY( IExternalConnection, NULL ), + INTERFACE_ENTRY( IMallocSpy, NULL ), + INTERFACE_ENTRY( IMultiQI, NULL ), + INTERFACE_ENTRY( IPersistStream, &IID_IPersist ), + INTERFACE_ENTRY( IPersistStorage, &IID_IPersist ), + INTERFACE_ENTRY( IPersistFile, &IID_IPersist ), + INTERFACE_ENTRY( IDataAdviseHolder, NULL ), + INTERFACE_ENTRY( IOleAdviseHolder, NULL ), + INTERFACE_ENTRY( IOleInPlaceObject, &IID_IOleWindow ), + INTERFACE_ENTRY( IOleInPlaceUIWindow, &IID_IOleWindow ), + INTERFACE_ENTRY( IOleInPlaceActiveObject, &IID_IOleWindow ), + INTERFACE_ENTRY( IOleInPlaceSite, &IID_IOleWindow ), + INTERFACE_ENTRY( IOleContainer, &IID_IParseDisplayName ), + INTERFACE_ENTRY( IOleItemContainer, &IID_IOleContainer ), + INTERFACE_ENTRY( IDropSource, NULL ), + INTERFACE_ENTRY( IAdviseSink2, &IID_IAdviseSink ), + INTERFACE_ENTRY( IViewObject2, &IID_IViewObject ), + INTERFACE_ENTRY( IOleCache2, &IID_IOleCache ), + INTERFACE_ENTRY( IClientSecurity, NULL ), + INTERFACE_ENTRY( IServerSecurity, NULL ), { NULL } /* list terminator */ }; diff --git a/reactos/dll/win32/ole32/rpc.c b/reactos/dll/win32/ole32/rpc.c index 9a344653248..0daa4ab815d 100644 --- a/reactos/dll/win32/ole32/rpc.c +++ b/reactos/dll/win32/ole32/rpc.c @@ -1358,7 +1358,7 @@ void RPC_ExecuteCall(struct dispatch_params *params) handlecall = IMessageFilter_HandleInComingCall(COM_CurrentApt()->filter, calltype, - (HTASK)GetCurrentProcessId(), + UlongToHandle(GetCurrentProcessId()), 0 /* FIXME */, &interface_info); TRACE("IMessageFilter_HandleInComingCall returned %d\n", handlecall); diff --git a/reactos/dll/win32/ole32/stg_prop.c b/reactos/dll/win32/ole32/stg_prop.c index 1c77c9e2d3c..52153a20d44 100644 --- a/reactos/dll/win32/ole32/stg_prop.c +++ b/reactos/dll/win32/ole32/stg_prop.c @@ -236,7 +236,7 @@ static PROPVARIANT *PropertyStorage_FindProperty(PropertyStorage_impl *This, { PROPVARIANT *ret = NULL; - dictionary_find(This->propid_to_prop, (void *)propid, (void **)&ret); + dictionary_find(This->propid_to_prop, UlongToPtr(propid), (void **)&ret); TRACE("returning %p\n", ret); return ret; } @@ -246,14 +246,14 @@ static PROPVARIANT *PropertyStorage_FindPropertyByName( PropertyStorage_impl *This, LPCWSTR name) { PROPVARIANT *ret = NULL; - PROPID propid; + void *propid; if (!name) return NULL; if (This->codePage == CP_UNICODE) { - if (dictionary_find(This->name_to_propid, name, (void **)&propid)) - ret = PropertyStorage_FindProperty(This, propid); + if (dictionary_find(This->name_to_propid, name, &propid)) + ret = PropertyStorage_FindProperty(This, PtrToUlong(propid)); } else { @@ -263,9 +263,8 @@ static PROPVARIANT *PropertyStorage_FindPropertyByName( if (SUCCEEDED(hr)) { - if (dictionary_find(This->name_to_propid, ansiName, - (void **)&propid)) - ret = PropertyStorage_FindProperty(This, propid); + if (dictionary_find(This->name_to_propid, ansiName, &propid)) + ret = PropertyStorage_FindProperty(This, PtrToUlong(propid)); CoTaskMemFree(ansiName); } } @@ -278,7 +277,7 @@ static LPWSTR PropertyStorage_FindPropertyNameById(PropertyStorage_impl *This, { LPWSTR ret = NULL; - dictionary_find(This->propid_to_name, (void *)propid, (void **)&ret); + dictionary_find(This->propid_to_name, UlongToPtr(propid), (void **)&ret); TRACE("returning %p\n", ret); return ret; } @@ -490,7 +489,7 @@ static HRESULT PropertyStorage_StorePropWithId(PropertyStorage_impl *This, lcid); if (SUCCEEDED(hr)) { - dictionary_insert(This->propid_to_prop, (void *)propid, prop); + dictionary_insert(This->propid_to_prop, UlongToPtr(propid), prop); if (propid > This->highestProp) This->highestProp = propid; } @@ -534,8 +533,8 @@ static HRESULT PropertyStorage_StoreNameWithId(PropertyStorage_impl *This, TRACE("Adding prop name %s, propid %d\n", This->codePage == CP_UNICODE ? debugstr_w((LPCWSTR)name) : debugstr_a(name), id); - dictionary_insert(This->name_to_propid, name, (void *)id); - dictionary_insert(This->propid_to_name, (void *)id, name); + dictionary_insert(This->name_to_propid, name, UlongToPtr(id)); + dictionary_insert(This->propid_to_name, UlongToPtr(id), name); } return hr; } @@ -666,18 +665,16 @@ static HRESULT WINAPI IPropertyStorage_fnDeleteMultiple( { if (rgpspec[i].ulKind == PRSPEC_LPWSTR) { - PROPID propid; + void *propid; - if (dictionary_find(This->name_to_propid, - (void *)rgpspec[i].u.lpwstr, (void **)&propid)) - dictionary_remove(This->propid_to_prop, (void *)propid); + if (dictionary_find(This->name_to_propid, rgpspec[i].u.lpwstr, &propid)) + dictionary_remove(This->propid_to_prop, propid); } else { if (rgpspec[i].u.propid >= PID_FIRST_USABLE && rgpspec[i].u.propid < PID_MIN_READONLY) - dictionary_remove(This->propid_to_prop, - (void *)rgpspec[i].u.propid); + dictionary_remove(This->propid_to_prop, UlongToPtr(rgpspec[i].u.propid)); else hr = STG_E_INVALIDPARAMETER; } @@ -787,10 +784,9 @@ static HRESULT WINAPI IPropertyStorage_fnDeletePropertyNames( { LPWSTR name = NULL; - if (dictionary_find(This->propid_to_name, (void *)rgpropid[i], - (void **)&name)) + if (dictionary_find(This->propid_to_name, UlongToPtr(rgpropid[i]), (void **)&name)) { - dictionary_remove(This->propid_to_name, (void *)rgpropid[i]); + dictionary_remove(This->propid_to_name, UlongToPtr(rgpropid[i])); dictionary_remove(This->name_to_propid, name); } } @@ -955,8 +951,8 @@ static void PropertyStorage_PropNameDestroy(void *k, void *d, void *extra) static int PropertyStorage_PropCompare(const void *a, const void *b, void *extra) { - TRACE("(%d, %d)\n", (PROPID)a, (PROPID)b); - return (PROPID)a - (PROPID)b; + TRACE("(%d, %d)\n", PtrToUlong(a), PtrToUlong(b)); + return PtrToUlong(a) - PtrToUlong(b); } static void PropertyStorage_PropertyDestroy(void *k, void *d, void *extra) @@ -1143,8 +1139,8 @@ static HRESULT PropertyStorage_ReadProperty(PropertyStorage_impl *This, prop->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA)); prop->u.pclipdata->cbSize = len; prop->u.pclipdata->ulClipFmt = tag; - prop->u.pclipdata->pClipData = CoTaskMemAlloc(len); - memcpy(prop->u.pclipdata->pClipData, data+8, len); + prop->u.pclipdata->pClipData = CoTaskMemAlloc(len - sizeof(prop->u.pclipdata->ulClipFmt)); + memcpy(prop->u.pclipdata->pClipData, data+8, len - sizeof(prop->u.pclipdata->ulClipFmt)); } else hr = STG_E_INVALIDPARAMETER; @@ -1406,6 +1402,7 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) idOffset->propid, &prop, This->codePage); } } + PropVariantClear(&prop); } } } @@ -1512,7 +1509,7 @@ static BOOL PropertyStorage_DictionaryWriter(const void *key, assert(key); assert(closure); - StorageUtl_WriteDWord((LPBYTE)&propid, 0, (DWORD)value); + StorageUtl_WriteDWord((LPBYTE)&propid, 0, PtrToUlong(value)); c->hr = IStream_Write(This->stm, &propid, sizeof(propid), &count); if (FAILED(c->hr)) goto end; @@ -1735,7 +1732,8 @@ static HRESULT PropertyStorage_WritePropertyToStream(PropertyStorage_impl *This, hr = IStream_Write(This->stm, cf_hdr, sizeof(cf_hdr), &count); if (FAILED(hr)) goto end; - hr = IStream_Write(This->stm, &var->u.pclipdata->pClipData, len, &count); + hr = IStream_Write(This->stm, var->u.pclipdata->pClipData, + len - sizeof(var->u.pclipdata->ulClipFmt), &count); if (FAILED(hr)) goto end; bytesWritten = count + sizeof cf_hdr; @@ -1779,7 +1777,7 @@ static BOOL PropertyStorage_PropertiesWriter(const void *key, const void *value, assert(extra); assert(closure); c->hr = PropertyStorage_WritePropertyToStream(This, c->propNum++, - (DWORD)key, value, c->sectionOffset); + PtrToUlong(key), value, c->sectionOffset); return SUCCEEDED(c->hr); } @@ -2396,7 +2394,7 @@ static HRESULT WINAPI IEnumSTATPROPSTG_fnClone( static BOOL prop_enum_stat(const void *k, const void *v, void *extra, void *arg) { enumx_impl *enumx = arg; - PROPID propid = (PROPID) k; + PROPID propid = PtrToUlong(k); const PROPVARIANT *prop = v; STATPROPSTG stat; diff --git a/reactos/dll/win32/ole32/stg_stream.c b/reactos/dll/win32/ole32/stg_stream.c index 79492a406c0..bfecbc72bd1 100644 --- a/reactos/dll/win32/ole32/stg_stream.c +++ b/reactos/dll/win32/ole32/stg_stream.c @@ -74,21 +74,6 @@ static void StgStreamImpl_Destroy(StgStreamImpl* This) This->parentStorage = 0; - /* - * Make sure we clean-up the block chain stream objects that we were using. - */ - if (This->bigBlockChain != 0) - { - BlockChainStream_Destroy(This->bigBlockChain); - This->bigBlockChain = 0; - } - - if (This->smallBlockChain != 0) - { - SmallBlockChainStream_Destroy(This->smallBlockChain); - This->smallBlockChain = 0; - } - /* * Finally, free the memory used-up by the class. */ @@ -179,73 +164,6 @@ static ULONG WINAPI StgStreamImpl_Release( return ref; } -/*** - * This method will open the block chain pointed by the property - * that describes the stream. - * If the stream's size is null, no chain is opened. - */ -static void StgStreamImpl_OpenBlockChain( - StgStreamImpl* This) -{ - StgProperty curProperty; - BOOL readSuccessful; - - /* - * Make sure no old object is left over. - */ - if (This->smallBlockChain != 0) - { - SmallBlockChainStream_Destroy(This->smallBlockChain); - This->smallBlockChain = 0; - } - - if (This->bigBlockChain != 0) - { - BlockChainStream_Destroy(This->bigBlockChain); - This->bigBlockChain = 0; - } - - /* - * Read the information from the property. - */ - readSuccessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - - if (readSuccessful) - { - This->streamSize = curProperty.size; - - /* - * This code supports only streams that are <32 bits in size. - */ - assert(This->streamSize.u.HighPart == 0); - - if(curProperty.startingBlock == BLOCK_END_OF_CHAIN) - { - assert( (This->streamSize.u.HighPart == 0) && (This->streamSize.u.LowPart == 0) ); - } - else - { - if ( (This->streamSize.u.HighPart == 0) && - (This->streamSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) ) - { - This->smallBlockChain = SmallBlockChainStream_Construct( - This->parentStorage->ancestorStorage, - NULL, - This->ownerProperty); - } - else - { - This->bigBlockChain = BlockChainStream_Construct( - This->parentStorage->ancestorStorage, - NULL, - This->ownerProperty); - } - } - } -} - /*** * This method is part of the ISequentialStream interface. * @@ -264,7 +182,6 @@ static HRESULT WINAPI StgStreamImpl_Read( StgStreamImpl* const This=(StgStreamImpl*)iface; ULONG bytesReadBuffer; - ULONG bytesToReadFromBuffer; HRESULT res; TRACE("(%p, %p, %d, %p)\n", @@ -283,60 +200,21 @@ static HRESULT WINAPI StgStreamImpl_Read( if (pcbRead==0) pcbRead = &bytesReadBuffer; - /* - * Using the known size of the stream, calculate the number of bytes - * to read from the block chain - */ - bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb); - - /* - * Depending on the type of chain that was opened when the stream was constructed, - * we delegate the work to the method that reads the block chains. - */ - if (This->smallBlockChain!=0) - { - res = SmallBlockChainStream_ReadAt(This->smallBlockChain, - This->currentPosition, - bytesToReadFromBuffer, - pv, - pcbRead); - - } - else if (This->bigBlockChain!=0) - { - res = BlockChainStream_ReadAt(This->bigBlockChain, - This->currentPosition, - bytesToReadFromBuffer, - pv, - pcbRead); - } - else - { - /* - * Small and big block chains are both NULL. This case will happen - * when a stream starts with BLOCK_END_OF_CHAIN and has size zero. - */ - - *pcbRead = 0; - res = S_OK; - goto end; - } + res = StorageBaseImpl_StreamReadAt(This->parentStorage, + This->dirEntry, + This->currentPosition, + cb, + pv, + pcbRead); if (SUCCEEDED(res)) { - /* - * We should always be able to read the proper amount of data from the - * chain. - */ - assert(bytesToReadFromBuffer == *pcbRead); - - /* - * Advance the pointer for the number of positions read. - */ - This->currentPosition.u.LowPart += *pcbRead; + /* + * Advance the pointer for the number of positions read. + */ + This->currentPosition.u.LowPart += *pcbRead; } -end: TRACE("<-- %08x\n", res); return res; } @@ -359,7 +237,6 @@ static HRESULT WINAPI StgStreamImpl_Write( { StgStreamImpl* const This=(StgStreamImpl*)iface; - ULARGE_INTEGER newSize; ULONG bytesWritten = 0; HRESULT res; @@ -405,51 +282,13 @@ static HRESULT WINAPI StgStreamImpl_Write( TRACE("<-- S_OK, written 0\n"); return S_OK; } - else - { - newSize.u.HighPart = 0; - newSize.u.LowPart = This->currentPosition.u.LowPart + cb; - } - /* - * Verify if we need to grow the stream - */ - if (newSize.u.LowPart > This->streamSize.u.LowPart) - { - /* grow stream */ - res = IStream_SetSize(iface, newSize); - if (FAILED(res)) - return res; - } - - /* - * Depending on the type of chain that was opened when the stream was constructed, - * we delegate the work to the method that readwrites to the block chains. - */ - if (This->smallBlockChain!=0) - { - res = SmallBlockChainStream_WriteAt(This->smallBlockChain, - This->currentPosition, - cb, - pv, - pcbWritten); - - } - else if (This->bigBlockChain!=0) - { - res = BlockChainStream_WriteAt(This->bigBlockChain, - This->currentPosition, - cb, - pv, - pcbWritten); - } - else - { - /* this should never happen because the IStream_SetSize call above will - * make sure a big or small block chain is created */ - assert(FALSE); - res = 0; - } + res = StorageBaseImpl_StreamWriteAt(This->parentStorage, + This->dirEntry, + This->currentPosition, + cb, + pv, + pcbWritten); /* * Advance the position pointer for the number of positions written. @@ -477,6 +316,8 @@ static HRESULT WINAPI StgStreamImpl_Seek( StgStreamImpl* const This=(StgStreamImpl*)iface; ULARGE_INTEGER newPosition; + DirEntry currentEntry; + HRESULT hr; TRACE("(%p, %d, %d, %p)\n", iface, dlibMove.u.LowPart, dwOrigin, plibNewPosition); @@ -515,7 +356,9 @@ static HRESULT WINAPI StgStreamImpl_Seek( *plibNewPosition = This->currentPosition; break; case STREAM_SEEK_END: - *plibNewPosition = This->streamSize; + hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, This->dirEntry, ¤tEntry); + if (FAILED(hr)) return hr; + *plibNewPosition = currentEntry.size; break; default: WARN("invalid dwOrigin %d\n", dwOrigin); @@ -545,8 +388,7 @@ static HRESULT WINAPI StgStreamImpl_SetSize( { StgStreamImpl* const This=(StgStreamImpl*)iface; - StgProperty curProperty; - BOOL Success; + HRESULT hr; TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart); @@ -574,99 +416,8 @@ static HRESULT WINAPI StgStreamImpl_SetSize( return STG_E_ACCESSDENIED; } - /* In simple mode keep the stream size above the small block limit */ - if (This->parentStorage->ancestorStorage->base.openFlags & STGM_SIMPLE) - libNewSize.u.LowPart = max(libNewSize.u.LowPart, LIMIT_TO_USE_SMALL_BLOCK); - - if (This->streamSize.u.LowPart == libNewSize.u.LowPart) - return S_OK; - - /* - * This will happen if we're creating a stream - */ - if ((This->smallBlockChain == 0) && (This->bigBlockChain == 0)) - { - if (libNewSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) - { - This->smallBlockChain = SmallBlockChainStream_Construct( - This->parentStorage->ancestorStorage, - NULL, - This->ownerProperty); - } - else - { - This->bigBlockChain = BlockChainStream_Construct( - This->parentStorage->ancestorStorage, - NULL, - This->ownerProperty); - } - } - - /* - * Read this stream's property to see if it's small blocks or big blocks - */ - Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - /* - * Determine if we have to switch from small to big blocks or vice versa - */ - if ( (This->smallBlockChain!=0) && - (curProperty.size.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) ) - { - if (libNewSize.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) - { - /* - * Transform the small block chain into a big block chain - */ - This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks( - This->parentStorage->ancestorStorage, - &This->smallBlockChain); - } - } - else if ( (This->bigBlockChain!=0) && - (curProperty.size.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) ) - { - if (libNewSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) - { - /* - * Transform the big block chain into a small block chain - */ - This->smallBlockChain = Storage32Impl_BigBlocksToSmallBlocks( - This->parentStorage->ancestorStorage, - &This->bigBlockChain); - } - } - - if (This->smallBlockChain!=0) - { - Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize); - } - else - { - Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize); - } - - /* - * Write the new information about this stream to the property - */ - Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - - curProperty.size.u.HighPart = libNewSize.u.HighPart; - curProperty.size.u.LowPart = libNewSize.u.LowPart; - - if (Success) - { - StorageImpl_WriteProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - } - - This->streamSize = libNewSize; - - return S_OK; + hr = StorageBaseImpl_StreamSetSize(This->parentStorage, This->dirEntry, libNewSize); + return hr; } /*** @@ -834,8 +585,8 @@ static HRESULT WINAPI StgStreamImpl_Stat( { StgStreamImpl* const This=(StgStreamImpl*)iface; - StgProperty curProperty; - BOOL readSuccessful; + DirEntry currentEntry; + HRESULT hr; TRACE("%p %p %d\n", This, pstatstg, grfStatFlag); @@ -850,31 +601,30 @@ static HRESULT WINAPI StgStreamImpl_Stat( } /* - * Read the information from the property. + * Read the information from the directory entry. */ - readSuccessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); + hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, + This->dirEntry, + ¤tEntry); - if (readSuccessful) + if (SUCCEEDED(hr)) { - StorageImpl *root = This->parentStorage->ancestorStorage; - - StorageUtl_CopyPropertyToSTATSTG(pstatstg, - &curProperty, + StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage, + pstatstg, + ¤tEntry, grfStatFlag); pstatstg->grfMode = This->grfMode; /* In simple create mode cbSize is the current pos */ - if((root->base.openFlags & STGM_SIMPLE) && root->create) + if((This->parentStorage->openFlags & STGM_SIMPLE) && This->parentStorage->create) pstatstg->cbSize = This->currentPosition; return S_OK; } - WARN("failed to read properties\n"); - return E_FAIL; + WARN("failed to read entry\n"); + return hr; } /*** @@ -910,7 +660,7 @@ static HRESULT WINAPI StgStreamImpl_Clone( if ( ppstm == 0 ) return STG_E_INVALIDPOINTER; - new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->ownerProperty); + new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->dirEntry); if (!new_stream) return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */ @@ -957,12 +707,12 @@ static const IStreamVtbl StgStreamImpl_Vtbl = * * Params: * parentStorage - Pointer to the storage that contains the stream to open - * ownerProperty - Index of the property that points to this stream. + * dirEntry - Index of the directory entry that points to this stream. */ StgStreamImpl* StgStreamImpl_Construct( StorageBaseImpl* parentStorage, DWORD grfMode, - ULONG ownerProperty) + DirRef dirEntry) { StgStreamImpl* newStream; @@ -991,7 +741,7 @@ StgStreamImpl* StgStreamImpl_Construct( */ newStream->grfMode = grfMode; - newStream->ownerProperty = ownerProperty; + newStream->dirEntry = dirEntry; /* * Start the stream at the beginning. @@ -999,20 +749,6 @@ StgStreamImpl* StgStreamImpl_Construct( newStream->currentPosition.u.HighPart = 0; newStream->currentPosition.u.LowPart = 0; - /* - * Initialize the rest of the data. - */ - newStream->streamSize.u.HighPart = 0; - newStream->streamSize.u.LowPart = 0; - newStream->bigBlockChain = 0; - newStream->smallBlockChain = 0; - - /* - * Read the size from the property and determine if the blocks forming - * this stream are large or small. - */ - StgStreamImpl_OpenBlockChain(newStream); - /* add us to the storage's list of active streams */ StorageBaseImpl_AddStream(parentStorage, newStream); } diff --git a/reactos/dll/win32/ole32/storage32.c b/reactos/dll/win32/ole32/storage32.c index 6e3e1e1d978..837365bdb9d 100644 --- a/reactos/dll/win32/ole32/storage32.c +++ b/reactos/dll/win32/ole32/storage32.c @@ -65,7 +65,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(storage); static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1}; static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d}; -static const char rootPropertyName[] = "Root Entry"; +static const char rootEntryName[] = "Root Entry"; /**************************************************************************** * Storage32InternalImpl definitions. @@ -77,16 +77,21 @@ static const char rootPropertyName[] = "Root Entry"; struct StorageInternalImpl { struct StorageBaseImpl base; + /* - * There is no specific data for this class. + * Entry in the parent's stream tracking list */ + struct list ParentListEntry; + + StorageBaseImpl *parentStorage; }; typedef struct StorageInternalImpl StorageInternalImpl; /* Method definitions for the Storage32InternalImpl class. */ -static StorageInternalImpl* StorageInternalImpl_Construct(StorageImpl* ancestorStorage, - DWORD openFlags, ULONG rootTropertyIndex); +static StorageInternalImpl* StorageInternalImpl_Construct(StorageBaseImpl* parentStorage, + DWORD openFlags, DirRef storageDirEntry); static void StorageImpl_Destroy(StorageBaseImpl* iface); +static void StorageImpl_Invalidate(StorageBaseImpl* iface); static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer); static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, const void* buffer); static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock); @@ -110,6 +115,30 @@ static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This, static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl* This, ULONG blockIndex, ULONG offset, DWORD* value); +static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry); +static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry); + +/**************************************************************************** + * Transacted storage object that reads/writes a snapshot file. + */ +typedef struct TransactedSnapshotImpl +{ + struct StorageBaseImpl base; + + /* + * Changes are temporarily saved to the snapshot. + */ + StorageBaseImpl *snapshot; + + /* + * Changes are committed to the transacted parent. + */ + StorageBaseImpl *transactedParent; +} TransactedSnapshotImpl; + +/* Generic function to create a transacted wrapper for a direct storage object. */ +static HRESULT Storage_ConstructTransacted(StorageBaseImpl* parent, StorageBaseImpl** result); + /* OLESTREAM memory structure to use for Get and Put Routines */ /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ typedef struct @@ -159,45 +188,47 @@ typedef struct /*********************************************************************** * Forward declaration of internal functions used by the method DestroyElement */ -static HRESULT deleteStorageProperty( - StorageImpl *parentStorage, - ULONG foundPropertyIndexToDelete, - StgProperty propertyToDelete); +static HRESULT deleteStorageContents( + StorageBaseImpl *parentStorage, + DirRef indexToDelete, + DirEntry entryDataToDelete); -static HRESULT deleteStreamProperty( - StorageImpl *parentStorage, - ULONG foundPropertyIndexToDelete, - StgProperty propertyToDelete); +static HRESULT deleteStreamContents( + StorageBaseImpl *parentStorage, + DirRef indexToDelete, + DirEntry entryDataToDelete); -static HRESULT findPlaceholder( - StorageImpl *storage, - ULONG propertyIndexToStore, - ULONG storagePropertyIndex, - INT typeOfRelation); - -static HRESULT adjustPropertyChain( - StorageImpl *This, - StgProperty propertyToDelete, - StgProperty parentProperty, - ULONG parentPropertyId, - INT typeOfRelation); +static HRESULT removeFromTree( + StorageBaseImpl *This, + DirRef parentStorageIndex, + DirRef deletedIndex); /*********************************************************************** - * Declaration of the functions used to manipulate StgProperty + * Declaration of the functions used to manipulate DirEntry */ -static ULONG getFreeProperty( - StorageImpl *storage); +static HRESULT insertIntoTree( + StorageBaseImpl *This, + DirRef parentStorageIndex, + DirRef newEntryIndex); -static void updatePropertyChain( - StorageImpl *storage, - ULONG newPropertyIndex, - StgProperty newProperty); +static LONG entryNameCmp( + const OLECHAR *name1, + const OLECHAR *name2); -static LONG propertyNameCmp( - const OLECHAR *newProperty, - const OLECHAR *currentProperty); +static DirRef findElement( + StorageBaseImpl *storage, + DirRef storageEntry, + const OLECHAR *name, + DirEntry *data); +static HRESULT findTreeParent( + StorageBaseImpl *storage, + DirRef storageEntry, + const OLECHAR *childName, + DirEntry *parentData, + DirRef *parentEntry, + ULONG *relation); /*********************************************************************** * Declaration of miscellaneous functions... @@ -224,30 +255,15 @@ struct IEnumSTATSTGImpl * since we want to cast this in an IEnumSTATSTG pointer */ LONG ref; /* Reference count */ - StorageImpl* parentStorage; /* Reference to the parent storage */ - ULONG firstPropertyNode; /* Index of the root of the storage to enumerate */ + StorageBaseImpl* parentStorage; /* Reference to the parent storage */ + DirRef storageDirEntry; /* Directory entry of the storage to enumerate */ - /* - * The current implementation of the IEnumSTATSTGImpl class uses a stack - * to walk the property sets to get the content of a storage. This stack - * is implemented by the following 3 data members - */ - ULONG stackSize; - ULONG stackMaxSize; - ULONG* stackToVisit; - -#define ENUMSTATSGT_SIZE_INCREMENT 10 + WCHAR name[DIRENTRY_NAME_MAX_LEN]; /* The most recent name visited */ }; -static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageImpl* This, ULONG firstPropertyNode); +static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageBaseImpl* This, DirRef storageDirEntry); static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This); -static void IEnumSTATSTGImpl_PushSearchNode(IEnumSTATSTGImpl* This, ULONG nodeToPush); -static ULONG IEnumSTATSTGImpl_PopSearchNode(IEnumSTATSTGImpl* This, BOOL remove); -static ULONG IEnumSTATSTGImpl_FindProperty(IEnumSTATSTGImpl* This, const OLECHAR* lpszPropName, - StgProperty* buffer); -static INT IEnumSTATSTGImpl_FindParentProperty(IEnumSTATSTGImpl *This, ULONG childProperty, - StgProperty *currentProperty, ULONG *propertyId); /************************************************************************ ** Block Functions @@ -298,20 +314,12 @@ static HRESULT WINAPI StorageBaseImpl_QueryInterface( void** ppvObject) { StorageBaseImpl *This = (StorageBaseImpl *)iface; - /* - * Perform a sanity check on the parameters. - */ + if ( (This==0) || (ppvObject==0) ) return E_INVALIDARG; - /* - * Initialize the return parameter. - */ *ppvObject = 0; - /* - * Compare the riid with the interface IDs implemented by this object. - */ if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IStorage, riid)) { @@ -322,16 +330,9 @@ static HRESULT WINAPI StorageBaseImpl_QueryInterface( *ppvObject = &This->pssVtbl; } - /* - * Check that we obtained an interface. - */ if ((*ppvObject)==0) return E_NOINTERFACE; - /* - * Query Interface always increases the reference count by one when it is - * successful - */ IStorage_AddRef(iface); return S_OK; @@ -368,16 +369,11 @@ static ULONG WINAPI StorageBaseImpl_Release( IStorage* iface) { StorageBaseImpl *This = (StorageBaseImpl *)iface; - /* - * Decrease the reference count on this object. - */ + ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ReleaseRef to %d\n", This, ref); - /* - * If the reference count goes down to 0, perform suicide. - */ if (ref == 0) { /* @@ -385,7 +381,7 @@ static ULONG WINAPI StorageBaseImpl_Release( * destructor of the appropriate derived class. To do this, we are * using virtual functions to implement the destructor. */ - This->v_destructor(This); + StorageBaseImpl_Destroy(This); } return ref; @@ -407,32 +403,22 @@ static HRESULT WINAPI StorageBaseImpl_OpenStream( IStream** ppstm) /* [out] */ { StorageBaseImpl *This = (StorageBaseImpl *)iface; - IEnumSTATSTGImpl* propertyEnumeration; StgStreamImpl* newStream; - StgProperty currentProperty; - ULONG foundPropertyIndex; + DirEntry currentEntry; + DirRef streamEntryRef; HRESULT res = STG_E_UNKNOWN; TRACE("(%p, %s, %p, %x, %d, %p)\n", iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm); - /* - * Perform a sanity check on the parameters. - */ if ( (pwcsName==NULL) || (ppstm==0) ) { res = E_INVALIDARG; goto end; } - /* - * Initialize the out parameter - */ *ppstm = NULL; - /* - * Validate the STGM flags - */ if ( FAILED( validateSTGM(grfMode) ) || STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) { @@ -449,55 +435,53 @@ static HRESULT WINAPI StorageBaseImpl_OpenStream( goto end; } + if (This->reverted) + { + res = STG_E_REVERTED; + goto end; + } + /* * Check that we're compatible with the parent's storage mode, but * only if we are not in transacted mode */ - if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) { + if(!(This->openFlags & STGM_TRANSACTED)) { if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) ) { - res = STG_E_ACCESSDENIED; + res = STG_E_INVALIDFLAG; goto end; } } /* - * Create a property enumeration to search the properties + * Search for the element with the given name */ - propertyEnumeration = IEnumSTATSTGImpl_Construct( - This->ancestorStorage, - This->rootPropertySetIndex); - - /* - * Search the enumeration for the property with the given name - */ - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty( - propertyEnumeration, + streamEntryRef = findElement( + This, + This->storageDirEntry, pwcsName, - ¤tProperty); - - /* - * Delete the property enumeration since we don't need it anymore - */ - IEnumSTATSTGImpl_Destroy(propertyEnumeration); + ¤tEntry); /* * If it was found, construct the stream object and return a pointer to it. */ - if ( (foundPropertyIndex!=PROPERTY_NULL) && - (currentProperty.propertyType==PROPTYPE_STREAM) ) + if ( (streamEntryRef!=DIRENTRY_NULL) && + (currentEntry.stgType==STGTY_STREAM) ) { - newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex); + if (StorageBaseImpl_IsStreamOpen(This, streamEntryRef)) + { + /* A single stream cannot be opened a second time. */ + res = STG_E_ACCESSDENIED; + goto end; + } + + newStream = StgStreamImpl_Construct(This, grfMode, streamEntryRef); if (newStream!=0) { newStream->grfMode = grfMode; *ppstm = (IStream*)newStream; - /* - * Since we are returning a pointer to the interface, we have to - * nail down the reference. - */ IStream_AddRef(*ppstm); res = S_OK; @@ -534,25 +518,28 @@ static HRESULT WINAPI StorageBaseImpl_OpenStorage( IStorage** ppstg) /* [out] */ { StorageBaseImpl *This = (StorageBaseImpl *)iface; - StorageInternalImpl* newStorage; - IEnumSTATSTGImpl* propertyEnumeration; - StgProperty currentProperty; - ULONG foundPropertyIndex; + StorageInternalImpl* newStorage; + StorageBaseImpl* newTransactedStorage; + DirEntry currentEntry; + DirRef storageEntryRef; HRESULT res = STG_E_UNKNOWN; TRACE("(%p, %s, %p, %x, %p, %d, %p)\n", iface, debugstr_w(pwcsName), pstgPriority, grfMode, snbExclude, reserved, ppstg); - /* - * Perform a sanity check on the parameters. - */ if ( (This==0) || (pwcsName==NULL) || (ppstg==0) ) { res = E_INVALIDARG; goto end; } + if (This->openFlags & STGM_SIMPLE) + { + res = STG_E_INVALIDFUNCTION; + goto end; + } + /* as documented */ if (snbExclude != NULL) { @@ -560,9 +547,6 @@ static HRESULT WINAPI StorageBaseImpl_OpenStorage( goto end; } - /* - * Validate the STGM flags - */ if ( FAILED( validateSTGM(grfMode) )) { res = STG_E_INVALIDFLAG; @@ -580,11 +564,14 @@ static HRESULT WINAPI StorageBaseImpl_OpenStorage( goto end; } + if (This->reverted) + return STG_E_REVERTED; + /* * Check that we're compatible with the parent's storage mode, * but only if we are not transacted */ - if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) { + if(!(This->openFlags & STGM_TRANSACTED)) { if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) ) { res = STG_E_ACCESSDENIED; @@ -592,54 +579,49 @@ static HRESULT WINAPI StorageBaseImpl_OpenStorage( } } - /* - * Initialize the out parameter - */ *ppstg = NULL; - /* - * Create a property enumeration to search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct( - This->ancestorStorage, - This->rootPropertySetIndex); - - /* - * Search the enumeration for the property with the given name - */ - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty( - propertyEnumeration, + storageEntryRef = findElement( + This, + This->storageDirEntry, pwcsName, - ¤tProperty); + ¤tEntry); - /* - * Delete the property enumeration since we don't need it anymore - */ - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - /* - * If it was found, construct the stream object and return a pointer to it. - */ - if ( (foundPropertyIndex!=PROPERTY_NULL) && - (currentProperty.propertyType==PROPTYPE_STORAGE) ) + if ( (storageEntryRef!=DIRENTRY_NULL) && + (currentEntry.stgType==STGTY_STORAGE) ) { - /* - * Construct a new Storage object - */ + if (StorageBaseImpl_IsStorageOpen(This, storageEntryRef)) + { + /* A single storage cannot be opened a second time. */ + res = STG_E_ACCESSDENIED; + goto end; + } + newStorage = StorageInternalImpl_Construct( - This->ancestorStorage, + This, grfMode, - foundPropertyIndex); + storageEntryRef); if (newStorage != 0) { - *ppstg = (IStorage*)newStorage; + if (grfMode & STGM_TRANSACTED) + { + res = Storage_ConstructTransacted(&newStorage->base, &newTransactedStorage); - /* - * Since we are returning a pointer to the interface, - * we have to nail down the reference. - */ - StorageBaseImpl_AddRef(*ppstg); + if (FAILED(res)) + { + HeapFree(GetProcessHeap(), 0, newStorage); + goto end; + } + + *ppstg = (IStorage*)newTransactedStorage; + } + else + { + *ppstg = (IStorage*)newStorage; + } + + list_add_tail(&This->storageHead, &newStorage->ParentListEntry); res = S_OK; goto end; @@ -660,7 +642,7 @@ end: * Storage32BaseImpl_EnumElements (IStorage) * * This method will create an enumerator object that can be used to - * retrieve information about all the properties in the storage object. + * retrieve information about all the elements in the storage object. * * See Windows documentation for more details on IStorage methods. */ @@ -677,27 +659,20 @@ static HRESULT WINAPI StorageBaseImpl_EnumElements( TRACE("(%p, %d, %p, %d, %p)\n", iface, reserved1, reserved2, reserved3, ppenum); - /* - * Perform a sanity check on the parameters. - */ if ( (This==0) || (ppenum==0)) return E_INVALIDARG; - /* - * Construct the enumerator. - */ + if (This->reverted) + return STG_E_REVERTED; + newEnum = IEnumSTATSTGImpl_Construct( - This->ancestorStorage, - This->rootPropertySetIndex); + This, + This->storageDirEntry); if (newEnum!=0) { *ppenum = (IEnumSTATSTG*)newEnum; - /* - * Don't forget to nail down a reference to the new object before - * returning it. - */ IEnumSTATSTG_AddRef(*ppenum); return S_OK; @@ -719,46 +694,41 @@ static HRESULT WINAPI StorageBaseImpl_Stat( DWORD grfStatFlag) /* [in] */ { StorageBaseImpl *This = (StorageBaseImpl *)iface; - StgProperty curProperty; - BOOL readSuccessful; + DirEntry currentEntry; HRESULT res = STG_E_UNKNOWN; TRACE("(%p, %p, %x)\n", iface, pstatstg, grfStatFlag); - /* - * Perform a sanity check on the parameters. - */ if ( (This==0) || (pstatstg==0)) { res = E_INVALIDARG; goto end; } - /* - * Read the information from the property. - */ - readSuccessful = StorageImpl_ReadProperty( - This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); - - if (readSuccessful) + if (This->reverted) { - StorageUtl_CopyPropertyToSTATSTG( + res = STG_E_REVERTED; + goto end; + } + + res = StorageBaseImpl_ReadDirEntry( + This, + This->storageDirEntry, + ¤tEntry); + + if (SUCCEEDED(res)) + { + StorageUtl_CopyDirEntryToSTATSTG( + This, pstatstg, - &curProperty, + ¤tEntry, grfStatFlag); pstatstg->grfMode = This->openFlags; pstatstg->grfStateBits = This->stateBits; - - res = S_OK; - goto end; } - res = E_FAIL; - end: if (res == S_OK) { @@ -774,10 +744,6 @@ end: * This method will rename the specified element. * * See Windows documentation for more details on IStorage methods. - * - * Implementation notes: The method used to rename consists of creating a clone - * of the deleted StgProperty object setting it with the new name and to - * perform a DestroyElement of the old StgProperty. */ static HRESULT WINAPI StorageBaseImpl_RenameElement( IStorage* iface, @@ -785,141 +751,67 @@ static HRESULT WINAPI StorageBaseImpl_RenameElement( const OLECHAR* pwcsNewName) /* [in] */ { StorageBaseImpl *This = (StorageBaseImpl *)iface; - IEnumSTATSTGImpl* propertyEnumeration; - StgProperty currentProperty; - ULONG foundPropertyIndex; + DirEntry currentEntry; + DirRef currentEntryRef; TRACE("(%p, %s, %s)\n", iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName)); - /* - * Create a property enumeration to search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage, - This->rootPropertySetIndex); + if (This->reverted) + return STG_E_REVERTED; - /* - * Search the enumeration for the new property name - */ - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, - pwcsNewName, - ¤tProperty); + currentEntryRef = findElement(This, + This->storageDirEntry, + pwcsNewName, + ¤tEntry); - if (foundPropertyIndex != PROPERTY_NULL) + if (currentEntryRef != DIRENTRY_NULL) { /* - * There is already a property with the new name + * There is already an element with the new name */ - IEnumSTATSTGImpl_Destroy(propertyEnumeration); return STG_E_FILEALREADYEXISTS; } - IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration); - /* - * Search the enumeration for the old property name + * Search for the old element name */ - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, - pwcsOldName, - ¤tProperty); + currentEntryRef = findElement(This, + This->storageDirEntry, + pwcsOldName, + ¤tEntry); - /* - * Delete the property enumeration since we don't need it anymore - */ - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - if (foundPropertyIndex != PROPERTY_NULL) + if (currentEntryRef != DIRENTRY_NULL) { - StgProperty renamedProperty; - ULONG renamedPropertyIndex; + if (StorageBaseImpl_IsStreamOpen(This, currentEntryRef) || + StorageBaseImpl_IsStorageOpen(This, currentEntryRef)) + { + WARN("Element is already open; cannot rename.\n"); + return STG_E_ACCESSDENIED; + } - /* - * Setup a new property for the renamed property - */ - renamedProperty.sizeOfNameString = - ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR); + /* Remove the element from its current position in the tree */ + removeFromTree(This, This->storageDirEntry, + currentEntryRef); - if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) - return STG_E_INVALIDNAME; + /* Change the name of the element */ + strcpyW(currentEntry.name, pwcsNewName); - strcpyW(renamedProperty.name, pwcsNewName); + /* Delete any sibling links */ + currentEntry.leftChild = DIRENTRY_NULL; + currentEntry.rightChild = DIRENTRY_NULL; - renamedProperty.propertyType = currentProperty.propertyType; - renamedProperty.startingBlock = currentProperty.startingBlock; - renamedProperty.size.u.LowPart = currentProperty.size.u.LowPart; - renamedProperty.size.u.HighPart = currentProperty.size.u.HighPart; - - renamedProperty.previousProperty = PROPERTY_NULL; - renamedProperty.nextProperty = PROPERTY_NULL; - - /* - * Bring the dirProperty link in case it is a storage and in which - * case the renamed storage elements don't require to be reorganized. - */ - renamedProperty.dirProperty = currentProperty.dirProperty; - - /* call CoFileTime to get the current time - renamedProperty.timeStampS1 - renamedProperty.timeStampD1 - renamedProperty.timeStampS2 - renamedProperty.timeStampD2 - renamedProperty.propertyUniqueID - */ - - /* - * Obtain a free property in the property chain - */ - renamedPropertyIndex = getFreeProperty(This->ancestorStorage); - - /* - * Save the new property into the new property spot - */ - StorageImpl_WriteProperty( - This->ancestorStorage, - renamedPropertyIndex, - &renamedProperty); - - /* - * Find a spot in the property chain for our newly created property. - */ - updatePropertyChain( - (StorageImpl*)This, - renamedPropertyIndex, - renamedProperty); - - /* - * At this point the renamed property has been inserted in the tree, - * now, before Destroying the old property we must zero its dirProperty - * otherwise the DestroyProperty below will zap it all and we do not want - * this to happen. - * Also, we fake that the old property is a storage so the DestroyProperty - * will not do a SetSize(0) on the stream data. - * - * This means that we need to tweak the StgProperty if it is a stream or a - * non empty storage. - */ - StorageImpl_ReadProperty(This->ancestorStorage, - foundPropertyIndex, - ¤tProperty); - - currentProperty.dirProperty = PROPERTY_NULL; - currentProperty.propertyType = PROPTYPE_STORAGE; - StorageImpl_WriteProperty( - This->ancestorStorage, - foundPropertyIndex, - ¤tProperty); - - /* - * Invoke Destroy to get rid of the ole property and automatically redo - * the linking of its previous and next members... - */ - IStorage_DestroyElement(iface, pwcsOldName); + StorageBaseImpl_WriteDirEntry(This, currentEntryRef, + ¤tEntry); + /* Insert the element in a new position in the tree */ + insertIntoTree(This, This->storageDirEntry, + currentEntryRef); } else { /* - * There is no property with the old name + * There is no element with the old name */ return STG_E_FILENOTFOUND; } @@ -943,18 +835,15 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( IStream** ppstm) /* [out] */ { StorageBaseImpl *This = (StorageBaseImpl *)iface; - IEnumSTATSTGImpl* propertyEnumeration; StgStreamImpl* newStream; - StgProperty currentProperty, newStreamProperty; - ULONG foundPropertyIndex, newPropertyIndex; + DirEntry currentEntry, newStreamEntry; + DirRef currentEntryRef, newStreamEntryRef; + HRESULT hr; TRACE("(%p, %s, %x, %d, %d, %p)\n", iface, debugstr_w(pwcsName), grfMode, reserved1, reserved2, ppstm); - /* - * Validate parameters - */ if (ppstm == 0) return STG_E_INVALIDPOINTER; @@ -964,15 +853,15 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( if (reserved1 || reserved2) return STG_E_INVALIDPARAMETER; - /* - * Validate the STGM flags - */ if ( FAILED( validateSTGM(grfMode) )) return STG_E_INVALIDFLAG; if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) return STG_E_INVALIDFLAG; + if (This->reverted) + return STG_E_REVERTED; + /* * As documented. */ @@ -980,133 +869,101 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( (grfMode & STGM_TRANSACTED)) return STG_E_INVALIDFUNCTION; - /* Can't create a stream on read-only storage */ - if ( STGM_ACCESS_MODE( This->openFlags ) == STGM_READ ) - return STG_E_ACCESSDENIED; - /* - * Check that we're compatible with the parent's storage mode - * if not in transacted mode + * Don't worry about permissions in transacted mode, as we can always write + * changes; we just can't always commit them. */ - if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) { + if(!(This->openFlags & STGM_TRANSACTED)) { + /* Can't create a stream on read-only storage */ + if ( STGM_ACCESS_MODE( This->openFlags ) == STGM_READ ) + return STG_E_ACCESSDENIED; + + /* Can't create a stream with greater access than the parent. */ if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) ) return STG_E_ACCESSDENIED; } - if(This->ancestorStorage->base.openFlags & STGM_SIMPLE) + if(This->openFlags & STGM_SIMPLE) if(grfMode & STGM_CREATE) return STG_E_INVALIDFLAG; - /* - * Initialize the out parameter - */ *ppstm = 0; - /* - * Create a property enumeration to search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage, - This->rootPropertySetIndex); + currentEntryRef = findElement(This, + This->storageDirEntry, + pwcsName, + ¤tEntry); - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, - pwcsName, - ¤tProperty); - - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - if (foundPropertyIndex != PROPERTY_NULL) + if (currentEntryRef != DIRENTRY_NULL) { /* * An element with this name already exists */ if (STGM_CREATE_MODE(grfMode) == STGM_CREATE) { - StgStreamImpl *strm; - - LIST_FOR_EACH_ENTRY(strm, &This->strmHead, StgStreamImpl, StrmListEntry) - { - if (strm->ownerProperty == foundPropertyIndex) - { - TRACE("Stream deleted %p\n", strm); - strm->parentStorage = NULL; - list_remove(&strm->StrmListEntry); - } - } IStorage_DestroyElement(iface, pwcsName); } else return STG_E_FILEALREADYEXISTS; } - else if (STGM_ACCESS_MODE(This->openFlags) == STGM_READ) - { - WARN("read-only storage\n"); - return STG_E_ACCESSDENIED; - } /* - * memset the empty property + * memset the empty entry */ - memset(&newStreamProperty, 0, sizeof(StgProperty)); + memset(&newStreamEntry, 0, sizeof(DirEntry)); - newStreamProperty.sizeOfNameString = + newStreamEntry.sizeOfNameString = ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR); - if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) + if (newStreamEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN) return STG_E_INVALIDNAME; - strcpyW(newStreamProperty.name, pwcsName); + strcpyW(newStreamEntry.name, pwcsName); - newStreamProperty.propertyType = PROPTYPE_STREAM; - newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN; - newStreamProperty.size.u.LowPart = 0; - newStreamProperty.size.u.HighPart = 0; + newStreamEntry.stgType = STGTY_STREAM; + newStreamEntry.startingBlock = BLOCK_END_OF_CHAIN; + newStreamEntry.size.u.LowPart = 0; + newStreamEntry.size.u.HighPart = 0; - newStreamProperty.previousProperty = PROPERTY_NULL; - newStreamProperty.nextProperty = PROPERTY_NULL; - newStreamProperty.dirProperty = PROPERTY_NULL; + newStreamEntry.leftChild = DIRENTRY_NULL; + newStreamEntry.rightChild = DIRENTRY_NULL; + newStreamEntry.dirRootEntry = DIRENTRY_NULL; /* call CoFileTime to get the current time - newStreamProperty.timeStampS1 - newStreamProperty.timeStampD1 - newStreamProperty.timeStampS2 - newStreamProperty.timeStampD2 + newStreamEntry.ctime + newStreamEntry.mtime */ - /* newStreamProperty.propertyUniqueID */ + /* newStreamEntry.clsid */ /* - * Get a free property or create a new one + * Create an entry with the new data */ - newPropertyIndex = getFreeProperty(This->ancestorStorage); + hr = StorageBaseImpl_CreateDirEntry(This, &newStreamEntry, &newStreamEntryRef); + if (FAILED(hr)) + return hr; /* - * Save the new property into the new property spot + * Insert the new entry in the parent storage's tree. */ - StorageImpl_WriteProperty( - This->ancestorStorage, - newPropertyIndex, - &newStreamProperty); - - /* - * Find a spot in the property chain for our newly created property. - */ - updatePropertyChain( - (StorageImpl*)This, - newPropertyIndex, - newStreamProperty); + hr = insertIntoTree( + This, + This->storageDirEntry, + newStreamEntryRef); + if (FAILED(hr)) + { + StorageBaseImpl_DestroyDirEntry(This, newStreamEntryRef); + return hr; + } /* * Open the stream to return it. */ - newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex); + newStream = StgStreamImpl_Construct(This, grfMode, newStreamEntryRef); if (newStream != 0) { *ppstm = (IStream*)newStream; - /* - * Since we are returning a pointer to the interface, we have to nail down - * the reference. - */ IStream_AddRef(*ppstm); } else @@ -1120,7 +977,7 @@ static HRESULT WINAPI StorageBaseImpl_CreateStream( /************************************************************************ * Storage32BaseImpl_SetClass (IStorage) * - * This method will write the specified CLSID in the property of this + * This method will write the specified CLSID in the directory entry of this * storage. * * See Windows documentation for more details on IStorage methods. @@ -1130,24 +987,24 @@ static HRESULT WINAPI StorageBaseImpl_SetClass( REFCLSID clsid) /* [in] */ { StorageBaseImpl *This = (StorageBaseImpl *)iface; - HRESULT hRes = E_FAIL; - StgProperty curProperty; - BOOL success; + HRESULT hRes; + DirEntry currentEntry; TRACE("(%p, %p)\n", iface, clsid); - success = StorageImpl_ReadProperty(This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); - if (success) - { - curProperty.propertyUniqueID = *clsid; + if (This->reverted) + return STG_E_REVERTED; - success = StorageImpl_WriteProperty(This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); - if (success) - hRes = S_OK; + hRes = StorageBaseImpl_ReadDirEntry(This, + This->storageDirEntry, + ¤tEntry); + if (SUCCEEDED(hRes)) + { + currentEntry.clsid = *clsid; + + hRes = StorageBaseImpl_WriteDirEntry(This, + This->storageDirEntry, + ¤tEntry); } return hRes; @@ -1158,13 +1015,13 @@ static HRESULT WINAPI StorageBaseImpl_SetClass( */ /************************************************************************ - * Storage32Impl_CreateStorage (IStorage) + * Storage32BaseImpl_CreateStorage (IStorage) * * This method will create the storage object within the provided storage. * * See Windows documentation for more details on IStorage methods. */ -static HRESULT WINAPI StorageImpl_CreateStorage( +static HRESULT WINAPI StorageBaseImpl_CreateStorage( IStorage* iface, const OLECHAR *pwcsName, /* [string][in] */ DWORD grfMode, /* [in] */ @@ -1172,36 +1029,31 @@ static HRESULT WINAPI StorageImpl_CreateStorage( DWORD reserved2, /* [in] */ IStorage **ppstg) /* [out] */ { - StorageImpl* const This=(StorageImpl*)iface; + StorageBaseImpl* const This=(StorageBaseImpl*)iface; - IEnumSTATSTGImpl *propertyEnumeration; - StgProperty currentProperty; - StgProperty newProperty; - ULONG foundPropertyIndex; - ULONG newPropertyIndex; + DirEntry currentEntry; + DirEntry newEntry; + DirRef currentEntryRef; + DirRef newEntryRef; HRESULT hr; TRACE("(%p, %s, %x, %d, %d, %p)\n", iface, debugstr_w(pwcsName), grfMode, reserved1, reserved2, ppstg); - /* - * Validate parameters - */ if (ppstg == 0) return STG_E_INVALIDPOINTER; + if (This->openFlags & STGM_SIMPLE) + { + return STG_E_INVALIDFUNCTION; + } + if (pwcsName == 0) return STG_E_INVALIDNAME; - /* - * Initialize the out parameter - */ *ppstg = NULL; - /* - * Validate the STGM flags - */ if ( FAILED( validateSTGM(grfMode) ) || (grfMode & STGM_DELETEONRELEASE) ) { @@ -1209,33 +1061,32 @@ static HRESULT WINAPI StorageImpl_CreateStorage( return STG_E_INVALIDFLAG; } + if (This->reverted) + return STG_E_REVERTED; + /* * Check that we're compatible with the parent's storage mode */ - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->base.openFlags ) ) + if ( !(This->openFlags & STGM_TRANSACTED) && + STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) ) { WARN("access denied\n"); return STG_E_ACCESSDENIED; } - /* - * Create a property enumeration and search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage, - This->base.rootPropertySetIndex); + currentEntryRef = findElement(This, + This->storageDirEntry, + pwcsName, + ¤tEntry); - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, - pwcsName, - ¤tProperty); - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - if (foundPropertyIndex != PROPERTY_NULL) + if (currentEntryRef != DIRENTRY_NULL) { /* * An element with this name already exists */ if (STGM_CREATE_MODE(grfMode) == STGM_CREATE && - STGM_ACCESS_MODE(This->base.openFlags) != STGM_READ) + ((This->openFlags & STGM_TRANSACTED) || + STGM_ACCESS_MODE(This->openFlags) != STGM_READ)) { hr = IStorage_DestroyElement(iface, pwcsName); if (FAILED(hr)) @@ -1247,65 +1098,60 @@ static HRESULT WINAPI StorageImpl_CreateStorage( return STG_E_FILEALREADYEXISTS; } } - else if (STGM_ACCESS_MODE(This->base.openFlags) == STGM_READ) + else if (!(This->openFlags & STGM_TRANSACTED) && + STGM_ACCESS_MODE(This->openFlags) == STGM_READ) { WARN("read-only storage\n"); return STG_E_ACCESSDENIED; } - /* - * memset the empty property - */ - memset(&newProperty, 0, sizeof(StgProperty)); + memset(&newEntry, 0, sizeof(DirEntry)); - newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR); + newEntry.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR); - if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) + if (newEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN) { FIXME("name too long\n"); return STG_E_INVALIDNAME; } - strcpyW(newProperty.name, pwcsName); + strcpyW(newEntry.name, pwcsName); - newProperty.propertyType = PROPTYPE_STORAGE; - newProperty.startingBlock = BLOCK_END_OF_CHAIN; - newProperty.size.u.LowPart = 0; - newProperty.size.u.HighPart = 0; + newEntry.stgType = STGTY_STORAGE; + newEntry.startingBlock = BLOCK_END_OF_CHAIN; + newEntry.size.u.LowPart = 0; + newEntry.size.u.HighPart = 0; - newProperty.previousProperty = PROPERTY_NULL; - newProperty.nextProperty = PROPERTY_NULL; - newProperty.dirProperty = PROPERTY_NULL; + newEntry.leftChild = DIRENTRY_NULL; + newEntry.rightChild = DIRENTRY_NULL; + newEntry.dirRootEntry = DIRENTRY_NULL; /* call CoFileTime to get the current time - newProperty.timeStampS1 - newProperty.timeStampD1 - newProperty.timeStampS2 - newProperty.timeStampD2 + newEntry.ctime + newEntry.mtime */ - /* newStorageProperty.propertyUniqueID */ + /* newEntry.clsid */ /* - * Obtain a free property in the property chain + * Create a new directory entry for the storage */ - newPropertyIndex = getFreeProperty(This->base.ancestorStorage); + hr = StorageBaseImpl_CreateDirEntry(This, &newEntry, &newEntryRef); + if (FAILED(hr)) + return hr; /* - * Save the new property into the new property spot + * Insert the new directory entry into the parent storage's tree */ - StorageImpl_WriteProperty( - This->base.ancestorStorage, - newPropertyIndex, - &newProperty); - - /* - * Find a spot in the property chain for our newly created property. - */ - updatePropertyChain( + hr = insertIntoTree( This, - newPropertyIndex, - newProperty); + This->storageDirEntry, + newEntryRef); + if (FAILED(hr)) + { + StorageBaseImpl_DestroyDirEntry(This, newEntryRef); + return hr; + } /* * Open it to get a pointer to return. @@ -1326,122 +1172,198 @@ static HRESULT WINAPI StorageImpl_CreateStorage( * * Internal Method * - * Get a free property or create a new one. + * Reserve a directory entry in the file and initialize it. */ -static ULONG getFreeProperty( - StorageImpl *storage) +static HRESULT StorageImpl_CreateDirEntry( + StorageBaseImpl *base, + const DirEntry *newData, + DirRef *index) { - ULONG currentPropertyIndex = 0; - ULONG newPropertyIndex = PROPERTY_NULL; - BOOL readSuccessful = TRUE; - StgProperty currentProperty; + StorageImpl *storage = (StorageImpl*)base; + ULONG currentEntryIndex = 0; + ULONG newEntryIndex = DIRENTRY_NULL; + HRESULT hr = S_OK; + BYTE currentData[RAW_DIRENTRY_SIZE]; + WORD sizeOfNameString; do { - /* - * Start by reading the root property - */ - readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage, - currentPropertyIndex, - ¤tProperty); - if (readSuccessful) + hr = StorageImpl_ReadRawDirEntry(storage, + currentEntryIndex, + currentData); + + if (SUCCEEDED(hr)) { - if (currentProperty.sizeOfNameString == 0) + StorageUtl_ReadWord( + currentData, + OFFSET_PS_NAMELENGTH, + &sizeOfNameString); + + if (sizeOfNameString == 0) { /* - * The property existis and is available, we found it. + * The entry exists and is available, we found it. */ - newPropertyIndex = currentPropertyIndex; + newEntryIndex = currentEntryIndex; } } else { /* - * We exhausted the property list, we will create more space below + * We exhausted the directory entries, we will create more space below */ - newPropertyIndex = currentPropertyIndex; + newEntryIndex = currentEntryIndex; } - currentPropertyIndex++; + currentEntryIndex++; - } while (newPropertyIndex == PROPERTY_NULL); + } while (newEntryIndex == DIRENTRY_NULL); /* - * grow the property chain + * grow the directory stream */ - if (! readSuccessful) + if (FAILED(hr)) { - StgProperty emptyProperty; + BYTE emptyData[RAW_DIRENTRY_SIZE]; ULARGE_INTEGER newSize; - ULONG propertyIndex; - ULONG lastProperty = 0; + ULONG entryIndex; + ULONG lastEntry = 0; ULONG blockCount = 0; /* - * obtain the new count of property blocks + * obtain the new count of blocks in the directory stream */ blockCount = BlockChainStream_GetCount( - storage->base.ancestorStorage->rootBlockChain)+1; + storage->rootBlockChain)+1; /* - * initialize the size used by the property stream + * initialize the size used by the directory stream */ newSize.u.HighPart = 0; newSize.u.LowPart = storage->bigBlockSize * blockCount; /* - * add a property block to the property chain + * add a block to the directory stream */ - BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize); + BlockChainStream_SetSize(storage->rootBlockChain, newSize); /* - * memset the empty property in order to initialize the unused newly - * created property + * memset the empty entry in order to initialize the unused newly + * created entries */ - memset(&emptyProperty, 0, sizeof(StgProperty)); + memset(&emptyData, 0, RAW_DIRENTRY_SIZE); /* * initialize them */ - lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount; + lastEntry = storage->bigBlockSize / RAW_DIRENTRY_SIZE * blockCount; for( - propertyIndex = newPropertyIndex; - propertyIndex < lastProperty; - propertyIndex++) + entryIndex = newEntryIndex + 1; + entryIndex < lastEntry; + entryIndex++) { - StorageImpl_WriteProperty( - storage->base.ancestorStorage, - propertyIndex, - &emptyProperty); + StorageImpl_WriteRawDirEntry( + storage, + entryIndex, + emptyData); } } - return newPropertyIndex; + UpdateRawDirEntry(currentData, newData); + + hr = StorageImpl_WriteRawDirEntry(storage, newEntryIndex, currentData); + + if (SUCCEEDED(hr)) + *index = newEntryIndex; + + return hr; } +/*************************************************************************** + * + * Internal Method + * + * Mark a directory entry in the file as free. + */ +static HRESULT StorageImpl_DestroyDirEntry( + StorageBaseImpl *base, + DirRef index) +{ + HRESULT hr; + BYTE emptyData[RAW_DIRENTRY_SIZE]; + StorageImpl *storage = (StorageImpl*)base; + + memset(&emptyData, 0, RAW_DIRENTRY_SIZE); + + hr = StorageImpl_WriteRawDirEntry(storage, index, emptyData); + + return hr; +} + + +/*************************************************************************** + * + * Internal Method + * + * Destroy an entry, its attached data, and all entries reachable from it. + */ +static HRESULT DestroyReachableEntries( + StorageBaseImpl *base, + DirRef index) +{ + HRESULT hr = S_OK; + DirEntry data; + ULARGE_INTEGER zero; + + zero.QuadPart = 0; + + if (index != DIRENTRY_NULL) + { + hr = StorageBaseImpl_ReadDirEntry(base, index, &data); + + if (SUCCEEDED(hr)) + hr = DestroyReachableEntries(base, data.dirRootEntry); + + if (SUCCEEDED(hr)) + hr = DestroyReachableEntries(base, data.leftChild); + + if (SUCCEEDED(hr)) + hr = DestroyReachableEntries(base, data.rightChild); + + if (SUCCEEDED(hr)) + hr = StorageBaseImpl_StreamSetSize(base, index, zero); + + if (SUCCEEDED(hr)) + hr = StorageBaseImpl_DestroyDirEntry(base, index); + } + + return hr; +} + + /**************************************************************************** * * Internal Method * - * Case insensitive comparison of StgProperty.name by first considering + * Case insensitive comparison of DirEntry.name by first considering * their size. * - * Returns <0 when newProperty < currentProperty - * >0 when newProperty > currentProperty - * 0 when newProperty == currentProperty + * Returns <0 when name1 < name2 + * >0 when name1 > name2 + * 0 when name1 == name2 */ -static LONG propertyNameCmp( - const OLECHAR *newProperty, - const OLECHAR *currentProperty) +static LONG entryNameCmp( + const OLECHAR *name1, + const OLECHAR *name2) { - LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty); + LONG diff = lstrlenW(name1) - lstrlenW(name2); - if (diff == 0) + while (diff == 0 && *name1 != 0) { /* * We compare the string themselves only when they are of the same length */ - diff = lstrcmpiW( newProperty, currentProperty); + diff = toupperW(*name1++) - toupperW(*name2++); } return diff; @@ -1451,84 +1373,92 @@ static LONG propertyNameCmp( * * Internal Method * - * Properly link this new element in the property chain. + * Add a directory entry to a storage */ -static void updatePropertyChain( - StorageImpl *storage, - ULONG newPropertyIndex, - StgProperty newProperty) +static HRESULT insertIntoTree( + StorageBaseImpl *This, + DirRef parentStorageIndex, + DirRef newEntryIndex) { - StgProperty currentProperty; + DirEntry currentEntry; + DirEntry newEntry; /* - * Read the root property + * Read the inserted entry */ - StorageImpl_ReadProperty(storage->base.ancestorStorage, - storage->base.rootPropertySetIndex, - ¤tProperty); + StorageBaseImpl_ReadDirEntry(This, + newEntryIndex, + &newEntry); - if (currentProperty.dirProperty != PROPERTY_NULL) + /* + * Read the storage entry + */ + StorageBaseImpl_ReadDirEntry(This, + parentStorageIndex, + ¤tEntry); + + if (currentEntry.dirRootEntry != DIRENTRY_NULL) { /* * The root storage contains some element, therefore, start the research * for the appropriate location. */ BOOL found = 0; - ULONG current, next, previous, currentPropertyId; + DirRef current, next, previous, currentEntryId; /* - * Keep the StgProperty sequence number of the storage first property + * Keep a reference to the root of the storage's element tree */ - currentPropertyId = currentProperty.dirProperty; + currentEntryId = currentEntry.dirRootEntry; /* * Read */ - StorageImpl_ReadProperty(storage->base.ancestorStorage, - currentProperty.dirProperty, - ¤tProperty); + StorageBaseImpl_ReadDirEntry(This, + currentEntry.dirRootEntry, + ¤tEntry); - previous = currentProperty.previousProperty; - next = currentProperty.nextProperty; - current = currentPropertyId; + previous = currentEntry.leftChild; + next = currentEntry.rightChild; + current = currentEntryId; while (found == 0) { - LONG diff = propertyNameCmp( newProperty.name, currentProperty.name); + LONG diff = entryNameCmp( newEntry.name, currentEntry.name); if (diff < 0) { - if (previous != PROPERTY_NULL) + if (previous != DIRENTRY_NULL) { - StorageImpl_ReadProperty(storage->base.ancestorStorage, - previous, - ¤tProperty); + StorageBaseImpl_ReadDirEntry(This, + previous, + ¤tEntry); current = previous; } else { - currentProperty.previousProperty = newPropertyIndex; - StorageImpl_WriteProperty(storage->base.ancestorStorage, - current, - ¤tProperty); + currentEntry.leftChild = newEntryIndex; + StorageBaseImpl_WriteDirEntry(This, + current, + ¤tEntry); found = 1; } } else if (diff > 0) { - if (next != PROPERTY_NULL) + if (next != DIRENTRY_NULL) { - StorageImpl_ReadProperty(storage->base.ancestorStorage, - next, - ¤tProperty); + StorageBaseImpl_ReadDirEntry(This, + next, + ¤tEntry); current = next; } else { - currentProperty.nextProperty = newPropertyIndex; - StorageImpl_WriteProperty(storage->base.ancestorStorage, - current, - ¤tProperty); + currentEntry.rightChild = newEntryIndex; + StorageBaseImpl_WriteDirEntry(This, + current, + ¤tEntry); found = 1; } } @@ -1538,30 +1468,131 @@ static void updatePropertyChain( * Trying to insert an item with the same name in the * subtree structure. */ - assert(FALSE); + return STG_E_FILEALREADYEXISTS; } - previous = currentProperty.previousProperty; - next = currentProperty.nextProperty; + previous = currentEntry.leftChild; + next = currentEntry.rightChild; } } else { /* - * The root storage is empty, link the new property to its dir property + * The storage is empty, make the new entry the root of its element tree */ - currentProperty.dirProperty = newPropertyIndex; - StorageImpl_WriteProperty(storage->base.ancestorStorage, - storage->base.rootPropertySetIndex, - ¤tProperty); + currentEntry.dirRootEntry = newEntryIndex; + StorageBaseImpl_WriteDirEntry(This, + parentStorageIndex, + ¤tEntry); } + + return S_OK; +} + +/**************************************************************************** + * + * Internal Method + * + * Find and read the element of a storage with the given name. + */ +static DirRef findElement(StorageBaseImpl *storage, DirRef storageEntry, + const OLECHAR *name, DirEntry *data) +{ + DirRef currentEntry; + + /* Read the storage entry to find the root of the tree. */ + StorageBaseImpl_ReadDirEntry(storage, storageEntry, data); + + currentEntry = data->dirRootEntry; + + while (currentEntry != DIRENTRY_NULL) + { + LONG cmp; + + StorageBaseImpl_ReadDirEntry(storage, currentEntry, data); + + cmp = entryNameCmp(name, data->name); + + if (cmp == 0) + /* found it */ + break; + + else if (cmp < 0) + currentEntry = data->leftChild; + + else if (cmp > 0) + currentEntry = data->rightChild; + } + + return currentEntry; +} + +/**************************************************************************** + * + * Internal Method + * + * Find and read the binary tree parent of the element with the given name. + * + * If there is no such element, find a place where it could be inserted and + * return STG_E_FILENOTFOUND. + */ +static HRESULT findTreeParent(StorageBaseImpl *storage, DirRef storageEntry, + const OLECHAR *childName, DirEntry *parentData, DirRef *parentEntry, + ULONG *relation) +{ + DirRef childEntry; + DirEntry childData; + + /* Read the storage entry to find the root of the tree. */ + StorageBaseImpl_ReadDirEntry(storage, storageEntry, parentData); + + *parentEntry = storageEntry; + *relation = DIRENTRY_RELATION_DIR; + + childEntry = parentData->dirRootEntry; + + while (childEntry != DIRENTRY_NULL) + { + LONG cmp; + + StorageBaseImpl_ReadDirEntry(storage, childEntry, &childData); + + cmp = entryNameCmp(childName, childData.name); + + if (cmp == 0) + /* found it */ + break; + + else if (cmp < 0) + { + *parentData = childData; + *parentEntry = childEntry; + *relation = DIRENTRY_RELATION_PREVIOUS; + + childEntry = parentData->leftChild; + } + + else if (cmp > 0) + { + *parentData = childData; + *parentEntry = childEntry; + *relation = DIRENTRY_RELATION_NEXT; + + childEntry = parentData->rightChild; + } + } + + if (childEntry == DIRENTRY_NULL) + return STG_E_FILENOTFOUND; + else + return S_OK; } /************************************************************************* * CopyTo (IStorage) */ -static HRESULT WINAPI StorageImpl_CopyTo( +static HRESULT WINAPI StorageBaseImpl_CopyTo( IStorage* iface, DWORD ciidExclude, /* [in] */ const IID* rgiidExclude, /* [size_is][unique][in] */ @@ -1573,17 +1604,13 @@ static HRESULT WINAPI StorageImpl_CopyTo( HRESULT hr; IStorage *pstgTmp, *pstgChild; IStream *pstrTmp, *pstrChild; - - if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL)) - FIXME("Exclude option not implemented\n"); + BOOL skip = FALSE, skip_storage = FALSE, skip_stream = FALSE; + int i; TRACE("(%p, %d, %p, %p, %p)\n", iface, ciidExclude, rgiidExclude, snbExclude, pstgDest); - /* - * Perform a sanity check - */ if ( pstgDest == 0 ) return STG_E_INVALIDPOINTER; @@ -1601,6 +1628,16 @@ static HRESULT WINAPI StorageImpl_CopyTo( IStorage_Stat( iface, &curElement, STATFLAG_NONAME); IStorage_SetClass( pstgDest, &curElement.clsid ); + for(i = 0; i < ciidExclude; ++i) + { + if(IsEqualGUID(&IID_IStorage, &rgiidExclude[i])) + skip_storage = TRUE; + else if(IsEqualGUID(&IID_IStream, &rgiidExclude[i])) + skip_stream = TRUE; + else + WARN("Unknown excluded GUID: %s\n", debugstr_guid(&rgiidExclude[i])); + } + do { /* @@ -1614,8 +1651,26 @@ static HRESULT WINAPI StorageImpl_CopyTo( break; } + if ( snbExclude ) + { + WCHAR **snb = snbExclude; + skip = FALSE; + while ( *snb != NULL && !skip ) + { + if ( lstrcmpW(curElement.pwcsName, *snb) == 0 ) + skip = TRUE; + ++snb; + } + } + + if ( skip ) + goto cleanup; + if (curElement.type == STGTY_STORAGE) { + if(skip_storage) + goto cleanup; + /* * open child source storage */ @@ -1624,18 +1679,7 @@ static HRESULT WINAPI StorageImpl_CopyTo( NULL, 0, &pstgChild ); if (hr != S_OK) - break; - - /* - * Check if destination storage is not a child of the source - * storage, which will cause an infinite loop - */ - if (pstgChild == pstgDest) - { - IEnumSTATSTG_Release(elements); - - return STG_E_ACCESSDENIED; - } + goto cleanup; /* * create a new storage in destination storage @@ -1654,21 +1698,24 @@ static HRESULT WINAPI StorageImpl_CopyTo( NULL, 0, &pstgTmp ); } - if (hr != S_OK) - break; + if (hr == S_OK) + { + /* + * do the copy recursively + */ + hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude, + NULL, pstgTmp ); + IStorage_Release( pstgTmp ); + } - /* - * do the copy recursively - */ - hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude, - snbExclude, pstgTmp ); - - IStorage_Release( pstgTmp ); IStorage_Release( pstgChild ); } else if (curElement.type == STGTY_STREAM) { + if(skip_stream) + goto cleanup; + /* * create a new stream in destination storage. If the stream already * exist, it will be deleted and a new one will be created. @@ -1678,7 +1725,7 @@ static HRESULT WINAPI StorageImpl_CopyTo( 0, 0, &pstrTmp ); if (hr != S_OK) - break; + goto cleanup; /* * open child stream storage @@ -1687,33 +1734,36 @@ static HRESULT WINAPI StorageImpl_CopyTo( STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pstrChild ); - if (hr != S_OK) - break; + if (hr == S_OK) + { + /* + * Get the size of the source stream + */ + IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME ); - /* - * Get the size of the source stream - */ - IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME ); + /* + * Set the size of the destination stream. + */ + IStream_SetSize(pstrTmp, strStat.cbSize); - /* - * Set the size of the destination stream. - */ - IStream_SetSize(pstrTmp, strStat.cbSize); + /* + * do the copy + */ + hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize, + NULL, NULL ); - /* - * do the copy - */ - hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize, - NULL, NULL ); + IStream_Release( pstrChild ); + } IStream_Release( pstrTmp ); - IStream_Release( pstrChild ); } else { WARN("unknown element type: %d\n", curElement.type); } +cleanup: + CoTaskMemFree(curElement.pwcsName); } while (hr == S_OK); /* @@ -1727,7 +1777,7 @@ static HRESULT WINAPI StorageImpl_CopyTo( /************************************************************************* * MoveElementTo (IStorage) */ -static HRESULT WINAPI StorageImpl_MoveElementTo( +static HRESULT WINAPI StorageBaseImpl_MoveElementTo( IStorage* iface, const OLECHAR *pwcsName, /* [string][in] */ IStorage *pstgDest, /* [unique][in] */ @@ -1766,8 +1816,8 @@ static HRESULT WINAPI StorageImpl_Commit( static HRESULT WINAPI StorageImpl_Revert( IStorage* iface) { - FIXME("(%p): stub\n", iface); - return E_NOTIMPL; + TRACE("(%p)\n", iface); + return S_OK; } /************************************************************************* @@ -1781,157 +1831,76 @@ static HRESULT WINAPI StorageImpl_Revert( * enumeration strategy that would give all the leaves of a storage * first. (postfix order) */ -static HRESULT WINAPI StorageImpl_DestroyElement( +static HRESULT WINAPI StorageBaseImpl_DestroyElement( IStorage* iface, const OLECHAR *pwcsName)/* [string][in] */ { - StorageImpl* const This=(StorageImpl*)iface; + StorageBaseImpl* const This=(StorageBaseImpl*)iface; - IEnumSTATSTGImpl* propertyEnumeration; HRESULT hr = S_OK; - BOOL res; - StgProperty propertyToDelete; - StgProperty parentProperty; - ULONG foundPropertyIndexToDelete; - ULONG typeOfRelation; - ULONG parentPropertyId = 0; + DirEntry entryToDelete; + DirRef entryToDeleteRef; TRACE("(%p, %s)\n", iface, debugstr_w(pwcsName)); - /* - * Perform a sanity check on the parameters. - */ if (pwcsName==NULL) return STG_E_INVALIDPOINTER; - if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ ) + if (This->reverted) + return STG_E_REVERTED; + + if ( !(This->openFlags & STGM_TRANSACTED) && + STGM_ACCESS_MODE( This->openFlags ) == STGM_READ ) return STG_E_ACCESSDENIED; - /* - * Create a property enumeration to search the property with the given name - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct( - This->base.ancestorStorage, - This->base.rootPropertySetIndex); - - foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty( - propertyEnumeration, + entryToDeleteRef = findElement( + This, + This->storageDirEntry, pwcsName, - &propertyToDelete); + &entryToDelete); - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - if ( foundPropertyIndexToDelete == PROPERTY_NULL ) + if ( entryToDeleteRef == DIRENTRY_NULL ) { return STG_E_FILENOTFOUND; } - /* - * Find the parent property of the property to delete (the one that - * link to it). If This->dirProperty == foundPropertyIndexToDelete, - * the parent is This. Otherwise, the parent is one of its sibling... - */ - - /* - * First, read This's StgProperty.. - */ - res = StorageImpl_ReadProperty( - This->base.ancestorStorage, - This->base.rootPropertySetIndex, - &parentProperty); - - assert(res); - - /* - * Second, check to see if by any chance the actual storage (This) is not - * the parent of the property to delete... We never know... - */ - if ( parentProperty.dirProperty == foundPropertyIndexToDelete ) + if ( entryToDelete.stgType == STGTY_STORAGE ) { - /* - * Set data as it would have been done in the else part... - */ - typeOfRelation = PROPERTY_RELATION_DIR; - parentPropertyId = This->base.rootPropertySetIndex; - } - else - { - /* - * Create a property enumeration to search the parent properties, and - * delete it once done. - */ - IEnumSTATSTGImpl* propertyEnumeration2; - - propertyEnumeration2 = IEnumSTATSTGImpl_Construct( - This->base.ancestorStorage, - This->base.rootPropertySetIndex); - - typeOfRelation = IEnumSTATSTGImpl_FindParentProperty( - propertyEnumeration2, - foundPropertyIndexToDelete, - &parentProperty, - &parentPropertyId); - - IEnumSTATSTGImpl_Destroy(propertyEnumeration2); - } - - if ( propertyToDelete.propertyType == PROPTYPE_STORAGE ) - { - hr = deleteStorageProperty( + hr = deleteStorageContents( This, - foundPropertyIndexToDelete, - propertyToDelete); + entryToDeleteRef, + entryToDelete); } - else if ( propertyToDelete.propertyType == PROPTYPE_STREAM ) + else if ( entryToDelete.stgType == STGTY_STREAM ) { - hr = deleteStreamProperty( + hr = deleteStreamContents( This, - foundPropertyIndexToDelete, - propertyToDelete); + entryToDeleteRef, + entryToDelete); } if (hr!=S_OK) return hr; /* - * Adjust the property chain + * Remove the entry from its parent storage */ - hr = adjustPropertyChain( + hr = removeFromTree( This, - propertyToDelete, - parentProperty, - parentPropertyId, - typeOfRelation); + This->storageDirEntry, + entryToDeleteRef); + + /* + * Invalidate the entry + */ + if (SUCCEEDED(hr)) + StorageBaseImpl_DestroyDirEntry(This, entryToDeleteRef); return hr; } -/************************************************************************ - * StorageImpl_Stat (IStorage) - * - * This method will retrieve information about this storage object. - * - * See Windows documentation for more details on IStorage methods. - */ -static HRESULT WINAPI StorageImpl_Stat( IStorage* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag) /* [in] */ -{ - StorageImpl* const This = (StorageImpl*)iface; - HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag ); - - if ( SUCCEEDED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName ) - { - CoTaskMemFree(pstatstg->pwcsName); - pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR)); - strcpyW(pstatstg->pwcsName, This->pwcsName); - } - - return result; -} - /****************************************************************************** * Internal stream list handlers */ @@ -1948,17 +1917,60 @@ void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm) list_remove(&(strm->StrmListEntry)); } +static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry) +{ + StgStreamImpl *strm; + + LIST_FOR_EACH_ENTRY(strm, &stg->strmHead, StgStreamImpl, StrmListEntry) + { + if (strm->dirEntry == streamEntry) + { + return TRUE; + } + } + + return FALSE; +} + +static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry) +{ + StorageInternalImpl *childstg; + + LIST_FOR_EACH_ENTRY(childstg, &stg->storageHead, StorageInternalImpl, ParentListEntry) + { + if (childstg->base.storageDirEntry == storageEntry) + { + return TRUE; + } + } + + return FALSE; +} + static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg) { struct list *cur, *cur2; StgStreamImpl *strm=NULL; + StorageInternalImpl *childstg=NULL; LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) { strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry); - TRACE("Streams deleted (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev); + TRACE("Streams invalidated (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev); strm->parentStorage = NULL; list_remove(cur); } + + LIST_FOR_EACH_SAFE(cur, cur2, &stg->storageHead) { + childstg = LIST_ENTRY(cur,StorageInternalImpl,ParentListEntry); + StorageBaseImpl_Invalidate( &childstg->base ); + } + + if (stg->transactedChild) + { + StorageBaseImpl_Invalidate(stg->transactedChild); + + stg->transactedChild = NULL; + } } @@ -1966,26 +1978,36 @@ static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg) * * Internal Method * - * Perform the deletion of a complete storage node + * Delete the contents of a storage entry. * */ -static HRESULT deleteStorageProperty( - StorageImpl *parentStorage, - ULONG indexOfPropertyToDelete, - StgProperty propertyToDelete) +static HRESULT deleteStorageContents( + StorageBaseImpl *parentStorage, + DirRef indexToDelete, + DirEntry entryDataToDelete) { IEnumSTATSTG *elements = 0; IStorage *childStorage = 0; STATSTG currentElement; HRESULT hr; HRESULT destroyHr = S_OK; + StorageInternalImpl *stg, *stg2; + + /* Invalidate any open storage objects. */ + LIST_FOR_EACH_ENTRY_SAFE(stg, stg2, &parentStorage->storageHead, StorageInternalImpl, ParentListEntry) + { + if (stg->base.storageDirEntry == indexToDelete) + { + StorageBaseImpl_Invalidate(&stg->base); + } + } /* * Open the storage and enumerate it */ hr = StorageBaseImpl_OpenStorage( (IStorage*)parentStorage, - propertyToDelete.name, + entryDataToDelete.name, 0, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, @@ -2010,7 +2032,7 @@ static HRESULT deleteStorageProperty( hr = IEnumSTATSTG_Next(elements, 1, ¤tElement, NULL); if (hr==S_OK) { - destroyHr = StorageImpl_DestroyElement(childStorage, currentElement.pwcsName); + destroyHr = IStorage_DestroyElement(childStorage, currentElement.pwcsName); CoTaskMemFree(currentElement.pwcsName); } @@ -2023,15 +2045,6 @@ static HRESULT deleteStorageProperty( } while ((hr == S_OK) && (destroyHr == S_OK)); - /* - * Invalidate the property by zeroing its name member. - */ - propertyToDelete.sizeOfNameString = 0; - - StorageImpl_WriteProperty(parentStorage->base.ancestorStorage, - indexOfPropertyToDelete, - &propertyToDelete); - IStorage_Release(childStorage); IEnumSTATSTG_Release(elements); @@ -2042,23 +2055,35 @@ static HRESULT deleteStorageProperty( * * Internal Method * - * Perform the deletion of a stream node + * Perform the deletion of a stream's data * */ -static HRESULT deleteStreamProperty( - StorageImpl *parentStorage, - ULONG indexOfPropertyToDelete, - StgProperty propertyToDelete) +static HRESULT deleteStreamContents( + StorageBaseImpl *parentStorage, + DirRef indexToDelete, + DirEntry entryDataToDelete) { IStream *pis; HRESULT hr; ULARGE_INTEGER size; + StgStreamImpl *strm, *strm2; + + /* Invalidate any open stream objects. */ + LIST_FOR_EACH_ENTRY_SAFE(strm, strm2, &parentStorage->strmHead, StgStreamImpl, StrmListEntry) + { + if (strm->dirEntry == indexToDelete) + { + TRACE("Stream deleted %p\n", strm); + strm->parentStorage = NULL; + list_remove(&strm->StrmListEntry); + } + } size.u.HighPart = 0; size.u.LowPart = 0; hr = StorageBaseImpl_OpenStream((IStorage*)parentStorage, - propertyToDelete.name, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pis); + entryDataToDelete.name, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pis); if (hr!=S_OK) { @@ -2080,260 +2105,127 @@ static HRESULT deleteStreamProperty( */ IStream_Release(pis); - /* - * Invalidate the property by zeroing its name member. - */ - propertyToDelete.sizeOfNameString = 0; - - /* - * Here we should re-read the property so we get the updated pointer - * but since we are here to zap it, I don't do it... - */ - StorageImpl_WriteProperty( - parentStorage->base.ancestorStorage, - indexOfPropertyToDelete, - &propertyToDelete); - return S_OK; } -/********************************************************************* - * - * Internal Method - * - * Finds a placeholder for the StgProperty within the Storage - * - */ -static HRESULT findPlaceholder( - StorageImpl *storage, - ULONG propertyIndexToStore, - ULONG storePropertyIndex, - INT typeOfRelation) +static void setEntryLink(DirEntry *entry, ULONG relation, DirRef new_target) { - StgProperty storeProperty; - BOOL res = TRUE; - - /* - * Read the storage property - */ - res = StorageImpl_ReadProperty( - storage->base.ancestorStorage, - storePropertyIndex, - &storeProperty); - - if(! res) + switch (relation) { - return E_FAIL; + case DIRENTRY_RELATION_PREVIOUS: + entry->leftChild = new_target; + break; + case DIRENTRY_RELATION_NEXT: + entry->rightChild = new_target; + break; + case DIRENTRY_RELATION_DIR: + entry->dirRootEntry = new_target; + break; + default: + assert(0); } - - if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) - { - if (storeProperty.previousProperty != PROPERTY_NULL) - { - return findPlaceholder( - storage, - propertyIndexToStore, - storeProperty.previousProperty, - typeOfRelation); - } - else - { - storeProperty.previousProperty = propertyIndexToStore; - } - } - else if (typeOfRelation == PROPERTY_RELATION_NEXT) - { - if (storeProperty.nextProperty != PROPERTY_NULL) - { - return findPlaceholder( - storage, - propertyIndexToStore, - storeProperty.nextProperty, - typeOfRelation); - } - else - { - storeProperty.nextProperty = propertyIndexToStore; - } - } - else if (typeOfRelation == PROPERTY_RELATION_DIR) - { - if (storeProperty.dirProperty != PROPERTY_NULL) - { - return findPlaceholder( - storage, - propertyIndexToStore, - storeProperty.dirProperty, - typeOfRelation); - } - else - { - storeProperty.dirProperty = propertyIndexToStore; - } - } - - res = StorageImpl_WriteProperty( - storage->base.ancestorStorage, - storePropertyIndex, - &storeProperty); - - if(!res) - { - return E_FAIL; - } - - return S_OK; } /************************************************************************* * * Internal Method * - * This method takes the previous and the next property link of a property - * to be deleted and find them a place in the Storage. + * This method removes a directory entry from its parent storage tree without + * freeing any resources attached to it. */ -static HRESULT adjustPropertyChain( - StorageImpl *This, - StgProperty propertyToDelete, - StgProperty parentProperty, - ULONG parentPropertyId, - INT typeOfRelation) +static HRESULT removeFromTree( + StorageBaseImpl *This, + DirRef parentStorageIndex, + DirRef deletedIndex) { - ULONG newLinkProperty = PROPERTY_NULL; - BOOL needToFindAPlaceholder = FALSE; - ULONG storeNode = PROPERTY_NULL; - ULONG toStoreNode = PROPERTY_NULL; - INT relationType = 0; HRESULT hr = S_OK; - BOOL res = TRUE; + DirEntry entryToDelete; + DirEntry parentEntry; + DirRef parentEntryRef; + ULONG typeOfRelation; - if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) - { - if (propertyToDelete.previousProperty != PROPERTY_NULL) - { - /* - * Set the parent previous to the property to delete previous - */ - newLinkProperty = propertyToDelete.previousProperty; + hr = StorageBaseImpl_ReadDirEntry(This, deletedIndex, &entryToDelete); - if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * We also need to find a storage for the other link, setup variables - * to do this at the end... - */ - needToFindAPlaceholder = TRUE; - storeNode = propertyToDelete.previousProperty; - toStoreNode = propertyToDelete.nextProperty; - relationType = PROPERTY_RELATION_NEXT; - } - } - else if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * Set the parent previous to the property to delete next - */ - newLinkProperty = propertyToDelete.nextProperty; - } - - /* - * Link it for real... - */ - parentProperty.previousProperty = newLinkProperty; - - } - else if (typeOfRelation == PROPERTY_RELATION_NEXT) - { - if (propertyToDelete.previousProperty != PROPERTY_NULL) - { - /* - * Set the parent next to the property to delete next previous - */ - newLinkProperty = propertyToDelete.previousProperty; - - if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * We also need to find a storage for the other link, setup variables - * to do this at the end... - */ - needToFindAPlaceholder = TRUE; - storeNode = propertyToDelete.previousProperty; - toStoreNode = propertyToDelete.nextProperty; - relationType = PROPERTY_RELATION_NEXT; - } - } - else if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * Set the parent next to the property to delete next - */ - newLinkProperty = propertyToDelete.nextProperty; - } - - /* - * Link it for real... - */ - parentProperty.nextProperty = newLinkProperty; - } - else /* (typeOfRelation == PROPERTY_RELATION_DIR) */ - { - if (propertyToDelete.previousProperty != PROPERTY_NULL) - { - /* - * Set the parent dir to the property to delete previous - */ - newLinkProperty = propertyToDelete.previousProperty; - - if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * We also need to find a storage for the other link, setup variables - * to do this at the end... - */ - needToFindAPlaceholder = TRUE; - storeNode = propertyToDelete.previousProperty; - toStoreNode = propertyToDelete.nextProperty; - relationType = PROPERTY_RELATION_NEXT; - } - } - else if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * Set the parent dir to the property to delete next - */ - newLinkProperty = propertyToDelete.nextProperty; - } - - /* - * Link it for real... - */ - parentProperty.dirProperty = newLinkProperty; - } + if (hr != S_OK) + return hr; /* - * Write back the parent property + * Find the element that links to the one we want to delete. */ - res = StorageImpl_WriteProperty( - This->base.ancestorStorage, - parentPropertyId, - &parentProperty); - if(! res) - { - return E_FAIL; - } + hr = findTreeParent(This, parentStorageIndex, entryToDelete.name, + &parentEntry, &parentEntryRef, &typeOfRelation); - /* - * If a placeholder is required for the other link, then, find one and - * get out of here... - */ - if (needToFindAPlaceholder) + if (hr != S_OK) + return hr; + + if (entryToDelete.leftChild != DIRENTRY_NULL) { - hr = findPlaceholder( - This, - toStoreNode, - storeNode, - relationType); + /* + * Replace the deleted entry with its left child + */ + setEntryLink(&parentEntry, typeOfRelation, entryToDelete.leftChild); + + hr = StorageBaseImpl_WriteDirEntry( + This, + parentEntryRef, + &parentEntry); + if(FAILED(hr)) + { + return hr; + } + + if (entryToDelete.rightChild != DIRENTRY_NULL) + { + /* + * We need to reinsert the right child somewhere. We already know it and + * its children are greater than everything in the left tree, so we + * insert it at the rightmost point in the left tree. + */ + DirRef newRightChildParent = entryToDelete.leftChild; + DirEntry newRightChildParentEntry; + + do + { + hr = StorageBaseImpl_ReadDirEntry( + This, + newRightChildParent, + &newRightChildParentEntry); + if (FAILED(hr)) + { + return hr; + } + + if (newRightChildParentEntry.rightChild != DIRENTRY_NULL) + newRightChildParent = newRightChildParentEntry.rightChild; + } while (newRightChildParentEntry.rightChild != DIRENTRY_NULL); + + newRightChildParentEntry.rightChild = entryToDelete.rightChild; + + hr = StorageBaseImpl_WriteDirEntry( + This, + newRightChildParent, + &newRightChildParentEntry); + if (FAILED(hr)) + { + return hr; + } + } + } + else + { + /* + * Replace the deleted entry with its right child + */ + setEntryLink(&parentEntry, typeOfRelation, entryToDelete.rightChild); + + hr = StorageBaseImpl_WriteDirEntry( + This, + parentEntryRef, + &parentEntry); + if(FAILED(hr)) + { + return hr; + } } return hr; @@ -2343,7 +2235,7 @@ static HRESULT adjustPropertyChain( /****************************************************************************** * SetElementTimes (IStorage) */ -static HRESULT WINAPI StorageImpl_SetElementTimes( +static HRESULT WINAPI StorageBaseImpl_SetElementTimes( IStorage* iface, const OLECHAR *pwcsName,/* [string][in] */ const FILETIME *pctime, /* [in] */ @@ -2357,16 +2249,282 @@ static HRESULT WINAPI StorageImpl_SetElementTimes( /****************************************************************************** * SetStateBits (IStorage) */ -static HRESULT WINAPI StorageImpl_SetStateBits( +static HRESULT WINAPI StorageBaseImpl_SetStateBits( IStorage* iface, DWORD grfStateBits,/* [in] */ DWORD grfMask) /* [in] */ { - StorageImpl* const This = (StorageImpl*)iface; - This->base.stateBits = (This->base.stateBits & ~grfMask) | (grfStateBits & grfMask); + StorageBaseImpl* const This = (StorageBaseImpl*)iface; + + if (This->reverted) + return STG_E_REVERTED; + + This->stateBits = (This->stateBits & ~grfMask) | (grfStateBits & grfMask); return S_OK; } +static HRESULT StorageImpl_BaseWriteDirEntry(StorageBaseImpl *base, + DirRef index, const DirEntry *data) +{ + StorageImpl *This = (StorageImpl*)base; + return StorageImpl_WriteDirEntry(This, index, data); +} + +static HRESULT StorageImpl_BaseReadDirEntry(StorageBaseImpl *base, + DirRef index, DirEntry *data) +{ + StorageImpl *This = (StorageImpl*)base; + return StorageImpl_ReadDirEntry(This, index, data); +} + +static BlockChainStream **StorageImpl_GetFreeBlockChainCacheEntry(StorageImpl* This) +{ + int i; + + for (i=0; iblockChainCache[i]) + { + return &This->blockChainCache[i]; + } + } + + i = This->blockChainToEvict; + + BlockChainStream_Destroy(This->blockChainCache[i]); + This->blockChainCache[i] = NULL; + + This->blockChainToEvict++; + if (This->blockChainToEvict == BLOCKCHAIN_CACHE_SIZE) + This->blockChainToEvict = 0; + + return &This->blockChainCache[i]; +} + +static BlockChainStream **StorageImpl_GetCachedBlockChainStream(StorageImpl *This, + DirRef index) +{ + int i, free_index=-1; + + for (i=0; iblockChainCache[i]) + { + if (free_index == -1) free_index = i; + } + else if (This->blockChainCache[i]->ownerDirEntry == index) + { + return &This->blockChainCache[i]; + } + } + + if (free_index == -1) + { + free_index = This->blockChainToEvict; + + BlockChainStream_Destroy(This->blockChainCache[free_index]); + This->blockChainCache[free_index] = NULL; + + This->blockChainToEvict++; + if (This->blockChainToEvict == BLOCKCHAIN_CACHE_SIZE) + This->blockChainToEvict = 0; + } + + This->blockChainCache[free_index] = BlockChainStream_Construct(This, NULL, index); + return &This->blockChainCache[free_index]; +} + +static HRESULT StorageImpl_StreamReadAt(StorageBaseImpl *base, DirRef index, + ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead) +{ + StorageImpl *This = (StorageImpl*)base; + DirEntry data; + HRESULT hr; + ULONG bytesToRead; + + hr = StorageImpl_ReadDirEntry(This, index, &data); + if (FAILED(hr)) return hr; + + if (data.size.QuadPart == 0) + { + *bytesRead = 0; + return S_OK; + } + + if (offset.QuadPart + size > data.size.QuadPart) + { + bytesToRead = data.size.QuadPart - offset.QuadPart; + } + else + { + bytesToRead = size; + } + + if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK) + { + SmallBlockChainStream *stream; + + stream = SmallBlockChainStream_Construct(This, NULL, index); + if (!stream) return E_OUTOFMEMORY; + + hr = SmallBlockChainStream_ReadAt(stream, offset, bytesToRead, buffer, bytesRead); + + SmallBlockChainStream_Destroy(stream); + + return hr; + } + else + { + BlockChainStream *stream = NULL; + + stream = *StorageImpl_GetCachedBlockChainStream(This, index); + if (!stream) return E_OUTOFMEMORY; + + hr = BlockChainStream_ReadAt(stream, offset, bytesToRead, buffer, bytesRead); + + return hr; + } +} + +static HRESULT StorageImpl_StreamSetSize(StorageBaseImpl *base, DirRef index, + ULARGE_INTEGER newsize) +{ + StorageImpl *This = (StorageImpl*)base; + DirEntry data; + HRESULT hr; + SmallBlockChainStream *smallblock=NULL; + BlockChainStream **pbigblock=NULL, *bigblock=NULL; + + hr = StorageImpl_ReadDirEntry(This, index, &data); + if (FAILED(hr)) return hr; + + /* In simple mode keep the stream size above the small block limit */ + if (This->base.openFlags & STGM_SIMPLE) + newsize.QuadPart = max(newsize.QuadPart, LIMIT_TO_USE_SMALL_BLOCK); + + if (data.size.QuadPart == newsize.QuadPart) + return S_OK; + + /* Create a block chain object of the appropriate type */ + if (data.size.QuadPart == 0) + { + if (newsize.QuadPart < LIMIT_TO_USE_SMALL_BLOCK) + { + smallblock = SmallBlockChainStream_Construct(This, NULL, index); + if (!smallblock) return E_OUTOFMEMORY; + } + else + { + pbigblock = StorageImpl_GetCachedBlockChainStream(This, index); + bigblock = *pbigblock; + if (!bigblock) return E_OUTOFMEMORY; + } + } + else if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK) + { + smallblock = SmallBlockChainStream_Construct(This, NULL, index); + if (!smallblock) return E_OUTOFMEMORY; + } + else + { + pbigblock = StorageImpl_GetCachedBlockChainStream(This, index); + bigblock = *pbigblock; + if (!bigblock) return E_OUTOFMEMORY; + } + + /* Change the block chain type if necessary. */ + if (smallblock && newsize.QuadPart >= LIMIT_TO_USE_SMALL_BLOCK) + { + bigblock = Storage32Impl_SmallBlocksToBigBlocks(This, &smallblock); + if (!bigblock) + { + SmallBlockChainStream_Destroy(smallblock); + return E_FAIL; + } + + pbigblock = StorageImpl_GetFreeBlockChainCacheEntry(This); + *pbigblock = bigblock; + } + else if (bigblock && newsize.QuadPart < LIMIT_TO_USE_SMALL_BLOCK) + { + smallblock = Storage32Impl_BigBlocksToSmallBlocks(This, pbigblock); + if (!smallblock) + return E_FAIL; + } + + /* Set the size of the block chain. */ + if (smallblock) + { + SmallBlockChainStream_SetSize(smallblock, newsize); + SmallBlockChainStream_Destroy(smallblock); + } + else + { + BlockChainStream_SetSize(bigblock, newsize); + } + + /* Set the size in the directory entry. */ + hr = StorageImpl_ReadDirEntry(This, index, &data); + if (SUCCEEDED(hr)) + { + data.size = newsize; + + hr = StorageImpl_WriteDirEntry(This, index, &data); + } + return hr; +} + +static HRESULT StorageImpl_StreamWriteAt(StorageBaseImpl *base, DirRef index, + ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten) +{ + StorageImpl *This = (StorageImpl*)base; + DirEntry data; + HRESULT hr; + ULARGE_INTEGER newSize; + + hr = StorageImpl_ReadDirEntry(This, index, &data); + if (FAILED(hr)) return hr; + + /* Grow the stream if necessary */ + newSize.QuadPart = 0; + newSize.QuadPart = offset.QuadPart + size; + + if (newSize.QuadPart > data.size.QuadPart) + { + hr = StorageImpl_StreamSetSize(base, index, newSize); + if (FAILED(hr)) + return hr; + + hr = StorageImpl_ReadDirEntry(This, index, &data); + if (FAILED(hr)) return hr; + } + + if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK) + { + SmallBlockChainStream *stream; + + stream = SmallBlockChainStream_Construct(This, NULL, index); + if (!stream) return E_OUTOFMEMORY; + + hr = SmallBlockChainStream_WriteAt(stream, offset, size, buffer, bytesWritten); + + SmallBlockChainStream_Destroy(stream); + + return hr; + } + else + { + BlockChainStream *stream; + + stream = *StorageImpl_GetCachedBlockChainStream(This, index); + if (!stream) return E_OUTOFMEMORY; + + hr = BlockChainStream_WriteAt(stream, offset, size, buffer, bytesWritten); + + return hr; + } +} + /* * Virtual function table for the IStorage32Impl class. */ @@ -2377,62 +2535,87 @@ static const IStorageVtbl Storage32Impl_Vtbl = StorageBaseImpl_Release, StorageBaseImpl_CreateStream, StorageBaseImpl_OpenStream, - StorageImpl_CreateStorage, + StorageBaseImpl_CreateStorage, StorageBaseImpl_OpenStorage, - StorageImpl_CopyTo, - StorageImpl_MoveElementTo, + StorageBaseImpl_CopyTo, + StorageBaseImpl_MoveElementTo, StorageImpl_Commit, StorageImpl_Revert, StorageBaseImpl_EnumElements, - StorageImpl_DestroyElement, + StorageBaseImpl_DestroyElement, StorageBaseImpl_RenameElement, - StorageImpl_SetElementTimes, + StorageBaseImpl_SetElementTimes, StorageBaseImpl_SetClass, - StorageImpl_SetStateBits, - StorageImpl_Stat + StorageBaseImpl_SetStateBits, + StorageBaseImpl_Stat +}; + +static const StorageBaseImplVtbl StorageImpl_BaseVtbl = +{ + StorageImpl_Destroy, + StorageImpl_Invalidate, + StorageImpl_CreateDirEntry, + StorageImpl_BaseWriteDirEntry, + StorageImpl_BaseReadDirEntry, + StorageImpl_DestroyDirEntry, + StorageImpl_StreamReadAt, + StorageImpl_StreamWriteAt, + StorageImpl_StreamSetSize }; static HRESULT StorageImpl_Construct( - StorageImpl* This, HANDLE hFile, LPCOLESTR pwcsName, ILockBytes* pLkbyt, DWORD openFlags, BOOL fileBased, - BOOL create) + BOOL create, + StorageImpl** result) { + StorageImpl* This; HRESULT hr = S_OK; - StgProperty currentProperty; - BOOL readSuccessful; - ULONG currentPropertyIndex; + DirEntry currentEntry; + DirRef currentEntryRef; + WCHAR fullpath[MAX_PATH]; if ( FAILED( validateSTGM(openFlags) )) return STG_E_INVALIDFLAG; + This = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); + if (!This) + return E_OUTOFMEMORY; + memset(This, 0, sizeof(StorageImpl)); list_init(&This->base.strmHead); + list_init(&This->base.storageHead); + This->base.lpVtbl = &Storage32Impl_Vtbl; This->base.pssVtbl = &IPropertySetStorage_Vtbl; - This->base.v_destructor = StorageImpl_Destroy; + This->base.baseVtbl = &StorageImpl_BaseVtbl; This->base.openFlags = (openFlags & ~STGM_CREATE); - This->create = create; + This->base.ref = 1; + This->base.create = create; - /* - * This is the top-level storage so initialize the ancestor pointer - * to this. - */ - This->base.ancestorStorage = This; + This->base.reverted = 0; This->hFile = hFile; if(pwcsName) { + if (!GetFullPathNameW(pwcsName, MAX_PATH, fullpath, NULL)) + { + lstrcpynW(fullpath, pwcsName, MAX_PATH); + } This->pwcsName = HeapAlloc(GetProcessHeap(), 0, - (lstrlenW(pwcsName)+1)*sizeof(WCHAR)); + (lstrlenW(fullpath)+1)*sizeof(WCHAR)); if (!This->pwcsName) - return STG_E_INSUFFICIENTMEMORY; - strcpyW(This->pwcsName, pwcsName); + { + hr = STG_E_INSUFFICIENTMEMORY; + goto end; + } + strcpyW(This->pwcsName, fullpath); + This->base.filename = This->pwcsName; } /* @@ -2447,7 +2630,10 @@ static HRESULT StorageImpl_Construct( fileBased); if (This->bigBlockFile == 0) - return E_FAIL; + { + hr = E_FAIL; + goto end; + } if (create) { @@ -2457,7 +2643,7 @@ static HRESULT StorageImpl_Construct( /* * Initialize all header variables: * - The big block depot consists of one block and it is at block 0 - * - The properties start at block 1 + * - The directory table starts at block 1 * - There is no small block depot */ memset( This->bigBlockDepotStart, @@ -2476,7 +2662,7 @@ static HRESULT StorageImpl_Construct( StorageImpl_SaveFileHeader(This); /* - * Add one block for the big block depot and one block for the properties + * Add one block for the big block depot and one block for the directory table */ size.u.HighPart = 0; size.u.LowPart = This->bigBlockSize * 3; @@ -2499,9 +2685,7 @@ static HRESULT StorageImpl_Construct( if (FAILED(hr)) { - BIGBLOCKFILE_Destructor(This->bigBlockFile); - - return hr; + goto end; } } @@ -2519,85 +2703,112 @@ static HRESULT StorageImpl_Construct( * Create the block chain abstractions. */ if(!(This->rootBlockChain = - BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL))) - return STG_E_READFAULT; + BlockChainStream_Construct(This, &This->rootStartBlock, DIRENTRY_NULL))) + { + hr = STG_E_READFAULT; + goto end; + } if(!(This->smallBlockDepotChain = BlockChainStream_Construct(This, &This->smallBlockDepotStart, - PROPERTY_NULL))) - return STG_E_READFAULT; - - /* - * Write the root property (memory only) - */ - if (create) + DIRENTRY_NULL))) { - StgProperty rootProp; - /* - * Initialize the property chain - */ - memset(&rootProp, 0, sizeof(rootProp)); - MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name, - sizeof(rootProp.name)/sizeof(WCHAR) ); - rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR); - rootProp.propertyType = PROPTYPE_ROOT; - rootProp.previousProperty = PROPERTY_NULL; - rootProp.nextProperty = PROPERTY_NULL; - rootProp.dirProperty = PROPERTY_NULL; - rootProp.startingBlock = BLOCK_END_OF_CHAIN; - rootProp.size.u.HighPart = 0; - rootProp.size.u.LowPart = 0; - - StorageImpl_WriteProperty(This, 0, &rootProp); + hr = STG_E_READFAULT; + goto end; } /* - * Find the ID of the root in the property sets. + * Write the root storage entry (memory only) */ - currentPropertyIndex = 0; + if (create) + { + DirEntry rootEntry; + /* + * Initialize the directory table + */ + memset(&rootEntry, 0, sizeof(rootEntry)); + MultiByteToWideChar( CP_ACP, 0, rootEntryName, -1, rootEntry.name, + sizeof(rootEntry.name)/sizeof(WCHAR) ); + rootEntry.sizeOfNameString = (strlenW(rootEntry.name)+1) * sizeof(WCHAR); + rootEntry.stgType = STGTY_ROOT; + rootEntry.leftChild = DIRENTRY_NULL; + rootEntry.rightChild = DIRENTRY_NULL; + rootEntry.dirRootEntry = DIRENTRY_NULL; + rootEntry.startingBlock = BLOCK_END_OF_CHAIN; + rootEntry.size.u.HighPart = 0; + rootEntry.size.u.LowPart = 0; + + StorageImpl_WriteDirEntry(This, 0, &rootEntry); + } + + /* + * Find the ID of the root storage. + */ + currentEntryRef = 0; do { - readSuccessful = StorageImpl_ReadProperty( + hr = StorageImpl_ReadDirEntry( This, - currentPropertyIndex, - ¤tProperty); + currentEntryRef, + ¤tEntry); - if (readSuccessful) + if (SUCCEEDED(hr)) { - if ( (currentProperty.sizeOfNameString != 0 ) && - (currentProperty.propertyType == PROPTYPE_ROOT) ) + if ( (currentEntry.sizeOfNameString != 0 ) && + (currentEntry.stgType == STGTY_ROOT) ) { - This->base.rootPropertySetIndex = currentPropertyIndex; + This->base.storageDirEntry = currentEntryRef; } } - currentPropertyIndex++; + currentEntryRef++; - } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) ); + } while (SUCCEEDED(hr) && (This->base.storageDirEntry == DIRENTRY_NULL) ); - if (!readSuccessful) + if (FAILED(hr)) { - /* TODO CLEANUP */ - return STG_E_READFAULT; + hr = STG_E_READFAULT; + goto end; } /* * Create the block chain abstraction for the small block root chain. */ if(!(This->smallBlockRootChain = - BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex))) - return STG_E_READFAULT; + BlockChainStream_Construct(This, NULL, This->base.storageDirEntry))) + { + hr = STG_E_READFAULT; + } + +end: + if (FAILED(hr)) + { + IStorage_Release((IStorage*)This); + *result = NULL; + } + else + *result = This; return hr; } +static void StorageImpl_Invalidate(StorageBaseImpl* iface) +{ + StorageImpl *This = (StorageImpl*) iface; + + StorageBaseImpl_DeleteAll(&This->base); + + This->base.reverted = 1; +} + static void StorageImpl_Destroy(StorageBaseImpl* iface) { StorageImpl *This = (StorageImpl*) iface; + int i; TRACE("(%p)\n", This); - StorageBaseImpl_DeleteAll(&This->base); + StorageImpl_Invalidate(iface); HeapFree(GetProcessHeap(), 0, This->pwcsName); @@ -2605,7 +2816,11 @@ static void StorageImpl_Destroy(StorageBaseImpl* iface) BlockChainStream_Destroy(This->rootBlockChain); BlockChainStream_Destroy(This->smallBlockDepotChain); - BIGBLOCKFILE_Destructor(This->bigBlockFile); + for (i=0; iblockChainCache[i]); + + if (This->bigBlockFile) + BIGBLOCKFILE_Destructor(This->bigBlockFile); HeapFree(GetProcessHeap(), 0, This); } @@ -3258,192 +3473,233 @@ static void StorageImpl_SaveFileHeader( } /****************************************************************************** - * Storage32Impl_ReadProperty + * StorageImpl_ReadRawDirEntry * - * This method will read the specified property from the property chain. + * This method will read the raw data from a directory entry in the file. + * + * buffer must be RAW_DIRENTRY_SIZE bytes long. */ -BOOL StorageImpl_ReadProperty( - StorageImpl* This, - ULONG index, - StgProperty* buffer) +HRESULT StorageImpl_ReadRawDirEntry(StorageImpl *This, ULONG index, BYTE *buffer) { - BYTE currentProperty[PROPSET_BLOCK_SIZE]; - ULARGE_INTEGER offsetInPropSet; - HRESULT readRes; - ULONG bytesRead; + ULARGE_INTEGER offset; + HRESULT hr; + ULONG bytesRead; - offsetInPropSet.u.HighPart = 0; - offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE; + offset.u.HighPart = 0; + offset.u.LowPart = index * RAW_DIRENTRY_SIZE; - readRes = BlockChainStream_ReadAt( + hr = BlockChainStream_ReadAt( This->rootBlockChain, - offsetInPropSet, - PROPSET_BLOCK_SIZE, - currentProperty, + offset, + RAW_DIRENTRY_SIZE, + buffer, &bytesRead); + return hr; +} + +/****************************************************************************** + * StorageImpl_WriteRawDirEntry + * + * This method will write the raw data from a directory entry in the file. + * + * buffer must be RAW_DIRENTRY_SIZE bytes long. + */ +HRESULT StorageImpl_WriteRawDirEntry(StorageImpl *This, ULONG index, const BYTE *buffer) +{ + ULARGE_INTEGER offset; + HRESULT hr; + ULONG bytesRead; + + offset.u.HighPart = 0; + offset.u.LowPart = index * RAW_DIRENTRY_SIZE; + + hr = BlockChainStream_WriteAt( + This->rootBlockChain, + offset, + RAW_DIRENTRY_SIZE, + buffer, + &bytesRead); + + return hr; +} + +/****************************************************************************** + * UpdateRawDirEntry + * + * Update raw directory entry data from the fields in newData. + * + * buffer must be RAW_DIRENTRY_SIZE bytes long. + */ +void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData) +{ + memset(buffer, 0, RAW_DIRENTRY_SIZE); + + memcpy( + buffer + OFFSET_PS_NAME, + newData->name, + DIRENTRY_NAME_BUFFER_LEN ); + + memcpy(buffer + OFFSET_PS_STGTYPE, &newData->stgType, 1); + + StorageUtl_WriteWord( + buffer, + OFFSET_PS_NAMELENGTH, + newData->sizeOfNameString); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_LEFTCHILD, + newData->leftChild); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_RIGHTCHILD, + newData->rightChild); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_DIRROOT, + newData->dirRootEntry); + + StorageUtl_WriteGUID( + buffer, + OFFSET_PS_GUID, + &newData->clsid); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_CTIMELOW, + newData->ctime.dwLowDateTime); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_CTIMEHIGH, + newData->ctime.dwHighDateTime); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_MTIMELOW, + newData->mtime.dwLowDateTime); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_MTIMEHIGH, + newData->ctime.dwHighDateTime); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_STARTBLOCK, + newData->startingBlock); + + StorageUtl_WriteDWord( + buffer, + OFFSET_PS_SIZE, + newData->size.u.LowPart); +} + +/****************************************************************************** + * Storage32Impl_ReadDirEntry + * + * This method will read the specified directory entry. + */ +HRESULT StorageImpl_ReadDirEntry( + StorageImpl* This, + DirRef index, + DirEntry* buffer) +{ + BYTE currentEntry[RAW_DIRENTRY_SIZE]; + HRESULT readRes; + + readRes = StorageImpl_ReadRawDirEntry(This, index, currentEntry); + if (SUCCEEDED(readRes)) { - /* replace the name of root entry (often "Root Entry") by the file name */ - WCHAR *propName = (index == This->base.rootPropertySetIndex) ? - This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME; - memset(buffer->name, 0, sizeof(buffer->name)); memcpy( buffer->name, - propName, - PROPERTY_NAME_BUFFER_LEN ); + (WCHAR *)currentEntry+OFFSET_PS_NAME, + DIRENTRY_NAME_BUFFER_LEN ); TRACE("storage name: %s\n", debugstr_w(buffer->name)); - memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1); + memcpy(&buffer->stgType, currentEntry + OFFSET_PS_STGTYPE, 1); StorageUtl_ReadWord( - currentProperty, + currentEntry, OFFSET_PS_NAMELENGTH, &buffer->sizeOfNameString); StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_PREVIOUSPROP, - &buffer->previousProperty); + currentEntry, + OFFSET_PS_LEFTCHILD, + &buffer->leftChild); StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_NEXTPROP, - &buffer->nextProperty); + currentEntry, + OFFSET_PS_RIGHTCHILD, + &buffer->rightChild); StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_DIRPROP, - &buffer->dirProperty); + currentEntry, + OFFSET_PS_DIRROOT, + &buffer->dirRootEntry); StorageUtl_ReadGUID( - currentProperty, + currentEntry, OFFSET_PS_GUID, - &buffer->propertyUniqueID); + &buffer->clsid); StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_TSS1, - &buffer->timeStampS1); + currentEntry, + OFFSET_PS_CTIMELOW, + &buffer->ctime.dwLowDateTime); StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_TSD1, - &buffer->timeStampD1); + currentEntry, + OFFSET_PS_CTIMEHIGH, + &buffer->ctime.dwHighDateTime); StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_TSS2, - &buffer->timeStampS2); + currentEntry, + OFFSET_PS_MTIMELOW, + &buffer->mtime.dwLowDateTime); StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_TSD2, - &buffer->timeStampD2); + currentEntry, + OFFSET_PS_MTIMEHIGH, + &buffer->mtime.dwHighDateTime); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_STARTBLOCK, &buffer->startingBlock); StorageUtl_ReadDWord( - currentProperty, + currentEntry, OFFSET_PS_SIZE, &buffer->size.u.LowPart); buffer->size.u.HighPart = 0; } - return SUCCEEDED(readRes) ? TRUE : FALSE; + return readRes; } /********************************************************************* - * Write the specified property into the property chain + * Write the specified directory entry to the file */ -BOOL StorageImpl_WriteProperty( +HRESULT StorageImpl_WriteDirEntry( StorageImpl* This, - ULONG index, - const StgProperty* buffer) + DirRef index, + const DirEntry* buffer) { - BYTE currentProperty[PROPSET_BLOCK_SIZE]; - ULARGE_INTEGER offsetInPropSet; + BYTE currentEntry[RAW_DIRENTRY_SIZE]; HRESULT writeRes; - ULONG bytesWritten; - offsetInPropSet.u.HighPart = 0; - offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE; + UpdateRawDirEntry(currentEntry, buffer); - memset(currentProperty, 0, PROPSET_BLOCK_SIZE); - - memcpy( - currentProperty + OFFSET_PS_NAME, - buffer->name, - PROPERTY_NAME_BUFFER_LEN ); - - memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1); - - StorageUtl_WriteWord( - currentProperty, - OFFSET_PS_NAMELENGTH, - buffer->sizeOfNameString); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_PREVIOUSPROP, - buffer->previousProperty); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_NEXTPROP, - buffer->nextProperty); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_DIRPROP, - buffer->dirProperty); - - StorageUtl_WriteGUID( - currentProperty, - OFFSET_PS_GUID, - &buffer->propertyUniqueID); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_TSS1, - buffer->timeStampS1); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_TSD1, - buffer->timeStampD1); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_TSS2, - buffer->timeStampS2); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_TSD2, - buffer->timeStampD2); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_STARTBLOCK, - buffer->startingBlock); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_SIZE, - buffer->size.u.LowPart); - - writeRes = BlockChainStream_WriteAt(This->rootBlockChain, - offsetInPropSet, - PROPSET_BLOCK_SIZE, - currentProperty, - &bytesWritten); - return SUCCEEDED(writeRes) ? TRUE : FALSE; + writeRes = StorageImpl_WriteRawDirEntry(This, index, currentEntry); + return writeRes; } static BOOL StorageImpl_ReadBigBlock( @@ -3527,22 +3783,22 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( ULARGE_INTEGER size, offset; ULONG cbRead, cbWritten; ULARGE_INTEGER cbTotalRead; - ULONG propertyIndex; + DirRef streamEntryRef; HRESULT resWrite = S_OK; HRESULT resRead; - StgProperty chainProperty; + DirEntry streamEntry; BYTE *buffer; BlockChainStream *bbTempChain = NULL; BlockChainStream *bigBlockChain = NULL; /* * Create a temporary big block chain that doesn't have - * an associated property. This temporary chain will be + * an associated directory entry. This temporary chain will be * used to copy data from small blocks to big blocks. */ bbTempChain = BlockChainStream_Construct(This, &bbHeadOfChain, - PROPERTY_NULL); + DIRENTRY_NULL); if(!bbTempChain) return NULL; /* * Grow the big block chain. @@ -3601,29 +3857,29 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( /* * Destroy the small block chain. */ - propertyIndex = (*ppsbChain)->ownerPropertyIndex; + streamEntryRef = (*ppsbChain)->ownerDirEntry; SmallBlockChainStream_SetSize(*ppsbChain, size); SmallBlockChainStream_Destroy(*ppsbChain); *ppsbChain = 0; /* - * Change the property information. This chain is now a big block chain + * Change the directory entry. This chain is now a big block chain * and it doesn't reside in the small blocks chain anymore. */ - StorageImpl_ReadProperty(This, propertyIndex, &chainProperty); + StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry); - chainProperty.startingBlock = bbHeadOfChain; + streamEntry.startingBlock = bbHeadOfChain; - StorageImpl_WriteProperty(This, propertyIndex, &chainProperty); + StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry); /* - * Destroy the temporary propertyless big block chain. - * Create a new big block chain associated with this property. + * Destroy the temporary entryless big block chain. + * Create a new big block chain associated with this entry. */ BlockChainStream_Destroy(bbTempChain); bigBlockChain = BlockChainStream_Construct(This, NULL, - propertyIndex); + streamEntryRef); return bigBlockChain; } @@ -3639,16 +3895,17 @@ SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks( BlockChainStream** ppbbChain) { ULARGE_INTEGER size, offset, cbTotalRead; - ULONG cbRead, cbWritten, propertyIndex, sbHeadOfChain = BLOCK_END_OF_CHAIN; + ULONG cbRead, cbWritten, sbHeadOfChain = BLOCK_END_OF_CHAIN; + DirRef streamEntryRef; HRESULT resWrite = S_OK, resRead; - StgProperty chainProperty; + DirEntry streamEntry; BYTE* buffer; SmallBlockChainStream* sbTempChain; TRACE("%p %p\n", This, ppbbChain); sbTempChain = SmallBlockChainStream_Construct(This, &sbHeadOfChain, - PROPERTY_NULL); + DIRENTRY_NULL); if(!sbTempChain) return NULL; @@ -3696,38 +3953,491 @@ SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks( } /* destroy the original big block chain */ - propertyIndex = (*ppbbChain)->ownerPropertyIndex; + streamEntryRef = (*ppbbChain)->ownerDirEntry; BlockChainStream_SetSize(*ppbbChain, size); BlockChainStream_Destroy(*ppbbChain); *ppbbChain = NULL; - StorageImpl_ReadProperty(This, propertyIndex, &chainProperty); - chainProperty.startingBlock = sbHeadOfChain; - StorageImpl_WriteProperty(This, propertyIndex, &chainProperty); + StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry); + streamEntry.startingBlock = sbHeadOfChain; + StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry); SmallBlockChainStream_Destroy(sbTempChain); - return SmallBlockChainStream_Construct(This, NULL, propertyIndex); + return SmallBlockChainStream_Construct(This, NULL, streamEntryRef); +} + +static HRESULT CreateSnapshotFile(StorageBaseImpl* original, StorageBaseImpl **snapshot) +{ + HRESULT hr; + DirEntry parentData, snapshotData; + + hr = StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_DELETEONRELEASE, + 0, (IStorage**)snapshot); + + if (SUCCEEDED(hr)) + { + hr = StorageBaseImpl_ReadDirEntry(original, + original->storageDirEntry, &parentData); + + if (SUCCEEDED(hr)) + hr = StorageBaseImpl_ReadDirEntry((*snapshot), + (*snapshot)->storageDirEntry, &snapshotData); + + if (SUCCEEDED(hr)) + { + memcpy(snapshotData.name, parentData.name, sizeof(snapshotData.name)); + snapshotData.sizeOfNameString = parentData.sizeOfNameString; + snapshotData.stgType = parentData.stgType; + snapshotData.clsid = parentData.clsid; + snapshotData.ctime = parentData.ctime; + snapshotData.mtime = parentData.mtime; + hr = StorageBaseImpl_WriteDirEntry((*snapshot), + (*snapshot)->storageDirEntry, &snapshotData); + } + + if (SUCCEEDED(hr)) + hr = IStorage_CopyTo((IStorage*)original, 0, NULL, NULL, + (IStorage*)(*snapshot)); + + if (FAILED(hr)) IStorage_Release((IStorage*)(*snapshot)); + } + + return hr; +} + +static HRESULT WINAPI TransactedSnapshotImpl_Commit( + IStorage* iface, + DWORD grfCommitFlags) /* [in] */ +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface; + HRESULT hr; + DirEntry data, tempStorageData, snapshotRootData; + DirRef tempStorageEntry, oldDirRoot; + StorageInternalImpl *tempStorage; + + TRACE("(%p,%x)\n", iface, grfCommitFlags); + + /* Cannot commit a read-only transacted storage */ + if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ ) + return STG_E_ACCESSDENIED; + + /* To prevent data loss, we create the new structure in the file before we + * delete the old one, so that in case of errors the old data is intact. We + * shouldn't do this if STGC_OVERWRITE is set, but that flag should only be + * needed in the rare situation where we have just enough free disk space to + * overwrite the existing data. */ + + /* Create an orphaned storage in the parent for the new directory structure. */ + memset(&data, 0, sizeof(data)); + data.name[0] = 'D'; + data.sizeOfNameString = 1; + data.stgType = STGTY_STORAGE; + data.leftChild = DIRENTRY_NULL; + data.rightChild = DIRENTRY_NULL; + data.dirRootEntry = DIRENTRY_NULL; + hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &data, &tempStorageEntry); + + if (FAILED(hr)) return hr; + + tempStorage = StorageInternalImpl_Construct(This->transactedParent, + STGM_READWRITE|STGM_SHARE_EXCLUSIVE, tempStorageEntry); + if (tempStorage) + { + hr = IStorage_CopyTo((IStorage*)This->snapshot, 0, NULL, NULL, + (IStorage*)tempStorage); + + list_init(&tempStorage->ParentListEntry); + + IStorage_Release((IStorage*) tempStorage); + } + else + hr = E_OUTOFMEMORY; + + if (FAILED(hr)) + { + DestroyReachableEntries(This->transactedParent, tempStorageEntry); + return hr; + } + + /* Update the storage to use the new data in one step. */ + hr = StorageBaseImpl_ReadDirEntry(This->transactedParent, + This->transactedParent->storageDirEntry, &data); + + if (SUCCEEDED(hr)) + { + hr = StorageBaseImpl_ReadDirEntry(This->transactedParent, + tempStorageEntry, &tempStorageData); + } + + if (SUCCEEDED(hr)) + { + hr = StorageBaseImpl_ReadDirEntry(This->snapshot, + This->snapshot->storageDirEntry, &snapshotRootData); + } + + if (SUCCEEDED(hr)) + { + oldDirRoot = data.dirRootEntry; + data.dirRootEntry = tempStorageData.dirRootEntry; + data.clsid = snapshotRootData.clsid; + data.ctime = snapshotRootData.ctime; + data.mtime = snapshotRootData.mtime; + + hr = StorageBaseImpl_WriteDirEntry(This->transactedParent, + This->transactedParent->storageDirEntry, &data); + } + + if (SUCCEEDED(hr)) + { + /* Destroy the old now-orphaned data. */ + DestroyReachableEntries(This->transactedParent, oldDirRoot); + StorageBaseImpl_DestroyDirEntry(This->transactedParent, tempStorageEntry); + } + else + { + DestroyReachableEntries(This->transactedParent, tempStorageEntry); + } + + return hr; +} + +static HRESULT WINAPI TransactedSnapshotImpl_Revert( + IStorage* iface) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface; + StorageBaseImpl *newSnapshot; + HRESULT hr; + + TRACE("(%p)\n", iface); + + /* Create a new copy of the parent data. */ + hr = CreateSnapshotFile(This->transactedParent, &newSnapshot); + if (FAILED(hr)) return hr; + + /* Destroy the open objects. */ + StorageBaseImpl_DeleteAll(&This->base); + + /* Replace our current snapshot. */ + IStorage_Release((IStorage*)This->snapshot); + This->snapshot = newSnapshot; + + return S_OK; +} + +static void TransactedSnapshotImpl_Invalidate(StorageBaseImpl* This) +{ + if (!This->reverted) + { + TRACE("Storage invalidated (stg=%p)\n", This); + + This->reverted = 1; + + StorageBaseImpl_DeleteAll(This); + } +} + +static void TransactedSnapshotImpl_Destroy( StorageBaseImpl *iface) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface; + + TransactedSnapshotImpl_Invalidate(iface); + + IStorage_Release((IStorage*)This->transactedParent); + + IStorage_Release((IStorage*)This->snapshot); + + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT TransactedSnapshotImpl_CreateDirEntry(StorageBaseImpl *base, + const DirEntry *newData, DirRef *index) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; + + return StorageBaseImpl_CreateDirEntry(This->snapshot, + newData, index); +} + +static HRESULT TransactedSnapshotImpl_WriteDirEntry(StorageBaseImpl *base, + DirRef index, const DirEntry *data) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; + + return StorageBaseImpl_WriteDirEntry(This->snapshot, + index, data); +} + +static HRESULT TransactedSnapshotImpl_ReadDirEntry(StorageBaseImpl *base, + DirRef index, DirEntry *data) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; + + return StorageBaseImpl_ReadDirEntry(This->snapshot, + index, data); +} + +static HRESULT TransactedSnapshotImpl_DestroyDirEntry(StorageBaseImpl *base, + DirRef index) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; + + return StorageBaseImpl_DestroyDirEntry(This->snapshot, + index); +} + +static HRESULT TransactedSnapshotImpl_StreamReadAt(StorageBaseImpl *base, + DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; + + return StorageBaseImpl_StreamReadAt(This->snapshot, + index, offset, size, buffer, bytesRead); +} + +static HRESULT TransactedSnapshotImpl_StreamWriteAt(StorageBaseImpl *base, + DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; + + return StorageBaseImpl_StreamWriteAt(This->snapshot, + index, offset, size, buffer, bytesWritten); +} + +static HRESULT TransactedSnapshotImpl_StreamSetSize(StorageBaseImpl *base, + DirRef index, ULARGE_INTEGER newsize) +{ + TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base; + + return StorageBaseImpl_StreamSetSize(This->snapshot, + index, newsize); +} + +static const IStorageVtbl TransactedSnapshotImpl_Vtbl = +{ + StorageBaseImpl_QueryInterface, + StorageBaseImpl_AddRef, + StorageBaseImpl_Release, + StorageBaseImpl_CreateStream, + StorageBaseImpl_OpenStream, + StorageBaseImpl_CreateStorage, + StorageBaseImpl_OpenStorage, + StorageBaseImpl_CopyTo, + StorageBaseImpl_MoveElementTo, + TransactedSnapshotImpl_Commit, + TransactedSnapshotImpl_Revert, + StorageBaseImpl_EnumElements, + StorageBaseImpl_DestroyElement, + StorageBaseImpl_RenameElement, + StorageBaseImpl_SetElementTimes, + StorageBaseImpl_SetClass, + StorageBaseImpl_SetStateBits, + StorageBaseImpl_Stat +}; + +static const StorageBaseImplVtbl TransactedSnapshotImpl_BaseVtbl = +{ + TransactedSnapshotImpl_Destroy, + TransactedSnapshotImpl_Invalidate, + TransactedSnapshotImpl_CreateDirEntry, + TransactedSnapshotImpl_WriteDirEntry, + TransactedSnapshotImpl_ReadDirEntry, + TransactedSnapshotImpl_DestroyDirEntry, + TransactedSnapshotImpl_StreamReadAt, + TransactedSnapshotImpl_StreamWriteAt, + TransactedSnapshotImpl_StreamSetSize +}; + +static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage, + TransactedSnapshotImpl** result) +{ + HRESULT hr; + + *result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedSnapshotImpl)); + if (*result) + { + (*result)->base.lpVtbl = &TransactedSnapshotImpl_Vtbl; + + /* This is OK because the property set storage functions use the IStorage functions. */ + (*result)->base.pssVtbl = parentStorage->pssVtbl; + + (*result)->base.baseVtbl = &TransactedSnapshotImpl_BaseVtbl; + + list_init(&(*result)->base.strmHead); + + list_init(&(*result)->base.storageHead); + + (*result)->base.ref = 1; + + (*result)->base.openFlags = parentStorage->openFlags; + + (*result)->base.filename = parentStorage->filename; + + /* Create a new temporary storage to act as the snapshot */ + hr = CreateSnapshotFile(parentStorage, &(*result)->snapshot); + + if (SUCCEEDED(hr)) + { + (*result)->base.storageDirEntry = (*result)->snapshot->storageDirEntry; + + /* parentStorage already has 1 reference, which we take over here. */ + (*result)->transactedParent = parentStorage; + + parentStorage->transactedChild = (StorageBaseImpl*)*result; + } + + if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, (*result)); + + return hr; + } + else + return E_OUTOFMEMORY; +} + +static HRESULT Storage_ConstructTransacted(StorageBaseImpl *parentStorage, + StorageBaseImpl** result) +{ + static int fixme=0; + + if (parentStorage->openFlags & (STGM_NOSCRATCH|STGM_NOSNAPSHOT) && !fixme++) + { + FIXME("Unimplemented flags %x\n", parentStorage->openFlags); + } + + return TransactedSnapshotImpl_Construct(parentStorage, + (TransactedSnapshotImpl**)result); +} + +static HRESULT Storage_Construct( + HANDLE hFile, + LPCOLESTR pwcsName, + ILockBytes* pLkbyt, + DWORD openFlags, + BOOL fileBased, + BOOL create, + StorageBaseImpl** result) +{ + StorageImpl *newStorage; + StorageBaseImpl *newTransactedStorage; + HRESULT hr; + + hr = StorageImpl_Construct(hFile, pwcsName, pLkbyt, openFlags, fileBased, create, &newStorage); + if (FAILED(hr)) goto end; + + if (openFlags & STGM_TRANSACTED) + { + hr = Storage_ConstructTransacted(&newStorage->base, &newTransactedStorage); + if (FAILED(hr)) + IStorage_Release((IStorage*)newStorage); + else + *result = newTransactedStorage; + } + else + *result = &newStorage->base; + +end: + return hr; +} + +static void StorageInternalImpl_Invalidate( StorageBaseImpl *base ) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + if (!This->base.reverted) + { + TRACE("Storage invalidated (stg=%p)\n", This); + + This->base.reverted = 1; + + This->parentStorage = NULL; + + StorageBaseImpl_DeleteAll(&This->base); + + list_remove(&This->ParentListEntry); + } } static void StorageInternalImpl_Destroy( StorageBaseImpl *iface) { StorageInternalImpl* This = (StorageInternalImpl*) iface; - StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage); + StorageInternalImpl_Invalidate(&This->base); + HeapFree(GetProcessHeap(), 0, This); } +static HRESULT StorageInternalImpl_CreateDirEntry(StorageBaseImpl *base, + const DirEntry *newData, DirRef *index) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + return StorageBaseImpl_CreateDirEntry(This->parentStorage, + newData, index); +} + +static HRESULT StorageInternalImpl_WriteDirEntry(StorageBaseImpl *base, + DirRef index, const DirEntry *data) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + return StorageBaseImpl_WriteDirEntry(This->parentStorage, + index, data); +} + +static HRESULT StorageInternalImpl_ReadDirEntry(StorageBaseImpl *base, + DirRef index, DirEntry *data) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + return StorageBaseImpl_ReadDirEntry(This->parentStorage, + index, data); +} + +static HRESULT StorageInternalImpl_DestroyDirEntry(StorageBaseImpl *base, + DirRef index) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + return StorageBaseImpl_DestroyDirEntry(This->parentStorage, + index); +} + +static HRESULT StorageInternalImpl_StreamReadAt(StorageBaseImpl *base, + DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + return StorageBaseImpl_StreamReadAt(This->parentStorage, + index, offset, size, buffer, bytesRead); +} + +static HRESULT StorageInternalImpl_StreamWriteAt(StorageBaseImpl *base, + DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + return StorageBaseImpl_StreamWriteAt(This->parentStorage, + index, offset, size, buffer, bytesWritten); +} + +static HRESULT StorageInternalImpl_StreamSetSize(StorageBaseImpl *base, + DirRef index, ULARGE_INTEGER newsize) +{ + StorageInternalImpl* This = (StorageInternalImpl*) base; + + return StorageBaseImpl_StreamSetSize(This->parentStorage, + index, newsize); +} + /****************************************************************************** ** ** Storage32InternalImpl_Commit ** -** The non-root storages cannot be opened in transacted mode thus this function -** does nothing. */ static HRESULT WINAPI StorageInternalImpl_Commit( IStorage* iface, DWORD grfCommitFlags) /* [in] */ { + FIXME("(%p,%x): stub\n", iface, grfCommitFlags); return S_OK; } @@ -3735,19 +4445,17 @@ static HRESULT WINAPI StorageInternalImpl_Commit( ** ** Storage32InternalImpl_Revert ** -** The non-root storages cannot be opened in transacted mode thus this function -** does nothing. */ static HRESULT WINAPI StorageInternalImpl_Revert( IStorage* iface) { + FIXME("(%p): stub\n", iface); return S_OK; } static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This) { IStorage_Release((IStorage*)This->parentStorage); - HeapFree(GetProcessHeap(), 0, This->stackToVisit); HeapFree(GetProcessHeap(), 0, This); } @@ -3758,20 +4466,11 @@ static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface( { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - /* - * Perform a sanity check on the parameters. - */ if (ppvObject==0) return E_INVALIDARG; - /* - * Initialize the return parameter. - */ *ppvObject = 0; - /* - * Compare the riid with the interface IDs implemented by this object. - */ if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IEnumSTATSTG, riid)) { @@ -3799,9 +4498,6 @@ static ULONG WINAPI IEnumSTATSTGImpl_Release( newRef = InterlockedDecrement(&This->ref); - /* - * If the reference count goes down to 0, perform suicide. - */ if (newRef==0) { IEnumSTATSTGImpl_Destroy(This); @@ -3810,6 +4506,51 @@ static ULONG WINAPI IEnumSTATSTGImpl_Release( return newRef; } +static HRESULT IEnumSTATSTGImpl_GetNextRef( + IEnumSTATSTGImpl* This, + DirRef *ref) +{ + DirRef result = DIRENTRY_NULL; + DirRef searchNode; + DirEntry entry; + HRESULT hr; + WCHAR result_name[DIRENTRY_NAME_MAX_LEN]; + + hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, + This->parentStorage->storageDirEntry, &entry); + searchNode = entry.dirRootEntry; + + while (SUCCEEDED(hr) && searchNode != DIRENTRY_NULL) + { + hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, searchNode, &entry); + + if (SUCCEEDED(hr)) + { + LONG diff = entryNameCmp( entry.name, This->name); + + if (diff <= 0) + { + searchNode = entry.rightChild; + } + else + { + result = searchNode; + memcpy(result_name, entry.name, sizeof(result_name)); + searchNode = entry.leftChild; + } + } + } + + if (SUCCEEDED(hr)) + { + *ref = result; + if (result != DIRENTRY_NULL) + memcpy(This->name, result_name, sizeof(result_name)); + } + + return hr; +} + static HRESULT WINAPI IEnumSTATSTGImpl_Next( IEnumSTATSTG* iface, ULONG celt, @@ -3818,17 +4559,18 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Next( { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - StgProperty currentProperty; + DirEntry currentEntry; STATSTG* currentReturnStruct = rgelt; ULONG objectFetched = 0; - ULONG currentSearchNode; + DirRef currentSearchNode; + HRESULT hr=S_OK; - /* - * Perform a sanity check on the parameters. - */ if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) ) return E_INVALIDARG; + if (This->parentStorage->reverted) + return STG_E_REVERTED; + /* * To avoid the special case, get another pointer to a ULONG value if * the caller didn't supply one. @@ -3842,31 +4584,26 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Next( */ *pceltFetched = 0; - /* - * Start with the node at the top of the stack. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - - while ( ( *pceltFetched < celt) && - ( currentSearchNode!=PROPERTY_NULL) ) + while ( *pceltFetched < celt ) { - /* - * Remove the top node from the stack - */ - IEnumSTATSTGImpl_PopSearchNode(This, TRUE); + hr = IEnumSTATSTGImpl_GetNextRef(This, ¤tSearchNode); + + if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL) + break; /* - * Read the property from the storage. + * Read the entry from the storage. */ - StorageImpl_ReadProperty(This->parentStorage, + StorageBaseImpl_ReadDirEntry(This->parentStorage, currentSearchNode, - ¤tProperty); + ¤tEntry); /* * Copy the information to the return buffer. */ - StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct, - ¤tProperty, + StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage, + currentReturnStruct, + ¤tEntry, STATFLAG_DEFAULT); /* @@ -3874,22 +4611,12 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Next( */ (*pceltFetched)++; currentReturnStruct++; - - /* - * Push the next search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty); - - /* - * continue the iteration. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); } - if (*pceltFetched == celt) - return S_OK; + if (SUCCEEDED(hr) && *pceltFetched != celt) + hr = S_FALSE; - return S_FALSE; + return hr; } @@ -3899,50 +4626,27 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Skip( { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - StgProperty currentProperty; ULONG objectFetched = 0; - ULONG currentSearchNode; + DirRef currentSearchNode; + HRESULT hr=S_OK; - /* - * Start with the node at the top of the stack. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + if (This->parentStorage->reverted) + return STG_E_REVERTED; - while ( (objectFetched < celt) && - (currentSearchNode!=PROPERTY_NULL) ) + while ( (objectFetched < celt) ) { - /* - * Remove the top node from the stack - */ - IEnumSTATSTGImpl_PopSearchNode(This, TRUE); + hr = IEnumSTATSTGImpl_GetNextRef(This, ¤tSearchNode); - /* - * Read the property from the storage. - */ - StorageImpl_ReadProperty(This->parentStorage, - currentSearchNode, - ¤tProperty); + if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL) + break; - /* - * Step to the next item in the iteration - */ objectFetched++; - - /* - * Push the next search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty); - - /* - * continue the iteration. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); } - if (objectFetched == celt) - return S_OK; + if (SUCCEEDED(hr) && objectFetched != celt) + return S_FALSE; - return S_FALSE; + return hr; } static HRESULT WINAPI IEnumSTATSTGImpl_Reset( @@ -3950,31 +4654,10 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Reset( { IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - StgProperty rootProperty; - BOOL readSuccessful; + if (This->parentStorage->reverted) + return STG_E_REVERTED; - /* - * Re-initialize the search stack to an empty stack - */ - This->stackSize = 0; - - /* - * Read the root property from the storage. - */ - readSuccessful = StorageImpl_ReadProperty( - This->parentStorage, - This->firstPropertyNode, - &rootProperty); - - if (readSuccessful) - { - assert(rootProperty.sizeOfNameString!=0); - - /* - * Push the search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty); - } + This->name[0] = 0; return S_OK; } @@ -3987,6 +4670,9 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Clone( IEnumSTATSTGImpl* newClone; + if (This->parentStorage->reverted) + return STG_E_REVERTED; + /* * Perform a sanity check on the parameters. */ @@ -3994,22 +4680,14 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Clone( return E_INVALIDARG; newClone = IEnumSTATSTGImpl_Construct(This->parentStorage, - This->firstPropertyNode); + This->storageDirEntry); /* * The new clone enumeration must point to the same current node as * the ole one. */ - newClone->stackSize = This->stackSize ; - newClone->stackMaxSize = This->stackMaxSize ; - newClone->stackToVisit = - HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize); - - memcpy( - newClone->stackToVisit, - This->stackToVisit, - sizeof(ULONG) * newClone->stackSize); + memcpy(newClone->name, This->name, sizeof(newClone->name)); *ppenum = (IEnumSTATSTG*)newClone; @@ -4022,180 +4700,6 @@ static HRESULT WINAPI IEnumSTATSTGImpl_Clone( return S_OK; } -static INT IEnumSTATSTGImpl_FindParentProperty( - IEnumSTATSTGImpl *This, - ULONG childProperty, - StgProperty *currentProperty, - ULONG *thisNodeId) -{ - ULONG currentSearchNode; - ULONG foundNode; - - /* - * To avoid the special case, get another pointer to a ULONG value if - * the caller didn't supply one. - */ - if (thisNodeId==0) - thisNodeId = &foundNode; - - /* - * Start with the node at the top of the stack. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - - - while (currentSearchNode!=PROPERTY_NULL) - { - /* - * Store the current node in the returned parameters - */ - *thisNodeId = currentSearchNode; - - /* - * Remove the top node from the stack - */ - IEnumSTATSTGImpl_PopSearchNode(This, TRUE); - - /* - * Read the property from the storage. - */ - StorageImpl_ReadProperty( - This->parentStorage, - currentSearchNode, - currentProperty); - - if (currentProperty->previousProperty == childProperty) - return PROPERTY_RELATION_PREVIOUS; - - else if (currentProperty->nextProperty == childProperty) - return PROPERTY_RELATION_NEXT; - - else if (currentProperty->dirProperty == childProperty) - return PROPERTY_RELATION_DIR; - - /* - * Push the next search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty); - - /* - * continue the iteration. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - } - - return PROPERTY_NULL; -} - -static ULONG IEnumSTATSTGImpl_FindProperty( - IEnumSTATSTGImpl* This, - const OLECHAR* lpszPropName, - StgProperty* currentProperty) -{ - ULONG currentSearchNode; - - /* - * Start with the node at the top of the stack. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - - while (currentSearchNode!=PROPERTY_NULL) - { - /* - * Remove the top node from the stack - */ - IEnumSTATSTGImpl_PopSearchNode(This, TRUE); - - /* - * Read the property from the storage. - */ - StorageImpl_ReadProperty(This->parentStorage, - currentSearchNode, - currentProperty); - - if (propertyNameCmp(currentProperty->name, lpszPropName) == 0) - return currentSearchNode; - - /* - * Push the next search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty); - - /* - * continue the iteration. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - } - - return PROPERTY_NULL; -} - -static void IEnumSTATSTGImpl_PushSearchNode( - IEnumSTATSTGImpl* This, - ULONG nodeToPush) -{ - StgProperty rootProperty; - BOOL readSuccessful; - - /* - * First, make sure we're not trying to push an unexisting node. - */ - if (nodeToPush==PROPERTY_NULL) - return; - - /* - * First push the node to the stack - */ - if (This->stackSize == This->stackMaxSize) - { - This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT; - - This->stackToVisit = HeapReAlloc( - GetProcessHeap(), - 0, - This->stackToVisit, - sizeof(ULONG) * This->stackMaxSize); - } - - This->stackToVisit[This->stackSize] = nodeToPush; - This->stackSize++; - - /* - * Read the root property from the storage. - */ - readSuccessful = StorageImpl_ReadProperty( - This->parentStorage, - nodeToPush, - &rootProperty); - - if (readSuccessful) - { - assert(rootProperty.sizeOfNameString!=0); - - /* - * Push the previous search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty); - } -} - -static ULONG IEnumSTATSTGImpl_PopSearchNode( - IEnumSTATSTGImpl* This, - BOOL remove) -{ - ULONG topNode; - - if (This->stackSize == 0) - return PROPERTY_NULL; - - topNode = This->stackToVisit[This->stackSize-1]; - - if (remove) - This->stackSize--; - - return topNode; -} - /* * Virtual function table for the IEnumSTATSTGImpl class. */ @@ -4215,8 +4719,8 @@ static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl = */ static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( - StorageImpl* parentStorage, - ULONG firstPropertyNode) + StorageBaseImpl* parentStorage, + DirRef storageDirEntry) { IEnumSTATSTGImpl* newEnumeration; @@ -4237,15 +4741,7 @@ static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( newEnumeration->parentStorage = parentStorage; IStorage_AddRef((IStorage*)newEnumeration->parentStorage); - newEnumeration->firstPropertyNode = firstPropertyNode; - - /* - * Initialize the search stack - */ - newEnumeration->stackSize = 0; - newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT; - newEnumeration->stackToVisit = - HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT); + newEnumeration->storageDirEntry = storageDirEntry; /* * Make sure the current node of the iterator is the first one. @@ -4266,61 +4762,72 @@ static const IStorageVtbl Storage32InternalImpl_Vtbl = StorageBaseImpl_Release, StorageBaseImpl_CreateStream, StorageBaseImpl_OpenStream, - StorageImpl_CreateStorage, + StorageBaseImpl_CreateStorage, StorageBaseImpl_OpenStorage, - StorageImpl_CopyTo, - StorageImpl_MoveElementTo, + StorageBaseImpl_CopyTo, + StorageBaseImpl_MoveElementTo, StorageInternalImpl_Commit, StorageInternalImpl_Revert, StorageBaseImpl_EnumElements, - StorageImpl_DestroyElement, + StorageBaseImpl_DestroyElement, StorageBaseImpl_RenameElement, - StorageImpl_SetElementTimes, + StorageBaseImpl_SetElementTimes, StorageBaseImpl_SetClass, - StorageImpl_SetStateBits, + StorageBaseImpl_SetStateBits, StorageBaseImpl_Stat }; +static const StorageBaseImplVtbl StorageInternalImpl_BaseVtbl = +{ + StorageInternalImpl_Destroy, + StorageInternalImpl_Invalidate, + StorageInternalImpl_CreateDirEntry, + StorageInternalImpl_WriteDirEntry, + StorageInternalImpl_ReadDirEntry, + StorageInternalImpl_DestroyDirEntry, + StorageInternalImpl_StreamReadAt, + StorageInternalImpl_StreamWriteAt, + StorageInternalImpl_StreamSetSize +}; + /****************************************************************************** ** Storage32InternalImpl implementation */ static StorageInternalImpl* StorageInternalImpl_Construct( - StorageImpl* ancestorStorage, + StorageBaseImpl* parentStorage, DWORD openFlags, - ULONG rootPropertyIndex) + DirRef storageDirEntry) { StorageInternalImpl* newStorage; - /* - * Allocate space for the new storage object - */ newStorage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StorageInternalImpl)); if (newStorage!=0) { - /* - * Initialize the stream list - */ list_init(&newStorage->base.strmHead); + list_init(&newStorage->base.storageHead); + /* * Initialize the virtual function table. */ newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl; - newStorage->base.v_destructor = StorageInternalImpl_Destroy; + newStorage->base.baseVtbl = &StorageInternalImpl_BaseVtbl; newStorage->base.openFlags = (openFlags & ~STGM_CREATE); - /* - * Keep the ancestor storage pointer and nail a reference to it. - */ - newStorage->base.ancestorStorage = ancestorStorage; - StorageBaseImpl_AddRef((IStorage*)(newStorage->base.ancestorStorage)); + newStorage->base.reverted = 0; + + newStorage->base.ref = 1; + + newStorage->parentStorage = parentStorage; /* - * Keep the index of the root property set for this storage, + * Keep a reference to the directory entry of this storage */ - newStorage->base.rootPropertySetIndex = rootPropertyIndex; + newStorage->base.storageDirEntry = storageDirEntry; + + newStorage->base.create = 0; return newStorage; } @@ -4406,35 +4913,48 @@ void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value) memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4)); } -void StorageUtl_CopyPropertyToSTATSTG( +void StorageUtl_CopyDirEntryToSTATSTG( + StorageBaseImpl* storage, STATSTG* destination, - const StgProperty* source, + const DirEntry* source, int statFlags) { + LPCWSTR entryName; + + if (source->stgType == STGTY_ROOT) + { + /* replace the name of root entry (often "Root Entry") by the file name */ + entryName = storage->filename; + } + else + { + entryName = source->name; + } + /* * The copy of the string occurs only when the flag is not set */ if( ((statFlags & STATFLAG_NONAME) != 0) || - (source->name == NULL) || - (source->name[0] == 0) ) + (entryName == NULL) || + (entryName[0] == 0) ) { destination->pwcsName = 0; } else { destination->pwcsName = - CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR)); + CoTaskMemAlloc((lstrlenW(entryName)+1)*sizeof(WCHAR)); - strcpyW(destination->pwcsName, source->name); + strcpyW(destination->pwcsName, entryName); } - switch (source->propertyType) + switch (source->stgType) { - case PROPTYPE_STORAGE: - case PROPTYPE_ROOT: + case STGTY_STORAGE: + case STGTY_ROOT: destination->type = STGTY_STORAGE; break; - case PROPTYPE_STREAM: + case STGTY_STREAM: destination->type = STGTY_STREAM; break; default: @@ -4450,7 +4970,7 @@ void StorageUtl_CopyPropertyToSTATSTG( */ destination->grfMode = 0; destination->grfLocksSupported = 0; - destination->clsid = source->propertyUniqueID; + destination->clsid = source->clsid; destination->grfStateBits = 0; destination->reserved = 0; } @@ -4462,7 +4982,7 @@ void StorageUtl_CopyPropertyToSTATSTG( BlockChainStream* BlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex) + DirRef dirEntry) { BlockChainStream* newStream; ULONG blockIndex; @@ -4471,7 +4991,7 @@ BlockChainStream* BlockChainStream_Construct( newStream->parentStorage = parentStorage; newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder; - newStream->ownerPropertyIndex = propertyIndex; + newStream->ownerDirEntry = dirEntry; newStream->lastBlockNoInSequence = 0xFFFFFFFF; newStream->tailIndex = BLOCK_END_OF_CHAIN; newStream->numBlocks = 0; @@ -4505,28 +5025,28 @@ void BlockChainStream_Destroy(BlockChainStream* This) * BlockChainStream_GetHeadOfChain * * Returns the head of this stream chain. - * Some special chains don't have properties, their heads are kept in + * Some special chains don't have directory entries, their heads are kept in * This->headOfStreamPlaceHolder. * */ static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This) { - StgProperty chainProperty; - BOOL readSuccessful; + DirEntry chainEntry; + HRESULT hr; if (This->headOfStreamPlaceHolder != 0) return *(This->headOfStreamPlaceHolder); - if (This->ownerPropertyIndex != PROPERTY_NULL) + if (This->ownerDirEntry != DIRENTRY_NULL) { - readSuccessful = StorageImpl_ReadProperty( + hr = StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); + This->ownerDirEntry, + &chainEntry); - if (readSuccessful) + if (SUCCEEDED(hr)) { - return chainProperty.startingBlock; + return chainEntry.startingBlock; } } @@ -4853,20 +5373,20 @@ static BOOL BlockChainStream_Enlarge(BlockChainStream* This, } else { - StgProperty chainProp; - assert(This->ownerPropertyIndex != PROPERTY_NULL); + DirEntry chainEntry; + assert(This->ownerDirEntry != DIRENTRY_NULL); - StorageImpl_ReadProperty( + StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProp); + This->ownerDirEntry, + &chainEntry); - chainProp.startingBlock = blockIndex; + chainEntry.startingBlock = blockIndex; - StorageImpl_WriteProperty( + StorageImpl_WriteDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProp); + This->ownerDirEntry, + &chainEntry); } This->tailIndex = blockIndex; @@ -4969,29 +5489,28 @@ BOOL BlockChainStream_SetSize( * BlockChainStream_GetSize * * Returns the size of this chain. - * Will return the block count if this chain doesn't have a property. + * Will return the block count if this chain doesn't have a directory entry. */ static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) { - StgProperty chainProperty; + DirEntry chainEntry; if(This->headOfStreamPlaceHolder == NULL) { /* - * This chain is a data stream read the property and return - * the appropriate size + * This chain has a directory entry so use the size value from there. */ - StorageImpl_ReadProperty( + StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); + This->ownerDirEntry, + &chainEntry); - return chainProperty.size; + return chainEntry.size; } else { /* - * this chain is a chain that does not have a property, figure out the + * this chain is a chain that does not have a directory entry, figure out the * size by making the product number of used blocks times the * size of them */ @@ -5013,7 +5532,7 @@ static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) SmallBlockChainStream* SmallBlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex) + DirRef dirEntry) { SmallBlockChainStream* newStream; @@ -5021,7 +5540,7 @@ SmallBlockChainStream* SmallBlockChainStream_Construct( newStream->parentStorage = parentStorage; newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder; - newStream->ownerPropertyIndex = propertyIndex; + newStream->ownerDirEntry = dirEntry; return newStream; } @@ -5040,22 +5559,22 @@ void SmallBlockChainStream_Destroy( static ULONG SmallBlockChainStream_GetHeadOfChain( SmallBlockChainStream* This) { - StgProperty chainProperty; - BOOL readSuccessful; + DirEntry chainEntry; + HRESULT hr; if (This->headOfStreamPlaceHolder != NULL) return *(This->headOfStreamPlaceHolder); - if (This->ownerPropertyIndex) + if (This->ownerDirEntry) { - readSuccessful = StorageImpl_ReadProperty( + hr = StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); + This->ownerDirEntry, + &chainEntry); - if (readSuccessful) + if (SUCCEEDED(hr)) { - return chainProperty.startingBlock; + return chainEntry.startingBlock; } } @@ -5234,7 +5753,7 @@ static ULONG SmallBlockChainStream_GetNextFreeBlock( /* * We have just created the small block depot. */ - StgProperty rootProp; + DirEntry rootEntry; ULONG sbStartIndex; /* @@ -5254,19 +5773,19 @@ static ULONG SmallBlockChainStream_GetNextFreeBlock( sbStartIndex, BLOCK_END_OF_CHAIN); - StorageImpl_ReadProperty( + StorageImpl_ReadDirEntry( This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); + This->parentStorage->base.storageDirEntry, + &rootEntry); - rootProp.startingBlock = sbStartIndex; - rootProp.size.u.HighPart = 0; - rootProp.size.u.LowPart = This->parentStorage->bigBlockSize; + rootEntry.startingBlock = sbStartIndex; + rootEntry.size.u.HighPart = 0; + rootEntry.size.u.LowPart = This->parentStorage->bigBlockSize; - StorageImpl_WriteProperty( + StorageImpl_WriteDirEntry( This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); + This->parentStorage->base.storageDirEntry, + &rootEntry); } else StorageImpl_SaveFileHeader(This->parentStorage); @@ -5281,27 +5800,27 @@ static ULONG SmallBlockChainStream_GetNextFreeBlock( */ if (blockIndex % smallBlocksPerBigBlock == 0) { - StgProperty rootProp; + DirEntry rootEntry; ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1; - StorageImpl_ReadProperty( + StorageImpl_ReadDirEntry( This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); + This->parentStorage->base.storageDirEntry, + &rootEntry); - if (rootProp.size.u.LowPart < + if (rootEntry.size.u.LowPart < (blocksRequired * This->parentStorage->bigBlockSize)) { - rootProp.size.u.LowPart += This->parentStorage->bigBlockSize; + rootEntry.size.u.LowPart += This->parentStorage->bigBlockSize; BlockChainStream_SetSize( This->parentStorage->smallBlockRootChain, - rootProp.size); + rootEntry.size); - StorageImpl_WriteProperty( + StorageImpl_WriteDirEntry( This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); + This->parentStorage->base.storageDirEntry, + &rootEntry); } } @@ -5531,17 +6050,17 @@ static BOOL SmallBlockChainStream_Shrink( */ if (count == 0) { - StgProperty chainProp; + DirEntry chainEntry; - StorageImpl_ReadProperty(This->parentStorage, - This->ownerPropertyIndex, - &chainProp); + StorageImpl_ReadDirEntry(This->parentStorage, + This->ownerDirEntry, + &chainEntry); - chainProp.startingBlock = BLOCK_END_OF_CHAIN; + chainEntry.startingBlock = BLOCK_END_OF_CHAIN; - StorageImpl_WriteProperty(This->parentStorage, - This->ownerPropertyIndex, - &chainProp); + StorageImpl_WriteDirEntry(This->parentStorage, + This->ownerDirEntry, + &chainEntry); /* * We start freeing the chain at the head block. @@ -5609,15 +6128,15 @@ static BOOL SmallBlockChainStream_Enlarge( } else { - StgProperty chainProp; + DirEntry chainEntry; - StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex, - &chainProp); + StorageImpl_ReadDirEntry(This->parentStorage, This->ownerDirEntry, + &chainEntry); - chainProp.startingBlock = blockIndex; + chainEntry.startingBlock = blockIndex; - StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex, - &chainProp); + StorageImpl_WriteDirEntry(This->parentStorage, This->ownerDirEntry, + &chainEntry); } } @@ -5726,7 +6245,7 @@ static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This) */ static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) { - StgProperty chainProperty; + DirEntry chainEntry; if(This->headOfStreamPlaceHolder != NULL) { @@ -5739,12 +6258,12 @@ static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) return result; } - StorageImpl_ReadProperty( + StorageImpl_ReadDirEntry( This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); + This->ownerDirEntry, + &chainEntry); - return chainProperty.size; + return chainEntry.size; } /****************************************************************************** @@ -5772,7 +6291,7 @@ HRESULT WINAPI StgCreateDocfile( DWORD reserved, IStorage **ppstgOpen) { - StorageImpl* newStorage = 0; + StorageBaseImpl* newStorage = 0; HANDLE hFile = INVALID_HANDLE_VALUE; HRESULT hr = STG_E_INVALIDFLAG; DWORD shareMode; @@ -5785,9 +6304,6 @@ HRESULT WINAPI StgCreateDocfile( debugstr_w(pwcsName), grfMode, reserved, ppstgOpen); - /* - * Validate the parameters - */ if (ppstgOpen == 0) return STG_E_INVALIDPOINTER; if (reserved != 0) @@ -5797,9 +6313,6 @@ HRESULT WINAPI StgCreateDocfile( if (STGM_SHARE_MODE(grfMode) == 0) grfMode |= STGM_SHARE_DENY_NONE; - /* - * Validate the STGM flags - */ if ( FAILED( validateSTGM(grfMode) )) goto end; @@ -5860,14 +6373,12 @@ HRESULT WINAPI StgCreateDocfile( fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; if (STGM_SHARE_MODE(grfMode) && !(grfMode & STGM_SHARE_DENY_NONE)) + { + static int fixme; + if (!fixme++) FIXME("Storage share mode not implemented.\n"); + } - if (grfMode & STGM_TRANSACTED) - FIXME("Transacted mode not implemented.\n"); - - /* - * Initialize the "out" parameter. - */ *ppstgOpen = 0; hFile = CreateFileW(pwcsName, @@ -5890,36 +6401,25 @@ HRESULT WINAPI StgCreateDocfile( /* * Allocate and initialize the new IStorage32object. */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - { - hr = STG_E_INSUFFICIENTMEMORY; - goto end; - } - - hr = StorageImpl_Construct( - newStorage, + hr = Storage_Construct( hFile, pwcsName, NULL, grfMode, TRUE, - TRUE); + TRUE, + &newStorage); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, newStorage); goto end; } /* * Get an "out" pointer for the caller. */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - &IID_IStorage, - (void**)ppstgOpen); + *ppstgOpen = (IStorage*)newStorage; + end: TRACE("<-- %p r = %08x\n", *ppstgOpen, hr); @@ -6034,20 +6534,16 @@ HRESULT WINAPI StgOpenStorage( DWORD reserved, IStorage **ppstgOpen) { - StorageImpl* newStorage = 0; + StorageBaseImpl* newStorage = 0; HRESULT hr = S_OK; HANDLE hFile = 0; DWORD shareMode; DWORD accessMode; - WCHAR fullname[MAX_PATH]; TRACE("(%s, %p, %x, %p, %d, %p)\n", debugstr_w(pwcsName), pstgPriority, grfMode, snbExclude, reserved, ppstgOpen); - /* - * Perform sanity checks - */ if (pwcsName == 0) { hr = STG_E_INVALIDNAME; @@ -6099,9 +6595,6 @@ HRESULT WINAPI StgOpenStorage( goto end; } - /* - * Validate the STGM flags - */ if ( FAILED( validateSTGM(grfMode) ) || (grfMode&STGM_CREATE)) { @@ -6124,9 +6617,6 @@ HRESULT WINAPI StgOpenStorage( shareMode = GetShareModeFromSTGM(grfMode); accessMode = GetAccessModeFromSTGM(grfMode); - /* - * Initialize the "out" parameter. - */ *ppstgOpen = 0; hFile = CreateFileW( pwcsName, @@ -6183,27 +6673,17 @@ HRESULT WINAPI StgOpenStorage( /* * Allocate and initialize the new IStorage32object. */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - { - hr = STG_E_INSUFFICIENTMEMORY; - goto end; - } - - /* Initialize the storage */ - hr = StorageImpl_Construct( - newStorage, + hr = Storage_Construct( hFile, pwcsName, NULL, grfMode, TRUE, - FALSE ); + FALSE, + &newStorage); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, newStorage); /* * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS */ @@ -6212,18 +6692,10 @@ HRESULT WINAPI StgOpenStorage( goto end; } - /* prepare the file name string given in lieu of the root property name */ - GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL); - memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN); - newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0'; - /* * Get an "out" pointer for the caller. */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - &IID_IStorage, - (void**)ppstgOpen); + *ppstgOpen = (IStorage*)newStorage; end: TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL); @@ -6239,45 +6711,33 @@ HRESULT WINAPI StgCreateDocfileOnILockBytes( DWORD reserved, IStorage** ppstgOpen) { - StorageImpl* newStorage = 0; + StorageBaseImpl* newStorage = 0; HRESULT hr = S_OK; - /* - * Validate the parameters - */ if ((ppstgOpen == 0) || (plkbyt == 0)) return STG_E_INVALIDPOINTER; /* * Allocate and initialize the new IStorage object. */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - return STG_E_INSUFFICIENTMEMORY; - - hr = StorageImpl_Construct( - newStorage, + hr = Storage_Construct( 0, 0, plkbyt, grfMode, FALSE, - TRUE); + TRUE, + &newStorage); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, newStorage); return hr; } /* * Get an "out" pointer for the caller. */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - &IID_IStorage, - (void**)ppstgOpen); + *ppstgOpen = (IStorage*)newStorage; return hr; } @@ -6293,56 +6753,38 @@ HRESULT WINAPI StgOpenStorageOnILockBytes( DWORD reserved, IStorage **ppstgOpen) { - StorageImpl* newStorage = 0; + StorageBaseImpl* newStorage = 0; HRESULT hr = S_OK; - /* - * Perform a sanity check - */ if ((plkbyt == 0) || (ppstgOpen == 0)) return STG_E_INVALIDPOINTER; - /* - * Validate the STGM flags - */ if ( FAILED( validateSTGM(grfMode) )) return STG_E_INVALIDFLAG; - /* - * Initialize the "out" parameter. - */ *ppstgOpen = 0; /* * Allocate and initialize the new IStorage object. */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - return STG_E_INSUFFICIENTMEMORY; - - hr = StorageImpl_Construct( - newStorage, + hr = Storage_Construct( 0, 0, plkbyt, grfMode, FALSE, - FALSE); + FALSE, + &newStorage); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, newStorage); return hr; } /* * Get an "out" pointer for the caller. */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - &IID_IStorage, - (void**)ppstgOpen); + *ppstgOpen = (IStorage*)newStorage; return hr; } @@ -7005,8 +7447,8 @@ static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBu hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage); if(hRes == S_OK) { - hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage); - StorageBaseImpl_Release(pTempStorage); + hRes = IStorage_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage); + IStorage_Release(pTempStorage); } DeleteFileW(wstrTempFile); } @@ -7050,8 +7492,8 @@ static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData) if(hRes == S_OK) { /* Copy Src Storage to the Temp Storage */ - StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage); - StorageBaseImpl_Release(pTempStorage); + IStorage_CopyTo(pStorage, 0, NULL, NULL, pTempStorage); + IStorage_Release(pTempStorage); /* Open Temp Storage as a file and copy to memory */ hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); @@ -7969,16 +8411,16 @@ StgIsStorageFile(LPCOLESTR fn) CloseHandle(hf); if (bytes_read != 8) { - WARN(" too short\n"); + TRACE(" too short\n"); return S_FALSE; } if (!memcmp(magic,STORAGE_magic,8)) { - WARN(" -> YES\n"); + TRACE(" -> YES\n"); return S_OK; } - WARN(" -> Invalid header.\n"); + TRACE(" -> Invalid header.\n"); return S_FALSE; } diff --git a/reactos/dll/win32/ole32/storage32.h b/reactos/dll/win32/ole32/storage32.h index fc4af325552..03328b29708 100644 --- a/reactos/dll/win32/ole32/storage32.h +++ b/reactos/dll/win32/ole32/storage32.h @@ -53,15 +53,15 @@ static const ULONG OFFSET_EXTBBDEPOTCOUNT = 0x00000048; static const ULONG OFFSET_BBDEPOTSTART = 0x0000004C; static const ULONG OFFSET_PS_NAME = 0x00000000; static const ULONG OFFSET_PS_NAMELENGTH = 0x00000040; -static const ULONG OFFSET_PS_PROPERTYTYPE = 0x00000042; -static const ULONG OFFSET_PS_PREVIOUSPROP = 0x00000044; -static const ULONG OFFSET_PS_NEXTPROP = 0x00000048; -static const ULONG OFFSET_PS_DIRPROP = 0x0000004C; +static const ULONG OFFSET_PS_STGTYPE = 0x00000042; +static const ULONG OFFSET_PS_LEFTCHILD = 0x00000044; +static const ULONG OFFSET_PS_RIGHTCHILD = 0x00000048; +static const ULONG OFFSET_PS_DIRROOT = 0x0000004C; static const ULONG OFFSET_PS_GUID = 0x00000050; -static const ULONG OFFSET_PS_TSS1 = 0x00000064; -static const ULONG OFFSET_PS_TSD1 = 0x00000068; -static const ULONG OFFSET_PS_TSS2 = 0x0000006C; -static const ULONG OFFSET_PS_TSD2 = 0x00000070; +static const ULONG OFFSET_PS_CTIMELOW = 0x00000064; +static const ULONG OFFSET_PS_CTIMEHIGH = 0x00000068; +static const ULONG OFFSET_PS_MTIMELOW = 0x0000006C; +static const ULONG OFFSET_PS_MTIMEHIGH = 0x00000070; static const ULONG OFFSET_PS_STARTBLOCK = 0x00000074; static const ULONG OFFSET_PS_SIZE = 0x00000078; static const WORD DEF_BIG_BLOCK_SIZE_BITS = 0x0009; @@ -72,26 +72,24 @@ static const ULONG BLOCK_EXTBBDEPOT = 0xFFFFFFFC; static const ULONG BLOCK_SPECIAL = 0xFFFFFFFD; static const ULONG BLOCK_END_OF_CHAIN = 0xFFFFFFFE; static const ULONG BLOCK_UNUSED = 0xFFFFFFFF; -static const ULONG PROPERTY_NULL = 0xFFFFFFFF; +static const ULONG DIRENTRY_NULL = 0xFFFFFFFF; -#define PROPERTY_NAME_MAX_LEN 0x20 -#define PROPERTY_NAME_BUFFER_LEN 0x40 +#define DIRENTRY_NAME_MAX_LEN 0x20 +#define DIRENTRY_NAME_BUFFER_LEN 0x40 -#define PROPSET_BLOCK_SIZE 0x00000080 +#define RAW_DIRENTRY_SIZE 0x00000080 /* - * Property type of relation + * Type of child entry link */ -#define PROPERTY_RELATION_PREVIOUS 0 -#define PROPERTY_RELATION_NEXT 1 -#define PROPERTY_RELATION_DIR 2 +#define DIRENTRY_RELATION_PREVIOUS 0 +#define DIRENTRY_RELATION_NEXT 1 +#define DIRENTRY_RELATION_DIR 2 /* - * Property type constants + * type constant used in files for the root storage */ -#define PROPTYPE_STORAGE 0x01 -#define PROPTYPE_STREAM 0x02 -#define PROPTYPE_ROOT 0x05 +#define STGTY_ROOT 0x05 /* * These defines assume a hardcoded blocksize. The code will assert @@ -116,30 +114,34 @@ static const ULONG PROPERTY_NULL = 0xFFFFFFFF; * module. */ typedef struct StorageBaseImpl StorageBaseImpl; +typedef struct StorageBaseImplVtbl StorageBaseImplVtbl; typedef struct StorageImpl StorageImpl; typedef struct BlockChainStream BlockChainStream; typedef struct SmallBlockChainStream SmallBlockChainStream; typedef struct IEnumSTATSTGImpl IEnumSTATSTGImpl; -typedef struct StgProperty StgProperty; +typedef struct DirEntry DirEntry; typedef struct StgStreamImpl StgStreamImpl; /* - * This utility structure is used to read/write the information in a storage - * property. + * A reference to a directory entry in the file or a transacted cache. */ -struct StgProperty +typedef ULONG DirRef; + +/* + * This utility structure is used to read/write the information in a directory + * entry. + */ +struct DirEntry { - WCHAR name[PROPERTY_NAME_MAX_LEN]; + WCHAR name[DIRENTRY_NAME_MAX_LEN]; WORD sizeOfNameString; - BYTE propertyType; - ULONG previousProperty; - ULONG nextProperty; - ULONG dirProperty; - GUID propertyUniqueID; - ULONG timeStampS1; - ULONG timeStampD1; - ULONG timeStampS2; - ULONG timeStampD2; + BYTE stgType; + DirRef leftChild; + DirRef rightChild; + DirRef dirRootEntry; + GUID clsid; + FILETIME ctime; + FILETIME mtime; ULONG startingBlock; ULARGE_INTEGER size; }; @@ -178,6 +180,7 @@ HRESULT BIGBLOCKFILE_WriteAt(LPBIGBLOCKFILE This, ULARGE_INTEGER offset, void OLECONVERT_CreateOleStream(LPSTORAGE pStorage); HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName); + /**************************************************************************** * Storage32BaseImpl definitions. * @@ -200,26 +203,30 @@ struct StorageBaseImpl struct list strmHead; + /* + * Storage tracking list + */ + struct list storageHead; + /* * Reference count of this object */ LONG ref; /* - * Ancestor storage (top level) + * TRUE if this object has been invalidated */ - StorageImpl* ancestorStorage; + int reverted; /* - * Index of the property for the root of - * this storage + * Index of the directory entry of this storage */ - ULONG rootPropertySetIndex; + DirRef storageDirEntry; /* - * virtual Destructor method. + * virtual methods. */ - void (*v_destructor)(StorageBaseImpl*); + const StorageBaseImplVtbl *baseVtbl; /* * flags that this storage was opened or created with @@ -230,8 +237,87 @@ struct StorageBaseImpl * State bits appear to only be preserved while running. No in the stream */ DWORD stateBits; + + /* If set, this overrides the root storage name returned by IStorage_Stat */ + LPCWSTR filename; + + BOOL create; /* Was the storage created or opened. + The behaviour of STGM_SIMPLE depends on this */ + /* + * If this storage was opened in transacted mode, the object that implements + * the transacted snapshot or cache. + */ + StorageBaseImpl *transactedChild; }; +/* virtual methods for StorageBaseImpl objects */ +struct StorageBaseImplVtbl { + void (*Destroy)(StorageBaseImpl*); + void (*Invalidate)(StorageBaseImpl*); + HRESULT (*CreateDirEntry)(StorageBaseImpl*,const DirEntry*,DirRef*); + HRESULT (*WriteDirEntry)(StorageBaseImpl*,DirRef,const DirEntry*); + HRESULT (*ReadDirEntry)(StorageBaseImpl*,DirRef,DirEntry*); + HRESULT (*DestroyDirEntry)(StorageBaseImpl*,DirRef); + HRESULT (*StreamReadAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,void*,ULONG*); + HRESULT (*StreamWriteAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,const void*,ULONG*); + HRESULT (*StreamSetSize)(StorageBaseImpl*,DirRef,ULARGE_INTEGER); +}; + +static inline void StorageBaseImpl_Destroy(StorageBaseImpl *This) +{ + This->baseVtbl->Destroy(This); +} + +static inline void StorageBaseImpl_Invalidate(StorageBaseImpl *This) +{ + This->baseVtbl->Invalidate(This); +} + +static inline HRESULT StorageBaseImpl_CreateDirEntry(StorageBaseImpl *This, + const DirEntry *newData, DirRef *index) +{ + return This->baseVtbl->CreateDirEntry(This, newData, index); +} + +static inline HRESULT StorageBaseImpl_WriteDirEntry(StorageBaseImpl *This, + DirRef index, const DirEntry *data) +{ + return This->baseVtbl->WriteDirEntry(This, index, data); +} + +static inline HRESULT StorageBaseImpl_ReadDirEntry(StorageBaseImpl *This, + DirRef index, DirEntry *data) +{ + return This->baseVtbl->ReadDirEntry(This, index, data); +} + +static inline HRESULT StorageBaseImpl_DestroyDirEntry(StorageBaseImpl *This, + DirRef index) +{ + return This->baseVtbl->DestroyDirEntry(This, index); +} + +/* Read up to size bytes from this directory entry's stream at the given offset. */ +static inline HRESULT StorageBaseImpl_StreamReadAt(StorageBaseImpl *This, + DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead) +{ + return This->baseVtbl->StreamReadAt(This, index, offset, size, buffer, bytesRead); +} + +/* Write size bytes to this directory entry's stream at the given offset, + * growing the stream if necessary. */ +static inline HRESULT StorageBaseImpl_StreamWriteAt(StorageBaseImpl *This, + DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten) +{ + return This->baseVtbl->StreamWriteAt(This, index, offset, size, buffer, bytesWritten); +} + +static inline HRESULT StorageBaseImpl_StreamSetSize(StorageBaseImpl *This, + DirRef index, ULARGE_INTEGER newsize) +{ + return This->baseVtbl->StreamSetSize(This, index, newsize); +} + /**************************************************************************** * StorageBaseImpl stream list handlers */ @@ -239,6 +325,9 @@ struct StorageBaseImpl void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm); void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm); +/* Number of BlockChainStream objects to cache in a StorageImpl */ +#define BLOCKCHAIN_CACHE_SIZE 4 + /**************************************************************************** * Storage32Impl definitions. * @@ -255,11 +344,6 @@ struct StorageImpl */ HANDLE hFile; /* Physical support for the Docfile */ LPOLESTR pwcsName; /* Full path of the document file */ - BOOL create; /* Was the storage created or opened. - The behaviour of STGM_SIMPLE depends on this */ - - /* FIXME: should this be in Storage32BaseImpl ? */ - WCHAR filename[PROPERTY_NAME_BUFFER_LEN]; /* * File header @@ -286,21 +370,39 @@ struct StorageImpl BlockChainStream* smallBlockDepotChain; BlockChainStream* smallBlockRootChain; + /* Cache of block chain streams objects for directory entries */ + BlockChainStream* blockChainCache[BLOCKCHAIN_CACHE_SIZE]; + UINT blockChainToEvict; + /* * Pointer to the big block file abstraction */ BigBlockFile* bigBlockFile; }; -BOOL StorageImpl_ReadProperty( - StorageImpl* This, - ULONG index, - StgProperty* buffer); +HRESULT StorageImpl_ReadRawDirEntry( + StorageImpl *This, + ULONG index, + BYTE *buffer); -BOOL StorageImpl_WriteProperty( +void UpdateRawDirEntry( + BYTE *buffer, + const DirEntry *newData); + +HRESULT StorageImpl_WriteRawDirEntry( + StorageImpl *This, + ULONG index, + const BYTE *buffer); + +HRESULT StorageImpl_ReadDirEntry( + StorageImpl* This, + DirRef index, + DirEntry* buffer); + +HRESULT StorageImpl_WriteDirEntry( StorageImpl* This, - ULONG index, - const StgProperty* buffer); + DirRef index, + const DirEntry* buffer); BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( StorageImpl* This, @@ -343,27 +445,14 @@ struct StgStreamImpl DWORD grfMode; /* - * Index of the property that owns (points to) this stream. + * Index of the directory entry that owns (points to) this stream. */ - ULONG ownerProperty; - - /* - * Helper variable that contains the size of the stream - */ - ULARGE_INTEGER streamSize; + DirRef dirEntry; /* * This is the current position of the cursor in the stream */ ULARGE_INTEGER currentPosition; - - /* - * The information in the stream is represented by a chain of small blocks - * or a chain of large blocks. Depending on the case, one of the two - * following variables points to that information. - */ - BlockChainStream* bigBlockChain; - SmallBlockChainStream* smallBlockChain; }; /* @@ -372,7 +461,7 @@ struct StgStreamImpl StgStreamImpl* StgStreamImpl_Construct( StorageBaseImpl* parentStorage, DWORD grfMode, - ULONG ownerProperty); + DirRef dirEntry); /****************************************************************************** @@ -409,8 +498,8 @@ void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset, const ULARGE_INTEGER *value); void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value); void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value); -void StorageUtl_CopyPropertyToSTATSTG(STATSTG* destination, const StgProperty* source, - int statFlags); +void StorageUtl_CopyDirEntryToSTATSTG(StorageBaseImpl *storage,STATSTG* destination, + const DirEntry* source, int statFlags); /**************************************************************************** * BlockChainStream definitions. @@ -422,7 +511,7 @@ struct BlockChainStream { StorageImpl* parentStorage; ULONG* headOfStreamPlaceHolder; - ULONG ownerPropertyIndex; + DirRef ownerDirEntry; ULONG lastBlockNoInSequence; ULONG lastBlockNoInSequenceIndex; ULONG tailIndex; @@ -435,7 +524,7 @@ struct BlockChainStream BlockChainStream* BlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex); + DirRef dirEntry); void BlockChainStream_Destroy( BlockChainStream* This); @@ -467,7 +556,7 @@ BOOL BlockChainStream_SetSize( struct SmallBlockChainStream { StorageImpl* parentStorage; - ULONG ownerPropertyIndex; + DirRef ownerDirEntry; ULONG* headOfStreamPlaceHolder; }; @@ -477,7 +566,7 @@ struct SmallBlockChainStream SmallBlockChainStream* SmallBlockChainStream_Construct( StorageImpl* parentStorage, ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex); + DirRef dirEntry); void SmallBlockChainStream_Destroy( SmallBlockChainStream* This); diff --git a/reactos/dll/win32/ole32/stubmanager.c b/reactos/dll/win32/ole32/stubmanager.c index 12813c6a5d7..f6b8bfa1a86 100644 --- a/reactos/dll/win32/ole32/stubmanager.c +++ b/reactos/dll/win32/ole32/stubmanager.c @@ -406,13 +406,15 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tablewea rc = (m->extrefs -= refs); if (tableweak) - rc += --m->weakrefs; + --m->weakrefs; + if (!last_unlock_releases) + rc += m->weakrefs; LeaveCriticalSection(&m->lock); TRACE("removed %u refs from %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc); - if (rc == 0 && last_unlock_releases) + if (rc == 0) stub_manager_int_release(m); return rc; @@ -551,7 +553,7 @@ void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const else if (ifstub->flags & MSHLFLAGS_TABLESTRONG) refs = 1; - stub_manager_ext_release(m, refs, tableweak, TRUE); + stub_manager_ext_release(m, refs, tableweak, FALSE); } /* is an ifstub table marshaled? */ diff --git a/reactos/dll/win32/ole32/usrmarshal.c b/reactos/dll/win32/ole32/usrmarshal.c index f180f42f8ca..ed316201f69 100644 --- a/reactos/dll/win32/ole32/usrmarshal.c +++ b/reactos/dll/win32/ole32/usrmarshal.c @@ -170,11 +170,9 @@ unsigned char * __RPC_USER CLIPFORMAT_UserMarshal(ULONG *pFlags, unsigned char * pBuffer += sizeof(UINT); *(UINT *)pBuffer = len; pBuffer += sizeof(UINT); - TRACE("marshaling format name %s\n", debugstr_wn(format, len-1)); - lstrcpynW((LPWSTR)pBuffer, format, len); + TRACE("marshaling format name %s\n", debugstr_w(format)); + memcpy(pBuffer, format, len * sizeof(WCHAR)); pBuffer += len * sizeof(WCHAR); - *(WCHAR *)pBuffer = '\0'; - pBuffer += sizeof(WCHAR); } else { @@ -238,11 +236,11 @@ unsigned char * __RPC_USER CLIPFORMAT_UserUnmarshal(ULONG *pFlags, unsigned char if (*(UINT *)pBuffer != len) RaiseException(RPC_S_INVALID_BOUND, 0, 0, NULL); pBuffer += sizeof(UINT); - if (((WCHAR *)pBuffer)[len] != '\0') + if (((WCHAR *)pBuffer)[len - 1] != '\0') RaiseException(RPC_S_INVALID_BOUND, 0, 0, NULL); TRACE("unmarshaling clip format %s\n", debugstr_w((LPCWSTR)pBuffer)); cf = RegisterClipboardFormatW((LPCWSTR)pBuffer); - pBuffer += (len + 1) * sizeof(WCHAR); + pBuffer += len * sizeof(WCHAR); if (!cf) RaiseException(DV_E_CLIPFORMAT, 0, 0, NULL); *pCF = cf;