1 | // |
2 | // Copyright (c) Microsoft. All rights reserved. |
3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
4 | // |
5 | |
6 | //---------------------------------------------------------- |
7 | // MCList.h - MethodContext List utility class |
8 | //---------------------------------------------------------- |
9 | |
10 | #include "standardpch.h" |
11 | #include "mclist.h" |
12 | #include "logging.h" |
13 | |
14 | bool MCList::processArgAsMCL(char* input, int* count, int** list) |
15 | { |
16 | // If it contains only '0-9', '-', ',' try to see it as a range list, else try to load as a file |
17 | bool isRangeList = true; |
18 | |
19 | size_t len = strlen(input); |
20 | |
21 | for (unsigned int i = 0; (i < len) && isRangeList; i++) |
22 | { |
23 | if ((input[i] != '-') && (input[i] != ',') && (!isdigit((unsigned char)input[i]))) |
24 | isRangeList = false; |
25 | } |
26 | |
27 | if (isRangeList) |
28 | { |
29 | // Count items |
30 | *count = 0; |
31 | unsigned rangeStart = 0; |
32 | bool inRange = false; |
33 | unsigned scratch = 0; |
34 | bool foundDigit = false; |
35 | |
36 | char* tail = input + len; |
37 | |
38 | for (char* head = input; head <= tail; head++) |
39 | { |
40 | scratch = 0; |
41 | foundDigit = false; |
42 | while ((head <= tail) && (isdigit((unsigned char)*head))) |
43 | { |
44 | scratch = (scratch * 10) + ((*head) - '0'); |
45 | foundDigit = true; |
46 | head++; |
47 | } |
48 | if (foundDigit) |
49 | { |
50 | if (inRange) |
51 | { |
52 | inRange = false; |
53 | if (rangeStart >= scratch) |
54 | { |
55 | LogError("Invalid range in '%s'" , input); |
56 | return false; |
57 | } |
58 | (*count) += scratch - rangeStart; |
59 | } |
60 | else |
61 | { |
62 | rangeStart = scratch; |
63 | (*count)++; |
64 | } |
65 | } |
66 | if (*head == '-') |
67 | inRange = true; |
68 | } |
69 | |
70 | if (*count == 0) |
71 | { |
72 | LogError("Didn't find a list!" ); |
73 | return false; |
74 | } |
75 | |
76 | inRange = false; |
77 | rangeStart = 0; |
78 | |
79 | int* ll = new int[*count]; |
80 | *list = ll; |
81 | int index = 0; |
82 | ll[index] = 0; |
83 | |
84 | for (char* head = input; head <= tail; head++) |
85 | { |
86 | scratch = 0; |
87 | foundDigit = false; |
88 | while ((head <= tail) && (isdigit((unsigned char)*head))) |
89 | { |
90 | scratch = (scratch * 10) + ((*head) - '0'); |
91 | foundDigit = true; |
92 | head++; |
93 | } |
94 | if (foundDigit) |
95 | { |
96 | if (inRange) |
97 | { |
98 | inRange = false; |
99 | for (unsigned int i = rangeStart + 1; i <= scratch; i++) |
100 | ll[index++] = i; |
101 | } |
102 | else |
103 | { |
104 | rangeStart = scratch; |
105 | ll[index++] = scratch; |
106 | } |
107 | } |
108 | if (*head == '-') |
109 | inRange = true; |
110 | } |
111 | if (inRange) |
112 | { |
113 | LogError("Found invalid external range in '%s'" , input); |
114 | return false; |
115 | } |
116 | goto checkMCL; |
117 | } |
118 | else |
119 | { |
120 | char* lastdot = strrchr(input, '.'); |
121 | if (lastdot != nullptr && _stricmp(lastdot, ".mcl" ) == 0) |
122 | { |
123 | // Read MCLFile |
124 | if (!getLineData(input, count, list)) |
125 | return false; |
126 | if (*count >= 0) |
127 | goto checkMCL; |
128 | } |
129 | return false; |
130 | } |
131 | |
132 | checkMCL: // check that mcl list is increasing only |
133 | int* ll = (*list); |
134 | if (ll[0] == 0) |
135 | { |
136 | LogError("MCL list needs to start from 1!" ); |
137 | return false; |
138 | } |
139 | for (int i = 1; i < *count; i++) |
140 | { |
141 | if (ll[i - 1] >= ll[i]) |
142 | { |
143 | LogError("MCL list must be increasing.. found %d -> %d" , ll[i - 1], ll[i]); |
144 | return false; |
145 | } |
146 | } |
147 | return true; |
148 | } |
149 | |
150 | // Returns true on success, false on failure. |
151 | // On success, sets *pIndexCount to the number of indices read, and *pIndexes to a new array with all the indices read. |
152 | // The caller must free the memory with delete[]. |
153 | /* static */ |
154 | bool MCList::getLineData(const char* nameOfInput, /* OUT */ int* pIndexCount, /* OUT */ int** pIndexes) |
155 | { |
156 | HANDLE hFile = CreateFileA(nameOfInput, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, |
157 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); |
158 | if (hFile == INVALID_HANDLE_VALUE) |
159 | { |
160 | LogError("Unable to open '%s'. GetLastError()=%u" , nameOfInput, GetLastError()); |
161 | return false; |
162 | } |
163 | LARGE_INTEGER DataTemp; |
164 | if (!GetFileSizeEx(hFile, &DataTemp)) |
165 | { |
166 | LogError("GetFileSizeEx failed. GetLastError()=%u" , GetLastError()); |
167 | return false; |
168 | } |
169 | |
170 | if (DataTemp.QuadPart > MAXMCLFILESIZE) |
171 | { |
172 | LogError("Size %d exceeds max size of %d" , DataTemp.QuadPart, MAXMCLFILESIZE); |
173 | return false; |
174 | } |
175 | |
176 | int sz = DataTemp.u.LowPart; |
177 | char* buff = new char[sz]; |
178 | DWORD bytesRead; |
179 | if (ReadFile(hFile, buff, sz, &bytesRead, nullptr) == 0) |
180 | { |
181 | LogError("ReadFile failed. GetLastError()=%u" , GetLastError()); |
182 | delete[] buff; |
183 | return false; |
184 | } |
185 | if (!CloseHandle(hFile)) |
186 | { |
187 | LogError("CloseHandle failed. GetLastError()=%u" , GetLastError()); |
188 | delete[] buff; |
189 | return false; |
190 | } |
191 | |
192 | // Count the lines. Note that the last line better be terminated by a newline. |
193 | int lineCount = 0; |
194 | for (int i = 0; i < sz; i++) |
195 | { |
196 | if (buff[i] == '\n') |
197 | { |
198 | lineCount++; |
199 | } |
200 | } |
201 | |
202 | int* indexes = new int[lineCount]; |
203 | int indexCount = 0; |
204 | int i = 0; |
205 | while (i < sz) |
206 | { |
207 | // seek the first number on the line. This will skip empty lines and lines with no digits. |
208 | while (!isdigit((unsigned char)buff[i])) |
209 | i++; |
210 | // read in the number |
211 | indexes[indexCount++] = atoi(&buff[i]); |
212 | // seek to the start of next line |
213 | while ((i < sz) && (buff[i] != '\n')) |
214 | i++; |
215 | i++; |
216 | } |
217 | delete[] buff; |
218 | |
219 | *pIndexCount = indexCount; |
220 | *pIndexes = indexes; |
221 | return true; |
222 | } |
223 | |
224 | void MCList::InitializeMCL(char* filename) |
225 | { |
226 | hMCLFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
227 | if (hMCLFile == INVALID_HANDLE_VALUE) |
228 | { |
229 | LogError("Failed to open output file '%s'. GetLastError()=%u" , filename, GetLastError()); |
230 | } |
231 | } |
232 | |
233 | void MCList::AddMethodToMCL(int methodIndex) |
234 | { |
235 | if (hMCLFile != INVALID_HANDLE_VALUE) |
236 | { |
237 | char strMethodIndex[12]; |
238 | DWORD charCount = 0; |
239 | DWORD bytesWritten = 0; |
240 | |
241 | charCount = sprintf_s(strMethodIndex, sizeof(strMethodIndex), "%d\r\n" , methodIndex); |
242 | |
243 | if (!WriteFile(hMCLFile, strMethodIndex, charCount, &bytesWritten, nullptr) || bytesWritten != charCount) |
244 | { |
245 | LogError("Failed to write method index '%d'. GetLastError()=%u" , strMethodIndex, GetLastError()); |
246 | } |
247 | } |
248 | } |
249 | |
250 | void MCList::CloseMCL() |
251 | { |
252 | if (hMCLFile != INVALID_HANDLE_VALUE) |
253 | { |
254 | if (CloseHandle(hMCLFile) == 0) |
255 | { |
256 | LogError("CloseHandle failed. GetLastError()=%u" , GetLastError()); |
257 | } |
258 | } |
259 | } |
260 | |