NTSTATUS NTAPI RawChannelOEcho(IN PSAC_CHANNEL Channel, IN PCHAR String, IN ULONG Length) { NTSTATUS Status = STATUS_SUCCESS; CHECK_PARAMETER1(Channel); CHECK_PARAMETER2(String); if (Length) { Status = ConMgrWriteData(Channel, String, Length); if (NT_SUCCESS(Status)) ConMgrFlushData(Channel); } return Status; }
NTSTATUS NTAPI RawChannelOFlush(IN PSAC_CHANNEL Channel) { NTSTATUS Status; ULONG ByteCount; CHAR Dummy; CHECK_PARAMETER1(Channel); while (ChannelHasNewOBufferData(Channel)) { Status = RawChannelORead(Channel, &Dummy, sizeof(Dummy), &ByteCount); if (!NT_SUCCESS(Status)) return Status; CHECK_PARAMETER_WITH_STATUS(ByteCount == 1, STATUS_UNSUCCESSFUL); Status = ConMgrWriteData(Channel, &Dummy, sizeof(Dummy)); if (!NT_SUCCESS(Status)) return Status; } return ConMgrFlushData(Channel); }
NTSTATUS NTAPI VTUTF8ChannelOFlush(IN PSAC_CHANNEL Channel) { NTSTATUS Status; PSAC_VTUTF8_SCREEN Screen; INT Color[2], Position[2]; ULONG Utf8ProcessedCount, Utf8Count, R, C, ForeColor, BackColor, Attribute; PWCHAR TmpBuffer; BOOLEAN Overflow = FALSE; CHECK_PARAMETER(Channel); /* Set the cell buffer position */ Screen = (PSAC_VTUTF8_SCREEN)Channel->OBuffer; /* Allocate a temporary buffer */ TmpBuffer = SacAllocatePool(40, GLOBAL_BLOCK_TAG); if (!TmpBuffer) { Status = STATUS_NO_MEMORY; goto Quickie; } /* First, clear the screen */ Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiClearScreen, NULL, 0); if (!NT_SUCCESS(Status)) goto Quickie; /* Next, reset the cursor position */ Position[1] = 0; Position[0] = 0; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; /* Finally, reset the attributes */ Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiClearAttributes, NULL, 0); if (!NT_SUCCESS(Status)) goto Quickie; /* Now set the current cell attributes */ Attribute = Channel->CellFlags; Status = VTUTF8ChannelProcessAttributes(Channel, Attribute); if (!NT_SUCCESS(Status)) goto Quickie; /* And set the current cell colors */ ForeColor = Channel->CellForeColor; BackColor = Channel->CellBackColor; Color[1] = BackColor; Color[0] = ForeColor; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetColors, Color, sizeof(Color)); if (!NT_SUCCESS(Status)) goto Quickie; /* Now loop all the characters in the cell buffer */ for (R = 0; R < SAC_VTUTF8_ROW_HEIGHT; R++) { /* Across every row */ for (C = 0; C < SAC_VTUTF8_COL_WIDTH; C++) { /* Check if there's been a change in colors */ if ((Screen->Cell[R][C].CellBackColor != BackColor) || (Screen->Cell[R][C].CellForeColor != ForeColor)) { /* New colors are being drawn -- are we also on a new row now? */ if (Overflow) { /* Reposition the cursor correctly */ Position[1] = R; Position[0] = C; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; Overflow = FALSE; } /* Cache the new colors */ ForeColor = Screen->Cell[R][C].CellForeColor; BackColor = Screen->Cell[R][C].CellBackColor; /* Set them on the screen */ Color[1] = BackColor; Color[0] = ForeColor; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetColors, Color, sizeof(Color)); if (!NT_SUCCESS(Status)) goto Quickie; } /* Check if there's been a change in attributes */ if (Screen->Cell[R][C].CellFlags != Attribute) { /* Yep! Are we also on a new row now? */ if (Overflow) { /* Reposition the cursor correctly */ Position[1] = R; Position[0] = C; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; Overflow = FALSE; } /* Set the new attributes on screen */ Attribute = Screen->Cell[R][C].CellFlags; Status = VTUTF8ChannelProcessAttributes(Channel, Attribute); if (!NT_SUCCESS(Status)) goto Quickie; } /* Time to write the character -- are we on a new row now? */ if (Overflow) { /* Reposition the cursor correctly */ Position[1] = R; Position[0] = C; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; Overflow = FALSE; } /* Write the character into our temporary buffer */ *TmpBuffer = Screen->Cell[R][C].Char; TmpBuffer[1] = UNICODE_NULL; /* Convert it to UTF-8 */ if (!SacTranslateUnicodeToUtf8(TmpBuffer, 1, Utf8ConversionBuffer, Utf8ConversionBufferSize, &Utf8Count, &Utf8ProcessedCount)) { /* Bail out if this failed */ Status = STATUS_UNSUCCESSFUL; goto Quickie; } /* Make sure we have a remaining valid character */ if (Utf8Count) { /* Write it out on the wire */ Status = ConMgrWriteData(Channel, Utf8ConversionBuffer, Utf8Count); if (!NT_SUCCESS(Status)) goto Quickie; } } /* All the characters on the row are done, indicate we need a reset */ Overflow = TRUE; } /* Everything is done, set the positition one last time */ Position[1] = Channel->CursorRow; Position[0] = Channel->CursorCol; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; /* Set the current attribute one last time */ Status = VTUTF8ChannelProcessAttributes(Channel, Channel->CellFlags); if (!NT_SUCCESS(Status)) goto Quickie; /* Set the current colors one last time */ Color[1] = Channel->CellBackColor; Color[0] = Channel->CellForeColor; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetColors, Color, sizeof(Color)); if (!NT_SUCCESS(Status)) goto Quickie; /* Flush all the data out on the wire */ Status = ConMgrFlushData(Channel); Quickie: /* We're done, free the temporary buffer */ if (TmpBuffer) SacFreePool(TmpBuffer); /* Indicate that all new data has been flushed now */ if (NT_SUCCESS(Status)) { _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0); } /* Return the result */ return Status; }
NTSTATUS NTAPI VTUTF8ChannelAnsiDispatch(IN PSAC_CHANNEL Channel, IN SAC_ANSI_DISPATCH AnsiCode, IN INT* Data, IN ULONG Length) { NTSTATUS Status = STATUS_SUCCESS; PCHAR LocalBuffer = NULL, Tmp; INT l; CHECK_PARAMETER1(Channel); /* Check which ANSI sequence we should output */ switch (AnsiCode) { /* Send the [2J (Clear Screen and Reset Cursor) */ case SacAnsiClearScreen: Tmp = "\x1B[2J"; break; /* Send the [0J (Clear From Position Till End Of Screen) */ case SacAnsiClearEndOfScreen: Tmp = "\x1B[0J"; break; /* Send the [0K (Clear from Position Till End Of Line) */ case SacAnsiClearEndOfLine: Tmp = "\x1B[0K"; break; /* Send a combination of two [#m attribute changes */ case SacAnsiSetColors: /* Allocate a small local buffer for it */ LocalBuffer = SacAllocatePool(SAC_VTUTF8_COL_WIDTH, GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(LocalBuffer); /* Caller should have sent two colors as two integers */ if (!(Data) || (Length != 8)) { Status = STATUS_INVALID_PARAMETER; break; } /* Create the escape sequence string */ l = sprintf(LocalBuffer, "\x1B[%dm\x1B[%dm", Data[1], Data[0]); ASSERT((l + 1)*sizeof(UCHAR) < SAC_VTUTF8_COL_WIDTH); ASSERT(LocalBuffer); Tmp = LocalBuffer; break; /* Send the [#;#H (Cursor Position) sequence */ case SacAnsiSetPosition: /* Allocate a small local buffer for it */ LocalBuffer = SacAllocatePool(SAC_VTUTF8_COL_WIDTH, GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(LocalBuffer); /* Caller should have sent the position as two integers */ if (!(Data) || (Length != 8)) { Status = STATUS_INVALID_PARAMETER; break; } /* Create the escape sequence string */ l = sprintf(LocalBuffer, "\x1B[%d;%dH", Data[1] + 1, Data[0] + 1); ASSERT((l + 1)*sizeof(UCHAR) < SAC_VTUTF8_COL_WIDTH); ASSERT(LocalBuffer); Tmp = LocalBuffer; break; /* Send the [0m sequence (Set Attribute 0) */ case SacAnsiClearAttributes: Tmp = "\x1B[0m"; break; /* Send the [7m sequence (Set Attribute 7) */ case SacAnsiSetInverseAttribute: Tmp = "\x1B[7m"; break; /* Send the [27m sequence (Set Attribute 27) */ case SacAnsiClearInverseAttribute: Tmp = "\x1B[27m"; break; /* Send the [5m sequence (Set Attribute 5) */ case SacAnsiSetBlinkAttribute: Tmp = "\x1B[5m"; break; /* Send the [25m sequence (Set Attribute 25) */ case SacAnsiClearBlinkAttribute: Tmp = "\x1B[25m"; break; /* Send the [1m sequence (Set Attribute 1) */ case SacAnsiSetBoldAttribute: Tmp = "\x1B[1m"; break; /* Send the [22m sequence (Set Attribute 22) */ case SacAnsiClearBoldAttribute: Tmp = "\x1B[22m"; break; /* We don't recognize it */ default: Status = STATUS_INVALID_PARAMETER; break; } /* Did everything work above? */ if (NT_SUCCESS(Status)) { /* Go write out the sequence */ Status = ConMgrWriteData(Channel, Tmp, strlen(Tmp)); if (NT_SUCCESS(Status)) { /* Now flush it */ Status = ConMgrFlushData(Channel); } } /* Free the temporary buffer, if any, and return the status */ if (LocalBuffer) SacFreePool(LocalBuffer); return Status; }
NTSTATUS NTAPI VTUTF8ChannelOEcho(IN PSAC_CHANNEL Channel, IN PCHAR String, IN ULONG Size) { NTSTATUS Status = STATUS_SUCCESS; PWSTR pwch; ULONG i, k, TranslatedCount, UTF8TranslationSize; BOOLEAN Result; CHECK_PARAMETER1(Channel); CHECK_PARAMETER2(String); /* Return success if there's nothing to echo */ if (!(Size / sizeof(WCHAR))) return Status; /* Start with the input string */ pwch = (PWCHAR)String; /* First, figure out how much is outside of the block length alignment */ k = (Size / sizeof(WCHAR)) % MAX_UTF8_ENCODE_BLOCK_LENGTH; if (k) { /* Translate the misaligned portion */ Result = SacTranslateUnicodeToUtf8(pwch, k, Utf8ConversionBuffer, Utf8ConversionBufferSize, &UTF8TranslationSize, &TranslatedCount); ASSERT(k == TranslatedCount); if (!Result) { /* If we couldn't translate, write failure to break out below */ Status = STATUS_UNSUCCESSFUL; } else { /* Write the misaligned portion into the buffer */ Status = ConMgrWriteData(Channel, Utf8ConversionBuffer, UTF8TranslationSize); } /* If translation or write failed, bail out */ if (!NT_SUCCESS(Status)) goto Return; } /* Push the string to its new location (this could be a noop if aligned) */ pwch += k; /* Now figure out how many aligned blocks we have, and loop each one */ k = (Size / sizeof(WCHAR)) / MAX_UTF8_ENCODE_BLOCK_LENGTH; for (i = 0; i < k; i++) { /* Translate the aligned block */ Result = SacTranslateUnicodeToUtf8(pwch, MAX_UTF8_ENCODE_BLOCK_LENGTH, Utf8ConversionBuffer, Utf8ConversionBufferSize, &UTF8TranslationSize, &TranslatedCount); ASSERT(MAX_UTF8_ENCODE_BLOCK_LENGTH == TranslatedCount); ASSERT(UTF8TranslationSize > 0); if (!Result) { /* Set failure here, we'll break out below */ Status = STATUS_UNSUCCESSFUL; } else { /* Move the string location to the next aligned block */ pwch += MAX_UTF8_ENCODE_BLOCK_LENGTH; /* Write the aligned block into the buffer */ Status = ConMgrWriteData(Channel, Utf8ConversionBuffer, UTF8TranslationSize); } /* If translation or write failed, bail out */ if (!NT_SUCCESS(Status)) break; } Return: ASSERT(pwch == (PWSTR)(String + Size)); if (NT_SUCCESS(Status)) Status = ConMgrFlushData(Channel); return Status; }