-
Notifications
You must be signed in to change notification settings - Fork 8.5k
/
Copy pathutils.cpp
236 lines (202 loc) · 8.9 KB
/
utils.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
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "utils.hpp"
#include "../interactivity/inc/ServiceLocator.hpp"
#include "srvinit.h"
using Microsoft::Console::Interactivity::ServiceLocator;
til::CoordType CalcWindowSizeX(const til::inclusive_rect& rect) noexcept
{
return rect.Right - rect.Left + 1;
}
til::CoordType CalcWindowSizeY(const til::inclusive_rect& rect) noexcept
{
return rect.Bottom - rect.Top + 1;
}
til::CoordType CalcCursorYOffsetInPixels(const til::CoordType sFontSizeY, const ULONG ulSize) noexcept
{
// TODO: MSFT 10229700 - Note, we want to likely enforce that this isn't negative.
// Pretty sure there's not a valid case for negative offsets here.
return (til::CoordType)((sFontSizeY) - (ulSize));
}
WORD ConvertStringToDec(_In_ PCWSTR pwchToConvert, _Out_opt_ PCWSTR* const ppwchEnd) noexcept
{
WORD val = 0;
while (*pwchToConvert != L'\0')
{
auto ch = *pwchToConvert;
if (L'0' <= ch && ch <= L'9')
{
val = (val * 10) + (ch - L'0');
}
else
{
break;
}
pwchToConvert++;
}
if (nullptr != ppwchEnd)
{
*ppwchEnd = pwchToConvert;
}
return val;
}
// Routine Description:
// - Retrieves string resources from our resource files.
// Arguments:
// - id - Resource id from resource.h to the string we need to load.
// Return Value:
// - The string resource
std::wstring _LoadString(const UINT id)
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
WCHAR ItemString[70];
size_t ItemLength = 0;
LANGID LangId;
const auto Status = GetConsoleLangId(gci.OutputCP, &LangId);
if (NT_SUCCESS(Status))
{
ItemLength = s_LoadStringEx(ServiceLocator::LocateGlobals().hInstance, id, ItemString, ARRAYSIZE(ItemString), LangId);
}
if (!NT_SUCCESS(Status) || ItemLength == 0)
{
ItemLength = LoadStringW(ServiceLocator::LocateGlobals().hInstance, id, ItemString, ARRAYSIZE(ItemString));
}
return std::wstring(ItemString, ItemLength);
}
// Routine Description:
// - Helper to retrieve string resources from a MUI with a particular LANGID.
// Arguments:
// - hModule - The module related to loading the resource
// - wID - The resource ID number
// - lpBuffer - Buffer to place string data when read.
// - cchBufferMax - Size of buffer
// - wLangId - Language ID of resources that we should retrieve.
UINT s_LoadStringEx(_In_ HINSTANCE hModule, _In_ UINT wID, _Out_writes_(cchBufferMax) LPWSTR lpBuffer, _In_ UINT cchBufferMax, _In_ WORD wLangId)
{
// Make sure the parms are valid.
if (lpBuffer == nullptr)
{
return 0;
}
UINT cch = 0;
// String Tables are broken up into 16 string segments. Find the segment containing the string we are interested in.
const auto hResInfo = FindResourceEx(hModule, RT_STRING, (LPTSTR)((LONG_PTR)(((USHORT)wID >> 4) + 1)), wLangId);
if (hResInfo != nullptr)
{
// Load that segment.
const auto hStringSeg = (HRSRC)LoadResource(hModule, (HRSRC)hResInfo);
// Lock the resource.
LPTSTR lpsz;
if (hStringSeg != nullptr && (lpsz = (LPTSTR)LockResource(hStringSeg)) != nullptr)
{
// Move past the other strings in this segment. (16 strings in a segment -> & 0x0F)
wID &= 0x0F;
for (;;)
{
// PASCAL like string count
// first WCHAR is count of WCHARs
cch = *((WCHAR*)lpsz++);
if (wID-- == 0)
{
break;
}
lpsz += cch; // Step to start if next string
}
// chhBufferMax == 0 means return a pointer to the read-only resource buffer.
if (cchBufferMax == 0)
{
*(LPTSTR*)lpBuffer = lpsz;
}
else
{
// Account for the nullptr
cchBufferMax--;
// Don't copy more than the max allowed.
if (cch > cchBufferMax)
cch = cchBufferMax;
// Copy the string into the buffer.
memmove(lpBuffer, lpsz, cch * sizeof(WCHAR));
}
}
}
// Append a nullptr.
if (cchBufferMax != 0)
{
lpBuffer[cch] = 0;
}
return cch;
}
// Routine Description:
// - Compares two coordinate positions to determine whether they're the same, left, or right within the given buffer size
// Arguments:
// - bufferSize - The size of the buffer to use for measurements.
// - coordFirst - The first coordinate position
// - coordSecond - The second coordinate position
// Return Value:
// - Negative if First is to the left of the Second.
// - 0 if First and Second are the same coordinate.
// - Positive if First is to the right of the Second.
// - This is so you can do s_CompareCoords(first, second) <= 0 for "first is left or the same as second".
// (the < looks like a left arrow :D)
// - The magnitude of the result is the distance between the two coordinates when typing characters into the buffer (left to right, top to bottom)
int Utils::s_CompareCoords(const til::size bufferSize, const til::point coordFirst, const til::point coordSecond) noexcept
{
const auto cRowWidth = bufferSize.X;
// Assert that our coordinates are within the expected boundaries
const auto cRowHeight = bufferSize.Y;
FAIL_FAST_IF(!(coordFirst.X >= 0 && coordFirst.X < cRowWidth));
FAIL_FAST_IF(!(coordSecond.X >= 0 && coordSecond.X < cRowWidth));
FAIL_FAST_IF(!(coordFirst.Y >= 0 && coordFirst.Y < cRowHeight));
FAIL_FAST_IF(!(coordSecond.Y >= 0 && coordSecond.Y < cRowHeight));
// First set the distance vertically
// If first is on row 4 and second is on row 6, first will be -2 rows behind second * an 80 character row would be -160.
// For the same row, it'll be 0 rows * 80 character width = 0 difference.
auto retVal = (coordFirst.Y - coordSecond.Y) * cRowWidth;
// Now adjust for horizontal differences
// If first is in position 15 and second is in position 30, first is -15 left in relation to 30.
retVal += (coordFirst.X - coordSecond.X);
// Further notes:
// If we already moved behind one row, this will help correct for when first is right of second.
// For example, with row 4, col 79 and row 5, col 0 as first and second respectively, the distance is -1.
// Assume the row width is 80.
// Step one will set the retVal as -80 as first is one row behind the second.
// Step two will then see that first is 79 - 0 = +79 right of second and add 79
// The total is -80 + 79 = -1.
return retVal;
}
// Routine Description:
// - Compares two coordinate positions to determine whether they're the same, left, or right
// Arguments:
// - coordFirst - The first coordinate position
// - coordSecond - The second coordinate position
// Return Value:
// - Negative if First is to the left of the Second.
// - 0 if First and Second are the same coordinate.
// - Positive if First is to the right of the Second.
// - This is so you can do s_CompareCoords(first, second) <= 0 for "first is left or the same as second".
// (the < looks like a left arrow :D)
// - The magnitude of the result is the distance between the two coordinates when typing characters into the buffer (left to right, top to bottom)
int Utils::s_CompareCoords(const til::point coordFirst, const til::point coordSecond) noexcept
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
// find the width of one row
const auto coordScreenBufferSize = gci.GetActiveOutputBuffer().GetBufferSize().Dimensions();
return s_CompareCoords(coordScreenBufferSize, coordFirst, coordSecond);
}
// Routine Description:
// - Finds the opposite corner given a rectangle and one of its corners.
// - For example, finds the bottom right corner given a rectangle and its top left corner.
// Arguments:
// - srRectangle - The rectangle to check
// - coordCorner - One of the corners of the given rectangle
// Return Value:
// - The opposite corner of the one given.
til::point Utils::s_GetOppositeCorner(const til::inclusive_rect& srRectangle, const til::point coordCorner) noexcept
{
// Assert we were given coordinates that are indeed one of the corners of the rectangle.
FAIL_FAST_IF(!(coordCorner.X == srRectangle.Left || coordCorner.X == srRectangle.Right));
FAIL_FAST_IF(!(coordCorner.Y == srRectangle.Top || coordCorner.Y == srRectangle.Bottom));
return { (srRectangle.Left == coordCorner.X) ? srRectangle.Right : srRectangle.Left,
(srRectangle.Top == coordCorner.Y) ? srRectangle.Bottom : srRectangle.Top };
}