diff --git a/reactos/drivers/sac/driver/sacdrv.h b/reactos/drivers/sac/driver/sacdrv.h index 17fd29671ac..771c2e7ad83 100644 --- a/reactos/drivers/sac/driver/sacdrv.h +++ b/reactos/drivers/sac/driver/sacdrv.h @@ -158,6 +158,8 @@ #define SAC_MAX_MESSAGES 200 #define SAC_VTUTF8_COL_WIDTH 80 #define SAC_VTUTF8_COL_HEIGHT 25 +#define SAC_VTUTF8_ROW_HEIGHT 24 +#define MAX_UTF8_ENCODE_BLOCK_LENGTH (Utf8ConversionBufferSize / 3 - 1) // // Channel flags @@ -1012,6 +1014,17 @@ VerifyEventWaitable( OUT PVOID *ActualWaitObject ); +BOOLEAN +NTAPI +SacTranslateUnicodeToUtf8( + IN PWCHAR SourceBuffer, + IN ULONG SourceBufferLength, + OUT PCHAR DestinationBuffer, + IN ULONG DestinationBufferSize, + OUT PULONG UTF8Count, + OUT PULONG ProcessedCount +); + // // SAC Command Functions // diff --git a/reactos/drivers/sac/driver/vtutf8chan.c b/reactos/drivers/sac/driver/vtutf8chan.c index 946a90ceafe..747ebe8317f 100644 --- a/reactos/drivers/sac/driver/vtutf8chan.c +++ b/reactos/drivers/sac/driver/vtutf8chan.c @@ -27,9 +27,398 @@ typedef struct _SAC_CURSOR_DATA C_ASSERT(sizeof(SAC_CURSOR_DATA) == 6); +typedef struct _SAC_STATIC_ESCAPE_STRING +{ + WCHAR Sequence[10]; + ULONG Size; + ULONG Action; +} SAC_STATIC_ESCAPE_STRING, *PSAC_STATIC_ESCAPE_STRING; + +SAC_STATIC_ESCAPE_STRING SacStaticEscapeStrings [] = +{ + { L"[A", 2, 0 }, + { L"[B", 2, 1 }, + { L"[C", 2, 2 }, + { L"[D", 2, 3 }, + { L"[0Z", 3, 11 }, + { L"[K", 2, 12 }, + { L"[1K", 3, 13 }, + { L"[2K", 3, 14 }, + { L"[J", 2, 15 }, + { L"[1J", 3, 16 }, + { L"[2J", 3, 17 }, +}; + #define SAC_VTUTF8_OBUFFER_SIZE 0x2D00 #define SAC_VTUTF8_IBUFFER_SIZE 0x2000 +BOOLEAN +NTAPI +VTUTF8ChannelScanForNumber(IN PWCHAR String, + OUT PULONG Number) +{ + /* If the first character is invalid, fail early */ + if ((*String < L'0') || (*String > L'9')) return FALSE; + + /* Otherwise, initialize the output and loop the string */ + *Number = 0; + while ((*String >= L'0') && (*String <= L'9')) + { + /* Save the first decimal */ + *Number = 10 * *Number; + + /* Compute and add the second one */ + *Number += *++String - L'0'; + } + + /* All done */ + return TRUE; +} + +NTSTATUS +NTAPI +VTUTF8ChannelAnsiDispatch( + IN NTSTATUS Status, + IN ULONG AnsiCode, + IN PWCHAR Data, + IN ULONG Length + ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +VTUTF8ChannelProcessAttributes( + IN PSAC_CHANNEL Channel, + IN UCHAR Attribute + ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +FORCEINLINE +VOID +VTUTF8ChannelAssertCursor(IN PSAC_CHANNEL Channel) +{ + ASSERT(Channel->CursorRow < SAC_VTUTF8_ROW_HEIGHT); + ASSERT(Channel->CursorCol < SAC_VTUTF8_COL_WIDTH); +} + +ULONG +NTAPI +VTUTF8ChannelConsumeEscapeSequence(IN PSAC_CHANNEL Channel, + IN PWCHAR String) +{ + ULONG Number, Number2, Number3, i, Action, Result; + PWCHAR Sequence; + PSAC_CURSOR_DATA Cursor; + ASSERT(String[0] == L'\x1B'); + + for (i = 0; i < RTL_NUMBER_OF(SacStaticEscapeStrings); i++) + { + if (!wcsncmp(String + 1, + SacStaticEscapeStrings[i].Sequence, + SacStaticEscapeStrings[i].Size)) + { + Action = SacStaticEscapeStrings[i].Action; + Result = SacStaticEscapeStrings[i].Size + 1; + Number = Number2 = Number3 = 1; + goto ProcessString; + } + } + + if (String[1] != L'[') return 0; + + Sequence = String + 2; + switch (*Sequence) + { + case L'A': + Action = 0; + break; + case L'B': + Action = 1; + break; + case L'C': + Action = 3; //bug + break; + case L'D': + Action = 2; //bug + break; + case L'K': + Action = 12; + break; + default: + if (!VTUTF8ChannelScanForNumber(Sequence, &Number)) return 0; + + while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; + + if (*Sequence == 'm') + { + switch (Number) + { + case 0: + Action = 4; + break; + case 1: + Action = 7; + break; + + case 5: + Action = 5; + break; + + case 7: + Action = 9; + break; + + case 22: + Action = 8; + break; + + case 25: + Action = 6; + break; + + case 27: + Action = 10; + break; + + default: + if ((Number < 40) || (Number > 47)) + { + if ((Number < 30) || (Number > 39)) + { + ASSERT(FALSE); + return 0; + } + + Action = 22; + } + else + { + Action = 21; + } + } + } + else + { + if (*Sequence != L';') return 0; + Sequence++; + + if (!VTUTF8ChannelScanForNumber(Sequence, &Number2)) return 0; + + while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; + + if (*Sequence == L'm') + { + Action = 20; + } + else + { + if (*Sequence == L'H') + { + Action = 18; + } + + if (*Sequence != L';') return 0; + + Sequence++; + + if ((*Sequence == L'H') || (*Sequence == L'f')) + { + Action = 18; + } + else if (*Sequence == L'r') + { + Action = 19; + } + else + { + if (!VTUTF8ChannelScanForNumber(Sequence, &Number3)) return 0; + + while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; + + if (*Sequence == L'm') + { + Action = 23; + } + else + { + return 0; + } + } + } + } + } + + Result = Sequence - String + 1; + +ProcessString: + Cursor = (PSAC_CURSOR_DATA)Channel->OBuffer; + VTUTF8ChannelAssertCursor(Channel); + switch (Action) + { + case 0: + if (Channel->CursorRow < Number) + { + Channel->CursorRow = 0; + } + else + { + Channel->CursorRow -= Number; + } + VTUTF8ChannelAssertCursor(Channel); + break; + + case 1: + if (Channel->CursorRow >= SAC_VTUTF8_ROW_HEIGHT) + { + Channel->CursorRow = SAC_VTUTF8_ROW_HEIGHT; + } + else + { + Channel->CursorRow += Number; + } + VTUTF8ChannelAssertCursor(Channel); + break; + + case 3: + if (Channel->CursorCol < Number) + { + Channel->CursorCol = 0; + } + else + { + Channel->CursorCol -= Number; + } + VTUTF8ChannelAssertCursor(Channel); + break; + + case 2: + if (Channel->CursorCol >= SAC_VTUTF8_COL_WIDTH) + { + Channel->CursorCol = SAC_VTUTF8_COL_WIDTH; + } + else + { + Channel->CursorCol += Number; + } + VTUTF8ChannelAssertCursor(Channel); + break; + + case 4: + Channel->CursorVisible = 0; + Channel->CursorX = 40; + Channel->CursorY = 37; + break; + + case 5: + Channel->CursorVisible |= 1; + break; + + case 6: + Channel->CursorVisible &= ~1; + break; + + case 7: + Channel->CursorVisible |= 2; + break; + + case 8: + Channel->CursorVisible &= ~2; + break; + + case 9: + Channel->CursorVisible |= 4; + break; + + case 10: + Channel->CursorVisible &= ~4; + break; + + case 12: + for (i = Channel->CursorCol; i < SAC_VTUTF8_COL_WIDTH; i++) + { + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorVisible = Channel->CursorVisible; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorX = Channel->CursorY; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorY = Channel->CursorX; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorValue = ' '; + } + break; + + case 13: + for (i = 0; i < (Channel->CursorCol + 1); i++) + { + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorVisible = Channel->CursorVisible; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorX = Channel->CursorY; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorY = Channel->CursorX; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorValue = ' '; + } + break; + + case 14: + for (i = 0; i < SAC_VTUTF8_COL_WIDTH; i++) + { + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorVisible = Channel->CursorVisible; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorX = Channel->CursorY; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorY = Channel->CursorX; + Cursor[(Channel->CursorRow * SAC_VTUTF8_COL_WIDTH) + + (i * SAC_VTUTF8_ROW_HEIGHT)].CursorValue = ' '; + } + break; + + case 15: + break; + + case 16: + break; + + case 17: + break; + + case 18: + break; + + case 19: + break; + + case 20: + Channel->CursorY = Number; + Channel->CursorX = Number2; + break; + + case 21: + Channel->CursorX = Number; + break; + + case 22: + Channel->CursorY = Number; + break; + + case 23: + Channel->CursorVisible = Number; + Channel->CursorY = Number2; + Channel->CursorX = Number3; + break; + default: + break; + } + + return Result; +} + NTSTATUS NTAPI VTUTF8ChannelOInit(IN PSAC_CHANNEL Channel) @@ -104,56 +493,12 @@ VTUTF8ChannelDestroy(IN PSAC_CHANNEL Channel) NTSTATUS NTAPI -VTUTF8ChannelORead( - IN PSAC_CHANNEL Channel, - IN PCHAR Buffer, - IN ULONG BufferSize, - OUT PULONG ByteCount - ) +VTUTF8ChannelORead(IN PSAC_CHANNEL Channel, + IN PCHAR Buffer, + IN ULONG BufferSize, + OUT PULONG ByteCount) { - return STATUS_NOT_IMPLEMENTED; -} - -BOOLEAN -NTAPI -VTUTF8ChannelScanForNumber( - IN PWCHAR String, - OUT PULONG Number - ) -{ - return FALSE; -} - -NTSTATUS -NTAPI -VTUTF8ChannelAnsiDispatch( - IN NTSTATUS Status, - IN ULONG AnsiCode, - IN PWCHAR Data, - IN ULONG Length - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -NTAPI -VTUTF8ChannelProcessAttributes( - IN PSAC_CHANNEL Channel, - IN UCHAR Attribute - ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -NTAPI -VTUTF8ChannelConsumeEscapeSequence( - IN PSAC_CHANNEL Channel, - IN PWCHAR String - ) -{ - return STATUS_NOT_IMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } NTSTATUS @@ -180,7 +525,88 @@ VTUTF8ChannelOEcho(IN PSAC_CHANNEL Channel, IN PCHAR String, IN ULONG Size) { - return STATUS_NOT_IMPLEMENTED; + 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; } NTSTATUS