datablok.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 10k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include "stream.h"
  3. #define _DBLNext(pdbList) ((LPDBLIST)(((LPBYTE)(pdbList)) + (pdbList)->cbSize ))
  4. #define DBSIG_WRAP ((DWORD)-1)
  5. extern "C" {
  6. HRESULT SHWriteDataBlockList(IStream* pstm, LPDBLIST pdbList)
  7. {
  8.     HRESULT hr = S_OK;
  9.     if (pdbList)
  10.     {
  11.         for ( ; pdbList->cbSize; pdbList = _DBLNext(pdbList))
  12.         {
  13.             LPDATABLOCK_HEADER pdb;
  14.             ULONG cbBytes;
  15.             pdb = pdbList;
  16.             if (DBSIG_WRAP == pdb->dwSignature)
  17.                 pdb++;
  18.             TraceMsg(TF_DBLIST, "Writing extra data block, size:%x sig:%x", pdb->cbSize, pdb->dwSignature);
  19.     
  20.             if (FAILED(hr = ((CMemStream*)pstm)->Write((LPBYTE)pdb, pdb->cbSize, &cbBytes)))
  21.                 break;
  22.     
  23.             if (cbBytes != pdb->cbSize)
  24.             {
  25.                 hr = STG_E_MEDIUMFULL;
  26.                 break;
  27.             }
  28.         }
  29.     }
  30.     // NULL terminate the list
  31.     if (SUCCEEDED(hr))
  32.     {
  33.         DWORD dwData = 0;
  34.         DWORD cbBytes;
  35.         hr = ((CMemStream*)pstm)->Write(&dwData, SIZEOF(dwData), &cbBytes);
  36.     }
  37.     return(hr);
  38. }
  39. HRESULT SHReadDataBlockList(IStream* pstm, LPDBLIST * ppdbList)
  40. {
  41.     HRESULT hres;
  42.     BYTE buf[200]; // all blocks today fit in this size (tested at 5)
  43.     LPDATABLOCK_HEADER lpBuf = (LPDATABLOCK_HEADER)buf;
  44.     DWORD cbBuf = SIZEOF(buf);
  45.     DWORD dwSizeToRead, cbBytes;
  46.     if (*ppdbList)
  47.     {
  48.         LocalFree((HLOCAL)(*ppdbList));
  49.         *ppdbList = NULL;
  50.     }
  51.     while (TRUE)
  52.     {
  53.         DWORD cbSize;
  54.         dwSizeToRead = SIZEOF(cbSize);
  55.         hres = ((CMemStream*)pstm)->Read(&cbSize, dwSizeToRead, &cbBytes);
  56.         if (SUCCEEDED(hres) && (cbBytes == dwSizeToRead))
  57.         {
  58.             // Windows 95 and NT 4 shipped a CShellLink that did NOT
  59.             // NULL terminate the data it wrote out to the stream.
  60.             // If more data was persisted after the CShellLink then
  61.             // we will read in garbage. No real harm comes of this (*)
  62.             // (because it is unlikely we'll get a dwSignature match)
  63.             // but if the first dword is huge, we'll allocate a ton
  64.             // of memory and page it in. This can take MINUTES on Win95.
  65.             // Assume anything over 64K is from one of these
  66.             // bogus streams.
  67.             //
  68.             // (*) actually, real harm comes because we don't leave the
  69.             // stream in the correct place. Forms^3 put a work-around
  70.             // in for this bug.
  71.             //
  72.             if (cbSize > 0x0000FFFF)
  73.             {
  74.                 ULARGE_INTEGER liStart;
  75.                 LARGE_INTEGER liMove;
  76.                 // We read a DWORD of data that wasn't ours, back up.
  77.                 // NOTE: all of our stream implementations assume
  78.                 //       HighPart == 0
  79.                 //
  80.                 liMove.HighPart = liMove.LowPart = 0;
  81.                 if (SUCCEEDED(((CMemStream*)pstm)->Seek(liMove, STREAM_SEEK_CUR, &liStart)))
  82.                 {
  83.                     ASSERT(liStart.HighPart == 0);
  84.                     ASSERT(liStart.LowPart >= SIZEOF(cbSize));
  85.                     liMove.LowPart = liStart.LowPart - SIZEOF(cbSize);
  86.                     ((CMemStream*)pstm)->Seek(liMove, STREAM_SEEK_SET, NULL);
  87.                 }
  88.                 TraceMsg(TF_DBLIST, "ASSUMING NO NULL TERMINATION (FOR SIZE 0x%x)", cbSize);
  89.                 cbSize = 0;
  90.             }
  91.             // If we hit the 0 terminator, we're done.
  92.             //
  93.             if (cbSize < SIZEOF(DATABLOCK_HEADER))
  94.                 break;
  95.             // Make sure we can read this block in.
  96.             //
  97.             if (cbSize > cbBuf)
  98.             {
  99.                 HLOCAL pTemp;
  100.                 if (lpBuf == (LPDATABLOCK_HEADER)buf)
  101.                     pTemp = LocalAlloc(LPTR, cbSize);
  102.                 else
  103.                     pTemp = LocalReAlloc((HLOCAL)lpBuf, cbSize, LMEM_ZEROINIT | LMEM_MOVEABLE);
  104.                 if (pTemp)
  105.                 {
  106.                     lpBuf = (LPDATABLOCK_HEADER)pTemp;
  107.                     cbBuf = cbSize;
  108.                 }
  109.                 else
  110.                 {
  111.                     hres = E_OUTOFMEMORY;
  112.                     break;
  113.                 }
  114.             }
  115.             // Read in data block
  116.             //
  117.             lpBuf->cbSize = cbSize;
  118.             dwSizeToRead = cbSize - SIZEOF(cbSize);
  119.             hres = ((CMemStream*)pstm)->Read((LPBYTE)&(lpBuf->dwSignature), dwSizeToRead, &cbBytes);
  120.             if (SUCCEEDED(hres) && (cbBytes == dwSizeToRead))
  121.             {
  122.                 TraceMsg(TF_DBLIST, "Reading extra data block, size:%x sig:%x", lpBuf->cbSize, lpBuf->dwSignature);
  123.                 SHAddDataBlock(ppdbList, lpBuf);
  124.             }
  125.             else
  126.                 break;
  127.         }
  128.         else
  129.             break;
  130.     }
  131.     // Free any allocated buffer
  132.     //
  133.     if (lpBuf != (LPDATABLOCK_HEADER)buf)
  134.     {
  135.         LocalFree((HLOCAL)lpBuf);
  136.     }
  137.     return(hres);
  138. }
  139. void SHFreeDataBlockList(LPDBLIST pdbList)
  140. {
  141.     if (pdbList)
  142.     {
  143.         LocalFree((HLOCAL)pdbList);
  144.     }
  145. }
  146. BOOL SHAddDataBlock(LPDBLIST * ppdbList, LPDATABLOCK_HEADER pdb)
  147. {
  148.     LPDBLIST pdbCopyTo = NULL;
  149.     DWORD dwSize;
  150.     // Don't let anyone use our special signature
  151.     //
  152.     if (DBSIG_WRAP == pdb->dwSignature ||
  153.         pdb->cbSize < SIZEOF(*pdb))
  154.     {
  155.         TraceMsg(TF_DBLIST, "SHAddDataBlock invalid datablock! (sig:%x size:%x)", pdb->dwSignature, pdb->cbSize);
  156.         return E_INVALIDARG;
  157.     }
  158.     // Figure out how much space we need to hold this block
  159.     //
  160.     dwSize = pdb->cbSize;
  161.     if (pdb->cbSize & 0x3)
  162.     {
  163.         dwSize = ((dwSize + 3) & ~0x3) + SIZEOF(DATABLOCK_HEADER);
  164.         TraceMsg(TF_DBLIST, "Adding non-DWORD data block, size:%x sig:%x", pdb->cbSize, pdb->dwSignature);
  165.     }
  166.     else
  167.     {
  168.         TraceMsg(TF_DBLIST, "Adding data block, size:%x sig:%x", pdb->cbSize, pdb->dwSignature);
  169.     }
  170.     // Allocate the space
  171.     //
  172.     if (!*ppdbList)
  173.     {
  174.         *ppdbList = (LPDBLIST)LocalAlloc(LPTR, dwSize + SIZEOF(DWORD)); // include NULL terminator
  175.         pdbCopyTo = *ppdbList;
  176.     }
  177.     else
  178.     {
  179.         DWORD dwTotalSize = 0;
  180.         LPDBLIST pdbList;
  181.         HLOCAL lpTmp;
  182.         for (pdbList = *ppdbList ; pdbList->cbSize ; pdbList = _DBLNext(pdbList))
  183.             dwTotalSize += pdbList->cbSize;
  184.         lpTmp = LocalReAlloc((HLOCAL)*ppdbList, dwTotalSize + dwSize + SIZEOF(DWORD), // include NULL terminator
  185.                              LMEM_ZEROINIT | LMEM_MOVEABLE);
  186.         if (lpTmp)
  187.         {
  188.             *ppdbList = (LPDBLIST)lpTmp;
  189.             pdbCopyTo = (LPDBLIST)(((LPBYTE)lpTmp) + dwTotalSize);
  190.         }
  191.     }
  192.     // Copy the data block
  193.     //
  194.     if (pdbCopyTo)
  195.     {
  196.         LPBYTE pTmp = (LPBYTE)pdbCopyTo;
  197.         // This block would cause other blocks to be
  198.         // unaligned, wrap it
  199.         //
  200.         ASSERT(0 == (dwSize & 0x3));
  201.         if (dwSize != pdb->cbSize)
  202.         {
  203.             pdbCopyTo->cbSize = dwSize;
  204.             pdbCopyTo->dwSignature = DBSIG_WRAP;
  205.             pTmp = (LPBYTE)(pdbCopyTo + 1);
  206.         }
  207.         CopyMemory(pTmp, pdb, pdb->cbSize);
  208.         // NULL terminate the list
  209.         _DBLNext(pdbCopyTo)->cbSize = 0;
  210.         return TRUE;
  211.     }
  212.     return FALSE;
  213. }
  214. BOOL SHRemoveDataBlock(LPDBLIST * ppdbList, DWORD dwSignature)
  215. {
  216.     LPDBLIST pdbRemove = NULL;
  217.     // Can't call SHFindDataBlock because that returnes the
  218.     // block that was wrapped, we want the block that wraps.
  219.     //
  220.     if (*ppdbList)
  221.     {
  222.         LPDBLIST pdbList = *ppdbList;
  223.         for ( ; pdbList->cbSize ; pdbList = _DBLNext(pdbList))
  224.         {
  225.             if (dwSignature == pdbList->dwSignature)
  226.             {
  227.                 TraceMsg(TF_DBLIST, "Removing data block, size:%x sig:%x ptr:%x", pdbList->cbSize, pdbList->dwSignature, pdbList);
  228.                 pdbRemove = pdbList;
  229.                 break;
  230.             }
  231.             else if (DBSIG_WRAP == pdbList->dwSignature)
  232.             {
  233.                 LPDBLIST pdbWrap = pdbList + 1;
  234.                 if (dwSignature == pdbWrap->dwSignature)
  235.                 {
  236.                     TraceMsg(TF_DBLIST, "Removing non-DWORD data block, size:%x sig:%x ptr:", pdbWrap->cbSize, pdbWrap->dwSignature, pdbWrap);
  237.                     pdbRemove = pdbList;
  238.                     break;
  239.                 }
  240.             }
  241.         }
  242.     }
  243.     if (pdbRemove)
  244.     {
  245.         LPDBLIST pdbNext = _DBLNext(pdbRemove);
  246.         LPDBLIST pdbEnd;
  247.         DWORD dwSizeOfBlockToRemove;
  248.         LONG lNewSize;
  249.         for (pdbEnd = pdbNext ; pdbEnd->cbSize ; pdbEnd = _DBLNext(pdbEnd))
  250.             ;
  251.         dwSizeOfBlockToRemove = pdbRemove->cbSize;
  252.         // Move remaining memory down
  253.         MoveMemory(pdbRemove, pdbNext, (DWORD_PTR)pdbEnd - (DWORD_PTR)pdbNext + SIZEOF(DWORD));
  254.         // Shrink our buffer
  255.         lNewSize = (LONG) LocalSize(*ppdbList ) - dwSizeOfBlockToRemove;
  256.         if (lNewSize > SIZEOF(DWORD))
  257.         {
  258.             LPVOID lpVoid;
  259.             if (NULL != (lpVoid = LocalReAlloc( (HLOCAL)*ppdbList, lNewSize, LMEM_ZEROINIT | LMEM_MOVEABLE )))
  260.             {
  261.                 *ppdbList = (LPDBLIST)lpVoid;
  262.             }
  263.         }
  264.         else
  265.         {
  266.             // We've removed the last section, delete the whole deal
  267.             LocalFree( (HLOCAL)(*ppdbList) );
  268.             *ppdbList = NULL;
  269.         }
  270.         return TRUE;
  271.     }
  272.     return FALSE;
  273. }
  274. LPVOID SHFindDataBlock(LPDBLIST pdbList, DWORD dwSignature)
  275. {
  276.     if (pdbList)
  277.     {
  278.         for ( ; pdbList->cbSize ; pdbList = _DBLNext(pdbList))
  279.         {
  280.             if (dwSignature == pdbList->dwSignature)
  281.             {
  282.                 TraceMsg(TF_DBLIST, "Found data block, size:%x sig:%x ptr:%x", pdbList->cbSize, pdbList->dwSignature, pdbList);
  283.                 return (LPVOID)pdbList;
  284.             }
  285.             else if (DBSIG_WRAP == pdbList->dwSignature)
  286.             {
  287.                 LPDBLIST pdbWrap = pdbList + 1;
  288.                 if (dwSignature == pdbWrap->dwSignature)
  289.                 {
  290.                     TraceMsg(TF_DBLIST, "Found non-DWORD data block, size:%x sig:%x ptr:%x", pdbWrap->cbSize, pdbWrap->dwSignature, pdbWrap);
  291.                     return (LPVOID)pdbWrap;
  292.                 }
  293.             }
  294.         }
  295.     }
  296.     return NULL;
  297. }
  298. } // extern "C"