📄 storage32.c
字号:
/*
* Compound Storage (32 bit version)
* Storage implementation
*
* This file contains the compound file implementation
* of the storage interface.
*
* 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
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* 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., 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>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winuser.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "storage32.h"
#include "ole2.h" /* For Write/ReadClassStm */
#include "winreg.h"
#include "wine/wingdi16.h"
WINE_DEFAULT_DEBUG_CHANNEL(storage);
/* 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, const 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 */
typedef struct
{
DWORD dwOleID;
DWORD dwTypeID;
DWORD dwOleTypeNameLength;
CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
CHAR *pstrOleObjFileName;
DWORD dwOleObjFileNameLength;
DWORD dwMetaFileWidth;
DWORD dwMetaFileHeight;
CHAR strUnknown[8]; /* don't know what is this 8 byts information in OLE stream. */
DWORD dwDataLength;
BYTE *pData;
}OLECONVERT_OLESTREAM_DATA;
/* CompObj Stream structure */
/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
typedef struct
{
BYTE byUnknown1[12];
CLSID clsid;
DWORD dwCLSIDNameLength;
CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
DWORD dwOleTypeNameLength;
CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
DWORD dwProgIDNameLength;
CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
BYTE byUnknown2[16];
}OLECONVERT_ISTORAGE_COMPOBJ;
/* Ole Presention Stream structure */
/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
typedef struct
{
BYTE byUnknown1[28];
DWORD dwExtentX;
DWORD dwExtentY;
DWORD dwSize;
BYTE *pData;
}OLECONVERT_ISTORAGE_OLEPRES;
/***********************************************************************
* Forward declaration of internal functions used by the method DestroyElement
*/
static HRESULT deleteStorageProperty(
StorageImpl *parentStorage,
ULONG foundPropertyIndexToDelete,
StgProperty propertyToDelete);
static HRESULT deleteStreamProperty(
StorageImpl *parentStorage,
ULONG foundPropertyIndexToDelete,
StgProperty propertyToDelete);
static HRESULT findPlaceholder(
StorageImpl *storage,
ULONG propertyIndexToStore,
ULONG storagePropertyIndex,
INT typeOfRelation);
static HRESULT adjustPropertyChain(
StorageImpl *This,
StgProperty propertyToDelete,
StgProperty parentProperty,
ULONG parentPropertyId,
INT typeOfRelation);
/***********************************************************************
* Declaration of the functions used to manipulate StgProperty
*/
static ULONG getFreeProperty(
StorageImpl *storage);
static void updatePropertyChain(
StorageImpl *storage,
ULONG newPropertyIndex,
StgProperty newProperty);
static LONG propertyNameCmp(
const OLECHAR *newProperty,
const OLECHAR *currentProperty);
/***********************************************************************
* Declaration of miscellaneous functions...
*/
static HRESULT validateSTGM(DWORD stgmValue);
static DWORD GetShareModeFromSTGM(DWORD stgm);
static DWORD GetAccessModeFromSTGM(DWORD stgm);
static DWORD GetCreationModeFromSTGM(DWORD stgm);
extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
/****************************************************************************
* 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.
*/
struct IEnumSTATSTGImpl
{
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,
const void* buffer,
const ULONG size,
ULONG* bytesWritten)
{
return BIGBLOCKFILE_WriteAt(This->bigBlockFile,offset,buffer,size,bytesWritten);
}
/************************************************************************
* Storage32BaseImpl_QueryInterface (IUnknown)
*
* This method implements the common QueryInterface for all IStorage32
* implementations contained in this file.
*
* See Windows documentation for more details on IUnknown methods.
*/
static HRESULT WINAPI StorageBaseImpl_QueryInterface(
IStorage* iface,
REFIID riid,
void** ppvObject)
{
StorageBaseImpl *This = (StorageBaseImpl *)iface;
/*
* Perform a sanity check on the parameters.
*/
if ( (This==0) || (ppvObject==0) )
return E_INVALIDARG;
/*
* Initialize the return parameter.
*/
*ppvObject = 0;
/*
* Compare the riid with the interface IDs implemented by this object.
*/
if (IsEqualGUID(&IID_IUnknown, riid) ||
IsEqualGUID(&IID_IStorage, riid))
{
*ppvObject = (IStorage*)This;
}
else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
{
*ppvObject = (IStorage*)&This->pssVtbl;
}
/*
* Check that we obtained an interface.
*/
if ((*ppvObject)==0)
return E_NOINTERFACE;
/*
* Query Interface always increases the reference count by one when it is
* successful
*/
IStorage_AddRef(iface);
return S_OK;
}
/************************************************************************
* Storage32BaseImpl_AddRef (IUnknown)
*
* This method implements the common AddRef for all IStorage32
* implementations contained in this file.
*
* See Windows documentation for more details on IUnknown methods.
*/
static ULONG WINAPI StorageBaseImpl_AddRef(
IStorage* iface)
{
StorageBaseImpl *This = (StorageBaseImpl *)iface;
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) AddRef to %d\n", This, ref);
return ref;
}
/************************************************************************
* Storage32BaseImpl_Release (IUnknown)
*
* This method implements the common Release for all IStorage32
* implementations contained in this file.
*
* See Windows documentation for more details on IUnknown methods.
*/
static ULONG WINAPI StorageBaseImpl_Release(
IStorage* iface)
{
StorageBaseImpl *This = (StorageBaseImpl *)iface;
/*
* Decrease the reference count on this object.
*/
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ReleaseRef to %d\n", This, ref);
/*
* If the reference count goes down to 0, perform suicide.
*/
if (ref == 0)
{
/*
* Since we are using a system of base-classes, we want to call the
* destructor of the appropriate derived class. To do this, we are
* using virtual functions to implement the destructor.
*/
This->v_destructor(This);
}
return ref;
}
/************************************************************************
* Storage32BaseImpl_OpenStream (IStorage)
*
* This method will open the specified stream object from the current storage.
*
* See Windows documentation for more details on IStorage methods.
*/
static HRESULT WINAPI StorageBaseImpl_OpenStream(
IStorage* iface,
const OLECHAR* pwcsName, /* [string][in] */
void* reserved1, /* [unique][in] */
DWORD grfMode, /* [in] */
DWORD reserved2, /* [in] */
IStream** ppstm) /* [out] */
{
StorageBaseImpl *This = (StorageBaseImpl *)iface;
IEnumSTATSTGImpl* propertyEnumeration;
StgStreamImpl* newStream;
StgProperty currentProperty;
ULONG foundPropertyIndex;
HRESULT res = STG_E_UNKNOWN;
TRACE("(%p, %s, %p, %x, %d, %p)\n",
iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
/*
* Perform a sanity check on the parameters.
*/
if ( (pwcsName==NULL) || (ppstm==0) )
{
res = E_INVALIDARG;
goto end;
}
/*
* Initialize the out parameter
*/
*ppstm = NULL;
/*
* Validate the STGM flags
*/
if ( FAILED( validateSTGM(grfMode) ) ||
STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
{
res = STG_E_INVALIDFLAG;
goto end;
}
/*
* As documented.
*/
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -