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.

1080 lines
29 KiB

  1. /*
  2. * npfile.c - Routines for file i/o for notepad
  3. * Copyright (C) 1984-2000 Microsoft Corporation
  4. */
  5. #include "precomp.h"
  6. HANDLE hFirstMem;
  7. const CHAR BOM_UTF8[3] = {(BYTE) 0xEF, (BYTE) 0xBB, (BYTE)0xBF};
  8. //****************************************************************
  9. //
  10. // ReverseEndian
  11. //
  12. // Purpose: copies unicode character from one endian source
  13. // to another.
  14. //
  15. // may work on lpDst == lpSrc
  16. //
  17. VOID ReverseEndian( PTCHAR lpDst, PTCHAR lpSrc, DWORD nChars )
  18. {
  19. DWORD cnt;
  20. for( cnt=0; cnt < nChars; cnt++,lpDst++,lpSrc++ )
  21. {
  22. *lpDst= (TCHAR) (((*lpSrc<<8) & 0xFF00) + ((*lpSrc>>8)&0xFF));
  23. }
  24. }
  25. //*****************************************************************
  26. //
  27. // AnsiWriteFile()
  28. //
  29. // Purpose : To simulate the effects of _lwrite() in a Unicode
  30. // environment by converting to ANSI buffer and
  31. // writing out the ANSI text.
  32. // Returns : TRUE is successful, FALSE if not
  33. // GetLastError() will have the error code.
  34. //
  35. //*****************************************************************
  36. BOOL AnsiWriteFile(HANDLE hFile, // file to write to
  37. UINT uCodePage, // code page to convert unicode to
  38. LPVOID lpBuffer, // unicode buffer
  39. DWORD nChars, // number of unicode chars
  40. DWORD nBytes ) // number of ascii chars to produce
  41. {
  42. LPSTR lpAnsi; // pointer to allocate buffer
  43. BOOL Done; // status from write (returned)
  44. DWORD nBytesWritten; // number of bytes written
  45. lpAnsi= (LPSTR) LocalAlloc( LPTR, nBytes + 1 );
  46. if( !lpAnsi )
  47. {
  48. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  49. return (FALSE);
  50. }
  51. ConvertFromUnicode(uCodePage, // code page
  52. g_fSaveEntity, // fNoBestFit
  53. g_fSaveEntity, // fWriteEntities
  54. (LPWSTR) lpBuffer, // wide char buffer
  55. nChars, // chars in wide char buffer
  56. lpAnsi, // resultant ascii string
  57. nBytes, // size of ascii string buffer
  58. NULL); // flag to set if default char used
  59. Done = WriteFile(hFile, lpAnsi, nBytes, &nBytesWritten, NULL);
  60. LocalFree(lpAnsi);
  61. return(Done);
  62. } // end of AnsiWriteFile()
  63. // Routines to deal with the soft EOL formatting.
  64. //
  65. // MLE Actually inserts characters into the text being under edit, so they
  66. // have to be removed before saving the file.
  67. //
  68. // It turns out that MLE will get confused if the current line is bigger than
  69. // the current file, so we will reset the cursor to 0,0 to keep it from looking stupid.
  70. // Should be fixed in MLE, but...
  71. //
  72. VOID ClearFmt(VOID)
  73. {
  74. if( fWrap )
  75. {
  76. GotoAndScrollInView( 1 );
  77. SendMessage( hwndEdit, EM_FMTLINES, (WPARAM)FALSE, 0 );// remove soft EOLs
  78. }
  79. }
  80. VOID RestoreFmt(VOID)
  81. {
  82. if( fWrap )
  83. {
  84. NpReCreate( ES_STD ); // slow but it works
  85. }
  86. }
  87. BOOL FDetectEncodingW(LPCTSTR szFile, LPCWSTR rgch, UINT cch, UINT *pcp)
  88. {
  89. TCHAR szExt[_MAX_EXT];
  90. if (FDetectXmlEncodingW(rgch, cch, pcp))
  91. {
  92. // We recognized this as an XML file with a valid encoding
  93. return TRUE;
  94. }
  95. if (FDetectHtmlEncodingW(rgch, cch, pcp))
  96. {
  97. // We recognized this as an HTML file with a valid encoding
  98. return TRUE;
  99. }
  100. _wsplitpath(szFile, NULL, NULL, NULL, szExt);
  101. if (lstrcmpi(szExt, TEXT(".css")) == 0)
  102. {
  103. if (FDetectCssEncodingW(rgch, cch, pcp))
  104. {
  105. // We recognized this as CSS file with a valid encoding
  106. return TRUE;
  107. }
  108. }
  109. return FALSE;
  110. }
  111. /* Save notepad file to disk. szFileSave points to filename. fSaveAs
  112. is TRUE iff we are being called from SaveAsDlgProc. This implies we must
  113. open file on current directory, whether or not it already exists there
  114. or somewhere else in our search path.
  115. Assumes that text exists within hwndEdit. 30 July 1991 Clark Cyr
  116. */
  117. BOOL SaveFile(HWND hwndParent, LPCTSTR szFile, BOOL fSaveAs)
  118. {
  119. LPTSTR lpch;
  120. UINT nChars;
  121. BOOL flag;
  122. BOOL fNew = FALSE;
  123. BOOL fSaveEntity;
  124. BOOL fDefCharUsed = FALSE;
  125. BOOL* pfDefCharUsed;
  126. static const WCHAR wchBOM = BYTE_ORDER_MARK;
  127. static const WCHAR wchRBOM = REVERSE_BYTE_ORDER_MARK;
  128. HLOCAL hEText; // handle to MLE text
  129. UINT cpDetected;
  130. DWORD nBytesWritten; // number of bytes written
  131. UINT cchMbcs; // length of equivalent MBCS file
  132. if (g_cpSave == CP_AUTO)
  133. {
  134. UINT cch;
  135. HANDLE hText;
  136. int id;
  137. g_cpSave = g_cpOpened;
  138. // Check for an HTML or XML file with a declared encoding
  139. // If one is found, suggest the declared encoding
  140. cch = (UINT) SendMessage(hwndEdit, WM_GETTEXTLENGTH, 0, 0);
  141. hText = (HANDLE) SendMessage(hwndEdit, EM_GETHANDLE, 0, 0);
  142. if (hText != NULL)
  143. {
  144. LPCTSTR rgwch = (LPTSTR) LocalLock(hText);
  145. if (rgwch != NULL)
  146. {
  147. if (FDetectEncodingW(szFile, rgwch, cch, &cpDetected))
  148. {
  149. // We detected an expected encoding for this file
  150. g_cpSave = cpDetected;
  151. }
  152. LocalUnlock(hText);
  153. }
  154. }
  155. id = (int) DialogBoxParam(hInstanceNP,
  156. MAKEINTRESOURCE(IDD_SELECT_ENCODING),
  157. hwndNP,
  158. SelectEncodingDlgProc,
  159. (LPARAM) &g_cpSave);
  160. if (id == IDCANCEL)
  161. {
  162. return(FALSE);
  163. }
  164. }
  165. /* If saving to an existing file, make sure correct disk is in drive */
  166. if (!fSaveAs)
  167. {
  168. fp = CreateFile(szFile, // name of file
  169. GENERIC_READ|GENERIC_WRITE, // access mode
  170. FILE_SHARE_READ, // share mode
  171. NULL, // security descriptor
  172. OPEN_EXISTING, // how to create
  173. FILE_ATTRIBUTE_NORMAL, // file attributes
  174. NULL); // hnd of file with attrs
  175. }
  176. else
  177. {
  178. // Carefully open the file. Do not truncate it if it exists.
  179. // set the fNew flag if it had to be created.
  180. // We do all this in case of failures later in the process.
  181. fp = CreateFile(szFile, // name of file
  182. GENERIC_READ|GENERIC_WRITE, // access mode
  183. FILE_SHARE_READ|FILE_SHARE_WRITE, // share mode
  184. NULL, // security descriptor
  185. OPEN_ALWAYS, // how to create
  186. FILE_ATTRIBUTE_NORMAL, // file attributes
  187. NULL); // hnd of file with attrs
  188. if( fp != INVALID_HANDLE_VALUE )
  189. {
  190. fNew= (GetLastError() != ERROR_ALREADY_EXISTS );
  191. }
  192. }
  193. if( fp == INVALID_HANDLE_VALUE )
  194. {
  195. if (fSaveAs)
  196. AlertBox( hwndParent, szNN, szCREATEERR, szFile,
  197. MB_APPLMODAL | MB_OK | MB_ICONWARNING);
  198. return FALSE;
  199. }
  200. // if wordwrap, remove soft carriage returns
  201. // Also move the cursor to a safe place to get around MLE bugs
  202. ClearFmt();
  203. /* Must get text length after formatting */
  204. nChars = (UINT) SendMessage(hwndEdit, WM_GETTEXTLENGTH, 0, 0);
  205. hEText = (HANDLE) SendMessage(hwndEdit, EM_GETHANDLE, 0, 0);
  206. if ((hEText == NULL) || ((lpch = (LPTSTR) LocalLock(hEText)) == NULL))
  207. {
  208. goto FailFile;
  209. }
  210. Retry:
  211. // Determine the SaveAs file type, and write the appropriate BOM.
  212. // If the filetype is UTF-8 or Ansi, do the conversion.
  213. if (FDetectEncodingW(szFile, lpch, nChars, &cpDetected))
  214. {
  215. // We detected an expected encoding for this file
  216. if (g_cpSave != cpDetected)
  217. {
  218. int id;
  219. // Display a warning that encodings do not match
  220. id = MessageBox(hwndNP,
  221. szEncodingMismatch,
  222. szNN,
  223. MB_APPLMODAL | MB_YESNOCANCEL | MB_ICONWARNING);
  224. if (id == IDCANCEL)
  225. {
  226. goto CleanUp;
  227. }
  228. if (id == IDYES)
  229. {
  230. g_cpSave = cpDetected;
  231. }
  232. }
  233. }
  234. switch (g_cpSave)
  235. {
  236. case CP_UTF16 :
  237. if (g_wbSave != wbNo)
  238. {
  239. WriteFile(fp, &wchBOM, ByteCountOf(1), &nBytesWritten, NULL);
  240. }
  241. flag = WriteFile(fp, lpch, ByteCountOf(nChars), &nBytesWritten, NULL);
  242. break;
  243. case CP_UTF16BE :
  244. if (g_wbSave != wbNo)
  245. {
  246. WriteFile(fp, &wchRBOM, ByteCountOf(1), &nBytesWritten, NULL);
  247. }
  248. ReverseEndian(lpch, lpch, nChars);
  249. flag = WriteFile(fp, lpch, ByteCountOf(nChars), &nBytesWritten, NULL);
  250. ReverseEndian(lpch, lpch, nChars);
  251. break;
  252. case CP_UTF8 :
  253. // For UTF-8, write the BOM and continue to the default case.
  254. // For XML, do NOT write a BOM for wbDefault
  255. if ((g_wbSave == wbYes) || ((g_wbSave == wbDefault) && !FIsXmlW(lpch, nChars)))
  256. {
  257. WriteFile(fp, &BOM_UTF8, 3, &nBytesWritten, NULL);
  258. }
  259. // Fall through to convert and write the file
  260. default:
  261. fSaveEntity = g_fSaveEntity && FSupportWriteEntities(g_cpSave);
  262. pfDefCharUsed = NULL;
  263. if (!fSaveEntity && (g_cpSave != CP_UTF8))
  264. {
  265. pfDefCharUsed = &fDefCharUsed;
  266. }
  267. cchMbcs = ConvertFromUnicode(g_cpSave,
  268. TRUE,
  269. fSaveEntity,
  270. (LPWSTR) lpch,
  271. nChars,
  272. NULL,
  273. 0,
  274. pfDefCharUsed);
  275. if (fDefCharUsed)
  276. {
  277. int id = (int) DialogBox(hInstanceNP,
  278. MAKEINTRESOURCE(IDD_SAVE_UNICODE_DIALOG),
  279. hwndNP,
  280. SaveUnicodeDlgProc);
  281. switch (id)
  282. {
  283. case IDC_SAVE_AS_UNICODE :
  284. g_cpSave = CP_UTF16;
  285. goto Retry;
  286. case IDOK :
  287. // Continue.
  288. break;
  289. case IDCANCEL :
  290. goto CleanUp;
  291. }
  292. }
  293. if (pfDefCharUsed != NULL)
  294. {
  295. // We need to convert again because WideCharToMultiByte
  296. // sometimes fails with pfDefUsedChar != NULL.
  297. cchMbcs = ConvertFromUnicode(g_cpSave,
  298. fSaveEntity,
  299. fSaveEntity,
  300. (LPWSTR) lpch,
  301. nChars,
  302. NULL,
  303. 0,
  304. NULL);
  305. }
  306. flag = AnsiWriteFile(fp, g_cpSave, lpch, nChars, cchMbcs);
  307. break;
  308. }
  309. if (!flag)
  310. {
  311. SetCursor(hStdCursor); /* display normal cursor */
  312. FailFile:
  313. AlertUser_FileFail(szFile);
  314. CleanUp:
  315. SetCursor(hStdCursor);
  316. CloseHandle(fp); fp=INVALID_HANDLE_VALUE;
  317. if( hEText )
  318. LocalUnlock( hEText );
  319. if (fNew)
  320. DeleteFile(szFile);
  321. //
  322. // if wordwrap, insert soft carriage returns
  323. //
  324. RestoreFmt();
  325. return FALSE;
  326. }
  327. SetEndOfFile(fp);
  328. g_cpOpened = g_cpSave;
  329. g_wbOpened = g_wbSave;
  330. SendMessage(hwndEdit, EM_SETMODIFY, FALSE, 0L);
  331. SetFileName(szFile);
  332. CloseHandle(fp); fp=INVALID_HANDLE_VALUE;
  333. if( hEText )
  334. LocalUnlock( hEText );
  335. //
  336. // if wordwrap, insert soft carriage returns
  337. //
  338. RestoreFmt();
  339. // Display the normal cursor
  340. SetCursor(hStdCursor);
  341. return TRUE;
  342. } // end of SaveFile()
  343. /* Read contents of file from disk.
  344. * Do any conversions required.
  345. * File is already open, referenced by handle fp
  346. * Close the file when done.
  347. * If cpOpen != CP_AUTO, then use it as codepage, otherwise do automagic guessing.
  348. */
  349. BOOL LoadFile(LPCTSTR szFile, BOOL fSelectEncoding)
  350. {
  351. UINT len, i, nChars;
  352. LPTSTR lpch=NULL;
  353. LPTSTR lpBuf;
  354. LPSTR lpBufAfterBOM;
  355. UINT cpOpen;
  356. BOOL fLog=FALSE;
  357. TCHAR* p;
  358. BY_HANDLE_FILE_INFORMATION fiFileInfo;
  359. BOOL bStatus; // boolean status
  360. HLOCAL hNewEdit=NULL; // new handle for edit buffer
  361. HANDLE hMap; // file mapping handle
  362. TCHAR szNullFile[2]; // fake null mapped file
  363. if( fp == INVALID_HANDLE_VALUE )
  364. {
  365. AlertUser_FileFail( szFile );
  366. return (FALSE);
  367. }
  368. //
  369. // Get size of file
  370. // We use this heavy duty GetFileInformationByHandle API
  371. // because it finds bugs. It takes longer, but it only is
  372. // called at user interaction time.
  373. //
  374. bStatus= GetFileInformationByHandle( fp, &fiFileInfo );
  375. len= (UINT) fiFileInfo.nFileSizeLow;
  376. // NT may delay giving this status until the file is accessed.
  377. // i.e. the open succeeds, but operations may fail on damaged files.
  378. if( !bStatus )
  379. {
  380. AlertUser_FileFail( szFile );
  381. CloseHandle( fp ); fp=INVALID_HANDLE_VALUE;
  382. return( FALSE );
  383. }
  384. // If the file is too big, fail now.
  385. // -1 not valid because we need a zero on the end.
  386. //
  387. // bug# 168148: silently fails to open 2.4 gig text file on win64
  388. // Caused by trying to convert ascii file to unicode which overflowed
  389. // the dword length handled by multibytetowidechar conversion.
  390. // Since no one will be happy with the performance of the MLE with
  391. // a file this big, we will just refuse to open it now.
  392. //
  393. // For example, on a Pentium 173 MHz with 192 Megs o'RAM (Tecra 8000)
  394. // I got these results:
  395. //
  396. // size CPU-time
  397. // 0 .12
  398. // 1 .46
  399. // 2 .77
  400. // 3 1.041
  401. // 4 1.662
  402. // 5 2.092
  403. // 6 2.543
  404. // 7 3.023
  405. // 8 3.534
  406. // 9 4.084
  407. // 10 4.576
  408. // 16 8.371
  409. // 32 23.142
  410. // 64 74.426
  411. //
  412. // Curve fitting these numbers to cpu-time=a+b*size+c*size*size
  413. // we get a really good fit with cpu= .24+.28*size+.013*size*size
  414. //
  415. // For 1 gig, this works out to be 3.68 hours. 2 gigs=14.6 hours
  416. //
  417. // And the user isn't going to be happy with adding or deleting characters
  418. // with the MLE control. It wants to keep the memory stuctures uptodate
  419. // at all times.
  420. //
  421. // Going to richedit isn't a near term solution either:
  422. //
  423. // size CPU-time
  424. // 2 3.8
  425. // 4 9.0
  426. // 6 21.9
  427. // 8 30.4
  428. // 10 65.3
  429. // 16 1721 or >3.5 hours (it was still running when I killed it)
  430. //
  431. //
  432. // feature: should we only bail if not unicode?
  433. //
  434. if( len >=0x4000000 || fiFileInfo.nFileSizeHigh != 0 )
  435. {
  436. AlertBox( hwndNP, szNN, szErrSpace, szFile,
  437. MB_APPLMODAL | MB_OK | MB_ICONWARNING );
  438. CloseHandle (fp); fp=INVALID_HANDLE_VALUE;
  439. return (FALSE);
  440. }
  441. SetCursor(hWaitCursor); // physical I/O takes time
  442. //
  443. // Create a file mapping so we don't page the file to
  444. // the pagefile. This is a big win on small ram machines.
  445. //
  446. if( len != 0 )
  447. {
  448. lpBuf= NULL;
  449. hMap= CreateFileMapping( fp, NULL, PAGE_READONLY, 0, len, NULL );
  450. if( hMap )
  451. {
  452. lpBuf= MapViewOfFile( hMap, FILE_MAP_READ, 0,0,len);
  453. CloseHandle( hMap );
  454. }
  455. }
  456. else // file mapping doesn't work on zero length files
  457. {
  458. lpBuf= (LPTSTR) &szNullFile;
  459. *lpBuf= 0; // null terminate
  460. }
  461. CloseHandle( fp ); fp=INVALID_HANDLE_VALUE;
  462. if( lpBuf == NULL )
  463. {
  464. SetCursor( hStdCursor );
  465. //
  466. // bug# 192007: Opening migrated files with bad RSS gives bad error msg
  467. //
  468. // We used to just say 'out of memory', but that was wrong.
  469. // We will now give the standard OS error message.
  470. // If the user doesn't understand that, then FormatMessage s/b be fixed.
  471. //
  472. AlertUser_FileFail( szFile );
  473. return( FALSE );
  474. }
  475. //
  476. // protect access to the mapped file with a try/except so we
  477. // can detect I/O errors.
  478. //
  479. //
  480. // WARNING: be very very careful. This code is pretty fragile.
  481. // Files across the network, or RSM files (tape) may throw excepts
  482. // at random points in this code. Anywhere the code touches the
  483. // memory mapped file can cause an AV. Make sure variables are
  484. // in consistent state if an exception is thrown. Be very careful
  485. // with globals.
  486. __try
  487. {
  488. /* Determine the file type and number of characters
  489. * If the user overrides, use what is specified.
  490. * Otherwise, we depend on 'IsTextUnicode' getting it right.
  491. * If it doesn't, bug IsTextUnicode.
  492. */
  493. cpOpen = g_cpDefault;
  494. if (fSelectEncoding || (cpOpen == CP_AUTO))
  495. {
  496. switch (*lpBuf)
  497. {
  498. TCHAR szExt[_MAX_EXT];
  499. case BYTE_ORDER_MARK:
  500. cpOpen = CP_UTF16;
  501. break;
  502. case REVERSE_BYTE_ORDER_MARK:
  503. cpOpen = CP_UTF16BE;
  504. break;
  505. case BOM_UTF8_HALF:
  506. // UTF-8 BOM has 3 bytes; if it doesn't have UTF-8 BOM just fall through ..
  507. if ((len > 2) && (((BYTE *) lpBuf)[2] == BOM_UTF8_2HALF))
  508. {
  509. cpOpen = CP_UTF8;
  510. break;
  511. }
  512. // Fall through
  513. default:
  514. // Is the file Unicode without BOM ?
  515. if (IsInputTextUnicode((LPSTR) lpBuf, len))
  516. {
  517. cpOpen = CP_UTF16;
  518. break;
  519. }
  520. if (FDetectXmlEncodingA((LPSTR) lpBuf, len, &cpOpen))
  521. {
  522. // We recognized this as an XML file with a valid encoding
  523. break;
  524. }
  525. if (FDetectHtmlEncodingA((LPSTR) lpBuf, len, &cpOpen))
  526. {
  527. // We recognized this as an HTML file with a valid encoding
  528. break;
  529. }
  530. _wsplitpath(szFile, NULL, NULL, NULL, szExt);
  531. if (lstrcmpi(szExt, TEXT(".css")) == 0)
  532. {
  533. if (FDetectCssEncodingA((LPSTR) lpBuf, len, &cpOpen))
  534. {
  535. // We recognized this as an HTML file with a valid encoding
  536. break;
  537. }
  538. }
  539. // Is the file UTF-8 even though it doesn't have UTF-8 BOM.
  540. if (IsTextUTF8((LPSTR) lpBuf, len))
  541. {
  542. cpOpen = CP_UTF8;
  543. break;
  544. }
  545. // Well, assume default or ANSI if no default
  546. if (fSelectEncoding)
  547. {
  548. // Use MLANG to detect the encoding as default in Select Encoding dialog
  549. if (FDetectEncodingA((LPSTR) lpBuf, len, &cpOpen))
  550. {
  551. // We recognized this as an XML file with a valid encoding
  552. break;
  553. }
  554. }
  555. // Use default
  556. cpOpen = g_cpDefault;
  557. if (cpOpen == CP_AUTO)
  558. {
  559. cpOpen = g_cpANSI;
  560. }
  561. break;
  562. }
  563. }
  564. if (fSelectEncoding)
  565. {
  566. int id;
  567. id = (int) DialogBoxParam(hInstanceNP,
  568. MAKEINTRESOURCE(IDD_SELECT_ENCODING),
  569. hwndNP,
  570. SelectEncodingDlgProc,
  571. (LPARAM) &cpOpen);
  572. if (id == IDCANCEL)
  573. {
  574. if (lpBuf != (LPTSTR) &szNullFile)
  575. {
  576. UnmapViewOfFile(lpBuf);
  577. }
  578. return(FALSE);
  579. }
  580. }
  581. lpBufAfterBOM = (LPSTR) lpBuf;
  582. if (cpOpen == CP_UTF16)
  583. {
  584. if ((len >= sizeof(WCHAR)) && ((*(WCHAR *) lpBuf) == BYTE_ORDER_MARK))
  585. {
  586. // Skip the BOM
  587. lpBufAfterBOM = (LPSTR) lpBuf + sizeof(WCHAR);
  588. len -= sizeof(WCHAR);
  589. }
  590. }
  591. else if (cpOpen == CP_UTF16BE)
  592. {
  593. if ((len >= sizeof(WCHAR)) && ((*(WCHAR *) lpBuf) == REVERSE_BYTE_ORDER_MARK))
  594. {
  595. // Skip the BOM
  596. lpBufAfterBOM = (LPSTR) lpBuf + sizeof(WCHAR);
  597. len -= sizeof(WCHAR);
  598. }
  599. }
  600. else if (cpOpen == CP_UTF8)
  601. {
  602. if ((len >= 3) && ((*(WCHAR *) lpBuf) == BOM_UTF8_HALF) && (((BYTE *) lpBuf)[2] == BOM_UTF8_2HALF))
  603. {
  604. // Skip the BOM
  605. lpBufAfterBOM = (LPSTR) lpBuf + 3;
  606. len -= 3;
  607. }
  608. }
  609. // Find out no. of chars present in the string.
  610. if ((cpOpen == CP_UTF16) || (cpOpen == CP_UTF16BE))
  611. {
  612. nChars = len / sizeof(WCHAR);
  613. }
  614. else
  615. {
  616. nChars = ConvertToUnicode(cpOpen, (LPSTR) lpBufAfterBOM, len, NULL, 0);
  617. }
  618. //
  619. // Don't display text until all done.
  620. //
  621. SendMessage(hwndEdit, WM_SETREDRAW, FALSE, 0);
  622. // Reset selection to 0
  623. SendMessage(hwndEdit, EM_SETSEL, 0, 0L);
  624. SendMessage(hwndEdit, EM_SCROLLCARET, 0, 0);
  625. // resize the edit buffer
  626. // if we can't resize the memory, inform the user
  627. hNewEdit= LocalReAlloc(hEdit, ByteCountOf(nChars + 1), LMEM_MOVEABLE);
  628. if( !hNewEdit )
  629. {
  630. TCHAR szFileT[MAX_PATH]; /* Private copy of current filename */
  631. /* Bug 7441: New() modifies szFileOpened to which szFile may point.
  632. * Save a copy of the filename to pass to AlertBox.
  633. * 17 November 1991 Clark R. Cyr
  634. */
  635. lstrcpy(szFileT, szFile);
  636. New(FALSE);
  637. /* Display the hour glass cursor */
  638. SetCursor(hStdCursor);
  639. AlertBox( hwndNP, szNN, szFTL, szFileT,
  640. MB_APPLMODAL | MB_OK | MB_ICONWARNING);
  641. if( lpBuf != (LPTSTR) &szNullFile )
  642. {
  643. UnmapViewOfFile( lpBuf );
  644. }
  645. // let user see old text
  646. SendMessage(hwndEdit, WM_SETREDRAW, FALSE, 0);
  647. return FALSE;
  648. }
  649. /* Transfer file from temporary buffer to the edit buffer */
  650. lpch= (LPTSTR) LocalLock(hNewEdit);
  651. if (cpOpen == CP_UTF16)
  652. {
  653. CopyMemory(lpch, lpBufAfterBOM, ByteCountOf(nChars));
  654. }
  655. else if (cpOpen == CP_UTF16BE)
  656. {
  657. ReverseEndian(lpch, (LPTSTR) lpBufAfterBOM, nChars);
  658. }
  659. else
  660. {
  661. ConvertToUnicode(cpOpen, (LPSTR) lpBufAfterBOM, len, lpch, nChars);
  662. }
  663. // Got everything; update global safe now
  664. g_cpOpened = cpOpen;
  665. if ((cpOpen != CP_UTF16) && (cpOpen != CP_UTF16BE) && (cpOpen != CP_UTF8))
  666. {
  667. g_wbOpened = wbDefault;
  668. }
  669. else if (lpBufAfterBOM != (LPSTR) lpBuf)
  670. {
  671. g_wbOpened = wbYes;
  672. }
  673. else
  674. {
  675. g_wbOpened = wbNo;
  676. }
  677. }
  678. __except(EXCEPTION_EXECUTE_HANDLER)
  679. {
  680. AlertBox( hwndNP, szNN, szDiskError, szFile,
  681. MB_APPLMODAL | MB_OK | MB_ICONWARNING );
  682. nChars= 0; // don't deal with it.
  683. }
  684. /* Free file mapping */
  685. if( lpBuf != (LPTSTR) &szNullFile )
  686. {
  687. UnmapViewOfFile( lpBuf );
  688. }
  689. if( lpch )
  690. {
  691. // Fix any NUL character that came in from the file to be spaces.
  692. for (i = 0, p = lpch; i < nChars; i++, p++)
  693. {
  694. if( *p == (TCHAR) 0 )
  695. *p= TEXT(' ');
  696. }
  697. // null terminate it. Safe even if nChars==0 because it is 1 TCHAR bigger
  698. *(lpch+nChars)= (TCHAR) 0; /* zero terminate the thing */
  699. // Set 'fLog' if first characters in file are ".LOG"
  700. fLog= *lpch++ == TEXT('.') && *lpch++ == TEXT('L') &&
  701. *lpch++ == TEXT('O') && *lpch == TEXT('G');
  702. }
  703. if( hNewEdit )
  704. {
  705. LocalUnlock( hNewEdit );
  706. // now it is safe to set the global edit handle
  707. hEdit= hNewEdit;
  708. }
  709. SetFileName(szFile);
  710. /* Pass handle to edit control. This is more efficient than WM_SETTEXT
  711. * which would require twice the buffer space.
  712. */
  713. /* Bug 7443: If EM_SETHANDLE doesn't have enough memory to complete things,
  714. * it will send the EN_ERRSPACE message. If this happens, don't put up the
  715. * out of memory notification, put up the file to large message instead.
  716. * 17 November 1991 Clark R. Cyr
  717. */
  718. dwEmSetHandle = SETHANDLEINPROGRESS;
  719. SendMessage(hwndEdit, EM_SETHANDLE, (WPARAM)hEdit, 0);
  720. if (dwEmSetHandle == SETHANDLEFAILED)
  721. {
  722. SetCursor(hStdCursor);
  723. dwEmSetHandle = 0;
  724. AlertBox(hwndNP, szNN, szFTL, szFile, MB_APPLMODAL|MB_OK|MB_ICONWARNING);
  725. New(FALSE);
  726. SendMessage (hwndEdit, WM_SETREDRAW, TRUE, 0);
  727. return(FALSE);
  728. }
  729. dwEmSetHandle = 0;
  730. PostMessage (hwndEdit, EM_LIMITTEXT, (WPARAM)CCHNPMAX, 0L);
  731. /* If file starts with ".LOG" go to end and stamp date time */
  732. if (fLog)
  733. {
  734. SendMessage( hwndEdit, EM_SETSEL, (WPARAM)nChars, (LPARAM)nChars);
  735. SendMessage( hwndEdit, EM_SCROLLCARET, 0, 0);
  736. InsertDateTime(TRUE);
  737. }
  738. /* Move vertical thumb to correct position */
  739. SetScrollPos(hwndNP,
  740. SB_VERT,
  741. (int) SendMessage (hwndEdit, WM_VSCROLL, EM_GETTHUMB, 0),
  742. TRUE);
  743. /* Now display text */
  744. SendMessage(hwndEdit, WM_SETREDRAW, TRUE, 0);
  745. InvalidateRect(hwndEdit, NULL, TRUE);
  746. UpdateWindow(hwndEdit);
  747. SetCursor(hStdCursor);
  748. return( TRUE );
  749. }
  750. /* New Command - reset everything
  751. */
  752. void New(BOOL fCheck)
  753. {
  754. HANDLE hTemp;
  755. TCHAR* pSz;
  756. if (!fCheck || CheckSave (FALSE))
  757. {
  758. SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM) TEXT(""));
  759. SetFileName(NULL);
  760. SendMessage(hwndEdit, EM_SETSEL, 0, 0);
  761. SendMessage(hwndEdit, EM_SCROLLCARET, 0, 0);
  762. // resize of 1 NULL character i.e. zero length
  763. hTemp= LocalReAlloc( hEdit, sizeof(TCHAR), LMEM_MOVEABLE );
  764. if( hTemp )
  765. {
  766. hEdit= hTemp;
  767. }
  768. // null terminate the buffer. LocalReAlloc won't do it
  769. // because in all cases it is not growing which is the
  770. // only time it would zero out anything.
  771. pSz= LocalLock( hEdit );
  772. *pSz= TEXT('\0');
  773. LocalUnlock( hEdit );
  774. SendMessage (hwndEdit, EM_SETHANDLE, (WPARAM)hEdit, 0L);
  775. szSearch[0] = (TCHAR) 0;
  776. // Set encoding of new document
  777. g_cpOpened = g_cpDefault;
  778. if (g_cpOpened == CP_AUTO)
  779. {
  780. g_cpOpened = g_cpANSI;
  781. }
  782. g_wbOpened = wbDefault;
  783. }
  784. } // end of New()
  785. /* If sz does not have extension, append ".txt"
  786. * This function is useful for getting to undecorated filenames
  787. * that setup apps use. DO NOT CHANGE the extension. Too many setup
  788. * apps depend on this functionality.
  789. */
  790. void AddExt( TCHAR* sz )
  791. {
  792. TCHAR* pch1;
  793. int ch;
  794. DWORD dwSize;
  795. dwSize= lstrlen(sz);
  796. pch1= sz + dwSize; // point to end
  797. ch= *pch1;
  798. while( ch != TEXT('.') && ch != TEXT('\\') && ch != TEXT(':') && pch1 > sz)
  799. {
  800. //
  801. // backup one character. Do NOT use CharPrev because
  802. // it sometimes doesn't actually backup. Some Thai
  803. // tone marks fit this category but there seems to be others.
  804. // This is safe since it will stop at the beginning of the
  805. // string or on delimiters listed above. bug# 139374 2/13/98
  806. //
  807. // pch1= (TCHAR*)CharPrev (sz, pch1);
  808. pch1--; // back up
  809. ch= *pch1;
  810. }
  811. if( *pch1 != TEXT('.') )
  812. {
  813. if( dwSize + sizeof(".txt") <= MAX_PATH ) { // avoid buffer overruns
  814. lstrcat( sz, TEXT(".txt") );
  815. }
  816. }
  817. }
  818. /* AlertUser_FileFail(LPTSTR szFile)
  819. *
  820. * szFile is the name of file that was attempted to open.
  821. * Some sort of failure on file open. Alert the user
  822. * with some monologue box. At least give him decent
  823. * error messages.
  824. */
  825. VOID AlertUser_FileFail(LPCTSTR szFile)
  826. {
  827. TCHAR msg[256]; // buffer to format message into
  828. DWORD dwStatus; // status from FormatMessage
  829. UINT style= MB_APPLMODAL | MB_OK | MB_ICONWARNING;
  830. // Check GetLastError to see why we failed
  831. dwStatus=
  832. FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS |
  833. FORMAT_MESSAGE_FROM_SYSTEM,
  834. NULL,
  835. GetLastError(),
  836. GetUserDefaultLangID(),
  837. msg, // where message will end up
  838. CharSizeOf(msg), NULL );
  839. if( dwStatus )
  840. {
  841. MessageBox(hwndNP, msg, szNN, style);
  842. }
  843. else
  844. {
  845. AlertBox(hwndNP, szNN, szDiskError, szFile, style);
  846. }
  847. }