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.

830 lines
18 KiB

  1. /*++
  2. Copyright (c) 1993-1995 Microsoft Corporation
  3. Module Name:
  4. nwconv.c
  5. Abstract:
  6. Author:
  7. Arthur Hanson (arth) 27-Jul-1994
  8. Revision History:
  9. --*/
  10. #include "globals.h"
  11. LPTSTR alpsz[TOTAL_STRINGS]; // String resource array cache.
  12. static UINT cswitch = 0;
  13. static HCURSOR hCursor;
  14. /////////////////////////////////////////////////////////////////////////
  15. LPTSTR
  16. Lids(
  17. WORD idsStr
  18. )
  19. /*++
  20. Routine Description:
  21. Returns the requested string from the string table. Caches the
  22. strings in an internal buffer. Will return a NULL string if the
  23. string can't be loaded.
  24. Arguments:
  25. Return Value:
  26. --*/
  27. {
  28. WORD idsString;
  29. static TCHAR szEmpty[] = TEXT("");
  30. TCHAR Buffer[MAX_STRING_SIZE];
  31. WORD nLen;
  32. LPTSTR lpsz;
  33. idsString = idsStr - IDS_STRINGBASE;
  34. if ((idsString == 0) ||( idsString > TOTAL_STRINGS))
  35. return(szEmpty);
  36. // -1 index as table is 0 based and 0 is not a valid string ID.
  37. if (alpsz[idsString-1])
  38. return((LPTSTR)alpsz[idsString-1]);
  39. if (!(nLen = (WORD) LoadString(hInst, idsStr, (LPTSTR) Buffer, MAX_STRING_SIZE)))
  40. return(szEmpty);
  41. if (!(lpsz = AllocMemory((nLen+1) * sizeof(TCHAR))))
  42. return(szEmpty);
  43. lstrcpy((LPTSTR)lpsz, (LPTSTR) Buffer);
  44. return (alpsz[idsString-1] = lpsz);
  45. } // Lids
  46. /////////////////////////////////////////////////////////////////////////
  47. VOID
  48. StringTableDestroy()
  49. /*++
  50. Routine Description:
  51. Frees up all the memory allocated in the string table.
  52. Arguments:
  53. Return Value:
  54. --*/
  55. {
  56. int i;
  57. for (i=0; i < TOTAL_STRINGS ; i++ ) {
  58. if (alpsz[i]) {
  59. FreeMemory(alpsz[i]);
  60. alpsz[i]=NULL;
  61. }
  62. }
  63. } // StringTableDestroy
  64. /////////////////////////////////////////////////////////////////////////
  65. VOID
  66. CursorHourGlass()
  67. /*++
  68. Routine Description:
  69. Arguments:
  70. Return Value:
  71. --*/
  72. {
  73. if (!cswitch) {
  74. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  75. ShowCursor(TRUE);
  76. }
  77. cswitch++;
  78. } // CursorHourGlass
  79. /////////////////////////////////////////////////////////////////////////
  80. VOID
  81. CursorNormal()
  82. /*++
  83. Routine Description:
  84. Arguments:
  85. Return Value:
  86. --*/
  87. {
  88. if (cswitch == 0)
  89. return;
  90. cswitch--;
  91. if (!cswitch) {
  92. ShowCursor(FALSE);
  93. SetCursor(hCursor);
  94. }
  95. } // Cursor Normal
  96. /////////////////////////////////////////////////////////////////////////
  97. BOOL
  98. BitTest(
  99. int Bit,
  100. BYTE *Bits
  101. )
  102. /*++
  103. Routine Description:
  104. Arguments:
  105. Return Value:
  106. --*/
  107. {
  108. int i, j;
  109. i = Bit / 8;
  110. j = Bit % 8;
  111. if ((Bits[i] >> j) & 0x01)
  112. return TRUE;
  113. else
  114. return FALSE;
  115. } // BitTest
  116. /////////////////////////////////////////////////////////////////////////
  117. BOOL
  118. CenterWindow(
  119. HWND hwndChild,
  120. HWND hwndParent
  121. )
  122. /*++
  123. Routine Description:
  124. Arguments:
  125. Return Value:
  126. --*/
  127. {
  128. RECT rChild, rParent;
  129. int wChild, hChild, wParent, hParent;
  130. int wScreen, hScreen, xNew, yNew;
  131. HDC hdc;
  132. // Get the Height and Width of the child window
  133. GetWindowRect (hwndChild, &rChild);
  134. wChild = rChild.right - rChild.left;
  135. hChild = rChild.bottom - rChild.top;
  136. // Get the Height and Width of the parent window
  137. GetWindowRect (hwndParent, &rParent);
  138. wParent = rParent.right - rParent.left;
  139. hParent = rParent.bottom - rParent.top;
  140. // Get the display limits
  141. hdc = GetDC (hwndChild);
  142. wScreen = GetDeviceCaps (hdc, HORZRES);
  143. hScreen = GetDeviceCaps (hdc, VERTRES);
  144. ReleaseDC (hwndChild, hdc);
  145. // Calculate new X position, then adjust for screen
  146. xNew = rParent.left + ((wParent - wChild) /2);
  147. if (xNew < 0)
  148. xNew = 0;
  149. else if ((xNew+wChild) > wScreen)
  150. xNew = wScreen - wChild;
  151. // Calculate new Y position, then adjust for screen
  152. yNew = rParent.top + ((hParent - hChild) /2);
  153. if (yNew < 0)
  154. yNew = 0;
  155. else if ((yNew+hChild) > hScreen)
  156. yNew = hScreen - hChild;
  157. // Set it, and return
  158. return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  159. } // CenterWindow
  160. /////////////////////////////////////////////////////////////////////////
  161. TCHAR *
  162. lstrchr(
  163. LPTSTR String,
  164. TCHAR c
  165. )
  166. /*++
  167. Routine Description:
  168. Arguments:
  169. Return Value:
  170. --*/
  171. {
  172. TCHAR *ptrChar = String;
  173. BOOL Found = FALSE;
  174. while(*ptrChar && !Found) {
  175. if (*ptrChar == c)
  176. Found = TRUE;
  177. else
  178. ptrChar++;
  179. }
  180. if (Found)
  181. return ptrChar;
  182. else
  183. return NULL;
  184. } // lstrchr
  185. /////////////////////////////////////////////////////////////////////////
  186. BOOL
  187. IsPath(
  188. LPTSTR Path
  189. )
  190. /*++
  191. Routine Description:
  192. Arguments:
  193. Return Value:
  194. --*/
  195. {
  196. ULONG len;
  197. LPTSTR ptr;
  198. len = lstrlen(Path);
  199. if (len < 2) // must have a slash and character
  200. return FALSE;
  201. // now know path is at least 2 characters long
  202. ptr = Path;
  203. // if slash anywhere then it has to be a path
  204. while (*ptr)
  205. if (*ptr == TEXT('\\'))
  206. return TRUE;
  207. else
  208. ptr++;
  209. // no slash - unless this is a drive then it aint no path.
  210. if (Path[1] == TEXT(':'))
  211. return TRUE;
  212. return FALSE;
  213. } // IsPath
  214. /////////////////////////////////////////////////////////////////////////
  215. LPTSTR
  216. lToStr(
  217. ULONG Number
  218. )
  219. /*++
  220. Routine Description:
  221. Arguments:
  222. Return Value:
  223. --*/
  224. {
  225. static TCHAR String[15];
  226. TCHAR tString[15];
  227. LPTSTR sptr, dptr;
  228. ULONG Count;
  229. sptr = String;
  230. dptr = tString;
  231. wsprintf(tString, TEXT("%lu"), Number);
  232. Count = lstrlen(tString);
  233. *sptr++ = *dptr++;
  234. Count--;
  235. while (*dptr) {
  236. if (!(Count % 3))
  237. *sptr++ = TEXT(',');
  238. *sptr++ = *dptr++;
  239. Count--;
  240. }
  241. *sptr = TEXT('\0');
  242. return String;
  243. } // lToStr;
  244. /////////////////////////////////////////////////////////////////////////
  245. LPTSTR
  246. TimeToStr(
  247. ULONG TotTime
  248. )
  249. /*++
  250. Routine Description:
  251. Arguments:
  252. Return Value:
  253. --*/
  254. {
  255. static TCHAR String[10];
  256. ULONG Hours, Minutes, Seconds;
  257. Hours = TotTime / 3600;
  258. TotTime -= (Hours * 3600);
  259. Minutes = TotTime / 60;
  260. Seconds = TotTime - (Minutes * 60);
  261. wsprintf(String, TEXT("%3lu:%2lu:%2lu"), Hours, Minutes, Seconds);
  262. return String;
  263. } // TimeToStr;
  264. /////////////////////////////////////////////////////////////////////////
  265. LPTSTR
  266. DateToStr(
  267. ULONG TotTime
  268. )
  269. /*++
  270. Routine Description:
  271. Arguments:
  272. Return Value:
  273. --*/
  274. {
  275. static TCHAR String[10];
  276. ULONG Hours, Minutes, Seconds;
  277. Hours = TotTime / 3600;
  278. TotTime -= (Hours * 3600);
  279. Minutes = TotTime / 60;
  280. Seconds = TotTime - (Minutes * 60);
  281. wsprintf(String, TEXT("%3lu:%2lu:%2lu"), Hours, Minutes, Seconds);
  282. return String;
  283. } // DateToStr;
  284. /*+-----------------------------------------------------------------------+
  285. | Took the _splitpath and _makepath routines and converted them to |
  286. | be NT (long file name) and Unicode friendly. |
  287. +-----------------------------------------------------------------------+*/
  288. /////////////////////////////////////////////////////////////////////////
  289. VOID
  290. lsplitpath(
  291. const TCHAR *path,
  292. TCHAR *drive,
  293. TCHAR *dir,
  294. TCHAR *fname,
  295. TCHAR *ext
  296. )
  297. /*++
  298. Routine Description:
  299. Splits a path name into its individual components
  300. Arguments:
  301. path - pointer to path name to be parsed
  302. drive - pointer to buffer for drive component, if any
  303. dir - pointer to buffer for subdirectory component, if any
  304. fname - pointer to buffer for file base name component, if any
  305. ext - pointer to buffer for file name extension component, if any
  306. Return Value:
  307. drive - pointer to drive string. Includes ':' if a drive was given.
  308. dir - pointer to subdirectory string. Includes leading and
  309. trailing '/' or '\', if any.
  310. fname - pointer to file base name
  311. ext - pointer to file extension, if any. Includes leading '.'.
  312. --*/
  313. {
  314. TCHAR *p;
  315. TCHAR *last_slash = NULL, *dot = NULL;
  316. unsigned len;
  317. // init these so we don't exit with bogus values
  318. drive[0] = TEXT('\0');
  319. dir[0] = TEXT('\0');
  320. fname[0] = TEXT('\0');
  321. ext[0] = TEXT('\0');
  322. if (path[0] == TEXT('\0'))
  323. return;
  324. /*+---------------------------------------------------------------------+
  325. | Assume that the path argument has the following form, where any or |
  326. | all of the components may be missing. |
  327. | |
  328. | <drive><dir><fname><ext> |
  329. | |
  330. | drive: |
  331. | 0 to MAX_DRIVE-1 characters, the last of which, if any, is a |
  332. | ':' or a '\' in the case of a UNC path. |
  333. | dir: |
  334. | 0 to _MAX_DIR-1 characters in the form of an absolute path |
  335. | (leading '/' or '\') or relative path, the last of which, if |
  336. | any, must be a '/' or '\'. E.g - |
  337. | |
  338. | absolute path: |
  339. | \top\next\last\ ; or |
  340. | /top/next/last/ |
  341. | relative path: |
  342. | top\next\last\ ; or |
  343. | top/next/last/ |
  344. | Mixed use of '/' and '\' within a path is also tolerated |
  345. | fname: |
  346. | 0 to _MAX_FNAME-1 characters not including the '.' character |
  347. | ext: |
  348. | 0 to _MAX_EXT-1 characters where, if any, the first must be a |
  349. | '.' |
  350. +---------------------------------------------------------------------+*/
  351. // extract drive letter and :, if any
  352. if ( path[0] && (path[1] == TEXT(':')) ) {
  353. if (drive) {
  354. drive[0] = path[0];
  355. drive[1] = path[1];
  356. drive[2] = TEXT('\0');
  357. }
  358. path += 2;
  359. }
  360. // if no drive then check for UNC pathname
  361. if (drive[0] == TEXT('\0'))
  362. if ((path[0] == TEXT('\\')) && (path[1] == TEXT('\\'))) {
  363. // got a UNC path so put server-sharename into drive
  364. drive[0] = path[0];
  365. drive[1] = path[1];
  366. path += 2;
  367. p = &drive[2];
  368. while ((*path != TEXT('\0')) && (*path != TEXT('\\')))
  369. *p++ = *path++;
  370. if (*path == TEXT('\0'))
  371. return;
  372. // now sitting at the share - copy this as well (copy slash first)
  373. *p++ = *path++;
  374. while ((*path != TEXT('\0')) && (*path != TEXT('\\')))
  375. *p++ = *path++;
  376. // tack on terminating NULL
  377. *p = TEXT('\0');
  378. }
  379. /*+---------------------------------------------------------------------+
  380. | extract path string, if any. Path now points to the first character|
  381. | of the path, if any, or the filename or extension, if no path was |
  382. | specified. Scan ahead for the last occurence, if any, of a '/' or |
  383. | '\' path separator character. If none is found, there is no path. |
  384. | We will also note the last '.' character found, if any, to aid in |
  385. | handling the extension. |
  386. +---------------------------------------------------------------------+*/
  387. for (last_slash = NULL, p = (TCHAR *)path; *p; p++) {
  388. if (*p == TEXT('/') || *p == TEXT('\\'))
  389. // point to one beyond for later copy
  390. last_slash = p + 1;
  391. else if (*p == TEXT('.'))
  392. dot = p;
  393. }
  394. if (last_slash) {
  395. // found a path - copy up through last_slash or max. characters allowed,
  396. // whichever is smaller
  397. if (dir) {
  398. len = (USHORT) __min((last_slash - path), (_MAX_DIR - 1));
  399. lstrcpyn(dir, path, len + 1);
  400. dir[len] = TEXT('\0');
  401. }
  402. path = last_slash;
  403. }
  404. /*+---------------------------------------------------------------------+
  405. | extract file name and extension, if any. Path now points to the |
  406. | first character of the file name, if any, or the extension if no |
  407. | file name was given. Dot points to the '.' beginning the extension,|
  408. | if any. |
  409. +---------------------------------------------------------------------+*/
  410. if (dot && (dot >= path)) {
  411. // found the marker for an extension - copy the file name up to the
  412. // '.'.
  413. if (fname) {
  414. len = (USHORT) __min((dot - path), (_MAX_FNAME - 1));
  415. lstrcpyn(fname, path, len + 1);
  416. *(fname + len) = TEXT('\0');
  417. }
  418. // now we can get the extension - remember that p still points to the
  419. // terminating nul character of path.
  420. if (ext) {
  421. len = (USHORT) __min((p - dot), (_MAX_EXT - 1));
  422. lstrcpyn(ext, dot, len + 1);
  423. ext[len] = TEXT('\0');
  424. }
  425. }
  426. else {
  427. // found no extension, give empty extension and copy rest of string
  428. // into fname.
  429. if (fname) {
  430. len = (USHORT) __min((p - path), (_MAX_FNAME - 1));
  431. lstrcpyn(fname, path, len + 1);
  432. fname[len] = TEXT('\0');
  433. }
  434. if (ext) {
  435. *ext = TEXT('\0');
  436. }
  437. }
  438. } // lsplitpath
  439. /////////////////////////////////////////////////////////////////////////
  440. VOID
  441. lmakepath(
  442. TCHAR *path,
  443. const TCHAR *drive,
  444. const TCHAR *dir,
  445. const TCHAR *fname,
  446. const TCHAR *ext
  447. )
  448. /*++
  449. Routine Description:
  450. create a path name from its individual components.
  451. Arguments:
  452. char *path - pointer to buffer for constructed path
  453. char *drive - pointer to drive component, may or may not contain
  454. trailing ':'
  455. char *dir - pointer to subdirectory component, may or may not include
  456. leading and/or trailing '/' or '\' characters
  457. char *fname - pointer to file base name component
  458. char *ext - pointer to extension component, may or may not contain
  459. a leading '.'.
  460. Return Value:
  461. path - pointer to constructed path name
  462. --*/
  463. {
  464. const TCHAR *p;
  465. /*+---------------------------------------------------------------------+
  466. | we assume that the arguments are in the following form (although we |
  467. | do not diagnose invalid arguments or illegal filenames (such as |
  468. | names longer than 8.3 or with illegal characters in them) |
  469. | |
  470. | drive: |
  471. | A or A: |
  472. | dir: |
  473. | \top\next\last\ ; or |
  474. | /top/next/last/ ; or |
  475. | |
  476. | either of the above forms with either/both the leading and |
  477. | trailing / or \ removed. Mixed use of '/' and '\' is also |
  478. | tolerated |
  479. | fname: |
  480. | any valid file name |
  481. | ext: |
  482. | any valid extension (none if empty or null ) |
  483. +---------------------------------------------------------------------+*/
  484. // copy drive
  485. if (drive && *drive)
  486. while (*drive)
  487. *path++ = *drive++;
  488. // copy dir
  489. if ((p = dir) && *p) {
  490. do {
  491. *path++ = *p++;
  492. }
  493. while (*p);
  494. if ((*(p-1) != TEXT('/')) && (*(p-1) != TEXT('\\'))) {
  495. *path++ = TEXT('\\');
  496. }
  497. }
  498. // copy fname
  499. if (p = fname) {
  500. while (*p) {
  501. *path++ = *p++;
  502. }
  503. }
  504. // copy ext, including 0-terminator - check to see if a '.' needs to be
  505. // inserted.
  506. if (p = ext) {
  507. if (*p && *p != TEXT('.')) {
  508. *path++ = TEXT('.');
  509. }
  510. while (*path++ = *p++)
  511. ;
  512. }
  513. else {
  514. // better add the 0-terminator
  515. *path = TEXT('\0');
  516. }
  517. } // lmakepath
  518. #ifndef _UNICODE
  519. #error "Function below not DBCS safe"
  520. #endif
  521. VOID
  522. EscapeFormattingChars(
  523. LPTSTR String,
  524. ULONG BufferLength
  525. )
  526. /*++
  527. Routine Description:
  528. Escapes any formatting chars (ie. % chars) in the string so
  529. if you sprintf it, you dont trap out as a result of trying to
  530. access bogus stack data.
  531. Arguments:
  532. String - String to fix up. Escaping is done IN PLACE.
  533. BufferLength - Size of the buffer the string is in. We need to know
  534. this since we are inserting characters. BufferLength is in
  535. characters, not bytes.
  536. Return Value:
  537. None
  538. --*/
  539. {
  540. ULONG Length; LONG Avail ;
  541. LPTSTR End, Tmp = String ;
  542. if (!Tmp)
  543. return ;
  544. Length = lstrlen(String) ;
  545. //
  546. // Point past end of string. We use this to figure out
  547. // via pointer substraction how much needs to be shifted
  548. // down as we insert chars.
  549. //
  550. End = Tmp + Length + 1 ;
  551. //
  552. // How much is avail for escape chars
  553. //
  554. Avail = BufferLength - (Length+1) ;
  555. while (*Tmp) {
  556. if (*Tmp == TEXT('%')) {
  557. //
  558. // If no more space, just change to '_'.
  559. //
  560. if (Avail <= 0) {
  561. *Tmp = TEXT('_') ;
  562. }
  563. else {
  564. //
  565. // Move string over and add escape character.
  566. // This is not very efficient but we assume
  567. // that this is not common.
  568. //
  569. --Avail ;
  570. memmove(Tmp+1,
  571. Tmp,
  572. (UINT) (End - Tmp)) ;
  573. *Tmp = TEXT('%') ;
  574. Tmp++ ;
  575. }
  576. }
  577. ++Tmp ;
  578. }
  579. }