Leaked source code of windows server 2003
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.

1500 lines
41 KiB

  1. // --------------------------------------------------------------------------------
  2. // Stmutil.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "oertpriv.h"
  8. #include "shlwapi.h"
  9. #include "unicnvrt.h"
  10. #include <BadStrFunctions.h>
  11. #pragma warning (disable: 4127) // conditional expression is constant
  12. // Stream Block Copy Size
  13. #define STMTRNSIZE 4096
  14. // --------------------------------------------------------------------------------
  15. // Disk full simulation on CFileStream
  16. // --------------------------------------------------------------------------------
  17. #ifdef DEBUG
  18. static BOOL g_fSimulateFullDisk = 0;
  19. #endif
  20. // --------------------------------------------------------------------------------
  21. // HrIsStreamUnicode
  22. // --------------------------------------------------------------------------------
  23. OESTDAPI_(HRESULT) HrIsStreamUnicode(LPSTREAM pStream, BOOL *pfLittleEndian)
  24. {
  25. // Locals
  26. HRESULT hr=S_OK;
  27. BYTE rgb[2];
  28. DWORD cbRead;
  29. DWORD cbPosition;
  30. // Invalid Args
  31. if (NULL == pStream || NULL == pfLittleEndian)
  32. return(TraceResult(E_INVALIDARG));
  33. // Trace
  34. TraceCall("HrIsStreamUnicode");
  35. // Get the current position
  36. IF_FAILEXIT(hr = HrGetStreamPos(pStream, &cbPosition));
  37. // Read Two Bytes
  38. IF_FAILEXIT(hr = pStream->Read(rgb, 2, &cbRead));
  39. // Reposition the Stream
  40. HrStreamSeekSet(pStream, cbPosition);
  41. // Didn't Read Enough ?
  42. if (2 != cbRead)
  43. {
  44. hr = S_FALSE;
  45. goto exit;
  46. }
  47. // Little Endian
  48. if (0xFF == rgb[0] && 0xFE == rgb[1])
  49. {
  50. *pfLittleEndian = TRUE;
  51. hr = S_OK;
  52. goto exit;
  53. }
  54. // Big Endian
  55. if (0xFE == rgb[0] && 0xFF == rgb[1])
  56. {
  57. *pfLittleEndian = FALSE;
  58. hr = S_OK;
  59. goto exit;
  60. }
  61. // Not Unicode
  62. hr = S_FALSE;
  63. exit:
  64. // Done
  65. return(hr);
  66. }
  67. // --------------------------------------------------------------------------------
  68. // HrCopyLockBytesToStream
  69. // --------------------------------------------------------------------------------
  70. OESTDAPI_(HRESULT) HrCopyLockBytesToStream(ILockBytes *pLockBytes, IStream *pStream, ULONG *pcbCopied)
  71. {
  72. // Locals
  73. HRESULT hr=S_OK;
  74. ULARGE_INTEGER uliCopy;
  75. ULONG cbRead;
  76. BYTE rgbBuffer[STMTRNSIZE];
  77. // Invalid Artg
  78. Assert(pLockBytes && pStream);
  79. // Set offset
  80. uliCopy.QuadPart = 0;
  81. // Copy m_pLockBytes to pstmTemp
  82. while(1)
  83. {
  84. // Read
  85. CHECKHR(hr = pLockBytes->ReadAt(uliCopy, rgbBuffer, sizeof(rgbBuffer), &cbRead));
  86. // Done
  87. if (0 == cbRead)
  88. break;
  89. // Write to stream
  90. CHECKHR(hr = pStream->Write(rgbBuffer, cbRead, NULL));
  91. // Increment offset
  92. uliCopy.QuadPart += cbRead;
  93. }
  94. // Return Amount Copied
  95. if (pcbCopied)
  96. *pcbCopied = (ULONG)uliCopy.QuadPart;
  97. exit:
  98. // Done
  99. return hr;
  100. }
  101. // --------------------------------------------------------------------------------
  102. // FDoesStreamContains8bit
  103. // --------------------------------------------------------------------------------
  104. BOOL FDoesStreamContain8bit (LPSTREAM lpstm)
  105. {
  106. // Locals
  107. BOOL fResult=FALSE;
  108. BYTE buf[4096];
  109. ULONG cbRead,
  110. i;
  111. // Loop through the stream
  112. while(1)
  113. {
  114. // Read cbCopy bytes from in
  115. if (FAILED(lpstm->Read (buf, sizeof(buf), &cbRead)) || cbRead == 0)
  116. break;
  117. // Scan for 8bit
  118. for (i=0; i<cbRead; i++)
  119. {
  120. if (IS_EXTENDED(buf[i]))
  121. {
  122. fResult = TRUE;
  123. break;
  124. }
  125. }
  126. }
  127. // Done
  128. return fResult;
  129. }
  130. // --------------------------------------------------------------------------------
  131. // HrCopyStreamCB - A generic implementation of IStream::CopyTo
  132. // --------------------------------------------------------------------------------
  133. OESTDAPI_(HRESULT) HrCopyStreamCB(
  134. LPSTREAM lpstmIn,
  135. LPSTREAM lpstmOut,
  136. ULARGE_INTEGER uliCopy,
  137. ULARGE_INTEGER *puliRead,
  138. ULARGE_INTEGER *puliWritten)
  139. {
  140. // Locals
  141. HRESULT hr = S_OK;
  142. BYTE buf[4096];
  143. ULONG cbRead,
  144. cbWritten,
  145. cbRemaining = uliCopy.LowPart,
  146. cbGet;
  147. // Init out params
  148. if (puliRead)
  149. ULISet32(*puliRead, 0);
  150. if (puliWritten)
  151. ULISet32(*puliWritten, 0);
  152. if ((NULL == lpstmIn) || (NULL == lpstmOut) ||
  153. ((0 != uliCopy.HighPart) && ((DWORD)-1 != uliCopy.HighPart || (DWORD)-1 != uliCopy.LowPart)))
  154. return TrapError(E_INVALIDARG);
  155. while (cbRemaining)
  156. {
  157. cbGet = min(sizeof(buf), cbRemaining);
  158. CHECKHR (hr = lpstmIn->Read (buf, cbGet, &cbRead));
  159. if (0 == cbRead)
  160. break;
  161. CHECKHR (hr = lpstmOut->Write (buf, cbRead, &cbWritten));
  162. // Verify
  163. Assert (cbWritten == cbRead);
  164. if (puliRead)
  165. puliRead->LowPart += cbRead;
  166. if (puliWritten)
  167. puliWritten->LowPart += cbWritten;
  168. // Compute number of bytes left to copy
  169. cbRemaining -= cbRead;
  170. }
  171. exit:
  172. return hr;
  173. }
  174. // --------------------------------------------------------------------------------
  175. // HrCopyStreamCBEndOnCRLF - Copy cb bytes from lpstmIn to lpstmOut, and last CRLF
  176. // --------------------------------------------------------------------------------
  177. OESTDAPI_(HRESULT) HrCopyStreamCBEndOnCRLF(LPSTREAM lpstmIn, LPSTREAM lpstmOut, ULONG cb, ULONG *pcbActual)
  178. {
  179. // Locals
  180. HRESULT hr = S_OK;
  181. BYTE buf[4096];
  182. ULONG cbRead = 0, cbWritten = 0, cbTotal = 0, cbRemaining = 0, cbCopy;
  183. do
  184. {
  185. // Compute number of bytes left to copy
  186. cbRemaining = cb - cbTotal;
  187. if (cbRemaining >= sizeof (buf))
  188. cbCopy = sizeof (buf);
  189. else
  190. cbCopy = cbRemaining;
  191. // Done
  192. if (cbCopy == 0)
  193. break;
  194. // Read cbCopy bytes from in
  195. CHECKHR (hr = lpstmIn->Read (buf, cbCopy, &cbRead));
  196. if (cbRead == 0)
  197. break;
  198. // Write cbCopy bytes to out
  199. CHECKHR (hr = lpstmOut->Write (buf, cbRead, NULL));
  200. // Verify
  201. cbTotal += cbRead;
  202. } while (cbRead == cbCopy);
  203. // If last character was not a '\n', append until we append a '\n'
  204. // Yes, please do not tell me that this is horable because I know that copying one
  205. // character at a time from a stream is not good and I should be deported right
  206. // along with brettm, but, this loop should never iterate more than the max line
  207. // length of the body of a message, so there. (sbailey)
  208. if (cbRead && buf[cbRead] != '\n')
  209. {
  210. do
  211. {
  212. // Read cbCopy bytes from in
  213. CHECKHR (hr = lpstmIn->Read (buf, 1, &cbRead));
  214. // Nothing left
  215. if (cbRead == 0)
  216. break;
  217. // Write cbCopy bytes to out
  218. CHECKHR (hr = lpstmOut->Write (buf, 1, NULL));
  219. // Inc Total
  220. cbTotal++;
  221. } while (buf[0] != '\n');
  222. }
  223. exit:
  224. if (pcbActual)
  225. *pcbActual = cbTotal;
  226. return hr;
  227. }
  228. // --------------------------------------------------------------------------------
  229. // HrCopyStream2 - copies lpstmIn to two out streams - caller must do the commit
  230. // --------------------------------------------------------------------------------
  231. HRESULT HrCopyStream2(LPSTREAM lpstmIn, LPSTREAM lpstmOut1, LPSTREAM lpstmOut2, ULONG *pcb)
  232. {
  233. // Locals
  234. HRESULT hr = S_OK;
  235. BYTE buf[4096];
  236. ULONG cbRead = 0, cbWritten = 0, cbTotal = 0;
  237. do
  238. {
  239. CHECKHR (hr = lpstmIn->Read (buf, sizeof (buf), &cbRead));
  240. if (cbRead == 0) break;
  241. CHECKHR (hr = lpstmOut1->Write (buf, cbRead, &cbWritten));
  242. Assert (cbWritten == cbRead);
  243. CHECKHR (hr = lpstmOut2->Write (buf, cbRead, &cbWritten));
  244. Assert (cbWritten == cbRead);
  245. cbTotal += cbRead;
  246. }
  247. while (cbRead == sizeof (buf));
  248. exit:
  249. if (pcb)
  250. *pcb = cbTotal;
  251. return hr;
  252. }
  253. // --------------------------------------------------------------------------------
  254. // HrCopyStreamToFile
  255. // --------------------------------------------------------------------------------
  256. HRESULT HrCopyStreamToFile (LPSTREAM lpstm, HANDLE hFile, ULONG *pcb)
  257. {
  258. // Locals
  259. HRESULT hr = S_OK;
  260. BYTE buf[4096];
  261. ULONG cbRead = 0, cbWritten = 0, cbTotal = 0;
  262. BOOL bResult;
  263. do
  264. {
  265. // Read a block
  266. CHECKHR (hr = lpstm->Read (buf, sizeof (buf), &cbRead));
  267. if (cbRead == 0) break;
  268. // Write the block to the file
  269. bResult = WriteFile (hFile, buf, cbRead, &cbWritten, NULL);
  270. if (bResult == FALSE || cbWritten != cbRead)
  271. {
  272. hr = TrapError(E_FAIL);
  273. goto exit;
  274. }
  275. // Keep Track of Total bytes written
  276. cbTotal += cbRead;
  277. }
  278. while (cbRead == sizeof (buf));
  279. exit:
  280. // Set Total
  281. if (pcb)
  282. *pcb = cbTotal;
  283. // Done
  284. return hr;
  285. }
  286. // --------------------------------------------------------------------------------
  287. // HrStreamToByte
  288. // --------------------------------------------------------------------------------
  289. OESTDAPI_(HRESULT) HrStreamToByte(LPSTREAM lpstm, LPBYTE *lppb, ULONG *pcb)
  290. {
  291. // Locals
  292. HRESULT hr = S_OK;
  293. ULONG cbRead, cbSize;
  294. // Check Params
  295. AssertSz (lpstm && lppb, "Null Parameter");
  296. CHECKHR(hr = HrGetStreamSize(lpstm, &cbSize));
  297. CHECKHR(hr = HrRewindStream(lpstm));
  298. // Allocate Memory
  299. CHECKHR(hr = HrAlloc((LPVOID *)lppb, cbSize + 10));
  300. // Read Everything to lppsz
  301. CHECKHR(hr = lpstm->Read(*lppb, cbSize, &cbRead));
  302. if (cbRead != cbSize)
  303. {
  304. hr = TrapError(S_FALSE);
  305. goto exit;
  306. }
  307. // Outbound size
  308. if (pcb)
  309. *pcb = cbSize;
  310. exit:
  311. // Done
  312. return hr;
  313. }
  314. // --------------------------------------------------------------------------------
  315. // HrCopyStream
  316. // --------------------------------------------------------------------------------
  317. OESTDAPI_(HRESULT) HrCopyStream(LPSTREAM pstmIn, LPSTREAM pstmOut, OPTIONAL ULONG *pcb)
  318. {
  319. // Locals
  320. HRESULT hr = S_OK;
  321. BYTE buf[STMTRNSIZE];
  322. ULONG cbRead=0,
  323. cbTotal=0;
  324. do
  325. {
  326. CHECKHR(hr = pstmIn->Read(buf, sizeof(buf), &cbRead));
  327. if (cbRead == 0) break;
  328. CHECKHR(hr = pstmOut->Write(buf, cbRead, NULL));
  329. cbTotal += cbRead;
  330. }
  331. while (cbRead == sizeof (buf));
  332. exit:
  333. if (pcb)
  334. *pcb = cbTotal;
  335. return hr;
  336. }
  337. // --------------------------------------------------------------------------------
  338. // HrCopyStreamToByte
  339. // --------------------------------------------------------------------------------
  340. OESTDAPI_(HRESULT) HrCopyStreamToByte(LPSTREAM lpstmIn, LPBYTE pbDest, ULONG *pcb)
  341. {
  342. // Locals
  343. HRESULT hr=S_OK;
  344. BYTE buf[STMTRNSIZE];
  345. ULONG cbRead=0,
  346. cbTotal=0;
  347. do
  348. {
  349. // Read a buffer from stream
  350. CHECKHR(hr = lpstmIn->Read (buf, sizeof (buf), &cbRead));
  351. // Nothing Read...
  352. if (cbRead == 0)
  353. break;
  354. // Copy that
  355. CopyMemory(pbDest + cbTotal, buf, cbRead);
  356. // Increment total
  357. cbTotal += cbRead;
  358. } while (cbRead == sizeof(buf));
  359. exit:
  360. // Set total
  361. if (pcb)
  362. *pcb = cbTotal;
  363. // Done
  364. return hr;
  365. }
  366. // --------------------------------------------------------------------------------
  367. // HrByteToStream
  368. // --------------------------------------------------------------------------------
  369. OESTDAPI_(HRESULT) HrByteToStream(LPSTREAM *lppstm, LPBYTE lpb, ULONG cb)
  370. {
  371. // Locals
  372. HRESULT hr=S_OK;
  373. // Check Params
  374. AssertSz(lppstm && lpb, "Null Parameter");
  375. // Create H Global Stream
  376. CHECKHR(hr = CreateStreamOnHGlobal (NULL, TRUE, lppstm));
  377. // Write String
  378. CHECKHR(hr = (*lppstm)->Write (lpb, cb, NULL));
  379. // Rewind the steam
  380. CHECKHR(hr = HrRewindStream(*lppstm));
  381. exit:
  382. // Done
  383. return hr;
  384. }
  385. // --------------------------------------------------------------------------------
  386. // HrRewindStream
  387. // --------------------------------------------------------------------------------
  388. OESTDAPI_(HRESULT) HrRewindStream(LPSTREAM pstm)
  389. {
  390. // Locals
  391. HRESULT hr=S_OK;
  392. LARGE_INTEGER liOrigin = {0,0};
  393. // Check Params
  394. Assert(pstm);
  395. // Seek to 0
  396. CHECKHR(hr = pstm->Seek(liOrigin, STREAM_SEEK_SET, NULL));
  397. exit:
  398. // Done
  399. return hr;
  400. }
  401. // --------------------------------------------------------------------------------
  402. // HrGetStreamPos
  403. // --------------------------------------------------------------------------------
  404. HRESULT HrGetStreamPos(LPSTREAM pstm, ULONG *piPos)
  405. {
  406. // Locals
  407. HRESULT hr=S_OK;
  408. ULARGE_INTEGER uliPos = {0,0};
  409. LARGE_INTEGER liOrigin = {0,0};
  410. // check Params
  411. Assert(piPos && pstm);
  412. // Seek
  413. CHECKHR(hr = pstm->Seek(liOrigin, STREAM_SEEK_CUR, &uliPos));
  414. // Set position
  415. *piPos = uliPos.LowPart;
  416. exit:
  417. // Done
  418. return hr;
  419. }
  420. // --------------------------------------------------------------------------------
  421. // HrGetStreamSize
  422. // --------------------------------------------------------------------------------
  423. OESTDAPI_(HRESULT) HrGetStreamSize(LPSTREAM pstm, ULONG *pcb)
  424. {
  425. // Locals
  426. HRESULT hr=S_OK;
  427. ULARGE_INTEGER uliPos = {0,0};
  428. LARGE_INTEGER liOrigin = {0,0};
  429. // check params
  430. Assert(pcb && pstm);
  431. // Seek
  432. CHECKHR(hr = pstm->Seek(liOrigin, STREAM_SEEK_END, &uliPos));
  433. // set size
  434. *pcb = uliPos.LowPart;
  435. exit:
  436. // Done
  437. return hr;
  438. }
  439. // --------------------------------------------------------------------------------
  440. // HrSafeGetStreamSize
  441. // --------------------------------------------------------------------------------
  442. HRESULT HrSafeGetStreamSize(LPSTREAM pstm, ULONG *pcb)
  443. {
  444. // Locals
  445. HRESULT hr=S_OK;
  446. ULONG iPos;
  447. ULARGE_INTEGER uliPos = {0,0};
  448. LARGE_INTEGER liOrigin = {0,0};
  449. // check params
  450. Assert(pcb && pstm);
  451. // Get the stream position
  452. CHECKHR(hr = HrGetStreamPos(pstm, &iPos));
  453. // Seek
  454. CHECKHR(hr = pstm->Seek(liOrigin, STREAM_SEEK_END, &uliPos));
  455. // set size
  456. *pcb = uliPos.LowPart;
  457. // Seek back to original position
  458. CHECKHR(hr = HrStreamSeekSet(pstm, iPos));
  459. exit:
  460. // Done
  461. return hr;
  462. }
  463. // --------------------------------------------------------------------------------
  464. // HrStreamSeekSet
  465. // --------------------------------------------------------------------------------
  466. OESTDAPI_(HRESULT) HrStreamSeekSet(LPSTREAM pstm, ULONG iPos)
  467. {
  468. // Locals
  469. HRESULT hr=S_OK;
  470. LARGE_INTEGER liOrigin;
  471. // Check Params
  472. Assert(pstm);
  473. // Set Origin Correctly
  474. liOrigin.QuadPart = iPos;
  475. // Seek
  476. CHECKHR(hr = pstm->Seek(liOrigin, STREAM_SEEK_SET, NULL));
  477. exit:
  478. // Done
  479. return hr;
  480. }
  481. // --------------------------------------------------------------------------------
  482. // HrStreamSeekEnd
  483. // --------------------------------------------------------------------------------
  484. OESTDAPI_(HRESULT) HrStreamSeekEnd(LPSTREAM pstm)
  485. {
  486. // Locals
  487. HRESULT hr=S_OK;
  488. LARGE_INTEGER liOrigin = {0,0};
  489. // Check Params
  490. Assert(pstm);
  491. // Seek
  492. CHECKHR(hr = pstm->Seek(liOrigin, STREAM_SEEK_END, NULL));
  493. exit:
  494. // Done
  495. return hr;
  496. }
  497. // --------------------------------------------------------------------------------
  498. // HrStreamSeekBegin
  499. // --------------------------------------------------------------------------------
  500. OESTDAPI_(HRESULT) HrStreamSeekBegin(LPSTREAM pstm)
  501. {
  502. // Locals
  503. HRESULT hr=S_OK;
  504. LARGE_INTEGER liOrigin = {0,0};
  505. // Check Params
  506. Assert(pstm);
  507. // Seek
  508. CHECKHR(hr = pstm->Seek(liOrigin, STREAM_SEEK_SET, NULL));
  509. exit:
  510. // Done
  511. return hr;
  512. }
  513. // --------------------------------------------------------------------------------
  514. // HrStreamSeekCur
  515. // --------------------------------------------------------------------------------
  516. OESTDAPI_(HRESULT) HrStreamSeekCur(LPSTREAM pstm, LONG iPos)
  517. {
  518. // Locals
  519. HRESULT hr=S_OK;
  520. LARGE_INTEGER liOrigin;
  521. // Check Params
  522. Assert(pstm);
  523. // Setup Origin
  524. liOrigin.QuadPart = iPos;
  525. // Seek
  526. CHECKHR(hr = pstm->Seek(liOrigin, STREAM_SEEK_CUR, NULL));
  527. exit:
  528. // Done
  529. return hr;
  530. }
  531. // --------------------------------------------------------------------------------
  532. // CreateFileStream
  533. // --------------------------------------------------------------------------------
  534. HRESULT CreateFileStream(
  535. LPWSTR pszFile,
  536. DWORD dwDesiredAccess,
  537. DWORD dwShareMode,
  538. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  539. DWORD dwCreationDistribution,
  540. DWORD dwFlagsAndAttributes,
  541. HANDLE hTemplateFile,
  542. LPSTREAM *ppstmFile)
  543. {
  544. // Locals
  545. HRESULT hr=S_OK;
  546. FILESTREAMINFO rInfo;
  547. CFileStream *pstmFile=NULL;
  548. WCHAR szTempDir[MAX_PATH];
  549. // check params
  550. if (NULL == ppstmFile)
  551. return TrapError(E_INVALIDARG);
  552. // Check Params
  553. Assert(dwDesiredAccess & GENERIC_READ || dwDesiredAccess & GENERIC_WRITE);
  554. // Setup File Stream Info struct
  555. ZeroMemory(&rInfo, sizeof(rInfo));
  556. rInfo.dwDesiredAccess = dwDesiredAccess;
  557. rInfo.dwShareMode = dwShareMode;
  558. if (lpSecurityAttributes)
  559. CopyMemory(&rInfo.rSecurityAttributes, lpSecurityAttributes, sizeof(SECURITY_ATTRIBUTES));
  560. rInfo.dwCreationDistribution = dwCreationDistribution;
  561. rInfo.dwFlagsAndAttributes = dwFlagsAndAttributes;
  562. rInfo.hTemplateFile = hTemplateFile;
  563. // Create Object
  564. pstmFile = new CFileStream();
  565. if (NULL == pstmFile)
  566. {
  567. hr = TrapError(E_OUTOFMEMORY);
  568. goto exit;
  569. }
  570. // Temp File ?
  571. if (NULL == pszFile)
  572. {
  573. // Get Temp Dir
  574. DWORD nBufferLength = AthGetTempPathW(ARRAYSIZE(szTempDir), szTempDir);
  575. if (nBufferLength == 0 || nBufferLength > ARRAYSIZE(szTempDir))
  576. {
  577. hr = TrapError(E_FAIL);
  578. goto exit;
  579. }
  580. // Get Temp File Name
  581. UINT uFile = AthGetTempFileNameW(szTempDir, L"tmp", 0, rInfo.szFilePath);
  582. if (uFile == 0)
  583. {
  584. hr = TrapError(E_FAIL);
  585. goto exit;
  586. }
  587. #ifdef DEBUG
  588. else if (g_fSimulateFullDisk)
  589. {
  590. hr = TrapError(E_FAIL);
  591. goto exit;
  592. }
  593. #endif
  594. // Delete When Done
  595. rInfo.dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
  596. // Always create a new temp file
  597. rInfo.dwCreationDistribution = OPEN_EXISTING;
  598. }
  599. else
  600. {
  601. // Copy filename
  602. StrCpyNW(rInfo.szFilePath, pszFile, ARRAYSIZE(rInfo.szFilePath));
  603. }
  604. // Open it
  605. CHECKHR(hr = pstmFile->Open(&rInfo));
  606. // Success
  607. *ppstmFile = pstmFile;
  608. pstmFile = NULL;
  609. exit:
  610. // Cleanup
  611. SafeRelease(pstmFile);
  612. // Done
  613. return hr;
  614. }
  615. // --------------------------------------------------------------------------------
  616. // CreateTempFileStream
  617. // --------------------------------------------------------------------------------
  618. OESTDAPI_(HRESULT) CreateTempFileStream(LPSTREAM *ppstmFile)
  619. {
  620. return CreateFileStream(NULL,
  621. GENERIC_READ | GENERIC_WRITE,
  622. FILE_SHARE_READ | FILE_SHARE_WRITE,
  623. NULL,
  624. OPEN_ALWAYS,
  625. FILE_ATTRIBUTE_NORMAL,
  626. NULL,
  627. ppstmFile);
  628. }
  629. // --------------------------------------------------------------------------------
  630. // OpenFileStream
  631. // --------------------------------------------------------------------------------
  632. OESTDAPI_(HRESULT) OpenFileStream(LPSTR pszFile, DWORD dwCreationDistribution,
  633. DWORD dwAccess, LPSTREAM *ppstmFile)
  634. {
  635. // Locals
  636. HRESULT hr=S_OK;
  637. LPWSTR pszFileW=NULL;
  638. // Trace
  639. TraceCall("OpenFileStream");
  640. // Convert
  641. IF_NULLEXIT(pszFileW = PszToUnicode(CP_ACP, pszFile));
  642. // Call unicode version
  643. IF_FAILEXIT(hr = OpenFileStreamW(pszFileW, dwCreationDistribution, dwAccess, ppstmFile));
  644. exit:
  645. // Cleanup
  646. SafeMemFree(pszFileW);
  647. // Done
  648. return(hr);
  649. }
  650. // --------------------------------------------------------------------------------
  651. // OpenFileStreamW
  652. // --------------------------------------------------------------------------------
  653. OESTDAPI_(HRESULT) OpenFileStreamW(LPWSTR pszFile, DWORD dwCreationDistribution,
  654. DWORD dwAccess, LPSTREAM *ppstmFile)
  655. {
  656. Assert(pszFile);
  657. return CreateFileStream(pszFile,
  658. dwAccess,
  659. FILE_SHARE_READ | FILE_SHARE_WRITE,
  660. NULL,
  661. dwCreationDistribution,
  662. FILE_ATTRIBUTE_NORMAL,
  663. NULL,
  664. ppstmFile);
  665. }
  666. // --------------------------------------------------------------------------------
  667. // OpenFileStreamWithFlags
  668. // --------------------------------------------------------------------------------
  669. OESTDAPI_(HRESULT) OpenFileStreamWithFlags(LPSTR pszFile, DWORD dwCreationDistribution,
  670. DWORD dwAccess, DWORD dwFlagsAndAttributes, LPSTREAM *ppstmFile)
  671. {
  672. // Locals
  673. HRESULT hr=S_OK;
  674. LPWSTR pszFileW=NULL;
  675. // Trace
  676. TraceCall("OpenFileStreamWithFlags");
  677. // Convert to unicode
  678. IF_NULLEXIT(pszFileW = PszToUnicode(CP_ACP, pszFile));
  679. // Call unicode version
  680. IF_FAILEXIT(hr = OpenFileStreamWithFlagsW(pszFileW, dwCreationDistribution, dwAccess, dwFlagsAndAttributes, ppstmFile));
  681. exit:
  682. // Cleanup
  683. SafeMemFree(pszFileW);
  684. // Done
  685. return(hr);
  686. }
  687. // --------------------------------------------------------------------------------
  688. // OpenFileStreamWithFlagsW
  689. // --------------------------------------------------------------------------------
  690. OESTDAPI_(HRESULT) OpenFileStreamWithFlagsW(LPWSTR pszFile, DWORD dwCreationDistribution,
  691. DWORD dwAccess, DWORD dwFlagsAndAttributes, LPSTREAM *ppstmFile)
  692. {
  693. Assert(pszFile);
  694. return CreateFileStream(pszFile,
  695. dwAccess,
  696. FILE_SHARE_READ | FILE_SHARE_WRITE,
  697. NULL,
  698. dwCreationDistribution,
  699. dwFlagsAndAttributes,
  700. NULL,
  701. ppstmFile);
  702. }
  703. // --------------------------------------------------------------------------------
  704. // WriteStreamToFile
  705. // --------------------------------------------------------------------------------
  706. OESTDAPI_(HRESULT) WriteStreamToFile(LPSTREAM pstm, LPSTR lpszFile, DWORD dwCreationDistribution, DWORD dwAccess)
  707. {
  708. // Locals
  709. HRESULT hr=S_OK;
  710. LPWSTR pszFileW=NULL;
  711. // Trace
  712. TraceCall("WriteStreamToFile");
  713. // Convert to unicode
  714. IF_NULLEXIT(pszFileW = PszToUnicode(CP_ACP, lpszFile));
  715. // Call Unicode Version
  716. IF_FAILEXIT(hr = WriteStreamToFileW(pstm, pszFileW, dwCreationDistribution, dwAccess));
  717. exit:
  718. // Cleanup
  719. SafeMemFree(pszFileW);
  720. // Done
  721. return(hr);
  722. }
  723. // --------------------------------------------------------------------------------
  724. // WriteStreamToFileW
  725. // --------------------------------------------------------------------------------
  726. OESTDAPI_(HRESULT) WriteStreamToFileW(LPSTREAM pstm, LPWSTR lpszFile, DWORD dwCreationDistribution, DWORD dwAccess)
  727. {
  728. // Locals
  729. HRESULT hr=S_OK;
  730. LPSTREAM pstmFile=NULL;
  731. // Open the stream
  732. IF_FAILEXIT(hr = OpenFileStreamW(lpszFile, dwCreationDistribution, dwAccess, &pstmFile));
  733. // Rewind
  734. IF_FAILEXIT(hr = HrRewindStream(pstm));
  735. // Copy
  736. IF_FAILEXIT(hr = HrCopyStream (pstm, pstmFile, NULL));
  737. // Rewind
  738. IF_FAILEXIT(hr = HrRewindStream(pstm));
  739. exit:
  740. // Cleanup
  741. SafeRelease(pstmFile);
  742. // Done
  743. return(hr);
  744. }
  745. // --------------------------------------------------------------------------------
  746. // OpenFileStreamShare
  747. // --------------------------------------------------------------------------------
  748. OESTDAPI_(HRESULT) OpenFileStreamShare(LPSTR pszFile, DWORD dwCreationDistribution, DWORD dwAccess,
  749. DWORD dwShare, LPSTREAM *ppstmFile)
  750. {
  751. // Locals
  752. HRESULT hr=S_OK;
  753. LPWSTR pszFileW=NULL;
  754. // Trace
  755. TraceCall("OpenFileStreamShare");
  756. // Convert to unicode
  757. IF_NULLEXIT(pszFileW = PszToUnicode(CP_ACP, pszFile));
  758. // Call unicode versoin
  759. IF_FAILEXIT(hr = OpenFileStreamShareW(pszFileW, dwCreationDistribution, dwAccess, dwShare, ppstmFile));
  760. exit:
  761. // Cleanup
  762. SafeMemFree(pszFileW);
  763. // Done
  764. return(hr);
  765. }
  766. // --------------------------------------------------------------------------------
  767. // OpenFileStreamShareW
  768. // --------------------------------------------------------------------------------
  769. OESTDAPI_(HRESULT) OpenFileStreamShareW(LPWSTR pszFile, DWORD dwCreationDistribution, DWORD dwAccess,
  770. DWORD dwShare, LPSTREAM *ppstmFile)
  771. {
  772. Assert(pszFile);
  773. return CreateFileStream(pszFile,
  774. dwAccess,
  775. dwShare,
  776. NULL,
  777. dwCreationDistribution,
  778. FILE_ATTRIBUTE_NORMAL,
  779. NULL,
  780. ppstmFile);
  781. }
  782. // --------------------------------------------------------------------------------
  783. // CFileStream::Constructor
  784. // --------------------------------------------------------------------------------
  785. CFileStream::CFileStream(void)
  786. {
  787. m_cRef = 1;
  788. m_hFile = INVALID_HANDLE_VALUE;
  789. ZeroMemory(&m_rInfo, sizeof(FILESTREAMINFO));
  790. }
  791. // --------------------------------------------------------------------------------
  792. // CFileStream::Deconstructor
  793. // --------------------------------------------------------------------------------
  794. CFileStream::~CFileStream(void)
  795. {
  796. Close();
  797. }
  798. // --------------------------------------------------------------------------------
  799. // CFileStream::AddRef
  800. // --------------------------------------------------------------------------------
  801. ULONG CFileStream::AddRef ()
  802. {
  803. return ++m_cRef;
  804. }
  805. // --------------------------------------------------------------------------------
  806. // CFileStream::Release
  807. // --------------------------------------------------------------------------------
  808. ULONG CFileStream::Release ()
  809. {
  810. if (0 != --m_cRef)
  811. return m_cRef;
  812. delete this;
  813. return 0;
  814. }
  815. // --------------------------------------------------------------------------------
  816. // CFileStream::QueryInterface
  817. // --------------------------------------------------------------------------------
  818. STDMETHODIMP CFileStream::QueryInterface (REFIID iid, LPVOID* ppvObj)
  819. {
  820. if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IStream))
  821. {
  822. *ppvObj = this;
  823. AddRef();
  824. return(S_OK);
  825. }
  826. return E_NOINTERFACE;
  827. }
  828. // --------------------------------------------------------------------------------
  829. // CFileStream::Open
  830. // --------------------------------------------------------------------------------
  831. HRESULT CFileStream::Open(LPFILESTREAMINFO pFileStreamInfo)
  832. {
  833. // Better not be open
  834. Assert(m_hFile == INVALID_HANDLE_VALUE);
  835. // Copy File Info
  836. CopyMemory(&m_rInfo, pFileStreamInfo, sizeof(FILESTREAMINFO));
  837. // Open the file
  838. m_hFile = AthCreateFileW(m_rInfo.szFilePath, m_rInfo.dwDesiredAccess, m_rInfo.dwShareMode,
  839. NULL, m_rInfo.dwCreationDistribution,
  840. m_rInfo.dwFlagsAndAttributes, m_rInfo.hTemplateFile);
  841. // Error
  842. if (INVALID_HANDLE_VALUE == m_hFile)
  843. return TrapError(E_FAIL);
  844. #ifdef DEBUG
  845. else if (g_fSimulateFullDisk)
  846. return TrapError(E_FAIL);
  847. #endif
  848. // Success
  849. return S_OK;
  850. }
  851. // --------------------------------------------------------------------------------
  852. // CFileStream::Close
  853. // --------------------------------------------------------------------------------
  854. void CFileStream::Close(void)
  855. {
  856. if (INVALID_HANDLE_VALUE != m_hFile)
  857. {
  858. CloseHandle_F16(m_hFile);
  859. m_hFile = INVALID_HANDLE_VALUE;
  860. }
  861. }
  862. // --------------------------------------------------------------------------------
  863. // CFileStream::Read
  864. // --------------------------------------------------------------------------------
  865. STDMETHODIMP CFileStream::Read (void HUGEP_16 *lpv, ULONG cb, ULONG *pcbRead)
  866. {
  867. // Locals
  868. HRESULT hr = S_OK;
  869. BOOL fReturn;
  870. DWORD dwRead;
  871. // Check Params
  872. Assert(lpv && m_hFile != INVALID_HANDLE_VALUE);
  873. // Read some bytes from m_hFile
  874. fReturn = ReadFile (m_hFile, lpv, cb, &dwRead, NULL);
  875. if (!fReturn)
  876. {
  877. AssertSz(FALSE, "CFileStream::Read Failed");
  878. hr = TrapError(E_FAIL);
  879. goto exit;
  880. }
  881. // Write byte
  882. if (pcbRead)
  883. *pcbRead = dwRead;
  884. exit:
  885. // Done
  886. return hr;
  887. }
  888. // --------------------------------------------------------------------------------
  889. // CFileStream::Write
  890. // --------------------------------------------------------------------------------
  891. STDMETHODIMP CFileStream::Write(const void HUGEP_16 *lpv, ULONG cb, ULONG *pcbWritten)
  892. {
  893. // Locals
  894. HRESULT hr = S_OK;
  895. BOOL fReturn;
  896. DWORD dwWritten;
  897. // Check Params
  898. Assert(lpv);
  899. Assert(m_hFile != INVALID_HANDLE_VALUE);
  900. // Read some bytes from m_hFile
  901. fReturn = WriteFile(m_hFile, lpv, cb, &dwWritten, NULL);
  902. if (!fReturn)
  903. {
  904. AssertSz (FALSE, "CFileStream::Write Failed");
  905. hr = TrapError(E_FAIL);
  906. goto exit;
  907. }
  908. #ifdef DEBUG
  909. else if (g_fSimulateFullDisk)
  910. {
  911. AssertSz (FALSE, "CFileStream::Write Failed");
  912. hr = TrapError(E_FAIL);
  913. goto exit;
  914. }
  915. #endif
  916. // Write byte
  917. if (pcbWritten)
  918. *pcbWritten = dwWritten;
  919. exit:
  920. // Done
  921. return hr;
  922. }
  923. // --------------------------------------------------------------------------------
  924. // CFileStream::Seek
  925. // --------------------------------------------------------------------------------
  926. STDMETHODIMP CFileStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  927. {
  928. // Locals
  929. HRESULT hr = S_OK;
  930. DWORD dwReturn;
  931. LONG lMove; // Cast to signed, could be negative
  932. Assert (m_hFile != INVALID_HANDLE_VALUE);
  933. // Cast lowpart
  934. lMove = (LONG)dlibMove.QuadPart;
  935. // Seek the file pointer
  936. switch (dwOrigin)
  937. {
  938. case STREAM_SEEK_SET:
  939. dwReturn = SetFilePointer (m_hFile, lMove, NULL, FILE_BEGIN);
  940. break;
  941. case STREAM_SEEK_CUR:
  942. dwReturn = SetFilePointer (m_hFile, lMove, NULL, FILE_CURRENT);
  943. break;
  944. case STREAM_SEEK_END:
  945. dwReturn = SetFilePointer (m_hFile, lMove, NULL, FILE_END);
  946. break;
  947. default:
  948. dwReturn = 0xFFFFFFFF;
  949. }
  950. // Failure ?
  951. if (dwReturn == 0xFFFFFFFF)
  952. {
  953. AssertSz(FALSE, "CFileStream::Seek Failed");
  954. hr = TrapError(E_FAIL);
  955. goto exit;
  956. }
  957. // Return Position
  958. if (plibNewPosition)
  959. plibNewPosition->QuadPart = dwReturn;
  960. exit:
  961. // Done
  962. return hr;
  963. }
  964. // --------------------------------------------------------------------------------
  965. // CFileStream::Commit
  966. // --------------------------------------------------------------------------------
  967. STDMETHODIMP CFileStream::Commit(DWORD)
  968. {
  969. // Locals
  970. HRESULT hr = S_OK;
  971. Assert(m_hFile != INVALID_HANDLE_VALUE);
  972. // Flush the buffers
  973. if (FlushFileBuffers (m_hFile) == FALSE)
  974. {
  975. AssertSz(FALSE, "FlushFileBuffers failed");
  976. hr = TrapError(E_FAIL);
  977. goto exit;
  978. }
  979. exit:
  980. // Done
  981. return hr;
  982. }
  983. // --------------------------------------------------------------------------------
  984. // CFileStream::SetSize
  985. // --------------------------------------------------------------------------------
  986. STDMETHODIMP CFileStream::SetSize (ULARGE_INTEGER uli)
  987. {
  988. DWORD dwOrig;
  989. // remember the current file position
  990. dwOrig = SetFilePointer (m_hFile, 0, NULL, FILE_CURRENT);
  991. if (dwOrig == 0xFFFFFFFF)
  992. {
  993. AssertSz(FALSE, "Get current position failed");
  994. return TrapError(E_FAIL);
  995. }
  996. // Seek to dwSize
  997. if (SetFilePointer (m_hFile, uli.LowPart, NULL, FILE_BEGIN) == 0xFFFFFFFF)
  998. {
  999. AssertSz(FALSE, "SetFilePointer failed");
  1000. return TrapError(STG_E_MEDIUMFULL);
  1001. }
  1002. // SetEndOfFile
  1003. if (SetEndOfFile (m_hFile) == FALSE)
  1004. {
  1005. AssertSz(FALSE, "SetEndOfFile failed");
  1006. return TrapError(STG_E_MEDIUMFULL);
  1007. }
  1008. // if the original position we less than the new size, return the file
  1009. // pointer to the original position
  1010. if (dwOrig < uli.LowPart)
  1011. {
  1012. if (SetFilePointer (m_hFile, dwOrig, NULL, FILE_BEGIN) == 0xFFFFFFFF)
  1013. {
  1014. AssertSz(FALSE, "SetFilePointer failed");
  1015. return TrapError(STG_E_MEDIUMFULL);
  1016. }
  1017. }
  1018. // Done
  1019. return S_OK;
  1020. }
  1021. // --------------------------------------------------------------------------------
  1022. // CFileStream::CopyTo
  1023. // This needs to be written better, but for now it's no worse that what a
  1024. // client would do
  1025. // --------------------------------------------------------------------------------
  1026. STDMETHODIMP CFileStream::CopyTo (LPSTREAM pstmDst,
  1027. ULARGE_INTEGER uli,
  1028. ULARGE_INTEGER* puliRead,
  1029. ULARGE_INTEGER* puliWritten)
  1030. {
  1031. ULONG cbBuf;
  1032. ULONG cbCopy;
  1033. VOID * pvBuf = 0;
  1034. BYTE rgBuf[STMTRNSIZE];
  1035. ULONG cbRemain;
  1036. ULONG cbReadTot = 0;
  1037. ULONG cbWriteTot = 0;
  1038. HRESULT hr = 0;
  1039. if (uli.HighPart)
  1040. cbRemain = 0xFFFFFFFF;
  1041. else
  1042. cbRemain = uli.LowPart;
  1043. // Attempt to allocate a buffer
  1044. cbBuf = (UINT)cbRemain;
  1045. if (cbBuf > STMTRNSIZE)
  1046. cbBuf = STMTRNSIZE;
  1047. // Copy the data one buffer at a time
  1048. while (cbRemain > 0)
  1049. {
  1050. // Compute maximum bytes to copy this time
  1051. cbCopy = cbRemain;
  1052. if (cbCopy > cbBuf)
  1053. cbCopy = cbBuf;
  1054. // Read into the buffer
  1055. hr = Read (rgBuf, cbCopy, &cbCopy);
  1056. if (FAILED(hr))
  1057. goto err;
  1058. if (cbCopy == 0)
  1059. break;
  1060. cbReadTot += cbCopy;
  1061. cbRemain -= cbCopy;
  1062. // Write buffer into the destination stream
  1063. {
  1064. ULONG cbWrite = cbCopy;
  1065. while (cbWrite)
  1066. {
  1067. hr = pstmDst->Write(rgBuf, cbWrite, &cbCopy);
  1068. if (FAILED(hr))
  1069. goto err;
  1070. cbWriteTot += cbCopy;
  1071. cbWrite -= cbCopy;
  1072. if (cbCopy == 0)
  1073. break;
  1074. }
  1075. }
  1076. }
  1077. err:
  1078. if (puliRead)
  1079. {
  1080. puliRead->HighPart = 0;
  1081. puliRead->LowPart = cbReadTot;
  1082. }
  1083. if (puliWritten)
  1084. {
  1085. puliWritten->HighPart = 0;
  1086. puliWritten->LowPart = cbWriteTot;
  1087. }
  1088. return (hr);
  1089. }
  1090. // --------------------------------------------------------------------------------
  1091. // CFileStream::Revert
  1092. // --------------------------------------------------------------------------------
  1093. STDMETHODIMP CFileStream::Revert ()
  1094. {
  1095. return E_NOTIMPL;
  1096. }
  1097. // --------------------------------------------------------------------------------
  1098. // CFileStream::LockRegion
  1099. // --------------------------------------------------------------------------------
  1100. STDMETHODIMP CFileStream::LockRegion (ULARGE_INTEGER, ULARGE_INTEGER,DWORD)
  1101. {
  1102. return E_NOTIMPL;
  1103. }
  1104. // --------------------------------------------------------------------------------
  1105. // CFileStream::UnlockRegion
  1106. // --------------------------------------------------------------------------------
  1107. STDMETHODIMP CFileStream::UnlockRegion (ULARGE_INTEGER, ULARGE_INTEGER, DWORD)
  1108. {
  1109. return E_NOTIMPL;
  1110. }
  1111. // --------------------------------------------------------------------------------
  1112. // CFileStream::Stat
  1113. // --------------------------------------------------------------------------------
  1114. STDMETHODIMP CFileStream::Stat (STATSTG*, DWORD)
  1115. {
  1116. return E_NOTIMPL;
  1117. }
  1118. // --------------------------------------------------------------------------------
  1119. // CFileStream::Clone
  1120. // --------------------------------------------------------------------------------
  1121. STDMETHODIMP CFileStream::Clone (LPSTREAM*)
  1122. {
  1123. return E_NOTIMPL;
  1124. }
  1125. DWORD RemoveCRLF(LPSTR pszT, DWORD cbT, BOOL * pfBadDBCS)
  1126. {
  1127. DWORD i = 0;
  1128. *pfBadDBCS = FALSE;
  1129. while (i < cbT)
  1130. {
  1131. if (IsDBCSLeadByte(pszT[i]))
  1132. {
  1133. if ((i + 1) >= cbT)
  1134. {
  1135. cbT--;
  1136. *pfBadDBCS = TRUE;
  1137. break;
  1138. }
  1139. i += 2;
  1140. }
  1141. else if ('\n' == pszT[i] || '\r' == pszT[i])
  1142. {
  1143. MoveMemory(pszT + i, pszT + (i + 1), cbT - i);
  1144. cbT--;
  1145. }
  1146. else
  1147. {
  1148. i++;
  1149. }
  1150. }
  1151. return cbT;
  1152. }
  1153. #define CB_STREAMMATCH 0x00000FFF
  1154. // --------------------------------------------------------------------------------
  1155. // StreamSubStringMatch
  1156. // --------------------------------------------------------------------------------
  1157. OESTDAPI_(BOOL) StreamSubStringMatch(LPSTREAM pstm, CHAR * pszSearch)
  1158. {
  1159. BOOL fRet = FALSE;
  1160. ULONG cbSave = 0;
  1161. LONG cbSize = 0;
  1162. CHAR rgchBuff[CB_STREAMMATCH + 1];
  1163. LPSTR pszRead = NULL;
  1164. ULONG cbRead = 0;
  1165. ULONG cbIn = 0;
  1166. BOOL fBadDBCS = FALSE;
  1167. CHAR chSave = 0;
  1168. // Check incoming params
  1169. if ((NULL == pstm) || (NULL == pszSearch))
  1170. {
  1171. goto exit;
  1172. }
  1173. // We want to save off the entire string and
  1174. // a possible ending lead byte...
  1175. cbSave = lstrlen(pszSearch);
  1176. // Get the stream size
  1177. if (FAILED(HrGetStreamSize(pstm, (ULONG *) &cbSize)))
  1178. {
  1179. goto exit;
  1180. }
  1181. // Reset the stream to the beginning
  1182. if (FAILED(HrRewindStream(pstm)))
  1183. {
  1184. goto exit;
  1185. }
  1186. // Set up the defaults
  1187. pszRead = rgchBuff;
  1188. cbRead = CB_STREAMMATCH;
  1189. // Search for string through the entire stream
  1190. while ((cbSize > 0) && (S_OK == pstm->Read(pszRead, cbRead, &cbIn)))
  1191. {
  1192. // We're done if we read nothing...
  1193. if (0 == cbIn)
  1194. {
  1195. goto exit;
  1196. }
  1197. // Note that we've read the bytes
  1198. cbSize -= cbIn;
  1199. // Raid 2741: FIND: OE: FE: Find Text/Message to be able to find wrapped DBCS words in plain text message body
  1200. cbIn = RemoveCRLF(rgchBuff, (DWORD) (cbIn + pszRead - rgchBuff), &fBadDBCS);
  1201. // Do we need to save the char
  1202. if (FALSE != fBadDBCS)
  1203. {
  1204. chSave = rgchBuff[cbIn];
  1205. }
  1206. // Terminate the buffer
  1207. rgchBuff[cbIn] = '\0';
  1208. // Search for string
  1209. if (NULL != StrStrIA(rgchBuff, pszSearch))
  1210. {
  1211. fRet = TRUE;
  1212. break;
  1213. }
  1214. // Are we done with the stream
  1215. if (0 >= cbSize)
  1216. {
  1217. break;
  1218. }
  1219. // Do we need to restore the char
  1220. if (FALSE != fBadDBCS)
  1221. {
  1222. rgchBuff[cbIn] = chSave;
  1223. cbIn++;
  1224. }
  1225. // Save part of the buffer
  1226. // How much space do we have in the buffer
  1227. cbRead = CB_STREAMMATCH - cbSave;
  1228. // Save the characters
  1229. MoveMemory(rgchBuff, rgchBuff + cbIn - cbSave, cbSave);
  1230. // Figure out the new start of the buffer
  1231. pszRead = rgchBuff + cbSave;
  1232. }
  1233. exit:
  1234. return(fRet);
  1235. }