Synchronize with trunk revision 59781.
[reactos.git] / drivers / sac / driver / vtutf8chan.c
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 /* FUNCTIONS *****************************************************************/
19
20 typedef struct _SAC_CURSOR_DATA
21 {
22 UCHAR CursorX;
23 UCHAR CursorY;
24 UCHAR CursorVisible;
25 WCHAR CursorValue;
26 } SAC_CURSOR_DATA, *PSAC_CURSOR_DATA;
27
28 C_ASSERT(sizeof(SAC_CURSOR_DATA) == 6);
29
30 #define SAC_VTUTF8_OBUFFER_SIZE 0x2D00
31 #define SAC_VTUTF8_IBUFFER_SIZE 0x2000
32
33 NTSTATUS
34 NTAPI
35 VTUTF8ChannelOInit(IN PSAC_CHANNEL Channel)
36 {
37 PSAC_CURSOR_DATA Cursor;
38 ULONG x, y;
39 CHECK_PARAMETER(Channel);
40
41 /* Set the current channel cursor parameters */
42 Channel->CursorVisible = 0;
43 Channel->CursorX = 40;
44 Channel->CursorY = 37;
45
46 /* Loop the output buffer height by width */
47 Cursor = (PSAC_CURSOR_DATA)Channel->OBuffer;
48 y = SAC_VTUTF8_COL_HEIGHT - 1;
49 do
50 {
51 x = SAC_VTUTF8_COL_WIDTH;
52 do
53 {
54 /* For every character, set the defaults */
55 Cursor->CursorValue = ' ';
56 Cursor->CursorX = 40;
57 Cursor->CursorY = 38;
58
59 /* Move to the next character */
60 Cursor++;
61 } while (--x);
62 } while (--y);
63
64 /* All done */
65 return STATUS_SUCCESS;
66 }
67
68 NTSTATUS
69 NTAPI
70 VTUTF8ChannelCreate(IN PSAC_CHANNEL Channel)
71 {
72 NTSTATUS Status;
73 CHECK_PARAMETER(Channel);
74
75 /* Allocate the output buffer */
76 Channel->OBuffer = SacAllocatePool(SAC_VTUTF8_OBUFFER_SIZE, GLOBAL_BLOCK_TAG);
77 CHECK_ALLOCATION(Channel->OBuffer);
78
79 /* Allocate the input buffer */
80 Channel->IBuffer = SacAllocatePool(SAC_VTUTF8_IBUFFER_SIZE, GLOBAL_BLOCK_TAG);
81 CHECK_ALLOCATION(Channel->IBuffer);
82
83 /* Initialize the output stream */
84 Status = VTUTF8ChannelOInit(Channel);
85 if (NT_SUCCESS(Status)) return Status;
86
87 /* Reset all flags and return success */
88 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0);
89 _InterlockedExchange(&Channel->ChannelHasNewIBufferData, 0);
90 return STATUS_SUCCESS;
91 }
92
93 NTSTATUS
94 NTAPI
95 VTUTF8ChannelDestroy(IN PSAC_CHANNEL Channel)
96 {
97 CHECK_PARAMETER(Channel);
98
99 /* Free the buffer and then destroy the channel */
100 if (Channel->OBuffer) SacFreePool(Channel->OBuffer);
101 if (Channel->IBuffer) SacFreePool(Channel->IBuffer);
102 return ChannelDestroy(Channel);
103 }
104
105 NTSTATUS
106 NTAPI
107 VTUTF8ChannelORead(
108 IN PSAC_CHANNEL Channel,
109 IN PCHAR Buffer,
110 IN ULONG BufferSize,
111 OUT PULONG ByteCount
112 )
113 {
114 return STATUS_NOT_IMPLEMENTED;
115 }
116
117 BOOLEAN
118 NTAPI
119 VTUTF8ChannelScanForNumber(
120 IN PWCHAR String,
121 OUT PULONG Number
122 )
123 {
124 return FALSE;
125 }
126
127 NTSTATUS
128 NTAPI
129 VTUTF8ChannelAnsiDispatch(
130 IN NTSTATUS Status,
131 IN ULONG AnsiCode,
132 IN PWCHAR Data,
133 IN ULONG Length
134 )
135 {
136 return STATUS_NOT_IMPLEMENTED;
137 }
138
139 NTSTATUS
140 NTAPI
141 VTUTF8ChannelProcessAttributes(
142 IN PSAC_CHANNEL Channel,
143 IN UCHAR Attribute
144 )
145 {
146 return STATUS_NOT_IMPLEMENTED;
147 }
148
149 NTSTATUS
150 NTAPI
151 VTUTF8ChannelConsumeEscapeSequence(
152 IN PSAC_CHANNEL Channel,
153 IN PWCHAR String
154 )
155 {
156 return STATUS_NOT_IMPLEMENTED;
157 }
158
159 NTSTATUS
160 NTAPI
161 VTUTF8ChannelOFlush(
162 IN PSAC_CHANNEL Channel
163 )
164 {
165 return STATUS_NOT_IMPLEMENTED;
166 }
167
168 NTSTATUS
169 NTAPI
170 VTUTF8ChannelOWrite2(IN PSAC_CHANNEL Channel,
171 IN PCHAR String,
172 IN ULONG Size)
173 {
174 return STATUS_NOT_IMPLEMENTED;
175 }
176
177 NTSTATUS
178 NTAPI
179 VTUTF8ChannelOEcho(IN PSAC_CHANNEL Channel,
180 IN PCHAR String,
181 IN ULONG Size)
182 {
183 return STATUS_NOT_IMPLEMENTED;
184 }
185
186 NTSTATUS
187 NTAPI
188 VTUTF8ChannelOWrite(IN PSAC_CHANNEL Channel,
189 IN PCHAR String,
190 IN ULONG Length)
191 {
192 NTSTATUS Status;
193 CHECK_PARAMETER1(Channel);
194 CHECK_PARAMETER2(String);
195
196 /* Call the lower level function */
197 Status = VTUTF8ChannelOWrite2(Channel, String, Length / sizeof(WCHAR));
198 if (NT_SUCCESS(Status))
199 {
200 /* Is the channel enabled for output? */
201 if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled))
202 {
203 /* Go ahead and output it */
204 Status = VTUTF8ChannelOEcho(Channel, String, Length);
205 }
206 else
207 {
208 /* Otherwise, just remember that we have new data */
209 _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 1);
210 }
211 }
212
213 /* We're done */
214 return Status;
215 }
216
217 ULONG
218 NTAPI
219 VTUTF8ChannelGetIBufferIndex(IN PSAC_CHANNEL Channel)
220 {
221 ASSERT(Channel);
222 ASSERT((Channel->IBufferIndex % sizeof(WCHAR)) == 0);
223 ASSERT(Channel->IBufferIndex < SAC_VTUTF8_IBUFFER_SIZE);
224
225 /* Return the current buffer index */
226 return Channel->IBufferIndex;
227 }
228
229 VOID
230 NTAPI
231 VTUTF8ChannelSetIBufferIndex(IN PSAC_CHANNEL Channel,
232 IN ULONG BufferIndex)
233 {
234 NTSTATUS Status;
235 ASSERT(Channel);
236 ASSERT((Channel->IBufferIndex % sizeof(WCHAR)) == 0);
237 ASSERT(Channel->IBufferIndex < SAC_VTUTF8_IBUFFER_SIZE);
238
239 /* Set the new index, and if it's not zero, it means we have data */
240 Channel->IBufferIndex = BufferIndex;
241 _InterlockedExchange(&Channel->ChannelHasNewIBufferData, BufferIndex != 0);
242
243 /* If we have new data, and an event has been registered... */
244 if (!(Channel->IBufferIndex) &&
245 (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT))
246 {
247 /* Go ahead and signal it */
248 ChannelClearEvent(Channel, HasNewDataEvent);
249 UNREFERENCED_PARAMETER(Status);
250 }
251 }
252
253 NTSTATUS
254 NTAPI
255 VTUTF8ChannelIRead(IN PSAC_CHANNEL Channel,
256 IN PCHAR Buffer,
257 IN ULONG BufferSize,
258 IN PULONG ReturnBufferSize)
259 {
260 ULONG CopyChars;
261 CHECK_PARAMETER1(Channel);
262 CHECK_PARAMETER2(Buffer);
263 CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);
264
265 /* Assume failure */
266 *ReturnBufferSize = 0;
267
268 /* Check how many bytes are in the buffer */
269 if (Channel->ChannelInputBufferLength(Channel) == 0)
270 {
271 /* Apparently nothing. Make sure the flag indicates so too */
272 ASSERT(ChannelHasNewIBufferData(Channel) == FALSE);
273 }
274 else
275 {
276 /* Use the smallest number of bytes either in the buffer or requested */
277 CopyChars = min(Channel->ChannelInputBufferLength(Channel) * sizeof(WCHAR),
278 BufferSize);
279 ASSERT(CopyChars <= Channel->ChannelInputBufferLength(Channel));
280
281 /* Copy them into the caller's buffer */
282 RtlCopyMemory(Buffer, Channel->IBuffer, CopyChars);
283
284 /* Update the channel's index past the copied (read) bytes */
285 VTUTF8ChannelSetIBufferIndex(Channel,
286 VTUTF8ChannelGetIBufferIndex(Channel) - CopyChars);
287
288 /* Are there still bytes that haven't been read yet? */
289 if (Channel->ChannelInputBufferLength(Channel))
290 {
291 /* Shift them up in the buffer */
292 RtlMoveMemory(Channel->IBuffer,
293 &Channel->IBuffer[CopyChars],
294 Channel->ChannelInputBufferLength(Channel) *
295 sizeof(WCHAR));
296 }
297
298 /* Return the number of bytes we actually copied */
299 *ReturnBufferSize = CopyChars;
300 }
301
302 /* Return success */
303 return STATUS_SUCCESS;
304 }
305
306 NTSTATUS
307 NTAPI
308 VTUTF8ChannelIBufferIsFull(IN PSAC_CHANNEL Channel,
309 OUT PBOOLEAN BufferStatus)
310 {
311 CHECK_PARAMETER1(Channel);
312
313 /* If the index is beyond the length, the buffer must be full */
314 *BufferStatus = VTUTF8ChannelGetIBufferIndex(Channel) > SAC_VTUTF8_IBUFFER_SIZE;
315 return STATUS_SUCCESS;
316 }
317
318 ULONG
319 NTAPI
320 VTUTF8ChannelIBufferLength(IN PSAC_CHANNEL Channel)
321 {
322 ASSERT(Channel);
323
324 /* The index is the length, so divide by two to get character count */
325 return VTUTF8ChannelGetIBufferIndex(Channel) / sizeof(WCHAR);
326 }
327
328 WCHAR
329 NTAPI
330 VTUTF8ChannelIReadLast(IN PSAC_CHANNEL Channel)
331 {
332 PWCHAR LastCharLocation;
333 WCHAR LastChar = 0;
334 ASSERT(Channel);
335
336 /* Check if there's anything to read in the buffer */
337 if (Channel->ChannelInputBufferLength(Channel))
338 {
339 /* Go back one character */
340 VTUTF8ChannelSetIBufferIndex(Channel,
341 VTUTF8ChannelGetIBufferIndex(Channel) -
342 sizeof(WCHAR));
343
344 /* Read it, and clear its current value */
345 LastCharLocation = (PWCHAR)&Channel->IBuffer[VTUTF8ChannelGetIBufferIndex(Channel)];
346 LastChar = *LastCharLocation;
347 *LastCharLocation = UNICODE_NULL;
348 }
349
350 /* Return the last character */
351 return LastChar;
352 }
353
354 NTSTATUS
355 NTAPI
356 VTUTF8ChannelIWrite(IN PSAC_CHANNEL Channel,
357 IN PCHAR Buffer,
358 IN ULONG BufferSize)
359 {
360 NTSTATUS Status;
361 BOOLEAN IsFull;
362 ULONG Index, i;
363 CHECK_PARAMETER1(Channel);
364 CHECK_PARAMETER2(Buffer);
365 CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);
366
367 /* First, check if the input buffer still has space */
368 Status = VTUTF8ChannelIBufferIsFull(Channel, &IsFull);
369 if (!NT_SUCCESS(Status)) return Status;
370 if (IsFull) return STATUS_UNSUCCESSFUL;
371
372 /* Get the current buffer index */
373 Index = VTUTF8ChannelGetIBufferIndex(Channel);
374 if ((SAC_VTUTF8_IBUFFER_SIZE - Index) < BufferSize)
375 {
376 return STATUS_INSUFFICIENT_RESOURCES;
377 }
378
379 /* Copy the new data */
380 for (i = 0; i < BufferSize; i++)
381 {
382 /* Convert the character */
383 if (SacTranslateUtf8ToUnicode(Buffer[i],
384 IncomingUtf8ConversionBuffer,
385 &IncomingUnicodeValue))
386 {
387 /* Write it into the buffer */
388 *(PWCHAR)&Channel->IBuffer[VTUTF8ChannelGetIBufferIndex(Channel)] =
389 IncomingUnicodeValue;
390
391 /* Update the index */
392 Index = VTUTF8ChannelGetIBufferIndex(Channel);
393 VTUTF8ChannelSetIBufferIndex(Channel, Index + sizeof(WCHAR));
394 }
395 }
396
397 /* Signal the event, if one was set */
398 if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
399 {
400 ChannelSetEvent(Channel, HasNewDataEvent);
401 }
402
403 /* All done */
404 return STATUS_SUCCESS;
405 }