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.

726 lines
15 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. String.c
  5. Abstract:
  6. This module contains support for loading resource strings.
  7. Author:
  8. David J. Gilman (davegi) 11-Sep-1992
  9. Gregg R. Acheson (GreggA) 28-Feb-1994
  10. Environment:
  11. User Mode
  12. --*/
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include "wintools.h"
  17. #include <search.h>
  18. #include <string.h>
  19. INT
  20. StricmpW(
  21. IN LPCWSTR String1,
  22. IN LPCWSTR String2
  23. )
  24. /*++
  25. Routine Description:
  26. StricmpW performs a case insesitive string compare returning a result that
  27. is acceptable for WM_COMPAREITEM messages.
  28. Arguments:
  29. String1 - Supplies the first string to compare.
  30. String2 - Supplies the second string to compare.
  31. Return Value:
  32. INT - Returns:
  33. -1 String1 precedes String2 in the sorted order.
  34. 0 String1 and String2 are equivalent in the sorted order.
  35. 1 String1 follows String2 in the sorted order.
  36. --*/
  37. {
  38. INT Compare;
  39. Compare = _wcsicmp( String1, String2 );
  40. if ( Compare < 0 ) {
  41. return -1;
  42. } else if ( Compare > 0 ) {
  43. return 1;
  44. } else {
  45. return 0;
  46. }
  47. }
  48. LPCSTR
  49. GetStringA(
  50. IN UINT StringId
  51. )
  52. /*++
  53. Routine Description:
  54. GetStringA returns a pointer to the ANSI string corresponding to
  55. the supplied resource id.
  56. Arguments:
  57. StringId - Supplies a string resource id.
  58. Return Value:
  59. LPCWSTR - Returns a pointer to a static buffer that contains
  60. the ANSI string.
  61. --*/
  62. {
  63. int Length;
  64. static
  65. CHAR Buffer[ MAX_CHARS ];
  66. //
  67. // Load the requested string making sure that it succesfully loaded
  68. // and fit in the buffer.
  69. //
  70. Length = LoadStringA(
  71. NULL,
  72. StringId,
  73. Buffer,
  74. sizeof( Buffer )
  75. );
  76. DbgAssert( Length != 0 );
  77. DbgAssert( Length < sizeof( Buffer ));
  78. if (( Length == 0 ) || ( Length >= NumberOfCharacters( Buffer ))) {
  79. return NULL;
  80. }
  81. return Buffer;
  82. }
  83. LPCWSTR
  84. GetStringW(
  85. IN UINT StringId
  86. )
  87. /*++
  88. Routine Description:
  89. GetStringW returns a pointer to the Unicode string corresponding to
  90. the supplied resource id.
  91. Arguments:
  92. StringId - Supplies a string resource id.
  93. Return Value:
  94. LPCWSTR - Returns a pointer to a static buffer that contains
  95. the Unicode string.
  96. --*/
  97. {
  98. int Length;
  99. static
  100. WCHAR Buffer[ MAX_CHARS ];
  101. //
  102. // Load the requested string making sure that it succesfully loaded
  103. // and fit in the buffer.
  104. //
  105. Length = LoadStringW(
  106. NULL,
  107. StringId,
  108. Buffer,
  109. sizeof( Buffer )
  110. );
  111. DbgAssert( Length != 0 );
  112. DbgAssert( Length < sizeof( Buffer ));
  113. if (( Length == 0 ) || ( Length >= NumberOfCharacters( Buffer ))) {
  114. return NULL;
  115. }
  116. return Buffer;
  117. }
  118. LPWSTR
  119. FormatLargeIntegerW(
  120. IN PLARGE_INTEGER Value,
  121. IN BOOL Signed
  122. )
  123. /*++
  124. Routine Description:
  125. Converts a large integer to a string inserting thousands separators
  126. as appropriate.
  127. Arguments:
  128. LargeInteger - Supplies the number to be formatted.
  129. Signed - Supplies a flag which if TRUE indicates that the supplied
  130. value is a signed number.
  131. Return Value:
  132. LPWSTR - Returns a pointer to the formatted string.
  133. --*/
  134. {
  135. static
  136. CHAR pIntegerChars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
  137. static
  138. WCHAR Buffer[ MAX_PATH ];
  139. WCHAR SThousand[ MAX_PATH ];
  140. DWORD SThousandChars;
  141. int Index;
  142. DWORD Count;
  143. WCHAR wString[ MAX_PATH ];
  144. CHAR aString[ MAX_PATH ];
  145. LONG OutputLength = 95;
  146. CHAR Result[ 100 ], *s;
  147. ULONG Shift, Digit;
  148. LONG_PTR Length;
  149. LARGE_INTEGER TempValue=*Value;
  150. //
  151. // Convert the Large Integer to a UNICODE string
  152. //
  153. Shift = 0;
  154. s = &Result[ 99 ];
  155. *s = '\0';
  156. do {
  157. TempValue = RtlExtendedLargeIntegerDivide(TempValue,10L,&Digit);
  158. *--s = pIntegerChars[ Digit ];
  159. } while (TempValue.HighPart != 0 || TempValue.LowPart != 0);
  160. Length = &Result[ 99 ] - s;
  161. if (OutputLength < 0) {
  162. OutputLength = -OutputLength;
  163. while ((LONG)Length < OutputLength) {
  164. *--s = '0';
  165. Length++;
  166. }
  167. }
  168. if ((LONG)Length > OutputLength) {
  169. return NULL;
  170. } else {
  171. RtlMoveMemory( aString, s, Length );
  172. if ((LONG)Length < OutputLength) {
  173. aString[ Length ] = '\0';
  174. }
  175. }
  176. //
  177. // Convert to UNICODE
  178. //
  179. Length = wsprintf( wString, L"%S", aString );
  180. //
  181. // Get the thousand separator for this locale.
  182. //
  183. SThousandChars = GetLocaleInfoW(
  184. LOCALE_USER_DEFAULT,
  185. LOCALE_STHOUSAND,
  186. SThousand,
  187. NumberOfCharacters( SThousand )
  188. );
  189. DbgAssert( SThousandChars != 0 );
  190. if ( SThousandChars == 0 ) {
  191. return NULL;
  192. }
  193. DbgAssert( Length < NumberOfCharacters( Buffer ));
  194. Index = NumberOfCharacters( Buffer ) - 1;
  195. Count = 0;
  196. //
  197. // Copy the NUL character.
  198. //
  199. Buffer[ Index-- ] = wString[ Length-- ];
  200. //
  201. // Copy the string in reverse order, inserting the thousands separator
  202. // every three characters.
  203. //
  204. while ( Length >= 0L ) {
  205. Buffer[ Index-- ] = wString[ Length-- ];
  206. Count++;
  207. //
  208. // Protect against leading separators by making sure that the last
  209. // digit wasn't just copied.
  210. //
  211. if (( Count == 3 ) && ( Length >= 0L )) {
  212. //
  213. // Adjust the index by the length of the thousands separator less 2
  214. // - one for the NUL and one because the index was already backed
  215. // up by one above.
  216. //
  217. Index -= SThousandChars - 2;
  218. wcsncpy( &Buffer[ Index ], SThousand, SThousandChars - 1 );
  219. Index--;
  220. Count = 0;
  221. }
  222. }
  223. //
  224. // Move the string to the beginning of the buffer (use MoveMemory to
  225. // handle overlaps).
  226. //
  227. MoveMemory(
  228. Buffer,
  229. &Buffer[ Index + 1 ],
  230. ( wcslen( &Buffer[ Index + 1 ]) + 1) * sizeof( WCHAR )
  231. );
  232. return Buffer;
  233. }
  234. LPWSTR
  235. FormatBigIntegerW(
  236. IN DWORD BigInteger,
  237. IN BOOL Signed
  238. )
  239. /*++
  240. Routine Description:
  241. Converts an integer to a string inserting thousands separators
  242. as appropriate.
  243. Arguments:
  244. BigInteger - Supplies the number to be formatted.
  245. Signed - Supplies a flag which if TRUE indicates that the supplied
  246. value is a signed number.
  247. Return Value:
  248. LPWSTR - Returns a pointer to the formatted string.
  249. --*/
  250. {
  251. WCHAR Buffer1[ MAX_PATH ];
  252. WCHAR SThousand[ MAX_PATH ];
  253. DWORD SThousandChars;
  254. int Index1;
  255. int Index;
  256. DWORD Count;
  257. static
  258. WCHAR Buffer[ MAX_PATH ];
  259. //
  260. // Get the thousand separator for this locale.
  261. //
  262. SThousandChars = GetLocaleInfoW(
  263. LOCALE_USER_DEFAULT,
  264. LOCALE_STHOUSAND,
  265. SThousand,
  266. NumberOfCharacters( SThousand )
  267. );
  268. DbgAssert( SThousandChars != 0 );
  269. if ( SThousandChars == 0 ) {
  270. return NULL;
  271. }
  272. //
  273. // Convert the number to a string.
  274. //
  275. Index1 = wsprintf( Buffer1, ( Signed ) ? L"%d" : L"%u", BigInteger );
  276. DbgAssert( Index1 < NumberOfCharacters( Buffer ));
  277. Index = NumberOfCharacters( Buffer ) - 1;
  278. Count = 0;
  279. //
  280. // Copy the NUL character.
  281. //
  282. Buffer[ Index-- ] = Buffer1[ Index1-- ];
  283. //
  284. // Copy the string in reverse order, inserting the thousands separator
  285. // every three characters.
  286. //
  287. while ( Index1 >= 0 ) {
  288. Buffer[ Index-- ] = Buffer1[ Index1-- ];
  289. Count++;
  290. //
  291. // Protect against leading separators by making sure that the last
  292. // digit wasn't just copied.
  293. //
  294. if (( Count == 3 ) && ( Index1 >= 0 )) {
  295. //
  296. // Adjust the index by the length of the thousands separator less 2
  297. // - one for the NUL and one because the index was already backed
  298. // up by one above.
  299. //
  300. Index -= SThousandChars - 2;
  301. wcsncpy( &Buffer[ Index ], SThousand, SThousandChars - 1 );
  302. Index--;
  303. Count = 0;
  304. }
  305. }
  306. //
  307. // Move the string to the beginning of the buffer (use MoveMemory to
  308. // handle overlaps).
  309. //
  310. MoveMemory(
  311. Buffer,
  312. &Buffer[ Index + 1 ],
  313. ( wcslen( &Buffer[ Index + 1 ]) + 1) * sizeof( WCHAR )
  314. );
  315. return Buffer;
  316. }
  317. DWORD
  318. WFormatMessageA(
  319. IN LPSTR Buffer,
  320. IN DWORD BufferSize,
  321. IN UINT FormatId,
  322. IN ...
  323. )
  324. /*++
  325. Routine Description:
  326. Format a printf style string and place it the supplied ANSI buffer.
  327. Arguments:
  328. Buffer - Supplies a pointer to a buffer where the formatted string
  329. will be stored.
  330. BufferSize - Supplies the number of bytes in the supplied buffer.
  331. FormatId - Supplies a resource id for a printf style format string.
  332. ... - Supplies zero or more values based on the format
  333. descpritors supplied in Format.
  334. Return Value:
  335. DWORD _ Returns the number of bytes stored in the supplied buffer.
  336. --*/
  337. {
  338. DWORD Count;
  339. va_list Args;
  340. DbgPointerAssert( Buffer );
  341. //
  342. // Retrieve the values and format the string.
  343. //
  344. va_start( Args, FormatId );
  345. Count = FormatMessageA(
  346. FORMAT_MESSAGE_FROM_HMODULE,
  347. NULL,
  348. FormatId,
  349. 0,
  350. Buffer,
  351. BufferSize,
  352. &Args
  353. );
  354. DbgAssert( Count != 0 );
  355. va_end( Args );
  356. return Count;
  357. }
  358. DWORD
  359. WFormatMessageW(
  360. IN LPWSTR Buffer,
  361. IN DWORD BufferSize,
  362. IN UINT FormatId,
  363. IN ...
  364. )
  365. /*++
  366. Routine Description:
  367. Format a printf style string and place it the supplied Unicode buffer.
  368. Arguments:
  369. Buffer - Supplies a pointer to a buffer where the formatted string
  370. will be stored.
  371. BufferSize - Supplies the number of bytes in the supplied buffer.
  372. FormatId - Supplies a resource id for a printf style format string.
  373. ... - Supplies zero or more values based on the format
  374. descpritors supplied in Format.
  375. Return Value:
  376. DWORD _ Returns the number of bytes stored in the supplied buffer.
  377. --*/
  378. {
  379. DWORD Count;
  380. va_list Args;
  381. DbgPointerAssert( Buffer );
  382. //
  383. // Retrieve the values and format the string.
  384. //
  385. va_start( Args, FormatId );
  386. Count = FormatMessageW(
  387. FORMAT_MESSAGE_FROM_HMODULE,
  388. NULL,
  389. FormatId,
  390. 0,
  391. Buffer,
  392. BufferSize,
  393. &Args
  394. );
  395. DbgAssert( Count != 0 );
  396. va_end( Args );
  397. return Count;
  398. }
  399. int
  400. __cdecl
  401. CompareTableEntries(
  402. IN const void* TableEntry1,
  403. IN const void* TableEntry2
  404. )
  405. /*++
  406. Routine Description:
  407. Compare the key portion of two STRING_TABLE_ENTRY objects in order to
  408. determine if a match was found. This routine is used as a callback function
  409. for the CRT lfind() function.
  410. Arguments:
  411. TableEntry1 - Supplies a pointer to the first STRING_TABLE_ENTRY object
  412. whose Key is use in the comparison.
  413. TableEntry1 - Supplies a pointer to the second STRING_TABLE_ENTRY object
  414. whose Key is use in the comparison.
  415. Return Value:
  416. int - Returns:
  417. < 0 TableEntry1 less than TableEntry2
  418. = 0 TableEntry1 identical to TableEntry2
  419. > 0 TableEntry1 greater than TableEntry2
  420. --*/
  421. {
  422. return( ((( LPSTRING_TABLE_ENTRY ) TableEntry1 )->Key.LowPart
  423. ^ (( LPSTRING_TABLE_ENTRY ) TableEntry2 )->Key.LowPart )
  424. | ((( LPSTRING_TABLE_ENTRY ) TableEntry1 )->Key.HighPart
  425. ^ (( LPSTRING_TABLE_ENTRY ) TableEntry2 )->Key.HighPart ));
  426. }
  427. LPSTRING_TABLE_ENTRY
  428. SearchStringTable(
  429. IN LPSTRING_TABLE_ENTRY StringTable,
  430. IN DWORD Count,
  431. IN int Class,
  432. IN DWORD Value
  433. )
  434. /*++
  435. Routine Description:
  436. SearchStringTable searches the supplied table of STRING_TABLE_ENTRY objects
  437. looking for a match based on the supplied Class and Value.
  438. Arguments:
  439. StringTable - Supplies a table of STRING_TABLE_ENTRY objects that should
  440. be searched.
  441. Count - Supplies the number of entries in the StringTable.
  442. Class - Supplies the class to be looked up.
  443. Value - Supplies the value within the class to be looked up.
  444. Return Value:
  445. LPSTRING_TABLE_ENTRY - Returns a pointer to the STRING_TABLE_ENTRY if found,
  446. NULL otherwise.
  447. --*/
  448. {
  449. STRING_TABLE_ENTRY TableEntry;
  450. LPSTRING_TABLE_ENTRY Id;
  451. DbgPointerAssert( StringTable );
  452. //
  453. // Assume that entry will not be found.
  454. //
  455. Id = NULL;
  456. //
  457. // Set up the search criteria.
  458. //
  459. TableEntry.Key.LowPart = Value;
  460. TableEntry.Key.HighPart = Class;
  461. //
  462. // Do the search.
  463. //
  464. Id = _lfind(
  465. &TableEntry,
  466. StringTable,
  467. &Count,
  468. sizeof( STRING_TABLE_ENTRY ),
  469. CompareTableEntries
  470. );
  471. //
  472. // Return a pointer to the found entry.
  473. //
  474. return Id;
  475. }
  476. UINT
  477. GetStringId(
  478. IN LPSTRING_TABLE_ENTRY StringTable,
  479. IN DWORD Count,
  480. IN int Class,
  481. IN DWORD Value
  482. )
  483. /*++
  484. Routine Description:
  485. GetStringId returns the string resource id for the requested
  486. STRING_TABLE_ENTRY object.
  487. Arguments:
  488. StringTable - Supplies a table of STRING_TABLE_ENTRY objects that should
  489. be searched.
  490. Count - Supplies the number of entries in the StringTable.
  491. Class - Supplies the class to be looked up.
  492. Value - Supplies the value within the class to be looked up.
  493. Return Value:
  494. UINT - Returns the string resource id for the entry that matches
  495. the supplied Class and value.
  496. --*/
  497. {
  498. LPSTRING_TABLE_ENTRY Id;
  499. DbgPointerAssert( StringTable );
  500. Id = SearchStringTable(
  501. StringTable,
  502. Count,
  503. Class,
  504. Value
  505. );
  506. if (Id) {
  507. return( Id->Id);
  508. }
  509. else
  510. return 0;
  511. }