#define NDEBUG
#include <debug.h>
+#define COMMON_LEAD_TRAIL (COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE)
+
/* GLOBALS ********************************************************************/
/*
IN PCOORD Start,
IN UINT Length)
{
- if (Buff->ScreenBufferSize.X <= Start->X + Length)
- {
- UpdateRect->Left = 0;
- }
- else
- {
- UpdateRect->Left = Start->X;
- }
- if (Buff->ScreenBufferSize.X <= Start->X + Length)
+ if ((UINT)Buff->ScreenBufferSize.X <= Start->X + Length)
{
+ UpdateRect->Left = 0;
UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
}
else
{
+ UpdateRect->Left = Start->X;
UpdateRect->Right = Start->X + Length - 1;
}
UpdateRect->Top = Start->Y;
IN USHORT NewScreenAttrib,
IN USHORT NewPopupAttrib)
{
- DWORD X, Y, Length;
+ ULONG X, Y, Length;
PCHAR_INFO Ptr;
COORD TopLeft = {0};
Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
Length = NumCodesToWrite;
- // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
- // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
-
while (Length--)
{
- // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
- Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
+ Ptr = ConioCoordToPointer(Buffer, X, Y);
/*
* Change the current colors only if they are the old ones.
/* Make sure ReadRegion is inside the screen buffer */
ConioInitRect(&ScreenBuffer, 0, 0,
- Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
+ Buffer->ScreenBufferSize.Y - 1,
+ Buffer->ScreenBufferSize.X - 1);
if (!ConioGetIntersection(&CapturedReadRegion, &ScreenBuffer, &CapturedReadRegion))
{
/*
WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1,
&CurCharInfo->Char.AsciiChar, 1, NULL, NULL);
}
- CurCharInfo->Attributes = Ptr->Attributes;
+ CurCharInfo->Attributes = (Ptr->Attributes & ~COMMON_LEAD_TRAIL);
++Ptr;
++CurCharInfo;
}
/* Make sure WriteRegion is inside the screen buffer */
ConioInitRect(&ScreenBuffer, 0, 0,
- Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
+ Buffer->ScreenBufferSize.Y - 1,
+ Buffer->ScreenBufferSize.X - 1);
if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
{
/*
/* Make sure WriteRegion is inside the screen buffer */
ConioInitRect(&ScreenBuffer, 0, 0,
- Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
+ Buffer->ScreenBufferSize.Y - 1,
+ Buffer->ScreenBufferSize.X - 1);
if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
{
/*
return Status;
}
-NTSTATUS NTAPI
-ConDrvReadConsoleOutputString(IN PCONSOLE Console,
- IN PTEXTMODE_SCREEN_BUFFER Buffer,
- IN CODE_TYPE CodeType,
- OUT PVOID StringBuffer,
- IN ULONG NumCodesToRead,
- IN PCOORD ReadCoord,
- // OUT PCOORD EndCoord,
- OUT PULONG NumCodesRead OPTIONAL)
+NTSTATUS FASTCALL
+IntReadConsoleOutputStringAscii(IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ OUT PVOID StringBuffer,
+ IN ULONG NumCodesToRead,
+ IN PCOORD ReadCoord,
+ OUT PULONG NumCodesRead OPTIONAL)
{
- SHORT Xpos, Ypos;
- PVOID ReadBuffer;
+ ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
+ LPBYTE ReadBuffer = StringBuffer;
+ SHORT Xpos = ReadCoord->X;
+ SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
ULONG i;
- ULONG CodeSize;
PCHAR_INFO Ptr;
+ BOOLEAN bCJK = Console->IsCJK;
- if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
+ for (i = 0; i < NumCodesToRead; ++i)
{
- return STATUS_INVALID_PARAMETER;
+ Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
+
+ ConsoleOutputUnicodeToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
+ ReadBuffer += CodeSize;
+
+ Xpos++;
+ if (Xpos == Buffer->ScreenBufferSize.X)
+ {
+ Xpos = 0;
+ Ypos++;
+ if (Ypos == Buffer->ScreenBufferSize.Y)
+ {
+ Ypos = 0;
+ }
+ }
+
+ /* For Chinese, Japanese and Korean */
+ if (bCJK && (Ptr->Attributes & COMMON_LVB_LEADING_BYTE))
+ {
+ Xpos++;
+ if (Xpos == Buffer->ScreenBufferSize.X)
+ {
+ Xpos = 0;
+ Ypos++;
+ if (Ypos == Buffer->ScreenBufferSize.Y)
+ {
+ Ypos = 0;
+ }
+ }
+ ++i;
+ }
}
- /* Validity checks */
- ASSERT(Console == Buffer->Header.Console);
- ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
+ if (NumCodesRead)
+ *NumCodesRead = i;
- //
- // FIXME: Make overflow checks on ReadCoord !!!!!!
- //
+ return STATUS_SUCCESS;
+}
- if (NumCodesRead) *NumCodesRead = 0;
+NTSTATUS FASTCALL
+IntReadConsoleOutputStringUnicode(IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ OUT PVOID StringBuffer,
+ IN ULONG NumCodesToRead,
+ IN PCOORD ReadCoord,
+ OUT PULONG NumCodesRead OPTIONAL)
+{
+ ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
+ LPBYTE ReadBuffer = StringBuffer;
+ SHORT Xpos = ReadCoord->X;
+ SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
+ ULONG i, nNumChars = 0;
+ PCHAR_INFO Ptr;
+ BOOLEAN bCJK = Console->IsCJK;
- switch (CodeType)
+ for (i = 0; i < NumCodesToRead; ++i, ++nNumChars)
{
- case CODE_ASCII:
- CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
- break;
+ Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
- case CODE_UNICODE:
- CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
- break;
+ *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
+ ReadBuffer += CodeSize;
- case CODE_ATTRIBUTE:
- CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
- break;
+ Xpos++;
+ if (Xpos == Buffer->ScreenBufferSize.X)
+ {
+ Xpos = 0;
+ Ypos++;
+ if (Ypos == Buffer->ScreenBufferSize.Y)
+ {
+ Ypos = 0;
+ }
+ }
- default:
- return STATUS_INVALID_PARAMETER;
+ /* For Chinese, Japanese and Korean */
+ if (bCJK && (Ptr->Attributes & COMMON_LVB_LEADING_BYTE))
+ {
+ Xpos++;
+ if (Xpos == Buffer->ScreenBufferSize.X)
+ {
+ Xpos = 0;
+ Ypos++;
+ if (Ypos == Buffer->ScreenBufferSize.Y)
+ {
+ Ypos = 0;
+ }
+ }
+ ++i;
+ }
}
- ReadBuffer = StringBuffer;
- Xpos = ReadCoord->X;
- Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
+ if (NumCodesRead)
+ *NumCodesRead = nNumChars;
- /*
- * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
- *
- * If the number of attributes (resp. characters) to be read from extends
- * beyond the end of the specified screen buffer row, attributes (resp.
- * characters) are read from the next row. If the number of attributes
- * (resp. characters) to be read from extends beyond the end of the console
- * screen buffer, attributes (resp. characters) up to the end of the console
- * screen buffer are read.
- *
- * TODO: Do NOT loop up to NumCodesToRead, but stop before
- * if we are going to overflow...
- */
- // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
- for (i = 0; i < min(NumCodesToRead, Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y); ++i)
- {
- // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
- Ptr = &Buffer->Buffer[Xpos + Ypos * Buffer->ScreenBufferSize.X];
+ return STATUS_SUCCESS;
+}
- switch (CodeType)
- {
- case CODE_ASCII:
- ConsoleOutputUnicodeToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
- break;
+NTSTATUS FASTCALL
+IntReadConsoleOutputStringAttributes(IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ OUT PVOID StringBuffer,
+ IN ULONG NumCodesToRead,
+ IN PCOORD ReadCoord,
+ OUT PULONG NumCodesRead OPTIONAL)
+{
+ ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
+ LPBYTE ReadBuffer = StringBuffer;
+ SHORT Xpos = ReadCoord->X;
+ SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
+ ULONG i;
+ PCHAR_INFO Ptr;
- case CODE_UNICODE:
- *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
- break;
+ for (i = 0; i < NumCodesToRead; ++i)
+ {
+ Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
- case CODE_ATTRIBUTE:
- *(PWORD)ReadBuffer = Ptr->Attributes;
- break;
- }
- ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
- // ++Ptr;
+ *(PWORD)ReadBuffer = Ptr->Attributes;
+ ReadBuffer += CodeSize;
Xpos++;
-
if (Xpos == Buffer->ScreenBufferSize.X)
{
Xpos = 0;
Ypos++;
-
if (Ypos == Buffer->ScreenBufferSize.Y)
{
Ypos = 0;
}
}
- // EndCoord->X = Xpos;
- // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
+ if (Xpos > 0 && Console->IsCJK)
+ {
+ ReadBuffer -= CodeSize;
+ *(PWORD)ReadBuffer &= ~COMMON_LVB_LEADING_BYTE;
+ }
if (NumCodesRead)
- *NumCodesRead = (ULONG)((ULONG_PTR)ReadBuffer - (ULONG_PTR)StringBuffer) / CodeSize;
- // <= NumCodesToRead
+ *NumCodesRead = NumCodesToRead;
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
-ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
- IN PTEXTMODE_SCREEN_BUFFER Buffer,
- IN CODE_TYPE CodeType,
- IN PVOID StringBuffer,
- IN ULONG NumCodesToWrite,
- IN PCOORD WriteCoord,
- // OUT PCOORD EndCoord,
- OUT PULONG NumCodesWritten OPTIONAL)
+ConDrvReadConsoleOutputString(IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ IN CODE_TYPE CodeType,
+ OUT PVOID StringBuffer,
+ IN ULONG NumCodesToRead,
+ IN PCOORD ReadCoord,
+ OUT PULONG NumCodesRead OPTIONAL)
{
- NTSTATUS Status = STATUS_SUCCESS;
- PVOID WriteBuffer = NULL;
- PWCHAR tmpString = NULL;
- DWORD X, Y, Length; // , Written = 0;
- ULONG CodeSize;
- PCHAR_INFO Ptr;
-
- if (Console == NULL || Buffer == NULL || WriteCoord == NULL /* || EndCoord == NULL */)
+ if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
{
return STATUS_INVALID_PARAMETER;
}
/* Validity checks */
ASSERT(Console == Buffer->Header.Console);
- ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToWrite == 0));
-
- //
- // FIXME: Make overflow checks on WriteCoord !!!!!!
- //
+ ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
- if (NumCodesWritten) *NumCodesWritten = 0;
+ if (NumCodesRead)
+ *NumCodesRead = 0;
switch (CodeType)
{
case CODE_ASCII:
- CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
- break;
+ return IntReadConsoleOutputStringAscii(Console,
+ Buffer,
+ StringBuffer,
+ NumCodesToRead,
+ ReadCoord,
+ NumCodesRead);
case CODE_UNICODE:
- CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
- break;
+ return IntReadConsoleOutputStringUnicode(Console,
+ Buffer,
+ StringBuffer,
+ NumCodesToRead,
+ ReadCoord,
+ NumCodesRead);
case CODE_ATTRIBUTE:
- CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
- break;
+ return IntReadConsoleOutputStringAttributes(Console,
+ Buffer,
+ StringBuffer,
+ NumCodesToRead,
+ ReadCoord,
+ NumCodesRead);
default:
return STATUS_INVALID_PARAMETER;
}
+}
- if (CodeType == CODE_ASCII)
+static NTSTATUS
+IntWriteConsoleOutputStringUnicode(
+ IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ IN PVOID StringBuffer,
+ IN ULONG NumCodesToWrite,
+ IN PCOORD WriteCoord,
+ OUT PULONG NumCodesWritten OPTIONAL)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PWCHAR WriteBuffer = StringBuffer;
+ ULONG i, X, Y, Length;
+ PCHAR_INFO Ptr;
+ BOOLEAN bCJK = Console->IsCJK;
+
+ if (!StringBuffer)
+ goto Cleanup;
+
+ X = WriteCoord->X;
+ Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
+ Length = NumCodesToWrite;
+
+ for (i = 0; i < Length; ++i)
{
- /* Convert the ASCII string into Unicode before writing it to the console */
- Length = MultiByteToWideChar(Console->OutputCodePage, 0,
- (PCHAR)StringBuffer,
- NumCodesToWrite,
- NULL, 0);
- tmpString = WriteBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
- if (WriteBuffer)
+ Ptr = ConioCoordToPointer(Buffer, X, Y);
+
+ Ptr->Char.UnicodeChar = *WriteBuffer;
+ ++WriteBuffer;
+
+ ++X;
+ if (X == Buffer->ScreenBufferSize.X)
{
- MultiByteToWideChar(Console->OutputCodePage, 0,
- (PCHAR)StringBuffer,
- NumCodesToWrite,
- (PWCHAR)WriteBuffer, Length);
+ X = 0;
+ ++Y;
+ if (Y == Buffer->ScreenBufferSize.Y)
+ {
+ Y = 0;
+ }
}
- else
+
+ /* For Chinese, Japanese and Korean */
+ if (bCJK && Ptr->Char.UnicodeChar >= 0x80 &&
+ mk_wcwidth_cjk(Ptr->Char.UnicodeChar) == 2)
{
- Status = STATUS_NO_MEMORY;
- }
+ /* A full-width character cannot cross a line boundary */
+ if (X == Buffer->ScreenBufferSize.X - 1)
+ {
+ /* go to next line */
+ X = 0;
+ ++Y;
+ if (Y == Buffer->ScreenBufferSize.Y)
+ {
+ Y = 0;
+ }
+ Ptr = ConioCoordToPointer(Buffer, X, Y);
+ }
+
+ /* the leading byte */
+ Ptr->Attributes = Buffer->ScreenDefaultAttrib;
+ Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
+ ++i;
+
+ /* the trailing byte */
+ Ptr = ConioCoordToPointer(Buffer, X, Y);
+ Ptr->Attributes = Buffer->ScreenDefaultAttrib;
+ Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
- // FIXME: Quick fix: fix the CodeType and CodeSize since the
- // ASCII string was converted into UNICODE.
- // A proper fix needs to be written.
- CodeType = CODE_UNICODE;
- CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
+ ++X;
+ if (X == Buffer->ScreenBufferSize.X)
+ {
+ X = 0;
+ ++Y;
+ if (Y == Buffer->ScreenBufferSize.Y)
+ {
+ Y = 0;
+ }
+ }
+ }
}
- else
+
+Cleanup:
+ if (NumCodesWritten)
+ *NumCodesWritten = NumCodesToWrite;
+ return Status;
+}
+
+static NTSTATUS
+IntWriteConsoleOutputStringAscii(
+ IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ IN PVOID StringBuffer,
+ IN ULONG NumCodesToWrite,
+ IN PCOORD WriteCoord,
+ OUT PULONG NumCodesWritten OPTIONAL)
+{
+ NTSTATUS Status;
+ PWCHAR tmpString;
+ ULONG Length;
+
+ if (!StringBuffer)
{
- /* For CODE_UNICODE or CODE_ATTRIBUTE, we are already OK */
- WriteBuffer = StringBuffer;
+ if (NumCodesWritten)
+ *NumCodesWritten = NumCodesToWrite;
+
+ return STATUS_SUCCESS;
}
- if (WriteBuffer == NULL || !NT_SUCCESS(Status)) goto Cleanup;
+ /* Convert the ASCII string into Unicode before writing it to the console */
+ Length = MultiByteToWideChar(Console->OutputCodePage, 0,
+ StringBuffer,
+ NumCodesToWrite,
+ NULL, 0);
+ tmpString = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
+ if (!tmpString)
+ return STATUS_NO_MEMORY;
+
+ MultiByteToWideChar(Console->OutputCodePage, 0,
+ StringBuffer,
+ NumCodesToWrite,
+ tmpString, Length);
+
+ Status = IntWriteConsoleOutputStringUnicode(Console,
+ Buffer,
+ tmpString,
+ Length,
+ WriteCoord,
+ NumCodesWritten);
+ ConsoleFreeHeap(tmpString);
+ return Status;
+}
+
+static NTSTATUS
+IntWriteConsoleOutputStringAttribute(
+ IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ IN PVOID StringBuffer,
+ IN ULONG NumCodesToWrite,
+ IN PCOORD WriteCoord,
+ OUT PULONG NumCodesWritten OPTIONAL)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PWORD WriteBuffer = StringBuffer;
+ ULONG i, X, Y, Length;
+ PCHAR_INFO Ptr;
+
+ if (!StringBuffer)
+ goto Cleanup;
X = WriteCoord->X;
Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
Length = NumCodesToWrite;
- // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
- // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
- while (Length--)
+ for (i = 0; i < Length; ++i)
{
- // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
- Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
-
- switch (CodeType)
- {
- case CODE_ASCII:
- case CODE_UNICODE:
- Ptr->Char.UnicodeChar = *(PWCHAR)WriteBuffer;
- break;
+ Ptr = ConioCoordToPointer(Buffer, X, Y);
- case CODE_ATTRIBUTE:
- Ptr->Attributes = *(PWORD)WriteBuffer;
- break;
- }
- WriteBuffer = (PVOID)((ULONG_PTR)WriteBuffer + CodeSize);
- // ++Ptr;
+ Ptr->Attributes = (*WriteBuffer & ~COMMON_LEAD_TRAIL);
+ ++WriteBuffer;
- // Written++;
- if (++X == Buffer->ScreenBufferSize.X)
+ ++X;
+ if (X == Buffer->ScreenBufferSize.X)
{
X = 0;
-
- if (++Y == Buffer->ScreenBufferSize.Y)
+ ++Y;
+ if (Y == Buffer->ScreenBufferSize.Y)
{
Y = 0;
}
}
}
+Cleanup:
+ if (NumCodesWritten)
+ *NumCodesWritten = NumCodesToWrite;
+ return Status;
+}
+
+NTSTATUS NTAPI
+ConDrvWriteConsoleOutputString(
+ IN PCONSOLE Console,
+ IN PTEXTMODE_SCREEN_BUFFER Buffer,
+ IN CODE_TYPE CodeType,
+ IN PVOID StringBuffer,
+ IN ULONG NumCodesToWrite,
+ IN PCOORD WriteCoord,
+ OUT PULONG NumCodesWritten OPTIONAL)
+{
+ NTSTATUS Status;
+ SMALL_RECT UpdateRect;
+
+ if (Console == NULL || Buffer == NULL || WriteCoord == NULL /* || EndCoord == NULL */)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Validity checks */
+ ASSERT(Console == Buffer->Header.Console);
+ ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToWrite == 0));
+
+ if (NumCodesWritten)
+ *NumCodesWritten = 0;
+
+ switch (CodeType)
+ {
+ case CODE_ASCII:
+ Status = IntWriteConsoleOutputStringAscii(
+ Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
+ break;
+
+ case CODE_UNICODE:
+ Status = IntWriteConsoleOutputStringUnicode(
+ Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
+ break;
+
+ case CODE_ATTRIBUTE:
+ Status = IntWriteConsoleOutputStringAttribute(
+ Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
{
- SMALL_RECT UpdateRect;
ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
TermDrawRegion(Console, &UpdateRect);
}
- // EndCoord->X = X;
- // EndCoord->Y = (Y + Buffer->ScreenBufferSize.Y - Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-
-Cleanup:
- if (tmpString) RtlFreeHeap(RtlGetProcessHeap(), 0, tmpString);
-
- if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
return Status;
}
IN PCOORD WriteCoord,
OUT PULONG NumCodesWritten OPTIONAL)
{
- DWORD X, Y, Length; // , Written = 0;
+ ULONG X, Y, i;
PCHAR_INFO Ptr;
+ BOOLEAN bLead, bFullwidth;
if (Console == NULL || Buffer == NULL || WriteCoord == NULL)
{
X = WriteCoord->X;
Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
- Length = NumCodesToWrite;
// Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
// Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
- while (Length--)
+ /* For Chinese, Japanese and Korean */
+ bLead = TRUE;
+ bFullwidth = FALSE;
+ if (Console->IsCJK)
+ {
+ bFullwidth = (mk_wcwidth_cjk(Code.UnicodeChar) == 2);
+ if (X > 0)
+ {
+ Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
+ if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
+ {
+ Ptr->Char.UnicodeChar = L' ';
+ Ptr->Attributes &= ~COMMON_LVB_LEADING_BYTE;
+ }
+ }
+ }
+
+ for (i = 0; i < NumCodesToWrite; ++i)
{
- // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
- Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
+ Ptr = ConioCoordToPointer(Buffer, X, Y);
switch (CodeType)
{
case CODE_ASCII:
case CODE_UNICODE:
Ptr->Char.UnicodeChar = Code.UnicodeChar;
+ Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
+ if (bFullwidth)
+ {
+ if (bLead)
+ Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
+ else
+ Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
+ }
break;
case CODE_ATTRIBUTE:
- Ptr->Attributes = Code.Attribute;
+ Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
+ Ptr->Attributes |= (Code.Attribute & ~COMMON_LEAD_TRAIL);
break;
}
- // ++Ptr;
- // Written++;
- if (++X == Buffer->ScreenBufferSize.X)
+ ++X;
+ if (X == Buffer->ScreenBufferSize.X)
{
X = 0;
-
- if (++Y == Buffer->ScreenBufferSize.Y)
+ ++Y;
+ if (Y == Buffer->ScreenBufferSize.Y)
{
Y = 0;
}
}
+
+ bLead = !bLead;
+ }
+
+ if ((NumCodesToWrite & 1) & bFullwidth)
+ {
+ if (X + Y * Buffer->ScreenBufferSize.X > 0)
+ {
+ Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
+ Ptr->Char.UnicodeChar = L' ';
+ Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
+ }
}
if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
OUT PCOORD MaximumViewSize,
OUT PWORD Attributes)
{
+ COORD LargestWindowSize;
+
if (Console == NULL || Buffer == NULL || ScreenBufferSize == NULL ||
CursorPosition == NULL || ViewOrigin == NULL || ViewSize == NULL ||
MaximumViewSize == NULL || Attributes == NULL)
*ViewSize = Buffer->ViewSize;
*Attributes = Buffer->ScreenDefaultAttrib;
- // FIXME: Refine the computation
- *MaximumViewSize = Buffer->ScreenBufferSize;
+ /*
+ * Retrieve the largest possible console window size, taking
+ * into account the size of the console screen buffer.
+ */
+ TermGetLargestConsoleWindowSize(Console, &LargestWindowSize);
+ LargestWindowSize.X = min(LargestWindowSize.X, Buffer->ScreenBufferSize.X);
+ LargestWindowSize.Y = min(LargestWindowSize.Y, Buffer->ScreenBufferSize.Y);
+ *MaximumViewSize = LargestWindowSize;
return STATUS_SUCCESS;
}
/* Make sure the source rectangle is inside the screen buffer */
ConioInitRect(&ScreenBuffer, 0, 0,
- Buffer->ScreenBufferSize.Y - 1, Buffer->ScreenBufferSize.X - 1);
+ Buffer->ScreenBufferSize.Y - 1,
+ Buffer->ScreenBufferSize.X - 1);
if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle))
{
return STATUS_SUCCESS;
IN PSMALL_RECT WindowRect)
{
SMALL_RECT CapturedWindowRect;
+ COORD LargestWindowSize;
if (Console == NULL || Buffer == NULL || WindowRect == NULL)
return STATUS_INVALID_PARAMETER;
CapturedWindowRect = *WindowRect;
- if (Absolute == FALSE)
+ if (!Absolute)
{
- /* Relative positions given. Transform them to absolute ones */
+ /* Relative positions are given, transform them to absolute ones */
CapturedWindowRect.Left += Buffer->ViewOrigin.X;
CapturedWindowRect.Top += Buffer->ViewOrigin.Y;
CapturedWindowRect.Right += Buffer->ViewOrigin.X + Buffer->ViewSize.X - 1;
CapturedWindowRect.Bottom += Buffer->ViewOrigin.Y + Buffer->ViewSize.Y - 1;
}
- /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
- if ( (CapturedWindowRect.Left < 0) || (CapturedWindowRect.Top < 0) ||
- (CapturedWindowRect.Right >= Buffer->ScreenBufferSize.X) ||
- (CapturedWindowRect.Bottom >= Buffer->ScreenBufferSize.Y) ||
- (CapturedWindowRect.Right <= CapturedWindowRect.Left) ||
- (CapturedWindowRect.Bottom <= CapturedWindowRect.Top) )
+ /*
+ * The MSDN documentation on SetConsoleWindowInfo is partially wrong about
+ * the performed checks this API performs. While it is correct that the
+ * 'Right'/'Bottom' members cannot be strictly smaller than the 'Left'/'Top'
+ * members, they can be equal.
+ * Also, if the 'Left' or 'Top' members are negative, this is automatically
+ * corrected for, and the window rectangle coordinates are shifted accordingly.
+ */
+ if ((CapturedWindowRect.Right < CapturedWindowRect.Left) ||
+ (CapturedWindowRect.Bottom < CapturedWindowRect.Top))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * Forbid window sizes larger than the largest allowed console window size,
+ * taking into account the size of the console screen buffer.
+ */
+ TermGetLargestConsoleWindowSize(Console, &LargestWindowSize);
+ LargestWindowSize.X = min(LargestWindowSize.X, Buffer->ScreenBufferSize.X);
+ LargestWindowSize.Y = min(LargestWindowSize.Y, Buffer->ScreenBufferSize.Y);
+ if ((CapturedWindowRect.Right - CapturedWindowRect.Left + 1 > LargestWindowSize.X) ||
+ (CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1 > LargestWindowSize.Y))
{
return STATUS_INVALID_PARAMETER;
}
+ /* Shift the window rectangle coordinates if 'Left' or 'Top' are negative */
+ if (CapturedWindowRect.Left < 0)
+ {
+ CapturedWindowRect.Right -= CapturedWindowRect.Left;
+ CapturedWindowRect.Left = 0;
+ }
+ if (CapturedWindowRect.Top < 0)
+ {
+ CapturedWindowRect.Bottom -= CapturedWindowRect.Top;
+ CapturedWindowRect.Top = 0;
+ }
+
+ /* Clip the window rectangle to the screen buffer */
+ CapturedWindowRect.Right = min(CapturedWindowRect.Right , Buffer->ScreenBufferSize.X);
+ CapturedWindowRect.Bottom = min(CapturedWindowRect.Bottom, Buffer->ScreenBufferSize.Y);
+
Buffer->ViewOrigin.X = CapturedWindowRect.Left;
Buffer->ViewOrigin.Y = CapturedWindowRect.Top;
Buffer->ViewSize.X = CapturedWindowRect.Right - CapturedWindowRect.Left + 1;
Buffer->ViewSize.Y = CapturedWindowRect.Bottom - CapturedWindowRect.Top + 1;
- // TermResizeTerminal(Console);
+ TermResizeTerminal(Console);
return STATUS_SUCCESS;
}