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.
1008 lines
22 KiB
1008 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1999-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rawchan.c
|
|
|
|
Abstract:
|
|
|
|
Routines for managing channels in the sac.
|
|
|
|
Author:
|
|
|
|
Sean Selitrennikoff (v-seans) Sept, 2000.
|
|
Brian Guarraci (briangu) March, 2001.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "sac.h"
|
|
|
|
VOID
|
|
RawChannelSetIBufferIndex(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN ULONG IBufferIndex
|
|
);
|
|
|
|
ULONG
|
|
RawChannelGetIBufferIndex(
|
|
IN PSAC_CHANNEL Channel
|
|
);
|
|
|
|
NTSTATUS
|
|
RawChannelCreate(
|
|
IN OUT PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates a channel and returns a pointer to it.
|
|
|
|
Arguments:
|
|
|
|
Channel - The resulting channel.
|
|
|
|
OpenChannelCmd - All the parameters for the new channel
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, else the appropriate error code.
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
|
|
|
|
Channel->OBuffer = (PUCHAR)ALLOCATE_POOL(SAC_RAW_OBUFFER_SIZE, GENERAL_POOL_TAG);
|
|
ASSERT_STATUS(Channel->OBuffer, STATUS_NO_MEMORY);
|
|
|
|
Channel->IBuffer = (PUCHAR)ALLOCATE_POOL(SAC_RAW_IBUFFER_SIZE, GENERAL_POOL_TAG);
|
|
ASSERT_STATUS(Channel->IBuffer, STATUS_NO_MEMORY);
|
|
|
|
Channel->OBufferIndex = 0;
|
|
Channel->OBufferFirstGoodIndex = 0;
|
|
|
|
ChannelSetIBufferHasNewData(Channel, FALSE);
|
|
ChannelSetOBufferHasNewData(Channel, FALSE);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RawChannelDestroy(
|
|
IN OUT PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes a channel.
|
|
|
|
Arguments:
|
|
|
|
Channel - The channel to be closed
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, else the appropriate error code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
|
|
|
|
//
|
|
// Free the dynamically allocated memory
|
|
//
|
|
|
|
if (Channel->OBuffer) {
|
|
FREE_POOL(&(Channel->OBuffer));
|
|
Channel->OBuffer = NULL;
|
|
}
|
|
|
|
if (Channel->IBuffer) {
|
|
FREE_POOL(&(Channel->IBuffer));
|
|
Channel->IBuffer = NULL;
|
|
}
|
|
|
|
//
|
|
// Now that we've done our channel specific destroy,
|
|
// Call the general channel destroy
|
|
//
|
|
Status = ChannelDestroy(Channel);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RawChannelORead(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to read BufferSize characters from the output buffer.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Buffer - Outgoing buffer
|
|
BufferSize - Outgoing buffer size
|
|
ByteCount - The number of bytes actually read
|
|
|
|
|
|
Note: if the buffered data stored in the channel has now been sent.
|
|
If Channel is also in the Inactive state, the channel will
|
|
now be qualified for removal.
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PUCHAR RawBuffer;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(Buffer, STATUS_INVALID_PARAMETER_2);
|
|
ASSERT_STATUS(BufferSize > 0, STATUS_INVALID_PARAMETER_3);
|
|
ASSERT_STATUS(ByteCount, STATUS_INVALID_PARAMETER_4);
|
|
|
|
do {
|
|
|
|
//
|
|
// We read 0 characters
|
|
//
|
|
*ByteCount = 0;
|
|
|
|
//
|
|
// if there is no data to read,
|
|
// then report this to the caller
|
|
// else read as much data as we can
|
|
//
|
|
if (! ChannelHasNewOBufferData(Channel)) {
|
|
|
|
//
|
|
// We are out of data
|
|
//
|
|
Status = STATUS_NO_DATA_DETECTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Get the raw channel obuffer
|
|
//
|
|
RawBuffer = (PUCHAR)Channel->OBuffer;
|
|
|
|
//
|
|
// default: we succeded to copy data
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Attempt to read the buffer
|
|
//
|
|
do {
|
|
|
|
//
|
|
// Do a byte-wise copy of the OBuffer to the destination buffer
|
|
//
|
|
// Note: doing a byte-wise copy rather than an RtlCopyMemory is
|
|
// ok here since in general, this routine is called with
|
|
// a small buffer size. Naturally, if the use of Raw Channels
|
|
// changes and becomes dependent on a faster ORead, this
|
|
// will have to change.
|
|
//
|
|
|
|
//
|
|
// copy the char
|
|
//
|
|
Buffer[*ByteCount] = RawBuffer[Channel->OBufferFirstGoodIndex];
|
|
|
|
//
|
|
// increment the byte count to what we actually read
|
|
//
|
|
*ByteCount += 1;
|
|
|
|
//
|
|
// advance the pointer to the next good index
|
|
//
|
|
Channel->OBufferFirstGoodIndex = (Channel->OBufferFirstGoodIndex + 1) % SAC_RAW_OBUFFER_SIZE;
|
|
|
|
//
|
|
// Make sure we don't pass the end of the buffer
|
|
//
|
|
if (Channel->OBufferFirstGoodIndex == Channel->OBufferIndex) {
|
|
|
|
//
|
|
// we have no new data
|
|
//
|
|
ChannelSetOBufferHasNewData(Channel, FALSE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// confirm the obvious
|
|
//
|
|
ASSERT(*ByteCount > 0);
|
|
|
|
} while(*ByteCount < BufferSize);
|
|
|
|
} while ( FALSE );
|
|
|
|
#if DBG
|
|
//
|
|
// More sanity checking
|
|
//
|
|
|
|
if (Channel->OBufferFirstGoodIndex == Channel->OBufferIndex) {
|
|
ASSERT(ChannelHasNewOBufferData(Channel) == FALSE);
|
|
}
|
|
|
|
if (ChannelHasNewOBufferData(Channel) == FALSE) {
|
|
ASSERT(Channel->OBufferFirstGoodIndex == Channel->OBufferIndex);
|
|
}
|
|
#endif
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RawChannelOEcho(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCUCHAR String,
|
|
IN ULONG Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine puts the string out the headless port.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
String - Output string.
|
|
Length - The # of String bytes to process
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, otherwise status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(String, STATUS_INVALID_PARAMETER_2);
|
|
|
|
ASSERT(FIELD_OFFSET(HEADLESS_CMD_PUT_STRING, String) == 0); // ASSERT if anyone changes this structure.
|
|
|
|
//
|
|
// Default: we succeeded
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Only echo if the buffer has something to send
|
|
//
|
|
if (Size > 0) {
|
|
|
|
//
|
|
// Send the bytes
|
|
//
|
|
Status = IoMgrWriteData(
|
|
Channel,
|
|
String,
|
|
Size
|
|
);
|
|
|
|
//
|
|
// If we were successful, flush the channel's data in the iomgr
|
|
//
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = IoMgrFlushData(Channel);
|
|
}
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RawChannelOWrite(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCUCHAR String,
|
|
IN ULONG Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a string and prints it to the specified channel. If the channel
|
|
is the currently active channel, it puts the string out the headless port as well.
|
|
|
|
Note: Current Channel lock must be held by caller
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
String - Output string.
|
|
Length - The # of String bytes to process
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, otherwise status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(String, STATUS_INVALID_PARAMETER_2);
|
|
|
|
ASSERT(FIELD_OFFSET(HEADLESS_CMD_PUT_STRING, String) == 0); // ASSERT if anyone changes this structure.
|
|
|
|
do {
|
|
//
|
|
// if the current channel is the active channel and the user has selected
|
|
// to display this channel, relay the output directly to the user
|
|
//
|
|
if (IoMgrIsWriteEnabled(Channel) && ChannelSentToScreen(Channel)){
|
|
|
|
Status = RawChannelOEcho(
|
|
Channel,
|
|
String,
|
|
Size
|
|
);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Write the data to the channel's obuffer
|
|
//
|
|
Status = RawChannelOWrite2(
|
|
Channel,
|
|
String,
|
|
Size
|
|
);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RawChannelOWrite2(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCUCHAR String,
|
|
IN ULONG Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a string and prints it into directly into the
|
|
screen buffer with NO translation.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
|
|
String - String to print.
|
|
|
|
Size - the # of bytes to write.
|
|
|
|
Note: If String is a character string, the Size = strlen(String),
|
|
otherwise, Size = the # of bytes to process.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, otherwise status
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
BOOLEAN TrackIndex;
|
|
PUCHAR RawBuffer;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(String, STATUS_INVALID_PARAMETER_2);
|
|
|
|
//
|
|
// If size == 0, then we are done
|
|
//
|
|
if (Size == 0) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Get the raw channel obuffer
|
|
//
|
|
RawBuffer = (PUCHAR)Channel->OBuffer;
|
|
|
|
//
|
|
// We are not in direct IO mode, so we need to buffer the string
|
|
//
|
|
|
|
TrackIndex = FALSE;
|
|
|
|
for (i = 0; i < Size; i++) {
|
|
|
|
//
|
|
// Did we span over Good Data? If so, then we need to
|
|
// move the First Good pointer. The new First Good pointer position
|
|
// is immediately after the newest data entry in the buffer.
|
|
//
|
|
// Note: Since both indices start at the same position,
|
|
// we need to skip the case when RawBufferIndex == RawBufferFirstGoodIndex
|
|
// and there is no data in the buffer ((i == 0) && RawBufferHasNewData == FALSE),
|
|
// otherwise the RawBufferFirstGoodIndex will always track the RawBufferIndex.
|
|
// We need to let RawBufferIndex go around the ring buffer once before we enable
|
|
// tracking.
|
|
//
|
|
if ((Channel->OBufferIndex == Channel->OBufferFirstGoodIndex) &&
|
|
((i > 0) || (ChannelHasNewOBufferData(Channel) == TRUE))
|
|
) {
|
|
|
|
TrackIndex = TRUE;
|
|
|
|
}
|
|
|
|
ASSERT(Channel->OBufferIndex < SAC_RAW_OBUFFER_SIZE);
|
|
|
|
RawBuffer[Channel->OBufferIndex] = String[i];
|
|
|
|
Channel->OBufferIndex = (Channel->OBufferIndex + 1) % SAC_RAW_OBUFFER_SIZE;
|
|
|
|
if (TrackIndex) {
|
|
|
|
Channel->OBufferFirstGoodIndex = Channel->OBufferIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ChannelSetOBufferHasNewData(Channel, TRUE);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RawChannelOFlush(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send all the data in the raw buffer since the channel was last active
|
|
(or since the channel was created)
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, otherwise status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PUCHAR RawBuffer;
|
|
UCHAR ch;
|
|
ULONG ByteCount;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
|
|
//
|
|
// Get the raw channel obuffer
|
|
//
|
|
RawBuffer = (PUCHAR)Channel->OBuffer;
|
|
|
|
//
|
|
// default: we succeeded
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Send the Obuffer out to the headless port
|
|
//
|
|
while ( ChannelHasNewOBufferData(Channel) == TRUE ) {
|
|
|
|
//
|
|
// get a byte from the OBuffer
|
|
//
|
|
Status = RawChannelORead(
|
|
Channel,
|
|
&ch,
|
|
sizeof(ch),
|
|
&ByteCount
|
|
);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
|
|
ASSERT(ByteCount == 1);
|
|
if (ByteCount != 1) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Send the byte
|
|
//
|
|
Status = IoMgrWriteData(
|
|
Channel,
|
|
&ch,
|
|
sizeof(ch)
|
|
);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If we were successful, flush the channel's data in the iomgr
|
|
//
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = IoMgrFlushData(Channel);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RawChannelIWrite(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PCUCHAR Buffer,
|
|
IN ULONG BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a single character and adds it to the buffered input for this channel.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Buffer - Incoming buffer of UCHARs
|
|
BufferSize - Incoming buffer size
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, otherwise status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
BOOLEAN IBufferStatus;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(Buffer, STATUS_INVALID_PARAMETER_2);
|
|
ASSERT_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);
|
|
|
|
//
|
|
// Make sure we aren't full
|
|
//
|
|
Status = RawChannelIBufferIsFull(
|
|
Channel,
|
|
&IBufferStatus
|
|
);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// If there is no more room, then fail
|
|
//
|
|
if (IBufferStatus == TRUE) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// make sure there is enough room for the buffer
|
|
//
|
|
// Note: this prevents us from writing a portion of the buffer
|
|
// and then failing, leaving the caller in the state where
|
|
// it doesn't know how much of the buffer was written.
|
|
//
|
|
if ((SAC_RAW_IBUFFER_SIZE - RawChannelGetIBufferIndex(Channel)) < BufferSize) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// default: we succeeded
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Copy the new data to the ibuffer
|
|
//
|
|
RtlCopyMemory(
|
|
&Channel->IBuffer[RawChannelGetIBufferIndex(Channel)],
|
|
Buffer,
|
|
BufferSize
|
|
);
|
|
|
|
//
|
|
// Account for the newly appended data
|
|
//
|
|
RawChannelSetIBufferIndex(
|
|
Channel,
|
|
RawChannelGetIBufferIndex(Channel) + BufferSize
|
|
);
|
|
|
|
|
|
//
|
|
// Fire the HasNewData event if specified
|
|
//
|
|
if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) {
|
|
|
|
ASSERT(Channel->HasNewDataEvent);
|
|
ASSERT(Channel->HasNewDataEventObjectBody);
|
|
ASSERT(Channel->HasNewDataEventWaitObjectBody);
|
|
|
|
KeSetEvent(
|
|
Channel->HasNewDataEventWaitObjectBody,
|
|
EVENT_INCREMENT,
|
|
FALSE
|
|
);
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RawChannelIRead(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG ByteCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the first character in the input buffer, removes and returns it. If
|
|
there is none, it returns 0x0.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
Buffer - The buffer to read into
|
|
BufferSize - The size of the buffer
|
|
ByteCount - The # of bytes read
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
ULONG CopyChars;
|
|
ULONG CopySize;
|
|
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(Buffer, STATUS_INVALID_PARAMETER_2);
|
|
ASSERT_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
CopyChars = 0;
|
|
CopySize = 0;
|
|
|
|
//
|
|
// Default: no bytes were read
|
|
//
|
|
*ByteCount = 0;
|
|
|
|
//
|
|
// If there is nothing to send,
|
|
// then return that we read 0 bytes
|
|
//
|
|
if (Channel->IBufferLength(Channel) == 0) {
|
|
|
|
ASSERT(ChannelHasNewIBufferData(Channel) == FALSE);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Caclulate the largest buffer size we can use (and need), and then calculate
|
|
// the number of characters this refers to.
|
|
//
|
|
CopySize = Channel->IBufferLength(Channel) * sizeof(UCHAR);
|
|
CopySize = CopySize > BufferSize ? BufferSize : CopySize;
|
|
CopyChars = CopySize / sizeof(UCHAR);
|
|
|
|
//
|
|
// We need to recalc the CopySize in case there was a rounding down when
|
|
// computing CopyChars
|
|
//
|
|
CopySize = CopyChars * sizeof(UCHAR);
|
|
|
|
ASSERT(CopyChars <= Channel->IBufferLength(Channel));
|
|
|
|
//
|
|
// Do a block copy of the ibuffer to the destination buffer
|
|
//
|
|
RtlCopyMemory(
|
|
Buffer,
|
|
Channel->IBuffer,
|
|
CopySize
|
|
);
|
|
|
|
//
|
|
// subtract the # of characters copied from the character counter
|
|
//
|
|
RawChannelSetIBufferIndex(
|
|
Channel,
|
|
RawChannelGetIBufferIndex(Channel) - CopyChars
|
|
);
|
|
|
|
//
|
|
// If there is remaining data left in the Channel input buffer,
|
|
// shift it to the beginning
|
|
//
|
|
if (Channel->IBufferLength(Channel) > 0) {
|
|
|
|
RtlMoveMemory(&(Channel->IBuffer[0]),
|
|
&(Channel->IBuffer[CopyChars]),
|
|
Channel->IBufferLength(Channel) * sizeof(Channel->IBuffer[0])
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Send back the # of bytes read
|
|
//
|
|
*ByteCount = CopySize;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
RawChannelIBufferIsFull(
|
|
IN PSAC_CHANNEL Channel,
|
|
OUT BOOLEAN* BufferStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if the IBuffer is full
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
BufferStatus - on exit, TRUE if the buffer is full, otherwise FALSE
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
|
|
ASSERT_STATUS(BufferStatus, STATUS_INVALID_PARAMETER_2);
|
|
|
|
*BufferStatus = (BOOLEAN)(RawChannelGetIBufferIndex(Channel) >= (SAC_RAW_IBUFFER_SIZE-1));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
RawChannelIBufferLength(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines the length of the input buffer, treating the input buffer
|
|
contents as a string
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
|
|
Return Value:
|
|
|
|
The length of the current input buffer
|
|
|
|
--*/
|
|
{
|
|
ASSERT(Channel);
|
|
|
|
return (RawChannelGetIBufferIndex(Channel) / sizeof(UCHAR));
|
|
}
|
|
|
|
|
|
WCHAR
|
|
RawChannelIReadLast(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the last character in the input buffer, removes and returns it. If
|
|
there is none, it returns 0x0.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
|
|
Return Value:
|
|
|
|
Last character in the input buffer.
|
|
|
|
--*/
|
|
{
|
|
WCHAR Char;
|
|
|
|
ASSERT(Channel);
|
|
|
|
//
|
|
// default: no character was read
|
|
//
|
|
Char = UNICODE_NULL;
|
|
|
|
if (Channel->IBufferLength(Channel) > 0) {
|
|
|
|
RawChannelSetIBufferIndex(
|
|
Channel,
|
|
RawChannelGetIBufferIndex(Channel) - sizeof(UCHAR)
|
|
);
|
|
|
|
Char = Channel->IBuffer[RawChannelGetIBufferIndex(Channel)];
|
|
|
|
Channel->IBuffer[RawChannelGetIBufferIndex(Channel)] = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
return Char;
|
|
}
|
|
|
|
ULONG
|
|
RawChannelGetIBufferIndex(
|
|
IN PSAC_CHANNEL Channel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get teh ibuffer index
|
|
|
|
Arguments:
|
|
|
|
Channel - the channel to get the ibuffer index from
|
|
|
|
Environment:
|
|
|
|
The ibuffer index
|
|
|
|
--*/
|
|
{
|
|
ASSERT(Channel);
|
|
|
|
//
|
|
// Make sure the ibuffer index is atleast aligned to a WCHAR
|
|
//
|
|
ASSERT((Channel->IBufferIndex % sizeof(UCHAR)) == 0);
|
|
|
|
//
|
|
// Make sure the ibuffer index is in bounds
|
|
//
|
|
ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE);
|
|
|
|
return Channel->IBufferIndex;
|
|
}
|
|
|
|
VOID
|
|
RawChannelSetIBufferIndex(
|
|
IN PSAC_CHANNEL Channel,
|
|
IN ULONG IBufferIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the ibuffer index
|
|
|
|
Arguments:
|
|
|
|
Channel - the channel to get the ibuffer index from
|
|
IBufferIndex - the new inbuffer index
|
|
|
|
Environment:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
ASSERT(Channel);
|
|
|
|
//
|
|
// Make sure the ibuffer index is atleast aligned to a WCHAR
|
|
//
|
|
ASSERT((Channel->IBufferIndex % sizeof(UCHAR)) == 0);
|
|
|
|
//
|
|
// Make sure the ibuffer index is in bounds
|
|
//
|
|
ASSERT(Channel->IBufferIndex < SAC_RAW_IBUFFER_SIZE);
|
|
|
|
//
|
|
// Set the index
|
|
//
|
|
Channel->IBufferIndex = IBufferIndex;
|
|
|
|
//
|
|
// Set the has new data flag accordingly
|
|
//
|
|
ChannelSetIBufferHasNewData(
|
|
Channel,
|
|
Channel->IBufferIndex == 0 ? FALSE : TRUE
|
|
);
|
|
|
|
//
|
|
// Additional checking if the index == 0
|
|
//
|
|
if (Channel->IBufferIndex == 0) {
|
|
|
|
//
|
|
// Clear the Has New Data event if specified
|
|
//
|
|
if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) {
|
|
|
|
ASSERT(Channel->HasNewDataEvent);
|
|
ASSERT(Channel->HasNewDataEventObjectBody);
|
|
ASSERT(Channel->HasNewDataEventWaitObjectBody);
|
|
|
|
KeClearEvent(Channel->HasNewDataEventWaitObjectBody);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|