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.

670 lines
17 KiB

  1. // convert.cpp : implementation file
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12. #include "stdafx.h"
  13. #include "wordpad.h"
  14. #include "multconv.h"
  15. #include "mswd6_32.h"
  16. #ifdef _DEBUG
  17. #undef THIS_FILE
  18. static char BASED_CODE THIS_FILE[] = __FILE__;
  19. #endif
  20. #ifdef CONVERTERS
  21. CConverter* CConverter::m_pThis = NULL;
  22. #endif
  23. #define BUFFSIZE 4096
  24. CTrackFile::CTrackFile(CFrameWnd* pWnd) : CFile()
  25. {
  26. m_nLastPercent = -1;
  27. m_dwLength = 0;
  28. m_pFrameWnd = pWnd;
  29. VERIFY(m_strComplete.LoadString(IDS_COMPLETE));
  30. VERIFY(m_strWait.LoadString(IDS_PLEASE_WAIT));
  31. VERIFY(m_strSaving.LoadString(IDS_SAVING));
  32. // OutputPercent(0);
  33. }
  34. CTrackFile::~CTrackFile()
  35. {
  36. OutputPercent(100);
  37. if (m_pFrameWnd != NULL)
  38. m_pFrameWnd->SetMessageText(AFX_IDS_IDLEMESSAGE);
  39. }
  40. UINT CTrackFile::Read(void FAR* lpBuf, UINT nCount)
  41. {
  42. UINT n = CFile::Read(lpBuf, nCount);
  43. if (m_dwLength != 0)
  44. OutputPercent((int)((GetPosition()*100)/m_dwLength));
  45. return n;
  46. }
  47. void CTrackFile::Write(const void FAR* lpBuf, UINT nCount)
  48. {
  49. CFile::Write(lpBuf, nCount);
  50. OutputString(m_strSaving);
  51. // if (m_dwLength != 0)
  52. // OutputPercent((int)((GetPosition()*100)/m_dwLength));
  53. }
  54. void CTrackFile::OutputString(LPCTSTR lpsz)
  55. {
  56. if (m_pFrameWnd != NULL)
  57. {
  58. m_pFrameWnd->SetMessageText(lpsz);
  59. CWnd* pBarWnd = m_pFrameWnd->GetMessageBar();
  60. if (pBarWnd != NULL)
  61. pBarWnd->UpdateWindow();
  62. }
  63. }
  64. void CTrackFile::OutputPercent(int nPercentComplete)
  65. {
  66. if (m_pFrameWnd != NULL && m_nLastPercent != nPercentComplete)
  67. {
  68. m_nLastPercent = nPercentComplete;
  69. TCHAR buf[64];
  70. int n = nPercentComplete;
  71. if (SUCCEEDED(StringCchPrintf(buf, ARRAYSIZE(buf), (n==100) ? m_strWait : m_strComplete, n)))
  72. {
  73. OutputString(buf);
  74. }
  75. }
  76. }
  77. COEMFile::COEMFile(CFrameWnd* pWnd) : CTrackFile(pWnd)
  78. {
  79. }
  80. UINT COEMFile::Read(void FAR* lpBuf, UINT nCount)
  81. {
  82. UINT n = CTrackFile::Read(lpBuf, nCount);
  83. OemToCharBuffA((const char*)lpBuf, (char*)lpBuf, n);
  84. return n;
  85. }
  86. void COEMFile::Write(const void FAR* lpBuf, UINT nCount)
  87. {
  88. CharToOemBuffA((const char*)lpBuf, (char*)lpBuf, nCount);
  89. CTrackFile::Write(lpBuf, nCount);
  90. }
  91. #ifdef CONVERTERS
  92. HGLOBAL CConverter::StringToHGLOBAL(LPCSTR pstr)
  93. {
  94. HGLOBAL hMem = NULL;
  95. if (pstr != NULL)
  96. {
  97. size_t cch = (lstrlenA(pstr)*2) + 1; // Why are we allocating this much?
  98. hMem = GlobalAlloc(GHND, cch);
  99. if (NULL == hMem)
  100. AfxThrowMemoryException();
  101. char* p = (char*) GlobalLock(hMem);
  102. if (p != NULL)
  103. EVAL(StringCchCopyA(p, cch, pstr) == S_OK);
  104. GlobalUnlock(hMem);
  105. }
  106. return hMem;
  107. }
  108. CConverter::CConverter(LPCTSTR pszLibName, CFrameWnd* pWnd) : CTrackFile(pWnd)
  109. {
  110. USES_CONVERSION;
  111. m_hBuff = NULL;
  112. m_pBuf = NULL;
  113. m_nBytesAvail = 0;
  114. m_nBytesWritten = 0;
  115. m_nPercent = 0;
  116. m_hEventFile = NULL;
  117. m_hEventConv = NULL;
  118. m_bDone = TRUE;
  119. m_bConvErr = FALSE;
  120. m_hFileName = NULL;
  121. m_bUseOEM = TRUE;
  122. #ifndef _X86_
  123. //Prevent known alignment exception problems in write converter
  124. //from crashing the app on some RISC machines
  125. m_uPrevErrMode = SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);
  126. #endif
  127. // Safe to call LoadLibrary - this should be a fully-qualified pathname.
  128. m_hLibCnv = LoadLibrary(pszLibName);
  129. if (NULL != m_hLibCnv)
  130. {
  131. LoadFunctions();
  132. ASSERT(m_pInitConverter != NULL);
  133. if (m_pInitConverter != NULL)
  134. {
  135. //
  136. // For the current converters, you have to pass a *static*
  137. // string to InitConverter32
  138. //
  139. VERIFY(m_pInitConverter(AfxGetMainWnd()->GetSafeHwnd(), "WORDPAD"));
  140. }
  141. if (m_pRegisterApp != NULL)
  142. {
  143. NegotiateForNonOEM();
  144. }
  145. }
  146. }
  147. CConverter::~CConverter()
  148. {
  149. if (!m_bDone) // converter thread hasn't exited
  150. {
  151. m_bDone = TRUE;
  152. if (!m_bForeignToRtf)
  153. WaitForConverter();
  154. m_nBytesAvail = 0;
  155. VERIFY(ResetEvent(m_hEventFile));
  156. m_nBytesAvail = 0;
  157. SetEvent(m_hEventConv);
  158. WaitForConverter();// wait for DoConversion exit
  159. VERIFY(ResetEvent(m_hEventFile));
  160. }
  161. if (m_hEventFile != NULL)
  162. VERIFY(CloseHandle(m_hEventFile));
  163. if (m_hEventConv != NULL)
  164. VERIFY(CloseHandle(m_hEventConv));
  165. if (m_hLibCnv != NULL)
  166. FreeLibrary(m_hLibCnv);
  167. if (m_hFileName != NULL)
  168. GlobalFree(m_hFileName);
  169. #ifndef _X86_
  170. //Reset error mode to what it was before we changed it in
  171. //the constructor
  172. SetErrorMode(m_uPrevErrMode);
  173. #endif
  174. }
  175. void CConverter::WaitForConverter()
  176. {
  177. // while event not signalled -- process messages
  178. while (MsgWaitForMultipleObjects(1, &m_hEventFile, FALSE, INFINITE,
  179. QS_SENDMESSAGE) != WAIT_OBJECT_0)
  180. {
  181. MSG msg;
  182. while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  183. {
  184. TranslateMessage(&msg);
  185. DispatchMessage(&msg);
  186. }
  187. }
  188. }
  189. void CConverter::WaitForBuffer()
  190. {
  191. // while event not signalled -- process messages
  192. while (MsgWaitForMultipleObjects(1, &m_hEventConv, FALSE, INFINITE,
  193. QS_SENDMESSAGE) != WAIT_OBJECT_0)
  194. {
  195. MSG msg;
  196. while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  197. {
  198. TranslateMessage(&msg);
  199. DispatchMessage(&msg);
  200. }
  201. }
  202. }
  203. UINT AFX_CDECL CConverter::ConverterThread(LPVOID) // AFX_CDECL added by t-stefb
  204. {
  205. ASSERT(m_pThis != NULL);
  206. #if defined(_DEBUG)
  207. HRESULT hRes = OleInitialize(NULL);
  208. ASSERT(hRes == S_OK || hRes == S_FALSE);
  209. #else
  210. OleInitialize(NULL);
  211. #endif
  212. m_pThis->DoConversion();
  213. OleUninitialize();
  214. return 0;
  215. }
  216. BOOL CConverter::IsFormatCorrect(LPCWSTR pszFileName)
  217. {
  218. BOOL bRet = FALSE;
  219. if (m_hLibCnv == NULL || m_pIsFormatCorrect == NULL)
  220. {
  221. bRet = FALSE;
  222. }
  223. else
  224. {
  225. char buf[_MAX_PATH];
  226. if (WideCharToMultiByte(CP_ACP, 0, pszFileName, -1, buf, ARRAYSIZE(buf), NULL, NULL))
  227. {
  228. if (m_bUseOEM)
  229. CharToOemA(buf, buf);
  230. HGLOBAL hFileName = StringToHGLOBAL(buf);
  231. HGLOBAL hDesc = GlobalAlloc(GHND, 256);
  232. if (NULL == hDesc)
  233. AfxThrowMemoryException();
  234. int nRet = m_pIsFormatCorrect(hFileName, hDesc);
  235. GlobalFree(hDesc);
  236. GlobalFree(hFileName);
  237. bRet = (nRet == 1) ? TRUE : FALSE;
  238. }
  239. else
  240. {
  241. bRet = FALSE;
  242. }
  243. }
  244. return bRet;
  245. }
  246. // static callback function
  247. int CALLBACK CConverter::WriteOutStatic(int cch, int nPercentComplete)
  248. {
  249. ASSERT(m_pThis != NULL);
  250. return m_pThis->WriteOut(cch, nPercentComplete);
  251. }
  252. int CALLBACK CConverter::WriteOut(int cch, int nPercentComplete)
  253. {
  254. ASSERT(m_hBuff != NULL);
  255. m_nPercent = nPercentComplete;
  256. if (m_hBuff == NULL)
  257. return -9;
  258. //
  259. // If m_bDone is TRUE that means the richedit control has stopped
  260. // streaming in text and is trying to destroy the CConverter object but
  261. // the converter still has more data to give
  262. //
  263. if (m_bDone)
  264. {
  265. ASSERT(!"Richedit control stopped streaming prematurely");
  266. AfxMessageBox(IDS_CONVERTER_ABORTED);
  267. return -9;
  268. }
  269. if (cch != 0)
  270. {
  271. WaitForBuffer();
  272. VERIFY(ResetEvent(m_hEventConv));
  273. m_nBytesAvail = cch;
  274. SetEvent(m_hEventFile);
  275. WaitForBuffer();
  276. }
  277. return 0; //everything OK
  278. }
  279. int CALLBACK CConverter::ReadInStatic(int /*flags*/, int nPercentComplete)
  280. {
  281. ASSERT(m_pThis != NULL);
  282. return m_pThis->ReadIn(nPercentComplete);
  283. }
  284. int CALLBACK CConverter::ReadIn(int /*nPercentComplete*/)
  285. {
  286. ASSERT(m_hBuff != NULL);
  287. if (m_hBuff == NULL)
  288. return -8;
  289. SetEvent(m_hEventFile);
  290. WaitForBuffer();
  291. VERIFY(ResetEvent(m_hEventConv));
  292. return m_nBytesAvail;
  293. }
  294. BOOL CConverter::DoConversion()
  295. {
  296. USES_CONVERSION;
  297. m_nLastPercent = -1;
  298. // m_dwLength = 0; // prevent Read/Write from displaying
  299. m_nPercent = 0;
  300. ASSERT(m_hBuff != NULL);
  301. ASSERT(m_pThis != NULL);
  302. HGLOBAL hDesc = StringToHGLOBAL("");
  303. HGLOBAL hSubset = StringToHGLOBAL("");
  304. int nRet = -1;
  305. if (m_bForeignToRtf && NULL != m_pForeignToRtf)
  306. {
  307. ASSERT(m_pForeignToRtf != NULL);
  308. ASSERT(m_hFileName != NULL);
  309. nRet = m_pForeignToRtf(m_hFileName, NULL, m_hBuff, hDesc, hSubset,
  310. (LPFNOUT)WriteOutStatic);
  311. // wait for next CConverter::Read to come through
  312. WaitForBuffer();
  313. VERIFY(ResetEvent(m_hEventConv));
  314. }
  315. else if (!m_bForeignToRtf && NULL != m_pRtfToForeign)
  316. {
  317. ASSERT(m_pRtfToForeign != NULL);
  318. ASSERT(m_hFileName != NULL);
  319. nRet = m_pRtfToForeign(m_hFileName, NULL, m_hBuff, hDesc,
  320. (LPFNIN)ReadInStatic);
  321. // don't need to wait for m_hEventConv
  322. }
  323. GlobalFree(hDesc);
  324. GlobalFree(hSubset);
  325. if (m_pBuf != NULL)
  326. GlobalUnlock(m_hBuff);
  327. GlobalFree(m_hBuff);
  328. if (nRet != 0)
  329. m_bConvErr = TRUE;
  330. m_bDone = TRUE;
  331. m_nPercent = 100;
  332. m_nLastPercent = -1;
  333. SetEvent(m_hEventFile);
  334. return (nRet == 0);
  335. }
  336. void CConverter::LoadFunctions()
  337. {
  338. m_pInitConverter = (PINITCONVERTER)GetProcAddress(m_hLibCnv, "InitConverter32");
  339. m_pIsFormatCorrect = (PISFORMATCORRECT)GetProcAddress(m_hLibCnv, "IsFormatCorrect32");
  340. m_pForeignToRtf = (PFOREIGNTORTF)GetProcAddress(m_hLibCnv, "ForeignToRtf32");
  341. m_pRtfToForeign = (PRTFTOFOREIGN)GetProcAddress(m_hLibCnv, "RtfToForeign32");
  342. m_pRegisterApp = (PREGISTERAPP) GetProcAddress(m_hLibCnv, "RegisterApp");
  343. }
  344. #endif // #ifdef CONVERTERS
  345. ///////////////////////////////////////////////////////////////////////////////
  346. BOOL CConverter::Open(LPCWSTR pszFileName, UINT nOpenFlags,
  347. CFileException* pException)
  348. {
  349. USES_CONVERSION;
  350. BOOL bRet;
  351. // The converters only speak ansi
  352. char buf[_MAX_PATH];
  353. if (WideCharToMultiByte(CP_ACP, 0, pszFileName, -1, buf, ARRAYSIZE(buf), NULL, NULL))
  354. {
  355. if (m_bUseOEM)
  356. CharToOemA(buf, buf);
  357. // let's make sure we could do what is wanted directly even though we aren't
  358. m_bCloseOnDelete = FALSE;
  359. m_hFile = (UINT_PTR)hFileNull;
  360. BOOL bOpen = CFile::Open(pszFileName, nOpenFlags, pException);
  361. CFile::Close();
  362. if (!bOpen)
  363. return FALSE;
  364. m_bForeignToRtf = !(nOpenFlags & (CFile::modeReadWrite | CFile::modeWrite));
  365. // check for reading empty file
  366. if (m_bForeignToRtf)
  367. {
  368. CFileStatus _stat;
  369. if (CFile::GetStatus(pszFileName, _stat) && _stat.m_size == 0)
  370. return TRUE;
  371. }
  372. //create the events
  373. m_hEventFile = CreateEvent(NULL, TRUE, FALSE, NULL);
  374. m_hEventConv = CreateEvent(NULL, TRUE, FALSE, NULL);
  375. //create the converter thread and create the events
  376. ASSERT(m_hFileName == NULL);
  377. m_hFileName = StringToHGLOBAL(buf);
  378. m_pThis = this;
  379. m_bDone = FALSE;
  380. m_hBuff = GlobalAlloc(GHND, BUFFSIZE);
  381. ASSERT(m_hBuff != NULL);
  382. AfxBeginThread(ConverterThread, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
  383. bRet = TRUE;
  384. }
  385. else
  386. {
  387. bRet = FALSE;
  388. }
  389. return bRet;
  390. }
  391. // m_hEventConv -- the main thread signals this event when ready for more data
  392. // m_hEventFile -- the converter signals this event when data is ready
  393. UINT CConverter::Read(void FAR* lpBuf, UINT nCount)
  394. {
  395. ASSERT(m_bForeignToRtf);
  396. if (m_bDone)
  397. return 0;
  398. // if converter is done
  399. int cch = nCount;
  400. BYTE* pBuf = (BYTE*)lpBuf;
  401. while (cch != 0)
  402. {
  403. if (m_nBytesAvail == 0)
  404. {
  405. if (m_pBuf != NULL)
  406. GlobalUnlock(m_hBuff);
  407. m_pBuf = NULL;
  408. SetEvent(m_hEventConv);
  409. WaitForConverter();
  410. VERIFY(ResetEvent(m_hEventFile));
  411. if (m_bConvErr)
  412. AfxThrowFileException(CFileException::generic);
  413. if (m_bDone)
  414. return nCount - cch;
  415. m_pBuf = (BYTE*)GlobalLock(m_hBuff);
  416. ASSERT(m_pBuf != NULL);
  417. }
  418. int nBytes = min(cch, m_nBytesAvail);
  419. memcpy(pBuf, m_pBuf, nBytes);
  420. pBuf += nBytes;
  421. m_pBuf += nBytes;
  422. m_nBytesAvail -= nBytes;
  423. cch -= nBytes;
  424. OutputPercent(m_nPercent);
  425. }
  426. return nCount - cch;
  427. }
  428. void CConverter::Write(const void FAR* lpBuf, UINT nCount)
  429. {
  430. ASSERT(!m_bForeignToRtf);
  431. m_nBytesWritten += nCount;
  432. while (nCount != 0)
  433. {
  434. WaitForConverter();
  435. VERIFY(ResetEvent(m_hEventFile));
  436. if (m_bConvErr)
  437. AfxThrowFileException(CFileException::generic);
  438. m_nBytesAvail = min(nCount, BUFFSIZE);
  439. nCount -= m_nBytesAvail;
  440. BYTE* pBuf = (BYTE*)GlobalLock(m_hBuff);
  441. ASSERT(pBuf != NULL);
  442. memcpy(pBuf, lpBuf, m_nBytesAvail);
  443. GlobalUnlock(m_hBuff);
  444. SetEvent(m_hEventConv);
  445. }
  446. OutputString(m_strSaving);
  447. }
  448. LONG CConverter::Seek(LONG lOff, UINT nFrom)
  449. {
  450. if (lOff != 0 && nFrom != current)
  451. AfxThrowNotSupportedException();
  452. return 0;
  453. }
  454. DWORD CConverter::GetPosition() const
  455. {
  456. return 0;
  457. }
  458. void CConverter::Flush()
  459. {
  460. }
  461. void CConverter::Close()
  462. {
  463. if (!m_bDone) // converter thread hasn't exited
  464. {
  465. m_bDone = TRUE;
  466. if (!m_bForeignToRtf)
  467. WaitForConverter();
  468. m_nBytesAvail = 0;
  469. VERIFY(ResetEvent(m_hEventFile));
  470. m_nBytesAvail = 0;
  471. SetEvent(m_hEventConv);
  472. WaitForConverter();// wait for DoConversion exit
  473. VERIFY(ResetEvent(m_hEventFile));
  474. }
  475. if (m_bConvErr)
  476. AfxThrowFileException(CFileException::generic);
  477. }
  478. void CConverter::Abort()
  479. {
  480. }
  481. DWORD CConverter::GetLength() const
  482. {
  483. ASSERT_VALID(this);
  484. return 1;
  485. }
  486. CFile* CConverter::Duplicate() const
  487. {
  488. AfxThrowNotSupportedException();
  489. return NULL;
  490. }
  491. void CConverter::LockRange(DWORD, DWORD)
  492. {
  493. AfxThrowNotSupportedException();
  494. }
  495. void CConverter::UnlockRange(DWORD, DWORD)
  496. {
  497. AfxThrowNotSupportedException();
  498. }
  499. void CConverter::SetLength(DWORD)
  500. {
  501. AfxThrowNotSupportedException();
  502. }
  503. //+--------------------------------------------------------------------------
  504. //
  505. // Method: CConverter::NegotiateForNonOEM
  506. //
  507. // Synopsis: Try to tell the converter not to expect OEM filenames
  508. //
  509. // Parameters: None
  510. //
  511. // Returns: void
  512. //
  513. // Notes: The converter's RegisterApp function will return a handle
  514. // containing it's preferences (what it supports). The
  515. // data structure is a 16-bit size and then a sequence of
  516. // records. For each record the first byte is the size, the
  517. // second is the "opcode", and then some variable-length opcode
  518. // specific data. All sizes are inclusive.
  519. //
  520. //---------------------------------------------------------------------------
  521. void CConverter::NegotiateForNonOEM()
  522. {
  523. ASSERT(NULL != m_pRegisterApp);
  524. HGLOBAL hPrefs;
  525. BYTE *pPrefs;
  526. __int16 cbPrefs;
  527. //
  528. // Tell the converter we don't want to use OEM
  529. //
  530. hPrefs = (*m_pRegisterApp)(fRegAppSupportNonOem, NULL);
  531. if (NULL == hPrefs)
  532. return;
  533. pPrefs = (BYTE *) GlobalLock(hPrefs);
  534. if (NULL == pPrefs)
  535. {
  536. ASSERT(!"GlobalLock failed");
  537. GlobalFree(hPrefs);
  538. return;
  539. }
  540. //
  541. // Parse the returned structure looking for a RegAppOpcodeCharset opcode.
  542. // The argument for this opcode should be either ANSI_CHARSET or
  543. // OEM_CHARSET. If its ANSI_CHARSET then we can talk Ansi otherwise were
  544. // stuck with OEM.
  545. //
  546. cbPrefs = (__int16) ((* (__int16 *) pPrefs) - sizeof(cbPrefs));
  547. pPrefs += sizeof(cbPrefs);
  548. while (cbPrefs > 0)
  549. {
  550. if (RegAppOpcodeCharset == pPrefs[1])
  551. {
  552. ASSERT(ANSI_CHARSET == pPrefs[2] || OEM_CHARSET == pPrefs[2]);
  553. m_bUseOEM = (OEM_CHARSET == pPrefs[2]);
  554. break;
  555. }
  556. else
  557. {
  558. if (pPrefs[0] <= 0)
  559. {
  560. ASSERT(!"RegisterApp is returning bogus data");
  561. break;
  562. }
  563. cbPrefs = (__int16) (cbPrefs - pPrefs[0]);
  564. pPrefs += pPrefs[0];
  565. }
  566. }
  567. GlobalUnlock(pPrefs);
  568. GlobalFree(hPrefs);
  569. }