346 lines
10 KiB
C++
346 lines
10 KiB
C++
|
#include "priv.h"
|
||
|
#include "stream.h"
|
||
|
|
||
|
#define _DBLNext(pdbList) ((LPDBLIST)(((LPBYTE)(pdbList)) + (pdbList)->cbSize ))
|
||
|
#define DBSIG_WRAP ((DWORD)-1)
|
||
|
|
||
|
STDAPI SHWriteDataBlockList(IStream* pstm, LPDBLIST pdbList)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if (pdbList)
|
||
|
{
|
||
|
for ( ; pdbList->cbSize; pdbList = _DBLNext(pdbList))
|
||
|
{
|
||
|
LPDATABLOCK_HEADER pdb;
|
||
|
ULONG cbBytes;
|
||
|
|
||
|
pdb = pdbList;
|
||
|
if (DBSIG_WRAP == pdb->dwSignature)
|
||
|
pdb++;
|
||
|
|
||
|
TraceMsg(TF_DBLIST, "Writing extra data block, size:%x sig:%x", pdb->cbSize, pdb->dwSignature);
|
||
|
|
||
|
if (FAILED(hr = ((CMemStream*)pstm)->Write((LPBYTE)pdb, pdb->cbSize, &cbBytes)))
|
||
|
break;
|
||
|
|
||
|
if (cbBytes != pdb->cbSize)
|
||
|
{
|
||
|
hr = STG_E_MEDIUMFULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NULL terminate the list
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
DWORD dwData = 0;
|
||
|
DWORD cbBytes;
|
||
|
hr = ((CMemStream*)pstm)->Write(&dwData, sizeof(dwData), &cbBytes);
|
||
|
}
|
||
|
|
||
|
return(hr);
|
||
|
}
|
||
|
|
||
|
STDAPI SHReadDataBlockList(IStream* pstm, LPDBLIST * ppdbList)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
BYTE buf[200]; // all blocks today fit in this size (tested at 5)
|
||
|
LPDATABLOCK_HEADER lpBuf = (LPDATABLOCK_HEADER)buf;
|
||
|
DWORD cbBuf = sizeof(buf);
|
||
|
DWORD dwSizeToRead, cbBytes;
|
||
|
|
||
|
if (*ppdbList)
|
||
|
{
|
||
|
LocalFree((HLOCAL)(*ppdbList));
|
||
|
*ppdbList = NULL;
|
||
|
}
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
dwSizeToRead = sizeof(cbSize);
|
||
|
hr = ((CMemStream*)pstm)->Read(&cbSize, dwSizeToRead, &cbBytes);
|
||
|
if (SUCCEEDED(hr) && (cbBytes == dwSizeToRead))
|
||
|
{
|
||
|
|
||
|
// Windows 95 and NT 4 shipped a CShellLink that did NOT
|
||
|
// NULL terminate the data it wrote out to the stream.
|
||
|
// If more data was persisted after the CShellLink then
|
||
|
// we will read in garbage. No real harm comes of this (*)
|
||
|
// (because it is unlikely we'll get a dwSignature match)
|
||
|
// but if the first dword is huge, we'll allocate a ton
|
||
|
// of memory and page it in. This can take MINUTES on Win95.
|
||
|
// Assume anything over 64K is from one of these
|
||
|
// bogus streams.
|
||
|
//
|
||
|
// (*) actually, real harm comes because we don't leave the
|
||
|
// stream in the correct place. Forms^3 put a work-around
|
||
|
// in for this bug.
|
||
|
//
|
||
|
if (cbSize > 0x0000FFFF)
|
||
|
{
|
||
|
ULARGE_INTEGER liStart;
|
||
|
LARGE_INTEGER liMove;
|
||
|
|
||
|
// We read a DWORD of data that wasn't ours, back up.
|
||
|
// NOTE: all of our stream implementations assume
|
||
|
// HighPart == 0
|
||
|
//
|
||
|
liMove.HighPart = liMove.LowPart = 0;
|
||
|
if (SUCCEEDED(((CMemStream*)pstm)->Seek(liMove, STREAM_SEEK_CUR, &liStart)))
|
||
|
{
|
||
|
ASSERT(liStart.HighPart == 0);
|
||
|
ASSERT(liStart.LowPart >= sizeof(cbSize));
|
||
|
liMove.LowPart = liStart.LowPart - sizeof(cbSize);
|
||
|
|
||
|
((CMemStream*)pstm)->Seek(liMove, STREAM_SEEK_SET, NULL);
|
||
|
}
|
||
|
|
||
|
TraceMsg(TF_DBLIST, "ASSUMING NO NULL TERMINATION (FOR SIZE 0x%x)", cbSize);
|
||
|
cbSize = 0;
|
||
|
}
|
||
|
|
||
|
// If we hit the 0 terminator, we're done.
|
||
|
//
|
||
|
if (cbSize < sizeof(DATABLOCK_HEADER))
|
||
|
break;
|
||
|
|
||
|
// Make sure we can read this block in.
|
||
|
//
|
||
|
if (cbSize > cbBuf)
|
||
|
{
|
||
|
HLOCAL pTemp;
|
||
|
|
||
|
if (lpBuf == (LPDATABLOCK_HEADER)buf)
|
||
|
pTemp = LocalAlloc(LPTR, cbSize);
|
||
|
else
|
||
|
pTemp = LocalReAlloc((HLOCAL)lpBuf, cbSize, LMEM_ZEROINIT | LMEM_MOVEABLE);
|
||
|
|
||
|
if (pTemp)
|
||
|
{
|
||
|
lpBuf = (LPDATABLOCK_HEADER)pTemp;
|
||
|
cbBuf = cbSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Read in data block
|
||
|
//
|
||
|
lpBuf->cbSize = cbSize;
|
||
|
dwSizeToRead = cbSize - sizeof(cbSize);
|
||
|
hr = ((CMemStream*)pstm)->Read((LPBYTE)&(lpBuf->dwSignature), dwSizeToRead, &cbBytes);
|
||
|
if (SUCCEEDED(hr) && (cbBytes == dwSizeToRead))
|
||
|
{
|
||
|
TraceMsg(TF_DBLIST, "Reading extra data block, size:%x sig:%x", lpBuf->cbSize, lpBuf->dwSignature);
|
||
|
|
||
|
SHAddDataBlock(ppdbList, lpBuf);
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Free any allocated buffer
|
||
|
//
|
||
|
if (lpBuf != (LPDATABLOCK_HEADER)buf)
|
||
|
{
|
||
|
LocalFree((HLOCAL)lpBuf);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDAPI_(void) SHFreeDataBlockList(LPDBLIST pdbList)
|
||
|
{
|
||
|
if (pdbList)
|
||
|
{
|
||
|
LocalFree((HLOCAL)pdbList);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STDAPI_(BOOL) SHAddDataBlock(LPDBLIST * ppdbList, LPDATABLOCK_HEADER pdb)
|
||
|
{
|
||
|
LPDBLIST pdbCopyTo = NULL;
|
||
|
DWORD dwSize;
|
||
|
|
||
|
// Don't let anyone use our special signature
|
||
|
//
|
||
|
if (DBSIG_WRAP == pdb->dwSignature ||
|
||
|
pdb->cbSize < sizeof(*pdb))
|
||
|
{
|
||
|
TraceMsg(TF_DBLIST, "SHAddDataBlock invalid datablock! (sig:%x size:%x)", pdb->dwSignature, pdb->cbSize);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Figure out how much space we need to hold this block
|
||
|
//
|
||
|
dwSize = pdb->cbSize;
|
||
|
if (pdb->cbSize & 0x3)
|
||
|
{
|
||
|
dwSize = ((dwSize + 3) & ~0x3) + sizeof(DATABLOCK_HEADER);
|
||
|
|
||
|
TraceMsg(TF_DBLIST, "Adding non-DWORD data block, size:%x sig:%x", pdb->cbSize, pdb->dwSignature);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_DBLIST, "Adding data block, size:%x sig:%x", pdb->cbSize, pdb->dwSignature);
|
||
|
}
|
||
|
|
||
|
// Allocate the space
|
||
|
//
|
||
|
if (!*ppdbList)
|
||
|
{
|
||
|
*ppdbList = (LPDBLIST)LocalAlloc(LPTR, dwSize + sizeof(DWORD)); // include NULL terminator
|
||
|
pdbCopyTo = *ppdbList;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD dwTotalSize = 0;
|
||
|
LPDBLIST pdbList;
|
||
|
HLOCAL lpTmp;
|
||
|
|
||
|
for (pdbList = *ppdbList ; pdbList->cbSize ; pdbList = _DBLNext(pdbList))
|
||
|
dwTotalSize += pdbList->cbSize;
|
||
|
|
||
|
lpTmp = LocalReAlloc((HLOCAL)*ppdbList, dwTotalSize + dwSize + sizeof(DWORD), // include NULL terminator
|
||
|
LMEM_ZEROINIT | LMEM_MOVEABLE);
|
||
|
if (lpTmp)
|
||
|
{
|
||
|
*ppdbList = (LPDBLIST)lpTmp;
|
||
|
pdbCopyTo = (LPDBLIST)(((LPBYTE)lpTmp) + dwTotalSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy the data block
|
||
|
//
|
||
|
if (pdbCopyTo)
|
||
|
{
|
||
|
LPBYTE pTmp = (LPBYTE)pdbCopyTo;
|
||
|
|
||
|
// This block would cause other blocks to be
|
||
|
// unaligned, wrap it
|
||
|
//
|
||
|
ASSERT(0 == (dwSize & 0x3));
|
||
|
if (dwSize != pdb->cbSize)
|
||
|
{
|
||
|
pdbCopyTo->cbSize = dwSize;
|
||
|
pdbCopyTo->dwSignature = DBSIG_WRAP;
|
||
|
pTmp = (LPBYTE)(pdbCopyTo + 1);
|
||
|
}
|
||
|
CopyMemory(pTmp, pdb, pdb->cbSize);
|
||
|
|
||
|
// NULL terminate the list
|
||
|
_DBLNext(pdbCopyTo)->cbSize = 0;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
STDAPI_(BOOL) SHRemoveDataBlock(LPDBLIST * ppdbList, DWORD dwSignature)
|
||
|
{
|
||
|
LPDBLIST pdbRemove = NULL;
|
||
|
|
||
|
// Can't call SHFindDataBlock because that returnes the
|
||
|
// block that was wrapped, we want the block that wraps.
|
||
|
//
|
||
|
if (*ppdbList)
|
||
|
{
|
||
|
LPDBLIST pdbList = *ppdbList;
|
||
|
|
||
|
for ( ; pdbList->cbSize ; pdbList = _DBLNext(pdbList))
|
||
|
{
|
||
|
if (dwSignature == pdbList->dwSignature)
|
||
|
{
|
||
|
TraceMsg(TF_DBLIST, "Removing data block, size:%x sig:%x ptr:%x", pdbList->cbSize, pdbList->dwSignature, pdbList);
|
||
|
pdbRemove = pdbList;
|
||
|
break;
|
||
|
}
|
||
|
else if (DBSIG_WRAP == pdbList->dwSignature)
|
||
|
{
|
||
|
LPDBLIST pdbWrap = pdbList + 1;
|
||
|
if (dwSignature == pdbWrap->dwSignature)
|
||
|
{
|
||
|
TraceMsg(TF_DBLIST, "Removing non-DWORD data block, size:%x sig:%x ptr:", pdbWrap->cbSize, pdbWrap->dwSignature, pdbWrap);
|
||
|
pdbRemove = pdbList;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pdbRemove)
|
||
|
{
|
||
|
LPDBLIST pdbNext = _DBLNext(pdbRemove);
|
||
|
LPDBLIST pdbEnd;
|
||
|
DWORD dwSizeOfBlockToRemove;
|
||
|
LONG lNewSize;
|
||
|
|
||
|
for (pdbEnd = pdbNext ; pdbEnd->cbSize ; pdbEnd = _DBLNext(pdbEnd))
|
||
|
;
|
||
|
|
||
|
dwSizeOfBlockToRemove = pdbRemove->cbSize;
|
||
|
|
||
|
// Move remaining memory down
|
||
|
MoveMemory(pdbRemove, pdbNext, (DWORD_PTR)pdbEnd - (DWORD_PTR)pdbNext + sizeof(DWORD));
|
||
|
|
||
|
// Shrink our buffer
|
||
|
lNewSize = (LONG) LocalSize(*ppdbList ) - dwSizeOfBlockToRemove;
|
||
|
if (lNewSize > sizeof(DWORD))
|
||
|
{
|
||
|
void *lpVoid = LocalReAlloc( (HLOCAL)*ppdbList, lNewSize, LMEM_ZEROINIT | LMEM_MOVEABLE );
|
||
|
if (NULL != lpVoid)
|
||
|
{
|
||
|
*ppdbList = (LPDBLIST)lpVoid;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We've removed the last section, delete the whole deal
|
||
|
LocalFree( (HLOCAL)(*ppdbList) );
|
||
|
*ppdbList = NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
STDAPI_(void *) SHFindDataBlock(LPDBLIST pdbList, DWORD dwSignature)
|
||
|
{
|
||
|
if (pdbList)
|
||
|
{
|
||
|
for ( ; pdbList->cbSize ; pdbList = _DBLNext(pdbList))
|
||
|
{
|
||
|
if (dwSignature == pdbList->dwSignature)
|
||
|
{
|
||
|
TraceMsg(TF_DBLIST, "Found data block, size:%x sig:%x ptr:%x", pdbList->cbSize, pdbList->dwSignature, pdbList);
|
||
|
|
||
|
return (void *)pdbList;
|
||
|
}
|
||
|
else if (DBSIG_WRAP == pdbList->dwSignature)
|
||
|
{
|
||
|
LPDBLIST pdbWrap = pdbList + 1;
|
||
|
if (dwSignature == pdbWrap->dwSignature)
|
||
|
{
|
||
|
TraceMsg(TF_DBLIST, "Found non-DWORD data block, size:%x sig:%x ptr:%x", pdbWrap->cbSize, pdbWrap->dwSignature, pdbWrap);
|
||
|
|
||
|
return (void *)pdbWrap;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|