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 | #include "standardpch.h" |
7 | #include "verbtoc.h" |
8 | #include "methodcontext.h" |
9 | #include "methodcontextreader.h" |
10 | #include "methodcontextiterator.h" |
11 | #include "simpletimer.h" |
12 | |
13 | class TOCElementNode |
14 | { |
15 | public: |
16 | TOCElementNode* Next; |
17 | TOCElement tocElement; |
18 | |
19 | TOCElementNode(int number, __int64 offset) : Next(nullptr), tocElement(number, offset) |
20 | { |
21 | } |
22 | }; |
23 | |
24 | int verbTOC::DoWork(const char* nameOfInput) |
25 | { |
26 | LogVerbose("Indexing from '%s' into '%s.mct'" , nameOfInput, nameOfInput); |
27 | |
28 | MethodContextIterator mci; |
29 | if (!mci.Initialize(nameOfInput)) |
30 | return -1; |
31 | |
32 | int savedCount = 0; |
33 | |
34 | TOCElementNode* head = nullptr; |
35 | TOCElementNode* curElem = nullptr; |
36 | |
37 | while (mci.MoveNext()) |
38 | { |
39 | MethodContext* mc = mci.Current(); |
40 | |
41 | TOCElementNode* nxt = new TOCElementNode(mci.MethodContextNumber(), mci.CurrentPos()); |
42 | mc->dumpMethodMD5HashToBuffer(nxt->tocElement.Hash, MD5_HASH_BUFFER_SIZE); |
43 | |
44 | if (curElem != nullptr) |
45 | { |
46 | curElem->Next = nxt; |
47 | } |
48 | else |
49 | { |
50 | head = nxt; |
51 | } |
52 | curElem = nxt; |
53 | savedCount++; |
54 | } |
55 | |
56 | size_t maxLen = strlen(nameOfInput) + 5; |
57 | char* nameOfOutput = (char*)_alloca(maxLen); |
58 | strcpy_s(nameOfOutput, maxLen, nameOfInput); |
59 | strcat_s(nameOfOutput, maxLen, ".mct" ); |
60 | HANDLE hFileOut = |
61 | CreateFileA(nameOfOutput, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
62 | if (hFileOut == INVALID_HANDLE_VALUE) |
63 | { |
64 | LogError("Failed to open input 1 '%s'. GetLastError()=%u" , nameOfOutput, GetLastError()); |
65 | return -1; |
66 | } |
67 | |
68 | DWORD written; |
69 | // Write out the signature "INDX" and then the element count |
70 | LARGE_INTEGER token; |
71 | token.u.LowPart = *(const int*)"INDX" ; // cuz Type Safety is for languages that have good IO facilities |
72 | token.u.HighPart = savedCount; |
73 | if (!WriteFile(hFileOut, &token, sizeof(token), &written, nullptr) || written != sizeof(token)) |
74 | { |
75 | LogError("Failed to write index header. GetLastError()=%u" , GetLastError()); |
76 | } |
77 | |
78 | // Now just dump sizeof(TOCElement) byte chunks into the file. |
79 | // I could probably do this more efficiently, but I don't think it matters |
80 | DWORD chunkSize = sizeof(TOCElement); |
81 | for (curElem = head; curElem != nullptr; curElem = curElem->Next) |
82 | { |
83 | if (!WriteFile(hFileOut, &curElem->tocElement, chunkSize, &written, nullptr) || written != chunkSize) |
84 | { |
85 | LogError("Failed to write index element '%d'. GetLastError()=%u" , curElem->tocElement.Number, |
86 | GetLastError()); |
87 | return -1; |
88 | } |
89 | } |
90 | // Now write out a final "INDX" to flag the end of the file... |
91 | if (!WriteFile(hFileOut, &token.u.LowPart, sizeof(token.u.LowPart), &written, nullptr) || |
92 | (written != sizeof(token.u.LowPart))) |
93 | { |
94 | LogError("Failed to write index terminal. GetLastError()=%u" , GetLastError()); |
95 | } |
96 | |
97 | LogInfo("Loaded %d, added %d to Table of Contents" , mci.MethodContextNumber(), savedCount); |
98 | |
99 | if (CloseHandle(hFileOut) == 0) |
100 | { |
101 | LogError("CloseHandle failed. GetLastError()=%u" , GetLastError()); |
102 | return -1; |
103 | } |
104 | |
105 | if (!mci.Destroy()) |
106 | return -1; |
107 | |
108 | return 0; |
109 | } |
110 | |