| 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 | |