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
13class TOCElementNode
14{
15public:
16 TOCElementNode* Next;
17 TOCElement tocElement;
18
19 TOCElementNode(int number, __int64 offset) : Next(nullptr), tocElement(number, offset)
20 {
21 }
22};
23
24int 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