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.

916 lines
23 KiB

  1. /*++
  2. Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. parse.c
  5. Abstract:
  6. This module contains the parse routines for the Win32 common dialogs.
  7. Revision History:
  8. --*/
  9. // precompiled headers
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #include "fileopen.h"
  13. //
  14. // Global Variables.
  15. //
  16. extern TCHAR szCaption[];
  17. extern TCHAR szWarning[];
  18. ////////////////////////////////////////////////////////////////////////////
  19. //
  20. // ParseFileNew
  21. //
  22. // On the return, pnExtOffset is the offset to the dot.
  23. //
  24. ////////////////////////////////////////////////////////////////////////////
  25. int ParseFileNew(
  26. LPTSTR pszPath,
  27. int *pnExtOffset,
  28. BOOL bWowApp,
  29. BOOL bNewStyle)
  30. {
  31. int lRet = ParseFile(pszPath, TRUE, bWowApp, bNewStyle);
  32. if (pnExtOffset)
  33. {
  34. int nExt;
  35. nExt = (int)(SHORT)HIWORD(lRet);
  36. *pnExtOffset = ((nExt) && *(pszPath + nExt)) ? nExt : 0;
  37. }
  38. return ((int)(SHORT)LOWORD(lRet));
  39. }
  40. ////////////////////////////////////////////////////////////////////////////
  41. //
  42. // ParseFileOld
  43. //
  44. // On return, pnExtOffset is the offset to the the dot and
  45. // pnOldExt is the offset to the character following the dot.
  46. //
  47. ////////////////////////////////////////////////////////////////////////////
  48. int ParseFileOld(
  49. LPTSTR pszPath,
  50. int *pnExtOffset,
  51. int *pnOldExt,
  52. BOOL bWowApp,
  53. BOOL bNewStyle)
  54. {
  55. int lRet = ParseFile(pszPath, TRUE, bWowApp, bNewStyle);
  56. int nExt = (int)(SHORT)HIWORD(lRet);
  57. *pnExtOffset = nExt;
  58. *pnOldExt = ((nExt) && *(pszPath + nExt)) ? nExt + 1 : 0;
  59. return ((int)(SHORT)LOWORD(lRet));
  60. }
  61. ////////////////////////////////////////////////////////////////////////////
  62. //
  63. // ParseFile
  64. //
  65. // Determines if the filename is a legal dos name.
  66. //
  67. // Circumstances checked:
  68. // 1) Valid as directory name, but not as file name
  69. // 2) Empty String
  70. // 3) Illegal Drive label
  71. // 4) Period in invalid location (in extension, 1st in file name)
  72. // 5) Missing directory character
  73. // 6) Illegal character
  74. // 7) Wildcard in directory name
  75. // 8) Double slash beyond 1st 2 characters
  76. // 9) Space character in the middle of the name (trailing spaces OK)
  77. // -->> no longer applies : spaces are allowed in LFN
  78. // 10) Filename greater than 8 characters : NOT APPLICABLE TO LONG FILE NAMES
  79. // 11) Extension greater than 3 characters: NOT APPLICABLE TO LONG FILE NAMES
  80. //
  81. // lpstrFileName - ptr to a single file name
  82. //
  83. // Returns:
  84. // LONG - LOWORD = char offset to filename,
  85. // HIWORD = char offset to extension (dot),
  86. // LONG - LOWORD is error code (<0), HIWORD is approx. place of problem
  87. //
  88. ////////////////////////////////////////////////////////////////////////////
  89. DWORD ParseFile(
  90. LPTSTR lpstrFileName,
  91. BOOL bLFNFileSystem,
  92. BOOL bWowApp,
  93. BOOL bNewStyle)
  94. {
  95. SHORT nFile, nExt, nFileOffset, nExtOffset = 0;
  96. BOOL bExt;
  97. BOOL bWildcard;
  98. SHORT nNetwork = 0;
  99. BOOL bUNCPath = FALSE;
  100. LPTSTR lpstr = lpstrFileName;
  101. //Check if the string is empty
  102. if (!*lpstr)
  103. {
  104. nFileOffset = PARSE_EMPTYSTRING;
  105. goto ParseFile_Failure;
  106. }
  107. //Check if the string is of form c:\foo1\foo2
  108. if (*(lpstr + 1) == CHAR_COLON)
  109. {
  110. //Yes. Get the drive letter
  111. TCHAR cDrive = CharLowerChar(*lpstr);
  112. //
  113. // Test to see if the drive is legal.
  114. //
  115. // Note: Does not test that drive exists.
  116. //
  117. if ((cDrive < CHAR_A) || (cDrive > CHAR_Z))
  118. {
  119. nFileOffset = PARSE_INVALIDDRIVE;
  120. goto ParseFile_Failure;
  121. }
  122. //Move string past drive letter and ':'
  123. lpstr = CharNext(CharNext(lpstr));
  124. }
  125. if ((*lpstr == CHAR_BSLASH) || (*lpstr == CHAR_SLASH && !bNewStyle))
  126. {
  127. //
  128. // Cannot have "c:\."
  129. //
  130. if (*++lpstr == CHAR_DOT)
  131. {
  132. //
  133. // Except that "c:\.\" is allowed.
  134. //
  135. if ((*++lpstr != CHAR_BSLASH) && (*lpstr != CHAR_SLASH || bNewStyle))
  136. {
  137. //
  138. // It's the root directory.
  139. //
  140. if (!*lpstr)
  141. {
  142. goto MustBeDir;
  143. }
  144. else
  145. {
  146. lpstr--;
  147. }
  148. }
  149. else
  150. {
  151. //
  152. // It's saying top dir (once again), thus allowed.
  153. //
  154. ++lpstr;
  155. }
  156. }
  157. else if ((*lpstr == CHAR_BSLASH) && (*(lpstr - 1) == CHAR_BSLASH))
  158. {
  159. //
  160. // It seems that for a full network path, whether a drive is
  161. // declared or not is insignificant, though if a drive is given,
  162. // it must be valid (hence the code above should remain there).
  163. //
  164. //
  165. // ...since it's the first slash, 2 are allowed.
  166. //
  167. ++lpstr;
  168. //
  169. // Must receive server and share to be real.
  170. //
  171. nNetwork = -1;
  172. //
  173. // No wildcards allowed if UNC name.
  174. //
  175. bUNCPath = TRUE;
  176. }
  177. else if (*lpstr == CHAR_SLASH && !bNewStyle)
  178. {
  179. nFileOffset = PARSE_INVALIDDIRCHAR;
  180. goto ParseFile_Failure;
  181. }
  182. }
  183. else if (*lpstr == CHAR_DOT)
  184. {
  185. //
  186. // Up one directory.
  187. //
  188. if (*++lpstr == CHAR_DOT)
  189. {
  190. ++lpstr;
  191. }
  192. if (!*lpstr)
  193. {
  194. goto MustBeDir;
  195. }
  196. if ((*lpstr != CHAR_BSLASH) && (*lpstr != CHAR_SLASH || bNewStyle))
  197. {
  198. //
  199. // Jumping to Failure here will skip the parsing that causes
  200. // ".xxx.txt" to return with nFileOffset = 2.
  201. //
  202. nFileOffset = 0;
  203. goto ParseFile_Failure;
  204. }
  205. else
  206. {
  207. //
  208. // Allow directory.
  209. //
  210. ++lpstr;
  211. }
  212. }
  213. if (!*lpstr)
  214. {
  215. goto MustBeDir;
  216. }
  217. //
  218. // Should point to first char in filename by now.
  219. //
  220. nFileOffset = nExtOffset = nFile = nExt = 0;
  221. bWildcard = bExt = FALSE;
  222. while (*lpstr)
  223. {
  224. //
  225. // Anything below the "Space" character is invalid.
  226. //
  227. #ifdef UNICODE
  228. if (*lpstr < CHAR_SPACE)
  229. #else
  230. if (((UCHAR)*lpstr) < CHAR_SPACE)
  231. #endif
  232. {
  233. nFileOffset = PARSE_INVALIDCHAR;
  234. goto ParseFile_Failure;
  235. }
  236. switch (*lpstr)
  237. {
  238. case ( CHAR_COLON ) :
  239. case ( CHAR_BAR ) :
  240. case ( CHAR_LTHAN ) :
  241. case ( CHAR_QUOTE ) :
  242. {
  243. //
  244. // Invalid characters for all file systems.
  245. //
  246. nFileOffset = PARSE_INVALIDCHAR;
  247. goto ParseFile_Failure;
  248. }
  249. case ( CHAR_SEMICOLON ) :
  250. case ( CHAR_COMMA ) :
  251. case ( CHAR_PLUS ) :
  252. case ( CHAR_LBRACKET ) :
  253. case ( CHAR_RBRACKET ) :
  254. case ( CHAR_EQUAL ) :
  255. {
  256. if (!bLFNFileSystem)
  257. {
  258. nFileOffset = PARSE_INVALIDCHAR;
  259. goto ParseFile_Failure;
  260. }
  261. else
  262. {
  263. goto RegularCharacter;
  264. }
  265. }
  266. case ( CHAR_SLASH ) :
  267. {
  268. if (bNewStyle)
  269. {
  270. nFileOffset = PARSE_INVALIDCHAR;
  271. goto ParseFile_Failure;
  272. }
  273. // fall thru...
  274. }
  275. case ( CHAR_BSLASH ) :
  276. {
  277. //
  278. // Subdir indicators.
  279. //
  280. nNetwork++;
  281. if (bWildcard)
  282. {
  283. nFileOffset = PARSE_WILDCARDINDIR;
  284. goto ParseFile_Failure;
  285. }
  286. //
  287. // if nFile==0 means that we are seeing this backslash right next to a backslash
  288. // which is not allowed.
  289. if (nFile == 0)
  290. {
  291. nFileOffset = PARSE_INVALIDDIRCHAR;
  292. goto ParseFile_Failure;
  293. }
  294. else
  295. {
  296. //Move over the BSLASH/SLASH character.
  297. ++lpstr;
  298. //Check if the path is valid network path name
  299. if (!nNetwork && !*lpstr)
  300. {
  301. nFileOffset = PARSE_INVALIDNETPATH;
  302. goto ParseFile_Failure;
  303. }
  304. //We assume that the characters we are seeing are filename characters. This BSLASH/SLASH
  305. //character tells that characters we have seen so far specifies the name of a directory in the
  306. //path. Reset flags so that we can start looking for filename again.
  307. nFile = nExt = 0;
  308. nExtOffset = 0;
  309. bExt = FALSE;
  310. }
  311. break;
  312. }
  313. case ( CHAR_SPACE ) :
  314. {
  315. LPTSTR lpSpace = lpstr;
  316. if (bLFNFileSystem)
  317. {
  318. // In Long file name file system space characters are O.K
  319. goto RegularCharacter;
  320. }
  321. //We are not interested in the trailing spaces so null terminate it.
  322. *lpSpace = CHAR_NULL;
  323. // In non long file name file systems, space characters are OK at the end of file
  324. // name. Check to see if all the characters that follows are spaces. if thats the case
  325. // then its valid. if we have any non space character after the first space then its a
  326. // invalid file name.
  327. while (*++lpSpace)
  328. {
  329. if (*lpSpace != CHAR_SPACE)
  330. {
  331. *lpstr = CHAR_SPACE;
  332. nFileOffset = PARSE_INVALIDSPACE;
  333. goto ParseFile_Failure;
  334. }
  335. }
  336. break;
  337. }
  338. case ( CHAR_DOT ) :
  339. {
  340. // In newstyle nExtOffset points to the dot and not to the first character of extension.
  341. if (bNewStyle)
  342. {
  343. nExtOffset = (SHORT)(lpstr - lpstrFileName);
  344. goto RegularCharacter;
  345. }
  346. if (nFile == 0)
  347. {
  348. nFileOffset = (SHORT)(lpstr - lpstrFileName);
  349. if (*++lpstr == CHAR_DOT)
  350. {
  351. ++lpstr;
  352. }
  353. if (!*lpstr)
  354. {
  355. goto MustBeDir;
  356. }
  357. //
  358. // Flags already set.
  359. //
  360. nFile++;
  361. ++lpstr;
  362. }
  363. else
  364. {
  365. nExtOffset = 0;
  366. ++lpstr;
  367. bExt = TRUE;
  368. }
  369. break;
  370. }
  371. case ( CHAR_STAR ) :
  372. case ( CHAR_QMARK ) :
  373. {
  374. bWildcard = TRUE;
  375. // Fall thru...
  376. }
  377. default :
  378. {
  379. RegularCharacter:
  380. //Are we in extension part ?
  381. if (bExt)
  382. {
  383. //Is this first character in extension part
  384. if (++nExt == 1)
  385. {
  386. //Yes, then get the Extension offset
  387. nExtOffset = (SHORT)(lpstr - lpstrFileName);
  388. }
  389. }
  390. //We are still in file name part.
  391. //Is this the first character in filename part ?
  392. else if (++nFile == 1)
  393. {
  394. //Yes. Get the filename offset
  395. nFileOffset = (SHORT)(lpstr - lpstrFileName);
  396. }
  397. //Move to the next character
  398. lpstr = CharNext(lpstr);
  399. break;
  400. }
  401. }
  402. }
  403. if (nNetwork == -1)
  404. {
  405. nFileOffset = PARSE_INVALIDNETPATH;
  406. goto ParseFile_Failure;
  407. }
  408. else if (bUNCPath)
  409. {
  410. if (!nNetwork)
  411. {
  412. //
  413. // Server and share only.(e.g \\server\foo)
  414. //
  415. *lpstr = CHAR_NULL;
  416. nFileOffset = PARSE_DIRECTORYNAME;
  417. goto ParseFile_Failure;
  418. }
  419. else if ((nNetwork == 1) && !nFile)
  420. {
  421. //
  422. // Server and share root.(e.g \\server\foo\)
  423. //
  424. *lpstr = CHAR_NULL;
  425. nFileOffset = PARSE_DIRECTORYNAME;
  426. goto ParseFile_Failure;
  427. }
  428. }
  429. if (!nFile)
  430. {
  431. MustBeDir:
  432. nFileOffset = PARSE_DIRECTORYNAME;
  433. goto ParseFile_Failure;
  434. }
  435. //
  436. // If bNewStyle is true, no ext. wanted.
  437. //
  438. if (!bNewStyle)
  439. {
  440. if ((bWowApp) &&
  441. (*(lpstr - 1) == CHAR_DOT) &&
  442. (*CharNext(lpstr - 2) == CHAR_DOT))
  443. {
  444. //
  445. // Remove terminating period.
  446. //
  447. *(lpstr - 1) = CHAR_NULL;
  448. }
  449. else if (!nExt)
  450. {
  451. ParseFile_Failure:
  452. //
  453. // Need to recheck bNewStyle since we can jump here.
  454. //
  455. if (!bNewStyle)
  456. {
  457. nExtOffset = (SHORT)(lpstr - lpstrFileName);
  458. }
  459. }
  460. }
  461. return (MAKELONG(nFileOffset, nExtOffset));
  462. }
  463. ////////////////////////////////////////////////////////////////////////////
  464. //
  465. // PathRemoveBslash
  466. //
  467. // Removes a trailing backslash from the given path.
  468. //
  469. // Returns:
  470. // Pointer to NULL that replaced the backslash OR
  471. // Pointer to the last character if it isn't a backslash
  472. //
  473. ////////////////////////////////////////////////////////////////////////////
  474. LPTSTR PathRemoveBslash(
  475. LPTSTR lpszPath)
  476. {
  477. int len = lstrlen(lpszPath) - 1;
  478. #ifndef UNICODE
  479. if (IsDBCSLeadByte(*CharPrev(lpszPath, lpszPath + len + 1)))
  480. {
  481. len--;
  482. }
  483. #endif
  484. if (!PathIsRoot(lpszPath) && (lpszPath[len] == CHAR_BSLASH))
  485. {
  486. lpszPath[len] = CHAR_NULL;
  487. }
  488. return (lpszPath + len);
  489. }
  490. ////////////////////////////////////////////////////////////////////////////
  491. //
  492. // IsWild
  493. //
  494. ////////////////////////////////////////////////////////////////////////////
  495. BOOL IsWild(
  496. LPCTSTR lpsz)
  497. {
  498. return (StrChr(lpsz, CHAR_STAR) || StrChr(lpsz, CHAR_QMARK));
  499. }
  500. ////////////////////////////////////////////////////////////////////////////
  501. //
  502. // AppendExt
  503. //
  504. // Appends default extension onto path name.
  505. // It assumes the current path name doesn't already have an extension.
  506. // lpExtension does not need to be null terminated.
  507. //
  508. ////////////////////////////////////////////////////////////////////////////
  509. VOID AppendExt(
  510. LPTSTR lpszPath,
  511. LPCTSTR lpExtension,
  512. BOOL bWildcard)
  513. {
  514. WORD wOffset;
  515. SHORT i;
  516. TCHAR szExt[MAX_PATH + 1];
  517. if (lpExtension && *lpExtension)
  518. {
  519. wOffset = (WORD)lstrlen(lpszPath);
  520. if (bWildcard)
  521. {
  522. *(lpszPath + wOffset++) = CHAR_STAR;
  523. }
  524. //
  525. // Add a period.
  526. //
  527. *(lpszPath + wOffset++) = CHAR_DOT;
  528. for (i = 0; *(lpExtension + i) && i < MAX_PATH; i++)
  529. {
  530. szExt[i] = *(lpExtension + i);
  531. }
  532. szExt[i] = 0;
  533. //
  534. // Remove leading / trailing blanks in the extension.
  535. //
  536. PathRemoveBlanks(szExt);
  537. //
  538. // Add the rest.
  539. //
  540. lstrcpy(lpszPath + wOffset, szExt);
  541. }
  542. }
  543. ////////////////////////////////////////////////////////////////////////////
  544. //
  545. // IsUNC
  546. //
  547. // Determines if the given path is a UNC path.
  548. //
  549. // Returns:
  550. // TRUE if path starts with "\\" or "X:\\"
  551. // FALSE otherwise
  552. //
  553. ////////////////////////////////////////////////////////////////////////////
  554. BOOL IsUNC(
  555. LPCTSTR lpszPath)
  556. {
  557. return ( DBL_BSLASH(lpszPath) ||
  558. ((lpszPath[1] == CHAR_COLON) && DBL_BSLASH(lpszPath + 2)) );
  559. }
  560. ////////////////////////////////////////////////////////////////////////////
  561. //
  562. // PortName
  563. //
  564. ////////////////////////////////////////////////////////////////////////////
  565. #define PORTARRAY 14
  566. BOOL PortName(
  567. LPTSTR lpszFileName)
  568. {
  569. static TCHAR *szPorts[PORTARRAY] = { TEXT("LPT1"),
  570. TEXT("LPT2"),
  571. TEXT("LPT3"),
  572. TEXT("LPT4"),
  573. TEXT("COM1"),
  574. TEXT("COM2"),
  575. TEXT("COM3"),
  576. TEXT("COM4"),
  577. TEXT("EPT"),
  578. TEXT("NUL"),
  579. TEXT("PRN"),
  580. TEXT("CLOCK$"),
  581. TEXT("CON"),
  582. TEXT("AUX"),
  583. };
  584. short i;
  585. TCHAR cSave, cSave2;
  586. cSave = *(lpszFileName + 4);
  587. if (cSave == CHAR_DOT)
  588. {
  589. *(lpszFileName + 4) = CHAR_NULL;
  590. }
  591. //
  592. // For "EPT".
  593. //
  594. cSave2 = *(lpszFileName + 3);
  595. if (cSave2 == CHAR_DOT)
  596. {
  597. *(lpszFileName + 3) = CHAR_NULL;
  598. }
  599. for (i = 0; i < PORTARRAY; i++)
  600. {
  601. if (!lstrcmpi(szPorts[i], lpszFileName))
  602. {
  603. break;
  604. }
  605. }
  606. *(lpszFileName + 4) = cSave;
  607. *(lpszFileName + 3) = cSave2;
  608. return (i != PORTARRAY);
  609. }
  610. ////////////////////////////////////////////////////////////////////////////
  611. //
  612. // IsDirectory
  613. //
  614. ////////////////////////////////////////////////////////////////////////////
  615. BOOL IsDirectory(
  616. LPTSTR pszPath)
  617. {
  618. DWORD dwAttributes;
  619. //
  620. // Clean up for GetFileAttributes.
  621. //
  622. PathRemoveBslash(pszPath);
  623. dwAttributes = GetFileAttributes(pszPath);
  624. return ( (dwAttributes != (DWORD)(-1)) &&
  625. (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) );
  626. }
  627. ////////////////////////////////////////////////////////////////////////////
  628. //
  629. // WriteProtectedDirCheck
  630. //
  631. // This function takes a full filename, strips the path, and creates
  632. // a temp file in that directory. If it can't, the directory is probably
  633. // write protected.
  634. //
  635. // Returns:
  636. // error code if writeprotected
  637. // 0 if successful creation of file.
  638. //
  639. // Assumptions:
  640. // Full Path name on input with space for full filename appended.
  641. //
  642. // Note: Do NOT use this on a floppy, it's too slow!
  643. //
  644. ////////////////////////////////////////////////////////////////////////////
  645. int WriteProtectedDirCheck(
  646. LPCTSTR lpszFile)
  647. {
  648. SHORT nFileOffset;
  649. TCHAR szFile[MAX_PATH + 1];
  650. TCHAR szBuf[MAX_PATH + 1];
  651. lstrcpyn(szFile, lpszFile, MAX_PATH + 1);
  652. nFileOffset = (SHORT)(int)LOWORD(ParseFile(szFile, TRUE, FALSE, TRUE));
  653. szFile[nFileOffset - 1] = CHAR_NULL;
  654. if (!GetTempFileName(szFile, TEXT("TMP"), 0, szBuf))
  655. {
  656. return (GetLastError());
  657. }
  658. else
  659. {
  660. DeleteFile(szBuf);
  661. return (0); // success
  662. }
  663. }
  664. ////////////////////////////////////////////////////////////////////////////
  665. //
  666. // FOkToWriteOver
  667. //
  668. // Verifies that the user really does want to destroy the file,
  669. // replacing its contents with new stuff.
  670. //
  671. ////////////////////////////////////////////////////////////////////////////
  672. BOOL FOkToWriteOver(
  673. HWND hDlg,
  674. LPTSTR szFileName)
  675. {
  676. if (!CDLoadString( g_hinst,
  677. iszOverwriteQuestion,
  678. szCaption,
  679. WARNINGMSGLENGTH - 1 ))
  680. {
  681. return (FALSE);
  682. }
  683. //
  684. // Since we're passed in a valid filename, if the 3rd & 4th characters
  685. // are both slashes, weve got a dummy drive as the 1st two characters.
  686. //
  687. if (DBL_BSLASH(szFileName + 2))
  688. {
  689. szFileName = szFileName + 2;
  690. }
  691. wsprintf(szWarning, szCaption, szFileName);
  692. GetWindowText(hDlg, szCaption, cbCaption);
  693. return (MessageBox( hDlg,
  694. szWarning,
  695. szCaption,
  696. MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION ) == IDYES);
  697. }
  698. ////////////////////////////////////////////////////////////////////////////
  699. //
  700. // CreateFileDlg
  701. //
  702. ////////////////////////////////////////////////////////////////////////////
  703. int CreateFileDlg(
  704. HWND hDlg,
  705. LPTSTR szPath)
  706. {
  707. //
  708. // Since we're passed in a valid filename, if the 3rd & 4th
  709. // characters are both slashes, we've got a dummy drive as the
  710. // 1st two characters.
  711. //
  712. if (DBL_BSLASH(szPath + 2))
  713. {
  714. szPath = szPath + 2;
  715. }
  716. if (!CDLoadString(g_hinst, iszCreatePrompt, szCaption, TOOLONGLIMIT))
  717. {
  718. return (IDNO);
  719. }
  720. if (lstrlen(szPath) > TOOLONGLIMIT)
  721. {
  722. *(szPath + TOOLONGLIMIT) = CHAR_NULL;
  723. }
  724. wsprintf(szWarning, szCaption, szPath);
  725. GetWindowText(hDlg, szCaption, TOOLONGLIMIT);
  726. return (MessageBox( hDlg,
  727. szWarning,
  728. szCaption,
  729. MB_YESNO | MB_ICONQUESTION ));
  730. }
  731. #ifndef UNICODE
  732. ////////////////////////////////////////////////////////////////////////////
  733. //
  734. // EliminateString
  735. //
  736. // Chops the string by the specified length. If a DBCS lead byte is
  737. // left as the last char, then it is removed as well.
  738. //
  739. // NOTE: For non-Unicode strings only.
  740. //
  741. ////////////////////////////////////////////////////////////////////////////
  742. VOID EliminateString(
  743. LPSTR lpStr,
  744. int nLen)
  745. {
  746. LPSTR lpChar;
  747. BOOL bFix = FALSE;
  748. *(lpStr + nLen) = CHAR_NULL;
  749. for (lpChar = lpStr + nLen - 1; lpChar >= lpStr; lpChar--)
  750. {
  751. if (!IsDBCSLeadByte(*lpChar))
  752. {
  753. break;
  754. }
  755. bFix = !bFix;
  756. }
  757. if (bFix)
  758. {
  759. *(lpStr + nLen - 1) = CHAR_NULL;
  760. }
  761. }
  762. ////////////////////////////////////////////////////////////////////////////
  763. //
  764. // IsBackSlash
  765. //
  766. // Decides whether a character is a '\' or a DBCS trail byte with the same
  767. // code point value.
  768. //
  769. // NOTE: For non-Unicode strings only.
  770. //
  771. ////////////////////////////////////////////////////////////////////////////
  772. BOOL IsBackSlash(
  773. LPSTR lpStart,
  774. LPSTR lpChar)
  775. {
  776. if (*lpChar == CHAR_BSLASH)
  777. {
  778. BOOL bRet = TRUE;
  779. while (--lpChar >= lpStart)
  780. {
  781. if (!IsDBCSLeadByte(*lpChar))
  782. {
  783. break;
  784. }
  785. bRet = !bRet;
  786. }
  787. return (bRet);
  788. }
  789. return (FALSE);
  790. }
  791. #endif