|
|
#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; }
|