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.

577 lines
16 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spdsputl.c
  5. Abstract:
  6. Text setup high-level display utility routines.
  7. Author:
  8. Ted Miller (tedm) 30-July-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #pragma hdrstop
  13. //
  14. // This will be filled in at init time with the base address of the image
  15. // containing the message resources.
  16. // This implementation assumes that we are always executing in the context
  17. // of that image!
  18. //
  19. PVOID ResourceImageBase;
  20. NTSTATUS
  21. SpRtlFormatMessage(
  22. IN PWSTR MessageFormat,
  23. IN ULONG MaximumWidth OPTIONAL,
  24. IN BOOLEAN IgnoreInserts,
  25. IN BOOLEAN ArgumentsAreAnsi,
  26. IN BOOLEAN ArgumentsAreAnArray,
  27. IN va_list *Arguments,
  28. OUT PWSTR Buffer,
  29. IN ULONG Length,
  30. OUT PULONG ReturnLength OPTIONAL
  31. )
  32. {
  33. ULONG Column;
  34. int cchRemaining, cchWritten;
  35. PULONG_PTR ArgumentsArray = (PULONG_PTR)Arguments;
  36. ULONG_PTR rgInserts[ 100 ];
  37. ULONG cSpaces;
  38. ULONG MaxInsert, CurInsert;
  39. ULONG PrintParameterCount;
  40. ULONG_PTR PrintParameter1;
  41. ULONG_PTR PrintParameter2;
  42. WCHAR PrintFormatString[ 32 ];
  43. WCHAR c;
  44. PWSTR s, s1;
  45. PWSTR lpDst, lpDstBeg, lpDstLastSpace;
  46. cchRemaining = Length / sizeof( WCHAR );
  47. lpDst = Buffer;
  48. MaxInsert = 0;
  49. lpDstLastSpace = NULL;
  50. Column = 0;
  51. s = MessageFormat;
  52. while (*s != UNICODE_NULL) {
  53. if (*s == L'%') {
  54. s++;
  55. lpDstBeg = lpDst;
  56. if (*s >= L'1' && *s <= L'9') {
  57. CurInsert = *s++ - L'0';
  58. if (*s >= L'0' && *s <= L'9') {
  59. CurInsert = (CurInsert * 10) + (*s++ - L'0');
  60. }
  61. CurInsert -= 1;
  62. PrintParameterCount = 0;
  63. if (*s == L'!') {
  64. s1 = PrintFormatString;
  65. *s1++ = L'%';
  66. s++;
  67. while (*s != L'!') {
  68. if (*s != UNICODE_NULL) {
  69. if (s1 >= &PrintFormatString[ 31 ]) {
  70. return( STATUS_INVALID_PARAMETER );
  71. }
  72. if (*s == L'*') {
  73. if (PrintParameterCount++ > 1) {
  74. return( STATUS_INVALID_PARAMETER );
  75. }
  76. }
  77. *s1++ = *s++;
  78. }
  79. else {
  80. return( STATUS_INVALID_PARAMETER );
  81. }
  82. }
  83. s++;
  84. *s1 = UNICODE_NULL;
  85. }
  86. else {
  87. wcscpy( PrintFormatString, L"%s" );
  88. s1 = PrintFormatString + wcslen( PrintFormatString );
  89. }
  90. if (!IgnoreInserts && ARGUMENT_PRESENT( Arguments )) {
  91. if (ArgumentsAreAnsi) {
  92. if (s1[ -1 ] == L'c' && s1[ -2 ] != L'h'
  93. && s1[ -2 ] != L'w' && s1[ -2 ] != L'l') {
  94. wcscpy( &s1[ -1 ], L"hc" );
  95. }
  96. else
  97. if (s1[ -1 ] == L's' && s1[ -2 ] != L'h'
  98. && s1[ -2 ] != L'w' && s1[ -2 ] != L'l') {
  99. wcscpy( &s1[ -1 ], L"hs" );
  100. }
  101. else if (s1[ -1 ] == L'S') {
  102. s1[ -1 ] = L's';
  103. }
  104. else if (s1[ -1 ] == L'C') {
  105. s1[ -1 ] = L'c';
  106. }
  107. }
  108. while (CurInsert >= MaxInsert) {
  109. if (ArgumentsAreAnArray) {
  110. rgInserts[ MaxInsert++ ] = *((PULONG_PTR)Arguments)++;
  111. }
  112. else {
  113. rgInserts[ MaxInsert++ ] = va_arg(*Arguments, ULONG_PTR);
  114. }
  115. }
  116. s1 = (PWSTR)rgInserts[ CurInsert ];
  117. PrintParameter1 = 0;
  118. PrintParameter2 = 0;
  119. if (PrintParameterCount > 0) {
  120. if (ArgumentsAreAnArray) {
  121. PrintParameter1 = rgInserts[ MaxInsert++ ] = *((PULONG_PTR)Arguments)++;
  122. }
  123. else {
  124. PrintParameter1 = rgInserts[ MaxInsert++ ] = va_arg( *Arguments, ULONG_PTR );
  125. }
  126. if (PrintParameterCount > 1) {
  127. if (ArgumentsAreAnArray) {
  128. PrintParameter2 = rgInserts[ MaxInsert++ ] = *((PULONG_PTR)Arguments)++;
  129. }
  130. else {
  131. PrintParameter2 = rgInserts[ MaxInsert++ ] = va_arg( *Arguments, ULONG_PTR );
  132. }
  133. }
  134. }
  135. cchWritten = _snwprintf( lpDst,
  136. cchRemaining,
  137. PrintFormatString,
  138. s1,
  139. PrintParameter1,
  140. PrintParameter2
  141. );
  142. }
  143. else
  144. if (!wcscmp( PrintFormatString, L"%s" )) {
  145. cchWritten = _snwprintf( lpDst,
  146. cchRemaining,
  147. L"%%%u",
  148. CurInsert+1
  149. );
  150. }
  151. else {
  152. cchWritten = _snwprintf( lpDst,
  153. cchRemaining,
  154. L"%%%u!%s!",
  155. CurInsert+1,
  156. &PrintFormatString[ 1 ]
  157. );
  158. }
  159. if ((cchRemaining -= cchWritten) <= 0) {
  160. return STATUS_BUFFER_OVERFLOW;
  161. }
  162. lpDst += cchWritten;
  163. }
  164. else
  165. if (*s == L'0') {
  166. break;
  167. }
  168. else
  169. if (!*s) {
  170. return( STATUS_INVALID_PARAMETER );
  171. }
  172. else
  173. if (*s == L'!') {
  174. if ((cchRemaining -= 1) <= 0) {
  175. return STATUS_BUFFER_OVERFLOW;
  176. }
  177. *lpDst++ = L'!';
  178. s++;
  179. }
  180. else
  181. if (*s == L't') {
  182. if ((cchRemaining -= 1) <= 0) {
  183. return STATUS_BUFFER_OVERFLOW;
  184. }
  185. if (Column % 8) {
  186. Column = (Column + 7) & ~7;
  187. }
  188. else {
  189. Column += 8;
  190. }
  191. lpDstLastSpace = lpDst;
  192. *lpDst++ = L'\t';
  193. s++;
  194. }
  195. else
  196. if (*s == L'b') {
  197. if ((cchRemaining -= 1) <= 0) {
  198. return STATUS_BUFFER_OVERFLOW;
  199. }
  200. lpDstLastSpace = lpDst;
  201. *lpDst++ = L' ';
  202. s++;
  203. }
  204. else
  205. if (*s == L'r') {
  206. if ((cchRemaining -= 1) <= 0) {
  207. return STATUS_BUFFER_OVERFLOW;
  208. }
  209. *lpDst++ = L'\r';
  210. s++;
  211. lpDstBeg = NULL;
  212. }
  213. else
  214. if (*s == L'n') {
  215. if ((cchRemaining -= 2) <= 0) {
  216. return STATUS_BUFFER_OVERFLOW;
  217. }
  218. *lpDst++ = L'\r';
  219. *lpDst++ = L'\n';
  220. s++;
  221. lpDstBeg = NULL;
  222. }
  223. else {
  224. if ((cchRemaining -= 1) <= 0) {
  225. return STATUS_BUFFER_OVERFLOW;
  226. }
  227. if (IgnoreInserts) {
  228. if ((cchRemaining -= 1) <= 0) {
  229. return STATUS_BUFFER_OVERFLOW;
  230. }
  231. *lpDst++ = L'%';
  232. }
  233. *lpDst++ = *s++;
  234. }
  235. if (lpDstBeg == NULL) {
  236. lpDstLastSpace = NULL;
  237. Column = 0;
  238. }
  239. else {
  240. Column += (ULONG)(lpDst - lpDstBeg);
  241. }
  242. }
  243. else {
  244. c = *s++;
  245. if (c == L'\r' || c == L'\n') {
  246. if (c == L'\r' && *s == L'\n') {
  247. s++;
  248. }
  249. if (MaximumWidth != 0) {
  250. lpDstLastSpace = lpDst;
  251. c = L' ';
  252. }
  253. else {
  254. c = L'\n';
  255. }
  256. }
  257. if (c == L'\n') {
  258. if ((cchRemaining -= 2) <= 0) {
  259. return STATUS_BUFFER_OVERFLOW;
  260. }
  261. *lpDst++ = L'\r';
  262. *lpDst++ = L'\n';
  263. lpDstLastSpace = NULL;
  264. Column = 0;
  265. }
  266. else {
  267. if ((cchRemaining -= 1) <= 0) {
  268. return STATUS_BUFFER_OVERFLOW;
  269. }
  270. if (c == L' ') {
  271. lpDstLastSpace = lpDst;
  272. }
  273. *lpDst++ = c;
  274. Column += 1;
  275. }
  276. }
  277. if (MaximumWidth != 0 &&
  278. MaximumWidth != 0xFFFFFFFF &&
  279. Column >= MaximumWidth
  280. ) {
  281. if (lpDstLastSpace != NULL) {
  282. lpDstBeg = lpDstLastSpace;
  283. while (*lpDstBeg == L' ' || *lpDstBeg == L'\t') {
  284. lpDstBeg += 1;
  285. if (lpDstBeg == lpDst) {
  286. break;
  287. }
  288. }
  289. while (lpDstLastSpace > Buffer) {
  290. if (lpDstLastSpace[ -1 ] == L' ' || lpDstLastSpace[ -1 ] == L'\t') {
  291. lpDstLastSpace -= 1;
  292. }
  293. else {
  294. break;
  295. }
  296. }
  297. cSpaces = (ULONG)(lpDstBeg - lpDstLastSpace);
  298. if (cSpaces == 1) {
  299. if ((cchRemaining -= 1) <= 0) {
  300. return STATUS_BUFFER_OVERFLOW;
  301. }
  302. }
  303. else
  304. if (cSpaces > 2) {
  305. cchRemaining += (cSpaces - 2);
  306. }
  307. memmove( lpDstLastSpace + 2,
  308. lpDstBeg,
  309. (size_t)((lpDst - lpDstBeg) * sizeof( WCHAR ))
  310. );
  311. *lpDstLastSpace++ = L'\r';
  312. *lpDstLastSpace++ = L'\n';
  313. Column = (ULONG)(lpDst - lpDstBeg);
  314. lpDst = lpDstLastSpace + Column;
  315. lpDstLastSpace = NULL;
  316. }
  317. else {
  318. if ((cchRemaining -= 2) <= 0) {
  319. return STATUS_BUFFER_OVERFLOW;
  320. }
  321. *lpDst++ = L'\r';
  322. *lpDst++ = L'\n';
  323. lpDstLastSpace = NULL;
  324. Column = 0;
  325. }
  326. }
  327. }
  328. if ((cchRemaining -= 1) <= 0) {
  329. return STATUS_BUFFER_OVERFLOW;
  330. }
  331. *lpDst++ = '\0';
  332. if ( ARGUMENT_PRESENT(ReturnLength) ) {
  333. *ReturnLength = (ULONG)((lpDst - Buffer) * sizeof( WCHAR ));
  334. }
  335. return( STATUS_SUCCESS );
  336. }
  337. PWCHAR
  338. SpRetreiveMessageText(
  339. IN PVOID ImageBase, OPTIONAL
  340. IN ULONG MessageId,
  341. IN OUT PWCHAR MessageText, OPTIONAL
  342. IN ULONG MessageTextBufferSize OPTIONAL
  343. )
  344. {
  345. ULONG LenBytes;
  346. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  347. BOOLEAN IsUnicode;
  348. ANSI_STRING AnsiString;
  349. UNICODE_STRING UnicodeString;
  350. NTSTATUS Status;
  351. Status = RtlFindMessage(
  352. ImageBase ? ImageBase : ResourceImageBase,
  353. (ULONG)(ULONG_PTR)RT_MESSAGETABLE,
  354. 0,
  355. MessageId,
  356. &MessageEntry
  357. );
  358. if(!NT_SUCCESS(Status)) {
  359. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Can't find message 0x%lx\n",MessageId));
  360. return(NULL);
  361. }
  362. IsUnicode = (BOOLEAN)((MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE) != 0);
  363. //
  364. // Get the size in bytes of a buffer large enough to hold the
  365. // message and its terminating nul wchar. If the message is
  366. // unicode, then this value is equal to the size of the message.
  367. // If the message is not unicode, then we have to calculate this value.
  368. //
  369. if(IsUnicode) {
  370. LenBytes = (wcslen((PWSTR)MessageEntry->Text) + 1) * sizeof(WCHAR);
  371. } else {
  372. //
  373. // RtlAnsiStringToUnicodeSize includes an implied wide-nul terminator
  374. // in the count it returns.
  375. //
  376. AnsiString.Buffer = MessageEntry->Text;
  377. AnsiString.Length = (USHORT)strlen(MessageEntry->Text);
  378. AnsiString.MaximumLength = AnsiString.Length;
  379. LenBytes = RtlAnsiStringToUnicodeSize(&AnsiString);
  380. }
  381. //
  382. // If the caller gave a buffer, check its size.
  383. // Otherwise, allocate a buffer.
  384. //
  385. if(MessageText) {
  386. if(MessageTextBufferSize < LenBytes) {
  387. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRetreiveMessageText: buffer is too small (%u bytes, need %u)\n",MessageTextBufferSize,LenBytes));
  388. return(NULL);
  389. }
  390. } else {
  391. MessageText = SpMemAlloc(LenBytes);
  392. if(MessageText == NULL) {
  393. return(NULL);
  394. }
  395. }
  396. if(IsUnicode) {
  397. //
  398. // Message is already unicode; just copy it into the buffer.
  399. //
  400. wcscpy(MessageText,(PWSTR)MessageEntry->Text);
  401. } else {
  402. //
  403. // Message is not unicode; convert in into the buffer.
  404. //
  405. UnicodeString.Buffer = MessageText;
  406. UnicodeString.Length = 0;
  407. UnicodeString.MaximumLength = (USHORT)LenBytes;
  408. RtlAnsiStringToUnicodeString(
  409. &UnicodeString,
  410. &AnsiString,
  411. FALSE
  412. );
  413. }
  414. return(MessageText);
  415. }
  416. VOID
  417. vSpFormatMessageText(
  418. OUT PVOID LargeBuffer,
  419. IN ULONG BufferSize,
  420. IN PWSTR MessageText,
  421. OUT PULONG ReturnLength, OPTIONAL
  422. IN va_list *arglist
  423. )
  424. {
  425. NTSTATUS Status;
  426. Status = SpRtlFormatMessage(
  427. MessageText,
  428. 0, // don't bother with maximum width
  429. FALSE, // don't ignore inserts
  430. FALSE, // args are unicode
  431. FALSE, // args are not an array
  432. arglist,
  433. LargeBuffer,
  434. BufferSize,
  435. ReturnLength
  436. );
  437. ASSERT(NT_SUCCESS(Status));
  438. }
  439. VOID
  440. SpFormatMessageText(
  441. OUT PVOID LargeBuffer,
  442. IN ULONG BufferSize,
  443. IN PWSTR MessageText,
  444. ...
  445. )
  446. {
  447. va_list arglist;
  448. va_start(arglist,MessageText);
  449. vSpFormatMessageText(LargeBuffer,BufferSize,MessageText,NULL,&arglist);
  450. va_end(arglist);
  451. }
  452. VOID
  453. vSpFormatMessage(
  454. OUT PVOID LargeBuffer,
  455. IN ULONG BufferSize,
  456. IN ULONG MessageId,
  457. OUT PULONG ReturnLength, OPTIONAL
  458. IN va_list *arglist
  459. )
  460. {
  461. PWCHAR MessageText;
  462. //
  463. // Get the message text.
  464. //
  465. MessageText = SpRetreiveMessageText(NULL,MessageId,NULL,0);
  466. ASSERT(MessageText);
  467. if(MessageText == NULL) {
  468. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: vSpFormatMessage: SpRetreiveMessageText %u returned NULL\n",MessageId));
  469. return;
  470. }
  471. vSpFormatMessageText(LargeBuffer,BufferSize,MessageText,ReturnLength,arglist);
  472. SpMemFree(MessageText);
  473. }
  474. VOID
  475. SpFormatMessage(
  476. OUT PVOID LargeBuffer,
  477. IN ULONG BufferSize,
  478. IN ULONG MessageId,
  479. ...
  480. )
  481. {
  482. va_list arglist;
  483. va_start(arglist,MessageId);
  484. vSpFormatMessage(LargeBuffer,BufferSize,MessageId,NULL,&arglist);
  485. va_end(arglist);
  486. }