* Copyright 1999 Francis Beaudet
* Copyright 1999 Sylvain St-Germain
* Copyright 1999 Thuy Nguyen
+ * Copyright 2005 Mike McCormack
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * NOTES
+ * The compound file implementation of IStorage used for create
+ * and manage substorages and streams within a storage object
+ * residing in a compound file object.
+ *
+ * MSDN
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/istorage_compound_file_implementation.asp
*/
#include <assert.h>
WINE_DEFAULT_DEBUG_CHANNEL(storage);
-#define FILE_BEGIN 0
-
-
/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
#define OLESTREAM_ID 0x501
#define OLESTREAM_MAX_STR_LEN 255
+/*
+ * These are signatures to detect the type of Document file.
+ */
+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";
+/****************************************************************************
+ * Storage32InternalImpl definitions.
+ *
+ * Definition of the implementation structure for the IStorage32 interface.
+ * This one implements the IStorage32 interface for storage that are
+ * inside another storage.
+ */
+struct StorageInternalImpl
+{
+ struct StorageBaseImpl base;
+ /*
+ * There is no specific data for this class.
+ */
+};
+typedef struct StorageInternalImpl StorageInternalImpl;
+
+/* Method definitions for the Storage32InternalImpl class. */
+static StorageInternalImpl* StorageInternalImpl_Construct(StorageImpl* ancestorStorage,
+ DWORD openFlags, ULONG rootTropertyIndex);
+static void StorageImpl_Destroy(StorageBaseImpl* iface);
+static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
+static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
+static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock);
+static HRESULT StorageImpl_LoadFileHeader(StorageImpl* This);
+static void StorageImpl_SaveFileHeader(StorageImpl* This);
+
+static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex);
+static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
+static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex);
+static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex);
+static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex);
+
+static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This);
+static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This);
+static ULONG BlockChainStream_GetCount(BlockChainStream* This);
+
+static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This);
+static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This,
+ ULONG blockIndex, ULONG offset, DWORD value);
+static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl* This,
+ ULONG blockIndex, ULONG offset, DWORD* value);
/* OLESTREAM memory structure to use for Get and Put Routines */
/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
static DWORD GetAccessModeFromSTGM(DWORD stgm);
static DWORD GetCreationModeFromSTGM(DWORD stgm);
-/*
- * Virtual function table for the IStorage32Impl class.
- */
-static IStorageVtbl Storage32Impl_Vtbl =
-{
- StorageBaseImpl_QueryInterface,
- StorageBaseImpl_AddRef,
- StorageBaseImpl_Release,
- StorageBaseImpl_CreateStream,
- StorageBaseImpl_OpenStream,
- StorageImpl_CreateStorage,
- StorageBaseImpl_OpenStorage,
- StorageImpl_CopyTo,
- StorageImpl_MoveElementTo,
- StorageImpl_Commit,
- StorageImpl_Revert,
- StorageBaseImpl_EnumElements,
- StorageImpl_DestroyElement,
- StorageBaseImpl_RenameElement,
- StorageImpl_SetElementTimes,
- StorageBaseImpl_SetClass,
- StorageImpl_SetStateBits,
- StorageImpl_Stat
-};
+extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
-/*
- * Virtual function table for the Storage32InternalImpl class.
- */
-static IStorageVtbl Storage32InternalImpl_Vtbl =
- {
- StorageBaseImpl_QueryInterface,
- StorageBaseImpl_AddRef,
- StorageBaseImpl_Release,
- StorageBaseImpl_CreateStream,
- StorageBaseImpl_OpenStream,
- StorageImpl_CreateStorage,
- StorageBaseImpl_OpenStorage,
- StorageImpl_CopyTo,
- StorageImpl_MoveElementTo,
- StorageInternalImpl_Commit,
- StorageInternalImpl_Revert,
- StorageBaseImpl_EnumElements,
- StorageImpl_DestroyElement,
- StorageBaseImpl_RenameElement,
- StorageImpl_SetElementTimes,
- StorageBaseImpl_SetClass,
- StorageImpl_SetStateBits,
- StorageBaseImpl_Stat
-};
-/*
- * Virtual function table for the IEnumSTATSTGImpl class.
+/****************************************************************************
+ * IEnumSTATSTGImpl definitions.
+ *
+ * Definition of the implementation structure for the IEnumSTATSTGImpl interface.
+ * This class allows iterating through the content of a storage and to find
+ * specific items inside it.
*/
-static IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
+struct IEnumSTATSTGImpl
{
- IEnumSTATSTGImpl_QueryInterface,
- IEnumSTATSTGImpl_AddRef,
- IEnumSTATSTGImpl_Release,
- IEnumSTATSTGImpl_Next,
- IEnumSTATSTGImpl_Skip,
- IEnumSTATSTGImpl_Reset,
- IEnumSTATSTGImpl_Clone
+ const IEnumSTATSTGVtbl *lpVtbl; /* Needs to be the first item in the struct
+ * 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 */
+
+ /*
+ * 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
};
+static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(StorageImpl* This, ULONG firstPropertyNode);
+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
+*/
+static ULONG BLOCK_GetBigBlockOffset(ULONG index)
+{
+ if (index == 0xffffffff)
+ index = 0;
+ else
+ index ++;
+ return index * BIG_BLOCK_SIZE;
+}
/************************************************************************
** Storage32BaseImpl implementatiion
*/
+static HRESULT StorageImpl_ReadAt(StorageImpl* This,
+ ULARGE_INTEGER offset,
+ void* buffer,
+ ULONG size,
+ ULONG* bytesRead)
+{
+ return BIGBLOCKFILE_ReadAt(This->bigBlockFile,offset,buffer,size,bytesRead);
+}
+
+static HRESULT StorageImpl_WriteAt(StorageImpl* This,
+ ULARGE_INTEGER offset,
+ void* buffer,
+ const ULONG size,
+ ULONG* bytesWritten)
+{
+ return BIGBLOCKFILE_WriteAt(This->bigBlockFile,offset,buffer,size,bytesWritten);
+}
/************************************************************************
* Storage32BaseImpl_QueryInterface (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
-HRESULT WINAPI StorageBaseImpl_QueryInterface(
+static HRESULT WINAPI StorageBaseImpl_QueryInterface(
IStorage* iface,
REFIID riid,
void** ppvObject)
/*
* Compare the riid with the interface IDs implemented by this object.
*/
- if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IStorage, riid))
{
*ppvObject = (IStorage*)This;
}
- else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
+ else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
{
- *ppvObject = (IStorage*)This;
+ *ppvObject = (IStorage*)&This->pssVtbl;
}
/*
* Query Interface always increases the reference count by one when it is
* successful
*/
- StorageBaseImpl_AddRef(iface);
+ IStorage_AddRef(iface);
return S_OK;
}
*
* See Windows documentation for more details on IUnknown methods.
*/
-ULONG WINAPI StorageBaseImpl_AddRef(
+static ULONG WINAPI StorageBaseImpl_AddRef(
IStorage* iface)
{
StorageBaseImpl *This = (StorageBaseImpl *)iface;
- return InterlockedIncrement(&This->ref);
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) AddRef to %d\n", This, ref);
+
+ return ref;
}
/************************************************************************
*
* See Windows documentation for more details on IUnknown methods.
*/
-ULONG WINAPI StorageBaseImpl_Release(
+static ULONG WINAPI StorageBaseImpl_Release(
IStorage* iface)
{
StorageBaseImpl *This = (StorageBaseImpl *)iface;
*/
ULONG ref = InterlockedDecrement(&This->ref);
+ TRACE("(%p) ReleaseRef to %d\n", This, ref);
+
/*
* If the reference count goes down to 0, perform suicide.
*/
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT WINAPI StorageBaseImpl_OpenStream(
+static HRESULT WINAPI StorageBaseImpl_OpenStream(
IStorage* iface,
const OLECHAR* pwcsName, /* [string][in] */
void* reserved1, /* [unique][in] */
ULONG foundPropertyIndex;
HRESULT res = STG_E_UNKNOWN;
- TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
+ TRACE("(%p, %s, %p, %x, %d, %p)\n",
iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
/*
/*
* Validate the STGM flags
*/
- if ( FAILED( validateSTGM(grfMode) ))
+ if ( FAILED( validateSTGM(grfMode) ) ||
+ STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
{
res = STG_E_INVALIDFLAG;
goto end;
/*
* As documented.
*/
- if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
- (grfMode & STGM_DELETEONRELEASE) ||
- (grfMode & STGM_TRANSACTED) )
+ if ( (grfMode & STGM_DELETEONRELEASE) || (grfMode & STGM_TRANSACTED) )
{
res = STG_E_INVALIDFUNCTION;
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 ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
+ {
+ res = STG_E_ACCESSDENIED;
+ goto end;
+ }
+ }
+
/*
* Create a property enumeration to search the properties
*/
* Since we are returning a pointer to the interface, we have to
* nail down the reference.
*/
- StgStreamImpl_AddRef(*ppstm);
+ IStream_AddRef(*ppstm);
res = S_OK;
goto end;
end:
if (res == S_OK)
TRACE("<-- IStream %p\n", *ppstm);
- TRACE("<-- %08lx\n", res);
+ TRACE("<-- %08x\n", res);
return res;
}
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT WINAPI StorageBaseImpl_OpenStorage(
+static HRESULT WINAPI StorageBaseImpl_OpenStorage(
IStorage* iface,
const OLECHAR* pwcsName, /* [string][unique][in] */
IStorage* pstgPriority, /* [unique][in] */
ULONG foundPropertyIndex;
HRESULT res = STG_E_UNKNOWN;
- TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
+ TRACE("(%p, %s, %p, %x, %p, %d, %p)\n",
iface, debugstr_w(pwcsName), pstgPriority,
grfMode, snbExclude, reserved, ppstg);
/*
* As documented.
*/
- if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
+ if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
(grfMode & STGM_DELETEONRELEASE) ||
(grfMode & STGM_PRIORITY) )
{
goto end;
}
+ /*
+ * 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 ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
+ {
+ res = STG_E_ACCESSDENIED;
+ goto end;
+ }
+ }
+
/*
* Initialize the out parameter
*/
*/
newStorage = StorageInternalImpl_Construct(
This->ancestorStorage,
+ grfMode,
foundPropertyIndex);
if (newStorage != 0)
res = STG_E_FILENOTFOUND;
end:
- TRACE("<-- %08lx\n", res);
+ TRACE("<-- %08x\n", res);
return res;
}
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT WINAPI StorageBaseImpl_EnumElements(
+static HRESULT WINAPI StorageBaseImpl_EnumElements(
IStorage* iface,
DWORD reserved1, /* [in] */
void* reserved2, /* [size_is][unique][in] */
StorageBaseImpl *This = (StorageBaseImpl *)iface;
IEnumSTATSTGImpl* newEnum;
- TRACE("(%p, %ld, %p, %ld, %p)\n",
+ TRACE("(%p, %d, %p, %d, %p)\n",
iface, reserved1, reserved2, reserved3, ppenum);
/*
* Don't forget to nail down a reference to the new object before
* returning it.
*/
- IEnumSTATSTGImpl_AddRef(*ppenum);
+ IEnumSTATSTG_AddRef(*ppenum);
return S_OK;
}
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT WINAPI StorageBaseImpl_Stat(
+static HRESULT WINAPI StorageBaseImpl_Stat(
IStorage* iface,
STATSTG* pstatstg, /* [out] */
DWORD grfStatFlag) /* [in] */
BOOL readSuccessful;
HRESULT res = STG_E_UNKNOWN;
- TRACE("(%p, %p, %lx)\n",
+ TRACE("(%p, %p, %x)\n",
iface, pstatstg, grfStatFlag);
/*
&curProperty,
grfStatFlag);
+ pstatstg->grfMode = This->openFlags;
+ pstatstg->grfStateBits = This->stateBits;
+
res = S_OK;
goto end;
}
end:
if (res == S_OK)
{
- TRACE("<-- STATSTG: pwcsName: %s, type: %ld, cbSize.Low/High: %ld/%ld, grfMode: %08lx, grfLocksSupported: %ld, grfStateBits: %08lx\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
+ TRACE("<-- STATSTG: pwcsName: %s, type: %d, cbSize.Low/High: %d/%d, grfMode: %08x, grfLocksSupported: %d, grfStateBits: %08x\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
}
- TRACE("<-- %08lx\n", res);
+ TRACE("<-- %08x\n", res);
return res;
}
* of the deleted StgProperty object setting it with the new name and to
* perform a DestroyElement of the old StgProperty.
*/
-HRESULT WINAPI StorageBaseImpl_RenameElement(
+static HRESULT WINAPI StorageBaseImpl_RenameElement(
IStorage* iface,
const OLECHAR* pwcsOldName, /* [in] */
const OLECHAR* pwcsNewName) /* [in] */
return STG_E_FILEALREADYEXISTS;
}
- IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
+ IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration);
/*
* Search the enumeration for the old property name
/*
* At this point the renamed property has been inserted in the tree,
- * now, before to Destroy the old property we must zeroed it's dirProperty
+ * 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 tweek the StgProperty if it is a stream or a
+ * This means that we need to tweak the StgProperty if it is a stream or a
* non empty storage.
*/
StorageImpl_ReadProperty(This->ancestorStorage,
/*
* Invoke Destroy to get rid of the ole property and automatically redo
- * the linking of it's previous and next members...
+ * the linking of its previous and next members...
*/
- StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
+ IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
}
else
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT WINAPI StorageBaseImpl_CreateStream(
+static HRESULT WINAPI StorageBaseImpl_CreateStream(
IStorage* iface,
const OLECHAR* pwcsName, /* [string][in] */
DWORD grfMode, /* [in] */
StgProperty currentProperty, newStreamProperty;
ULONG foundPropertyIndex, newPropertyIndex;
- TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
+ TRACE("(%p, %s, %x, %d, %d, %p)\n",
iface, debugstr_w(pwcsName), grfMode,
reserved1, reserved2, ppstm);
if ( FAILED( validateSTGM(grfMode) ))
return STG_E_INVALIDFLAG;
- if ( !(grfMode & STGM_SHARE_EXCLUSIVE) )
+ if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
return STG_E_INVALIDFLAG;
/*
(grfMode & STGM_TRANSACTED))
return STG_E_INVALIDFUNCTION;
+ /*
+ * Check that we're compatible with the parent's storage mode
+ * if not in transacted mode
+ */
+ if(!(This->ancestorStorage->base.openFlags & STGM_TRANSACTED)) {
+ if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
+ return STG_E_ACCESSDENIED;
+ }
+
/*
* Initialize the out parameter
*/
/*
* An element with this name already exists
*/
- if (grfMode & STGM_CREATE)
+ if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
{
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
* Since we are returning a pointer to the interface, we have to nail down
* the reference.
*/
- StgStreamImpl_AddRef(*ppstm);
+ IStream_AddRef(*ppstm);
}
else
{
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT WINAPI StorageBaseImpl_SetClass(
+static HRESULT WINAPI StorageBaseImpl_SetClass(
IStorage* iface,
REFCLSID clsid) /* [in] */
{
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT WINAPI StorageImpl_CreateStorage(
+static HRESULT WINAPI StorageImpl_CreateStorage(
IStorage* iface,
const OLECHAR *pwcsName, /* [string][in] */
DWORD grfMode, /* [in] */
ULONG newPropertyIndex;
HRESULT hr;
- TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
+ TRACE("(%p, %s, %x, %d, %d, %p)\n",
iface, debugstr_w(pwcsName), grfMode,
reserved1, reserved2, ppstg);
if (pwcsName == 0)
return STG_E_INVALIDNAME;
+ /*
+ * Initialize the out parameter
+ */
+ *ppstg = NULL;
+
/*
* Validate the STGM flags
*/
if ( FAILED( validateSTGM(grfMode) ) ||
(grfMode & STGM_DELETEONRELEASE) )
+ {
+ WARN("bad grfMode: 0x%x\n", grfMode);
return STG_E_INVALIDFLAG;
+ }
/*
- * Initialize the out parameter
+ * Check that we're compatible with the parent's storage mode
*/
- *ppstg = 0;
+ if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->base.openFlags ) )
+ {
+ WARN("access denied\n");
+ return STG_E_ACCESSDENIED;
+ }
/*
* Create a property enumeration and search the properties
*/
- propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
- This->rootPropertySetIndex);
+ propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage,
+ This->base.rootPropertySetIndex);
foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
pwcsName,
/*
* An element with this name already exists
*/
- if (grfMode & STGM_CREATE)
+ if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
IStorage_DestroyElement(iface, pwcsName);
else
+ {
+ WARN("file already exists\n");
return STG_E_FILEALREADYEXISTS;
+ }
+ }
+ else if (STGM_ACCESS_MODE(This->base.openFlags) == STGM_READ)
+ {
+ WARN("read-only storage\n");
+ return STG_E_ACCESSDENIED;
}
/*
newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+ {
+ FIXME("name too long\n");
return STG_E_INVALIDNAME;
+ }
strcpyW(newProperty.name, pwcsName);
/*
* Obtain a free property in the property chain
*/
- newPropertyIndex = getFreeProperty(This->ancestorStorage);
+ newPropertyIndex = getFreeProperty(This->base.ancestorStorage);
/*
* Save the new property into the new property spot
*/
StorageImpl_WriteProperty(
- This->ancestorStorage,
+ This->base.ancestorStorage,
newPropertyIndex,
&newProperty);
/*
* Start by reading the root property
*/
- readSuccessful = StorageImpl_ReadProperty(storage->ancestorStorage,
+ readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage,
currentPropertyIndex,
¤tProperty);
if (readSuccessful)
* obtain the new count of property blocks
*/
blockCount = BlockChainStream_GetCount(
- storage->ancestorStorage->rootBlockChain)+1;
+ storage->base.ancestorStorage->rootBlockChain)+1;
/*
* initialize the size used by the property stream
/*
* add a property block to the property chain
*/
- BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
+ BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize);
/*
* memset the empty property in order to initialize the unused newly
propertyIndex++)
{
StorageImpl_WriteProperty(
- storage->ancestorStorage,
+ storage->base.ancestorStorage,
propertyIndex,
&emptyProperty);
}
/*
* Read the root property
*/
- StorageImpl_ReadProperty(storage->ancestorStorage,
- storage->rootPropertySetIndex,
+ StorageImpl_ReadProperty(storage->base.ancestorStorage,
+ storage->base.rootPropertySetIndex,
¤tProperty);
if (currentProperty.dirProperty != PROPERTY_NULL)
/*
* Read
*/
- StorageImpl_ReadProperty(storage->ancestorStorage,
+ StorageImpl_ReadProperty(storage->base.ancestorStorage,
currentProperty.dirProperty,
¤tProperty);
{
if (previous != PROPERTY_NULL)
{
- StorageImpl_ReadProperty(storage->ancestorStorage,
+ StorageImpl_ReadProperty(storage->base.ancestorStorage,
previous,
¤tProperty);
current = previous;
else
{
currentProperty.previousProperty = newPropertyIndex;
- StorageImpl_WriteProperty(storage->ancestorStorage,
+ StorageImpl_WriteProperty(storage->base.ancestorStorage,
current,
¤tProperty);
found = 1;
{
if (next != PROPERTY_NULL)
{
- StorageImpl_ReadProperty(storage->ancestorStorage,
+ StorageImpl_ReadProperty(storage->base.ancestorStorage,
next,
¤tProperty);
current = next;
else
{
currentProperty.nextProperty = newPropertyIndex;
- StorageImpl_WriteProperty(storage->ancestorStorage,
+ StorageImpl_WriteProperty(storage->base.ancestorStorage,
current,
¤tProperty);
found = 1;
else
{
/*
- * The root storage is empty, link the new property to it's dir property
+ * The root storage is empty, link the new property to its dir property
*/
currentProperty.dirProperty = newPropertyIndex;
- StorageImpl_WriteProperty(storage->ancestorStorage,
- storage->rootPropertySetIndex,
+ StorageImpl_WriteProperty(storage->base.ancestorStorage,
+ storage->base.rootPropertySetIndex,
¤tProperty);
}
}
/*************************************************************************
* CopyTo (IStorage)
*/
-HRESULT WINAPI StorageImpl_CopyTo(
+static HRESULT WINAPI StorageImpl_CopyTo(
IStorage* iface,
DWORD ciidExclude, /* [in] */
const IID* rgiidExclude, /* [size_is][unique][in] */
if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
FIXME("Exclude option not implemented\n");
- TRACE("(%p, %ld, %p, %p, %p)\n",
+ TRACE("(%p, %d, %p, %p, %p)\n",
iface, ciidExclude, rgiidExclude,
snbExclude, pstgDest);
}
else
{
- WARN("unknown element type: %ld\n", curElement.type);
+ WARN("unknown element type: %d\n", curElement.type);
}
} while (hr == S_OK);
/*************************************************************************
* MoveElementTo (IStorage)
*/
-HRESULT WINAPI StorageImpl_MoveElementTo(
+static HRESULT WINAPI StorageImpl_MoveElementTo(
IStorage* iface,
const OLECHAR *pwcsName, /* [string][in] */
IStorage *pstgDest, /* [unique][in] */
const OLECHAR *pwcsNewName,/* [string][in] */
DWORD grfFlags) /* [in] */
{
- FIXME("not implemented!\n");
+ FIXME("(%p %s %p %s %u): stub\n", iface,
+ debugstr_w(pwcsName), pstgDest,
+ debugstr_w(pwcsNewName), grfFlags);
return E_NOTIMPL;
}
/*************************************************************************
* Commit (IStorage)
+ *
+ * Ensures that any changes made to a storage object open in transacted mode
+ * are reflected in the parent storage
+ *
+ * NOTES
+ * Wine doesn't implement transacted mode, which seems to be a basic
+ * optimization, so we can ignore this stub for now.
*/
-HRESULT WINAPI StorageImpl_Commit(
+static HRESULT WINAPI StorageImpl_Commit(
IStorage* iface,
DWORD grfCommitFlags)/* [in] */
{
- FIXME("(%ld): stub!\n", grfCommitFlags);
+ FIXME("(%p %d): stub\n", iface, grfCommitFlags);
return S_OK;
}
/*************************************************************************
* Revert (IStorage)
+ *
+ * Discard all changes that have been made since the last commit operation
*/
-HRESULT WINAPI StorageImpl_Revert(
+static HRESULT WINAPI StorageImpl_Revert(
IStorage* iface)
{
- FIXME("not implemented!\n");
+ FIXME("(%p): stub\n", iface);
return E_NOTIMPL;
}
/*************************************************************************
* DestroyElement (IStorage)
*
- * Stategy: This implementation is build this way for simplicity not for speed.
- * I always delete the top most element of the enumeration and adjust
+ * Strategy: This implementation is built this way for simplicity not for speed.
+ * I always delete the topmost element of the enumeration and adjust
* the deleted element pointer all the time. This takes longer to
* do but allow to reinvoke DestroyElement whenever we encounter a
- * storage object. The optimisation reside in the usage of another
- * enumeration stategy that would give all the leaves of a storage
+ * storage object. The optimisation resides in the usage of another
+ * enumeration strategy that would give all the leaves of a storage
* first. (postfix order)
*/
-HRESULT WINAPI StorageImpl_DestroyElement(
+static HRESULT WINAPI StorageImpl_DestroyElement(
IStorage* iface,
const OLECHAR *pwcsName)/* [string][in] */
{
StgProperty parentProperty;
ULONG foundPropertyIndexToDelete;
ULONG typeOfRelation;
- ULONG parentPropertyId;
+ ULONG parentPropertyId = 0;
TRACE("(%p, %s)\n",
iface, debugstr_w(pwcsName));
* Create a property enumeration to search the property with the given name
*/
propertyEnumeration = IEnumSTATSTGImpl_Construct(
- This->ancestorStorage,
- This->rootPropertySetIndex);
+ This->base.ancestorStorage,
+ This->base.rootPropertySetIndex);
foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
propertyEnumeration,
/*
* 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 it's sibling...
+ * the parent is This. Otherwise, the parent is one of its sibling...
*/
/*
* First, read This's StgProperty..
*/
res = StorageImpl_ReadProperty(
- This->ancestorStorage,
- This->rootPropertySetIndex,
+ This->base.ancestorStorage,
+ This->base.rootPropertySetIndex,
&parentProperty);
assert(res);
* Set data as it would have been done in the else part...
*/
typeOfRelation = PROPERTY_RELATION_DIR;
- parentPropertyId = This->rootPropertySetIndex;
+ parentPropertyId = This->base.rootPropertySetIndex;
}
else
{
IEnumSTATSTGImpl* propertyEnumeration2;
propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
- This->ancestorStorage,
- This->rootPropertySetIndex);
+ This->base.ancestorStorage,
+ This->base.rootPropertySetIndex);
typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
propertyEnumeration2,
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
+static HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
STATSTG* pstatstg, /* [out] */
DWORD grfStatFlag) /* [in] */
{
return result;
}
+/******************************************************************************
+ * Internal stream list handlers
+ */
+
+void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm)
+{
+ TRACE("Stream added (stg=%p strm=%p)\n", stg, strm);
+ list_add_tail(&stg->strmHead,&strm->StrmListEntry);
+}
+
+void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm)
+{
+ TRACE("Stream removed (stg=%p strm=%p)\n", stg,strm);
+ list_remove(&(strm->StrmListEntry));
+}
+
+static void StorageBaseImpl_DeleteAll(StorageBaseImpl * stg)
+{
+ struct list *cur, *cur2;
+ StgStreamImpl *strm=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);
+ strm->parentStorage = NULL;
+ list_remove(cur);
+ }
+}
/*********************************************************************
(IStorage*)parentStorage,
propertyToDelete.name,
0,
- STGM_SHARE_EXCLUSIVE,
+ STGM_WRITE | STGM_SHARE_EXCLUSIVE,
0,
0,
&childStorage);
} while ((hr == S_OK) && (destroyHr == S_OK));
/*
- * Invalidate the property by zeroing it's name member.
+ * Invalidate the property by zeroing its name member.
*/
propertyToDelete.sizeOfNameString = 0;
- StorageImpl_WriteProperty(parentStorage->ancestorStorage,
+ StorageImpl_WriteProperty(parentStorage->base.ancestorStorage,
indexOfPropertyToDelete,
&propertyToDelete);
IStream_Release(pis);
/*
- * Invalidate the property by zeroing it's name member.
+ * Invalidate the property by zeroing its name member.
*/
propertyToDelete.sizeOfNameString = 0;
* but since we are here to zap it, I don't do it...
*/
StorageImpl_WriteProperty(
- parentStorage->ancestorStorage,
+ parentStorage->base.ancestorStorage,
indexOfPropertyToDelete,
&propertyToDelete);
* Read the storage property
*/
res = StorageImpl_ReadProperty(
- storage->ancestorStorage,
+ storage->base.ancestorStorage,
storePropertyIndex,
&storeProperty);
}
hr = StorageImpl_WriteProperty(
- storage->ancestorStorage,
+ storage->base.ancestorStorage,
storePropertyIndex,
&storeProperty);
* Write back the parent property
*/
res = StorageImpl_WriteProperty(
- This->ancestorStorage,
+ This->base.ancestorStorage,
parentPropertyId,
&parentProperty);
if(! res)
/******************************************************************************
* SetElementTimes (IStorage)
*/
-HRESULT WINAPI StorageImpl_SetElementTimes(
+static HRESULT WINAPI StorageImpl_SetElementTimes(
IStorage* iface,
const OLECHAR *pwcsName,/* [string][in] */
const FILETIME *pctime, /* [in] */
/******************************************************************************
* SetStateBits (IStorage)
*/
-HRESULT WINAPI StorageImpl_SetStateBits(
+static HRESULT WINAPI StorageImpl_SetStateBits(
IStorage* iface,
DWORD grfStateBits,/* [in] */
DWORD grfMask) /* [in] */
{
- FIXME("not implemented!\n");
- return E_NOTIMPL;
+ StorageImpl* const This = (StorageImpl*)iface;
+ This->base.stateBits = (This->base.stateBits & ~grfMask) | (grfStateBits & grfMask);
+ return S_OK;
}
-HRESULT StorageImpl_Construct(
+/*
+ * Virtual function table for the IStorage32Impl class.
+ */
+static const IStorageVtbl Storage32Impl_Vtbl =
+{
+ StorageBaseImpl_QueryInterface,
+ StorageBaseImpl_AddRef,
+ StorageBaseImpl_Release,
+ StorageBaseImpl_CreateStream,
+ StorageBaseImpl_OpenStream,
+ StorageImpl_CreateStorage,
+ StorageBaseImpl_OpenStorage,
+ StorageImpl_CopyTo,
+ StorageImpl_MoveElementTo,
+ StorageImpl_Commit,
+ StorageImpl_Revert,
+ StorageBaseImpl_EnumElements,
+ StorageImpl_DestroyElement,
+ StorageBaseImpl_RenameElement,
+ StorageImpl_SetElementTimes,
+ StorageBaseImpl_SetClass,
+ StorageImpl_SetStateBits,
+ StorageImpl_Stat
+};
+
+static HRESULT StorageImpl_Construct(
StorageImpl* This,
HANDLE hFile,
LPCOLESTR pwcsName,
memset(This, 0, sizeof(StorageImpl));
+ /*
+ * Initialize stream list
+ */
+
+ list_init(&This->base.strmHead);
+
/*
* Initialize the virtual function table.
*/
- This->lpVtbl = &Storage32Impl_Vtbl;
- This->v_destructor = &StorageImpl_Destroy;
+ This->base.lpVtbl = &Storage32Impl_Vtbl;
+ This->base.pssVtbl = &IPropertySetStorage_Vtbl;
+ This->base.v_destructor = &StorageImpl_Destroy;
+ This->base.openFlags = (openFlags & ~STGM_CREATE);
/*
* This is the top-level storage so initialize the ancestor pointer
* to this.
*/
- This->ancestorStorage = This;
+ This->base.ancestorStorage = This;
/*
* Initialize the physical support of the storage.
if (fileCreate)
{
ULARGE_INTEGER size;
- BYTE* bigBlockBuffer;
+ BYTE bigBlockBuffer[BIG_BLOCK_SIZE];
/*
* Initialize all header variables:
/*
* Initialize the big block depot
*/
- bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
- StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+ StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
}
else
{
return STG_E_READFAULT;
/*
- * Write the root property
+ * Write the root property (memory only)
*/
if (fileCreate)
{
if ( (currentProperty.sizeOfNameString != 0 ) &&
(currentProperty.propertyType == PROPTYPE_ROOT) )
{
- This->rootPropertySetIndex = currentPropertyIndex;
+ This->base.rootPropertySetIndex = currentPropertyIndex;
}
}
currentPropertyIndex++;
- } while (readSuccessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
+ } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) );
if (!readSuccessful)
{
* Create the block chain abstraction for the small block root chain.
*/
if(!(This->smallBlockRootChain =
- BlockChainStream_Construct(This, NULL, This->rootPropertySetIndex)))
+ BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex)))
return STG_E_READFAULT;
return hr;
}
-void StorageImpl_Destroy(
- StorageImpl* This)
+static void StorageImpl_Destroy(StorageBaseImpl* iface)
{
+ StorageImpl *This = (StorageImpl*) iface;
TRACE("(%p)\n", This);
+ StorageBaseImpl_DeleteAll(&This->base);
+
HeapFree(GetProcessHeap(), 0, This->pwcsName);
BlockChainStream_Destroy(This->smallBlockRootChain);
BlockChainStream_Destroy(This->smallBlockDepotChain);
BIGBLOCKFILE_Destructor(This->bigBlockFile);
- return;
+ HeapFree(GetProcessHeap(), 0, This);
}
/******************************************************************************
* If the big block depot is filled, this method will enlarge it.
*
*/
-ULONG StorageImpl_GetNextFreeBigBlock(
+static ULONG StorageImpl_GetNextFreeBigBlock(
StorageImpl* This)
{
ULONG depotBlockIndexPos;
- void *depotBuffer;
+ BYTE depotBuffer[BIG_BLOCK_SIZE];
+ BOOL success;
ULONG depotBlockOffset;
ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
ULONG nextBlockIndex = BLOCK_SPECIAL;
}
}
- depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+ success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
- if (depotBuffer != 0)
+ if (success)
{
while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
( nextBlockIndex != BLOCK_UNUSED))
depotBlockOffset += sizeof(ULONG);
}
-
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
}
depotIndex++;
depotBlockOffset = 0;
}
+ /*
+ * make sure that the block physically exists before using it
+ */
+ BIGBLOCKFILE_EnsureExists(This->bigBlockFile, freeBlock);
+
This->prevFreeBlock = freeBlock;
return freeBlock;
* This will create a depot block, essentially it is a block initialized
* to BLOCK_UNUSEDs.
*/
-void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
+static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
{
- BYTE* blockBuffer;
-
- blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+ BYTE blockBuffer[BIG_BLOCK_SIZE];
/*
* Initialize blocks as free
*/
memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
-
- StorageImpl_ReleaseBigBlock(This, blockBuffer);
+ StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
}
/******************************************************************************
* index. This method is only for depot indexes equal or greater than
* COUNT_BBDEPOTINHEADER.
*/
-ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
+static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
{
ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
}
if (extBlockIndex != BLOCK_UNUSED)
- {
- BYTE* depotBuffer;
-
- depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
-
- if (depotBuffer != 0)
- {
- StorageUtl_ReadDWord(depotBuffer,
- extBlockOffset * sizeof(ULONG),
- &blockIndex);
-
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
- }
- }
+ StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex,
+ extBlockOffset * sizeof(ULONG), &blockIndex);
return blockIndex;
}
* This method is only for depot indexes equal or greater than
* COUNT_BBDEPOTINHEADER.
*/
-void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
- ULONG depotIndex,
- ULONG blockIndex)
+static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
{
ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
if (extBlockIndex != BLOCK_UNUSED)
{
- BYTE* depotBuffer;
-
- depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
-
- if (depotBuffer != 0)
- {
- StorageUtl_WriteDWord(depotBuffer,
- extBlockOffset * sizeof(ULONG),
- blockIndex);
-
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
- }
+ StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
+ extBlockOffset * sizeof(ULONG),
+ blockIndex);
}
}
*
* Creates an extended depot block.
*/
-ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
+static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
{
ULONG numExtBlocks = This->extBigBlockDepotCount;
ULONG nextExtBlock = This->extBigBlockDepotStart;
- BYTE* depotBuffer = NULL;
+ BYTE depotBuffer[BIG_BLOCK_SIZE];
ULONG index = BLOCK_UNUSED;
ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
/*
* Add the new extended block to the chain.
*/
- depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
- StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
+ StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
+ index);
}
/*
* Initialize this block.
*/
- depotBuffer = StorageImpl_GetBigBlock(This, index);
memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
+ StorageImpl_WriteBigBlock(This, index, depotBuffer);
return index;
}
*
* This method will flag the specified block as free in the big block depot.
*/
-void StorageImpl_FreeBigBlock(
+static void StorageImpl_FreeBigBlock(
StorageImpl* This,
ULONG blockIndex)
{
*
* See Windows documentation for more details on IStorage methods.
*/
-HRESULT StorageImpl_GetNextBlockInChain(
+static HRESULT StorageImpl_GetNextBlockInChain(
StorageImpl* This,
ULONG blockIndex,
ULONG* nextBlockIndex)
ULONG offsetInDepot = blockIndex * sizeof (ULONG);
ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
- void* depotBuffer;
+ BYTE depotBuffer[BIG_BLOCK_SIZE];
+ BOOL success;
ULONG depotBlockIndexPos;
int index;
if(depotBlockCount >= This->bigBlockDepotCount)
{
- WARN("depotBlockCount %ld, bigBlockDepotCount %ld\n", depotBlockCount,
+ WARN("depotBlockCount %d, bigBlockDepotCount %d\n", depotBlockCount,
This->bigBlockDepotCount);
return STG_E_READFAULT;
}
depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
}
- depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+ success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
- if (!depotBuffer)
+ if (!success)
return STG_E_READFAULT;
for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
This->blockDepotCached[index] = *nextBlockIndex;
}
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
}
*nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
* - BLOCK_UNUSED: there is no next extended block.
* - Any other return values denotes failure.
*/
-ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
+static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
{
ULONG nextBlockIndex = BLOCK_SPECIAL;
ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
- void* depotBuffer;
-
- depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
-
- if (depotBuffer!=0)
- {
- StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
- }
+ StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
+ &nextBlockIndex);
return nextBlockIndex;
}
* Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
*
*/
-void StorageImpl_SetNextBlockInChain(
+static void StorageImpl_SetNextBlockInChain(
StorageImpl* This,
ULONG blockIndex,
ULONG nextBlock)
ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
ULONG depotBlockIndexPos;
- void* depotBuffer;
assert(depotBlockCount < This->bigBlockDepotCount);
assert(blockIndex != nextBlock);
depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
}
- depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
-
- if (depotBuffer!=0)
- {
- StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
- }
-
+ StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
+ nextBlock);
/*
* Update the cached block depot, if necessary.
*/
*
* This method will read in the file header, i.e. big block index -1.
*/
-HRESULT StorageImpl_LoadFileHeader(
+static HRESULT StorageImpl_LoadFileHeader(
StorageImpl* This)
{
HRESULT hr = STG_E_FILENOTFOUND;
- void* headerBigBlock = NULL;
+ BYTE headerBigBlock[BIG_BLOCK_SIZE];
+ BOOL success;
int index;
+ TRACE("\n");
/*
* Get a pointer to the big block of data containing the header.
*/
- headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
+ success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
/*
* Extract the information from the header.
*/
- if (headerBigBlock!=0)
+ if (success)
{
/*
* Check for the "magic number" signature and return an error if it is not
*/
if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
{
- StorageImpl_ReleaseBigBlock(This, headerBigBlock);
return STG_E_OLDFORMAT;
}
if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
{
- StorageImpl_ReleaseBigBlock(This, headerBigBlock);
return STG_E_INVALIDHEADER;
}
}
else
hr = S_OK;
-
- /*
- * Release the block.
- */
- StorageImpl_ReleaseBigBlock(This, headerBigBlock);
}
return hr;
*
* This method will save to the file the header, i.e. big block -1.
*/
-void StorageImpl_SaveFileHeader(
+static void StorageImpl_SaveFileHeader(
StorageImpl* This)
{
BYTE headerBigBlock[BIG_BLOCK_SIZE];
{
BYTE currentProperty[PROPSET_BLOCK_SIZE];
ULARGE_INTEGER offsetInPropSet;
- BOOL readSuccessful;
+ HRESULT readRes;
ULONG bytesRead;
offsetInPropSet.u.HighPart = 0;
offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE;
- readSuccessful = BlockChainStream_ReadAt(
+ readRes = BlockChainStream_ReadAt(
This->rootBlockChain,
offsetInPropSet,
PROPSET_BLOCK_SIZE,
currentProperty,
&bytesRead);
- if (readSuccessful)
+ if (SUCCEEDED(readRes))
{
/* replace the name of root entry (often "Root Entry") by the file name */
- WCHAR *propName = (index == This->rootPropertySetIndex) ?
+ WCHAR *propName = (index == This->base.rootPropertySetIndex) ?
This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME;
memset(buffer->name, 0, sizeof(buffer->name));
buffer->size.u.HighPart = 0;
}
- return readSuccessful;
+ return SUCCEEDED(readRes) ? TRUE : FALSE;
}
/*********************************************************************
{
BYTE currentProperty[PROPSET_BLOCK_SIZE];
ULARGE_INTEGER offsetInPropSet;
- BOOL writeSuccessful;
+ HRESULT writeRes;
ULONG bytesWritten;
offsetInPropSet.u.HighPart = 0;
OFFSET_PS_SIZE,
buffer->size.u.LowPart);
- writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
- offsetInPropSet,
- PROPSET_BLOCK_SIZE,
- currentProperty,
- &bytesWritten);
- return writeSuccessful;
+ writeRes = BlockChainStream_WriteAt(This->rootBlockChain,
+ offsetInPropSet,
+ PROPSET_BLOCK_SIZE,
+ currentProperty,
+ &bytesWritten);
+ return SUCCEEDED(writeRes) ? TRUE : FALSE;
}
-BOOL StorageImpl_ReadBigBlock(
+static BOOL StorageImpl_ReadBigBlock(
StorageImpl* This,
ULONG blockIndex,
void* buffer)
{
- void* bigBlockBuffer;
+ ULARGE_INTEGER ulOffset;
+ DWORD read;
- bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
- if (bigBlockBuffer!=0)
- {
- memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
+ StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
+ return (read == This->bigBlockSize);
+}
- StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+static BOOL StorageImpl_ReadDWordFromBigBlock(
+ StorageImpl* This,
+ ULONG blockIndex,
+ ULONG offset,
+ DWORD* value)
+{
+ ULARGE_INTEGER ulOffset;
+ DWORD read;
+ DWORD tmp;
- return TRUE;
- }
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
+ ulOffset.u.LowPart += offset;
- return FALSE;
+ StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
+ *value = le32toh(tmp);
+ return (read == sizeof(DWORD));
}
-BOOL StorageImpl_WriteBigBlock(
+static BOOL StorageImpl_WriteBigBlock(
StorageImpl* This,
ULONG blockIndex,
void* buffer)
{
- void* bigBlockBuffer;
-
- bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
-
- if (bigBlockBuffer!=0)
- {
- memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
+ ULARGE_INTEGER ulOffset;
+ DWORD wrote;
- StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
- return TRUE;
- }
-
- return FALSE;
+ StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
+ return (wrote == This->bigBlockSize);
}
-void* StorageImpl_GetROBigBlock(
+static BOOL StorageImpl_WriteDWordToBigBlock(
StorageImpl* This,
- ULONG blockIndex)
+ ULONG blockIndex,
+ ULONG offset,
+ DWORD value)
{
- return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
-}
+ ULARGE_INTEGER ulOffset;
+ DWORD wrote;
-void* StorageImpl_GetBigBlock(
- StorageImpl* This,
- ULONG blockIndex)
-{
- return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
-}
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
+ ulOffset.u.LowPart += offset;
-void StorageImpl_ReleaseBigBlock(
- StorageImpl* This,
- void* pBigBlock)
-{
- BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
+ value = htole32(value);
+ StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
+ return (wrote == sizeof(DWORD));
}
/******************************************************************************
{
ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
ULARGE_INTEGER size, offset;
- ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
+ ULONG cbRead, cbWritten;
+ ULARGE_INTEGER cbTotalRead;
ULONG propertyIndex;
- BOOL successRead, successWrite;
+ HRESULT resWrite = S_OK;
+ HRESULT resRead;
StgProperty chainProperty;
BYTE *buffer;
BlockChainStream *bbTempChain = NULL;
*/
offset.u.LowPart = 0;
offset.u.HighPart = 0;
- cbTotalRead = 0;
- cbTotalWritten = 0;
+ cbTotalRead.QuadPart = 0;
- buffer = (BYTE *) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
+ buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
do
{
- successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
- offset,
- DEF_SMALL_BLOCK_SIZE,
- buffer,
- &cbRead);
- cbTotalRead += cbRead;
+ resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
+ offset,
+ This->smallBlockSize,
+ buffer,
+ &cbRead);
+ if (FAILED(resRead))
+ break;
- successWrite = BlockChainStream_WriteAt(bbTempChain,
+ if (cbRead > 0)
+ {
+ cbTotalRead.QuadPart += cbRead;
+
+ resWrite = BlockChainStream_WriteAt(bbTempChain,
offset,
cbRead,
buffer,
&cbWritten);
- cbTotalWritten += cbWritten;
- offset.u.LowPart += This->smallBlockSize;
+ if (FAILED(resWrite))
+ break;
- } while (successRead && successWrite);
+ offset.u.LowPart += This->smallBlockSize;
+ }
+ } while (cbTotalRead.QuadPart < size.QuadPart);
HeapFree(GetProcessHeap(),0,buffer);
- assert(cbTotalRead == cbTotalWritten);
+ if (FAILED(resRead) || FAILED(resWrite))
+ {
+ ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
+ BlockChainStream_Destroy(bbTempChain);
+ return NULL;
+ }
/*
* Destroy the small block chain.
return bigBlockChain;
}
-/******************************************************************************
-** Storage32InternalImpl implementation
-*/
-
-StorageInternalImpl* StorageInternalImpl_Construct(
- StorageImpl* ancestorStorage,
- ULONG rootPropertyIndex)
+static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
{
- StorageInternalImpl* newStorage;
-
- /*
- * Allocate space for the new storage object
- */
- newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
-
- if (newStorage!=0)
- {
- memset(newStorage, 0, sizeof(StorageInternalImpl));
-
- /*
- * Initialize the virtual function table.
- */
- newStorage->lpVtbl = &Storage32InternalImpl_Vtbl;
- newStorage->v_destructor = &StorageInternalImpl_Destroy;
-
- /*
- * Keep the ancestor storage pointer and nail a reference to it.
- */
- newStorage->ancestorStorage = ancestorStorage;
- StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
-
- /*
- * Keep the index of the root property set for this storage,
- */
- newStorage->rootPropertySetIndex = rootPropertyIndex;
+ StorageInternalImpl* This = (StorageInternalImpl*) iface;
- return newStorage;
- }
-
- return 0;
-}
-
-void StorageInternalImpl_Destroy(
- StorageInternalImpl* This)
-{
- StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
+ StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage);
HeapFree(GetProcessHeap(), 0, This);
}
** The non-root storages cannot be opened in transacted mode thus this function
** does nothing.
*/
-HRESULT WINAPI StorageInternalImpl_Commit(
+static HRESULT WINAPI StorageInternalImpl_Commit(
IStorage* iface,
DWORD grfCommitFlags) /* [in] */
{
** The non-root storages cannot be opened in transacted mode thus this function
** does nothing.
*/
-HRESULT WINAPI StorageInternalImpl_Revert(
+static HRESULT WINAPI StorageInternalImpl_Revert(
IStorage* iface)
{
return S_OK;
}
-/******************************************************************************
-** IEnumSTATSTGImpl implementation
-*/
-
-IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
- StorageImpl* parentStorage,
- ULONG firstPropertyNode)
-{
- IEnumSTATSTGImpl* newEnumeration;
-
- newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
-
- if (newEnumeration!=0)
- {
- /*
- * Set-up the virtual function table and reference count.
- */
- newEnumeration->lpVtbl = &IEnumSTATSTGImpl_Vtbl;
- newEnumeration->ref = 0;
-
- /*
- * We want to nail-down the reference to the storage in case the
- * enumeration out-lives the storage in the client application.
- */
- 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);
-
- /*
- * Make sure the current node of the iterator is the first one.
- */
- IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
- }
-
- return newEnumeration;
-}
-
-void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
+static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
{
IStorage_Release((IStorage*)This->parentStorage);
HeapFree(GetProcessHeap(), 0, This->stackToVisit);
HeapFree(GetProcessHeap(), 0, This);
}
-HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
+static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
IEnumSTATSTG* iface,
REFIID riid,
void** ppvObject)
/*
* Compare the riid with the interface IDs implemented by this object.
*/
- if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
- {
- *ppvObject = (IEnumSTATSTG*)This;
- }
- else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IEnumSTATSTG, riid))
{
*ppvObject = (IEnumSTATSTG*)This;
+ IEnumSTATSTG_AddRef((IEnumSTATSTG*)This);
+ return S_OK;
}
- /*
- * 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
- */
- IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
-
- return S_OK;
+ return E_NOINTERFACE;
}
-ULONG WINAPI IEnumSTATSTGImpl_AddRef(
+static ULONG WINAPI IEnumSTATSTGImpl_AddRef(
IEnumSTATSTG* iface)
{
IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
return InterlockedIncrement(&This->ref);
}
-ULONG WINAPI IEnumSTATSTGImpl_Release(
+static ULONG WINAPI IEnumSTATSTGImpl_Release(
IEnumSTATSTG* iface)
{
IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
return newRef;
}
-HRESULT WINAPI IEnumSTATSTGImpl_Next(
+static HRESULT WINAPI IEnumSTATSTGImpl_Next(
IEnumSTATSTG* iface,
ULONG celt,
STATSTG* rgelt,
}
-HRESULT WINAPI IEnumSTATSTGImpl_Skip(
+static HRESULT WINAPI IEnumSTATSTGImpl_Skip(
IEnumSTATSTG* iface,
ULONG celt)
{
return S_FALSE;
}
-HRESULT WINAPI IEnumSTATSTGImpl_Reset(
+static HRESULT WINAPI IEnumSTATSTGImpl_Reset(
IEnumSTATSTG* iface)
{
IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
return S_OK;
}
-HRESULT WINAPI IEnumSTATSTGImpl_Clone(
+static HRESULT WINAPI IEnumSTATSTGImpl_Clone(
IEnumSTATSTG* iface,
IEnumSTATSTG** ppenum)
{
return S_OK;
}
-INT IEnumSTATSTGImpl_FindParentProperty(
+static INT IEnumSTATSTGImpl_FindParentProperty(
IEnumSTATSTGImpl *This,
ULONG childProperty,
StgProperty *currentProperty,
return PROPERTY_NULL;
}
-ULONG IEnumSTATSTGImpl_FindProperty(
+static ULONG IEnumSTATSTGImpl_FindProperty(
IEnumSTATSTGImpl* This,
const OLECHAR* lpszPropName,
StgProperty* currentProperty)
return PROPERTY_NULL;
}
-void IEnumSTATSTGImpl_PushSearchNode(
+static void IEnumSTATSTGImpl_PushSearchNode(
IEnumSTATSTGImpl* This,
ULONG nodeToPush)
{
}
}
-ULONG IEnumSTATSTGImpl_PopSearchNode(
+static ULONG IEnumSTATSTGImpl_PopSearchNode(
IEnumSTATSTGImpl* This,
BOOL remove)
{
return topNode;
}
+/*
+ * Virtual function table for the IEnumSTATSTGImpl class.
+ */
+static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
+{
+ IEnumSTATSTGImpl_QueryInterface,
+ IEnumSTATSTGImpl_AddRef,
+ IEnumSTATSTGImpl_Release,
+ IEnumSTATSTGImpl_Next,
+ IEnumSTATSTGImpl_Skip,
+ IEnumSTATSTGImpl_Reset,
+ IEnumSTATSTGImpl_Clone
+};
+
+/******************************************************************************
+** IEnumSTATSTGImpl implementation
+*/
+
+static IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
+ StorageImpl* parentStorage,
+ ULONG firstPropertyNode)
+{
+ IEnumSTATSTGImpl* newEnumeration;
+
+ newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
+
+ if (newEnumeration!=0)
+ {
+ /*
+ * Set-up the virtual function table and reference count.
+ */
+ newEnumeration->lpVtbl = &IEnumSTATSTGImpl_Vtbl;
+ newEnumeration->ref = 0;
+
+ /*
+ * We want to nail-down the reference to the storage in case the
+ * enumeration out-lives the storage in the client application.
+ */
+ 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);
+
+ /*
+ * Make sure the current node of the iterator is the first one.
+ */
+ IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
+ }
+
+ return newEnumeration;
+}
+
+/*
+ * Virtual function table for the Storage32InternalImpl class.
+ */
+static const IStorageVtbl Storage32InternalImpl_Vtbl =
+{
+ StorageBaseImpl_QueryInterface,
+ StorageBaseImpl_AddRef,
+ StorageBaseImpl_Release,
+ StorageBaseImpl_CreateStream,
+ StorageBaseImpl_OpenStream,
+ StorageImpl_CreateStorage,
+ StorageBaseImpl_OpenStorage,
+ StorageImpl_CopyTo,
+ StorageImpl_MoveElementTo,
+ StorageInternalImpl_Commit,
+ StorageInternalImpl_Revert,
+ StorageBaseImpl_EnumElements,
+ StorageImpl_DestroyElement,
+ StorageBaseImpl_RenameElement,
+ StorageImpl_SetElementTimes,
+ StorageBaseImpl_SetClass,
+ StorageImpl_SetStateBits,
+ StorageBaseImpl_Stat
+};
+
+/******************************************************************************
+** Storage32InternalImpl implementation
+*/
+
+static StorageInternalImpl* StorageInternalImpl_Construct(
+ StorageImpl* ancestorStorage,
+ DWORD openFlags,
+ ULONG rootPropertyIndex)
+{
+ 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);
+
+ /*
+ * Initialize the virtual function table.
+ */
+ newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl;
+ newStorage->base.v_destructor = &StorageInternalImpl_Destroy;
+ 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));
+
+ /*
+ * Keep the index of the root property set for this storage,
+ */
+ newStorage->base.rootPropertySetIndex = rootPropertyIndex;
+
+ return newStorage;
+ }
+
+ return 0;
+}
+
/******************************************************************************
** StorageUtl implementation
*/
-void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
+void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value)
+{
+ WORD tmp;
+
+ memcpy(&tmp, buffer+offset, sizeof(WORD));
+ *value = le16toh(tmp);
+}
+
+void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value)
{
- memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
+ value = htole16(value);
+ memcpy(buffer+offset, &value, sizeof(WORD));
}
-void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
+void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value)
{
- memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
+ DWORD tmp;
+
+ memcpy(&tmp, buffer+offset, sizeof(DWORD));
+ *value = le32toh(tmp);
}
-void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
+void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value)
{
- memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
+ value = htole32(value);
+ memcpy(buffer+offset, &value, sizeof(DWORD));
}
-void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
+void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
+ ULARGE_INTEGER* value)
{
- memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
+#ifdef WORDS_BIGENDIAN
+ ULARGE_INTEGER tmp;
+
+ memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
+ value->u.LowPart = htole32(tmp.u.HighPart);
+ value->u.HighPart = htole32(tmp.u.LowPart);
+#else
+ memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER));
+#endif
}
-void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
+void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
+ const ULARGE_INTEGER *value)
+{
+#ifdef WORDS_BIGENDIAN
+ ULARGE_INTEGER tmp;
+
+ tmp.u.LowPart = htole32(value->u.HighPart);
+ tmp.u.HighPart = htole32(value->u.LowPart);
+ memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
+#else
+ memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER));
+#endif
+}
+
+void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value)
{
StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
- memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
+ memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
}
-void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
+void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value)
{
StorageUtl_WriteDWord(buffer, offset, value->Data1);
StorageUtl_WriteWord(buffer, offset+4, value->Data2);
StorageUtl_WriteWord(buffer, offset+6, value->Data3);
- memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
+ memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4));
}
void StorageUtl_CopyPropertyToSTATSTG(
* This->headOfStreamPlaceHolder.
*
*/
-ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
+static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
{
StgProperty chainProperty;
BOOL readSuccessful;
* This is not the size of the stream as the last block may not be full!
*
*/
-ULONG BlockChainStream_GetCount(BlockChainStream* This)
+static ULONG BlockChainStream_GetCount(BlockChainStream* This)
{
ULONG blockIndex;
ULONG count = 0;
* bytesRead may be NULL.
* Failure will be returned if the specified number of bytes has not been read.
*/
-BOOL BlockChainStream_ReadAt(BlockChainStream* This,
+HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
ULARGE_INTEGER offset,
ULONG size,
void* buffer,
ULONG bytesToReadInBuffer;
ULONG blockIndex;
BYTE* bufferWalker;
- BYTE* bigBlockBuffer;
+
+ TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
/*
* Find the first block in the stream that contains part of the buffer.
while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
{
if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
- return FALSE;
+ return STG_E_DOCFILECORRUPT;
blockNoInSequence--;
}
+ if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN))
+ return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */
+
This->lastBlockNoInSequenceIndex = blockIndex;
/*
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
{
+ ULARGE_INTEGER ulOffset;
+ DWORD bytesReadAt;
/*
* Calculate how many bytes we can copy from this big block.
*/
bytesToReadInBuffer =
min(This->parentStorage->bigBlockSize - offsetInBlock, size);
- /*
- * Copy those bytes to the buffer
- */
- bigBlockBuffer =
- StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
-
- memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
-
- StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+ TRACE("block %i\n",blockIndex);
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
+ offsetInBlock;
+ StorageImpl_ReadAt(This->parentStorage,
+ ulOffset,
+ bufferWalker,
+ bytesToReadInBuffer,
+ &bytesReadAt);
/*
* Step to the next big block.
*/
- if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
- return FALSE;
+ if( size > bytesReadAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
+ return STG_E_DOCFILECORRUPT;
- bufferWalker += bytesToReadInBuffer;
- size -= bytesToReadInBuffer;
- *bytesRead += bytesToReadInBuffer;
+ bufferWalker += bytesReadAt;
+ size -= bytesReadAt;
+ *bytesRead += bytesReadAt;
offsetInBlock = 0; /* There is no offset on the next block */
+ if (bytesToReadInBuffer != bytesReadAt)
+ break;
}
- return (size == 0);
+ return (size == 0) ? S_OK : STG_E_READFAULT;
}
/******************************************************************************
* bytesWritten may be NULL.
* Will fail if not all specified number of bytes have been written.
*/
-BOOL BlockChainStream_WriteAt(BlockChainStream* This,
+HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
ULARGE_INTEGER offset,
ULONG size,
const void* buffer,
ULONG bytesToWrite;
ULONG blockIndex;
const BYTE* bufferWalker;
- BYTE* bigBlockBuffer;
/*
* Find the first block in the stream that contains part of the buffer.
{
if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
&blockIndex)))
- return FALSE;
+ return STG_E_DOCFILECORRUPT;
blockNoInSequence--;
}
This->lastBlockNoInSequenceIndex = blockIndex;
+ /* BlockChainStream_SetSize should have already been called to ensure we have
+ * enough blocks in the chain to write into */
+ if (blockIndex == BLOCK_END_OF_CHAIN)
+ {
+ ERR("not enough blocks in chain to write data\n");
+ return STG_E_DOCFILECORRUPT;
+ }
+
/*
* Here, I'm casting away the constness on the buffer variable
* This is OK since we don't intend to modify that buffer.
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
{
+ ULARGE_INTEGER ulOffset;
+ DWORD bytesWrittenAt;
/*
* Calculate how many bytes we can copy from this big block.
*/
bytesToWrite =
min(This->parentStorage->bigBlockSize - offsetInBlock, size);
- /*
- * Copy those bytes to the buffer
- */
- bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
-
- memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
+ TRACE("block %i\n",blockIndex);
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
+ offsetInBlock;
- StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+ StorageImpl_WriteAt(This->parentStorage,
+ ulOffset,
+ (BYTE*)bufferWalker,
+ bytesToWrite,
+ &bytesWrittenAt);
/*
* Step to the next big block.
*/
- if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
+ if(size > bytesWrittenAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
&blockIndex)))
- return FALSE;
- bufferWalker += bytesToWrite;
- size -= bytesToWrite;
- *bytesWritten += bytesToWrite;
+ return STG_E_DOCFILECORRUPT;
+
+ bufferWalker += bytesWrittenAt;
+ size -= bytesWrittenAt;
+ *bytesWritten += bytesWrittenAt;
offsetInBlock = 0; /* There is no offset on the next block */
+
+ if (bytesWrittenAt != bytesToWrite)
+ break;
}
- return (size == 0);
+ return (size == 0) ? S_OK : STG_E_WRITEFAULT;
}
/******************************************************************************
*
* Shrinks this chain in the big block depot.
*/
-BOOL BlockChainStream_Shrink(BlockChainStream* This,
- ULARGE_INTEGER newSize)
+static BOOL BlockChainStream_Shrink(BlockChainStream* This,
+ ULARGE_INTEGER newSize)
{
ULONG blockIndex, extraBlock;
ULONG numBlocks;
*
* Grows this chain in the big block depot.
*/
-BOOL BlockChainStream_Enlarge(BlockChainStream* This,
- ULARGE_INTEGER newSize)
+static BOOL BlockChainStream_Enlarge(BlockChainStream* This,
+ ULARGE_INTEGER newSize)
{
ULONG blockIndex, currentBlock;
ULONG newNumBlocks;
}
else
{
- ULARGE_INTEGER fileSize =
- BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
-
- ULONG diff = newSize.u.LowPart - size.u.LowPart;
-
- /*
- * Make sure the file stays a multiple of blocksize
- */
- if ((diff % This->parentStorage->bigBlockSize) != 0)
- diff += (This->parentStorage->bigBlockSize -
- (diff % This->parentStorage->bigBlockSize) );
-
- fileSize.u.LowPart += diff;
- BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
-
BlockChainStream_Enlarge(This, newSize);
}
* Returns the size of this chain.
* Will return the block count if this chain doesn't have a property.
*/
-ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
+static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
{
StgProperty chainProperty;
*
* Returns the head of this chain of small blocks.
*/
-ULONG SmallBlockChainStream_GetHeadOfChain(
+static ULONG SmallBlockChainStream_GetHeadOfChain(
SmallBlockChainStream* This)
{
StgProperty chainProperty;
* - BLOCK_END_OF_CHAIN: end of this chain
* - BLOCK_UNUSED: small block 'blockIndex' is free
*/
-HRESULT SmallBlockChainStream_GetNextBlockInChain(
+static HRESULT SmallBlockChainStream_GetNextBlockInChain(
SmallBlockChainStream* This,
ULONG blockIndex,
ULONG* nextBlockInChain)
ULARGE_INTEGER offsetOfBlockInDepot;
DWORD buffer;
ULONG bytesRead;
- BOOL success;
+ HRESULT res;
*nextBlockInChain = BLOCK_END_OF_CHAIN;
/*
* Read those bytes in the buffer from the small block file.
*/
- success = BlockChainStream_ReadAt(
+ res = BlockChainStream_ReadAt(
This->parentStorage->smallBlockDepotChain,
offsetOfBlockInDepot,
sizeof(DWORD),
&buffer,
&bytesRead);
- if (success)
+ if (SUCCEEDED(res))
{
- StorageUtl_ReadDWord(&buffer, 0, nextBlockInChain);
+ StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
return S_OK;
}
- return STG_E_READFAULT;
+ return res;
}
/******************************************************************************
* To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
* To flag a block as free use BLOCK_UNUSED as nextBlock.
*/
-void SmallBlockChainStream_SetNextBlockInChain(
+static void SmallBlockChainStream_SetNextBlockInChain(
SmallBlockChainStream* This,
ULONG blockIndex,
ULONG nextBlock)
offsetOfBlockInDepot.u.HighPart = 0;
offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
- StorageUtl_WriteDWord(&buffer, 0, nextBlock);
+ StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock);
/*
* Read those bytes in the buffer from the small block file.
*
* Flag small block 'blockIndex' as free in the small block depot.
*/
-void SmallBlockChainStream_FreeBlock(
+static void SmallBlockChainStream_FreeBlock(
SmallBlockChainStream* This,
ULONG blockIndex)
{
* enlarged if necessary. The small block chain will also be enlarged if
* necessary.
*/
-ULONG SmallBlockChainStream_GetNextFreeBlock(
+static ULONG SmallBlockChainStream_GetNextFreeBlock(
SmallBlockChainStream* This)
{
ULARGE_INTEGER offsetOfBlockInDepot;
ULONG bytesRead;
ULONG blockIndex = 0;
ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
- BOOL success = TRUE;
+ HRESULT res = S_OK;
ULONG smallBlocksPerBigBlock;
offsetOfBlockInDepot.u.HighPart = 0;
{
offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG);
- success = BlockChainStream_ReadAt(
+ res = BlockChainStream_ReadAt(
This->parentStorage->smallBlockDepotChain,
offsetOfBlockInDepot,
sizeof(DWORD),
/*
* If we run out of space for the small block depot, enlarge it
*/
- if (success)
+ if (SUCCEEDED(res))
{
- StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
+ StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
if (nextBlockIndex != BLOCK_UNUSED)
blockIndex++;
ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
ULONG nextBlock, newsbdIndex;
- BYTE* smallBlockDepot;
+ BYTE smallBlockDepot[BIG_BLOCK_SIZE];
nextBlock = sbdIndex;
while (nextBlock != BLOCK_END_OF_CHAIN)
/*
* Initialize all the small blocks to free
*/
- smallBlockDepot =
- StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
-
memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
- StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
+ StorageImpl_WriteBigBlock(This->parentStorage, newsbdIndex, smallBlockDepot);
if (count == 0)
{
StorageImpl_ReadProperty(
This->parentStorage,
- This->parentStorage->rootPropertySetIndex,
+ This->parentStorage->base.rootPropertySetIndex,
&rootProp);
rootProp.startingBlock = sbStartIndex;
StorageImpl_WriteProperty(
This->parentStorage,
- This->parentStorage->rootPropertySetIndex,
+ This->parentStorage->base.rootPropertySetIndex,
&rootProp);
}
}
StorageImpl_ReadProperty(
This->parentStorage,
- This->parentStorage->rootPropertySetIndex,
+ This->parentStorage->base.rootPropertySetIndex,
&rootProp);
if (rootProp.size.u.LowPart <
StorageImpl_WriteProperty(
This->parentStorage,
- This->parentStorage->rootPropertySetIndex,
+ This->parentStorage->base.rootPropertySetIndex,
&rootProp);
}
}
* bytesRead may be NULL.
* Failure will be returned if the specified number of bytes has not been read.
*/
-BOOL SmallBlockChainStream_ReadAt(
+HRESULT SmallBlockChainStream_ReadAt(
SmallBlockChainStream* This,
ULARGE_INTEGER offset,
ULONG size,
void* buffer,
ULONG* bytesRead)
{
+ HRESULT rc = S_OK;
ULARGE_INTEGER offsetInBigBlockFile;
ULONG blockNoInSequence =
offset.u.LowPart / This->parentStorage->smallBlockSize;
while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
{
- if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
- &blockIndex)))
- return FALSE;
+ rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
+ if(FAILED(rc))
+ return rc;
blockNoInSequence--;
}
/*
* Read those bytes in the buffer from the small block file.
+ * The small block has already been identified so it shouldn't fail
+ * unless the file is corrupt.
*/
- BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
+ rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
offsetInBigBlockFile,
bytesToReadInBuffer,
bufferWalker,
&bytesReadFromBigBlockFile);
- assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
+ if (FAILED(rc))
+ return rc;
/*
* Step to the next big block.
*/
- if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
- return FALSE;
- bufferWalker += bytesToReadInBuffer;
- size -= bytesToReadInBuffer;
- *bytesRead += bytesToReadInBuffer;
- offsetInBlock = 0; /* There is no offset on the next block */
+ rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
+ if(FAILED(rc))
+ return STG_E_DOCFILECORRUPT;
+
+ bufferWalker += bytesReadFromBigBlockFile;
+ size -= bytesReadFromBigBlockFile;
+ *bytesRead += bytesReadFromBigBlockFile;
+ offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
}
- return (size == 0);
+ return (size == 0) ? S_OK : STG_E_READFAULT;
}
/******************************************************************************
* bytesWritten may be NULL.
* Will fail if not all specified number of bytes have been written.
*/
-BOOL SmallBlockChainStream_WriteAt(
+HRESULT SmallBlockChainStream_WriteAt(
SmallBlockChainStream* This,
ULARGE_INTEGER offset,
ULONG size,
ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize;
ULONG bytesToWriteInBuffer;
ULONG blockIndex;
- ULONG bytesWrittenFromBigBlockFile;
+ ULONG bytesWrittenToBigBlockFile;
const BYTE* bufferWalker;
+ HRESULT res;
/*
* This should never happen on a small block file.
while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
{
if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
- return FALSE;
+ return STG_E_DOCFILECORRUPT;
blockNoInSequence--;
}
/*
* Write those bytes in the buffer to the small block file.
*/
- BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
+ res = BlockChainStream_WriteAt(
+ This->parentStorage->smallBlockRootChain,
offsetInBigBlockFile,
bytesToWriteInBuffer,
bufferWalker,
- &bytesWrittenFromBigBlockFile);
-
- assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
+ &bytesWrittenToBigBlockFile);
+ if (FAILED(res))
+ return res;
/*
* Step to the next big block.
if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex,
&blockIndex)))
return FALSE;
- bufferWalker += bytesToWriteInBuffer;
- size -= bytesToWriteInBuffer;
- *bytesWritten += bytesToWriteInBuffer;
- offsetInBlock = 0; /* There is no offset on the next block */
+ bufferWalker += bytesWrittenToBigBlockFile;
+ size -= bytesWrittenToBigBlockFile;
+ *bytesWritten += bytesWrittenToBigBlockFile;
+ offsetInBlock = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
}
- return (size == 0);
+ return (size == 0) ? S_OK : STG_E_WRITEFAULT;
}
/******************************************************************************
*
* Shrinks this chain in the small block depot.
*/
-BOOL SmallBlockChainStream_Shrink(
+static BOOL SmallBlockChainStream_Shrink(
SmallBlockChainStream* This,
ULARGE_INTEGER newSize)
{
*
* Grows this chain in the small block depot.
*/
-BOOL SmallBlockChainStream_Enlarge(
+static BOOL SmallBlockChainStream_Enlarge(
SmallBlockChainStream* This,
ULARGE_INTEGER newSize)
{
SmallBlockChainStream_SetNextBlockInChain(
This,
blockIndex,
- BLOCK_END_OF_CHAIN);
-
- currentBlock = blockIndex;
- oldNumBlocks++;
- }
-
- return TRUE;
-}
-
-/******************************************************************************
- * SmallBlockChainStream_GetCount
- *
- * Returns the number of blocks that comprises this chain.
- * This is not the size of this chain as the last block may not be full!
- */
-ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
-{
- ULONG blockIndex;
- ULONG count = 0;
-
- blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
-
- while (blockIndex != BLOCK_END_OF_CHAIN)
- {
- count++;
+ BLOCK_END_OF_CHAIN);
- if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
- return 0;
+ currentBlock = blockIndex;
+ oldNumBlocks++;
}
- return count;
+ return TRUE;
}
/******************************************************************************
*
* Returns the size of this chain.
*/
-ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
+static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
{
StgProperty chainProperty;
/******************************************************************************
* StgCreateDocfile [OLE32.@]
+ * Creates a new compound file storage object
+ *
+ * PARAMS
+ * pwcsName [ I] Unicode string with filename (can be relative or NULL)
+ * grfMode [ I] Access mode for opening the new storage object (see STGM_ constants)
+ * reserved [ ?] unused?, usually 0
+ * ppstgOpen [IO] A pointer to IStorage pointer to the new onject
+ *
+ * RETURNS
+ * S_OK if the file was successfully created
+ * some STG_E_ value if error
+ * NOTES
+ * if pwcsName is NULL, create file with new unique name
+ * the function can returns
+ * STG_S_CONVERTED if the specified file was successfully converted to storage format
+ * (unrealized now)
*/
HRESULT WINAPI StgCreateDocfile(
LPCOLESTR pwcsName,
{
StorageImpl* newStorage = 0;
HANDLE hFile = INVALID_HANDLE_VALUE;
- HRESULT hr = S_OK;
+ HRESULT hr = STG_E_INVALIDFLAG;
DWORD shareMode;
DWORD accessMode;
DWORD creationMode;
DWORD fileAttributes;
WCHAR tempFileName[MAX_PATH];
- TRACE("(%s, %lx, %ld, %p)\n",
+ TRACE("(%s, %x, %d, %p)\n",
debugstr_w(pwcsName), grfMode,
reserved, ppstgOpen);
if (reserved != 0)
return STG_E_INVALIDPARAMETER;
+ /* if no share mode given then DENY_NONE is the default */
+ if (STGM_SHARE_MODE(grfMode) == 0)
+ grfMode |= STGM_SHARE_DENY_NONE;
+
/*
* Validate the STGM flags
*/
if ( FAILED( validateSTGM(grfMode) ))
- return STG_E_INVALIDFLAG;
+ goto end;
- /* StgCreateDocFile always opens for write */
- if (!(grfMode & (STGM_WRITE|STGM_READWRITE)))
- return STG_E_INVALIDFLAG;
+ /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
+ switch(STGM_ACCESS_MODE(grfMode))
+ {
+ case STGM_WRITE:
+ case STGM_READWRITE:
+ break;
+ default:
+ goto end;
+ }
+
+ /* in direct mode, can only use SHARE_EXCLUSIVE */
+ if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
+ goto end;
+
+ /* but in transacted mode, any share mode is valid */
- /* always opens non-shared */
- if (!(grfMode & STGM_SHARE_EXCLUSIVE))
- return STG_E_INVALIDFLAG;
-
/*
* Generate a unique name.
*/
WCHAR tempPath[MAX_PATH];
static const WCHAR prefix[] = { 'S', 'T', 'O', 0 };
- if (!(grfMode & STGM_SHARE_EXCLUSIVE))
- return STG_E_INVALIDFLAG;
- if (!(grfMode & (STGM_WRITE|STGM_READWRITE)))
- return STG_E_INVALIDFLAG;
-
memset(tempPath, 0, sizeof(tempPath));
memset(tempFileName, 0, sizeof(tempFileName));
if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
pwcsName = tempFileName;
else
- return STG_E_INSUFFICIENTMEMORY;
+ {
+ hr = STG_E_INSUFFICIENTMEMORY;
+ goto end;
+ }
creationMode = TRUNCATE_EXISTING;
}
hFile = CreateFileW(pwcsName,
accessMode,
shareMode,
- NULL,
+ NULL,
creationMode,
fileAttributes,
- 0);
+ 0);
if (hFile == INVALID_HANDLE_VALUE)
{
if(GetLastError() == ERROR_FILE_EXISTS)
- return STG_E_FILEALREADYEXISTS;
- return E_FAIL;
+ hr = STG_E_FILEALREADYEXISTS;
+ else
+ hr = E_FAIL;
+ goto end;
}
/*
newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
if (newStorage == 0)
- return STG_E_INSUFFICIENTMEMORY;
+ {
+ hr = STG_E_INSUFFICIENTMEMORY;
+ goto end;
+ }
hr = StorageImpl_Construct(
newStorage,
if (FAILED(hr))
{
HeapFree(GetProcessHeap(), 0, newStorage);
- return hr;
+ goto end;
}
/*
(IStorage*)newStorage,
(REFIID)&IID_IStorage,
(void**)ppstgOpen);
+end:
+ TRACE("<-- %p r = %08x\n", *ppstgOpen, hr);
return hr;
}
*/
HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
{
- TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
+ TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
+ grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
+
+ if (stgfmt != STGFMT_FILE && grfAttrs != 0)
+ {
+ ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
+ return STG_E_INVALIDPARAMETER;
+ }
+
+ if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
+ {
+ ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
+ return STG_E_INVALIDPARAMETER;
+ }
+
+ if (stgfmt == STGFMT_FILE)
+ {
+ ERR("Cannot use STGFMT_FILE - this is NTFS only\n");
+ return STG_E_INVALIDPARAMETER;
+ }
+
+ if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
+ {
+ FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n");
+ return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen);
+ }
+
+ ERR("Invalid stgfmt argument\n");
+ return STG_E_INVALIDPARAMETER;
+}
+
+/******************************************************************************
+ * StgCreatePropSetStg [OLE32.@]
+ */
+HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved,
+ IPropertySetStorage **ppPropSetStg)
+{
+ HRESULT hr;
+
+ TRACE("(%p, 0x%x, %p)\n", pstg, reserved, ppPropSetStg);
+ if (reserved)
+ hr = STG_E_INVALIDPARAMETER;
+ else
+ hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage,
+ (void**)ppPropSetStg);
+ return hr;
+}
+
+/******************************************************************************
+ * StgOpenStorageEx [OLE32.@]
+ */
+HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
+{
+ TRACE("(%s, %x, %x, %x, %p, %p, %p, %p)\n", debugstr_w(pwcsName),
grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
- return STG_E_UNIMPLEMENTEDFUNCTION;
+
+ if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
+ {
+ ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
+ return STG_E_INVALIDPARAMETER;
+ }
+
+ switch (stgfmt)
+ {
+ case STGFMT_FILE:
+ ERR("Cannot use STGFMT_FILE - this is NTFS only\n");
+ return STG_E_INVALIDPARAMETER;
+
+ case STGFMT_STORAGE:
+ break;
+
+ case STGFMT_DOCFILE:
+ if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
+ {
+ ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
+ return STG_E_INVALIDPARAMETER;
+ }
+ FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
+ break;
+
+ case STGFMT_ANY:
+ WARN("STGFMT_ANY assuming storage\n");
+ break;
+
+ default:
+ return STG_E_INVALIDPARAMETER;
+ }
+
+ return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen);
}
+
/******************************************************************************
* StgOpenStorage [OLE32.@]
*/
HRESULT WINAPI StgOpenStorage(
const OLECHAR *pwcsName,
IStorage *pstgPriority,
- DWORD grfMode,
- SNB snbExclude,
- DWORD reserved,
- IStorage **ppstgOpen)
+ DWORD grfMode,
+ SNB snbExclude,
+ DWORD reserved,
+ IStorage **ppstgOpen)
{
- StorageImpl* newStorage = 0;
+ StorageImpl* newStorage = 0;
HRESULT hr = S_OK;
- HANDLE hFile = 0;
+ HANDLE hFile = 0;
DWORD shareMode;
DWORD accessMode;
WCHAR fullname[MAX_PATH];
- DWORD length;
- TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
+ TRACE("(%s, %p, %x, %p, %d, %p)\n",
debugstr_w(pwcsName), pstgPriority, grfMode,
snbExclude, reserved, ppstgOpen);
/*
- * Perform a sanity check
+ * Perform sanity checks
*/
- if (( pwcsName == 0) || (ppstgOpen == 0) )
+ if (pwcsName == 0)
+ {
+ hr = STG_E_INVALIDNAME;
+ goto end;
+ }
+
+ if (ppstgOpen == 0)
{
hr = STG_E_INVALIDPOINTER;
goto end;
}
+ if (reserved)
+ {
+ hr = STG_E_INVALIDPARAMETER;
+ goto end;
+ }
+
+ if (grfMode & STGM_PRIORITY)
+ {
+ if (grfMode & (STGM_TRANSACTED|STGM_SIMPLE|STGM_NOSCRATCH|STGM_NOSNAPSHOT))
+ return STG_E_INVALIDFLAG;
+ if (grfMode & STGM_DELETEONRELEASE)
+ return STG_E_INVALIDFUNCTION;
+ if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
+ return STG_E_INVALIDFLAG;
+ grfMode &= ~0xf0; /* remove the existing sharing mode */
+ grfMode |= STGM_SHARE_DENY_NONE;
+
+ /* STGM_PRIORITY stops other IStorage objects on the same file from
+ * committing until the STGM_PRIORITY IStorage is closed. it also
+ * stops non-transacted mode StgOpenStorage calls with write access from
+ * succeeding. obviously, both of these cannot be achieved through just
+ * file share flags */
+ FIXME("STGM_PRIORITY mode not implemented correctly\n");
+ }
+
+ /*
+ * Validate the sharing mode
+ */
+ if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
+ switch(STGM_SHARE_MODE(grfMode))
+ {
+ case STGM_SHARE_EXCLUSIVE:
+ case STGM_SHARE_DENY_WRITE:
+ break;
+ default:
+ hr = STG_E_INVALIDFLAG;
+ goto end;
+ }
+
/*
* Validate the STGM flags
*/
- if ( FAILED( validateSTGM(grfMode) ))
+ if ( FAILED( validateSTGM(grfMode) ) ||
+ (grfMode&STGM_CREATE))
+ {
+ hr = STG_E_INVALIDFLAG;
+ goto end;
+ }
+
+ /* shared reading requires transacted mode */
+ if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
+ STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
+ !(grfMode&STGM_TRANSACTED) )
{
hr = STG_E_INVALIDFLAG;
goto end;
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
0);
- length = GetFileSize(hFile, NULL);
-
if (hFile==INVALID_HANDLE_VALUE)
{
DWORD last_error = GetLastError();
goto end;
}
+ /*
+ * Refuse to open the file if it's too small to be a structured storage file
+ * FIXME: verify the file when reading instead of here
+ */
+ if (GetFileSize(hFile, NULL) < 0x100)
+ {
+ CloseHandle(hFile);
+ hr = STG_E_FILEALREADYEXISTS;
+ goto end;
+ }
+
/*
* Allocate and initialize the new IStorage32object.
*/
goto end;
}
- /* if the file's length was zero, initialize the storage */
+ /* Initialize the storage */
hr = StorageImpl_Construct(
newStorage,
hFile,
- pwcsName,
+ pwcsName,
NULL,
grfMode,
TRUE,
- !length );
+ FALSE );
if (FAILED(hr))
{
(void**)ppstgOpen);
end:
- TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
+ TRACE("<-- %08x, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
return hr;
}
*
*
*/
-HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *a,
- FILETIME const *b, FILETIME const *c )
+HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime,
+ FILETIME const *patime, FILETIME const *pmtime)
{
- FIXME("(%s, %p, %p, %p),stub!\n", debugstr_w(str), a, b, c);
- return S_OK;
+ IStorage *stg = NULL;
+ HRESULT r;
+
+ TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
+
+ r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE,
+ 0, 0, &stg);
+ if( SUCCEEDED(r) )
+ {
+ r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
+ IStorage_Release(stg);
+ }
+
+ return r;
}
/******************************************************************************
{
HRESULT hRes;
- assert(pStg != 0);
+ if(!pStg)
+ return E_INVALIDARG;
hRes = IStorage_SetClass(pStg, rclsid);
/***********************************************************************
* ReadClassStg (OLE32.@)
*
- * This method reads the CLSID previously written to a storage object with the WriteClassStg.
+ * This method reads the CLSID previously written to a storage object with
+ * the WriteClassStg.
+ *
+ * PARAMS
+ * pstg [I] IStorage pointer
+ * pclsid [O] Pointer to where the CLSID is written
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
*/
HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
STATSTG pstatstg;
HRESULT hRes;
- TRACE("()\n");
+ TRACE("(%p, %p)\n", pstg, pclsid);
+
+ if(!pstg || !pclsid)
+ return E_INVALIDARG;
- if(pclsid==NULL)
- return E_POINTER;
/*
* read a STATSTG structure (contains the clsid) from the storage
*/
/****************************************************************************
* This method validate a STGM parameter that can contain the values below
*
+ * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
+ * The stgm values contained in 0xffff0000 are bitmasks.
+ *
* STGM_DIRECT 0x00000000
* STGM_TRANSACTED 0x00010000
* STGM_SIMPLE 0x08000000
*/
static HRESULT validateSTGM(DWORD stgm)
{
- BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
- BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
- BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
-
- BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
- BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
- BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
-
- BOOL bSTGM_SHARE_DENY_NONE =
- ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
+ DWORD access = STGM_ACCESS_MODE(stgm);
+ DWORD share = STGM_SHARE_MODE(stgm);
+ DWORD create = STGM_CREATE_MODE(stgm);
- BOOL bSTGM_SHARE_DENY_READ =
- ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
-
- BOOL bSTGM_SHARE_DENY_WRITE =
- ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
+ if (stgm&~STGM_KNOWN_FLAGS)
+ {
+ ERR("unknown flags %08x\n", stgm);
+ return E_FAIL;
+ }
- BOOL bSTGM_SHARE_EXCLUSIVE =
- ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
+ switch (access)
+ {
+ case STGM_READ:
+ case STGM_WRITE:
+ case STGM_READWRITE:
+ break;
+ default:
+ return E_FAIL;
+ }
- BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
- BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
+ switch (share)
+ {
+ case STGM_SHARE_DENY_NONE:
+ case STGM_SHARE_DENY_READ:
+ case STGM_SHARE_DENY_WRITE:
+ case STGM_SHARE_EXCLUSIVE:
+ break;
+ default:
+ return E_FAIL;
+ }
- BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
- BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
+ switch (create)
+ {
+ case STGM_CREATE:
+ case STGM_FAILIFTHERE:
+ break;
+ default:
+ return E_FAIL;
+ }
/*
* STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
*/
- if ( ! bSTGM_DIRECT )
- if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
- return E_FAIL;
-
- /*
- * STGM_WRITE | STGM_READWRITE | STGM_READ
- */
- if ( ! bSTGM_READ )
- if( bSTGM_WRITE && bSTGM_READWRITE )
- return E_FAIL;
-
- /*
- * STGM_SHARE_DENY_NONE | others
- * (I assume here that DENY_READ implies DENY_WRITE)
- */
- if ( bSTGM_SHARE_DENY_NONE )
- if ( bSTGM_SHARE_DENY_READ ||
- bSTGM_SHARE_DENY_WRITE ||
- bSTGM_SHARE_EXCLUSIVE)
+ if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
return E_FAIL;
/*
* STGM_CREATE | STGM_CONVERT
* if both are false, STGM_FAILIFTHERE is set to TRUE
*/
- if ( bSTGM_CREATE && bSTGM_CONVERT )
+ if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
return E_FAIL;
/*
* STGM_NOSCRATCH requires STGM_TRANSACTED
*/
- if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
+ if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
return E_FAIL;
/*
* STGM_NOSNAPSHOT requires STGM_TRANSACTED and
* not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
*/
- if (bSTGM_NOSNAPSHOT)
- {
- if ( ! ( bSTGM_TRANSACTED &&
- !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
+ if ( (stgm & STGM_NOSNAPSHOT) &&
+ (!(stgm & STGM_TRANSACTED) ||
+ share == STGM_SHARE_EXCLUSIVE ||
+ share == STGM_SHARE_DENY_WRITE) )
return E_FAIL;
- }
return S_OK;
}
*/
static DWORD GetShareModeFromSTGM(DWORD stgm)
{
- DWORD dwShareMode = 0;
- BOOL bSTGM_SHARE_DENY_NONE =
- ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
-
- BOOL bSTGM_SHARE_DENY_READ =
- ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
-
- BOOL bSTGM_SHARE_DENY_WRITE =
- ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
-
- BOOL bSTGM_SHARE_EXCLUSIVE =
- ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
-
- if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
- dwShareMode = 0;
-
- if (bSTGM_SHARE_DENY_NONE)
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-
- if (bSTGM_SHARE_DENY_WRITE)
- dwShareMode = FILE_SHARE_READ;
-
- return dwShareMode;
+ switch (STGM_SHARE_MODE(stgm))
+ {
+ case STGM_SHARE_DENY_NONE:
+ return FILE_SHARE_READ | FILE_SHARE_WRITE;
+ case STGM_SHARE_DENY_READ:
+ return FILE_SHARE_WRITE;
+ case STGM_SHARE_DENY_WRITE:
+ return FILE_SHARE_READ;
+ case STGM_SHARE_EXCLUSIVE:
+ return 0;
+ }
+ ERR("Invalid share mode!\n");
+ assert(0);
+ return 0;
}
/****************************************************************************
*/
static DWORD GetAccessModeFromSTGM(DWORD stgm)
{
- DWORD dwDesiredAccess = GENERIC_READ;
- BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
- BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
- BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
-
- if (bSTGM_READ)
- dwDesiredAccess = GENERIC_READ;
-
- if (bSTGM_WRITE)
- dwDesiredAccess |= GENERIC_WRITE;
-
- if (bSTGM_READWRITE)
- dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
-
- return dwDesiredAccess;
+ switch (STGM_ACCESS_MODE(stgm))
+ {
+ case STGM_READ:
+ return GENERIC_READ;
+ case STGM_WRITE:
+ case STGM_READWRITE:
+ return GENERIC_READ | GENERIC_WRITE;
+ }
+ ERR("Invalid access mode!\n");
+ assert(0);
+ return 0;
}
/****************************************************************************
*/
static DWORD GetCreationModeFromSTGM(DWORD stgm)
{
- if ( stgm & STGM_CREATE)
+ switch(STGM_CREATE_MODE(stgm))
+ {
+ case STGM_CREATE:
return CREATE_ALWAYS;
- if (stgm & STGM_CONVERT) {
+ case STGM_CONVERT:
FIXME("STGM_CONVERT not implemented!\n");
return CREATE_NEW;
+ case STGM_FAILIFTHERE:
+ return CREATE_NEW;
}
- /* All other cases */
- if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
- FIXME("unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
- return CREATE_NEW;
+ ERR("Invalid create mode!\n");
+ assert(0);
+ return 0;
}
*
* Memory allocated for pData must be freed by the caller
*/
-HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
+static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
{
DWORD dwSize;
HRESULT hRes = S_OK;
{
if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
- pData->pstrOleObjFileName = (CHAR *)HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
+ pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
if(pData->pstrOleObjFileName)
{
dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
{
if(pData->dwDataLength > 0)
{
- pData->pData = (BYTE *)HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
+ pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
/* Get Data (ex. IStorage, Metafile, or BMP) */
if(pData->pData)
* This function is used by OleConvertIStorageToOLESTREAM only.
*
*/
-HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
+static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
{
DWORD dwSize;
HRESULT hRes = S_OK;
*
*
*/
-void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
+static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
{
HRESULT hRes;
HANDLE hFile;
* Used by OleConvertIStorageToOLESTREAM only.
*
*/
-DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
+static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
{
HANDLE hFile;
HRESULT hRes;
if(hFile != INVALID_HANDLE_VALUE)
{
nDataLength = GetFileSize(hFile, NULL);
- *pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,nDataLength);
+ *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
CloseHandle(hFile);
}
if( count != sizeof(len) )
return E_OUTOFMEMORY;
- TRACE("%ld bytes\n",len);
+ TRACE("%d bytes\n",len);
str = CoTaskMemAlloc( len );
if( !str )
return r;
}
-/* enumerate HKEY_CLASSES_ROOT\\CLSID looking for a CLSID whose name matches */
-static HRESULT CLSIDFromUserType(LPCWSTR lpszUserType, CLSID *clsid)
-{
- LONG r, i, len;
- ULONG count;
- WCHAR szKey[0x40];
- HKEY hkey, hkeyclsid;
- LPWSTR buffer = NULL;
- BOOL found = FALSE;
- static const WCHAR szclsid[] = { 'C','L','S','I','D',0 };
-
- TRACE("Finding CLSID for %s\n", debugstr_w(lpszUserType));
-
- r = RegOpenKeyW( HKEY_CLASSES_ROOT, szclsid, &hkeyclsid );
- if( r )
- return E_INVALIDARG;
-
- len = lstrlenW( lpszUserType ) + 1;
- buffer = CoTaskMemAlloc( len * sizeof (WCHAR) );
- if( !buffer )
- goto end;
-
- for(i=0; !found; i++ )
- {
- r = RegEnumKeyW( hkeyclsid, i, szKey, sizeof(szKey)/sizeof(WCHAR));
- if( r != ERROR_SUCCESS )
- break;
- hkey = 0;
- r = RegOpenKeyW( hkeyclsid, szKey, &hkey );
- if( r != ERROR_SUCCESS )
- break;
- count = len * sizeof (WCHAR);
- r = RegQueryValueW( hkey, NULL, buffer, &count );
- found = ( r == ERROR_SUCCESS ) &&
- ( count == len*sizeof(WCHAR) ) &&
- !lstrcmpW( buffer, lpszUserType ) ;
- RegCloseKey( hkey );
- }
-
-end:
- if( buffer )
- CoTaskMemFree( buffer );
- RegCloseKey( hkeyclsid );
-
- if ( !found )
- return E_INVALIDARG;
-
- TRACE("clsid is %s\n", debugstr_w( szKey ) );
-
- r = CLSIDFromString( szKey, clsid );
-
- return r;
-}
-
-
/***********************************************************************
* WriteFmtUserTypeStg (OLE32.@)
*/
{
HRESULT r;
WCHAR szwClipName[0x40];
- WCHAR szCLSIDName[OLESTREAM_MAX_STR_LEN];
- CLSID clsid;
- LPWSTR wstrProgID;
+ CLSID clsid = CLSID_NULL;
+ LPWSTR wstrProgID = NULL;
DWORD n;
- LPMALLOC allocator = NULL;
TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
- r = CoGetMalloc(0, &allocator);
- if( FAILED( r) )
- return E_OUTOFMEMORY;
-
/* get the clipboard format name */
n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) );
szwClipName[n]=0;
TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
- /* Get the CLSID */
- szCLSIDName[0]=0;
- r = CLSIDFromUserType(lpszUserType, &clsid);
- if( FAILED( r ) )
- return r;
-
- TRACE("CLSID is %s\n",debugstr_guid(&clsid));
+ /* FIXME: There's room to save a CLSID and its ProgID, but
+ the CLSID is not looked up in the registry and in all the
+ tests I wrote it was CLSID_NULL. Where does it come from?
+ */
- /* get the real program ID */
- r = ProgIDFromCLSID( &clsid, &wstrProgID);
- if( FAILED( r ) )
- return r;
+ /* get the real program ID. This may fail, but that's fine */
+ ProgIDFromCLSID(&clsid, &wstrProgID);
TRACE("progid is %s\n",debugstr_w(wstrProgID));
- /* if we have a good string, write the stream */
- if( wstrProgID )
- r = STORAGE_WriteCompObj( pstg, &clsid,
- lpszUserType, szwClipName, wstrProgID );
- else
- r = E_OUTOFMEMORY;
+ r = STORAGE_WriteCompObj( pstg, &clsid,
+ lpszUserType, szwClipName, wstrProgID );
- IMalloc_Free( allocator, wstrProgID);
+ CoTaskMemFree(wstrProgID);
return r;
}
STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
if( FAILED ( r ) )
{
- ERR("Failed to open stream\n");
+ WARN("Failed to open stream r = %08x\n", r);
return r;
}
{
char strTemp[OLESTREAM_MAX_STR_LEN];
IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
- hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));
+ hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
if(hErr == ERROR_SUCCESS)
{
strcpy(IStorageCompObj.strCLSIDName, strTemp);
* This function is used by OleConvertOLESTREAMToIStorage only.
*
*/
-void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
+static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
{
HRESULT hRes;
IStream *pStream;
* Might need to verify the data and return appropriate error message
*
*/
-void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
+static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
{
HRESULT hRes;
IStream *pStream;
*
*
*/
-HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
+static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
{
HRESULT hRes;
IStream *pStream;
*
*
*/
-void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
{
HRESULT hRes;
IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
if(pOleStreamData->dwDataLength > 0)
{
- pOleStreamData->pData = (LPSTR) HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
+ pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
}
IStream_Release(pStream);
*
* Memory allocated for pData must be freed by the caller
*/
-void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
{
HRESULT hRes;
IStream *pStream;
MetaFilePict.hMF = 0;
/* Get Metafile Data */
- pOleStreamData[1].pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
+ pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
}
HRESULT hRes=S_OK;
OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
+ TRACE("%p %p %p\n", pOleStream, pstg, ptd);
+
memset(pOleStreamData, 0, sizeof(pOleStreamData));
if(ptd != NULL)
OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+ TRACE("%p %p\n", pstg, pOleStream);
memset(pOleStreamData, 0, sizeof(pOleStreamData));
/******************************************************************************
* StgIsStorageFile [OLE32.@]
+ * Verify if the file contains a storage object
+ *
+ * PARAMS
+ * fn [ I] Filename
+ *
+ * RETURNS
+ * S_OK if file has magic bytes as a storage object
+ * S_FALSE if file is not storage
*/
HRESULT WINAPI
StgIsStorageFile(LPCOLESTR fn)
BYTE magic[8];
DWORD bytes_read;
- TRACE("(\'%s\')\n", debugstr_w(fn));
+ TRACE("%s\n", debugstr_w(fn));
hf = CreateFileW(fn, GENERIC_READ,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
WARN(" -> Invalid header.\n");
return S_FALSE;
}
+
+/***********************************************************************
+ * WriteClassStm (OLE32.@)
+ *
+ * Writes a CLSID to a stream.
+ *
+ * PARAMS
+ * pStm [I] Stream to write to.
+ * rclsid [I] CLSID to write.
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
+ */
+HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
+{
+ TRACE("(%p,%p)\n",pStm,rclsid);
+
+ if (!pStm || !rclsid)
+ return E_INVALIDARG;
+
+ return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
+}
+
+/***********************************************************************
+ * ReadClassStm (OLE32.@)
+ *
+ * Reads a CLSID from a stream.
+ *
+ * PARAMS
+ * pStm [I] Stream to read from.
+ * rclsid [O] CLSID to read.
+ *
+ * RETURNS
+ * Success: S_OK.
+ * Failure: HRESULT code.
+ */
+HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
+{
+ ULONG nbByte;
+ HRESULT res;
+
+ TRACE("(%p,%p)\n",pStm,pclsid);
+
+ if (!pStm || !pclsid)
+ return E_INVALIDARG;
+
+ /* clear the output args */
+ memcpy(pclsid, &CLSID_NULL, sizeof(*pclsid));
+
+ res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
+
+ if (FAILED(res))
+ return res;
+
+ if (nbByte != sizeof(CLSID))
+ return STG_E_READFAULT;
+ else
+ return S_OK;
+}