📄 storage32.c
字号:
}
}
return newPropertyIndex;
}
/****************************************************************************
*
* Internal Method
*
* Case insensitive comparaison of StgProperty.name by first considering
* their size.
*
* Returns <0 when newPrpoerty < currentProperty
* >0 when newPrpoerty > currentProperty
* 0 when newPrpoerty == currentProperty
*/
static LONG propertyNameCmp(
const OLECHAR *newProperty,
const OLECHAR *currentProperty)
{
LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty);
if (diff == 0)
{
/*
* We compare the string themselves only when they are of the same length
*/
diff = lstrcmpiW( newProperty, currentProperty);
}
return diff;
}
/****************************************************************************
*
* Internal Method
*
* Properly link this new element in the property chain.
*/
static void updatePropertyChain(
StorageImpl *storage,
ULONG newPropertyIndex,
StgProperty newProperty)
{
StgProperty currentProperty;
/*
* Read the root property
*/
StorageImpl_ReadProperty(storage->base.ancestorStorage,
storage->base.rootPropertySetIndex,
¤tProperty);
if (currentProperty.dirProperty != PROPERTY_NULL)
{
/*
* The root storage contains some element, therefore, start the research
* for the appropriate location.
*/
BOOL found = 0;
ULONG current, next, previous, currentPropertyId;
/*
* Keep the StgProperty sequence number of the storage first property
*/
currentPropertyId = currentProperty.dirProperty;
/*
* Read
*/
StorageImpl_ReadProperty(storage->base.ancestorStorage,
currentProperty.dirProperty,
¤tProperty);
previous = currentProperty.previousProperty;
next = currentProperty.nextProperty;
current = currentPropertyId;
while (found == 0)
{
LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
if (diff < 0)
{
if (previous != PROPERTY_NULL)
{
StorageImpl_ReadProperty(storage->base.ancestorStorage,
previous,
¤tProperty);
current = previous;
}
else
{
currentProperty.previousProperty = newPropertyIndex;
StorageImpl_WriteProperty(storage->base.ancestorStorage,
current,
¤tProperty);
found = 1;
}
}
else if (diff > 0)
{
if (next != PROPERTY_NULL)
{
StorageImpl_ReadProperty(storage->base.ancestorStorage,
next,
¤tProperty);
current = next;
}
else
{
currentProperty.nextProperty = newPropertyIndex;
StorageImpl_WriteProperty(storage->base.ancestorStorage,
current,
¤tProperty);
found = 1;
}
}
else
{
/*
* Trying to insert an item with the same name in the
* subtree structure.
*/
assert(FALSE);
}
previous = currentProperty.previousProperty;
next = currentProperty.nextProperty;
}
}
else
{
/*
* The root storage is empty, link the new property to its dir property
*/
currentProperty.dirProperty = newPropertyIndex;
StorageImpl_WriteProperty(storage->base.ancestorStorage,
storage->base.rootPropertySetIndex,
¤tProperty);
}
}
/*************************************************************************
* CopyTo (IStorage)
*/
static HRESULT WINAPI StorageImpl_CopyTo(
IStorage* iface,
DWORD ciidExclude, /* [in] */
const IID* rgiidExclude, /* [size_is][unique][in] */
SNB snbExclude, /* [unique][in] */
IStorage* pstgDest) /* [unique][in] */
{
IEnumSTATSTG *elements = 0;
STATSTG curElement, strStat;
HRESULT hr;
IStorage *pstgTmp, *pstgChild;
IStream *pstrTmp, *pstrChild;
if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
FIXME("Exclude option not implemented\n");
TRACE("(%p, %d, %p, %p, %p)\n",
iface, ciidExclude, rgiidExclude,
snbExclude, pstgDest);
/*
* Perform a sanity check
*/
if ( pstgDest == 0 )
return STG_E_INVALIDPOINTER;
/*
* Enumerate the elements
*/
hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
if ( hr != S_OK )
return hr;
/*
* set the class ID
*/
IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
IStorage_SetClass( pstgDest, &curElement.clsid );
do
{
/*
* Obtain the next element
*/
hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
if ( hr == S_FALSE )
{
hr = S_OK; /* done, every element has been copied */
break;
}
if (curElement.type == STGTY_STORAGE)
{
/*
* open child source storage
*/
hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
STGM_READ|STGM_SHARE_EXCLUSIVE,
NULL, 0, &pstgChild );
if (hr != S_OK)
break;
/*
* Check if destination storage is not a child of the source
* storage, which will cause an infinite loop
*/
if (pstgChild == pstgDest)
{
IEnumSTATSTG_Release(elements);
return STG_E_ACCESSDENIED;
}
/*
* create a new storage in destination storage
*/
hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
0, 0,
&pstgTmp );
/*
* if it already exist, don't create a new one use this one
*/
if (hr == STG_E_FILEALREADYEXISTS)
{
hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
STGM_WRITE|STGM_SHARE_EXCLUSIVE,
NULL, 0, &pstgTmp );
}
if (hr != S_OK)
break;
/*
* do the copy recursively
*/
hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
snbExclude, pstgTmp );
IStorage_Release( pstgTmp );
IStorage_Release( pstgChild );
}
else if (curElement.type == STGTY_STREAM)
{
/*
* create a new stream in destination storage. If the stream already
* exist, it will be deleted and a new one will be created.
*/
hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
0, 0, &pstrTmp );
if (hr != S_OK)
break;
/*
* open child stream storage
*/
hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
STGM_READ|STGM_SHARE_EXCLUSIVE,
0, &pstrChild );
if (hr != S_OK)
break;
/*
* Get the size of the source stream
*/
IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
/*
* Set the size of the destination stream.
*/
IStream_SetSize(pstrTmp, strStat.cbSize);
/*
* do the copy
*/
hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
NULL, NULL );
IStream_Release( pstrTmp );
IStream_Release( pstrChild );
}
else
{
WARN("unknown element type: %d\n", curElement.type);
}
} while (hr == S_OK);
/*
* Clean-up
*/
IEnumSTATSTG_Release(elements);
return hr;
}
/*************************************************************************
* MoveElementTo (IStorage)
*/
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("(%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.
*/
static HRESULT WINAPI StorageImpl_Commit(
IStorage* iface,
DWORD grfCommitFlags)/* [in] */
{
FIXME("(%p %d): stub\n", iface, grfCommitFlags);
return S_OK;
}
/*************************************************************************
* Revert (IStorage)
*
* Discard all changes that have been made since the last commit operation
*/
static HRESULT WINAPI StorageImpl_Revert(
IStorage* iface)
{
FIXME("(%p): stub\n", iface);
return E_NOTIMPL;
}
/*************************************************************************
* DestroyElement (IStorage)
*
* 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 resides in the usage of another
* enumeration strategy that would give all the leaves of a storage
* first. (postfix order)
*/
static HRESULT WINAPI StorageImpl_DestroyElement(
IStorage* iface,
const OLECHAR *pwcsName)/* [string][in] */
{
StorageImpl* const This=(StorageImpl*)iface;
IEnumSTATSTGImpl* propertyEnumeration;
HRESULT hr = S_OK;
BOOL res;
StgProperty propertyToDelete;
StgProperty parentProperty;
ULONG foundPropertyIndexToDelete;
ULONG typeOfRelation;
ULONG parentPropertyId = 0;
TRACE("(%p, %s)\n",
iface, debugstr_w(pwcsName));
/*
* Perform a sanity check on the parameters.
*/
if (pwcsName==NULL)
return STG_E_INVALIDPOINTER;
/*
* Create a property enumeration to search the property with the given name
*/
propertyEnumeration = IEnumSTATSTGImpl_Construct(
This->base.ancestorStorage,
This->base.rootPropertySetIndex);
foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
propertyEnumeration,
pwcsName,
&propertyToDelete);
IEnumSTATSTGImpl_Destroy(propertyEnumeration);
if ( foundPropertyIndexToDelete == PROPERTY_NULL )
{
return STG_E_FILENOTFOUND;
}
/*
* Find the parent property of the property to delete (the one that
* link to it). If This->dirProperty == foundPropertyIndexToDelete,
* the parent is This. Otherwise, the parent is one of its sibling...
*/
/*
* First, read This's StgProperty..
*/
res = StorageImpl_ReadProperty(
This->base.ancestorStorage,
This->base.rootPropertySetIndex,
&parentProperty);
assert(res);
/*
* Second, check to see if by any chance the actual storage (This) is not
* the parent of the property to delete... We never know...
*/
if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
{
/*
* Set data as it would have been done in the else part...
*/
typeOfRelation = PROPERTY_RELATION_DIR;
parentPropertyId = This->base.rootPropertySetIndex;
}
else
{
/*
* Create a property enumeration to search the parent properties, and
* delete it once done.
*/
IEnumSTATSTGImpl* propertyEnumeration2;
propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
This->base.ancestorStorage,
This->base.rootPropertySetIndex);
typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
propertyEnumeration2,
foundPropertyIndexToDelete,
&parentProperty,
&parentPropertyId);
IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
}
if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
{
hr = deleteStorageProperty(
This,
foundPropertyIndexToDelete,
propertyToDelete);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -