-
Notifications
You must be signed in to change notification settings - Fork 8.5k
/
Copy pathmisc.cpp
316 lines (291 loc) · 10.5 KB
/
misc.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "misc.h"
#include "dbcs.h"
#include "../types/inc/convert.hpp"
#include "../types/inc/GlyphWidth.hpp"
#include "../interactivity/inc/ServiceLocator.hpp"
#pragma hdrstop
#define CHAR_NULL ((char)0)
using Microsoft::Console::Interactivity::ServiceLocator;
WCHAR CharToWchar(_In_reads_(cch) const char* const pch, const UINT cch)
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto wc = L'\0';
FAIL_FAST_IF(!(IsDBCSLeadByteConsole(*pch, &gci.OutputCPInfo) || cch == 1));
ConvertOutputToUnicode(gci.OutputCP, pch, cch, &wc, 1);
return wc;
}
void SetConsoleCPInfo(const BOOL fOutput)
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
if (fOutput)
{
if (!GetCPInfo(gci.OutputCP, &gci.OutputCPInfo))
{
gci.OutputCPInfo.LeadByte[0] = 0;
}
}
else
{
if (!GetCPInfo(gci.CP, &gci.CPInfo))
{
gci.CPInfo.LeadByte[0] = 0;
}
}
}
// Routine Description:
// - This routine check bisected on Unicode string end.
// Arguments:
// - pwchBuffer - Pointer to Unicode string buffer.
// - cWords - Number of Unicode string.
// - cBytes - Number of bisect position by byte counts.
// Return Value:
// - TRUE - Bisected character.
// - FALSE - Correctly.
BOOL CheckBisectStringW(_In_reads_bytes_(cBytes) const WCHAR* pwchBuffer,
_In_ size_t cWords,
_In_ size_t cBytes) noexcept
{
while (cWords && cBytes)
{
if (IsGlyphFullWidth(*pwchBuffer))
{
if (cBytes < 2)
{
return TRUE;
}
else
{
cWords--;
cBytes -= 2;
pwchBuffer++;
}
}
else
{
cWords--;
cBytes--;
pwchBuffer++;
}
}
return FALSE;
}
// Routine Description:
// - This routine check bisected on Unicode string end.
// Arguments:
// - ScreenInfo - reference to screen information structure.
// - pwchBuffer - Pointer to Unicode string buffer.
// - cWords - Number of Unicode string.
// - cBytes - Number of bisect position by byte counts.
// - fPrintableControlChars - TRUE if control characters are being expanded (to ^X)
// Return Value:
// - TRUE - Bisected character.
// - FALSE - Correctly.
BOOL CheckBisectProcessW(const SCREEN_INFORMATION& ScreenInfo,
_In_reads_bytes_(cBytes) const WCHAR* pwchBuffer,
_In_ size_t cWords,
_In_ size_t cBytes,
_In_ til::CoordType sOriginalXPosition,
_In_ BOOL fPrintableControlChars)
{
if (WI_IsFlagSet(ScreenInfo.OutputMode, ENABLE_PROCESSED_OUTPUT))
{
while (cWords && cBytes)
{
const auto Char = *pwchBuffer;
if (Char >= UNICODE_SPACE)
{
if (IsGlyphFullWidth(Char))
{
if (cBytes < 2)
{
return TRUE;
}
else
{
cWords--;
cBytes -= 2;
pwchBuffer++;
sOriginalXPosition += 2;
}
}
else
{
cWords--;
cBytes--;
pwchBuffer++;
sOriginalXPosition++;
}
}
else
{
cWords--;
pwchBuffer++;
switch (Char)
{
case UNICODE_BELL:
if (fPrintableControlChars)
goto CtrlChar;
break;
case UNICODE_BACKSPACE:
case UNICODE_LINEFEED:
case UNICODE_CARRIAGERETURN:
break;
case UNICODE_TAB:
{
size_t TabSize = NUMBER_OF_SPACES_IN_TAB(sOriginalXPosition);
sOriginalXPosition = (til::CoordType)(sOriginalXPosition + TabSize);
if (cBytes < TabSize)
return TRUE;
cBytes -= TabSize;
break;
}
default:
if (fPrintableControlChars)
{
CtrlChar:
if (cBytes < 2)
return TRUE;
cBytes -= 2;
sOriginalXPosition += 2;
}
else
{
cBytes--;
sOriginalXPosition++;
}
}
}
}
return FALSE;
}
else
{
return CheckBisectStringW(pwchBuffer, cWords, cBytes);
}
}
// Routine Description:
// - Converts all key events in the deque to the oem char data and adds
// them back to events.
// Arguments:
// - events - on input the IInputEvents to convert. on output, the
// converted input events
// Note: may throw on error
void SplitToOem(std::deque<std::unique_ptr<IInputEvent>>& events)
{
const auto codepage = ServiceLocator::LocateGlobals().getConsoleInformation().CP;
// convert events to oem codepage
std::deque<std::unique_ptr<IInputEvent>> convertedEvents;
while (!events.empty())
{
auto currentEvent = std::move(events.front());
events.pop_front();
if (currentEvent->EventType() == InputEventType::KeyEvent)
{
const auto pKeyEvent = static_cast<const KeyEvent* const>(currentEvent.get());
// convert from wchar to char
std::wstring wstr{ pKeyEvent->GetCharData() };
const auto str = ConvertToA(codepage, wstr);
for (auto& ch : str)
{
auto tempEvent = std::make_unique<KeyEvent>(*pKeyEvent);
tempEvent->SetCharData(ch);
convertedEvents.push_back(std::move(tempEvent));
}
}
else
{
convertedEvents.push_back(std::move(currentEvent));
}
}
// move all events back
while (!convertedEvents.empty())
{
events.push_back(std::move(convertedEvents.front()));
convertedEvents.pop_front();
}
}
// Routine Description:
// - Converts unicode characters to ANSI given a destination codepage
// Arguments:
// - uiCodePage - codepage for use in conversion
// - pwchSource - unicode string to convert
// - cchSource - length of pwchSource in characters
// - pchTarget - pointer to destination buffer to receive converted ANSI string
// - cchTarget - size of destination buffer in characters
// Return Value:
// - Returns the number characters written to pchTarget, or 0 on failure
int ConvertToOem(const UINT uiCodePage,
_In_reads_(cchSource) const WCHAR* const pwchSource,
const UINT cchSource,
_Out_writes_(cchTarget) CHAR* const pchTarget,
const UINT cchTarget) noexcept
{
FAIL_FAST_IF(!(pwchSource != (LPWSTR)pchTarget));
DBGCHARS(("ConvertToOem U->%d %.*ls\n", uiCodePage, cchSource > 10 ? 10 : cchSource, pwchSource));
// clang-format off
#pragma prefast(suppress: __WARNING_W2A_BEST_FIT, "WC_NO_BEST_FIT_CHARS doesn't work in many codepages. Retain old behavior.")
// clang-format on
return LOG_IF_WIN32_BOOL_FALSE(WideCharToMultiByte(uiCodePage, 0, pwchSource, cchSource, pchTarget, cchTarget, nullptr, nullptr));
}
// Data in the output buffer is the true unicode value.
int ConvertInputToUnicode(const UINT uiCodePage,
_In_reads_(cchSource) const CHAR* const pchSource,
const UINT cchSource,
_Out_writes_(cchTarget) WCHAR* const pwchTarget,
const UINT cchTarget) noexcept
{
DBGCHARS(("ConvertInputToUnicode %d->U %.*s\n", uiCodePage, cchSource > 10 ? 10 : cchSource, pchSource));
return MultiByteToWideChar(uiCodePage, 0, pchSource, cchSource, pwchTarget, cchTarget);
}
// Output data is always translated via the ansi codepage so glyph translation works.
int ConvertOutputToUnicode(_In_ UINT uiCodePage,
_In_reads_(cchSource) const CHAR* const pchSource,
_In_ UINT cchSource,
_Out_writes_(cchTarget) WCHAR* pwchTarget,
_In_ UINT cchTarget) noexcept
{
FAIL_FAST_IF(!(cchTarget > 0));
pwchTarget[0] = L'\0';
DBGCHARS(("ConvertOutputToUnicode %d->U %.*s\n", uiCodePage, cchSource > 10 ? 10 : cchSource, pchSource));
if (DoBuffersOverlap(reinterpret_cast<const BYTE* const>(pchSource),
cchSource * sizeof(CHAR),
reinterpret_cast<const BYTE* const>(pwchTarget),
cchTarget * sizeof(WCHAR)))
{
try
{
// buffers overlap so we need to copy one
std::string copyData(pchSource, cchSource);
return MultiByteToWideChar(uiCodePage, MB_USEGLYPHCHARS, copyData.data(), cchSource, pwchTarget, cchTarget);
}
catch (...)
{
return 0;
}
}
else
{
return MultiByteToWideChar(uiCodePage, MB_USEGLYPHCHARS, pchSource, cchSource, pwchTarget, cchTarget);
}
}
// Routine Description:
// - checks if two buffers overlap
// Arguments:
// - pBufferA - pointer to start of first buffer
// - cbBufferA - size of first buffer, in bytes
// - pBufferB - pointer to start of second buffer
// - cbBufferB - size of second buffer, in bytes
// Return Value:
// - true if buffers overlap, false otherwise
bool DoBuffersOverlap(const BYTE* const pBufferA,
const UINT cbBufferA,
const BYTE* const pBufferB,
const UINT cbBufferB) noexcept
{
const auto pBufferAEnd = pBufferA + cbBufferA;
const auto pBufferBEnd = pBufferB + cbBufferB;
return (pBufferA <= pBufferB && pBufferAEnd >= pBufferB) || (pBufferB <= pBufferA && pBufferBEnd >= pBufferA);
}