1 /* 2 * PROJECT: ReactOS Drivers 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/sac/driver/vtutf8chan.c 5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "sacdrv.h" 12 13 /* GLOBALS ********************************************************************/ 14 15 CHAR IncomingUtf8ConversionBuffer[4]; 16 WCHAR IncomingUnicodeValue; 17 18 SAC_STATIC_ESCAPE_STRING SacStaticEscapeStrings [] = 19 { 20 { VT_ANSI_CURSOR_UP, 2, SacCursorUp }, 21 { VT_ANSI_CURSOR_DOWN, 2, SacCursorDown }, 22 { VT_ANSI_CURSOR_RIGHT, 2, SacCursorRight }, 23 { VT_ANSI_CURSOR_LEFT, 2, SacCursorLeft }, 24 { VT_220_BACKTAB, 3, SacBackTab }, 25 { VT_ANSI_ERASE_END_LINE, 2, SacEraseEndOfLine }, 26 { VT_ANSI_ERASE_START_LINE, 3, SacEraseStartOfLine }, 27 { VT_ANSI_ERASE_ENTIRE_LINE, 3, SacEraseLine }, 28 { VT_ANSI_ERASE_DOWN_SCREEN, 2, SacEraseEndOfScreen }, 29 { VT_ANSI_ERASE_UP_SCREEN, 3, SacEraseStartOfScreen }, 30 { VT_ANSI_ERASE_ENTIRE_SCREEN, 3, SacEraseScreen }, 31 }; 32 33 /* FUNCTIONS ******************************************************************/ 34 35 FORCEINLINE 36 VOID 37 VTUTF8ChannelAssertCursor(IN PSAC_CHANNEL Channel) 38 { 39 ASSERT(Channel->CursorRow < SAC_VTUTF8_ROW_HEIGHT); 40 ASSERT(Channel->CursorCol < SAC_VTUTF8_COL_WIDTH); 41 } 42 43 BOOLEAN 44 NTAPI 45 VTUTF8ChannelScanForNumber(IN PWCHAR String, 46 OUT PULONG Number) 47 { 48 /* If the first character is invalid, fail early */ 49 if ((*String < L'0') || (*String > L'9')) return FALSE; 50 51 /* Otherwise, initialize the output and loop the string */ 52 *Number = 0; 53 while ((*String >= L'0') && (*String <= L'9')) 54 { 55 /* Save the first decimal */ 56 *Number = 10 * *Number; 57 58 /* Compute and add the second one */ 59 *Number += *++String - L'0'; 60 } 61 62 /* All done */ 63 return TRUE; 64 } 65 66 NTSTATUS 67 NTAPI 68 VTUTF8ChannelAnsiDispatch(IN PSAC_CHANNEL Channel, 69 IN SAC_ANSI_DISPATCH AnsiCode, 70 IN INT* Data, 71 IN ULONG Length) 72 { 73 NTSTATUS Status = STATUS_SUCCESS; 74 PCHAR LocalBuffer = NULL, Tmp; 75 INT l; 76 CHECK_PARAMETER1(Channel); 77 78 /* Check which ANSI sequence we should output */ 79 switch (AnsiCode) 80 { 81 /* Send the [2J (Clear Screen and Reset Cursor) */ 82 case SacAnsiClearScreen: 83 Tmp = "\x1B[2J"; 84 break; 85 86 /* Send the [0J (Clear From Position Till End Of Screen) */ 87 case SacAnsiClearEndOfScreen: 88 Tmp = "\x1B[0J"; 89 break; 90 91 /* Send the [0K (Clear from Position Till End Of Line) */ 92 case SacAnsiClearEndOfLine: 93 Tmp = "\x1B[0K"; 94 break; 95 96 /* Send a combination of two [#m attribute changes */ 97 case SacAnsiSetColors: 98 99 /* Allocate a small local buffer for it */ 100 LocalBuffer = SacAllocatePool(SAC_VTUTF8_COL_WIDTH, GLOBAL_BLOCK_TAG); 101 CHECK_ALLOCATION(LocalBuffer); 102 103 /* Caller should have sent two colors as two integers */ 104 if (!(Data) || (Length != 8)) 105 { 106 Status = STATUS_INVALID_PARAMETER; 107 break; 108 } 109 110 /* Create the escape sequence string */ 111 l = sprintf(LocalBuffer, "\x1B[%dm\x1B[%dm", Data[1], Data[0]); 112 ASSERT((l + 1)*sizeof(UCHAR) < SAC_VTUTF8_COL_WIDTH); 113 ASSERT(LocalBuffer); 114 Tmp = LocalBuffer; 115 break; 116 117 /* Send the [#;#H (Cursor Position) sequence */ 118 case SacAnsiSetPosition: 119 120 /* Allocate a small local buffer for it */ 121 LocalBuffer = SacAllocatePool(SAC_VTUTF8_COL_WIDTH, GLOBAL_BLOCK_TAG); 122 CHECK_ALLOCATION(LocalBuffer); 123 124 /* Caller should have sent the position as two integers */ 125 if (!(Data) || (Length != 8)) 126 { 127 Status = STATUS_INVALID_PARAMETER; 128 break; 129 } 130 131 /* Create the escape sequence string */ 132 l = sprintf(LocalBuffer, "\x1B[%d;%dH", Data[1] + 1, Data[0] + 1); 133 ASSERT((l + 1)*sizeof(UCHAR) < SAC_VTUTF8_COL_WIDTH); 134 ASSERT(LocalBuffer); 135 Tmp = LocalBuffer; 136 break; 137 138 /* Send the [0m sequence (Set Attribute 0) */ 139 case SacAnsiClearAttributes: 140 Tmp = "\x1B[0m"; 141 break; 142 143 /* Send the [7m sequence (Set Attribute 7) */ 144 case SacAnsiSetInverseAttribute: 145 Tmp = "\x1B[7m"; 146 break; 147 148 /* Send the [27m sequence (Set Attribute 27) */ 149 case SacAnsiClearInverseAttribute: 150 Tmp = "\x1B[27m"; 151 break; 152 153 /* Send the [5m sequence (Set Attribute 5) */ 154 case SacAnsiSetBlinkAttribute: 155 Tmp = "\x1B[5m"; 156 break; 157 158 /* Send the [25m sequence (Set Attribute 25) */ 159 case SacAnsiClearBlinkAttribute: 160 Tmp = "\x1B[25m"; 161 break; 162 163 /* Send the [1m sequence (Set Attribute 1) */ 164 case SacAnsiSetBoldAttribute: 165 Tmp = "\x1B[1m"; 166 break; 167 168 /* Send the [22m sequence (Set Attribute 22) */ 169 case SacAnsiClearBoldAttribute: 170 Tmp = "\x1B[22m"; 171 break; 172 173 /* We don't recognize it */ 174 default: 175 Status = STATUS_INVALID_PARAMETER; 176 break; 177 } 178 179 /* Did everything work above? */ 180 if (NT_SUCCESS(Status)) 181 { 182 /* Go write out the sequence */ 183 Status = ConMgrWriteData(Channel, Tmp, strlen(Tmp)); 184 if (NT_SUCCESS(Status)) 185 { 186 /* Now flush it */ 187 Status = ConMgrFlushData(Channel); 188 } 189 } 190 191 /* Free the temporary buffer, if any, and return the status */ 192 if (LocalBuffer) SacFreePool(LocalBuffer); 193 return Status; 194 } 195 196 NTSTATUS 197 NTAPI 198 VTUTF8ChannelProcessAttributes(IN PSAC_CHANNEL Channel, 199 IN UCHAR Attribute) 200 { 201 NTSTATUS Status; 202 CHECK_PARAMETER(Channel); 203 204 /* Set bold if needed */ 205 Status = VTUTF8ChannelAnsiDispatch(Channel, 206 Attribute & SAC_CELL_FLAG_BOLD ? 207 SacAnsiSetBoldAttribute : 208 SacAnsiClearBoldAttribute, 209 NULL, 210 0); 211 if (!NT_SUCCESS(Status)) return Status; 212 213 /* Set blink if needed */ 214 Status = VTUTF8ChannelAnsiDispatch(Channel, 215 Attribute & SAC_CELL_FLAG_BLINK ? 216 SacAnsiSetBlinkAttribute : 217 SacAnsiClearBlinkAttribute, 218 NULL, 219 0); 220 if (!NT_SUCCESS(Status)) return Status; 221 222 /* Set inverse if needed */ 223 return VTUTF8ChannelAnsiDispatch(Channel, 224 Attribute & SAC_CELL_FLAG_INVERTED ? 225 SacAnsiSetInverseAttribute : 226 SacAnsiClearInverseAttribute, 227 NULL, 228 0); 229 } 230 231 // 232 // This function is the guts of the sequences that SAC supports. 233 // 234 // It is written to conform to the way that Microsoft's SAC driver interprets 235 // the ANSI standard. If you want to extend and/or "fix" it, please use a flag 236 // that can be set in the Registry to enable "extended" ANSI support or etc... 237 // 238 // Hermes, I'm looking at you, buddy. 239 // 240 ULONG 241 NTAPI 242 VTUTF8ChannelConsumeEscapeSequence(IN PSAC_CHANNEL Channel, 243 IN PWCHAR String) 244 { 245 ULONG Number, Number2, Number3, i, Action, Result; 246 PWCHAR Sequence; 247 PSAC_VTUTF8_SCREEN Screen; 248 ASSERT(String[0] == VT_ANSI_ESCAPE); 249 250 /* Microsoft's driver does this after the O(n) check below. Be smarter. */ 251 if (String[1] != VT_ANSI_COMMAND) return 0; 252 253 /* Now that we know it's a valid command, look through the common cases */ 254 for (i = 0; i < RTL_NUMBER_OF(SacStaticEscapeStrings); i++) 255 { 256 /* Check if an optimized sequence was detected */ 257 if (!wcsncmp(String + 1, 258 SacStaticEscapeStrings[i].Sequence, 259 SacStaticEscapeStrings[i].Size)) 260 { 261 /* Yep, return the right action, length, and set optionals to 1 */ 262 Action = SacStaticEscapeStrings[i].Action; 263 Result = SacStaticEscapeStrings[i].Size + 1; 264 Number = Number2 = Number3 = 1; 265 goto ProcessString; 266 } 267 } 268 269 /* It's a more complex sequence, start parsing it */ 270 Result = 0; 271 Sequence = String + 2; 272 273 /* First, check for the cursor sequences. This is useless due to above. */ 274 switch (*Sequence) 275 { 276 case VT_ANSI_CURSOR_UP_CHAR: 277 Action = SacCursorUp; 278 goto ProcessString; 279 280 case VT_ANSI_CURSOR_DOWN_CHAR: 281 Action = SacCursorDown; 282 goto ProcessString; 283 284 case VT_ANSI_CURSOR_RIGHT_CHAR: 285 Action = SacCursorLeft; //bug 286 goto ProcessString; 287 288 case VT_ANSI_CURSOR_LEFT_CHAR: 289 Action = SacCursorRight; //bug 290 goto ProcessString; 291 292 case VT_ANSI_ERASE_LINE_CHAR: 293 Action = SacEraseEndOfLine; 294 goto ProcessString; 295 296 default: 297 break; 298 } 299 300 /* This must be a sequence starting with ESC[# */ 301 if (!VTUTF8ChannelScanForNumber(Sequence, &Number)) return 0; 302 while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; 303 304 /* Check if this is ESC[#m */ 305 if (*Sequence == VT_ANSI_SET_ATTRIBUTE_CHAR) 306 { 307 /* Some attribute is being set, go over the ones we support */ 308 switch (Number) 309 { 310 /* Make the font standard */ 311 case Normal: 312 Action = SacFontNormal; 313 break; 314 315 /* Make the font bold */ 316 case Bold: 317 Action = SacFontBold; 318 break; 319 320 /* Make the font blink */ 321 case SlowBlink: 322 Action = SacFontBlink; 323 break; 324 325 /* Make the font colors inverted */ 326 case Inverse: 327 Action = SacFontInverse; 328 break; 329 330 /* Make the font standard intensity */ 331 case BoldOff: 332 Action = SacFontBoldOff; 333 break; 334 335 /* Turn off blinking */ 336 case BlinkOff: 337 Action = SacFontBlinkOff; 338 break; 339 340 /* Turn off inverted colors */ 341 case InverseOff: 342 Action = SacFontInverseOff; 343 break; 344 345 /* Something else... */ 346 default: 347 348 /* Is a background color being set? */ 349 if ((Number < SetBackColorStart) || (Number > SetBackColorMax)) 350 { 351 /* Nope... is it the foreground color? */ 352 if ((Number < SetColorStart) || (Number > SetColorMax)) 353 { 354 /* Nope. SAC expects no other attributes so bail out */ 355 ASSERT(FALSE); 356 return 0; 357 } 358 359 /* Yep -- the number will tell us which */ 360 Action = SacSetFontColor; 361 } 362 else 363 { 364 /* Yep -- the number will tell us which */ 365 Action = SacSetBackgroundColor; 366 } 367 break; 368 } 369 370 /* In all cases, we're done here */ 371 goto ProcessString; 372 } 373 374 /* The only allowed possibility now is ESC[#;# */ 375 if (*Sequence != VT_ANSI_SEPARATOR_CHAR) return 0; 376 Sequence++; 377 if (!VTUTF8ChannelScanForNumber(Sequence, &Number2)) return 0; 378 while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; 379 380 /* There's two valid forms accepted at this point: ESC[#;#m and ESC[#;#H */ 381 switch (*Sequence) 382 { 383 /* This is ESC[#;#m -- used to set both colors at once */ 384 case VT_ANSI_SET_ATTRIBUTE_CHAR: 385 Action = SacSetColors; 386 goto ProcessString; 387 388 /* This is ESC[#;#H -- used to set the cursor position */ 389 case VT_ANSI_CUP_CURSOR_CHAR: 390 Action = SacSetCursorPosition; 391 goto ProcessString; 392 393 /* Finally, this *could* be ESC[#;#; -- we'll keep parsing */ 394 case VT_ANSI_SEPARATOR_CHAR: 395 Sequence++; 396 break; 397 398 /* Abandon anything else */ 399 default: 400 return 0; 401 } 402 403 /* The SAC seems to accept a few more possibilities if a ';' follows... */ 404 switch (*Sequence) 405 { 406 /* Both ESC[#;#;H and ESC[#;#;f are really the same command */ 407 case VT_ANSI_CUP_CURSOR_CHAR: 408 case VT_ANSI_HVP_CURSOR_CHAR: 409 /* It's unclear why MS doesn't allow the HVP sequence on its own */ 410 Action = SacSetCursorPosition; 411 goto ProcessString; 412 413 /* And this is the ESC[#;#;r command to set the scroll region... */ 414 case VT_ANSI_SCROLL_CHAR: 415 /* Again, not clear why ESC[#;#r isn't supported */ 416 Action = SacSetScrollRegion; 417 goto ProcessString; 418 419 /* Anything else must be ESC[#;#;# */ 420 default: 421 break; 422 } 423 424 /* Get the last "#" */ 425 if (!VTUTF8ChannelScanForNumber(Sequence, &Number3)) return 0; 426 while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; 427 428 /* And now the only remaining possibility is ESC[#;#;#;m */ 429 if (*Sequence == VT_ANSI_SET_ATTRIBUTE_CHAR) 430 { 431 /* Which sets both color and attributes in one command */ 432 Action = SacSetColorsAndAttributes; 433 goto ProcessString; 434 } 435 436 /* No other sequences supported */ 437 return 0; 438 439 ProcessString: 440 /* Unless we got here from the optimized path, calculate the length */ 441 if (!Result) Result = Sequence - String + 1; 442 443 /* Get the current cell buffer */ 444 Screen = (PSAC_VTUTF8_SCREEN)Channel->OBuffer; 445 VTUTF8ChannelAssertCursor(Channel); 446 447 /* Handle all the supported SAC ANSI commands */ 448 switch (Action) 449 { 450 case SacCursorUp: 451 /* Check if we are scrolling too high */ 452 if (Channel->CursorRow < Number) 453 { 454 /* Reset the row to the top */ 455 Channel->CursorRow = 0; 456 } 457 else 458 { 459 /* We're fine -- scroll up by that much */ 460 Channel->CursorRow -= Number; 461 } 462 463 /* All done */ 464 VTUTF8ChannelAssertCursor(Channel); 465 break; 466 467 case SacCursorDown: 468 /* Check if we are scrolling too low */ 469 if (Channel->CursorRow >= SAC_VTUTF8_ROW_HEIGHT) 470 { 471 /* Reset the row to the bottom */ 472 Channel->CursorRow = SAC_VTUTF8_ROW_HEIGHT; 473 } 474 else 475 { 476 /* We're fine -- scroll down by that much */ 477 Channel->CursorRow += Number; 478 } 479 480 /* All done */ 481 VTUTF8ChannelAssertCursor(Channel); 482 break; 483 484 case SacCursorLeft: 485 /* Check if we're scrolling too much to the left */ 486 if (Channel->CursorCol < Number) 487 { 488 /* Reset the column to the left-most margin */ 489 Channel->CursorCol = 0; 490 } 491 else 492 { 493 /* We're fine -- scroll left by that much */ 494 Channel->CursorCol -= Number; 495 } 496 497 /* All done */ 498 VTUTF8ChannelAssertCursor(Channel); 499 break; 500 501 case SacCursorRight: 502 /* Check if we're scrolling too much to the right */ 503 if (Channel->CursorCol >= SAC_VTUTF8_COL_WIDTH) 504 { 505 /* Reset the column to the right-most margin */ 506 Channel->CursorCol = SAC_VTUTF8_COL_WIDTH; 507 } 508 else 509 { 510 /* We're fine -- scroll right by that much */ 511 Channel->CursorCol += Number; 512 } 513 514 /* All done */ 515 VTUTF8ChannelAssertCursor(Channel); 516 break; 517 518 case SacFontNormal: 519 /* Reset the cell attributes */ 520 Channel->CellFlags = 0; 521 Channel->CellBackColor = SetBackColorBlack; 522 Channel->CellForeColor = SetColorWhite; 523 break; 524 525 case SacFontBlink: 526 /* Set the appropriate flag */ 527 Channel->CellFlags |= SAC_CELL_FLAG_BLINK; 528 break; 529 530 case SacFontBlinkOff: 531 /* Clear the appropriate flag */ 532 Channel->CellFlags &= ~SAC_CELL_FLAG_BLINK; 533 break; 534 535 case SacFontBold: 536 /* Set the appropriate flag */ 537 Channel->CellFlags |= SAC_CELL_FLAG_BOLD; 538 break; 539 540 case SacFontBoldOff: 541 /* Clear the appropriate flag */ 542 Channel->CellFlags &= ~SAC_CELL_FLAG_BOLD; 543 break; 544 545 case SacFontInverse: 546 /* Set the appropriate flag */ 547 Channel->CellFlags |= SAC_CELL_FLAG_INVERTED; 548 break; 549 550 case SacFontInverseOff: 551 /* Clear the appropriate flag */ 552 Channel->CellFlags &= ~SAC_CELL_FLAG_INVERTED; 553 break; 554 555 case SacEraseEndOfLine: 556 /* Loop all columns in this line past the current position */ 557 for (i = Channel->CursorCol; i < SAC_VTUTF8_COL_WIDTH; i++) 558 { 559 /* Replace everything after the current position with blanks */ 560 Screen->Cell[Channel->CursorRow][i].CellFlags = Channel->CellFlags; 561 Screen->Cell[Channel->CursorRow][i].CellBackColor = Channel->CellForeColor; 562 Screen->Cell[Channel->CursorRow][i].CellForeColor = Channel->CellBackColor; 563 Screen->Cell[Channel->CursorRow][i].Char = L' '; 564 } 565 break; 566 567 case SacEraseStartOfLine: 568 /* Loop all columns in this line, before the current position */ 569 for (i = 0; i < (Channel->CursorCol + 1); i++) 570 { 571 /* Replace everything after the current position with blanks */ 572 Screen->Cell[Channel->CursorRow][i].CellFlags = Channel->CellFlags; 573 Screen->Cell[Channel->CursorRow][i].CellBackColor = Channel->CellForeColor; 574 Screen->Cell[Channel->CursorRow][i].CellForeColor = Channel->CellBackColor; 575 Screen->Cell[Channel->CursorRow][i].Char = L' '; 576 } 577 break; 578 579 case SacEraseLine: 580 /* Loop all the columns in this line */ 581 for (i = 0; i < SAC_VTUTF8_COL_WIDTH; i++) 582 { 583 /* Replace them all with blanks */ 584 Screen->Cell[Channel->CursorRow][i].CellFlags = Channel->CellFlags; 585 Screen->Cell[Channel->CursorRow][i].CellBackColor = Channel->CellForeColor; 586 Screen->Cell[Channel->CursorRow][i].CellForeColor = Channel->CellBackColor; 587 Screen->Cell[Channel->CursorRow][i].Char = L' '; 588 } 589 break; 590 591 case SacEraseEndOfScreen: 592 ASSERT(FALSE); // todo 593 break; 594 595 case SacEraseStartOfScreen: 596 ASSERT(FALSE); // todo 597 break; 598 599 case SacEraseScreen: 600 ASSERT(FALSE); // todo 601 break; 602 603 case SacSetCursorPosition: 604 ASSERT(FALSE); // todo 605 break; 606 607 case SacSetScrollRegion: 608 ASSERT(FALSE); // todo 609 break; 610 611 case SacSetColors: 612 /* Set the cell colors */ 613 Channel->CellForeColor = Number; 614 Channel->CellBackColor = Number2; 615 break; 616 617 case SacSetBackgroundColor: 618 /* Set the cell back color */ 619 Channel->CellBackColor = Number; 620 break; 621 622 case SacSetFontColor: 623 /* Set the cell text color */ 624 Channel->CellForeColor = Number; 625 break; 626 627 case SacSetColorsAndAttributes: 628 /* Set the cell flag and colors */ 629 Channel->CellFlags = Number; 630 Channel->CellForeColor = Number2; 631 Channel->CellBackColor = Number3; 632 break; 633 634 default: 635 /* Unknown, do nothing */ 636 break; 637 } 638 639 /* Return the length of the sequence */ 640 return Result; 641 } 642 643 NTSTATUS 644 NTAPI 645 VTUTF8ChannelOInit(IN PSAC_CHANNEL Channel) 646 { 647 PSAC_VTUTF8_SCREEN Screen; 648 ULONG R, C; 649 CHECK_PARAMETER(Channel); 650 651 /* Set the current channel cell parameters */ 652 Channel->CellFlags = 0; 653 Channel->CellBackColor = SetBackColorBlack; 654 Channel->CellForeColor = SetColorWhite; 655 656 /* Set the cell buffer position */ 657 Screen = (PSAC_VTUTF8_SCREEN)Channel->OBuffer; 658 659 /* Loop the output buffer height by width */ 660 for (R = 0; R < SAC_VTUTF8_ROW_HEIGHT; R++) 661 { 662 for (C = 0; C < SAC_VTUTF8_COL_WIDTH; C++) 663 { 664 /* For every character, set the defaults */ 665 Screen->Cell[R][C].Char = L' '; 666 Screen->Cell[R][C].CellBackColor = SetBackColorBlack; 667 Screen->Cell[R][C].CellForeColor = SetColorWhite; 668 } 669 } 670 671 /* All done */ 672 return STATUS_SUCCESS; 673 } 674 675 NTSTATUS 676 NTAPI 677 VTUTF8ChannelCreate(IN PSAC_CHANNEL Channel) 678 { 679 NTSTATUS Status; 680 CHECK_PARAMETER(Channel); 681 682 /* Allocate the output buffer */ 683 Channel->OBuffer = SacAllocatePool(SAC_VTUTF8_OBUFFER_SIZE, GLOBAL_BLOCK_TAG); 684 CHECK_ALLOCATION(Channel->OBuffer); 685 686 /* Allocate the input buffer */ 687 Channel->IBuffer = SacAllocatePool(SAC_VTUTF8_IBUFFER_SIZE, GLOBAL_BLOCK_TAG); 688 CHECK_ALLOCATION(Channel->IBuffer); 689 690 /* Initialize the output stream */ 691 Status = VTUTF8ChannelOInit(Channel); 692 if (NT_SUCCESS(Status)) return Status; 693 694 /* Reset all flags and return success */ 695 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0); 696 _InterlockedExchange(&Channel->ChannelHasNewIBufferData, 0); 697 return STATUS_SUCCESS; 698 } 699 700 NTSTATUS 701 NTAPI 702 VTUTF8ChannelDestroy(IN PSAC_CHANNEL Channel) 703 { 704 CHECK_PARAMETER(Channel); 705 706 /* Free the buffer and then destroy the channel */ 707 if (Channel->OBuffer) SacFreePool(Channel->OBuffer); 708 if (Channel->IBuffer) SacFreePool(Channel->IBuffer); 709 return ChannelDestroy(Channel); 710 } 711 712 NTSTATUS 713 NTAPI 714 VTUTF8ChannelORead(IN PSAC_CHANNEL Channel, 715 IN PCHAR Buffer, 716 IN ULONG BufferSize, 717 OUT PULONG ByteCount) 718 { 719 ASSERT(FALSE); 720 return STATUS_NOT_IMPLEMENTED; 721 } 722 723 NTSTATUS 724 NTAPI 725 VTUTF8ChannelOFlush(IN PSAC_CHANNEL Channel) 726 { 727 NTSTATUS Status; 728 PSAC_VTUTF8_SCREEN Screen; 729 INT Color[2], Position[2]; 730 ULONG Utf8ProcessedCount, Utf8Count, R, C, ForeColor, BackColor, Attribute; 731 PWCHAR TmpBuffer; 732 BOOLEAN Overflow = FALSE; 733 CHECK_PARAMETER(Channel); 734 735 /* Set the cell buffer position */ 736 Screen = (PSAC_VTUTF8_SCREEN)Channel->OBuffer; 737 738 /* Allocate a temporary buffer */ 739 TmpBuffer = SacAllocatePool(40, GLOBAL_BLOCK_TAG); 740 if (!TmpBuffer) 741 { 742 Status = STATUS_NO_MEMORY; 743 goto Quickie; 744 } 745 746 /* First, clear the screen */ 747 Status = VTUTF8ChannelAnsiDispatch(Channel, 748 SacAnsiClearScreen, 749 NULL, 750 0); 751 if (!NT_SUCCESS(Status)) goto Quickie; 752 753 /* Next, reset the cursor position */ 754 Position[1] = 0; 755 Position[0] = 0; 756 Status = VTUTF8ChannelAnsiDispatch(Channel, 757 SacAnsiSetPosition, 758 Position, 759 sizeof(Position)); 760 if (!NT_SUCCESS(Status)) goto Quickie; 761 762 /* Finally, reset the attributes */ 763 Status = VTUTF8ChannelAnsiDispatch(Channel, 764 SacAnsiClearAttributes, 765 NULL, 766 0); 767 if (!NT_SUCCESS(Status)) goto Quickie; 768 769 /* Now set the current cell attributes */ 770 Attribute = Channel->CellFlags; 771 Status = VTUTF8ChannelProcessAttributes(Channel, Attribute); 772 if (!NT_SUCCESS(Status)) goto Quickie; 773 774 /* And set the current cell colors */ 775 ForeColor = Channel->CellForeColor; 776 BackColor = Channel->CellBackColor; 777 Color[1] = BackColor; 778 Color[0] = ForeColor; 779 Status = VTUTF8ChannelAnsiDispatch(Channel, 780 SacAnsiSetColors, 781 Color, 782 sizeof(Color)); 783 if (!NT_SUCCESS(Status)) goto Quickie; 784 785 /* Now loop all the characters in the cell buffer */ 786 for (R = 0; R < SAC_VTUTF8_ROW_HEIGHT; R++) 787 { 788 /* Across every row */ 789 for (C = 0; C < SAC_VTUTF8_COL_WIDTH; C++) 790 { 791 /* Check if there's been a change in colors */ 792 if ((Screen->Cell[R][C].CellBackColor != BackColor) || 793 (Screen->Cell[R][C].CellForeColor != ForeColor)) 794 { 795 /* New colors are being drawn -- are we also on a new row now? */ 796 if (Overflow) 797 { 798 /* Reposition the cursor correctly */ 799 Position[1] = R; 800 Position[0] = C; 801 Status = VTUTF8ChannelAnsiDispatch(Channel, 802 SacAnsiSetPosition, 803 Position, 804 sizeof(Position)); 805 if (!NT_SUCCESS(Status)) goto Quickie; 806 Overflow = FALSE; 807 } 808 809 /* Cache the new colors */ 810 ForeColor = Screen->Cell[R][C].CellForeColor; 811 BackColor = Screen->Cell[R][C].CellBackColor; 812 813 /* Set them on the screen */ 814 Color[1] = BackColor; 815 Color[0] = ForeColor; 816 Status = VTUTF8ChannelAnsiDispatch(Channel, 817 SacAnsiSetColors, 818 Color, 819 sizeof(Color)); 820 if (!NT_SUCCESS(Status)) goto Quickie; 821 } 822 823 /* Check if there's been a change in attributes */ 824 if (Screen->Cell[R][C].CellFlags != Attribute) 825 { 826 /* Yep! Are we also on a new row now? */ 827 if (Overflow) 828 { 829 /* Reposition the cursor correctly */ 830 Position[1] = R; 831 Position[0] = C; 832 Status = VTUTF8ChannelAnsiDispatch(Channel, 833 SacAnsiSetPosition, 834 Position, 835 sizeof(Position)); 836 if (!NT_SUCCESS(Status)) goto Quickie; 837 Overflow = FALSE; 838 } 839 840 /* Set the new attributes on screen */ 841 Attribute = Screen->Cell[R][C].CellFlags; 842 Status = VTUTF8ChannelProcessAttributes(Channel, Attribute); 843 if (!NT_SUCCESS(Status)) goto Quickie; 844 } 845 846 /* Time to write the character -- are we on a new row now? */ 847 if (Overflow) 848 { 849 /* Reposition the cursor correctly */ 850 Position[1] = R; 851 Position[0] = C; 852 Status = VTUTF8ChannelAnsiDispatch(Channel, 853 SacAnsiSetPosition, 854 Position, 855 sizeof(Position)); 856 if (!NT_SUCCESS(Status)) goto Quickie; 857 Overflow = FALSE; 858 } 859 860 /* Write the character into our temporary buffer */ 861 *TmpBuffer = Screen->Cell[R][C].Char; 862 TmpBuffer[1] = UNICODE_NULL; 863 864 /* Convert it to UTF-8 */ 865 if (!SacTranslateUnicodeToUtf8(TmpBuffer, 866 1, 867 Utf8ConversionBuffer, 868 Utf8ConversionBufferSize, 869 &Utf8Count, 870 &Utf8ProcessedCount)) 871 { 872 /* Bail out if this failed */ 873 Status = STATUS_UNSUCCESSFUL; 874 goto Quickie; 875 } 876 877 /* Make sure we have a remaining valid character */ 878 if (Utf8Count) 879 { 880 /* Write it out on the wire */ 881 Status = ConMgrWriteData(Channel, Utf8ConversionBuffer, Utf8Count); 882 if (!NT_SUCCESS(Status)) goto Quickie; 883 } 884 } 885 886 /* All the characters on the row are done, indicate we need a reset */ 887 Overflow = TRUE; 888 } 889 890 /* Everything is done, set the position one last time */ 891 Position[1] = Channel->CursorRow; 892 Position[0] = Channel->CursorCol; 893 Status = VTUTF8ChannelAnsiDispatch(Channel, 894 SacAnsiSetPosition, 895 Position, 896 sizeof(Position)); 897 if (!NT_SUCCESS(Status)) goto Quickie; 898 899 /* Set the current attribute one last time */ 900 Status = VTUTF8ChannelProcessAttributes(Channel, Channel->CellFlags); 901 if (!NT_SUCCESS(Status)) goto Quickie; 902 903 /* Set the current colors one last time */ 904 Color[1] = Channel->CellBackColor; 905 Color[0] = Channel->CellForeColor; 906 Status = VTUTF8ChannelAnsiDispatch(Channel, 907 SacAnsiSetColors, 908 Color, 909 sizeof(Color)); 910 if (!NT_SUCCESS(Status)) goto Quickie; 911 912 /* Flush all the data out on the wire */ 913 Status = ConMgrFlushData(Channel); 914 915 Quickie: 916 /* We're done, free the temporary buffer */ 917 if (TmpBuffer) SacFreePool(TmpBuffer); 918 919 /* Indicate that all new data has been flushed now */ 920 if (NT_SUCCESS(Status)) 921 { 922 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0); 923 } 924 925 /* Return the result */ 926 return Status; 927 } 928 929 NTSTATUS 930 NTAPI 931 VTUTF8ChannelOWrite2(IN PSAC_CHANNEL Channel, 932 IN PWCHAR String, 933 IN ULONG Size) 934 { 935 PSAC_VTUTF8_SCREEN Screen; 936 ULONG i, EscapeSize, R, C; 937 PWSTR pwch; 938 CHECK_PARAMETER1(Channel); 939 CHECK_PARAMETER2(String); 940 VTUTF8ChannelAssertCursor(Channel); 941 942 /* Loop every character */ 943 Screen = (PSAC_VTUTF8_SCREEN)Channel->OBuffer; 944 for (i = 0; i < Size; i++) 945 { 946 /* Check what the character is */ 947 pwch = &String[i]; 948 switch (*pwch) 949 { 950 /* It's an escape sequence... */ 951 case L'\x1B': 952 953 /* Send it to the parser, see how long the sequence was */ 954 EscapeSize = VTUTF8ChannelConsumeEscapeSequence(Channel, pwch); 955 if (EscapeSize) 956 { 957 /* Consume that many characters for next time*/ 958 i += EscapeSize - 1; 959 } 960 else 961 { 962 /* Invalid escape sequence, skip just the ESC character */ 963 i++; 964 } 965 966 /* Keep going*/ 967 break; 968 969 /* It's a line feed */ 970 case L'\n': 971 972 /* Simply reset the column to zero on the current line */ 973 Channel->CursorCol = 0; 974 break; 975 976 /* It's a carriage feed */ 977 case L'\r': 978 979 /* Move to the next row */ 980 Channel->CursorRow++; 981 982 /* Check if we hit the last row on the screen */ 983 if (Channel->CursorRow >= SAC_VTUTF8_ROW_HEIGHT) 984 { 985 /* Go over every row before the last one */ 986 for (R = 0; R < (SAC_VTUTF8_ROW_HEIGHT - 1); R++) 987 { 988 /* Sanity check, since we always copy one row below */ 989 ASSERT((R + 1) < SAC_VTUTF8_ROW_HEIGHT); 990 991 /* Loop every character on the row */ 992 for (C = 0; C < SAC_VTUTF8_COL_WIDTH; C++) 993 { 994 /* And replace it with one from the row below */ 995 Screen->Cell[R][C] = Screen->Cell[R + 1][C]; 996 } 997 } 998 999 /* Now we're left with the before-last row, zero it out */ 1000 ASSERT(R == (SAC_VTUTF8_ROW_HEIGHT - 1)); 1001 RtlZeroMemory(&Screen->Cell[R], sizeof(Screen->Cell[R])); 1002 1003 /* Reset the row back by one */ 1004 Channel->CursorRow--; 1005 VTUTF8ChannelAssertCursor(Channel); 1006 } 1007 break; 1008 1009 /* It's a TAB character */ 1010 case L'\t': 1011 1012 /* Loop the remaining characters until a multiple of 4 */ 1013 VTUTF8ChannelAssertCursor(Channel); 1014 for (C = (4 - Channel->CursorCol % 4); C; C--) 1015 { 1016 /* Fill each remaining character with a space */ 1017 VTUTF8ChannelAssertCursor(Channel); 1018 Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellFlags = Channel->CellFlags; 1019 Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellBackColor = Channel->CellBackColor; 1020 Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellForeColor = Channel->CellForeColor; 1021 Screen->Cell[Channel->CursorRow][Channel->CursorCol].Char = L' '; 1022 1023 /* Move to the next character position, but don't overflow */ 1024 Channel->CursorCol++; 1025 if (Channel->CursorCol >= SAC_VTUTF8_COL_WIDTH) 1026 { 1027 Channel->CursorCol = SAC_VTUTF8_COL_WIDTH - 1; 1028 } 1029 } 1030 1031 /* All done, move to the next one */ 1032 VTUTF8ChannelAssertCursor(Channel); 1033 break; 1034 1035 /* It's a backspace or delete character */ 1036 case L'\b': 1037 case L'\x7F': 1038 1039 /* Move back one character, unless we had nothing typed */ 1040 if (Channel->CursorCol) Channel->CursorCol--; 1041 VTUTF8ChannelAssertCursor(Channel); 1042 break; 1043 1044 /* It's some other character */ 1045 default: 1046 1047 /* Is it non-printable? Ignore it and keep parsing */ 1048 if (*pwch < L' ') continue; 1049 1050 /* Otherwise, print it out with the current attributes */ 1051 VTUTF8ChannelAssertCursor(Channel); 1052 Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellFlags = Channel->CellFlags; 1053 Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellBackColor = Channel->CellBackColor; 1054 Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellForeColor = Channel->CellForeColor; 1055 Screen->Cell[Channel->CursorRow][Channel->CursorCol].Char = *pwch; 1056 1057 /* Move forward one character, but make sure not to overflow */ 1058 Channel->CursorCol++; 1059 if (Channel->CursorCol == SAC_VTUTF8_COL_WIDTH) 1060 { 1061 Channel->CursorCol = SAC_VTUTF8_COL_WIDTH - 1; 1062 } 1063 1064 /* All done, move to the next one */ 1065 VTUTF8ChannelAssertCursor(Channel); 1066 break; 1067 } 1068 } 1069 1070 /* Parsing of the input string completed -- string was written */ 1071 VTUTF8ChannelAssertCursor(Channel); 1072 return STATUS_SUCCESS; 1073 } 1074 1075 NTSTATUS 1076 NTAPI 1077 VTUTF8ChannelOEcho(IN PSAC_CHANNEL Channel, 1078 IN PCHAR String, 1079 IN ULONG Size) 1080 { 1081 NTSTATUS Status = STATUS_SUCCESS; 1082 PWSTR pwch; 1083 ULONG i, k, TranslatedCount, UTF8TranslationSize; 1084 BOOLEAN Result; 1085 CHECK_PARAMETER1(Channel); 1086 CHECK_PARAMETER2(String); 1087 1088 /* Return success if there's nothing to echo */ 1089 if (!(Size / sizeof(WCHAR))) return Status; 1090 1091 /* Start with the input string */ 1092 pwch = (PWCHAR)String; 1093 1094 /* First, figure out how much is outside of the block length alignment */ 1095 k = (Size / sizeof(WCHAR)) % MAX_UTF8_ENCODE_BLOCK_LENGTH; 1096 if (k) 1097 { 1098 /* Translate the misaligned portion */ 1099 Result = SacTranslateUnicodeToUtf8(pwch, 1100 k, 1101 Utf8ConversionBuffer, 1102 Utf8ConversionBufferSize, 1103 &UTF8TranslationSize, 1104 &TranslatedCount); 1105 ASSERT(k == TranslatedCount); 1106 if (!Result) 1107 { 1108 /* If we couldn't translate, write failure to break out below */ 1109 Status = STATUS_UNSUCCESSFUL; 1110 } 1111 else 1112 { 1113 /* Write the misaligned portion into the buffer */ 1114 Status = ConMgrWriteData(Channel, 1115 Utf8ConversionBuffer, 1116 UTF8TranslationSize); 1117 } 1118 1119 /* If translation or write failed, bail out */ 1120 if (!NT_SUCCESS(Status)) goto Return; 1121 } 1122 1123 /* Push the string to its new location (this could be a noop if aligned) */ 1124 pwch += k; 1125 1126 /* Now figure out how many aligned blocks we have, and loop each one */ 1127 k = (Size / sizeof(WCHAR)) / MAX_UTF8_ENCODE_BLOCK_LENGTH; 1128 for (i = 0; i < k; i++) 1129 { 1130 /* Translate the aligned block */ 1131 Result = SacTranslateUnicodeToUtf8(pwch, 1132 MAX_UTF8_ENCODE_BLOCK_LENGTH, 1133 Utf8ConversionBuffer, 1134 Utf8ConversionBufferSize, 1135 &UTF8TranslationSize, 1136 &TranslatedCount); 1137 ASSERT(MAX_UTF8_ENCODE_BLOCK_LENGTH == TranslatedCount); 1138 ASSERT(UTF8TranslationSize > 0); 1139 if (!Result) 1140 { 1141 /* Set failure here, we'll break out below */ 1142 Status = STATUS_UNSUCCESSFUL; 1143 } 1144 else 1145 { 1146 /* Move the string location to the next aligned block */ 1147 pwch += MAX_UTF8_ENCODE_BLOCK_LENGTH; 1148 1149 /* Write the aligned block into the buffer */ 1150 Status = ConMgrWriteData(Channel, 1151 Utf8ConversionBuffer, 1152 UTF8TranslationSize); 1153 } 1154 1155 /* If translation or write failed, bail out */ 1156 if (!NT_SUCCESS(Status)) break; 1157 } 1158 1159 Return: 1160 ASSERT(pwch == (PWSTR)(String + Size)); 1161 if (NT_SUCCESS(Status)) Status = ConMgrFlushData(Channel); 1162 return Status; 1163 } 1164 1165 NTSTATUS 1166 NTAPI 1167 VTUTF8ChannelOWrite(IN PSAC_CHANNEL Channel, 1168 IN PCHAR String, 1169 IN ULONG Length) 1170 { 1171 NTSTATUS Status; 1172 CHECK_PARAMETER1(Channel); 1173 CHECK_PARAMETER2(String); 1174 1175 /* Call the lower level function */ 1176 Status = VTUTF8ChannelOWrite2(Channel, (PWCHAR)String, Length / sizeof(WCHAR)); 1177 if (NT_SUCCESS(Status)) 1178 { 1179 /* Is the channel enabled for output? */ 1180 if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled)) 1181 { 1182 /* Go ahead and output it */ 1183 Status = VTUTF8ChannelOEcho(Channel, String, Length); 1184 } 1185 else 1186 { 1187 /* Otherwise, just remember that we have new data */ 1188 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 1); 1189 } 1190 } 1191 1192 /* We're done */ 1193 return Status; 1194 } 1195 1196 ULONG 1197 NTAPI 1198 VTUTF8ChannelGetIBufferIndex(IN PSAC_CHANNEL Channel) 1199 { 1200 ASSERT(Channel); 1201 ASSERT((Channel->IBufferIndex % sizeof(WCHAR)) == 0); 1202 ASSERT(Channel->IBufferIndex < SAC_VTUTF8_IBUFFER_SIZE); 1203 1204 /* Return the current buffer index */ 1205 return Channel->IBufferIndex; 1206 } 1207 1208 VOID 1209 NTAPI 1210 VTUTF8ChannelSetIBufferIndex(IN PSAC_CHANNEL Channel, 1211 IN ULONG BufferIndex) 1212 { 1213 NTSTATUS Status; 1214 ASSERT(Channel); 1215 ASSERT((Channel->IBufferIndex % sizeof(WCHAR)) == 0); 1216 ASSERT(Channel->IBufferIndex < SAC_VTUTF8_IBUFFER_SIZE); 1217 1218 /* Set the new index, and if it's not zero, it means we have data */ 1219 Channel->IBufferIndex = BufferIndex; 1220 _InterlockedExchange(&Channel->ChannelHasNewIBufferData, BufferIndex != 0); 1221 1222 /* If we have new data, and an event has been registered... */ 1223 if (!(Channel->IBufferIndex) && 1224 (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)) 1225 { 1226 /* Go ahead and signal it */ 1227 ChannelClearEvent(Channel, HasNewDataEvent); 1228 UNREFERENCED_PARAMETER(Status); 1229 } 1230 } 1231 1232 NTSTATUS 1233 NTAPI 1234 VTUTF8ChannelIRead(IN PSAC_CHANNEL Channel, 1235 IN PCHAR Buffer, 1236 IN ULONG BufferSize, 1237 IN PULONG ReturnBufferSize) 1238 { 1239 ULONG CopyChars, ReadLength; 1240 CHECK_PARAMETER1(Channel); 1241 CHECK_PARAMETER2(Buffer); 1242 CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE); 1243 1244 /* Assume failure */ 1245 *ReturnBufferSize = 0; 1246 1247 /* Check how many bytes are in the buffer */ 1248 if (Channel->ChannelInputBufferLength(Channel) == 0) 1249 { 1250 /* Apparently nothing. Make sure the flag indicates so too */ 1251 ASSERT(ChannelHasNewIBufferData(Channel) == FALSE); 1252 } 1253 else 1254 { 1255 /* Use the smallest number of bytes either in the buffer or requested */ 1256 ReadLength = min(Channel->ChannelInputBufferLength(Channel) * sizeof(WCHAR), 1257 BufferSize); 1258 1259 /* Do some cheezy buffer alignment */ 1260 CopyChars = ReadLength / sizeof(WCHAR); 1261 ReadLength = CopyChars * sizeof(WCHAR); 1262 ASSERT(CopyChars <= Channel->ChannelInputBufferLength(Channel)); 1263 1264 /* Copy them into the caller's buffer */ 1265 RtlCopyMemory(Buffer, Channel->IBuffer, ReadLength); 1266 1267 /* Update the channel's index past the copied (read) bytes */ 1268 VTUTF8ChannelSetIBufferIndex(Channel, 1269 VTUTF8ChannelGetIBufferIndex(Channel) - ReadLength); 1270 1271 /* Are there still bytes that haven't been read yet? */ 1272 if (Channel->ChannelInputBufferLength(Channel)) 1273 { 1274 /* Shift them up in the buffer */ 1275 RtlMoveMemory(Channel->IBuffer, 1276 &Channel->IBuffer[ReadLength], 1277 Channel->ChannelInputBufferLength(Channel) * 1278 sizeof(WCHAR)); 1279 } 1280 1281 /* Return the number of bytes we actually copied */ 1282 *ReturnBufferSize = ReadLength; 1283 } 1284 1285 /* Return success */ 1286 return STATUS_SUCCESS; 1287 } 1288 1289 NTSTATUS 1290 NTAPI 1291 VTUTF8ChannelIBufferIsFull(IN PSAC_CHANNEL Channel, 1292 OUT PBOOLEAN BufferStatus) 1293 { 1294 CHECK_PARAMETER1(Channel); 1295 1296 /* If the index is beyond the length, the buffer must be full */ 1297 *BufferStatus = VTUTF8ChannelGetIBufferIndex(Channel) > SAC_VTUTF8_IBUFFER_SIZE; 1298 return STATUS_SUCCESS; 1299 } 1300 1301 ULONG 1302 NTAPI 1303 VTUTF8ChannelIBufferLength(IN PSAC_CHANNEL Channel) 1304 { 1305 ASSERT(Channel); 1306 1307 /* The index is the length, so divide by two to get character count */ 1308 return VTUTF8ChannelGetIBufferIndex(Channel) / sizeof(WCHAR); 1309 } 1310 1311 WCHAR 1312 NTAPI 1313 VTUTF8ChannelIReadLast(IN PSAC_CHANNEL Channel) 1314 { 1315 PWCHAR LastCharLocation; 1316 WCHAR LastChar = 0; 1317 ASSERT(Channel); 1318 1319 /* Check if there's anything to read in the buffer */ 1320 if (Channel->ChannelInputBufferLength(Channel)) 1321 { 1322 /* Go back one character */ 1323 VTUTF8ChannelSetIBufferIndex(Channel, 1324 VTUTF8ChannelGetIBufferIndex(Channel) - 1325 sizeof(WCHAR)); 1326 1327 /* Read it, and clear its current value */ 1328 LastCharLocation = (PWCHAR)&Channel->IBuffer[VTUTF8ChannelGetIBufferIndex(Channel)]; 1329 LastChar = *LastCharLocation; 1330 *LastCharLocation = UNICODE_NULL; 1331 } 1332 1333 /* Return the last character */ 1334 return LastChar; 1335 } 1336 1337 NTSTATUS 1338 NTAPI 1339 VTUTF8ChannelIWrite(IN PSAC_CHANNEL Channel, 1340 IN PCHAR Buffer, 1341 IN ULONG BufferSize) 1342 { 1343 NTSTATUS Status; 1344 BOOLEAN IsFull; 1345 ULONG Index, i; 1346 CHECK_PARAMETER1(Channel); 1347 CHECK_PARAMETER2(Buffer); 1348 CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE); 1349 1350 /* First, check if the input buffer still has space */ 1351 Status = VTUTF8ChannelIBufferIsFull(Channel, &IsFull); 1352 if (!NT_SUCCESS(Status)) return Status; 1353 if (IsFull) return STATUS_UNSUCCESSFUL; 1354 1355 /* Get the current buffer index */ 1356 Index = VTUTF8ChannelGetIBufferIndex(Channel); 1357 if ((SAC_VTUTF8_IBUFFER_SIZE - Index) < BufferSize) 1358 { 1359 return STATUS_INSUFFICIENT_RESOURCES; 1360 } 1361 1362 /* Copy the new data */ 1363 for (i = 0; i < BufferSize; i++) 1364 { 1365 /* Convert the character */ 1366 if (SacTranslateUtf8ToUnicode(Buffer[i], 1367 IncomingUtf8ConversionBuffer, 1368 &IncomingUnicodeValue)) 1369 { 1370 /* Write it into the buffer */ 1371 *(PWCHAR)&Channel->IBuffer[VTUTF8ChannelGetIBufferIndex(Channel)] = 1372 IncomingUnicodeValue; 1373 1374 /* Update the index */ 1375 Index = VTUTF8ChannelGetIBufferIndex(Channel); 1376 VTUTF8ChannelSetIBufferIndex(Channel, Index + sizeof(WCHAR)); 1377 } 1378 } 1379 1380 /* Signal the event, if one was set */ 1381 if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) 1382 { 1383 ChannelSetEvent(Channel, HasNewDataEvent); 1384 } 1385 1386 /* All done */ 1387 return STATUS_SUCCESS; 1388 } 1389