ReactOS 0.4.15-dev-7953-g1f49173
stream.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Console Utilities Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Provides basic abstraction wrappers around CRT streams or
5 * Win32 console API I/O functions, to deal with i18n + Unicode
6 * related problems.
7 * COPYRIGHT: Copyright 2017-2018 ReactOS Team
8 * Copyright 2017-2018 Hermes Belusca-Maito
9 */
10
18/*
19 * Enable this define if you want to only use CRT functions to output
20 * UNICODE stream to the console, as in the way explained by
21 * http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
22 */
24// #define USE_CRT
25
26/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
27#define UNICODE
28#define _UNICODE
29
30#ifdef USE_CRT
31#include <fcntl.h>
32#include <io.h>
33#endif /* USE_CRT */
34
35#include <windef.h>
36#include <winbase.h>
37#include <winnls.h>
38// #include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
39#include <wincon.h> // Console APIs (only if kernel32 support included)
40#include <strsafe.h>
41
42#include "conutils.h"
43#include "stream.h"
44#include "stream_private.h"
45
46
47/*
48 * Standard console streams, initialized by
49 * calls to ConStreamInit/ConInitStdStreams.
50 */
51#if 0 // FIXME!
53{
54 {0}, // StdIn
55 {0}, // StdOut
56 {0}, // StdErr
57};
58#else
62#endif
63
64
65/* Stream translation modes */
66#ifdef USE_CRT
67/* Lookup table to convert CON_STREAM_MODE to CRT mode */
68static int ConToCRTMode[] =
69{
70 _O_BINARY, // Binary (untranslated)
71 _O_TEXT, // AnsiText (translated)
72 _O_WTEXT, // WideText (UTF16 with BOM; translated)
73 _O_U16TEXT, // UTF16Text (UTF16 without BOM; translated)
74 _O_U8TEXT, // UTF8Text (UTF8 without BOM; translated)
75};
76
77/*
78 * See http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
79 * and http://archives.miloush.net/michkap/archive/2009/08/14/9869928.html
80 * for more details.
81 */
82
83// NOTE1: May the translated mode be cached somehow?
84// NOTE2: We may also call IsConsoleHandle to directly set the mode to
85// _O_U16TEXT if it's ok??
86// NOTE3: _setmode returns the previous mode, or -1 if failure.
87#define CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage) \
88do { \
89 fflush((Stream)->fStream); \
90 if ((Mode) < ARRAYSIZE(ConToCRTMode)) \
91 _setmode(_fileno((Stream)->fStream), ConToCRTMode[(Mode)]); \
92 else \
93 _setmode(_fileno((Stream)->fStream), _O_TEXT); /* Default to ANSI text */ \
94} while(0)
95
96#else /* defined(USE_CRT) */
97
98/*
99 * We set Stream->CodePage to INVALID_CP (== -1) to signal that the code page
100 * is either not assigned (if the mode is Binary, WideText, or UTF16Text), or
101 * is not cached (if the mode is AnsiText). In this latter case the code page
102 * is resolved inside ConWrite. Finally, if the mode is UTF8Text, the code page
103 * cache is always set to CP_UTF8.
104 * The code page cache can be reset by an explicit call to CON_STREAM_SET_MODE
105 * (i.e. by calling ConStreamSetMode, or by reinitializing the stream with
106 * ConStreamInit(Ex)).
107 *
108 * NOTE: the reserved values are: 0 (CP_ACP), 1 (CP_OEMCP), 2 (CP_MACCP),
109 * 3 (CP_THREAD_ACP), 42 (CP_SYMBOL), 65000 (CP_UTF7) and 65001 (CP_UTF8).
110 */
111#define CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage) \
112do { \
113 (Stream)->Mode = (Mode); \
114\
115 if ((Mode) == AnsiText) \
116 (Stream)->CodePage = CacheCodePage; /* Possibly assigned */ \
117 else if ((Mode) == UTF8Text) \
118 (Stream)->CodePage = CP_UTF8; /* Fixed */ \
119 else /* Mode == Binary, WideText, UTF16Text */ \
120 (Stream)->CodePage = INVALID_CP; /* Not assigned (meaningless) */ \
121} while(0)
122
123#endif /* defined(USE_CRT) */
124
125
126BOOL
131 IN UINT CacheCodePage OPTIONAL,
132 // IN CON_READ_FUNC ReadFunc OPTIONAL,
133 IN CON_WRITE_FUNC WriteFunc OPTIONAL)
134{
135 /* Parameters validation */
136 if (!Stream || !Handle || (Mode > UTF8Text))
137 return FALSE;
138
139#ifdef USE_CRT
140
141 Stream->fStream = (FILE*)Handle;
142
143#else
144
146 return FALSE;
147
148 /*
149 * As the user calls us by giving us an existing handle to attach on,
150 * it is not our duty to close it if we are called again. The user
151 * is responsible for having opened those handles, and is responsible
152 * for closing them!
153 */
154#if 0
155 /* Attempt to close the handle of the old stream */
156 if (/* Stream->IsInitialized && */ Stream->hHandle &&
157 Stream->hHandle != INVALID_HANDLE_VALUE)
158 {
159 CloseHandle(Stream->hHandle);
160 }
161#endif
162
163 /* Initialize the stream critical section if not already done */
164 if (!Stream->IsInitialized)
165 {
166 InitializeCriticalSection/*AndSpinCount*/(&Stream->Lock /* , 4000 */);
167 Stream->IsInitialized = TRUE;
168 }
169
170 Stream->hHandle = (HANDLE)Handle;
171 Stream->IsConsole = IsConsoleHandle(Stream->hHandle);
172
173#endif /* defined(USE_CRT) */
174
175 /* Set the correct file translation mode */
176 CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
177
178 /* Use the default 'ConWrite' helper if nothing is specified */
179 Stream->WriteFunc = (WriteFunc ? WriteFunc : ConWrite);
180
181 return TRUE;
182}
183
184BOOL
189 IN UINT CacheCodePage OPTIONAL)
190{
191 return ConStreamInitEx(Stream, Handle, Mode, CacheCodePage, ConWrite);
192}
193
194BOOL
198 IN UINT CacheCodePage OPTIONAL)
199{
200 /* Parameters validation */
201 if (!Stream || (Mode > UTF8Text))
202 return FALSE;
203
204#ifdef USE_CRT
205 if (!Stream->fStream)
206 return FALSE;
207#endif
208
209 /* Set the correct file translation mode */
210 CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
211 return TRUE;
212}
213
214BOOL
217 IN UINT CacheCodePage)
218{
219#ifdef USE_CRT
220// FIXME!
221#warning The ConStreamSetCacheCodePage function does not make much sense with the CRT!
222#else
224
225 /* Parameters validation */
226 if (!Stream)
227 return FALSE;
228
229 /*
230 * Keep the original stream mode but set the correct file code page
231 * (will be reset only if Mode == AnsiText).
232 */
233 Mode = Stream->Mode;
234 CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
235#endif
236 return TRUE;
237}
238
239HANDLE
242{
243 /* Parameters validation */
244 if (!Stream)
246
247 /*
248 * See https://support.microsoft.com/kb/99173
249 * for more details.
250 */
251
252#ifdef USE_CRT
253 if (!Stream->fStream)
255
256 return (HANDLE)_get_osfhandle(_fileno(Stream->fStream));
257#else
258 return Stream->hHandle;
259#endif
260}
261
262BOOL
266{
267 /* Parameters validation */
268 if (!Stream)
269 return FALSE;
270
271 /*
272 * See https://support.microsoft.com/kb/99173
273 * for more details.
274 */
275
276#ifdef USE_CRT
277 if (!Stream->fStream)
278 return FALSE;
279
280 int fdOut = _open_osfhandle((intptr_t)Handle, _O_TEXT /* FIXME! */);
281 FILE* fpOut = _fdopen(fdOut, "w");
282 *Stream->fStream = *fpOut;
284
285 return TRUE;
286#else
287 /* Flush the stream and reset its handle */
288 if (Stream->hHandle != INVALID_HANDLE_VALUE)
289 FlushFileBuffers(Stream->hHandle);
290
291 Stream->hHandle = Handle;
292 Stream->IsConsole = IsConsoleHandle(Stream->hHandle);
293
294 // NOTE: Mode reset??
295
296 return TRUE;
297#endif
298}
299
300/* EOF */
int intptr_t
Definition: crtdefs.h:304
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define _O_BINARY
Definition: cabinet.h:51
#define _O_TEXT
Definition: cabinet.h:50
#define CloseHandle
Definition: compat.h:739
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
BOOL WINAPI FlushFileBuffers(IN HANDLE hFile)
Definition: fileinfo.c:25
unsigned int BOOL
Definition: ntddk_ex.h:94
ULONG Handle
Definition: gdb_input.c:15
_In_ ULONG Mode
Definition: hubbusif.h:303
#define _O_WTEXT
Definition: fcntl.h:20
#define _O_U8TEXT
Definition: fcntl.h:22
#define _O_U16TEXT
Definition: fcntl.h:21
_Check_return_ _CRTIMP int __cdecl _fileno(_In_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl _fdopen(_In_ int _FileHandle, _In_z_ const char *_Mode)
static IStream Stream
Definition: htmldoc.c:1115
unsigned int UINT
Definition: ndis.h:50
INT __stdcall ConWrite(IN PCON_STREAM Stream, IN PCTCH szStr, IN DWORD len)
Definition: outstream.c:85
INT(__stdcall * CON_WRITE_FUNC)(IN PCON_STREAM Stream, IN PCTCH szStr, IN DWORD len)
Definition: outstream.h:47
static const PCON_STREAM StdStreams[]
Definition: redir.c:36
_CRTIMP intptr_t __cdecl _get_osfhandle(_In_ int _FileHandle)
_CRTIMP int __cdecl _open_osfhandle(_In_ intptr_t _OSFileHandle, _In_ int _Flags)
#define IsConsoleHandle(h)
Definition: console.h:14
CON_STREAM csStdErr
Definition: stream.c:61
BOOL ConStreamInitEx(OUT PCON_STREAM Stream, IN PVOID Handle, IN CON_STREAM_MODE Mode, IN UINT CacheCodePage OPTIONAL, IN CON_WRITE_FUNC WriteFunc OPTIONAL)
Definition: stream.c:127
BOOL ConStreamSetOSHandle(IN PCON_STREAM Stream, IN HANDLE Handle)
Definition: stream.c:263
BOOL ConStreamSetCacheCodePage(IN PCON_STREAM Stream, IN UINT CacheCodePage)
Definition: stream.c:215
#define CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage)
Definition: stream.c:111
BOOL ConStreamSetMode(IN PCON_STREAM Stream, IN CON_STREAM_MODE Mode, IN UINT CacheCodePage OPTIONAL)
Definition: stream.c:195
CON_STREAM csStdIn
Definition: stream.c:59
BOOL ConStreamInit(OUT PCON_STREAM Stream, IN PVOID Handle, IN CON_STREAM_MODE Mode, IN UINT CacheCodePage OPTIONAL)
Definition: stream.c:185
CON_STREAM csStdOut
Definition: stream.c:60
HANDLE ConStreamGetOSHandle(IN PCON_STREAM Stream)
Definition: stream.c:240
Console I/O streams.
@ UTF8Text
Definition: stream.h:50
enum _CON_STREAM_MODE CON_STREAM_MODE
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
PVOID HANDLE
Definition: typedefs.h:73
#define IN
Definition: typedefs.h:39
#define OUT
Definition: typedefs.h:40