Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
10 KiB

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