summaryrefslogtreecommitdiff
path: root/src/ToolBox/superpmi/mcs/verbtoc.cpp
blob: a99fbf0183540284a50824969d256f8fa4310569 (plain)
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
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

#include "standardpch.h"
#include "verbtoc.h"
#include "methodcontext.h"
#include "methodcontextreader.h"
#include "methodcontextiterator.h"
#include "simpletimer.h"

class TOCElementNode
{
public:
    TOCElementNode *Next;
    TOCElement tocElement;

    TOCElementNode(int number, __int64 offset)
        : Next(nullptr)
        , tocElement(number, offset)
    {
    }
};

int verbTOC::DoWork(const char *nameOfInput)
{
    LogVerbose("Indexing from '%s' into '%s.mct'", nameOfInput, nameOfInput);

    MethodContextIterator mci;
    if (!mci.Initialize(nameOfInput))
        return -1;

    int savedCount = 0;

    TOCElementNode *head = nullptr;
    TOCElementNode *curElem = nullptr;

    while (mci.MoveNext())
    {
        MethodContext* mc = mci.Current();

        TOCElementNode *nxt = new TOCElementNode(mci.MethodContextNumber(), mci.CurrentPos());
        mc->dumpMethodMD5HashToBuffer(nxt->tocElement.Hash, MD5_HASH_BUFFER_SIZE);

        if (curElem != nullptr)
        {
            curElem->Next = nxt;
        }
        else
        {
            head = nxt;
        }
        curElem = nxt;
        savedCount++;
    }

    size_t maxLen = strlen(nameOfInput) + 5;
    char *nameOfOutput = (char*)_alloca(maxLen);
    strcpy_s(nameOfOutput, maxLen, nameOfInput);
    strcat_s(nameOfOutput, maxLen, ".mct");
    HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFileOut == INVALID_HANDLE_VALUE)
    {
        LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError());
        return -1;
    }

    DWORD written;
    // Write out the signature "INDX" and then the element count
    LARGE_INTEGER token;
    token.u.LowPart = *(const int*)"INDX"; // cuz Type Safety is for languages that have good IO facilities
    token.u.HighPart = savedCount;
    if (!WriteFile(hFileOut, &token, sizeof(token), &written, nullptr) || written != sizeof(token))
    {
        LogError("Failed to write index header. GetLastError()=%u", GetLastError());
    }

    // Now just dump sizeof(TOCElement) byte chunks into the file.
    // I could probably do this more efficiently, but I don't think it matters
    DWORD chunkSize = sizeof(TOCElement);
    for (curElem = head; curElem != nullptr; curElem = curElem->Next)
    {
        if (!WriteFile(hFileOut, &curElem->tocElement, chunkSize, &written, nullptr) || written != chunkSize)
        {
            LogError("Failed to write index element '%d'. GetLastError()=%u", curElem->tocElement.Number, GetLastError());
            return -1;
        }
    }
    // Now write out a final "INDX" to flag the end of the file...
    if (!WriteFile(hFileOut, &token.u.LowPart, sizeof(token.u.LowPart), &written, nullptr) || (written != sizeof(token.u.LowPart)))
    {
        LogError("Failed to write index terminal. GetLastError()=%u", GetLastError());
    }

    LogInfo("Loaded %d, added %d to Table of Contents", mci.MethodContextNumber(), savedCount);

    if (CloseHandle(hFileOut) == 0)
    {
        LogError("CloseHandle failed. GetLastError()=%u", GetLastError());
        return -1;
    }

    if (!mci.Destroy())
        return -1;

    return 0;
}