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.

1359 lines
53 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. _stream.h
  5. Abstract:
  6. Performance critical routine for Single Binary
  7. Each function will be created with two flavors FE and non FE
  8. Author:
  9. KazuM Jun.09.1997
  10. Revision History:
  11. --*/
  12. #define WWSB_NEUTRAL_FILE 1
  13. #if !defined(FE_SB)
  14. #error This header file should be included with FE_SB
  15. #endif
  16. #if !defined(WWSB_FE) && !defined(WWSB_NOFE)
  17. #error Either WWSB_FE and WWSB_NOFE must be defined.
  18. #endif
  19. #if defined(WWSB_FE) && defined(WWSB_NOFE)
  20. #error Both WWSB_FE and WWSB_NOFE defined.
  21. #endif
  22. #ifdef WWSB_FE
  23. #pragma alloc_text(FE_TEXT, FE_AdjustCursorPosition)
  24. #pragma alloc_text(FE_TEXT, FE_WriteChars)
  25. #pragma alloc_text(FE_TEXT, FE_DoWriteConsole)
  26. #pragma alloc_text(FE_TEXT, FE_DoSrvWriteConsole)
  27. #endif
  28. NTSTATUS
  29. WWSB_AdjustCursorPosition(
  30. IN PSCREEN_INFORMATION ScreenInfo,
  31. IN COORD CursorPosition,
  32. IN BOOL KeepCursorVisible,
  33. OUT PSHORT ScrollY OPTIONAL
  34. )
  35. /*++
  36. Routine Description:
  37. This routine updates the cursor position. Its input is the non-special
  38. cased new location of the cursor. For example, if the cursor were being
  39. moved one space backwards from the left edge of the screen, the X
  40. coordinate would be -1. This routine would set the X coordinate to
  41. the right edge of the screen and decrement the Y coordinate by one.
  42. Arguments:
  43. ScreenInfo - Pointer to screen buffer information structure.
  44. CursorPosition - New location of cursor.
  45. KeepCursorVisible - TRUE if changing window origin desirable when hit right edge
  46. Return Value:
  47. --*/
  48. {
  49. COORD WindowOrigin;
  50. NTSTATUS Status;
  51. #ifdef WWSB_FE
  52. PCONSOLE_INFORMATION Console = ScreenInfo->Console;
  53. if (!(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER))
  54. return STATUS_SUCCESS;
  55. #endif
  56. if (CursorPosition.X < 0) {
  57. if (CursorPosition.Y > 0) {
  58. CursorPosition.X = (SHORT)(ScreenInfo->ScreenBufferSize.X+CursorPosition.X);
  59. CursorPosition.Y = (SHORT)(CursorPosition.Y-1);
  60. }
  61. else {
  62. CursorPosition.X = 0;
  63. }
  64. }
  65. else if (CursorPosition.X >= ScreenInfo->ScreenBufferSize.X) {
  66. //
  67. // at end of line. if wrap mode, wrap cursor. otherwise leave it
  68. // where it is.
  69. //
  70. if (ScreenInfo->OutputMode & ENABLE_WRAP_AT_EOL_OUTPUT) {
  71. CursorPosition.Y += CursorPosition.X / ScreenInfo->ScreenBufferSize.X;
  72. CursorPosition.X = CursorPosition.X % ScreenInfo->ScreenBufferSize.X;
  73. }
  74. else {
  75. CursorPosition.X = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
  76. }
  77. }
  78. #ifdef WWSB_FE
  79. if (CursorPosition.Y >= ScreenInfo->ScreenBufferSize.Y &&
  80. !(Console->InputBuffer.ImeMode.Open)
  81. )
  82. #else
  83. if (CursorPosition.Y >= ScreenInfo->ScreenBufferSize.Y)
  84. #endif
  85. {
  86. //
  87. // at end of buffer. scroll contents of screen buffer so new
  88. // position is visible.
  89. //
  90. ASSERT (CursorPosition.Y == ScreenInfo->ScreenBufferSize.Y);
  91. StreamScrollRegion(ScreenInfo);
  92. if (ARGUMENT_PRESENT(ScrollY)) {
  93. *ScrollY += (SHORT)(ScreenInfo->ScreenBufferSize.Y - CursorPosition.Y - 1);
  94. }
  95. CursorPosition.Y += (SHORT)(ScreenInfo->ScreenBufferSize.Y - CursorPosition.Y - 1);
  96. }
  97. #ifdef WWSB_FE
  98. else if (!(Console->InputBuffer.ImeMode.Disable) && Console->InputBuffer.ImeMode.Open)
  99. {
  100. if (CursorPosition.Y == (ScreenInfo->ScreenBufferSize.Y-1)) {
  101. ConsoleImeBottomLineUse(ScreenInfo,2);
  102. if (ARGUMENT_PRESENT(ScrollY)) {
  103. *ScrollY += (SHORT)(ScreenInfo->ScreenBufferSize.Y - CursorPosition.Y - 2);
  104. }
  105. CursorPosition.Y += (SHORT)(ScreenInfo->ScreenBufferSize.Y - CursorPosition.Y - 2);
  106. if (!ARGUMENT_PRESENT(ScrollY) && Console->lpCookedReadData) {
  107. ((PCOOKED_READ_DATA)(Console->lpCookedReadData))->OriginalCursorPosition.Y--;
  108. }
  109. }
  110. else if (CursorPosition.Y == ScreenInfo->Window.Bottom) {
  111. ;
  112. }
  113. }
  114. #endif
  115. //
  116. // if at right or bottom edge of window, scroll right or down one char.
  117. //
  118. #ifdef WWSB_FE
  119. if (CursorPosition.Y > ScreenInfo->Window.Bottom &&
  120. !(Console->InputBuffer.ImeMode.Open)
  121. )
  122. #else
  123. if (CursorPosition.Y > ScreenInfo->Window.Bottom)
  124. #endif
  125. {
  126. WindowOrigin.X = 0;
  127. WindowOrigin.Y = CursorPosition.Y - ScreenInfo->Window.Bottom;
  128. Status = SetWindowOrigin(ScreenInfo,
  129. FALSE,
  130. WindowOrigin
  131. );
  132. if (!NT_SUCCESS(Status)) {
  133. return Status;
  134. }
  135. }
  136. #ifdef WWSB_FE
  137. else if (Console->InputBuffer.ImeMode.Open)
  138. {
  139. if (CursorPosition.Y >= ScreenInfo->Window.Bottom &&
  140. CONSOLE_WINDOW_SIZE_Y(ScreenInfo) > 1
  141. ) {
  142. WindowOrigin.X = 0;
  143. WindowOrigin.Y = CursorPosition.Y - ScreenInfo->Window.Bottom + 1;
  144. Status = SetWindowOrigin(ScreenInfo,
  145. FALSE,
  146. WindowOrigin
  147. );
  148. if (!NT_SUCCESS(Status)) {
  149. return Status;
  150. }
  151. }
  152. }
  153. #endif
  154. if (KeepCursorVisible) {
  155. MakeCursorVisible(ScreenInfo,CursorPosition);
  156. }
  157. Status = SetCursorPosition(ScreenInfo,
  158. CursorPosition,
  159. KeepCursorVisible
  160. );
  161. return Status;
  162. }
  163. #define LOCAL_BUFFER_SIZE 100
  164. NTSTATUS
  165. WWSB_WriteChars(
  166. IN PSCREEN_INFORMATION ScreenInfo,
  167. IN PWCHAR lpBufferBackupLimit,
  168. IN PWCHAR lpBuffer,
  169. IN PWCHAR lpRealUnicodeString,
  170. IN OUT PDWORD NumBytes,
  171. OUT PLONG NumSpaces OPTIONAL,
  172. IN SHORT OriginalXPosition,
  173. IN DWORD dwFlags,
  174. OUT PSHORT ScrollY OPTIONAL
  175. )
  176. /*++
  177. Routine Description:
  178. This routine writes a string to the screen, processing any embedded
  179. unicode characters. The string is also copied to the input buffer, if
  180. the output mode is line mode.
  181. Arguments:
  182. ScreenInfo - Pointer to screen buffer information structure.
  183. lpBufferBackupLimit - Pointer to beginning of buffer.
  184. lpBuffer - Pointer to buffer to copy string to. assumed to be at least
  185. as long as lpRealUnicodeString. This pointer is updated to point to the
  186. next position in the buffer.
  187. lpRealUnicodeString - Pointer to string to write.
  188. NumBytes - On input, number of bytes to write. On output, number of
  189. bytes written.
  190. NumSpaces - On output, the number of spaces consumed by the written characters.
  191. dwFlags -
  192. WC_DESTRUCTIVE_BACKSPACE backspace overwrites characters.
  193. WC_KEEP_CURSOR_VISIBLE change window origin desirable when hit rt. edge
  194. WC_ECHO if called by Read (echoing characters)
  195. WC_FALSIFY_UNICODE if RealUnicodeToFalseUnicode need be called.
  196. Return Value:
  197. Note:
  198. This routine does not process tabs and backspace properly. That code
  199. will be implemented as part of the line editing services.
  200. --*/
  201. {
  202. DWORD BufferSize;
  203. COORD CursorPosition;
  204. NTSTATUS Status;
  205. ULONG NumChars;
  206. static WCHAR Blanks[TAB_SIZE] = { UNICODE_SPACE,
  207. UNICODE_SPACE,
  208. UNICODE_SPACE,
  209. UNICODE_SPACE,
  210. UNICODE_SPACE,
  211. UNICODE_SPACE,
  212. UNICODE_SPACE,
  213. UNICODE_SPACE };
  214. SHORT XPosition;
  215. WCHAR LocalBuffer[LOCAL_BUFFER_SIZE];
  216. PWCHAR LocalBufPtr;
  217. ULONG i,j;
  218. SMALL_RECT Region;
  219. ULONG TabSize;
  220. DWORD TempNumSpaces;
  221. WCHAR Char;
  222. WCHAR RealUnicodeChar;
  223. WORD Attributes;
  224. PWCHAR lpString;
  225. PWCHAR lpAllocatedString;
  226. BOOL fUnprocessed = ((ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT) == 0);
  227. #ifdef WWSB_FE
  228. CHAR LocalBufferA[LOCAL_BUFFER_SIZE];
  229. PCHAR LocalBufPtrA;
  230. #endif
  231. ConsoleHideCursor(ScreenInfo);
  232. Attributes = ScreenInfo->Attributes;
  233. BufferSize = *NumBytes;
  234. *NumBytes = 0;
  235. TempNumSpaces = 0;
  236. lpAllocatedString = NULL;
  237. if (dwFlags & WC_FALSIFY_UNICODE) {
  238. // translation from OEM -> ANSI -> OEM doesn't
  239. // necessarily yield the same value, so do
  240. // translation in a separate buffer.
  241. lpString = ConsoleHeapAlloc(TMP_TAG, BufferSize);
  242. if (lpString == NULL) {
  243. Status = STATUS_NO_MEMORY;
  244. goto ExitWriteChars;
  245. }
  246. lpAllocatedString = lpString;
  247. RtlCopyMemory(lpString, lpRealUnicodeString, BufferSize);
  248. Status = RealUnicodeToFalseUnicode(lpString,
  249. BufferSize / sizeof(WCHAR),
  250. ScreenInfo->Console->OutputCP
  251. );
  252. if (!NT_SUCCESS(Status)) {
  253. goto ExitWriteChars;
  254. }
  255. } else {
  256. lpString = lpRealUnicodeString;
  257. }
  258. while (*NumBytes < BufferSize) {
  259. //
  260. // as an optimization, collect characters in buffer and
  261. // print out all at once.
  262. //
  263. XPosition = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
  264. i=0;
  265. LocalBufPtr = LocalBuffer;
  266. #ifdef WWSB_FE
  267. LocalBufPtrA = LocalBufferA;
  268. #endif
  269. while (*NumBytes < BufferSize &&
  270. i < LOCAL_BUFFER_SIZE &&
  271. XPosition < ScreenInfo->ScreenBufferSize.X) {
  272. Char = *lpString;
  273. RealUnicodeChar = *lpRealUnicodeString;
  274. if (!IS_GLYPH_CHAR(RealUnicodeChar) || fUnprocessed) {
  275. #ifdef WWSB_FE
  276. if (IsConsoleFullWidth(ScreenInfo->Console->hDC,
  277. ScreenInfo->Console->OutputCP,Char)) {
  278. if (i < (LOCAL_BUFFER_SIZE-1) &&
  279. XPosition < (ScreenInfo->ScreenBufferSize.X-1)) {
  280. *LocalBufPtr++ = Char;
  281. *LocalBufPtrA++ = ATTR_LEADING_BYTE;
  282. *LocalBufPtr++ = Char;
  283. *LocalBufPtrA++ = ATTR_TRAILING_BYTE;
  284. XPosition+=2;
  285. i+=2;
  286. lpBuffer++;
  287. }
  288. else
  289. goto EndWhile;
  290. }
  291. else {
  292. #endif
  293. *LocalBufPtr = Char;
  294. LocalBufPtr++;
  295. XPosition++;
  296. i++;
  297. lpBuffer++;
  298. #ifdef WWSB_FE
  299. *LocalBufPtrA++ = 0;
  300. }
  301. #endif
  302. } else {
  303. ASSERT(ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT);
  304. switch (RealUnicodeChar) {
  305. case UNICODE_BELL:
  306. if (dwFlags & WC_ECHO) {
  307. goto CtrlChar;
  308. } else {
  309. SendNotifyMessage(ScreenInfo->Console->hWnd,
  310. CM_BEEP,
  311. 0,
  312. 0x47474747);
  313. }
  314. break;
  315. case UNICODE_BACKSPACE:
  316. // automatically go to EndWhile. this is because
  317. // backspace is not destructive, so "aBkSp" prints
  318. // a with the cursor on the "a". we could achieve
  319. // this behavior staying in this loop and figuring out
  320. // the string that needs to be printed, but it would
  321. // be expensive and it's the exceptional case.
  322. goto EndWhile;
  323. break;
  324. case UNICODE_TAB:
  325. TabSize = NUMBER_OF_SPACES_IN_TAB(XPosition);
  326. XPosition = (SHORT)(XPosition + TabSize);
  327. if (XPosition >= ScreenInfo->ScreenBufferSize.X) {
  328. goto EndWhile;
  329. }
  330. for (j=0;j<TabSize && i<LOCAL_BUFFER_SIZE;j++,i++) {
  331. *LocalBufPtr = (WCHAR)' ';
  332. LocalBufPtr++;
  333. #ifdef WWSB_FE
  334. *LocalBufPtrA++ = 0;
  335. #endif
  336. }
  337. lpBuffer++;
  338. break;
  339. case UNICODE_LINEFEED:
  340. case UNICODE_CARRIAGERETURN:
  341. goto EndWhile;
  342. default:
  343. //
  344. // if char is ctrl char, write ^char.
  345. //
  346. if ((dwFlags & WC_ECHO) && (IS_CONTROL_CHAR(RealUnicodeChar))) {
  347. CtrlChar: if (i < (LOCAL_BUFFER_SIZE-1)) {
  348. *LocalBufPtr = (WCHAR)'^';
  349. LocalBufPtr++;
  350. XPosition++;
  351. i++;
  352. *LocalBufPtr = (WCHAR)(RealUnicodeChar+(WCHAR)'@');
  353. LocalBufPtr++;
  354. XPosition++;
  355. i++;
  356. lpBuffer++;
  357. #ifdef WWSB_FE
  358. *LocalBufPtrA++ = 0;
  359. *LocalBufPtrA++ = 0;
  360. #endif
  361. }
  362. else {
  363. goto EndWhile;
  364. }
  365. } else {
  366. if (!(ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) ||
  367. (ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
  368. /*
  369. * As a special favor to incompetent apps
  370. * that attempt to display control chars,
  371. * convert to corresponding OEM Glyph Chars
  372. */
  373. #ifdef WWSB_FE
  374. WORD CharType;
  375. GetStringTypeW(CT_CTYPE1,&RealUnicodeChar,1,&CharType);
  376. if (CharType == C1_CNTRL)
  377. ConvertOutputToUnicode(ScreenInfo->Console->OutputCP,
  378. &(char)RealUnicodeChar,
  379. 1,
  380. LocalBufPtr,
  381. 1);
  382. else
  383. *LocalBufPtr = Char;
  384. #else
  385. *LocalBufPtr = SB_CharToWcharGlyph(
  386. ScreenInfo->Console->OutputCP,
  387. (char)RealUnicodeChar);
  388. #endif
  389. } else {
  390. *LocalBufPtr = Char;
  391. }
  392. LocalBufPtr++;
  393. XPosition++;
  394. i++;
  395. lpBuffer++;
  396. #ifdef WWSB_FE
  397. *LocalBufPtrA++ = 0;
  398. #endif
  399. }
  400. }
  401. }
  402. lpString++;
  403. lpRealUnicodeString++;
  404. *NumBytes += sizeof(WCHAR);
  405. }
  406. EndWhile:
  407. if (i != 0) {
  408. //
  409. // Make sure we don't write past the end of the buffer.
  410. //
  411. if (i > (ULONG)ScreenInfo->ScreenBufferSize.X - ScreenInfo->BufferInfo.TextInfo.CursorPosition.X) {
  412. i = (ULONG)ScreenInfo->ScreenBufferSize.X - ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
  413. }
  414. #ifdef WWSB_FE
  415. FE_StreamWriteToScreenBuffer(LocalBuffer,
  416. (SHORT)i,
  417. ScreenInfo,
  418. LocalBufferA
  419. );
  420. #else
  421. SB_StreamWriteToScreenBuffer(LocalBuffer,
  422. (SHORT)i,
  423. ScreenInfo
  424. );
  425. #endif
  426. Region.Left = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
  427. Region.Right = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + i - 1);
  428. Region.Top = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  429. Region.Bottom = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  430. WWSB_WriteToScreen(ScreenInfo,&Region);
  431. TempNumSpaces += i;
  432. CursorPosition.X = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + i);
  433. CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  434. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
  435. dwFlags & WC_KEEP_CURSOR_VISIBLE,ScrollY);
  436. if (*NumBytes == BufferSize) {
  437. ConsoleShowCursor(ScreenInfo);
  438. if (ARGUMENT_PRESENT(NumSpaces)) {
  439. *NumSpaces = TempNumSpaces;
  440. }
  441. Status = STATUS_SUCCESS;
  442. goto ExitWriteChars;
  443. }
  444. continue;
  445. } else if (*NumBytes == BufferSize) {
  446. ASSERT(ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT);
  447. // this catches the case where the number of backspaces ==
  448. // the number of characters.
  449. if (ARGUMENT_PRESENT(NumSpaces)) {
  450. *NumSpaces = TempNumSpaces;
  451. }
  452. ConsoleShowCursor(ScreenInfo);
  453. Status = STATUS_SUCCESS;
  454. goto ExitWriteChars;
  455. }
  456. ASSERT(ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT);
  457. switch (*lpString) {
  458. case UNICODE_BACKSPACE:
  459. //
  460. // move cursor backwards one space. overwrite current char with blank.
  461. //
  462. // we get here because we have to backspace from the beginning of the line
  463. CursorPosition = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  464. TempNumSpaces -= 1;
  465. if (lpBuffer == lpBufferBackupLimit) {
  466. CursorPosition.X-=1;
  467. }
  468. else {
  469. PWCHAR pBuffer;
  470. WCHAR TmpBuffer[LOCAL_BUFFER_SIZE];
  471. PWCHAR Tmp,Tmp2;
  472. WCHAR LastChar;
  473. ULONG i;
  474. if (lpBuffer-lpBufferBackupLimit > LOCAL_BUFFER_SIZE) {
  475. pBuffer = ConsoleHeapAlloc(TMP_TAG, (ULONG)(lpBuffer-lpBufferBackupLimit) * sizeof(WCHAR));
  476. if (pBuffer == NULL) {
  477. Status = STATUS_NO_MEMORY;
  478. goto ExitWriteChars;
  479. }
  480. } else {
  481. pBuffer = TmpBuffer;
  482. }
  483. for (i=0,Tmp2=pBuffer,Tmp=lpBufferBackupLimit;
  484. i<(ULONG)(lpBuffer-lpBufferBackupLimit);
  485. i++,Tmp++) {
  486. if (*Tmp == UNICODE_BACKSPACE) {
  487. if (Tmp2 > pBuffer) {
  488. Tmp2--;
  489. }
  490. } else {
  491. ASSERT(Tmp2 >= pBuffer);
  492. *Tmp2++ = *Tmp;
  493. }
  494. }
  495. if (Tmp2 == pBuffer) {
  496. LastChar = (WCHAR)' ';
  497. } else {
  498. LastChar = *(Tmp2-1);
  499. }
  500. if (pBuffer != TmpBuffer) {
  501. ConsoleHeapFree(pBuffer);
  502. }
  503. if (LastChar == UNICODE_TAB) {
  504. CursorPosition.X -=
  505. (SHORT)(RetrieveNumberOfSpaces(OriginalXPosition,
  506. lpBufferBackupLimit,
  507. (ULONG)(lpBuffer - lpBufferBackupLimit - 1),
  508. ScreenInfo->Console,
  509. ScreenInfo->Console->OutputCP
  510. ));
  511. if (CursorPosition.X < 0) {
  512. CursorPosition.X = (ScreenInfo->ScreenBufferSize.X - 1)/TAB_SIZE;
  513. CursorPosition.X *= TAB_SIZE;
  514. CursorPosition.X += 1;
  515. CursorPosition.Y -= 1;
  516. }
  517. }
  518. else if (IS_CONTROL_CHAR(LastChar)) {
  519. CursorPosition.X-=1;
  520. TempNumSpaces -= 1;
  521. //
  522. // overwrite second character of ^x sequence.
  523. //
  524. if (dwFlags & WC_DESTRUCTIVE_BACKSPACE) {
  525. NumChars = 1;
  526. Status = WWSB_WriteOutputString(ScreenInfo,
  527. Blanks, CursorPosition,
  528. CONSOLE_FALSE_UNICODE, // faster than real unicode
  529. &NumChars, NULL);
  530. Status = WWSB_FillOutput(ScreenInfo,
  531. Attributes, CursorPosition,
  532. CONSOLE_ATTRIBUTE, &NumChars);
  533. }
  534. CursorPosition.X-=1;
  535. }
  536. #ifdef WWSB_FE
  537. else if (IsConsoleFullWidth(ScreenInfo->Console->hDC,
  538. ScreenInfo->Console->OutputCP,LastChar))
  539. {
  540. CursorPosition.X-=1;
  541. TempNumSpaces -= 1;
  542. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
  543. dwFlags & WC_KEEP_CURSOR_VISIBLE,ScrollY);
  544. if (dwFlags & WC_DESTRUCTIVE_BACKSPACE) { // bug 7672
  545. NumChars = 1;
  546. Status = WWSB_WriteOutputString(ScreenInfo,
  547. Blanks, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
  548. CONSOLE_FALSE_UNICODE, // faster than real unicode
  549. &NumChars, NULL);
  550. Status = WWSB_FillOutput(ScreenInfo,
  551. Attributes, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
  552. CONSOLE_ATTRIBUTE, &NumChars);
  553. }
  554. CursorPosition.X-=1;
  555. }
  556. #endif
  557. else {
  558. CursorPosition.X--;
  559. }
  560. }
  561. if ((dwFlags & WC_LIMIT_BACKSPACE) && (CursorPosition.X < 0)) {
  562. CursorPosition.X = 0;
  563. KdPrint(("CONSRV: Ignoring backspace to previous line\n"));
  564. }
  565. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
  566. (dwFlags & WC_KEEP_CURSOR_VISIBLE) != 0,ScrollY);
  567. if (dwFlags & WC_DESTRUCTIVE_BACKSPACE) {
  568. NumChars = 1;
  569. Status = WWSB_WriteOutputString(ScreenInfo,
  570. Blanks, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
  571. CONSOLE_FALSE_UNICODE, //faster than real unicode
  572. &NumChars, NULL);
  573. Status = WWSB_FillOutput(ScreenInfo,
  574. Attributes, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
  575. CONSOLE_ATTRIBUTE, &NumChars);
  576. }
  577. #ifdef WWSB_FE
  578. if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.X == 0 &&
  579. (ScreenInfo->OutputMode & ENABLE_WRAP_AT_EOL_OUTPUT) &&
  580. lpBuffer > lpBufferBackupLimit) {
  581. if (CheckBisectProcessW(ScreenInfo,
  582. ScreenInfo->Console->OutputCP,
  583. lpBufferBackupLimit,
  584. (ULONG)(lpBuffer+1-lpBufferBackupLimit),
  585. ScreenInfo->ScreenBufferSize.X-OriginalXPosition,
  586. OriginalXPosition,
  587. dwFlags & WC_ECHO)) {
  588. CursorPosition.X = ScreenInfo->ScreenBufferSize.X-1;
  589. CursorPosition.Y = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y-1);
  590. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
  591. dwFlags & WC_KEEP_CURSOR_VISIBLE,ScrollY);
  592. }
  593. }
  594. #endif
  595. break;
  596. case UNICODE_TAB:
  597. TabSize = NUMBER_OF_SPACES_IN_TAB(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X);
  598. CursorPosition.X = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + TabSize);
  599. //
  600. // move cursor forward to next tab stop. fill space with blanks.
  601. // we get here when the tab extends beyond the right edge of the
  602. // window. if the tab goes wraps the line, set the cursor to the first
  603. // position in the next line.
  604. //
  605. lpBuffer++;
  606. TempNumSpaces += TabSize;
  607. if (CursorPosition.X >= ScreenInfo->ScreenBufferSize.X) {
  608. NumChars = ScreenInfo->ScreenBufferSize.X - ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
  609. CursorPosition.X = 0;
  610. CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1;
  611. }
  612. else {
  613. NumChars = CursorPosition.X - ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
  614. CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  615. }
  616. Status = WWSB_WriteOutputString(ScreenInfo,
  617. Blanks,
  618. ScreenInfo->BufferInfo.TextInfo.CursorPosition,
  619. CONSOLE_FALSE_UNICODE, // faster than real unicode
  620. &NumChars,
  621. NULL);
  622. Status = WWSB_FillOutput(ScreenInfo,
  623. Attributes, ScreenInfo->BufferInfo.TextInfo.CursorPosition,
  624. CONSOLE_ATTRIBUTE,
  625. &NumChars);
  626. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
  627. (dwFlags & WC_KEEP_CURSOR_VISIBLE) != 0,ScrollY);
  628. break;
  629. case UNICODE_CARRIAGERETURN:
  630. //
  631. // Carriage return moves the cursor to the beginning of the line.
  632. // We don't need to worry about handling cr or lf for
  633. // backspace because input is sent to the user on cr or lf.
  634. //
  635. lpBuffer++;
  636. CursorPosition.X = 0;
  637. CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  638. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
  639. (dwFlags & WC_KEEP_CURSOR_VISIBLE) != 0,ScrollY);
  640. break;
  641. case UNICODE_LINEFEED:
  642. //
  643. // move cursor to the beginning of the next line.
  644. //
  645. lpBuffer++;
  646. CursorPosition.X = 0;
  647. CursorPosition.Y = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1);
  648. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
  649. (dwFlags & WC_KEEP_CURSOR_VISIBLE) != 0,ScrollY);
  650. break;
  651. default:
  652. #ifdef WWSB_FE
  653. Char = *lpString;
  654. if (Char >= (WCHAR)' ' &&
  655. IsConsoleFullWidth(ScreenInfo->Console->hDC,
  656. ScreenInfo->Console->OutputCP,Char) &&
  657. XPosition >= (ScreenInfo->ScreenBufferSize.X-1) &&
  658. (ScreenInfo->OutputMode & ENABLE_WRAP_AT_EOL_OUTPUT)) {
  659. SHORT RowIndex;
  660. PROW Row;
  661. PWCHAR Char;
  662. COORD TargetPoint;
  663. PCHAR AttrP;
  664. TargetPoint = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  665. RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
  666. Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
  667. Char = &Row->CharRow.Chars[TargetPoint.X];
  668. AttrP = &Row->CharRow.KAttrs[TargetPoint.X];
  669. if (*AttrP & ATTR_TRAILING_BYTE)
  670. {
  671. *(Char-1) = UNICODE_SPACE;
  672. *Char = UNICODE_SPACE;
  673. *AttrP = 0;
  674. *(AttrP-1) = 0;
  675. Region.Left = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X-1;
  676. Region.Right = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X);
  677. Region.Top = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  678. Region.Bottom = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  679. WWSB_WriteToScreen(ScreenInfo,&Region);
  680. }
  681. CursorPosition.X = 0;
  682. CursorPosition.Y = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1);
  683. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,
  684. dwFlags & WC_KEEP_CURSOR_VISIBLE,ScrollY);
  685. continue;
  686. }
  687. #endif
  688. break;
  689. }
  690. if (!NT_SUCCESS(Status)) {
  691. ConsoleShowCursor(ScreenInfo);
  692. goto ExitWriteChars;
  693. }
  694. *NumBytes += sizeof(WCHAR);
  695. lpString++;
  696. lpRealUnicodeString++;
  697. }
  698. if (ARGUMENT_PRESENT(NumSpaces)) {
  699. *NumSpaces = TempNumSpaces;
  700. }
  701. ConsoleShowCursor(ScreenInfo);
  702. Status = STATUS_SUCCESS;
  703. ExitWriteChars:
  704. if (lpAllocatedString) {
  705. ConsoleHeapFree(lpAllocatedString);
  706. }
  707. return Status;
  708. }
  709. ULONG
  710. WWSB_DoWriteConsole(
  711. IN OUT PCSR_API_MSG m,
  712. IN PCONSOLE_INFORMATION Console,
  713. IN PCSR_THREAD Thread
  714. )
  715. //
  716. // NOTE: console lock must be held when calling this routine
  717. //
  718. // string has been translated to unicode at this point
  719. //
  720. {
  721. PCONSOLE_WRITECONSOLE_MSG a = (PCONSOLE_WRITECONSOLE_MSG)&m->u.ApiMessageData;
  722. PHANDLE_DATA HandleData;
  723. NTSTATUS Status;
  724. PSCREEN_INFORMATION ScreenInfo;
  725. DWORD NumCharsToWrite;
  726. #ifdef WWSB_FE
  727. DWORD i;
  728. SHORT j;
  729. #endif
  730. if (Console->Flags & (CONSOLE_SUSPENDED | CONSOLE_SELECTING | CONSOLE_SCROLLBAR_TRACKING)) {
  731. PWCHAR TransBuffer;
  732. TransBuffer = ConsoleHeapAlloc(TMP_TAG, a->NumBytes);
  733. if (TransBuffer == NULL) {
  734. return (ULONG)STATUS_NO_MEMORY;
  735. }
  736. RtlCopyMemory(TransBuffer,a->TransBuffer,a->NumBytes);
  737. a->TransBuffer = TransBuffer;
  738. a->StackBuffer = FALSE;
  739. if (!CsrCreateWait(&Console->OutputQueue,
  740. WriteConsoleWaitRoutine,
  741. Thread,
  742. m,
  743. NULL)) {
  744. ConsoleHeapFree(TransBuffer);
  745. return (ULONG)STATUS_NO_MEMORY;
  746. }
  747. return (ULONG)CONSOLE_STATUS_WAIT;
  748. }
  749. Status = DereferenceIoHandle(CONSOLE_FROMTHREADPERPROCESSDATA(Thread),
  750. a->OutputHandle,
  751. CONSOLE_OUTPUT_HANDLE,
  752. GENERIC_WRITE,
  753. &HandleData
  754. );
  755. if (!NT_SUCCESS(Status)) {
  756. a->NumBytes = 0;
  757. return((ULONG) Status);
  758. }
  759. ScreenInfo = HandleData->Buffer.ScreenBuffer;
  760. //
  761. // see if we're the typical case - a string containing no special
  762. // characters, optionally terminated with CRLF. if so, skip the
  763. // special processing.
  764. //
  765. NumCharsToWrite=a->NumBytes/sizeof(WCHAR);
  766. if ((ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT) &&
  767. ((LONG)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + NumCharsToWrite) <
  768. ScreenInfo->ScreenBufferSize.X) ) {
  769. SMALL_RECT Region;
  770. COORD CursorPosition;
  771. if (a->Unicode) {
  772. #ifdef WWSB_FE
  773. a->WriteFlags = WRITE_SPECIAL_CHARS;
  774. #else
  775. a->WriteFlags = FastStreamWrite(a->TransBuffer,NumCharsToWrite);
  776. #endif
  777. }
  778. if (a->WriteFlags == WRITE_SPECIAL_CHARS) {
  779. goto ProcessedWrite;
  780. }
  781. ConsoleHideCursor(ScreenInfo);
  782. //
  783. // WriteFlags is designed so that the number of special characters
  784. // is also the flag value.
  785. //
  786. NumCharsToWrite -= a->WriteFlags;
  787. if (NumCharsToWrite) {
  788. #ifdef WWSB_FE
  789. PWCHAR TransBuffer,TransBufPtr,String;
  790. PBYTE TransBufferA,TransBufPtrA;
  791. BOOL fLocalHeap = FALSE;
  792. COORD TargetPoint;
  793. if (NumCharsToWrite > (ULONG)(ScreenInfo->ScreenBufferSize.X * ScreenInfo->ScreenBufferSize.Y)) {
  794. TransBuffer = ConsoleHeapAlloc(TMP_DBCS_TAG, NumCharsToWrite * 2 * sizeof(WCHAR));
  795. if (TransBuffer == NULL) {
  796. return (ULONG)STATUS_NO_MEMORY;
  797. }
  798. TransBufferA = ConsoleHeapAlloc(TMP_DBCS_TAG, NumCharsToWrite * 2 * sizeof(CHAR));
  799. if (TransBufferA == NULL) {
  800. ConsoleHeapFree(TransBuffer);
  801. return (ULONG)STATUS_NO_MEMORY;
  802. }
  803. fLocalHeap = TRUE;
  804. }
  805. else {
  806. TransBuffer = ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferCharacter;
  807. TransBufferA = ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferAttribute;
  808. }
  809. String = a->TransBuffer;
  810. TransBufPtr = TransBuffer;
  811. TransBufPtrA = TransBufferA;
  812. for (i = 0 , j = 0 ; i < NumCharsToWrite ; i++,j++){
  813. if (IsConsoleFullWidth(ScreenInfo->Console->hDC,
  814. ScreenInfo->Console->OutputCP,*String)){
  815. *TransBuffer++ = *String ;
  816. *TransBufferA++ = ATTR_LEADING_BYTE;
  817. *TransBuffer++ = *String++ ;
  818. *TransBufferA++ = ATTR_TRAILING_BYTE;
  819. j++;
  820. }
  821. else{
  822. *TransBuffer++ = *String++ ;
  823. *TransBufferA++ = 0;
  824. }
  825. }
  826. TargetPoint = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  827. BisectWrite(j,TargetPoint,ScreenInfo);
  828. if (TargetPoint.Y == ScreenInfo->ScreenBufferSize.Y-1 &&
  829. TargetPoint.X+j >= ScreenInfo->ScreenBufferSize.X &&
  830. *(TransBufPtrA+j) & ATTR_LEADING_BYTE){
  831. *(TransBufPtr+ScreenInfo->ScreenBufferSize.X-TargetPoint.X-1) = UNICODE_SPACE;
  832. *(TransBufPtrA+ScreenInfo->ScreenBufferSize.X-TargetPoint.X-1) = 0;
  833. if (j > ScreenInfo->ScreenBufferSize.X-TargetPoint.X-1) {
  834. *(TransBufPtr+ScreenInfo->ScreenBufferSize.X-TargetPoint.X) = UNICODE_SPACE;
  835. *(TransBufPtrA+ScreenInfo->ScreenBufferSize.X-TargetPoint.X) = 0;
  836. }
  837. }
  838. FE_StreamWriteToScreenBuffer(TransBufPtr,
  839. (SHORT)j,
  840. ScreenInfo,
  841. TransBufPtrA
  842. );
  843. if (fLocalHeap){
  844. ConsoleHeapFree(TransBufPtr);
  845. ConsoleHeapFree(TransBufPtrA);
  846. }
  847. #else
  848. SB_StreamWriteToScreenBuffer(a->TransBuffer,
  849. (SHORT)NumCharsToWrite,
  850. ScreenInfo
  851. );
  852. #endif
  853. Region.Left = ScreenInfo->BufferInfo.TextInfo.CursorPosition.X;
  854. #ifdef WWSB_FE
  855. Region.Right = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + j - 1);
  856. #else
  857. Region.Right = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + NumCharsToWrite - 1);
  858. #endif
  859. Region.Top = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  860. Region.Bottom = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  861. ASSERT (Region.Right < ScreenInfo->ScreenBufferSize.X);
  862. if (ACTIVE_SCREEN_BUFFER(ScreenInfo) &&
  863. !(ScreenInfo->Console->Flags & CONSOLE_IS_ICONIC && ScreenInfo->Console->FullScreenFlags == 0)) {
  864. WWSB_WriteRegionToScreen(ScreenInfo,&Region);
  865. }
  866. }
  867. switch (a->WriteFlags) {
  868. case WRITE_NO_CR_LF:
  869. CursorPosition.X = (SHORT)(ScreenInfo->BufferInfo.TextInfo.CursorPosition.X + NumCharsToWrite);
  870. CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  871. break;
  872. case WRITE_CR:
  873. CursorPosition.X = 0;
  874. CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y;
  875. break;
  876. case WRITE_CR_LF:
  877. CursorPosition.X = 0;
  878. CursorPosition.Y = ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y+1;
  879. break;
  880. default:
  881. ASSERT(FALSE);
  882. break;
  883. }
  884. Status = WWSB_AdjustCursorPosition(ScreenInfo,CursorPosition,FALSE,NULL);
  885. ConsoleShowCursor(ScreenInfo);
  886. return STATUS_SUCCESS;
  887. }
  888. ProcessedWrite:
  889. return WWSB_WriteChars(ScreenInfo,
  890. a->TransBuffer,
  891. a->TransBuffer,
  892. a->TransBuffer,
  893. &a->NumBytes,
  894. NULL,
  895. ScreenInfo->BufferInfo.TextInfo.CursorPosition.X,
  896. WC_LIMIT_BACKSPACE,
  897. NULL
  898. );
  899. }
  900. NTSTATUS
  901. WWSB_DoSrvWriteConsole(
  902. IN OUT PCSR_API_MSG m,
  903. IN OUT PCSR_REPLY_STATUS ReplyStatus,
  904. IN PCONSOLE_INFORMATION Console,
  905. IN PHANDLE_DATA HandleData
  906. )
  907. {
  908. NTSTATUS Status = STATUS_SUCCESS;
  909. PCONSOLE_WRITECONSOLE_MSG a = (PCONSOLE_WRITECONSOLE_MSG)&m->u.ApiMessageData;
  910. PSCREEN_INFORMATION ScreenInfo;
  911. WCHAR StackBuffer[STACK_BUFFER_SIZE];
  912. #ifdef WWSB_FE
  913. BOOL fLocalHeap = FALSE;
  914. #endif
  915. ScreenInfo = HandleData->Buffer.ScreenBuffer;
  916. #ifdef WWSB_FE
  917. // Check code for must CONSOLE_TEXTMODE_BUFFER !!
  918. ASSERT(!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER));
  919. #endif
  920. //
  921. // if the string was passed in the message, rather than in
  922. // a capture buffer, adjust the pointer.
  923. //
  924. if (a->BufferInMessage) {
  925. a->BufPtr = a->Buffer;
  926. }
  927. //
  928. // if ansi, translate string. for speed, we don't allocate a
  929. // capture buffer if the ansi string was <= 80 chars. if it's
  930. // greater than 80 / sizeof(WCHAR), the translated string won't
  931. // fit into the capture buffer, so reset a->BufPtr to point to
  932. // a heap buffer and set a->CaptureBufferSize so that we don't
  933. // think the buffer is in the message.
  934. //
  935. if (!a->Unicode) {
  936. PWCHAR TransBuffer;
  937. DWORD Length;
  938. DWORD SpecialChars = 0;
  939. UINT Codepage;
  940. #ifdef WWSB_FE
  941. PWCHAR TmpTransBuffer;
  942. ULONG NumBytes1 = 0;
  943. ULONG NumBytes2 = 0;
  944. #endif
  945. if (a->NumBytes <= STACK_BUFFER_SIZE) {
  946. TransBuffer = StackBuffer;
  947. a->StackBuffer = TRUE;
  948. #ifdef WWSB_FE
  949. TmpTransBuffer = TransBuffer;
  950. #endif
  951. }
  952. #ifdef WWSB_FE
  953. else if (a->NumBytes > (ULONG)(ScreenInfo->ScreenBufferSize.X * ScreenInfo->ScreenBufferSize.Y)) {
  954. TransBuffer = ConsoleHeapAlloc(TMP_DBCS_TAG, (a->NumBytes + 2) * sizeof(WCHAR));
  955. if (TransBuffer == NULL) {
  956. return (ULONG)STATUS_NO_MEMORY;
  957. }
  958. TmpTransBuffer = TransBuffer;
  959. a->StackBuffer = FALSE;
  960. fLocalHeap = TRUE;
  961. }
  962. else {
  963. TransBuffer = ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransWriteConsole;
  964. TmpTransBuffer = TransBuffer;
  965. }
  966. #else
  967. else {
  968. TransBuffer = ConsoleHeapAlloc(TMP_TAG, a->NumBytes * sizeof(WCHAR));
  969. if (TransBuffer == NULL) {
  970. return (ULONG)STATUS_NO_MEMORY;
  971. }
  972. a->StackBuffer = FALSE;
  973. }
  974. #endif
  975. //a->NumBytes = ConvertOutputToUnicode(Console->OutputCP,
  976. // Buffer,
  977. // a->NumBytes,
  978. // TransBuffer,
  979. // a->NumBytes);
  980. // same as ConvertOutputToUnicode
  981. #ifdef WWSB_FE
  982. if (! ScreenInfo->WriteConsoleDbcsLeadByte[0]) {
  983. NumBytes1 = 0;
  984. NumBytes2 = a->NumBytes;
  985. }
  986. else {
  987. if (*(PUCHAR)a->BufPtr < (UCHAR)' ') {
  988. NumBytes1 = 0;
  989. NumBytes2 = a->NumBytes;
  990. }
  991. else if (a->NumBytes) {
  992. ScreenInfo->WriteConsoleDbcsLeadByte[1] = *(PCHAR)a->BufPtr;
  993. NumBytes1 = sizeof(ScreenInfo->WriteConsoleDbcsLeadByte);
  994. if (Console->OutputCP == OEMCP) {
  995. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  996. ((Console->FullScreenFlags & CONSOLE_FULLSCREEN) == 0)) {
  997. /*
  998. * Translate OEM characters into False Unicode for Window-mode
  999. * OEM font. If OutputCP != OEMCP, characters will not appear
  1000. * correctly, because the OEM fonts are designed to support
  1001. * only OEMCP (we can't switch fonts in Windowed mode).
  1002. * Fullscreen or TT "Unicode" fonts should be used for
  1003. * non-OEMCP output
  1004. */
  1005. DBGCHARS(("SrvWriteConsole ACP->U %.*s\n",
  1006. min(NumBytes1,10), a->BufPtr));
  1007. Status = RtlConsoleMultiByteToUnicodeN(TransBuffer,
  1008. NumBytes1 * sizeof(WCHAR), &NumBytes1,
  1009. ScreenInfo->WriteConsoleDbcsLeadByte, NumBytes1, &SpecialChars);
  1010. } else {
  1011. /*
  1012. * Good! We have Fullscreen or TT "Unicode" fonts, so convert
  1013. * the OEM characters to real Unicode according to OutputCP.
  1014. * First find out if any special chars are involved.
  1015. */
  1016. DBGCHARS(("SrvWriteConsole %d->U %.*s\n", Console->OutputCP,
  1017. min(NumBytes1,10), a->BufPtr));
  1018. NumBytes1 = sizeof(WCHAR) * MultiByteToWideChar(Console->OutputCP,
  1019. 0, ScreenInfo->WriteConsoleDbcsLeadByte, NumBytes1, TransBuffer, NumBytes1);
  1020. if (NumBytes1 == 0) {
  1021. Status = STATUS_UNSUCCESSFUL;
  1022. }
  1023. }
  1024. }
  1025. else {
  1026. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1027. !(Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
  1028. if (Console->OutputCP != WINDOWSCP)
  1029. Codepage = USACP;
  1030. else
  1031. Codepage = WINDOWSCP;
  1032. } else {
  1033. Codepage = Console->OutputCP;
  1034. }
  1035. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1036. ((Console->FullScreenFlags & CONSOLE_FULLSCREEN) == 0)) {
  1037. NumBytes1 = ConvertOutputToUnicode(Codepage,
  1038. ScreenInfo->WriteConsoleDbcsLeadByte,
  1039. NumBytes1,
  1040. TransBuffer,
  1041. NumBytes1);
  1042. }
  1043. else {
  1044. NumBytes1 = MultiByteToWideChar(Console->OutputCP,
  1045. 0, ScreenInfo->WriteConsoleDbcsLeadByte, NumBytes1, TransBuffer, NumBytes1);
  1046. if (NumBytes1 == 0) {
  1047. Status = STATUS_UNSUCCESSFUL;
  1048. }
  1049. }
  1050. NumBytes1 *= sizeof(WCHAR);
  1051. }
  1052. TransBuffer++;
  1053. (PCHAR)a->BufPtr += (NumBytes1 / sizeof(WCHAR));
  1054. NumBytes2 = a->NumBytes - 1;
  1055. }
  1056. else {
  1057. NumBytes2 = 0;
  1058. }
  1059. ScreenInfo->WriteConsoleDbcsLeadByte[0] = 0;
  1060. }
  1061. if (NumBytes2 &&
  1062. CheckBisectStringA(Console->OutputCP,a->BufPtr,NumBytes2,&Console->OutputCPInfo)) {
  1063. ScreenInfo->WriteConsoleDbcsLeadByte[0] = *((PCHAR)a->BufPtr+NumBytes2-1);
  1064. NumBytes2--;
  1065. }
  1066. Length = NumBytes2;
  1067. #else
  1068. Length = a->NumBytes;
  1069. if (a->NumBytes >= 2 &&
  1070. ((PCHAR)a->BufPtr)[a->NumBytes-1] == '\n' &&
  1071. ((PCHAR)a->BufPtr)[a->NumBytes-2] == '\r') {
  1072. Length -= 2;
  1073. a->WriteFlags = WRITE_CR_LF;
  1074. } else if (a->NumBytes >= 1 &&
  1075. ((PCHAR)a->BufPtr)[a->NumBytes-1] == '\r') {
  1076. Length -= 1;
  1077. a->WriteFlags = WRITE_CR;
  1078. } else {
  1079. a->WriteFlags = WRITE_NO_CR_LF;
  1080. }
  1081. #endif
  1082. if (Length != 0) {
  1083. if (Console->OutputCP == OEMCP) {
  1084. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1085. ((Console->FullScreenFlags & CONSOLE_FULLSCREEN) == 0)) {
  1086. /*
  1087. * Translate OEM characters into UnicodeOem for the Window-mode
  1088. * OEM font. If OutputCP != OEMCP, characters will not appear
  1089. * correctly, because the OEM fonts are designed to support
  1090. * only OEMCP (we can't switch fonts in Windowed mode).
  1091. * Fullscreen or TT "Unicode" fonts should be used for
  1092. * non-OEMCP output
  1093. */
  1094. DBGCHARS(("SrvWriteConsole ACP->U %.*s\n",
  1095. min(Length,10), a->BufPtr));
  1096. Status = RtlConsoleMultiByteToUnicodeN(TransBuffer,
  1097. Length * sizeof(WCHAR), &Length,
  1098. a->BufPtr, Length, &SpecialChars);
  1099. } else {
  1100. /*
  1101. * Good! We have Fullscreen or TT "Unicode" fonts, so convert
  1102. * the OEM characters to real Unicode according to OutputCP.
  1103. * First find out if any special chars are involved.
  1104. */
  1105. #ifdef WWSB_NOFE
  1106. UINT i;
  1107. for (i = 0; i < Length; i++) {
  1108. if (((PCHAR)a->BufPtr)[i] < 0x20) {
  1109. SpecialChars = 1;
  1110. break;
  1111. }
  1112. }
  1113. #endif
  1114. DBGCHARS(("SrvWriteConsole %d->U %.*s\n", Console->OutputCP,
  1115. min(Length,10), a->BufPtr));
  1116. Length = sizeof(WCHAR) * MultiByteToWideChar(Console->OutputCP,
  1117. 0, a->BufPtr, Length, TransBuffer, Length);
  1118. if (Length == 0) {
  1119. Status = STATUS_UNSUCCESSFUL;
  1120. }
  1121. }
  1122. }
  1123. else
  1124. {
  1125. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1126. !(Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
  1127. if (Console->OutputCP != WINDOWSCP)
  1128. Codepage = USACP;
  1129. else
  1130. Codepage = WINDOWSCP;
  1131. } else {
  1132. Codepage = Console->OutputCP;
  1133. }
  1134. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1135. ((Console->FullScreenFlags & CONSOLE_FULLSCREEN) == 0)) {
  1136. Length = sizeof(WCHAR) * ConvertOutputToUnicode(Codepage,
  1137. a->BufPtr,
  1138. Length,
  1139. TransBuffer,
  1140. Length);
  1141. }
  1142. else {
  1143. Length = sizeof(WCHAR) * MultiByteToWideChar(Console->OutputCP,
  1144. 0, a->BufPtr, Length, TransBuffer, Length);
  1145. if (Length == 0) {
  1146. Status = STATUS_UNSUCCESSFUL;
  1147. }
  1148. }
  1149. #ifdef WWSB_NOFE
  1150. SpecialChars = 1;
  1151. #endif
  1152. }
  1153. }
  1154. #ifdef WWSB_FE
  1155. NumBytes2 = Length;
  1156. if ((NumBytes1+NumBytes2) == 0) {
  1157. if (!a->StackBuffer && fLocalHeap) {
  1158. ConsoleHeapFree(a->TransBuffer);
  1159. }
  1160. return Status;
  1161. }
  1162. #else
  1163. if (!NT_SUCCESS(Status)) {
  1164. if (!a->StackBuffer) {
  1165. ConsoleHeapFree(TransBuffer);
  1166. }
  1167. return Status;
  1168. }
  1169. #endif
  1170. #ifdef WWSB_FE
  1171. Console->WriteConOutNumBytesTemp = a->NumBytes;
  1172. a->NumBytes = Console->WriteConOutNumBytesUnicode = NumBytes1 + NumBytes2;
  1173. a->WriteFlags = WRITE_SPECIAL_CHARS;
  1174. a->TransBuffer = TmpTransBuffer;
  1175. #else
  1176. DBGOUTPUT(("TransBuffer=%lx, Length = %x(bytes), SpecialChars=%lx\n",
  1177. TransBuffer, Length, SpecialChars));
  1178. a->NumBytes = Length + (a->WriteFlags * sizeof(WCHAR));
  1179. if (a->WriteFlags == WRITE_CR_LF) {
  1180. TransBuffer[(Length+sizeof(WCHAR))/sizeof(WCHAR)] = UNICODE_LINEFEED;
  1181. TransBuffer[Length/sizeof(WCHAR)] = UNICODE_CARRIAGERETURN;
  1182. } else if (a->WriteFlags == WRITE_CR) {
  1183. TransBuffer[Length/sizeof(WCHAR)] = UNICODE_CARRIAGERETURN;
  1184. }
  1185. if (SpecialChars) {
  1186. // CRLF didn't get translated
  1187. a->WriteFlags = WRITE_SPECIAL_CHARS;
  1188. }
  1189. a->TransBuffer = TransBuffer;
  1190. #endif
  1191. } else {
  1192. if ((ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) &&
  1193. ((Console->FullScreenFlags & CONSOLE_FULLSCREEN) == 0)) {
  1194. Status = RealUnicodeToFalseUnicode(a->BufPtr,
  1195. a->NumBytes / sizeof(WCHAR), Console->OutputCP);
  1196. if (!NT_SUCCESS(Status)) {
  1197. return Status;
  1198. }
  1199. }
  1200. a->WriteFlags = (DWORD)-1;
  1201. a->TransBuffer = a->BufPtr;
  1202. }
  1203. Status = WWSB_DoWriteConsole(m,Console,CSR_SERVER_QUERYCLIENTTHREAD());
  1204. if (Status == CONSOLE_STATUS_WAIT) {
  1205. *ReplyStatus = CsrReplyPending;
  1206. return (ULONG)STATUS_SUCCESS;
  1207. } else {
  1208. if (!a->Unicode) {
  1209. #ifdef WWSB_FE
  1210. if (a->NumBytes == Console->WriteConOutNumBytesUnicode)
  1211. a->NumBytes = Console->WriteConOutNumBytesTemp;
  1212. else
  1213. a->NumBytes /= sizeof(WCHAR);
  1214. if (!a->StackBuffer && fLocalHeap) {
  1215. ConsoleHeapFree(a->TransBuffer);
  1216. }
  1217. #else
  1218. a->NumBytes /= sizeof(WCHAR);
  1219. if (!a->StackBuffer) {
  1220. ConsoleHeapFree(a->TransBuffer);
  1221. }
  1222. #endif
  1223. }
  1224. }
  1225. return Status;
  1226. }