<commit_before>//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

//*****************************************************************************
// unixinterface.cpp
//
// Implementation for the interface exposed by the libcoreclr.so on Unix
//

//*****************************************************************************

#include "stdafx.h"
#include <utilcode.h>
#include <corhost.h>

typedef int (STDMETHODCALLTYPE *HostMain)(
    const int argc,
    const wchar_t** argv
    );

#define ASSERTE_ALL_BUILDS(expr) _ASSERTE_ALL_BUILDS(__FILE__, (expr))

// Holder for const wide strings
typedef NewArrayHolder<const WCHAR> ConstWStringHolder;

// Holder for array of wide strings
class ConstWStringArrayHolder : public NewArrayHolder<LPCWSTR>
{
    int m_cElements;

public:
    ConstWStringArrayHolder() :
        NewArrayHolder<LPCWSTR>(),
        m_cElements(0)
    {
    }

    void Set(LPCWSTR* value, int cElements)
    {
        NewArrayHolder<LPCWSTR>::operator=(value);
        m_cElements = cElements;
    }

    ~ConstWStringArrayHolder()
    {
        for (int i = 0; i < m_cElements; i++)
        {
            delete [] this->m_value[i];
        }
    }
};

// Convert 8 bit string to unicode
static LPCWSTR StringToUnicode(LPCSTR str)
{
    int length = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
    ASSERTE_ALL_BUILDS(length != 0);

    LPWSTR result = new (nothrow) WCHAR[length];
    ASSERTE_ALL_BUILDS(result != NULL);

    length = MultiByteToWideChar(CP_ACP, 0, str, length, result, length);
    ASSERTE_ALL_BUILDS(length != 0);

    return result;
}

// Convert 8 bit string array to unicode string array
static LPCWSTR* StringArrayToUnicode(int argc, LPCSTR* argv)
{
    LPCWSTR* argvW = nullptr;

    if (argc > 0)
    {
        argvW = new (nothrow) LPCWSTR[argc];
        ASSERTE_ALL_BUILDS(argvW != 0);

        for (int i = 0; i < argc; i++)
        {
            argvW[i] = StringToUnicode(argv[i]);
        }
    }

    return argvW;
}

static void ExtractStartupFlagsAndConvertToUnicode(
    const char** propertyKeys,
    const char** propertyValues,
    int* propertyCountRef,
    STARTUP_FLAGS* startupFlagsRef,
    LPCWSTR** propertyKeysWRef,
    LPCWSTR** propertyValuesWRef)
{
    int propertyCount = *propertyCountRef;

    LPCWSTR* propertyKeysW = new (nothrow) LPCWSTR[propertyCount];
    ASSERTE_ALL_BUILDS(propertyKeysW != nullptr);

    LPCWSTR* propertyValuesW = new (nothrow) LPCWSTR[propertyCount];
    ASSERTE_ALL_BUILDS(propertyValuesW != nullptr);

    // Extract the startup flags from the properties, and convert the remaining properties into unicode
    STARTUP_FLAGS startupFlags =
        static_cast<STARTUP_FLAGS>(
            STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN |
            STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN |
            STARTUP_FLAGS::STARTUP_CONCURRENT_GC);
    int propertyCountW = 0;
    for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex)
    {
        auto SetFlagValue = [&](STARTUP_FLAGS flag)
        {
            if (strcmp(propertyValues[propertyIndex], "0") == 0)
            {
                startupFlags = static_cast<STARTUP_FLAGS>(startupFlags & ~flag);
            }
            else if (strcmp(propertyValues[propertyIndex], "1") == 0)
            {
                startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | flag);
            }
        };

        if (strcmp(propertyKeys[propertyIndex], "CONCURRENT_GC") == 0)
        {
            SetFlagValue(STARTUP_CONCURRENT_GC);
        }
        else if (strcmp(propertyKeys[propertyIndex], "SERVER_GC") == 0)
        {
            SetFlagValue(STARTUP_SERVER_GC);
        }
        else if (strcmp(propertyKeys[propertyIndex], "HOARD_GC_VM") == 0)
        {
            SetFlagValue(STARTUP_HOARD_GC_VM);
        }
        else if (strcmp(propertyKeys[propertyIndex], "TRIM_GC_COMMIT") == 0)
        {
            SetFlagValue(STARTUP_TRIM_GC_COMMIT);
        }
        else
        {
            // This is not a CoreCLR startup flag, convert it to unicode and preserve it for returning
            propertyKeysW[propertyCountW] = StringToUnicode(propertyKeys[propertyIndex]);
            propertyValuesW[propertyCountW] = StringToUnicode(propertyValues[propertyIndex]);
            ++propertyCountW;
        }
    }

    for (int propertyIndex = propertyCountW; propertyIndex < propertyCount; ++propertyIndex)
    {
        propertyKeysW[propertyIndex] = nullptr;
        propertyValuesW[propertyIndex] = nullptr;
    }

    *propertyCountRef = propertyCountW;
    *startupFlagsRef = startupFlags;
    *propertyKeysWRef = propertyKeysW;
    *propertyValuesWRef = propertyValuesW;
}

//
// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain
//
// Parameters:
//  exePath                 - Absolute path of the executable that invoked the ExecuteAssembly
//  appDomainFriendlyName   - Friendly name of the app domain that will be created to execute the assembly
//  propertyCount           - Number of properties (elements of the following two arguments)
//  propertyKeys            - Keys of properties of the app domain
//  propertyValues          - Values of properties of the app domain
//  hostHandle              - Output parameter, handle of the created host
//  domainId                - Output parameter, id of the created app domain
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
int coreclr_initialize(
            const char* exePath,
            const char* appDomainFriendlyName,
            int propertyCount,
            const char** propertyKeys,
            const char** propertyValues,
            void** hostHandle,
            unsigned int* domainId)
{
    HRESULT hr;
#ifdef FEATURE_PAL
    DWORD error = PAL_InitializeCoreCLR(exePath);
    hr = HRESULT_FROM_WIN32(error);

    // If PAL initialization failed, then we should return right away and avoid
    // calling any other APIs because they can end up calling into the PAL layer again.
    if (FAILED(hr))
    {
        return hr;
    }
#endif

    ReleaseHolder<ICLRRuntimeHost2> host;

    hr = CorHost2::CreateObject(IID_ICLRRuntimeHost2, (void**)&host);
    IfFailRet(hr);

    ConstWStringHolder appDomainFriendlyNameW = StringToUnicode(appDomainFriendlyName);

    STARTUP_FLAGS startupFlags;
    LPCWSTR* propertyKeysWTemp;
    LPCWSTR* propertyValuesWTemp;
    ExtractStartupFlagsAndConvertToUnicode(
        propertyKeys,
        propertyValues,
        &propertyCount,
        &startupFlags,
        &propertyKeysWTemp,
        &propertyValuesWTemp);

    ConstWStringArrayHolder propertyKeysW;
    propertyKeysW.Set(propertyKeysWTemp, propertyCount);

    ConstWStringArrayHolder propertyValuesW;
    propertyValuesW.Set(propertyValuesWTemp, propertyCount);

    hr = host->SetStartupFlags(startupFlags);
    IfFailRet(hr);

    hr = host->Start();
    IfFailRet(hr);

    hr = host->CreateAppDomainWithManager(
        appDomainFriendlyNameW,
        // Flags:
        // APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS
        // - By default CoreCLR only allows platform neutral assembly to be run. To allow
        //   assemblies marked as platform specific, include this flag
        //
        // APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP
        // - Allows sandboxed applications to make P/Invoke calls and use COM interop
        //
        // APPDOMAIN_SECURITY_SANDBOXED
        // - Enables sandboxing. If not set, the app is considered full trust
        //
        // APPDOMAIN_IGNORE_UNHANDLED_EXCEPTION
        // - Prevents the application from being torn down if a managed exception is unhandled
        //
        APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS |
        APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP |
        APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT,
        NULL,                    // Name of the assembly that contains the AppDomainManager implementation
        NULL,                    // The AppDomainManager implementation type name
        propertyCount,
        propertyKeysW,
        propertyValuesW,
        (DWORD *)domainId);

    if (SUCCEEDED(hr))
    {
        host.SuppressRelease();
        *hostHandle = host;
    }

    return hr;
}

//
// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
//
// Parameters:
//  hostHandle              - Handle of the host
//  domainId                - Id of the domain
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
int coreclr_shutdown(
            void* hostHandle,
            unsigned int domainId)
{
    ReleaseHolder<ICLRRuntimeHost2> host(reinterpret_cast<ICLRRuntimeHost2*>(hostHandle));
    HRESULT hr = host->UnloadAppDomain(domainId,
                                       true); // Wait until done
    IfFailRet(hr);

    hr = host->Stop();

    // The PAL_Terminate is not called here since it would terminate the current process.

    return hr;
}

//
// Create a native callable delegate for a managed method.
//
// Parameters:
//  hostHandle              - Handle of the host
//  domainId                - Id of the domain
//  entryPointAssemblyName  - Name of the assembly which holds the custom entry point
//  entryPointTypeName      - Name of the type which holds the custom entry point
//  entryPointMethodName    - Name of the method which is the custom entry point
//  delegate                - Output parameter, the function stores a pointer to the delegate at the specified address
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
int coreclr_create_delegate(
            void* hostHandle,
            unsigned int domainId,
            const char* entryPointAssemblyName,
            const char* entryPointTypeName,
            const char* entryPointMethodName,
            void** delegate)
{
    ICLRRuntimeHost2* host = reinterpret_cast<ICLRRuntimeHost2*>(hostHandle);

    ConstWStringHolder entryPointAssemblyNameW = StringToUnicode(entryPointAssemblyName);
    ConstWStringHolder entryPointTypeNameW = StringToUnicode(entryPointTypeName);
    ConstWStringHolder entryPointMethodNameW = StringToUnicode(entryPointMethodName);

    HRESULT hr = host->CreateDelegate(
                            domainId,
                            entryPointAssemblyNameW,
                            entryPointTypeNameW,
                            entryPointMethodNameW,
                            (INT_PTR*)delegate);

    return hr;
}

//
// Execute a managed assembly with given arguments
//
// Parameters:
//  hostHandle              - Handle of the host
//  domainId                - Id of the domain
//  argc                    - Number of arguments passed to the executed assembly
//  argv                    - Array of arguments passed to the executed assembly
//  managedAssemblyPath     - Path of the managed assembly to execute (or NULL if using a custom entrypoint).
//  exitCode                - Exit code returned by the executed assembly
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
int coreclr_execute_assembly(
            void* hostHandle,
            unsigned int domainId,
            int argc,
            const char** argv,
            const char* managedAssemblyPath,
            unsigned int* exitCode)
{
    if (exitCode == NULL)
    {
        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
    }
    *exitCode = -1;

    ICLRRuntimeHost2* host = reinterpret_cast<ICLRRuntimeHost2*>(hostHandle);

    ConstWStringArrayHolder argvW;
    argvW.Set(StringArrayToUnicode(argc, argv), argc);

    ConstWStringHolder managedAssemblyPathW = StringToUnicode(managedAssemblyPath);

    HRESULT hr = host->ExecuteAssembly(domainId, managedAssemblyPathW, argc, argvW, (DWORD *)exitCode);
    IfFailRet(hr);

    return hr;
}

#ifdef PLATFORM_UNIX
//
// Execute a managed assembly with given arguments
//
// Parameters:
//  exePath                 - Absolute path of the executable that invoked the ExecuteAssembly
//  coreClrPath             - Absolute path of the libcoreclr.so
//  appDomainFriendlyName   - Friendly name of the app domain that will be created to execute the assembly
//  propertyCount           - Number of properties (elements of the following two arguments)
//  propertyKeys            - Keys of properties of the app domain
//  propertyValues          - Values of properties of the app domain
//  argc                    - Number of arguments passed to the executed assembly
//  argv                    - Array of arguments passed to the executed assembly
//  managedAssemblyPath     - Path of the managed assembly to execute (or NULL if using a custom entrypoint).
//  enntyPointAssemblyName  - Name of the assembly which holds the custom entry point (or NULL to use managedAssemblyPath).
//  entryPointTypeName      - Name of the type which holds the custom entry point (or NULL to use managedAssemblyPath).
//  entryPointMethodName    - Name of the method which is the custom entry point (or NULL to use managedAssemblyPath).
//  exitCode                - Exit code returned by the executed assembly
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
HRESULT ExecuteAssembly(
            LPCSTR exePath,
            LPCSTR coreClrPath,
            LPCSTR appDomainFriendlyName,
            int propertyCount,
            LPCSTR* propertyKeys,
            LPCSTR* propertyValues,
            int argc,
            LPCSTR* argv,
            LPCSTR managedAssemblyPath,
            LPCSTR entryPointAssemblyName,
            LPCSTR entryPointTypeName,
            LPCSTR entryPointMethodName,
            DWORD* exitCode)
{
    if (exitCode == NULL)
    {
        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
    }
    *exitCode = -1;

    ReleaseHolder<ICLRRuntimeHost2> host; //(reinterpret_cast<ICLRRuntimeHost2*>(hostHandle));
    DWORD domainId;

    HRESULT hr = coreclr_initialize(exePath, appDomainFriendlyName, propertyCount, propertyKeys, propertyValues, &host, &domainId);
    IfFailRet(hr);

    ConstWStringArrayHolder argvW;
    argvW.Set(StringArrayToUnicode(argc, argv), argc);

    if (entryPointAssemblyName == NULL || entryPointTypeName == NULL || entryPointMethodName == NULL)
    {
        ConstWStringHolder managedAssemblyPathW = StringToUnicode(managedAssemblyPath);

        hr = host->ExecuteAssembly(domainId, managedAssemblyPathW, argc, argvW, exitCode);
        IfFailRet(hr);
    }
    else
    {
        ConstWStringHolder entryPointAssemblyNameW = StringToUnicode(entryPointAssemblyName);
        ConstWStringHolder entryPointTypeNameW = StringToUnicode(entryPointTypeName);
        ConstWStringHolder entryPointMethodNameW = StringToUnicode(entryPointMethodName);

        HostMain pHostMain;

        hr = host->CreateDelegate(
            domainId,
            entryPointAssemblyNameW,
            entryPointTypeNameW,
            entryPointMethodNameW,
            (INT_PTR*)&pHostMain);

        IfFailRet(hr);

        *exitCode = pHostMain(argc, argvW);
    }

    hr = coreclr_shutdown(host, domainId);

    return hr;
}
#endif
<commit_msg>Fix unicode input on the command line<commit_after>//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

//*****************************************************************************
// unixinterface.cpp
//
// Implementation for the interface exposed by the libcoreclr.so on Unix
//

//*****************************************************************************

#include "stdafx.h"
#include <utilcode.h>
#include <corhost.h>

typedef int (STDMETHODCALLTYPE *HostMain)(
    const int argc,
    const wchar_t** argv
    );

#define ASSERTE_ALL_BUILDS(expr) _ASSERTE_ALL_BUILDS(__FILE__, (expr))

// Holder for const wide strings
typedef NewArrayHolder<const WCHAR> ConstWStringHolder;

// Holder for array of wide strings
class ConstWStringArrayHolder : public NewArrayHolder<LPCWSTR>
{
    int m_cElements;

public:
    ConstWStringArrayHolder() :
        NewArrayHolder<LPCWSTR>(),
        m_cElements(0)
    {
    }

    void Set(LPCWSTR* value, int cElements)
    {
        NewArrayHolder<LPCWSTR>::operator=(value);
        m_cElements = cElements;
    }

    ~ConstWStringArrayHolder()
    {
        for (int i = 0; i < m_cElements; i++)
        {
            delete [] this->m_value[i];
        }
    }
};

// Convert 8 bit string to unicode
static LPCWSTR StringToUnicode(LPCSTR str)
{
    int length = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
    ASSERTE_ALL_BUILDS(length != 0);

    LPWSTR result = new (nothrow) WCHAR[length];
    ASSERTE_ALL_BUILDS(result != NULL);

    length = MultiByteToWideChar(CP_ACP, 0, str, -1, result, length);
    ASSERTE_ALL_BUILDS(length != 0);

    return result;
}

// Convert 8 bit string array to unicode string array
static LPCWSTR* StringArrayToUnicode(int argc, LPCSTR* argv)
{
    LPCWSTR* argvW = nullptr;

    if (argc > 0)
    {
        argvW = new (nothrow) LPCWSTR[argc];
        ASSERTE_ALL_BUILDS(argvW != 0);

        for (int i = 0; i < argc; i++)
        {
            argvW[i] = StringToUnicode(argv[i]);
        }
    }

    return argvW;
}

static void ExtractStartupFlagsAndConvertToUnicode(
    const char** propertyKeys,
    const char** propertyValues,
    int* propertyCountRef,
    STARTUP_FLAGS* startupFlagsRef,
    LPCWSTR** propertyKeysWRef,
    LPCWSTR** propertyValuesWRef)
{
    int propertyCount = *propertyCountRef;

    LPCWSTR* propertyKeysW = new (nothrow) LPCWSTR[propertyCount];
    ASSERTE_ALL_BUILDS(propertyKeysW != nullptr);

    LPCWSTR* propertyValuesW = new (nothrow) LPCWSTR[propertyCount];
    ASSERTE_ALL_BUILDS(propertyValuesW != nullptr);

    // Extract the startup flags from the properties, and convert the remaining properties into unicode
    STARTUP_FLAGS startupFlags =
        static_cast<STARTUP_FLAGS>(
            STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN |
            STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN |
            STARTUP_FLAGS::STARTUP_CONCURRENT_GC);
    int propertyCountW = 0;
    for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex)
    {
        auto SetFlagValue = [&](STARTUP_FLAGS flag)
        {
            if (strcmp(propertyValues[propertyIndex], "0") == 0)
            {
                startupFlags = static_cast<STARTUP_FLAGS>(startupFlags & ~flag);
            }
            else if (strcmp(propertyValues[propertyIndex], "1") == 0)
            {
                startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | flag);
            }
        };

        if (strcmp(propertyKeys[propertyIndex], "CONCURRENT_GC") == 0)
        {
            SetFlagValue(STARTUP_CONCURRENT_GC);
        }
        else if (strcmp(propertyKeys[propertyIndex], "SERVER_GC") == 0)
        {
            SetFlagValue(STARTUP_SERVER_GC);
        }
        else if (strcmp(propertyKeys[propertyIndex], "HOARD_GC_VM") == 0)
        {
            SetFlagValue(STARTUP_HOARD_GC_VM);
        }
        else if (strcmp(propertyKeys[propertyIndex], "TRIM_GC_COMMIT") == 0)
        {
            SetFlagValue(STARTUP_TRIM_GC_COMMIT);
        }
        else
        {
            // This is not a CoreCLR startup flag, convert it to unicode and preserve it for returning
            propertyKeysW[propertyCountW] = StringToUnicode(propertyKeys[propertyIndex]);
            propertyValuesW[propertyCountW] = StringToUnicode(propertyValues[propertyIndex]);
            ++propertyCountW;
        }
    }

    for (int propertyIndex = propertyCountW; propertyIndex < propertyCount; ++propertyIndex)
    {
        propertyKeysW[propertyIndex] = nullptr;
        propertyValuesW[propertyIndex] = nullptr;
    }

    *propertyCountRef = propertyCountW;
    *startupFlagsRef = startupFlags;
    *propertyKeysWRef = propertyKeysW;
    *propertyValuesWRef = propertyValuesW;
}

//
// Initialize the CoreCLR. Creates and starts CoreCLR host and creates an app domain
//
// Parameters:
//  exePath                 - Absolute path of the executable that invoked the ExecuteAssembly
//  appDomainFriendlyName   - Friendly name of the app domain that will be created to execute the assembly
//  propertyCount           - Number of properties (elements of the following two arguments)
//  propertyKeys            - Keys of properties of the app domain
//  propertyValues          - Values of properties of the app domain
//  hostHandle              - Output parameter, handle of the created host
//  domainId                - Output parameter, id of the created app domain
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
int coreclr_initialize(
            const char* exePath,
            const char* appDomainFriendlyName,
            int propertyCount,
            const char** propertyKeys,
            const char** propertyValues,
            void** hostHandle,
            unsigned int* domainId)
{
    HRESULT hr;
#ifdef FEATURE_PAL
    DWORD error = PAL_InitializeCoreCLR(exePath);
    hr = HRESULT_FROM_WIN32(error);

    // If PAL initialization failed, then we should return right away and avoid
    // calling any other APIs because they can end up calling into the PAL layer again.
    if (FAILED(hr))
    {
        return hr;
    }
#endif

    ReleaseHolder<ICLRRuntimeHost2> host;

    hr = CorHost2::CreateObject(IID_ICLRRuntimeHost2, (void**)&host);
    IfFailRet(hr);

    ConstWStringHolder appDomainFriendlyNameW = StringToUnicode(appDomainFriendlyName);

    STARTUP_FLAGS startupFlags;
    LPCWSTR* propertyKeysWTemp;
    LPCWSTR* propertyValuesWTemp;
    ExtractStartupFlagsAndConvertToUnicode(
        propertyKeys,
        propertyValues,
        &propertyCount,
        &startupFlags,
        &propertyKeysWTemp,
        &propertyValuesWTemp);

    ConstWStringArrayHolder propertyKeysW;
    propertyKeysW.Set(propertyKeysWTemp, propertyCount);

    ConstWStringArrayHolder propertyValuesW;
    propertyValuesW.Set(propertyValuesWTemp, propertyCount);

    hr = host->SetStartupFlags(startupFlags);
    IfFailRet(hr);

    hr = host->Start();
    IfFailRet(hr);

    hr = host->CreateAppDomainWithManager(
        appDomainFriendlyNameW,
        // Flags:
        // APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS
        // - By default CoreCLR only allows platform neutral assembly to be run. To allow
        //   assemblies marked as platform specific, include this flag
        //
        // APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP
        // - Allows sandboxed applications to make P/Invoke calls and use COM interop
        //
        // APPDOMAIN_SECURITY_SANDBOXED
        // - Enables sandboxing. If not set, the app is considered full trust
        //
        // APPDOMAIN_IGNORE_UNHANDLED_EXCEPTION
        // - Prevents the application from being torn down if a managed exception is unhandled
        //
        APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS |
        APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP |
        APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT,
        NULL,                    // Name of the assembly that contains the AppDomainManager implementation
        NULL,                    // The AppDomainManager implementation type name
        propertyCount,
        propertyKeysW,
        propertyValuesW,
        (DWORD *)domainId);

    if (SUCCEEDED(hr))
    {
        host.SuppressRelease();
        *hostHandle = host;
    }

    return hr;
}

//
// Shutdown CoreCLR. It unloads the app domain and stops the CoreCLR host.
//
// Parameters:
//  hostHandle              - Handle of the host
//  domainId                - Id of the domain
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
int coreclr_shutdown(
            void* hostHandle,
            unsigned int domainId)
{
    ReleaseHolder<ICLRRuntimeHost2> host(reinterpret_cast<ICLRRuntimeHost2*>(hostHandle));
    HRESULT hr = host->UnloadAppDomain(domainId,
                                       true); // Wait until done
    IfFailRet(hr);

    hr = host->Stop();

    // The PAL_Terminate is not called here since it would terminate the current process.

    return hr;
}

//
// Create a native callable delegate for a managed method.
//
// Parameters:
//  hostHandle              - Handle of the host
//  domainId                - Id of the domain
//  entryPointAssemblyName  - Name of the assembly which holds the custom entry point
//  entryPointTypeName      - Name of the type which holds the custom entry point
//  entryPointMethodName    - Name of the method which is the custom entry point
//  delegate                - Output parameter, the function stores a pointer to the delegate at the specified address
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
int coreclr_create_delegate(
            void* hostHandle,
            unsigned int domainId,
            const char* entryPointAssemblyName,
            const char* entryPointTypeName,
            const char* entryPointMethodName,
            void** delegate)
{
    ICLRRuntimeHost2* host = reinterpret_cast<ICLRRuntimeHost2*>(hostHandle);

    ConstWStringHolder entryPointAssemblyNameW = StringToUnicode(entryPointAssemblyName);
    ConstWStringHolder entryPointTypeNameW = StringToUnicode(entryPointTypeName);
    ConstWStringHolder entryPointMethodNameW = StringToUnicode(entryPointMethodName);

    HRESULT hr = host->CreateDelegate(
                            domainId,
                            entryPointAssemblyNameW,
                            entryPointTypeNameW,
                            entryPointMethodNameW,
                            (INT_PTR*)delegate);

    return hr;
}

//
// Execute a managed assembly with given arguments
//
// Parameters:
//  hostHandle              - Handle of the host
//  domainId                - Id of the domain
//  argc                    - Number of arguments passed to the executed assembly
//  argv                    - Array of arguments passed to the executed assembly
//  managedAssemblyPath     - Path of the managed assembly to execute (or NULL if using a custom entrypoint).
//  exitCode                - Exit code returned by the executed assembly
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
int coreclr_execute_assembly(
            void* hostHandle,
            unsigned int domainId,
            int argc,
            const char** argv,
            const char* managedAssemblyPath,
            unsigned int* exitCode)
{
    if (exitCode == NULL)
    {
        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
    }
    *exitCode = -1;

    ICLRRuntimeHost2* host = reinterpret_cast<ICLRRuntimeHost2*>(hostHandle);

    ConstWStringArrayHolder argvW;
    argvW.Set(StringArrayToUnicode(argc, argv), argc);

    ConstWStringHolder managedAssemblyPathW = StringToUnicode(managedAssemblyPath);

    HRESULT hr = host->ExecuteAssembly(domainId, managedAssemblyPathW, argc, argvW, (DWORD *)exitCode);
    IfFailRet(hr);

    return hr;
}

#ifdef PLATFORM_UNIX
//
// Execute a managed assembly with given arguments
//
// Parameters:
//  exePath                 - Absolute path of the executable that invoked the ExecuteAssembly
//  coreClrPath             - Absolute path of the libcoreclr.so
//  appDomainFriendlyName   - Friendly name of the app domain that will be created to execute the assembly
//  propertyCount           - Number of properties (elements of the following two arguments)
//  propertyKeys            - Keys of properties of the app domain
//  propertyValues          - Values of properties of the app domain
//  argc                    - Number of arguments passed to the executed assembly
//  argv                    - Array of arguments passed to the executed assembly
//  managedAssemblyPath     - Path of the managed assembly to execute (or NULL if using a custom entrypoint).
//  enntyPointAssemblyName  - Name of the assembly which holds the custom entry point (or NULL to use managedAssemblyPath).
//  entryPointTypeName      - Name of the type which holds the custom entry point (or NULL to use managedAssemblyPath).
//  entryPointMethodName    - Name of the method which is the custom entry point (or NULL to use managedAssemblyPath).
//  exitCode                - Exit code returned by the executed assembly
//
// Returns:
//  HRESULT indicating status of the operation. S_OK if the assembly was successfully executed
//
extern "C"
HRESULT ExecuteAssembly(
            LPCSTR exePath,
            LPCSTR coreClrPath,
            LPCSTR appDomainFriendlyName,
            int propertyCount,
            LPCSTR* propertyKeys,
            LPCSTR* propertyValues,
            int argc,
            LPCSTR* argv,
            LPCSTR managedAssemblyPath,
            LPCSTR entryPointAssemblyName,
            LPCSTR entryPointTypeName,
            LPCSTR entryPointMethodName,
            DWORD* exitCode)
{
    if (exitCode == NULL)
    {
        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
    }
    *exitCode = -1;

    ReleaseHolder<ICLRRuntimeHost2> host; //(reinterpret_cast<ICLRRuntimeHost2*>(hostHandle));
    DWORD domainId;

    HRESULT hr = coreclr_initialize(exePath, appDomainFriendlyName, propertyCount, propertyKeys, propertyValues, &host, &domainId);
    IfFailRet(hr);

    ConstWStringArrayHolder argvW;
    argvW.Set(StringArrayToUnicode(argc, argv), argc);

    if (entryPointAssemblyName == NULL || entryPointTypeName == NULL || entryPointMethodName == NULL)
    {
        ConstWStringHolder managedAssemblyPathW = StringToUnicode(managedAssemblyPath);

        hr = host->ExecuteAssembly(domainId, managedAssemblyPathW, argc, argvW, exitCode);
        IfFailRet(hr);
    }
    else
    {
        ConstWStringHolder entryPointAssemblyNameW = StringToUnicode(entryPointAssemblyName);
        ConstWStringHolder entryPointTypeNameW = StringToUnicode(entryPointTypeName);
        ConstWStringHolder entryPointMethodNameW = StringToUnicode(entryPointMethodName);

        HostMain pHostMain;

        hr = host->CreateDelegate(
            domainId,
            entryPointAssemblyNameW,
            entryPointTypeNameW,
            entryPointMethodNameW,
            (INT_PTR*)&pHostMain);

        IfFailRet(hr);

        *exitCode = pHostMain(argc, argvW);
    }

    hr = coreclr_shutdown(host, domainId);

    return hr;
}
#endif
<|endoftext|>


<commit_before>//
// detail/compression_snappy_test.cpp
// ----------------------------------
//
// Copyright (c) 2015 Daniel Joos
//
// Distributed under MIT license. (See file LICENSE)
//

#include <gtest/gtest.h>
#include <snappy.h>
#include <libkafka_asio/libkafka_asio.h>

using libkafka_asio::Byte;
using libkafka_asio::Bytes;
using libkafka_asio::String;
using libkafka_asio::detail::Decompress;

TEST(CompressionSnappyTest, SimpleDecompress)
{
  const String expected_result = "HelloWorld";
  String compressed;
  ::snappy::Compress(expected_result.c_str(), expected_result.size(),
                     &compressed);
  Bytes test_data(new Bytes::element_type(compressed.begin(),
                                          compressed.end()));
  ASSERT_FALSE(test_data->empty());
  boost::system::error_code ec;
  using namespace libkafka_asio::constants;
  Bytes result = Decompress(test_data, kCompressionSnappy, ec);
  ASSERT_EQ(libkafka_asio::kErrorSuccess, ec);
  ASSERT_EQ(expected_result.size(), result->size());
  ASSERT_STREQ(expected_result.c_str(),
               String((const char *) &(*result)[0], result->size()).c_str());
}

TEST(CompressionSnappyTest, StreamDecompress)
{
  // Compress this little test string using two chunks
  const String expected_result = "Hello World";
  using boost::asio::streambuf;
  using boost::asio::buffer_cast;
  using boost::asio::buffer_size;
  using libkafka_asio::detail::WriteInt32;
  using libkafka_asio::Int32;
  String compressed1, compressed2;
  ::snappy::Compress(expected_result.c_str(), 5,
                     &compressed1);
  ::snappy::Compress(expected_result.c_str() + 5, expected_result.size() - 5,
                     &compressed2);
  streambuf compressed_streambuf;
  std::iostream compressed_stream(&compressed_streambuf);
  Bytes magic_bytes =
    libkafka_asio::detail::SnappyCompressionAlgorithm::kSnappyStreamMagic();
  compressed_stream.write(reinterpret_cast<const char *>(&(*magic_bytes)[0]),
                          magic_bytes->size());
  WriteInt32(1, compressed_stream);
  WriteInt32(1, compressed_stream);
  WriteInt32(static_cast<Int32>(compressed1.size()), compressed_stream);
  compressed_stream.write(compressed1.c_str(), compressed1.size());
  WriteInt32(static_cast<Int32>(compressed2.size()), compressed_stream);
  compressed_stream.write(compressed2.c_str(), compressed2.size());
  streambuf::const_buffers_type compressed_data =
    compressed_streambuf.data();
  Bytes test_data(new Bytes::element_type(
    buffer_cast<const Bytes::element_type::value_type *>(compressed_data),
    buffer_cast<const Bytes::element_type::value_type *>(compressed_data) +
    buffer_size(compressed_data)
  ));

  ASSERT_FALSE(test_data->empty());
  boost::system::error_code ec;
  using namespace libkafka_asio::constants;
  Bytes result = Decompress(test_data, kCompressionSnappy, ec);
  ASSERT_EQ(libkafka_asio::kErrorSuccess, ec);
  ASSERT_EQ(expected_result.size(), result->size());
  ASSERT_STREQ(expected_result.c_str(),
               String((const char *) &(*result)[0], result->size()).c_str());
}

TEST(CompressionSnappyTest, EmptyDecompress)
{
  {
    Bytes test_data;
    boost::system::error_code ec;
    using namespace libkafka_asio::constants;
    Bytes result = Decompress(test_data, kCompressionSnappy, ec);
    ASSERT_EQ(libkafka_asio::kErrorCompressionFailed, ec);
    ASSERT_TRUE(!result);
  }
  {
    Bytes test_data(new Bytes::element_type());
    boost::system::error_code ec;
    using namespace libkafka_asio::constants;
    Bytes result = Decompress(test_data, kCompressionSnappy, ec);
    ASSERT_EQ(libkafka_asio::kErrorCompressionFailed, ec);
    ASSERT_TRUE(!result);
  }
}
<commit_msg>Cleaned up tests for snappy compression<commit_after>//
// detail/compression_snappy_test.cpp
// ----------------------------------
//
// Copyright (c) 2015 Daniel Joos
//
// Distributed under MIT license. (See file LICENSE)
//

#include <gtest/gtest.h>
#include <snappy.h>
#include <libkafka_asio/libkafka_asio.h>

using libkafka_asio::Byte;
using libkafka_asio::Bytes;
using libkafka_asio::String;
using libkafka_asio::detail::Compress;
using libkafka_asio::detail::Decompress;

class CompressionSnappyTest : public ::testing::Test
{
protected:
  Bytes TestCase1Compressed()
  {
    static const unsigned char data[11] =
    {
      0x24, 0x14, 0x52, 0x45, 0x50, 0x45, 0x41, 0x54,
      0x76, 0x06, 0x00
    };
    return Bytes(new Bytes::element_type(data, data + sizeof(data)));
  }

  Bytes TestCase2Compressed()
  {
    const unsigned char data[39] =
    {
      0x82, 0x53, 0x4e, 0x41, 0x50, 0x50, 0x59, 0x00,
      0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
      0x00, 0x00, 0x00, 0x07, 0x05, 0x10, 0x48, 0x65,
      0x6c, 0x6c, 0x6f, 0x00, 0x00, 0x00, 0x08, 0x06,
      0x14, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64
    };
    return Bytes(new Bytes::element_type(data, data + sizeof(data)));
  }

  Bytes TestCase1Uncompressed()
  {
    static const String data = "REPEATREPEATREPEATREPEATREPEATREPEAT";
    return Bytes(new Bytes::element_type(data.begin(), data.end()));
  }

  Bytes TestCase2Uncompressed()
  {
    static const String data = "Hello World";
    return Bytes(new Bytes::element_type(data.begin(), data.end()));
  }

  void AssertBytesEq(const Bytes& expected, const Bytes& actual)
  {
    ASSERT_TRUE(expected);
    ASSERT_TRUE(actual);
    ASSERT_EQ(expected->size(), actual->size());
    for (size_t i = 0; i < actual->size(); ++i)
    {
      ASSERT_EQ(expected->at(i), actual->at(i));
    }
  }
};

TEST_F(CompressionSnappyTest, SimpleDecompress)
{
  boost::system::error_code ec;
  using namespace libkafka_asio::constants;
  Bytes result = Decompress(TestCase1Compressed(), kCompressionSnappy, ec);
  Bytes expected_result = TestCase1Uncompressed();
  ASSERT_EQ(libkafka_asio::kErrorSuccess, ec);
  AssertBytesEq(expected_result, result);
}

TEST_F(CompressionSnappyTest, StreamDecompress)
{
  boost::system::error_code ec;
  using namespace libkafka_asio::constants;
  Bytes result = Decompress(TestCase2Compressed(), kCompressionSnappy, ec);
  Bytes expected_result = TestCase2Uncompressed();
  ASSERT_EQ(libkafka_asio::kErrorSuccess, ec);
  AssertBytesEq(expected_result, result);
}

TEST_F(CompressionSnappyTest, EmptyDecompress)
{
  {
    Bytes test_data;
    boost::system::error_code ec;
    using namespace libkafka_asio::constants;
    Bytes result = Decompress(test_data, kCompressionSnappy, ec);
    ASSERT_EQ(libkafka_asio::kErrorCompressionFailed, ec);
    ASSERT_TRUE(!result);
  }
  {
    Bytes test_data(new Bytes::element_type());
    boost::system::error_code ec;
    using namespace libkafka_asio::constants;
    Bytes result = Decompress(test_data, kCompressionSnappy, ec);
    ASSERT_EQ(libkafka_asio::kErrorCompressionFailed, ec);
    ASSERT_TRUE(!result);
  }
}

TEST_F(CompressionSnappyTest, SimpleCompress)
{
  boost::system::error_code ec;
  using namespace libkafka_asio::constants;
  Bytes result = Compress(TestCase1Uncompressed(), kCompressionSnappy, ec);
  Bytes expected_result = TestCase1Compressed();
  ASSERT_EQ(libkafka_asio::kErrorSuccess, ec);
  AssertBytesEq(expected_result, result);
}
<|endoftext|>


<commit_before>#include "bindings.h"

Nan::Persistent<v8::Function> Event::constructor;

// Construct a blank event from the context metadata
Event::Event() {
  oboe_event_init(&event, OboeContext::get());
}

// Construct a new event point an edge at another
Event::Event(const oboe_metadata_t *md, bool addEdge) {
  // both methods copy metadata from md -> this
  if (addEdge) {
    // create_event automatically adds edge in event to md
    oboe_metadata_create_event(md, &event);
  } else {
    // initializes new Event with this md's task_id & new random op_id; no edges set
    oboe_event_init(&event, md);
  }
}

// Remember to cleanup the struct when garbage collected
Event::~Event() {
  oboe_event_destroy(&event);
}

v8::Local<v8::Object> Event::NewInstance(v8::Local<v8::Value> context, v8::Local<v8::Value> addEdge) {
  Nan::EscapableHandleScope scope;

  const unsigned argc = 2;
  v8::Local<v8::Value> argv[argc] = { context, addEdge };
  v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
  v8::Local<v8::Object> instance = cons->NewInstance(argc, argv);

  return scope.Escape(instance);
}

v8::Local<v8::Object> Event::NewInstance(v8::Local<v8::Value> context) {
  Nan::EscapableHandleScope scope;

  const unsigned argc = 1;
  v8::Local<v8::Value> argv[argc] = { context };
  v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
  v8::Local<v8::Object> instance = cons->NewInstance(argc, argv);

  return scope.Escape(instance);
}

v8::Local<v8::Object> Event::NewInstance() {
  Nan::EscapableHandleScope scope;

  const unsigned argc = 0;
  v8::Local<v8::Value> argv[argc] = {};
  v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
  v8::Local<v8::Object> instance = cons->NewInstance(argc, argv);

  return scope.Escape(instance);
}

// Add info to the event
NAN_METHOD(Event::addInfo) {
  // Validate arguments
  if (info.Length() != 2) {
    return Nan::ThrowError("Wrong number of arguments");
  }
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError("Key must be a string");
  }
  if (!info[1]->IsString() && !info[1]->IsNumber() && !info[1]->IsBoolean()) {
    return Nan::ThrowTypeError("Value must be a boolean, string or number");
  }

  // Unwrap event instance from V8
  Event* self = ObjectWrap::Unwrap<Event>(info.This());
  oboe_event_t* event = &self->event;

  // Get key string from arguments and prepare a status variable
  const char* key = *Nan::Utf8String(info[0]);
  int status;

  // Handle integer values
  if (info[1]->IsBoolean()) {
    bool val = info[1]->BooleanValue();
    status = oboe_event_add_info_bool(event, key, val);

  // Handle double values
  } else if (info[1]->IsInt32()) {
    int64_t val = info[1]->Int32Value();
    status = oboe_event_add_info_int64(event, key, val);

  // Handle double values
  } else if (info[1]->IsNumber()) {
    const double val = info[1]->NumberValue();
    status = oboe_event_add_info_double(event, key, val);

  // Handle string values
  } else {
    // Get value string from arguments
    char* val = *Nan::Utf8String(info[1]);
    int len = strlen(val);

    // Detect if we should add as binary or a string
    // TODO: Should probably use buffers for binary data...
    if (memchr(val, '\0', len)) {
      status = oboe_event_add_info_binary(event, key, val, len);
    } else {
      status = oboe_event_add_info(event, key, val);
    }
  }

  if (status < 0) {
    return Nan::ThrowError("Failed to add info");
  }
}

// Add an edge from a metadata instance
NAN_METHOD(Event::addEdge) {
  // Validate arguments
  if (info.Length() != 1) {
    return Nan::ThrowError("Wrong number of arguments");
  }
  if (!info[0]->IsObject() && !info[0]->IsString()) {
    return Nan::ThrowTypeError("Must supply an edge metadata instance or string");
  }

  // Unwrap event instance from V8
  Event* self = Nan::ObjectWrap::Unwrap<Event>(info.This());
  int status;

  if (info[0]->IsObject()) {
    // Unwrap metadata instance from arguments
    Metadata* metadata = Nan::ObjectWrap::Unwrap<Metadata>(info[0]->ToObject());

    // Attempt to add the edge
    status = oboe_event_add_edge(&self->event, &metadata->metadata);
  } else {
    // Get string data from arguments
    char* val = *Nan::Utf8String(info[0]);

    // Attempt to add edge
    status = oboe_event_add_edge_fromstr(&self->event, val, strlen(val));
  }

  if (status < 0) {
    return Nan::ThrowError("Failed to add edge");
  }
}

// Get the metadata of an event
NAN_METHOD(Event::getMetadata) {
  // Unwrap event instance from V8
  Event* self = Nan::ObjectWrap::Unwrap<Event>(info.This());
  oboe_event_t* event = &self->event;

  // Make an empty object template with space for internal field pointers
  v8::Local<v8::ObjectTemplate> t = Nan::New<v8::ObjectTemplate>();
  t->SetInternalFieldCount(2);

  // Construct an object with our internal field pointer
  v8::Local<v8::Object> obj = t->NewInstance();

  // Attach the internal field pointer
  Nan::SetInternalFieldPointer(obj, 1, (void *) &event->metadata);

  // Use the object as an argument in the event constructor
  info.GetReturnValue().Set(Metadata::NewInstance(obj));
}

// Get the metadata of an event as a string
NAN_METHOD(Event::toString) {
  // Unwrap the event instance from V8
  Event* self = Nan::ObjectWrap::Unwrap<Event>(info.This());

  // Get a pointer to the event struct
  oboe_event_t* event = &self->event;

  // Build a character array from the event metadata content
  char buf[OBOE_MAX_METADATA_PACK_LEN];
  int rc = oboe_metadata_tostr(&event->metadata, buf, sizeof(buf) - 1);

  // If we have data, return it as a string
  if (rc == 0) {
    info.GetReturnValue().Set(Nan::New(buf).ToLocalChecked());

  // Otherwise, return an empty string
  } else {
    info.GetReturnValue().Set(Nan::New("").ToLocalChecked());
  }
}

// Start tracing using supplied metadata
NAN_METHOD(Event::startTrace) {
  // Validate arguments
  if (info.Length() != 1) {
    return Nan::ThrowError("Wrong number of arguments");
  }
  if (!info[0]->IsObject()) {
    return Nan::ThrowTypeError("Must supply a metadata instance");
  }

  // Unwrap metadata from arguments
  Metadata* metadata = Nan::ObjectWrap::Unwrap<Metadata>(info[0]->ToObject());

  // Make an empty object template with space for internal field pointers
  v8::Local<v8::ObjectTemplate> t = Nan::New<v8::ObjectTemplate>();
  t->SetInternalFieldCount(2);

  // Construct an object with our internal field pointer
  v8::Local<v8::Object> obj = t->NewInstance();

  // Attach the internal field pointer
  Nan::SetInternalFieldPointer(obj, 1, (void *) &metadata->metadata);

  // Use the object as an argument in the event constructor
  info.GetReturnValue().Set(Event::NewInstance(obj, Nan::New(false)));
}

// Creates a new Javascript instance
NAN_METHOD(Event::New) {
  if (!info.IsConstructCall()) {
    return Nan::ThrowError("Event() must be called as a constructor");
  }

  Event* event;
  if (info.Length() > 0) {
    void* ptr = Nan::GetInternalFieldPointer(info[0].As<v8::Object>(), 1);
    oboe_metadata_t* context = static_cast<oboe_metadata_t*>(ptr);

    bool addEdge = true;
    if (info.Length() == 2 && info[1]->IsBoolean()) {
      addEdge = info[1]->BooleanValue();
    }

    event = new Event(context, addEdge);
  } else {
    event = new Event();
  }

  event->Wrap(info.This());
  Nan::SetInternalFieldPointer(info.This(), 1, &event->event);
  info.GetReturnValue().Set(info.This());
}

// Wrap the C++ object so V8 can understand it
void Event::Init(v8::Local<v8::Object> exports) {
  Nan::HandleScope scope;

  // Prepare constructor template
  v8::Local<v8::FunctionTemplate> ctor = Nan::New<v8::FunctionTemplate>(New);
  ctor->InstanceTemplate()->SetInternalFieldCount(2);
  ctor->SetClassName(Nan::New("Event").ToLocalChecked());

  // Statics
  Nan::SetMethod(ctor, "startTrace", Event::startTrace);

  // Prototype
  Nan::SetPrototypeMethod(ctor, "addInfo", Event::addInfo);
  Nan::SetPrototypeMethod(ctor, "addEdge", Event::addEdge);
  Nan::SetPrototypeMethod(ctor, "getMetadata", Event::getMetadata);
  Nan::SetPrototypeMethod(ctor, "toString", Event::toString);

  constructor.Reset(ctor->GetFunction());
  Nan::Set(exports, Nan::New("Event").ToLocalChecked(), ctor->GetFunction());
}
<commit_msg>[misc] Fix issue identifying utf8 string length<commit_after>#include "bindings.h"

Nan::Persistent<v8::Function> Event::constructor;

// Construct a blank event from the context metadata
Event::Event() {
  oboe_event_init(&event, OboeContext::get());
}

// Construct a new event point an edge at another
Event::Event(const oboe_metadata_t *md, bool addEdge) {
  // both methods copy metadata from md -> this
  if (addEdge) {
    // create_event automatically adds edge in event to md
    oboe_metadata_create_event(md, &event);
  } else {
    // initializes new Event with this md's task_id & new random op_id; no edges set
    oboe_event_init(&event, md);
  }
}

// Remember to cleanup the struct when garbage collected
Event::~Event() {
  oboe_event_destroy(&event);
}

v8::Local<v8::Object> Event::NewInstance(v8::Local<v8::Value> context, v8::Local<v8::Value> addEdge) {
  Nan::EscapableHandleScope scope;

  const unsigned argc = 2;
  v8::Local<v8::Value> argv[argc] = { context, addEdge };
  v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
  v8::Local<v8::Object> instance = cons->NewInstance(argc, argv);

  return scope.Escape(instance);
}

v8::Local<v8::Object> Event::NewInstance(v8::Local<v8::Value> context) {
  Nan::EscapableHandleScope scope;

  const unsigned argc = 1;
  v8::Local<v8::Value> argv[argc] = { context };
  v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
  v8::Local<v8::Object> instance = cons->NewInstance(argc, argv);

  return scope.Escape(instance);
}

v8::Local<v8::Object> Event::NewInstance() {
  Nan::EscapableHandleScope scope;

  const unsigned argc = 0;
  v8::Local<v8::Value> argv[argc] = {};
  v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
  v8::Local<v8::Object> instance = cons->NewInstance(argc, argv);

  return scope.Escape(instance);
}

// Add info to the event
NAN_METHOD(Event::addInfo) {
  // Validate arguments
  if (info.Length() != 2) {
    return Nan::ThrowError("Wrong number of arguments");
  }
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError("Key must be a string");
  }
  if (!info[1]->IsString() && !info[1]->IsNumber() && !info[1]->IsBoolean()) {
    return Nan::ThrowTypeError("Value must be a boolean, string or number");
  }

  // Unwrap event instance from V8
  Event* self = ObjectWrap::Unwrap<Event>(info.This());
  oboe_event_t* event = &self->event;

  // Get key string from arguments and prepare a status variable
  const char* key = *Nan::Utf8String(info[0]);
  int status;

  // Handle integer values
  if (info[1]->IsBoolean()) {
    bool val = info[1]->BooleanValue();
    status = oboe_event_add_info_bool(event, key, val);

  // Handle double values
  } else if (info[1]->IsInt32()) {
    int64_t val = info[1]->Int32Value();
    status = oboe_event_add_info_int64(event, key, val);

  // Handle double values
  } else if (info[1]->IsNumber()) {
    const double val = info[1]->NumberValue();
    status = oboe_event_add_info_double(event, key, val);

  // Handle string values
  } else {
    // Get value string from arguments
    Nan::Utf8String v8_value(info[1]);
    int length = v8_value.length();
    char* value = *v8_value;

    // Detect if we should add as binary or a string
    // TODO: Should probably use buffers for binary data...
    if (memchr(value, '\0', length)) {
      status = oboe_event_add_info_binary(event, key, value, length);
    } else {
      status = oboe_event_add_info(event, key, value);
    }
  }

  if (status < 0) {
    return Nan::ThrowError("Failed to add info");
  }
}

// Add an edge from a metadata instance
NAN_METHOD(Event::addEdge) {
  // Validate arguments
  if (info.Length() != 1) {
    return Nan::ThrowError("Wrong number of arguments");
  }
  if (!info[0]->IsObject() && !info[0]->IsString()) {
    return Nan::ThrowTypeError("Must supply an edge metadata instance or string");
  }

  // Unwrap event instance from V8
  Event* self = Nan::ObjectWrap::Unwrap<Event>(info.This());
  int status;

  if (info[0]->IsObject()) {
    // Unwrap metadata instance from arguments
    Metadata* metadata = Nan::ObjectWrap::Unwrap<Metadata>(info[0]->ToObject());

    // Attempt to add the edge
    status = oboe_event_add_edge(&self->event, &metadata->metadata);
  } else {
    // Get string data from arguments
    char* val = *Nan::Utf8String(info[0]);

    // Attempt to add edge
    status = oboe_event_add_edge_fromstr(&self->event, val, strlen(val));
  }

  if (status < 0) {
    return Nan::ThrowError("Failed to add edge");
  }
}

// Get the metadata of an event
NAN_METHOD(Event::getMetadata) {
  // Unwrap event instance from V8
  Event* self = Nan::ObjectWrap::Unwrap<Event>(info.This());
  oboe_event_t* event = &self->event;

  // Make an empty object template with space for internal field pointers
  v8::Local<v8::ObjectTemplate> t = Nan::New<v8::ObjectTemplate>();
  t->SetInternalFieldCount(2);

  // Construct an object with our internal field pointer
  v8::Local<v8::Object> obj = t->NewInstance();

  // Attach the internal field pointer
  Nan::SetInternalFieldPointer(obj, 1, (void *) &event->metadata);

  // Use the object as an argument in the event constructor
  info.GetReturnValue().Set(Metadata::NewInstance(obj));
}

// Get the metadata of an event as a string
NAN_METHOD(Event::toString) {
  // Unwrap the event instance from V8
  Event* self = Nan::ObjectWrap::Unwrap<Event>(info.This());

  // Get a pointer to the event struct
  oboe_event_t* event = &self->event;

  // Build a character array from the event metadata content
  char buf[OBOE_MAX_METADATA_PACK_LEN];
  int rc = oboe_metadata_tostr(&event->metadata, buf, sizeof(buf) - 1);

  // If we have data, return it as a string
  if (rc == 0) {
    info.GetReturnValue().Set(Nan::New(buf).ToLocalChecked());

  // Otherwise, return an empty string
  } else {
    info.GetReturnValue().Set(Nan::New("").ToLocalChecked());
  }
}

// Start tracing using supplied metadata
NAN_METHOD(Event::startTrace) {
  // Validate arguments
  if (info.Length() != 1) {
    return Nan::ThrowError("Wrong number of arguments");
  }
  if (!info[0]->IsObject()) {
    return Nan::ThrowTypeError("Must supply a metadata instance");
  }

  // Unwrap metadata from arguments
  Metadata* metadata = Nan::ObjectWrap::Unwrap<Metadata>(info[0]->ToObject());

  // Make an empty object template with space for internal field pointers
  v8::Local<v8::ObjectTemplate> t = Nan::New<v8::ObjectTemplate>();
  t->SetInternalFieldCount(2);

  // Construct an object with our internal field pointer
  v8::Local<v8::Object> obj = t->NewInstance();

  // Attach the internal field pointer
  Nan::SetInternalFieldPointer(obj, 1, (void *) &metadata->metadata);

  // Use the object as an argument in the event constructor
  info.GetReturnValue().Set(Event::NewInstance(obj, Nan::New(false)));
}

// Creates a new Javascript instance
NAN_METHOD(Event::New) {
  if (!info.IsConstructCall()) {
    return Nan::ThrowError("Event() must be called as a constructor");
  }

  Event* event;
  if (info.Length() > 0) {
    void* ptr = Nan::GetInternalFieldPointer(info[0].As<v8::Object>(), 1);
    oboe_metadata_t* context = static_cast<oboe_metadata_t*>(ptr);

    bool addEdge = true;
    if (info.Length() == 2 && info[1]->IsBoolean()) {
      addEdge = info[1]->BooleanValue();
    }

    event = new Event(context, addEdge);
  } else {
    event = new Event();
  }

  event->Wrap(info.This());
  Nan::SetInternalFieldPointer(info.This(), 1, &event->event);
  info.GetReturnValue().Set(info.This());
}

// Wrap the C++ object so V8 can understand it
void Event::Init(v8::Local<v8::Object> exports) {
  Nan::HandleScope scope;

  // Prepare constructor template
  v8::Local<v8::FunctionTemplate> ctor = Nan::New<v8::FunctionTemplate>(New);
  ctor->InstanceTemplate()->SetInternalFieldCount(2);
  ctor->SetClassName(Nan::New("Event").ToLocalChecked());

  // Statics
  Nan::SetMethod(ctor, "startTrace", Event::startTrace);

  // Prototype
  Nan::SetPrototypeMethod(ctor, "addInfo", Event::addInfo);
  Nan::SetPrototypeMethod(ctor, "addEdge", Event::addEdge);
  Nan::SetPrototypeMethod(ctor, "getMetadata", Event::getMetadata);
  Nan::SetPrototypeMethod(ctor, "toString", Event::toString);

  constructor.Reset(ctor->GetFunction());
  Nan::Set(exports, Nan::New("Event").ToLocalChecked(), ctor->GetFunction());
}
<|endoftext|>


<commit_before>#include "file.hpp"

#include <cstring>

namespace CaDiCaL {

static bool has_suffix (const char * str, const char * suffix) {
  int k = strlen (str), l = strlen (suffix);
  return k > l && !strcmp (str + k - l, suffix);
}

static FILE *
open_pipe (const char * fmt, const char * path, const char * mode) {
  char * cmd = new char [strlen (fmt) + strlen (path)];
  sprintf (cmd, fmt, path);
  FILE * res = popen (cmd, mode);
  delete [] cmd;
  return res;
}

static FILE * read_pipe (const char * fmt, const char * path) {
  return open_pipe (fmt, path, "r");
}

static FILE * write_pipe (const char * fmt, const char * path) {
  return open_pipe (fmt, path, "w");
}

File::File (bool w, int c, FILE * f, const char * n) :
#ifndef NDEBUG
  writing (w),
#endif
  close_file (c), file (f), _name (n), _lineno (1)
{
  assert (f), assert (n);
}

File * File::read (FILE * f, const char * n) {
  return new File (false, 0, f, n);
}

File * File::write (FILE * f, const char * n) {
  return new File (true, 0, f, n);
}

File * File::read (const char * path) {
  FILE * file;
  int close_input = 2;
  if (has_suffix (path, ".bz2"))
    file = read_pipe ("bzcat %s", path);
  else if (has_suffix (path, ".gz"))
    file = read_pipe ("gunzip -c %s", path);
  else if (has_suffix (path, ".7z"))
    file = read_pipe ("7z x -so %s 2>/dev/null", path);
  else
    file = fopen (path, "r"), close_input = 1;
  return file ? new File (false, close_input, file, path) : 0;
}

File * File::write (const char * path) {
  FILE * file = fopen (path, "w");
  int close_input = 2;
  if (has_suffix (path, ".bz2"))
    file = write_pipe ("bzip2 -c > %s", path);
  else if (has_suffix (path, ".gz"))
    file = write_pipe ("gzip -c > %s", path);
  else if (has_suffix (path, ".7z"))
    file = write_pipe ("7z a -an -txz -si -so > %s 2>/dev/null", path);
  else
    file = fopen (path, "w"), close_input = 1;
  return file ? new File (true, close_input, file, path) : 0;
}

File::~File () {
  if (close_file == 1) fclose (file);
  if (close_file == 2) pclose (file);
}

};
<commit_msg>support of xz files<commit_after>#include "file.hpp"

#include <cstring>

namespace CaDiCaL {

static bool has_suffix (const char * str, const char * suffix) {
  int k = strlen (str), l = strlen (suffix);
  return k > l && !strcmp (str + k - l, suffix);
}

static FILE *
open_pipe (const char * fmt, const char * path, const char * mode) {
  char * cmd = new char [strlen (fmt) + strlen (path)];
  sprintf (cmd, fmt, path);
  FILE * res = popen (cmd, mode);
  delete [] cmd;
  return res;
}

static FILE * read_pipe (const char * fmt, const char * path) {
  return open_pipe (fmt, path, "r");
}

static FILE * write_pipe (const char * fmt, const char * path) {
  return open_pipe (fmt, path, "w");
}

File::File (bool w, int c, FILE * f, const char * n) :
#ifndef NDEBUG
  writing (w),
#endif
  close_file (c), file (f), _name (n), _lineno (1)
{
  assert (f), assert (n);
}

File * File::read (FILE * f, const char * n) {
  return new File (false, 0, f, n);
}

File * File::write (FILE * f, const char * n) {
  return new File (true, 0, f, n);
}

File * File::read (const char * path) {
  FILE * file;
  int close_input = 2;
  if (has_suffix (path, ".xz"))
    file = read_pipe ("xz -c -d %s", path);
  else if (has_suffix (path, ".bz2"))
    file = read_pipe ("bzcat %s", path);
  else if (has_suffix (path, ".gz"))
    file = read_pipe ("gunzip -c %s", path);
  else if (has_suffix (path, ".7z"))
    file = read_pipe ("7z x -so %s 2>/dev/null", path);
  else
    file = fopen (path, "r"), close_input = 1;
  return file ? new File (false, close_input, file, path) : 0;
}

File * File::write (const char * path) {
  FILE * file = fopen (path, "w");
  int close_input = 2;
  if (has_suffix (path, ".xz"))
    file = write_pipe ("xz -c -e > %s", path);
  else if (has_suffix (path, ".bz2"))
    file = write_pipe ("bzip2 -c > %s", path);
  else if (has_suffix (path, ".gz"))
    file = write_pipe ("gzip -c > %s", path);
  else if (has_suffix (path, ".7z"))
    file = write_pipe ("7z a -an -txz -si -so > %s 2>/dev/null", path);
  else
    file = fopen (path, "w"), close_input = 1;
  return file ? new File (true, close_input, file, path) : 0;
}

File::~File () {
  if (close_file == 1) fclose (file);
  if (close_file == 2) pclose (file);
}

};
<|endoftext|>


<commit_before>
#include "ufopaediacategory.h"
#include "framework/framework.h"

namespace OpenApoc {

UfopaediaCategory::UfopaediaCategory(Framework &fw, tinyxml2::XMLElement* Element) : Stage(fw)
{
	UString nodename;

	ViewingEntry = 0;

	if( Element->Attribute("id") != nullptr && UString(Element->Attribute("id")) != "" )
	{
		ID = Element->Attribute("id");
	}

	tinyxml2::XMLElement* node;
	for( node = Element->FirstChildElement(); node != nullptr; node = node->NextSiblingElement() )
	{
		nodename = node->Name();

		if( nodename == "backgroundimage" )
		{
			BackgroundImageFilename = node->GetText();
		}
		if( nodename == "title" )
		{
			Title = node->GetText();
		}
		if( nodename == "text_info" )
		{
			BodyInformation = node->GetText();
		}
		if( nodename == "entries" )
		{
			tinyxml2::XMLElement* node2;
			for( node2 = node->FirstChildElement(); node2 != nullptr; node2 = node2->NextSiblingElement() )
			{
				std::shared_ptr<UfopaediaEntry> newentry = std::make_shared<UfopaediaEntry>( node2 );
				Entries.push_back( newentry );
			}
		}
	}

	menuform = fw.gamecore->GetForm("FORM_UFOPAEDIA_BASE");

}

UfopaediaCategory::~UfopaediaCategory()
{
}

void UfopaediaCategory::Begin()
{
	Label* infolabel = ((Label*)menuform->FindControl("TEXT_INFO"));
	ListBox* entrylist = ((ListBox*)menuform->FindControl("LISTBOX_SHORTCUTS"));
	entrylist->Clear();
	entrylist->ItemHeight = infolabel->GetFont()->GetFontHeight() + 2;
	for( auto entry = Entries.begin(); entry != Entries.end(); entry++ )
	{
		std::shared_ptr<UfopaediaEntry> e = (std::shared_ptr<UfopaediaEntry>)*entry;
		TextButton* tb = new TextButton( fw, entrylist, fw.gamecore->GetString(e->Title), infolabel->GetFont() );
		tb->RenderStyle = TextButton::TextButtonRenderStyles::SolidButtonStyle;
		tb->TextHAlign = HorizontalAlignment::Left;
		tb->TextVAlign = VerticalAlignment::Centre;
		entrylist->AddItem( tb );
	}

	SetupForm();
}

void UfopaediaCategory::Pause()
{
}

void UfopaediaCategory::Resume()
{
}

void UfopaediaCategory::Finish()
{
	//ListBox* entrylist = ((ListBox*)menuform->FindControl("LISTBOX_SHORTCUTS"));
	//entrylist->Clear();
}

void UfopaediaCategory::EventOccurred(Event *e)
{
	menuform->EventOccured( e );
	fw.gamecore->MouseCursor->EventOccured( e );

	if( e->Type == EVENT_KEY_DOWN )
	{
		if( e->Data.Keyboard.KeyCode == ALLEGRO_KEY_ESCAPE )
		{
			stageCmd.cmd = StageCmd::Command::POP;
			return;
		}
	}

	if( e->Type == EVENT_FORM_INTERACTION && e->Data.Forms.EventFlag == FormEventType::ButtonClick )
	{
		if( e->Data.Forms.RaisedBy->Name == "BUTTON_QUIT" )
		{
			stageCmd.cmd = StageCmd::Command::POP;
			return;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_INFORMATION" )
		{
			menuform->FindControl("INFORMATION_PANEL")->Visible = !menuform->FindControl("INFORMATION_PANEL")->Visible;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_NEXT_SECTION" )
		{
			return;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_NEXT_TOPIC" )
		{
			if( ViewingEntry < Entries.size() )
			{
				SetTopic( ViewingEntry + 1 );
			}
			return;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_PREVIOUS_TOPIC" )
		{
			if( ViewingEntry > 0 )
			{
				SetTopic( ViewingEntry - 1 );
			}
			return;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_PREVIOUS_SECTION" )
		{
			return;
		}
		else
		{
			return;
		}
	}
}

void UfopaediaCategory::Update(StageCmd * const cmd)
{
	menuform->Update();
	*cmd = this->stageCmd;
	//Reset the command to default
	this->stageCmd = StageCmd();
}

void UfopaediaCategory::Render()
{
	fw.Stage_GetPrevious(this->shared_from_this())->Render();
	fw.renderer->drawFilledRect({0,0}, fw.Display_GetSize(), Colour{0,0,0,128});
	menuform->Render();
	fw.gamecore->MouseCursor->Render();
}

bool UfopaediaCategory::IsTransition()
{
	return false;
}

void UfopaediaCategory::SetTopic(int Index)
{
	ViewingEntry = Index;
	SetupForm();
}

void UfopaediaCategory::SetupForm()
{
	if( ViewingEntry == 0 )
	{
		((Graphic*)menuform->FindControl("BACKGROUND_PICTURE"))->SetImage( fw.data->load_image(BackgroundImageFilename) );
		Label* infolabel = ((Label*)menuform->FindControl("TEXT_INFO"));
		infolabel->SetText( fw.gamecore->GetString(BodyInformation) );
		infolabel = ((Label*)menuform->FindControl("TEXT_TITLE_DATA"));
		infolabel->SetText( fw.gamecore->GetString(Title).toUpper() );
	} else {
		std::shared_ptr<UfopaediaEntry> e = Entries.at( ViewingEntry - 1 );
		((Graphic*)menuform->FindControl("BACKGROUND_PICTURE"))->SetImage( fw.data->load_image( e->BackgroundImageFilename ) );
		Label* infolabel = ((Label*)menuform->FindControl("TEXT_INFO"));
		infolabel->SetText( fw.gamecore->GetString( e->BodyInformation ) );
		infolabel = ((Label*)menuform->FindControl("TEXT_TITLE_DATA"));
		infolabel->SetText( fw.gamecore->GetString( e->Title ).toUpper() );
	}
}

}; //namespace OpenApoc
<commit_msg>Fix list double-add<commit_after>
#include "ufopaediacategory.h"
#include "framework/framework.h"

namespace OpenApoc {

UfopaediaCategory::UfopaediaCategory(Framework &fw, tinyxml2::XMLElement* Element) : Stage(fw)
{
	UString nodename;

	ViewingEntry = 0;

	if( Element->Attribute("id") != nullptr && UString(Element->Attribute("id")) != "" )
	{
		ID = Element->Attribute("id");
	}

	tinyxml2::XMLElement* node;
	for( node = Element->FirstChildElement(); node != nullptr; node = node->NextSiblingElement() )
	{
		nodename = node->Name();

		if( nodename == "backgroundimage" )
		{
			BackgroundImageFilename = node->GetText();
		}
		if( nodename == "title" )
		{
			Title = node->GetText();
		}
		if( nodename == "text_info" )
		{
			BodyInformation = node->GetText();
		}
		if( nodename == "entries" )
		{
			tinyxml2::XMLElement* node2;
			for( node2 = node->FirstChildElement(); node2 != nullptr; node2 = node2->NextSiblingElement() )
			{
				std::shared_ptr<UfopaediaEntry> newentry = std::make_shared<UfopaediaEntry>( node2 );
				Entries.push_back( newentry );
			}
		}
	}

	menuform = fw.gamecore->GetForm("FORM_UFOPAEDIA_BASE");

}

UfopaediaCategory::~UfopaediaCategory()
{
}

void UfopaediaCategory::Begin()
{
	Label* infolabel = ((Label*)menuform->FindControl("TEXT_INFO"));
	ListBox* entrylist = ((ListBox*)menuform->FindControl("LISTBOX_SHORTCUTS"));
	entrylist->Clear();
	entrylist->ItemHeight = infolabel->GetFont()->GetFontHeight() + 2;
	for( auto entry = Entries.begin(); entry != Entries.end(); entry++ )
	{
		std::shared_ptr<UfopaediaEntry> e = (std::shared_ptr<UfopaediaEntry>)*entry;
		TextButton* tb = new TextButton( fw, nullptr, fw.gamecore->GetString(e->Title), infolabel->GetFont() );
		tb->RenderStyle = TextButton::TextButtonRenderStyles::SolidButtonStyle;
		tb->TextHAlign = HorizontalAlignment::Left;
		tb->TextVAlign = VerticalAlignment::Centre;
		entrylist->AddItem( tb );
	}

	SetupForm();
}

void UfopaediaCategory::Pause()
{
}

void UfopaediaCategory::Resume()
{
}

void UfopaediaCategory::Finish()
{
	//ListBox* entrylist = ((ListBox*)menuform->FindControl("LISTBOX_SHORTCUTS"));
	//entrylist->Clear();
}

void UfopaediaCategory::EventOccurred(Event *e)
{
	menuform->EventOccured( e );
	fw.gamecore->MouseCursor->EventOccured( e );

	if( e->Type == EVENT_KEY_DOWN )
	{
		if( e->Data.Keyboard.KeyCode == ALLEGRO_KEY_ESCAPE )
		{
			stageCmd.cmd = StageCmd::Command::POP;
			return;
		}
	}

	if( e->Type == EVENT_FORM_INTERACTION && e->Data.Forms.EventFlag == FormEventType::ButtonClick )
	{
		if( e->Data.Forms.RaisedBy->Name == "BUTTON_QUIT" )
		{
			stageCmd.cmd = StageCmd::Command::POP;
			return;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_INFORMATION" )
		{
			menuform->FindControl("INFORMATION_PANEL")->Visible = !menuform->FindControl("INFORMATION_PANEL")->Visible;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_NEXT_SECTION" )
		{
			return;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_NEXT_TOPIC" )
		{
			if( ViewingEntry < Entries.size() )
			{
				SetTopic( ViewingEntry + 1 );
			}
			return;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_PREVIOUS_TOPIC" )
		{
			if( ViewingEntry > 0 )
			{
				SetTopic( ViewingEntry - 1 );
			}
			return;
		}
		else if( e->Data.Forms.RaisedBy->Name == "BUTTON_PREVIOUS_SECTION" )
		{
			return;
		}
		else
		{
			return;
		}
	}
}

void UfopaediaCategory::Update(StageCmd * const cmd)
{
	menuform->Update();
	*cmd = this->stageCmd;
	//Reset the command to default
	this->stageCmd = StageCmd();
}

void UfopaediaCategory::Render()
{
	fw.Stage_GetPrevious(this->shared_from_this())->Render();
	fw.renderer->drawFilledRect({0,0}, fw.Display_GetSize(), Colour{0,0,0,128});
	menuform->Render();
	fw.gamecore->MouseCursor->Render();
}

bool UfopaediaCategory::IsTransition()
{
	return false;
}

void UfopaediaCategory::SetTopic(int Index)
{
	ViewingEntry = Index;
	SetupForm();
}

void UfopaediaCategory::SetupForm()
{
	if( ViewingEntry == 0 )
	{
		((Graphic*)menuform->FindControl("BACKGROUND_PICTURE"))->SetImage( fw.data->load_image(BackgroundImageFilename) );
		Label* infolabel = ((Label*)menuform->FindControl("TEXT_INFO"));
		infolabel->SetText( fw.gamecore->GetString(BodyInformation) );
		infolabel = ((Label*)menuform->FindControl("TEXT_TITLE_DATA"));
		infolabel->SetText( fw.gamecore->GetString(Title).toUpper() );
	} else {
		std::shared_ptr<UfopaediaEntry> e = Entries.at( ViewingEntry - 1 );
		((Graphic*)menuform->FindControl("BACKGROUND_PICTURE"))->SetImage( fw.data->load_image( e->BackgroundImageFilename ) );
		Label* infolabel = ((Label*)menuform->FindControl("TEXT_INFO"));
		infolabel->SetText( fw.gamecore->GetString( e->BodyInformation ) );
		infolabel = ((Label*)menuform->FindControl("TEXT_TITLE_DATA"));
		infolabel->SetText( fw.gamecore->GetString( e->Title ).toUpper() );
	}
}

}; //namespace OpenApoc
<|endoftext|>


<commit_before>#include "DB.h"

#include <stdexcept>

#include <iostream>

namespace ygo
{

std::string operator_to_string(Operator op)
{
    switch (op)
    {
        case Operator::LT: return "<";
        case Operator::LTE: return "<=";
        case Operator::GT: return ">";
        case Operator::GTE: return ">=";
        case Operator::EQ: return "==";
        case Operator::NEQ: return "!=";
    }
}

std::string DBEsc(const std::string& s)
{
    char* query = sqlite3_mprintf("'%q'",s.c_str());
    auto ret = std::string(query);
    sqlite3_free(query);
    return ret;
}

std::string DBPair(const std::string& key, const std::string& value)
{
    return key + "= " + DBEsc(value);
}

std::string DBFuzzyPair(const std::string& key, const std::string& value)
{
    return key + " LIKE " + DBEsc(std::string("%") + value + "%");
}

std::string DBNull()
{
    return "NULL";
}

std::string DBTrue()
{
    return "1";
}

std::string DBFalse()
{
    return "0";
}

std::string DBAll()
{
    return "*";
}

std::string DBList(const std::vector<std::string>& list)
{
    std::string s;
    if (list.empty())
    {
        return s;
    }

    s += DBNull();
    for (auto&& l : list)
    {
        s += "," + DBEsc(l);
    }
    return s;
}

std::string DBKeyList(const std::vector<std::string>& list)
{
    std::string s;
    if (list.empty())
    {
        return s;
    }

    s += DBNull();
    for (auto&& l : list)
    {
        s += "," + l;
    }
    return s;
}

std::string DBUnique(const std::string& s)
{
    return std::string("DISTINCT ") + s;
}

std::string DBAnd(const std::vector<std::string>& list)
{
    if (list.empty())
    {
        return "1";
    }
    std::string where = "(";
    where += list[0];
    for (auto i = 1; i < list.size(); ++i)
    {
        where += " AND " + list[i];
    }
    where += ")";
    return where;
}

std::string DBOr(const std::vector<std::string>& list)
{
    if (list.empty())
    {
        return "1";
    }
    std::string where = "(";
    where += list[0];
    for (auto i = 1; i < list.size(); ++i)
    {
        where += " OR " + list[i];
    }
    where += ")";
    return where;
}

DB::DB(const char* name)
{
    if (sqlite3_open(name,&mDB))
    {
        throw std::runtime_error(std::string("Can't open database ") + name);
    }
}

DB::~DB()
{
    sqlite3_close(mDB);
}

void DB::select(const std::string& select, const std::string& from,
            const std::string& where, DataMapFn f)
{
    std::string sql("SELECT ");
    sql += select + " FROM " + from + " WHERE " + where;
    exec(sql,f);
}

std::string DB::insert(const std::string& insert, const std::string& values)
{
    std::string sql("INSERT INTO ");
    sql += insert + " VALUES(" + values + ")";
    exec(sql,[&](DB::DataMap){});
    return std::to_string(sqlite3_last_insert_rowid(mDB));
}

void DB::update(const std::string& update, const std::string& set,
        const std::string& where)
{
    std::string sql("UPDATE ");
    sql += update + " SET " + set + " WHERE " + where;
    exec(sql,[&](DB::DataMap){});
}

void DB::del(const std::string& del, const std::string& where)
{
    std::string sql("DELETE FROM ");
    sql += del + " WHERE " + where;
    exec(sql,[&](DB::DataMap){});
}

void DB::exec(const std::string& statement, DataMapFn f)
{
    sqlite3_stmt* s;
    if (sqlite3_prepare_v2(mDB,statement.c_str(),-1,&s,nullptr) == SQLITE_OK)
    {
        auto cols = sqlite3_column_count(s);
        while (true)
        {
            auto result = sqlite3_step(s);

            if (result == SQLITE_ROW)
            {
                DB::DataMap ret;
                for (auto i = 0; i < cols; ++i)
                {
                    auto* data =
                        reinterpret_cast<const char*>(sqlite3_column_text(s,i));
                    ret.insert({sqlite3_column_name(s,i),data ? data : "NULL"});
                }
                f(ret);
            }
            else
            {
                break;
            }
        }
    }
    else
    {
        throw std::runtime_error(sqlite3_errmsg(mDB));
    }
}

}
<commit_msg>Remove superfluous includes<commit_after>#include "DB.h"

#include <stdexcept>

namespace ygo
{

std::string operator_to_string(Operator op)
{
    switch (op)
    {
        case Operator::LT: return "<";
        case Operator::LTE: return "<=";
        case Operator::GT: return ">";
        case Operator::GTE: return ">=";
        case Operator::EQ: return "==";
        case Operator::NEQ: return "!=";
    }
}

std::string DBEsc(const std::string& s)
{
    char* query = sqlite3_mprintf("'%q'",s.c_str());
    auto ret = std::string(query);
    sqlite3_free(query);
    return ret;
}

std::string DBPair(const std::string& key, const std::string& value)
{
    return key + "= " + DBEsc(value);
}

std::string DBFuzzyPair(const std::string& key, const std::string& value)
{
    return key + " LIKE " + DBEsc(std::string("%") + value + "%");
}

std::string DBNull()
{
    return "NULL";
}

std::string DBTrue()
{
    return "1";
}

std::string DBFalse()
{
    return "0";
}

std::string DBAll()
{
    return "*";
}

std::string DBList(const std::vector<std::string>& list)
{
    std::string s;
    if (list.empty())
    {
        return s;
    }

    s += DBNull();
    for (auto&& l : list)
    {
        s += "," + DBEsc(l);
    }
    return s;
}

std::string DBKeyList(const std::vector<std::string>& list)
{
    std::string s;
    if (list.empty())
    {
        return s;
    }

    s += DBNull();
    for (auto&& l : list)
    {
        s += "," + l;
    }
    return s;
}

std::string DBUnique(const std::string& s)
{
    return std::string("DISTINCT ") + s;
}

std::string DBAnd(const std::vector<std::string>& list)
{
    if (list.empty())
    {
        return "1";
    }
    std::string where = "(";
    where += list[0];
    for (auto i = 1; i < list.size(); ++i)
    {
        where += " AND " + list[i];
    }
    where += ")";
    return where;
}

std::string DBOr(const std::vector<std::string>& list)
{
    if (list.empty())
    {
        return "1";
    }
    std::string where = "(";
    where += list[0];
    for (auto i = 1; i < list.size(); ++i)
    {
        where += " OR " + list[i];
    }
    where += ")";
    return where;
}

DB::DB(const char* name)
{
    if (sqlite3_open(name,&mDB))
    {
        throw std::runtime_error(std::string("Can't open database ") + name);
    }
}

DB::~DB()
{
    sqlite3_close(mDB);
}

void DB::select(const std::string& select, const std::string& from,
            const std::string& where, DataMapFn f)
{
    std::string sql("SELECT ");
    sql += select + " FROM " + from + " WHERE " + where;
    exec(sql,f);
}

std::string DB::insert(const std::string& insert, const std::string& values)
{
    std::string sql("INSERT INTO ");
    sql += insert + " VALUES(" + values + ")";
    exec(sql,[&](DB::DataMap){});
    return std::to_string(sqlite3_last_insert_rowid(mDB));
}

void DB::update(const std::string& update, const std::string& set,
        const std::string& where)
{
    std::string sql("UPDATE ");
    sql += update + " SET " + set + " WHERE " + where;
    exec(sql,[&](DB::DataMap){});
}

void DB::del(const std::string& del, const std::string& where)
{
    std::string sql("DELETE FROM ");
    sql += del + " WHERE " + where;
    exec(sql,[&](DB::DataMap){});
}

void DB::exec(const std::string& statement, DataMapFn f)
{
    sqlite3_stmt* s;
    if (sqlite3_prepare_v2(mDB,statement.c_str(),-1,&s,nullptr) == SQLITE_OK)
    {
        auto cols = sqlite3_column_count(s);
        while (true)
        {
            auto result = sqlite3_step(s);

            if (result == SQLITE_ROW)
            {
                DB::DataMap ret;
                for (auto i = 0; i < cols; ++i)
                {
                    auto* data =
                        reinterpret_cast<const char*>(sqlite3_column_text(s,i));
                    ret.insert({sqlite3_column_name(s,i),data ? data : "NULL"});
                }
                f(ret);
            }
            else
            {
                break;
            }
        }
    }
    else
    {
        throw std::runtime_error(sqlite3_errmsg(mDB));
    }
}

}
<|endoftext|>


<commit_before><commit_msg>removed accidentaly commited code<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkCornerPathEffect.h"
#include "SkPath.h"
#include "SkPoint.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius) {}
SkCornerPathEffect::~SkCornerPathEffect() {}

static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
                        SkPoint* step) {
    SkScalar dist = SkPoint::Distance(a, b);

    *step = b - a;
    if (dist <= radius * 2) {
        *step *= SK_ScalarHalf;
        return false;
    } else {
        *step *= radius / dist;
        return true;
    }
}

bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
                                    SkStrokeRec*, const SkRect*) const {
    if (0 == fRadius) {
        return false;
    }

    SkPath::Iter    iter(src, false);
    SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
    SkPoint         pts[4];

    bool        closed;
    SkPoint     moveTo, lastCorner;
    SkVector    firstStep, step;
    bool        prevIsValid = true;

    // to avoid warnings
    step.set(0, 0);
    moveTo.set(0, 0);
    firstStep.set(0, 0);
    lastCorner.set(0, 0);

    for (;;) {
        switch (verb = iter.next(pts, false)) {
            case SkPath::kMove_Verb:
                    // close out the previous (open) contour
                if (SkPath::kLine_Verb == prevVerb) {
                    dst->lineTo(lastCorner);
                }
                closed = iter.isClosedContour();
                if (closed) {
                    moveTo = pts[0];
                    prevIsValid = false;
                } else {
                    dst->moveTo(pts[0]);
                    prevIsValid = true;
                }
                break;
            case SkPath::kLine_Verb: {
                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
                // prev corner
                if (!prevIsValid) {
                    dst->moveTo(moveTo + step);
                    prevIsValid = true;
                } else {
                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
                                pts[0].fY + step.fY);
                }
                if (drawSegment) {
                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
                }
                lastCorner = pts[1];
                prevIsValid = true;
                break;
            }
            case SkPath::kQuad_Verb:
                // TBD - just replicate the curve for now
                if (!prevIsValid) {
                    dst->moveTo(pts[0]);
                    prevIsValid = true;
                }
                dst->quadTo(pts[1], pts[2]);
                lastCorner = pts[2];
                firstStep.set(0, 0);
                break;
            case SkPath::kConic_Verb:
                // TBD - just replicate the curve for now
                if (!prevIsValid) {
                    dst->moveTo(pts[0]);
                    prevIsValid = true;
                }
                dst->conicTo(pts[1], pts[2], iter.conicWeight());
                lastCorner = pts[2];
                firstStep.set(0, 0);
                break;
            case SkPath::kCubic_Verb:
                if (!prevIsValid) {
                    dst->moveTo(pts[0]);
                    prevIsValid = true;
                }
                // TBD - just replicate the curve for now
                dst->cubicTo(pts[1], pts[2], pts[3]);
                lastCorner = pts[3];
                firstStep.set(0, 0);
                break;
            case SkPath::kClose_Verb:
                if (firstStep.fX || firstStep.fY) {
                    dst->quadTo(lastCorner.fX, lastCorner.fY,
                                lastCorner.fX + firstStep.fX,
                                lastCorner.fY + firstStep.fY);
                    }
                dst->close();
                prevIsValid = false;
                break;
            case SkPath::kDone_Verb:
                if (prevIsValid) {
                    dst->lineTo(lastCorner);
                }
                goto DONE;
        }

        if (SkPath::kMove_Verb == prevVerb) {
            firstStep = step;
        }
        prevVerb = verb;
    }
DONE:
    return true;
}

sk_sp<SkFlattenable> SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
    return SkCornerPathEffect::Make(buffer.readScalar());
}

void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
    buffer.writeScalar(fRadius);
}

#ifndef SK_IGNORE_TO_STRING
void SkCornerPathEffect::toString(SkString* str) const {
    str->appendf("SkCornerPathEffect: (");
    str->appendf("radius: %.2f", fRadius);
    str->appendf(")");
}
#endif
<commit_msg>detect bad radius in cornerpatheffect<commit_after>/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkCornerPathEffect.h"
#include "SkPath.h"
#include "SkPoint.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) {
    // check with ! to catch NaNs
    if (!(radius > 0)) {
        radius = 0;
    }
    fRadius = radius;
}
SkCornerPathEffect::~SkCornerPathEffect() {}

static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius,
                        SkPoint* step) {
    SkScalar dist = SkPoint::Distance(a, b);

    *step = b - a;
    if (dist <= radius * 2) {
        *step *= SK_ScalarHalf;
        return false;
    } else {
        *step *= radius / dist;
        return true;
    }
}

bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
                                    SkStrokeRec*, const SkRect*) const {
    if (fRadius <= 0) {
        return false;
    }

    SkPath::Iter    iter(src, false);
    SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
    SkPoint         pts[4];

    bool        closed;
    SkPoint     moveTo, lastCorner;
    SkVector    firstStep, step;
    bool        prevIsValid = true;

    // to avoid warnings
    step.set(0, 0);
    moveTo.set(0, 0);
    firstStep.set(0, 0);
    lastCorner.set(0, 0);

    for (;;) {
        switch (verb = iter.next(pts, false)) {
            case SkPath::kMove_Verb:
                    // close out the previous (open) contour
                if (SkPath::kLine_Verb == prevVerb) {
                    dst->lineTo(lastCorner);
                }
                closed = iter.isClosedContour();
                if (closed) {
                    moveTo = pts[0];
                    prevIsValid = false;
                } else {
                    dst->moveTo(pts[0]);
                    prevIsValid = true;
                }
                break;
            case SkPath::kLine_Verb: {
                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
                // prev corner
                if (!prevIsValid) {
                    dst->moveTo(moveTo + step);
                    prevIsValid = true;
                } else {
                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX,
                                pts[0].fY + step.fY);
                }
                if (drawSegment) {
                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
                }
                lastCorner = pts[1];
                prevIsValid = true;
                break;
            }
            case SkPath::kQuad_Verb:
                // TBD - just replicate the curve for now
                if (!prevIsValid) {
                    dst->moveTo(pts[0]);
                    prevIsValid = true;
                }
                dst->quadTo(pts[1], pts[2]);
                lastCorner = pts[2];
                firstStep.set(0, 0);
                break;
            case SkPath::kConic_Verb:
                // TBD - just replicate the curve for now
                if (!prevIsValid) {
                    dst->moveTo(pts[0]);
                    prevIsValid = true;
                }
                dst->conicTo(pts[1], pts[2], iter.conicWeight());
                lastCorner = pts[2];
                firstStep.set(0, 0);
                break;
            case SkPath::kCubic_Verb:
                if (!prevIsValid) {
                    dst->moveTo(pts[0]);
                    prevIsValid = true;
                }
                // TBD - just replicate the curve for now
                dst->cubicTo(pts[1], pts[2], pts[3]);
                lastCorner = pts[3];
                firstStep.set(0, 0);
                break;
            case SkPath::kClose_Verb:
                if (firstStep.fX || firstStep.fY) {
                    dst->quadTo(lastCorner.fX, lastCorner.fY,
                                lastCorner.fX + firstStep.fX,
                                lastCorner.fY + firstStep.fY);
                    }
                dst->close();
                prevIsValid = false;
                break;
            case SkPath::kDone_Verb:
                if (prevIsValid) {
                    dst->lineTo(lastCorner);
                }
                goto DONE;
        }

        if (SkPath::kMove_Verb == prevVerb) {
            firstStep = step;
        }
        prevVerb = verb;
    }
DONE:
    return true;
}

sk_sp<SkFlattenable> SkCornerPathEffect::CreateProc(SkReadBuffer& buffer) {
    return SkCornerPathEffect::Make(buffer.readScalar());
}

void SkCornerPathEffect::flatten(SkWriteBuffer& buffer) const {
    buffer.writeScalar(fRadius);
}

#ifndef SK_IGNORE_TO_STRING
void SkCornerPathEffect::toString(SkString* str) const {
    str->appendf("SkCornerPathEffect: (");
    str->appendf("radius: %.2f", fRadius);
    str->appendf(")");
}
#endif
<|endoftext|>


<commit_before>/**
 * @file game.cpp
 * @authors Gabriel Araújo de Souza e Mayra Dantas de Azevedo
 * @date 23 Abr 2017
 * @brief Arquivo com as impletações dos métodos do namespace Game.
 */

 #include "game.h"

 bool Game::validate ( std::string filename){
    std::string line = " ";
    std::ifstream file (filename);
    if (file.is_open()){
        int n = 0;
        while ( getline (file, line) ){
            if(n > 2 ) return false;
            n++;
        }

        if( n < 3) return false;
        file.close();

    }

    return true;

}

bool compare(const void * a, const void * b){
    int * x = (int *) a;
    int * y = (int *) b;

    return (*x <= *y);
}
<commit_msg>documentação finish<commit_after>/**
 * @file game.cpp
 * @authors Gabriel Araújo de Souza e Mayra Dantas de Azevedo
 * @date 23 Abr 2017
 * @brief Arquivo com as impletações dos métodos do namespace Game.
 */

 #include "game.h"

 //<! Valida arquivo
 bool Game::validate ( std::string filename){
    std::string line = " ";
    std::ifstream file (filename);
    if (file.is_open()){
        int n = 0;
        while ( getline (file, line) ){
            if(n > 2 ) return false;
            n++;
        }

        if( n < 3) return false;
        file.close();

    }

    return true;

}

//<! Função usada pela biblioteca graal
bool compare(const void * a, const void * b){
    int * x = (int *) a;
    int * y = (int *) b;

    return (*x <= *y);
}
<|endoftext|>


<commit_before>/* OpenGL implementation of Blek*/
#include "../includes/declarations.h"
#include "helpers.cpp"
#include "getresolution.cpp"
#include "display.cpp"
#include "collision.cpp"
#include "strings.cpp"
#include "genlevel.cpp"
#include "drawobjects.cpp"

//Main Function of the program.
int main( int argc, char ** argv)
{
    findresoulution();
    glutInit( &argc, argv);
    glutInitDisplayMode( GLUT_DOUBLE| GLUT_RGB);
    glutInitWindowPosition( 100, 100);
    glutInitWindowSize(WIDTH,HEIGHT);
    glutCreateWindow( "OpenBlek");
    glutFullScreen();
    init();
    glutDisplayFunc(myDisplay);
    glutMouseFunc(myMouseStat);
    glutPassiveMotionFunc(mouse_motion);
    glutMotionFunc(myPressedMove);
    glutTimerFunc(9,myTimer,0);
    glutKeyboardFunc(keyPressed);
    glutMainLoop();
    return 0;
}
<commit_msg>Fixed Typo<commit_after>/* OpenGL implementation of Blek*/
#include "../includes/declarations.h"
#include "helpers.cpp"
#include "getresolution.cpp"
#include "display.cpp"
#include "collision.cpp"
#include "strings.cpp"
#include "genlevel.cpp"
#include "drawobjects.cpp"

//Main Function of the program.
int main( int argc, char ** argv)
{
    findresolution();
    glutInit( &argc, argv);
    glutInitDisplayMode( GLUT_DOUBLE| GLUT_RGB);
    glutInitWindowPosition( 100, 100);
    glutInitWindowSize(WIDTH,HEIGHT);
    glutCreateWindow( "OpenBlek");
    glutFullScreen();
    init();
    glutDisplayFunc(myDisplay);
    glutMouseFunc(myMouseStat);
    glutPassiveMotionFunc(mouse_motion);
    glutMotionFunc(myPressedMove);
    glutTimerFunc(9,myTimer,0);
    glutKeyboardFunc(keyPressed);
    glutMainLoop();
    return 0;
}
<|endoftext|>