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.

982 lines
29 KiB

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