0
\$\begingroup\$

https://github.com/speedrun-program/load_extender

This is the previous post: UPDATE #1: Lengthening the time it takes to access files using function hooking

I came back to this to try to improve it. I'm using std::unique_ptr instead of std::string_view and vector in the hash map to reduce memory per key. I don't include std::string anymore because I was barely using std::string features. I didn't use the filesystem header, but I did use std::to_chars to make the file finding function more simple.

I still tried to reduce the executable size because, even though the easyhook DLLs are big, they seem like they're an independent thing and could just be replaced with something smaller if it's made available. If I increased the size by ~50% when it could be avoided easily, it would irritate me, so I didn't use the filesystem header.

I tried to improve hash map lookup speed, hash map memory usage, files_and_delays.txt reading speed, and exe file size.

To compile this on Windows, you need to install EasyHook.

load_extender_injector.cpp (only used on Windows because LD_PRELOAD and DYLD_INSERT_LIBRARIES can be used on Linux and Mac OS)

#include <tchar.h>
#include <iostream>
#include <format>
#include <climits>
// easyhook.h installed with NuGet
// https://easyhook.github.io/documentation.html
#include <easyhook.h>
#include <Windows.h>

void getExitInput()
{
    int ch = 0;

    for (; ch != '\n'; ch = std::getchar());

    std::printf("Press Enter to exit\n");
    ch = std::getchar();
}

int _tmain(int argc, _TCHAR* argv[])
{
    WCHAR* dllToInject32 = nullptr;
    WCHAR* dllToInject64 = nullptr;
    _TCHAR* applicationName = argv[0];
    DWORD binaryType = 0;
    BOOL getBinaryTypeResult = GetBinaryType(applicationName, &binaryType);

    if (getBinaryTypeResult == 0 || (binaryType != 0 && binaryType != 6))
    {
        std::printf("ERROR: This exe wasn't identified as 32-bit or as 64-bit\n");
        getExitInput();
        return EXIT_FAILURE;
    }
    else if (binaryType == 0)
    {
        dllToInject32 = (WCHAR*)L"load_extender_32.dll";
    }
    else
    {
        dllToInject64 = (WCHAR*)L"load_extender_64.dll";
    }

    std::printf("Enter the process Id: ");
    DWORD pid = 0;
    std::cin >> pid;

    NTSTATUS errorCode = RhInjectLibrary(
        pid,                     // The process to inject into
        0,                       // ThreadId to wake up upon injection
        EASYHOOK_INJECT_DEFAULT,
        dllToInject32,           // 32-bit
        dllToInject64,           // 64-bit
        nullptr,                 // data to send to injected DLL entry point
        0                        // size of data to send
    );

    if (errorCode != 0)
    {
        std::printf("RhInjectLibrary failed with error code = %d\n", errorCode);
        PWCHAR errorMessage = RtlGetLastErrorString();
        std::printf("%ls\n", errorMessage);
        getExitInput();
        return EXIT_FAILURE;
    }

    std::printf("Library injected successfully.\n");
    getExitInput();
    return EXIT_SUCCESS;
}

load_extender.cpp

#include <climits>
#include <mutex>
#include <thread>
#include <vector>
#include <memory>
#include <cstring>
#include <charconv>
#include <exception>
#include <string_view>
#include <unordered_map>

#ifdef _WIN32
// easyhook.h installed with NuGet
// https://easyhook.github.io/documentation.html
#include <easyhook.h>
#include <Windows.h>
using wcharOrChar = wchar_t; // file paths are UTF-16LE on Windows
using svType = std::wstring_view;
#define cmpFunction std::wcscmp
#else
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
using wcharOrChar = char;
using svType = std::string_view;
#define cmpFunction std::strcmp
#endif

using uPtrType = std::unique_ptr<wcharOrChar[]>;
using vectorType = std::vector<wcharOrChar>;

// using multiple cpp files made exe bigger, so definitions are in this header
#include "shared.h"

static MapAndMutex mapAndMutexObject;

#ifdef _WIN32
static NTSTATUS WINAPI NtCreateFileHook(
    PHANDLE            FileHandle,
    ACCESS_MASK        DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    PIO_STATUS_BLOCK   IoStatusBlock,
    PLARGE_INTEGER     AllocationSize,
    ULONG              FileAttributes,
    ULONG              ShareAccess,
    ULONG              CreateDisposition,
    ULONG              CreateOptions,
    PVOID              EaBuffer,
    ULONG              EaLength)
{
    const wchar_t* path = (const wchar_t*)(ObjectAttributes->ObjectName->Buffer);
    int pathEndIndex = (ObjectAttributes->ObjectName->Length) / sizeof(wchar_t);
    int filenameIndex = pathEndIndex;

    for (; filenameIndex >= 0 && path[filenameIndex] != '\\'; filenameIndex--);

    filenameIndex++; // moving past '\\' character or to 0 if no '\\' was found
    auto it = mapAndMutexObject.fileMap.find(
        svType(path + filenameIndex,
        (size_t)pathEndIndex - filenameIndex)
    );

    if (it != mapAndMutexObject.fileMap.end())
    {
        mapAndMutexObject.delayFile(it->second);
    }
    
    return NtCreateFile(
        FileHandle,
        DesiredAccess,
        ObjectAttributes,
        IoStatusBlock,
        AllocationSize,
        FileAttributes,
        ShareAccess,
        CreateDisposition,
        CreateOptions,
        EaBuffer,
        EaLength
    );
}

extern "C" void __declspec(dllexport) __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO * inRemoteInfo);

void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo)
{
    HOOK_TRACE_INFO hHook1 = { nullptr };
    HMODULE moduleHandle = GetModuleHandle(TEXT("ntdll"));

    if (moduleHandle)
    {
        LhInstallHook(
            GetProcAddress(moduleHandle, "NtCreateFile"),
            NtCreateFileHook,
            nullptr,
            &hHook1
        );
    }

    ULONG ACLEntries[1] = { 0 };
    LhSetExclusiveACL(ACLEntries, 1, &hHook1);
}
#else
static auto originalFopen = reinterpret_cast<FILE * (*)(const char* path, const char* mode)>(dlsym(RTLD_NEXT, "fopen"));

FILE* fopen(const char* path, const char* mode)
{
    int filenameIndex = -1;
    int pathEndIndex = 0;

    for (; path[pathEndIndex] != '\0'; pathEndIndex++)
    {
        if (path[pathEndIndex] == '/')
        {
            filenameIndex = pathEndIndex;
        }
    }
    
    filenameIndex++; // moving past '/' character or to 0 if no '/' was found
    auto it = mapAndMutexObject.fileMap.find(
        svType(path + filenameIndex,
        (size_t)pathEndIndex - filenameIndex)
    );
    
    if (it != mapAndMutexObject.fileMap.end())
    {
        delayFile(it->second);
    }

    return original_fopen(path, mode);
}
#endif

shared.h

#ifndef DEBUG
#define stdprintf(...) (0)
#endif

bool checkIfFileExists(const char* filename)
{
    FILE* fcheck = nullptr;
    try
    {
        bool exists = false;
#ifdef _WIN32
        fopen_s(&fcheck, filename, "rb");
#else
        fcheck = std::fopen(filename, "rb");
#endif

        if (fcheck)
        {
            std::fclose(fcheck);
            fcheck = nullptr;
            exists = true;
        }

        return exists;
    }
    catch (char const* e) // making sure fcheck gets closed if an error happens somehow
    {
        if (fcheck)
        {
            std::fclose(fcheck);
        }

        throw std::runtime_error(e);
    }
}

// char name[16 + 10 + 4 + 1] starts as "files_and_delays1.txt"
// 16: "files_and_delays"
// 10: number part
// 4: ".txt"
// 1: '\0'
void findCorrectFileName(char* name)
{
    unsigned int fileNumber = 1;

    while (checkIfFileExists(name))
    {
        fileNumber++;
        auto [dottxt, ec] = std::to_chars(name + 16, name + 26, fileNumber);

        if (ec == std::errc::value_too_large || fileNumber == 0) // this probably won't ever happen
        {
            throw std::runtime_error("too many files_and_delays files");
        }

        dottxt[0] = '.'; dottxt[1] = 't'; dottxt[2] = 'x'; dottxt[3] = 't';
    }

    fileNumber--;
    auto [dottxt, _] = std::to_chars(name + 16, name + 26, fileNumber);
    // dottxt[4] might not be '\0'. for example, fileNumber decrements from 100 to 99
    dottxt[0] = '.'; dottxt[1] = 't'; dottxt[2] = 'x'; dottxt[3] = 't'; dottxt[4] = '\0';
}

class FileHelper
{
public:
    FileHelper(const FileHelper& fhelper) = delete;
    FileHelper& operator=(FileHelper other) = delete;
    FileHelper(FileHelper&&) = delete;
    FileHelper& operator=(FileHelper&&) = delete;

    FileHelper(const char* filename)
    {
#ifdef _WIN32
        if (fopen_s(&_f, filename, "rb") != 0 || !_f)
#else
        if (!(_f = std::fopen(filePath, "rb")))
#endif
        {
            stdprintf("ERROR: %s\n", filename);
            throw std::runtime_error("FileHelper fopen failure in constructor");
        }
    }

    ~FileHelper()
    {
        if (_f)
        {
            std::fclose(_f);
        }
    }

    bool getCharacter(wcharOrChar& ch)
    {
        if (_bufferPosition == _charactersRead)
        {
            _bufferPosition = 0;
            _charactersRead = (int)std::fread(_buffer.data(), sizeof(wcharOrChar), _buffer.size(), _f);

            if (!_charactersRead)
            {
                return false;
            }
        }

        ch = _buffer.at(_bufferPosition);
        _bufferPosition++;

        return true;
    }

    void resetFile() // used in tests
    {
        if (std::fseek(_f, 0, SEEK_SET) != 0)
        {
            throw std::runtime_error("FileHelper fseek failure in resetFile");
        }

        _bufferPosition = 0;
        _charactersRead = 0;
    }

private:
    FILE* _f = nullptr;
    std::vector<wcharOrChar> _buffer = std::vector<wcharOrChar>(8192 / sizeof(wcharOrChar));
    int _bufferPosition = 0;
    int _charactersRead = 0;
};

struct MapValue
{
    // delays[0] == -1 says to reset all MapValue.position to 0
    // delays ending with -1 says to reset at the end
    // delays ending with -2 says to NOT reset at the end
    std::unique_ptr<int[]> delays;
    size_t position = 0;
    size_t fullResetCheckNumber = 0;

    MapValue(std::vector<int>& delaysVector)
    {
        delays = std::make_unique_for_overwrite<int[]>(delaysVector.size());
        std::memcpy(delays.get(), delaysVector.data(), delaysVector.size() * sizeof(int));
    }
};

struct KeyCmp
{
    using is_transparent = void;

    bool operator()(const uPtrType& cStr1, const uPtrType& cStr2) const
    {
        return cmpFunction(cStr1.get(), cStr2.get()) == 0;
    }

    bool operator()(const uPtrType& cStr, const svType sv) const
    {
        return cmpFunction(cStr.get(), sv.data()) == 0;
    }

    bool operator()(const svType sv, const uPtrType& cStr) const
    {
        return cmpFunction(sv.data(), cStr.get()) == 0;
    }
};

struct KeyHash
{
    using is_transparent = void;

    size_t operator()(const svType sv) const
    {
        return _hashObject(sv);
    }

    size_t operator()(const uPtrType& cStr) const
    {
        // if they add an easy way to do it, change this so it doesn't need to find the c-string length
        return _hashObject(svType(cStr.get()));
    }

private:
    std::hash<svType> _hashObject = std::hash<svType>();
};

using myMapType = std::unordered_map<uPtrType, MapValue, KeyHash, KeyCmp>;

class MapAndMutex
{
public:
    std::mutex mutexForMap;
    myMapType fileMap;

    MapAndMutex()
    {
        try
        {
            // intAsChars used in fillDelaysVector but made here so it doesn't need to be remade repeatedly
            std::vector<char> intAsChars;
            intAsChars.reserve(10);
            intAsChars.push_back('0'); // empty vector causes std::errc::invalid_argument
            vectorType keyVector;
            std::vector<int> delaysVector;
            char name[16 + 10 + 4 + 1] = "files_and_delays.txt";
            // 16: "files_and_delays"
            // 10: number part
            // 4: ".txt"
            // 1: '\0'

            if (checkIfFileExists("files_and_delays0.txt"))
            {
                char* nameEnd = name + 16;
                nameEnd[0] = '1'; nameEnd[1] = '.'; nameEnd[2] = 't'; nameEnd[3] = 'x'; nameEnd[4] = 't';
                findCorrectFileName(name);
            }

            FileHelper fhelper(name);
#ifdef _WIN32
            wchar_t byteOrderMark = '\0';

            if (!fhelper.getCharacter(byteOrderMark))
            {
                stdprintf(
                    "files_and_delays.txt byte order mark is missing\n\
make sure files_and_delays.txt is saved as UTF-16 LE\n"
);
            }
            else if (byteOrderMark != 0xFEFF) // not 0xFFFE due to how wchar_t is read
            {
                stdprintf(
                    "files_and_delays.txt byte order mark isn't marked as UTF-16 LE\n\
make sure files_and_delays.txt is saved as UTF-16 LE\n"
);
            }
#endif

            while (addMapPair(fileMap, keyVector, delaysVector, fhelper, intAsChars));
        }
        catch (const std::runtime_error& e)
        {
            char const* fixC4101Warning = e.what();
            stdprintf("%s\n", fixC4101Warning);
            fileMap.clear(); // clear map so failure is more obvious
        }
    }

    bool addMapPair(myMapType& fileMap, vectorType& keyVector, std::vector<int>& delaysVector, FileHelper& fhelper, std::vector<char> intAsChars)
    {
        keyVector.clear();
        delaysVector.clear();
        wcharOrChar ch = '\0';
        bool stripWhitespace = false;
        bool textRemaining = fhelper.getCharacter(ch);

        if (ch == '/')
        {
            stripWhitespace = true;
            textRemaining = fhelper.getCharacter(ch);
        }
        else if (ch == ' ' || ch == '\f' || ch == '\r' || ch == '\t' || ch == '\v')
        {
            // don't include starting whitespace
            for (
                textRemaining = fhelper.getCharacter(ch);
                textRemaining && (ch == ' ' || ch == '\f' || ch == '\r' || ch == '\t' || ch == '\v');
                textRemaining = fhelper.getCharacter(ch));
        }

        while (ch != '\n' && ch != '/' && textRemaining)
        {
            keyVector.push_back(ch);
            textRemaining = fhelper.getCharacter(ch);
        }

        // don't include ending whitespace
        if (!stripWhitespace)
        {
            while (!keyVector.empty())
            {
                wcharOrChar ch = keyVector.back();

                if (ch == ' ' || ch == '\f' || ch == '\r' || ch == '\t' || ch == '\v')
                {
                    keyVector.pop_back();
                }
                else
                {
                    break;
                }
            }
        }

        if (textRemaining && ch == '/') // line didn't end abruptly
        {
            fillDelaysVector(textRemaining, delaysVector, fhelper, intAsChars);

            if (!keyVector.empty() && !delaysVector.empty())
            {
                if (delaysVector.back() != -1)
                {
                    delaysVector.push_back(-2);
                }

                keyVector.push_back('\0');
                uPtrType keyPtr = std::make_unique_for_overwrite<wcharOrChar[]>(keyVector.size());
                std::memcpy(keyPtr.get(), keyVector.data(), keyVector.size() * sizeof(wcharOrChar));
                fileMap.emplace(std::move(keyPtr), MapValue(delaysVector));
            }
        }

        return textRemaining;
    }

    // the -2 at the end is added in addMapPair when there isn't already a -1
    void fillDelaysVector(bool& textRemaining, std::vector<int>& delaysVector, FileHelper& fhelper, std::vector<char> intAsChars)
    {
        wcharOrChar ch = '\0';
        int delay = 0;

        for (
            textRemaining = fhelper.getCharacter(ch);
            ch != '\n' && textRemaining;
            textRemaining = fhelper.getCharacter(ch))
        {
            if (ch >= '0' && ch <= '9')
            {
                intAsChars.push_back((char)ch);
            }
            else if (ch == '-')
            {
                delaysVector.push_back(-1);

                break;
            }
            else if (ch == '/')
            {
                auto [ptr, ec] = std::from_chars(intAsChars.data(), intAsChars.data() + intAsChars.size(), delay);

                if (ec == std::errc::result_out_of_range)
                {
                    throw std::runtime_error("delays can't be larger than INT_MAX");
                }

                delaysVector.push_back(delay);
                intAsChars.clear();
                intAsChars.push_back('0'); // empty vector causes std::errc::invalid_argument
            }
        }

        if (delaysVector.empty() || delaysVector.back() != -1)
        {
            if (intAsChars.size() > 1)
            {
                auto [ptr, ec] = std::from_chars(intAsChars.data(), intAsChars.data() + intAsChars.size(), delay);

                if (ec == std::errc::result_out_of_range)
                {
                    throw std::runtime_error("delays can't be larger than INT_MAX");
                }

                delaysVector.push_back(delay);
            }
        }

        // make sure to go to end of line
        for (; ch != '\n' && textRemaining; textRemaining = fhelper.getCharacter(ch));
    }

    void delayFile(MapValue& fileMapValue)
    {
#ifndef DEBUG // this needs to be reset in the test, so it's a global variable instead
        size_t fullResetCount = 0;
#endif

        stdprintf("fullResetCount: %zu\n", fullResetCount);
        int delay = 0;

        {
            std::lock_guard<std::mutex> mutexForMapLock(mutexForMap);

            if (fileMapValue.fullResetCheckNumber < fullResetCount)
            {
                fileMapValue.position = 0;
                fileMapValue.fullResetCheckNumber = fullResetCount;
                stdprintf("this delay sequence reset due to prior full reset\n");
            }

            if (fileMapValue.delays[0] == -1)
            {
                if (fullResetCount == SIZE_MAX) // this probably won't ever happen
                {
                    fullResetCount = 0;

                    for (auto& [uPtrType, MapValue] : fileMap)
                    {
                        MapValue.fullResetCheckNumber = 0;
                    }

                    stdprintf("fullResetCount reset\n");
                }

                fullResetCount++;
                stdprintf("fullResetCount set to %zu, all sequences will be reset\n", fullResetCount);
            }
            else if (fileMapValue.delays[fileMapValue.position] == -1)
            {
                fileMapValue.position = 0;
                stdprintf("this delay sequence reset\n");
            }
            else if (fileMapValue.delays[fileMapValue.position] == -2)
            {
                stdprintf("delay sequence already finished\n");
            }

            if (fileMapValue.delays[fileMapValue.position] > 0)
            {
                delay = fileMapValue.delays[fileMapValue.position];
                fileMapValue.position++;
            }

            stdprintf("delay is %d millisecond(s)\n\n", delay);
        }

        if (delay > 0)
        {
#ifndef DEBUG
            std::this_thread::sleep_for(std::chrono::milliseconds(delay));
#endif
        }
    }
};

load_extender_test.cpp

#include <climits>
#include <mutex>
#include <vector>
#include <memory>
#include <cstring>
#include <charconv>
#include <exception>
#include <string_view>
#include <unordered_map>

#ifdef _WIN32
using wcharOrChar = wchar_t; // file paths are UTF-16LE on Windows
using svType = std::wstring_view;
#define cmpFunction std::wcscmp
#else
using wcharOrChar = char;
using svType = std::string_view;
#define cmpFunction std::strcmp
#endif

using uPtrType = std::unique_ptr<wcharOrChar[]>;
using vectorType = std::vector<wcharOrChar>;

#define DEBUG
#define stdprintf std::printf
size_t fullResetCount = 0;

// using multiple cpp files made exe bigger, so definitions are in this header
#include "shared.h"

void windowsHookFunction(MapAndMutex& mapAndMutexObject, vectorType& path)
{
    if (!path.empty() && path.back() == '\r')
    {
        path.pop_back();
    }

    path.push_back('\0');
    const wcharOrChar* pathPtr = path.data();

    // in the actual program, pathEndIndex will always be less than INT_MAX
    int pathEndIndex = path.size() < INT_MAX ? (int)path.size() : INT_MAX;
    int filenameIndex = pathEndIndex;

    for (; filenameIndex >= 0 && pathPtr[filenameIndex] != '\\'; filenameIndex--);

    filenameIndex++; // moving past '\\' character or to 0 if no '\\' was found
    auto it = mapAndMutexObject.fileMap.find(
        svType(pathPtr + filenameIndex,
        (size_t)pathEndIndex - filenameIndex)
    );

    if (it != mapAndMutexObject.fileMap.end())
    {
#ifdef _WIN32
        std::printf("\n%ls found in map\n", path.data());
#else
        std::printf("\n%s found in map\n", path.c_str());
#endif
        mapAndMutexObject.delayFile(it->second);
    }
    else
    {
#ifdef _WIN32
        std::printf("\n%ls not found in map\n", path.data());
#else
        std::printf("\n%s not found in map\n", path.c_str());
#endif
    }
}

void unixHookFunction(MapAndMutex& mapAndMutexObject, vectorType& path)
{
    if (!path.empty() && path.back() == '\r')
    {
        path.pop_back();
    }

    path.push_back('\0');
    const wcharOrChar* pathPtr = path.data();

    int filenameIndex = -1;
    int pathEndIndex = 0;

    // in the actual program, pathEndIndex will always be less than INT_MAX
    for (; pathPtr[pathEndIndex] != '\0' && pathEndIndex < INT_MAX; pathEndIndex++)
    {
        if (pathPtr[pathEndIndex] == '/')
        {
            filenameIndex = pathEndIndex;
        }
    }

    filenameIndex++; // moving past '/' character or to 0 if no '/' was found
    auto it = mapAndMutexObject.fileMap.find(
        svType(pathPtr + filenameIndex,
        (size_t)pathEndIndex - filenameIndex)
    );

    if (it != mapAndMutexObject.fileMap.end())
    {
#ifdef _WIN32
        std::printf("\n%ls found in map\n", path.data());
#else
        std::printf("\n%s found in map\n", path.data());
#endif
        mapAndMutexObject.delayFile(it->second);
    }
    else
    {
#ifdef _WIN32
        std::printf("\n%ls not found in map\n", path.data());
#else
        std::printf("\n%s not found in map\n", path.data());
#endif
    }
}

void printMap(const myMapType& fileMap)
{
    for (auto& [key, value] : fileMap)
    {
        std::printf(
#ifdef _WIN32
            "%ls : fullResetCheckNumber %zu : position %zu : ",
#else
            "%s : fullResetCheckNumber %zu : position %zu : ",
#endif
            key.get(),
            value.fullResetCheckNumber,
            value.position
        );

        size_t delaysPosition = 0;

        for (; value.delays[delaysPosition] >= 0; delaysPosition++)
        {
            std::printf("%d / ", value.delays[delaysPosition]);
        }

        if (value.delays[delaysPosition] == -1)
        {
            std::printf(delaysPosition == 0 ? "RESET ALL" : "RESET");
        }

        std::printf("\n");
    }
}

void testFunctions(MapAndMutex& mapAndMutexObject, FileHelper& fhelper, bool testUnix)
{
    vectorType path;
    wcharOrChar ch = '\0';

    while (fhelper.getCharacter(ch))
    {
        if (ch == '\n')
        {
            if (testUnix)
            {
                unixHookFunction(mapAndMutexObject, path);
            }
            else
            {
                windowsHookFunction(mapAndMutexObject, path);
            }

            printMap(mapAndMutexObject.fileMap);
            path.clear();
        }
        else
        {
            path.push_back(ch);
        }
    }

    if (testUnix)
    {
        unixHookFunction(mapAndMutexObject, path);
    }
    else
    {
        windowsHookFunction(mapAndMutexObject, path);
    }
}

void testInputs(MapAndMutex& mapAndMutexObject)
{
    FileHelper fhelper("test_input.txt");
    wcharOrChar byteOrderMark = '\0';
#ifdef _WIN32

    if (!fhelper.getCharacter(byteOrderMark))
    {
        std::printf(
            "test_input.txt byte order mark is missing\n\
save test_input.txt as UTF-16 LE\n\n"
        );

        return;
    }
    else if (byteOrderMark != 0xFEFF) // not 0xFFFE due to how wchar_t is read
    {
        std::printf(
            "test_input.txt byte order mark isn't marked as UTF-16 LE\n\
make sure files_and_delays.txt is saved as UTF-16 LE\n\n"
        );
    }
#endif
    std::printf("\ntesting UNIX\n\n - - - - - - - - - -\n\n");
    printMap(mapAndMutexObject.fileMap);
    testFunctions(mapAndMutexObject, fhelper, true);
    printMap(mapAndMutexObject.fileMap);

    // resetting things to test windows version of fake hook function
    fullResetCount = 0;
    fhelper.resetFile();
#ifdef _WIN32
    fhelper.getCharacter(byteOrderMark);
#endif

    for (auto& [key, value] : mapAndMutexObject.fileMap)
    {
        value.position = 0;
        value.fullResetCheckNumber = 0;
    }

    std::printf("\n\ntesting Windows\n\n - - - - - - - - - -\n\n");
    printMap(mapAndMutexObject.fileMap);
    testFunctions(mapAndMutexObject, fhelper, false);
    printMap(mapAndMutexObject.fileMap);
}

int main()
{
    try
    {
        std::printf("\ntest start\n\n");
        MapAndMutex mapAndMutexObject;
        testInputs(mapAndMutexObject);
    }
    catch (const std::runtime_error& e)
    {
        std::printf("%s", e.what());
        return EXIT_FAILURE;
    }

    std::printf("\ntest finished, press Enter to exit\n");
    char ch = getchar();

    return EXIT_SUCCESS;
}
\$\endgroup\$
2
  • \$\begingroup\$ I noticed that in the fopen unix hook function, original_fopen should be originalFopen. \$\endgroup\$ Jun 3, 2022 at 19:08
  • \$\begingroup\$ Also I should be passing intAsChars by reference \$\endgroup\$ Jun 5, 2022 at 2:53

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.