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.

582 lines
17 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. if (LenBytes > MAXUSHORT){
  381. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRetreiveMessageText: Lenth of ANSI to Unicode convert string too big (%u)\n",LenBytes));
  382. return(NULL);
  383. }
  384. }
  385. //
  386. // If the caller gave a buffer, check its size.
  387. // Otherwise, allocate a buffer.
  388. //
  389. if(MessageText) {
  390. if(MessageTextBufferSize < LenBytes) {
  391. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpRetreiveMessageText: buffer is too small (%u bytes, need %u)\n",MessageTextBufferSize,LenBytes));
  392. return(NULL);
  393. }
  394. } else {
  395. MessageText = SpMemAlloc(LenBytes);
  396. if(MessageText == NULL) {
  397. return(NULL);
  398. }
  399. }
  400. if(IsUnicode) {
  401. //
  402. // Message is already unicode; just copy it into the buffer.
  403. //
  404. wcscpy(MessageText,(PWSTR)MessageEntry->Text);
  405. } else {
  406. //
  407. // Message is not unicode; convert in into the buffer.
  408. //
  409. UnicodeString.Buffer = MessageText;
  410. UnicodeString.Length = 0;
  411. UnicodeString.MaximumLength = (USHORT)LenBytes;
  412. RtlAnsiStringToUnicodeString(
  413. &UnicodeString,
  414. &AnsiString,
  415. FALSE
  416. );
  417. }
  418. return(MessageText);
  419. }
  420. VOID
  421. vSpFormatMessageText(
  422. OUT PVOID LargeBuffer,
  423. IN ULONG BufferSize,
  424. IN PWSTR MessageText,
  425. OUT PULONG ReturnLength, OPTIONAL
  426. IN va_list *arglist
  427. )
  428. {
  429. NTSTATUS Status;
  430. Status = SpRtlFormatMessage(
  431. MessageText,
  432. 0, // don't bother with maximum width
  433. FALSE, // don't ignore inserts
  434. FALSE, // args are unicode
  435. FALSE, // args are not an array
  436. arglist,
  437. LargeBuffer,
  438. BufferSize,
  439. ReturnLength
  440. );
  441. ASSERT(NT_SUCCESS(Status));
  442. }
  443. VOID
  444. SpFormatMessageText(
  445. OUT PVOID LargeBuffer,
  446. IN ULONG BufferSize,
  447. IN PWSTR MessageText,
  448. ...
  449. )
  450. {
  451. va_list arglist;
  452. va_start(arglist,MessageText);
  453. vSpFormatMessageText(LargeBuffer,BufferSize,MessageText,NULL,&arglist);
  454. va_end(arglist);
  455. }
  456. VOID
  457. vSpFormatMessage(
  458. OUT PVOID LargeBuffer,
  459. IN ULONG BufferSize,
  460. IN ULONG MessageId,
  461. OUT PULONG ReturnLength, OPTIONAL
  462. IN va_list *arglist
  463. )
  464. {
  465. PWCHAR MessageText;
  466. //
  467. // Get the message text.
  468. //
  469. MessageText = SpRetreiveMessageText(NULL,MessageId,NULL,0);
  470. ASSERT(MessageText);
  471. if(MessageText == NULL) {
  472. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: vSpFormatMessage: SpRetreiveMessageText %u returned NULL\n",MessageId));
  473. return;
  474. }
  475. vSpFormatMessageText(LargeBuffer,BufferSize,MessageText,ReturnLength,arglist);
  476. SpMemFree(MessageText);
  477. }
  478. VOID
  479. SpFormatMessage(
  480. OUT PVOID LargeBuffer,
  481. IN ULONG BufferSize,
  482. IN ULONG MessageId,
  483. ...
  484. )
  485. {
  486. va_list arglist;
  487. va_start(arglist,MessageId);
  488. vSpFormatMessage(LargeBuffer,BufferSize,MessageId,NULL,&arglist);
  489. va_end(arglist);
  490. }