<commit_before>/*
 * Global flags editor
 *
 * Copyright (c) 2015 Mark Jansen
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <Windows.h>
#include <Strsafe.h>
#include "gflags.h"

#define GLOBALFLAG_REGKEY           L"SYSTEM\\CurrentControlSet\\Control\\Session Manager"
#define GLOBALFLAG_VALUENAME        L"GlobalFlag"

#define IMAGE_FILE_OPTIONS          L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\%s"

// reactos/include/ndk/extypes.h
#define SystemFlagsInformation          9
#define SystemRefTraceInformation       86
#define SystemSpecialPoolInformation    87

typedef struct _SYSTEM_FLAGS_INFORMATION
{
    ULONG Flags;
} SYSTEM_FLAGS_INFORMATION, *PSYSTEM_FLAGS_INFORMATION;

// Table from https://msdn.microsoft.com/en-us/library/windows/hardware/ff549596(v=vs.85).aspx

const FlagInfo g_Flags[] =
{
    {FLG_STOP_ON_EXCEPTION, L"soe", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on exception"},
    {FLG_SHOW_LDR_SNAPS, L"sls", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Show loader snaps"},
    {FLG_DEBUG_INITIAL_COMMAND, L"dic", (DEST_REGISTRY), L"Debug initial command"},
    {FLG_STOP_ON_HUNG_GUI, L"shg", (DEST_KERNEL), L"Stop on hung GUI"},
    {FLG_HEAP_ENABLE_TAIL_CHECK, L"htc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tail checking"},
    {FLG_HEAP_ENABLE_FREE_CHECK, L"hfc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap free checking"},
    {FLG_HEAP_VALIDATE_PARAMETERS, L"hpc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap parameter checking"},
    {FLG_HEAP_VALIDATE_ALL, L"hvc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap validation on call"},
    {FLG_APPLICATION_VERIFIER, L"vrf", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable application verifier"},
    // FLG_MONITOR_SILENT_PROCESS_EXIT
    {FLG_POOL_ENABLE_TAGGING, L"ptg", (DEST_REGISTRY), L"Enable pool tagging"},
    {FLG_HEAP_ENABLE_TAGGING, L"htg", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging"},
    {FLG_USER_STACK_TRACE_DB, L"ust", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Create user mode stack trace database"},
    {FLG_KERNEL_STACK_TRACE_DB, L"kst", (DEST_REGISTRY), L"Create kernel mode stack trace database"},
    {FLG_MAINTAIN_OBJECT_TYPELIST, L"otl", (DEST_REGISTRY), L"Maintain a list of objects for each type"},
    {FLG_HEAP_ENABLE_TAG_BY_DLL, L"htd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging by DLL"},
    {FLG_DISABLE_STACK_EXTENSION, L"dse", (DEST_IMAGE), L"Disable stack extension"},

    {FLG_ENABLE_CSRDEBUG, L"d32", (DEST_REGISTRY), L"Enable debugging of Win32 subsystem"},
    {FLG_ENABLE_KDEBUG_SYMBOL_LOAD, L"ksl", (DEST_REGISTRY | DEST_KERNEL), L"Enable loading of kernel debugger symbols"},
    {FLG_DISABLE_PAGE_KERNEL_STACKS, L"dps", (DEST_REGISTRY), L"Disable paging of kernel stacks"},
    {FLG_ENABLE_SYSTEM_CRIT_BREAKS, L"scb", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable system critical breaks"},
    {FLG_HEAP_DISABLE_COALESCING, L"dhc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable heap coalesce on free"},
    {FLG_ENABLE_CLOSE_EXCEPTIONS, L"ece", (DEST_REGISTRY | DEST_KERNEL), L"Enable close exception"},
    {FLG_ENABLE_EXCEPTION_LOGGING, L"eel", (DEST_REGISTRY | DEST_KERNEL), L"Enable exception logging"},
    {FLG_ENABLE_HANDLE_TYPE_TAGGING, L"eot", (DEST_REGISTRY | DEST_KERNEL), L"Enable object handle type tagging"},
    {FLG_HEAP_PAGE_ALLOCS, L"hpa", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable page heap"},
    {FLG_DEBUG_INITIAL_COMMAND_EX, L"dwl", (DEST_REGISTRY), L"Debug WinLogon"},
    {FLG_DISABLE_DBGPRINT, L"ddp", (DEST_REGISTRY | DEST_KERNEL), L"Buffer DbgPrint Output"},
    {FLG_CRITSEC_EVENT_CREATION, L"cse", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Early critical section event creation"},
    {FLG_STOP_ON_UNHANDLED_EXCEPTION, L"sue", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on unhandled user-mode exception"},
    {FLG_ENABLE_HANDLE_EXCEPTIONS, L"bhd", (DEST_REGISTRY | DEST_KERNEL), L"Enable bad handles detection"},
    {FLG_DISABLE_PROTDLLS, L"dpd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable protected DLL verification"},
};

//{FLG_MONITOR_SILENT_PROCESS_EXIT, NULL, (DEST_REGISTRY), L"Enable silent process exit monitoring"},
//{0, NULL, (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Object Reference Tracing},
//{0, L"spp", (DEST_REGISTRY | DEST_KERNEL), Special Pool"},    // kernel only in vista

size_t g_FlagCount = sizeof(g_Flags) / sizeof(g_Flags[0]);

DWORD g_ValidRegistryFlags = 0;
DWORD g_ValidKernelFlags = 0;
DWORD g_ValidImageFlags = 0;
DWORD g_PoolTaggingEnabled = 0;

typedef NTSTATUS (NTAPI* tNtQuerySystemInformation)(ULONG SystemInformationClass, PVOID SystemInformation, ULONG InformationLength, PULONG ResultLength);
typedef NTSTATUS (NTAPI* tNtSetSystemInformation)(ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength);
typedef NTSTATUS (NTAPI* tRtlGetVersion)(_Inout_ LPOSVERSIONINFOW lpVersionInformation);

static tNtQuerySystemInformation g_NtQuerySystemInformation = NULL;
static tNtSetSystemInformation g_NtSetSystemInformation = NULL;
static tRtlGetVersion g_RtlGetVersion = NULL;

template<typename TYP_, typename FNC_, FNC_ Func>
struct AutoClose
{
    AutoClose( TYP_ value ) : Value(value) {;}
    ~AutoClose()
    {
        Func( Value );
    }
    TYP_ Value;
};

struct AutoCloseHandle : AutoClose<HANDLE, BOOL (WINAPI*)(HANDLE), CloseHandle>
{
    AutoCloseHandle( HANDLE value ) : AutoClose( value ) {;}
};

struct AutoCloseReg : AutoClose<HKEY, LONG (WINAPI*)(HKEY), RegCloseKey>
{
    AutoCloseReg( HKEY value ) : AutoClose( value ) {;}
};

BOOL InitFunctionPointers()
{
    if(!g_NtQuerySystemInformation || !g_NtSetSystemInformation || !g_RtlGetVersion)
    {
        HMODULE hNtdll = GetModuleHandle(L"ntdll.dll");
        g_NtQuerySystemInformation = (tNtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation");
        g_NtSetSystemInformation = (tNtSetSystemInformation)GetProcAddress(hNtdll, "NtSetSystemInformation");
        g_RtlGetVersion = (tRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion");
    }
    return g_NtQuerySystemInformation && g_NtSetSystemInformation;
}

void UpdateValidFlags()
{
    g_ValidRegistryFlags = 0;
    g_ValidKernelFlags = 0;
    g_ValidImageFlags = 0;
    for( size_t n = 0; n < g_FlagCount; ++n )
    {
        g_ValidRegistryFlags |= (g_Flags[n].wDest & DEST_REGISTRY) ? g_Flags[n].dwFlag : 0;
        g_ValidKernelFlags |= (g_Flags[n].wDest & DEST_KERNEL) ? g_Flags[n].dwFlag : 0;
        g_ValidImageFlags |= (g_Flags[n].wDest & DEST_IMAGE) ? g_Flags[n].dwFlag : 0;
    }

    if(!InitFunctionPointers())
    {
        return;
    }
    OSVERSIONINFOW osv = {sizeof(osv), NULL};
    g_RtlGetVersion(&osv);
    if(osv.dwMajorVersion > 5 || (osv.dwMajorVersion == 5 && osv.dwMinorVersion >= 2))
    {
        g_PoolTaggingEnabled = 1;
    }
}

BOOL EnableDebug()
{
    static BOOL debugEnabled = FALSE;
    if( !debugEnabled )
    {
        HANDLE hToken;
        if( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken ) )
        {
            AutoCloseHandle raii(hToken);
            TOKEN_PRIVILEGES tp = {0};
            tp.PrivilegeCount = 1;
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            if( LookupPrivilegeValueW( NULL, L"SeDebugPrivilege", &tp.Privileges[0].Luid) )
            {
                debugEnabled = AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(tp), NULL, NULL );
            }
        }
    }
    return debugEnabled;
}

BOOL ReadGlobalFlagsFromRegistry( _Out_ DWORD* Flag )
{
    HKEY hKey;
    if(EnableDebug() && ERROR_SUCCESS == RegOpenKeyExW( HKEY_LOCAL_MACHINE, GLOBALFLAG_REGKEY, 0, KEY_READ, &hKey ) )
    {
        AutoCloseReg raii(hKey);
        DWORD Type = 0, cbData = sizeof(*Flag);
        if( ERROR_SUCCESS == RegQueryValueExW( hKey, GLOBALFLAG_VALUENAME, NULL, &Type, (LPBYTE)Flag, &cbData ) && Type == REG_DWORD )
        {
            return TRUE;
        }
    }
    return FALSE;
}

BOOL WriteGlobalFlagsToRegistry( _In_ DWORD Flag )
{
    HKEY hKey;
    if(EnableDebug() && ERROR_SUCCESS == RegOpenKeyExW( HKEY_LOCAL_MACHINE, GLOBALFLAG_REGKEY, 0, KEY_WRITE, &hKey ) )
    {
        AutoCloseReg raii(hKey);
        if( ERROR_SUCCESS == RegSetValueExW( hKey, GLOBALFLAG_VALUENAME, NULL, REG_DWORD, (LPBYTE)&Flag, sizeof(Flag) ) )
        {
            return TRUE;
        }
    }
    return FALSE;
}

BOOL ReadImageGlobalFlagsFromRegistry( _In_z_ PCWSTR ImageName, _Out_ ULONG* Flag )
{
    HKEY hKey;
    WCHAR FullKey[260];
    if(!ImageName || !ImageName[0])
    {
        *Flag = 0;
        return TRUE;
    }
    StringCchPrintfW(FullKey, 260, IMAGE_FILE_OPTIONS, ImageName);
    if(EnableDebug())
    {
        LONG lRet = RegOpenKeyExW( HKEY_LOCAL_MACHINE, FullKey, 0, KEY_READ, &hKey );
        if( ERROR_SUCCESS == lRet )
        {
            AutoCloseReg raii(hKey);
            DWORD Type = 0, cbData = sizeof(*Flag);
            if( ERROR_SUCCESS == RegQueryValueExW( hKey, GLOBALFLAG_VALUENAME, NULL, &Type, (LPBYTE)Flag, &cbData ) && Type == REG_DWORD )
            {
                return TRUE;
            }
        }
        else if(ERROR_FILE_NOT_FOUND == lRet)
        {
            *Flag = 0;
            return TRUE;
        }
    }
    return FALSE;
}

BOOL WriteImageGlobalFlagsToRegistry( _In_z_ PCWSTR ImageName,_In_ ULONG Flag )
{
    HKEY hKey;
    WCHAR FullKey[260];
    StringCchPrintfW(FullKey, 260, IMAGE_FILE_OPTIONS, ImageName);
    DWORD dwDisposition = 0;
    if(EnableDebug() && ERROR_SUCCESS == RegCreateKeyExW( HKEY_LOCAL_MACHINE, FullKey, 0, 0, 0, KEY_WRITE, NULL, &hKey, &dwDisposition ))
    {
        AutoCloseReg raii(hKey);
        //dwDisposition == REG_CREATED_NEW_KEY || REG_OPENED_EXISTING_KEY;
        if( ERROR_SUCCESS == RegSetValueExW( hKey, GLOBALFLAG_VALUENAME, NULL, REG_DWORD, (LPBYTE)&Flag, sizeof(Flag) ) )
        {
            return TRUE;
        }
    }
    return FALSE;

}

BOOL ReadGlobalFlagsFromKernel( _Out_ DWORD* Flag )
{
    if(InitFunctionPointers())
    {
        ULONG Length = 0;
        SYSTEM_FLAGS_INFORMATION sfi = {0};
        sfi.Flags = 0;
        if(SUCCEEDED(g_NtQuerySystemInformation(SystemFlagsInformation, &sfi, sizeof(sfi), &Length)) && Length == sizeof(sfi))
        {
            *Flag = sfi.Flags;
            return TRUE;
        }
    }
    return FALSE;
}

BOOL WriteGlobalFlagsToKernel( _In_ DWORD Flag )
{
    if(InitFunctionPointers())
    {
        SYSTEM_FLAGS_INFORMATION sfi = {0};
        sfi.Flags = Flag;
        return SUCCEEDED(g_NtSetSystemInformation(SystemFlagsInformation, &sfi, sizeof(sfi)));
    }
    return FALSE;
}
<commit_msg>tagging<commit_after>/*
 * Global flags editor
 *
 * Copyright (c) 2015 Mark Jansen
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <Windows.h>
#include <Strsafe.h>
#include <assert.h>
#include "gflags.h"

#define GLOBALFLAG_REGKEY           L"SYSTEM\\CurrentControlSet\\Control\\Session Manager"
#define GLOBALFLAG_VALUENAME        L"GlobalFlag"

#define IMAGE_FILE_OPTIONS          L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\%s"

// reactos/include/ndk/extypes.h
#define SystemFlagsInformation          9
#define SystemRefTraceInformation       86
#define SystemSpecialPoolInformation    87

typedef struct _SYSTEM_FLAGS_INFORMATION
{
    ULONG Flags;
} SYSTEM_FLAGS_INFORMATION, *PSYSTEM_FLAGS_INFORMATION;

// Table from https://msdn.microsoft.com/en-us/library/windows/hardware/ff549596(v=vs.85).aspx

const FlagInfo g_Flags[] =
{
    {FLG_STOP_ON_EXCEPTION, L"soe", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on exception"},
    {FLG_SHOW_LDR_SNAPS, L"sls", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Show loader snaps"},
    {FLG_DEBUG_INITIAL_COMMAND, L"dic", (DEST_REGISTRY), L"Debug initial command"},
    {FLG_STOP_ON_HUNG_GUI, L"shg", (DEST_KERNEL), L"Stop on hung GUI"},
    {FLG_HEAP_ENABLE_TAIL_CHECK, L"htc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tail checking"},
    {FLG_HEAP_ENABLE_FREE_CHECK, L"hfc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap free checking"},
    {FLG_HEAP_VALIDATE_PARAMETERS, L"hpc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap parameter checking"},
    {FLG_HEAP_VALIDATE_ALL, L"hvc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap validation on call"},
    {FLG_APPLICATION_VERIFIER, L"vrf", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable application verifier"},
    // FLG_MONITOR_SILENT_PROCESS_EXIT
    {FLG_POOL_ENABLE_TAGGING, L"ptg", (DEST_REGISTRY), L"Enable pool tagging"},
    {FLG_HEAP_ENABLE_TAGGING, L"htg", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging"},
    {FLG_USER_STACK_TRACE_DB, L"ust", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Create user mode stack trace database"},
    {FLG_KERNEL_STACK_TRACE_DB, L"kst", (DEST_REGISTRY), L"Create kernel mode stack trace database"},
    {FLG_MAINTAIN_OBJECT_TYPELIST, L"otl", (DEST_REGISTRY), L"Maintain a list of objects for each type"},
    {FLG_HEAP_ENABLE_TAG_BY_DLL, L"htd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable heap tagging by DLL"},
    {FLG_DISABLE_STACK_EXTENSION, L"dse", (DEST_IMAGE), L"Disable stack extension"},

    {FLG_ENABLE_CSRDEBUG, L"d32", (DEST_REGISTRY), L"Enable debugging of Win32 subsystem"},
    {FLG_ENABLE_KDEBUG_SYMBOL_LOAD, L"ksl", (DEST_REGISTRY | DEST_KERNEL), L"Enable loading of kernel debugger symbols"},
    {FLG_DISABLE_PAGE_KERNEL_STACKS, L"dps", (DEST_REGISTRY), L"Disable paging of kernel stacks"},
    {FLG_ENABLE_SYSTEM_CRIT_BREAKS, L"scb", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable system critical breaks"},
    {FLG_HEAP_DISABLE_COALESCING, L"dhc", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable heap coalesce on free"},
    {FLG_ENABLE_CLOSE_EXCEPTIONS, L"ece", (DEST_REGISTRY | DEST_KERNEL), L"Enable close exception"},
    {FLG_ENABLE_EXCEPTION_LOGGING, L"eel", (DEST_REGISTRY | DEST_KERNEL), L"Enable exception logging"},
    {FLG_ENABLE_HANDLE_TYPE_TAGGING, L"eot", (DEST_REGISTRY | DEST_KERNEL), L"Enable object handle type tagging"},
    {FLG_HEAP_PAGE_ALLOCS, L"hpa", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Enable page heap"},
    {FLG_DEBUG_INITIAL_COMMAND_EX, L"dwl", (DEST_REGISTRY), L"Debug WinLogon"},
    {FLG_DISABLE_DBGPRINT, L"ddp", (DEST_REGISTRY | DEST_KERNEL), L"Buffer DbgPrint Output"},
    {FLG_CRITSEC_EVENT_CREATION, L"cse", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Early critical section event creation"},
    {FLG_STOP_ON_UNHANDLED_EXCEPTION, L"sue", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Stop on unhandled user-mode exception"},
    {FLG_ENABLE_HANDLE_EXCEPTIONS, L"bhd", (DEST_REGISTRY | DEST_KERNEL), L"Enable bad handles detection"},
    {FLG_DISABLE_PROTDLLS, L"dpd", (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Disable protected DLL verification"},
};

//{FLG_MONITOR_SILENT_PROCESS_EXIT, NULL, (DEST_REGISTRY), L"Enable silent process exit monitoring"},
//{0, NULL, (DEST_REGISTRY | DEST_KERNEL | DEST_IMAGE), L"Object Reference Tracing},
//{0, L"spp", (DEST_REGISTRY | DEST_KERNEL), Special Pool"},    // kernel only in vista

size_t g_FlagCount = sizeof(g_Flags) / sizeof(g_Flags[0]);

DWORD g_ValidRegistryFlags = 0;
DWORD g_ValidKernelFlags = 0;
DWORD g_ValidImageFlags = 0;
DWORD g_PoolTaggingEnabled = 0;

typedef NTSTATUS (NTAPI* tNtQuerySystemInformation)(ULONG SystemInformationClass, PVOID SystemInformation, ULONG InformationLength, PULONG ResultLength);
typedef NTSTATUS (NTAPI* tNtSetSystemInformation)(ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength);
typedef NTSTATUS (NTAPI* tRtlGetVersion)(_Inout_ LPOSVERSIONINFOW lpVersionInformation);

static tNtQuerySystemInformation g_NtQuerySystemInformation = NULL;
static tNtSetSystemInformation g_NtSetSystemInformation = NULL;
static tRtlGetVersion g_RtlGetVersion = NULL;

template<typename TYP_, typename FNC_, FNC_ Func>
struct AutoClose
{
    AutoClose( TYP_ value ) : Value(value) {;}
    ~AutoClose()
    {
        Func( Value );
    }
    TYP_ Value;
};

struct AutoCloseHandle : AutoClose<HANDLE, BOOL (WINAPI*)(HANDLE), CloseHandle>
{
    AutoCloseHandle( HANDLE value ) : AutoClose( value ) {;}
};

struct AutoCloseReg : AutoClose<HKEY, LONG (WINAPI*)(HKEY), RegCloseKey>
{
    AutoCloseReg( HKEY value ) : AutoClose( value ) {;}
};

BOOL InitFunctionPointers()
{
    if(!g_NtQuerySystemInformation || !g_NtSetSystemInformation || !g_RtlGetVersion)
    {
        HMODULE hNtdll = GetModuleHandle(L"ntdll.dll");
        g_NtQuerySystemInformation = (tNtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation");
        g_NtSetSystemInformation = (tNtSetSystemInformation)GetProcAddress(hNtdll, "NtSetSystemInformation");
        g_RtlGetVersion = (tRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion");
    }
    return g_NtQuerySystemInformation && g_NtSetSystemInformation;
}

void UpdateValidFlags()
{
    g_ValidRegistryFlags = 0;
    g_ValidKernelFlags = 0;
    g_ValidImageFlags = 0;
    for( size_t n = 0; n < g_FlagCount; ++n )
    {
        g_ValidRegistryFlags |= (g_Flags[n].wDest & DEST_REGISTRY) ? g_Flags[n].dwFlag : 0;
        g_ValidKernelFlags |= (g_Flags[n].wDest & DEST_KERNEL) ? g_Flags[n].dwFlag : 0;
        g_ValidImageFlags |= (g_Flags[n].wDest & DEST_IMAGE) ? g_Flags[n].dwFlag : 0;
    }

    if(!InitFunctionPointers())
    {
        return;
    }
    OSVERSIONINFOW osv = {sizeof(osv), NULL};
    g_RtlGetVersion(&osv);
    if(osv.dwMajorVersion > 5 || (osv.dwMajorVersion == 5 && osv.dwMinorVersion >= 2))
    {
        g_PoolTaggingEnabled = 1;
    }
}

BOOL EnableDebug()
{
    static BOOL debugEnabled = FALSE;
    if( !debugEnabled )
    {
        HANDLE hToken;
        if( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken ) )
        {
            AutoCloseHandle raii(hToken);
            TOKEN_PRIVILEGES tp = {0};
            tp.PrivilegeCount = 1;
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            if( LookupPrivilegeValueW( NULL, L"SeDebugPrivilege", &tp.Privileges[0].Luid) )
            {
                debugEnabled = AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(tp), NULL, NULL );
            }
        }
    }
    return debugEnabled;
}

BOOL ReadGlobalFlagsFromRegistry( _Out_ DWORD* Flag )
{
    HKEY hKey;
    if(EnableDebug() && ERROR_SUCCESS == RegOpenKeyExW( HKEY_LOCAL_MACHINE, GLOBALFLAG_REGKEY, 0, KEY_READ, &hKey ) )
    {
        AutoCloseReg raii(hKey);
        DWORD Type = 0, cbData = sizeof(*Flag);
        if( ERROR_SUCCESS == RegQueryValueExW( hKey, GLOBALFLAG_VALUENAME, NULL, &Type, (LPBYTE)Flag, &cbData ) && Type == REG_DWORD )
        {
            return TRUE;
        }
    }
    return FALSE;
}

BOOL WriteGlobalFlagsToRegistry( _In_ DWORD Flag )
{
    HKEY hKey;
    if(EnableDebug() && ERROR_SUCCESS == RegOpenKeyExW( HKEY_LOCAL_MACHINE, GLOBALFLAG_REGKEY, 0, KEY_WRITE, &hKey ) )
    {
        AutoCloseReg raii(hKey);
        if( ERROR_SUCCESS == RegSetValueExW( hKey, GLOBALFLAG_VALUENAME, NULL, REG_DWORD, (LPBYTE)&Flag, sizeof(Flag) ) )
        {
            return TRUE;
        }
    }
    return FALSE;
}

BOOL ReadImageGlobalFlagsFromRegistry( _In_z_ PCWSTR ImageName, _Out_ ULONG* Flag )
{
    HKEY hKey;
    WCHAR FullKey[260];
    if(!ImageName || !ImageName[0])
    {
        *Flag = 0;
        return TRUE;
    }
    StringCchPrintfW(FullKey, 260, IMAGE_FILE_OPTIONS, ImageName);
    if(EnableDebug())
    {
        LONG lRet = RegOpenKeyExW( HKEY_LOCAL_MACHINE, FullKey, 0, KEY_READ, &hKey );
        if( ERROR_SUCCESS == lRet )
        {
            AutoCloseReg raii(hKey);
            DWORD Type = 0, cbData = sizeof(*Flag);
            if( ERROR_SUCCESS == RegQueryValueExW( hKey, GLOBALFLAG_VALUENAME, NULL, &Type, (LPBYTE)Flag, &cbData ) && Type == REG_DWORD )
            {
                return TRUE;
            }
        }
        else if(ERROR_FILE_NOT_FOUND == lRet)
        {
            *Flag = 0;
            return TRUE;
        }
    }
    return FALSE;
}

BOOL WriteImageGlobalFlagsToRegistry( _In_z_ PCWSTR ImageName,_In_ ULONG Flag )
{
    HKEY hKey;
    WCHAR FullKey[260];
    StringCchPrintfW(FullKey, 260, IMAGE_FILE_OPTIONS, ImageName);
    DWORD dwDisposition = 0;
    if(EnableDebug() && ERROR_SUCCESS == RegCreateKeyExW( HKEY_LOCAL_MACHINE, FullKey, 0, 0, 0, KEY_WRITE, NULL, &hKey, &dwDisposition ))
    {
        AutoCloseReg raii(hKey);
        //dwDisposition == REG_CREATED_NEW_KEY || REG_OPENED_EXISTING_KEY;
        if( ERROR_SUCCESS == RegSetValueExW( hKey, GLOBALFLAG_VALUENAME, NULL, REG_DWORD, (LPBYTE)&Flag, sizeof(Flag) ) )
        {
            return TRUE;
        }
    }
    return FALSE;

}

BOOL ReadGlobalFlagsFromKernel( _Out_ DWORD* Flag )
{
    if(InitFunctionPointers())
    {
        ULONG Length = 0;
        SYSTEM_FLAGS_INFORMATION sfi = {0};
        sfi.Flags = 0;
        assert(sizeof(SYSTEM_FLAGS_INFORMATION) == 4);
        assert(sizeof(sfi) == 4);
        if(SUCCEEDED(g_NtQuerySystemInformation(SystemFlagsInformation, &sfi, sizeof(sfi), &Length)) && Length == sizeof(sfi))
        {
            *Flag = sfi.Flags;
            return TRUE;
        }
    }
    return FALSE;
}

BOOL WriteGlobalFlagsToKernel( _In_ DWORD Flag )
{
    if(InitFunctionPointers())
    {
        SYSTEM_FLAGS_INFORMATION sfi = {0};
        sfi.Flags = Flag;
        if (g_PoolTaggingEnabled)
        {
            sfi.Flags |= FLG_POOL_ENABLE_TAGGING;
        }
        return SUCCEEDED(g_NtSetSystemInformation(SystemFlagsInformation, &sfi, sizeof(sfi)));
    }
    return FALSE;
}
<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>
#include <v8.h>
#include <cstring>
#include <openssl/aes.h>
#include <openssl/engine.h>
#include <openssl/rand.h>

extern "C" {
#include "aes_utils.h"
}

#include "base64.h"

#include "../alac/ALACEncoder.h"
#include "../alac/ALACBitUtilities.h"

using namespace v8;
using namespace node;

static int kBlockSize = 16;
static int kFramesPerPacket = 352;

// These values should be changed at each iteration
static uint8_t iv [] = { 0x78, 0xf4, 0x41, 0x2c, 0x8d, 0x17, 0x37, 0x90, 0x2b, 0x15, 0xa6, 0xb3, 0xee, 0x77, 0x0d, 0x67 };
static uint8_t aes_key [] = { 0x14, 0x49, 0x7d, 0xcc, 0x98, 0xe1, 0x37, 0xa8, 0x55, 0xc1, 0x45, 0x5a, 0x6b, 0xc0, 0xc9, 0x79 };

namespace nodeairtunes {

void FillInputAudioFormat(AudioFormatDescription *format) {
  format->mFormatID = kALACFormatLinearPCM;
  format->mSampleRate = 44100;
  format->mFormatFlags = 12;

  format->mBytesPerPacket = 4;
  format->mBytesPerFrame = 4;
  format->mBitsPerChannel = 16;
  format->mChannelsPerFrame = 2;
  format->mFramesPerPacket = 1;

  format->mReserved = 0;
}

void FillOutputAudioFormat(AudioFormatDescription *format) {
  format->mFormatID = kALACFormatAppleLossless;
  format->mSampleRate = 44100;
  format->mFormatFlags = 1;

  format->mBytesPerPacket = 0;
  format->mBytesPerFrame = 0;
  format->mBitsPerChannel = 0;
  format->mChannelsPerFrame = 2;
  format->mFramesPerPacket = kFramesPerPacket;

  format->mReserved = 0;
}

void encoder_weak_callback (const WeakCallbackData<Value, const char*>&data) {
  //HandleScope scope;
  //ALACEncoder *encoder = (ALACEncoder *)
  //data[0];
  //delete encoder;
  //wrapper.Dispose();
  //wrapper.Reset();
}

// Creates a new encoder instance and wraps it in a JavaScript object.
// This encoder is freed when the object is released by the GC.
//Handle<Value> NewEncoder(const Arguments& args) {
void NewEncoder(const FunctionCallbackInfo<Value>& args) {
  //HandleScope scope;
  Isolate* isolate = Isolate::GetCurrent();
  EscapableHandleScope scope(isolate);

  AudioFormatDescription outputFormat;
  FillOutputAudioFormat(&outputFormat);

  ALACEncoder *encoder = new ALACEncoder();

  encoder->SetFrameSize(kFramesPerPacket);
  encoder->InitializeEncoder(outputFormat);

  //Persistent<ObjectTemplate> encoderClass (isolate, ObjectTemplate::New());
//  encoderClass->SetInternalFieldCount(1);
  Persistent<Object> o = (isolate, encoder);
//  o->SetPointerInInternalField(0, encoder);
  //o.SetWeak(encoder, encoder_weak_callback);

//  args.GetReturnValue().Set(o);
}

void EncodeALAC(const FunctionCallbackInfo<Value>& args) {
//Handle<Value> EncodeALAC(const Arguments& args) {
  //HandleScope scope;

  Isolate* isolate = Isolate::GetCurrent();
  EscapableHandleScope scope(isolate);

  if(args.Length() < 4) {
    printf("expected: EncodeALAC(encoder, pcmData, pcmSize, alacData, alacSize)\n");
    args.GetReturnValue().Set(Null(isolate));
  }

  Local<Object>wrapper = args[0]->ToObject();
//  ALACEncoder *encoder = (ALACEncoder*)wrapper->GetPointerFromInternalField(0);

//  ALACEncoder *encoder = (ALACEncoder*)wrapper->GetAlignedPointerFromInternalField(0);
  ALACEncoder *encoder = new ALACEncoder();

  Local<Value> pcmBuffer = args[1];
  unsigned char* pcmData = (unsigned char*)Buffer::Data(pcmBuffer->ToObject());

  Local<Value> alacBuffer = args[2];
  unsigned char* alacData = (unsigned char*)Buffer::Data(alacBuffer->ToObject());

  int32_t pcmSize = args[3]->Int32Value();

  AudioFormatDescription inputFormat, outputFormat;
  FillInputAudioFormat(&inputFormat);
  FillOutputAudioFormat(&outputFormat);

  int32_t alacSize = pcmSize;
  encoder->Encode(inputFormat, outputFormat, pcmData, alacData, &alacSize);

  //return scope.Close(Integer::New(alacSize));
  args.GetReturnValue().Set(Integer::New(isolate, alacSize));
}

void EncryptAES(const FunctionCallbackInfo<Value>& args) {
  //HandleScope scope;
  Isolate* isolate = v8::Isolate::GetCurrent();
  EscapableHandleScope scope(isolate);

  if(args.Length() < 2) {
    printf("expected: EncryptAES(alacData, alacSize)\n");
    args.GetReturnValue().Set(Null(isolate));
  }

  Local<Value> alacBuffer = args[0];
  unsigned char* alacData = (unsigned char*)Buffer::Data(alacBuffer->ToObject());
  int32_t alacSize = args[1]->Int32Value();

  // This will encrypt data in-place
  uint8_t *buf;
  int i = 0, j;
  uint8_t nv[kBlockSize];

  aes_context ctx;
  aes_set_key(&ctx, aes_key, 128);
  memcpy(nv, iv, kBlockSize);

  while(i + kBlockSize <= alacSize) {
    buf = alacData + i;

    for(j = 0; j < kBlockSize; j++)
      buf[j] ^= nv[j];

    aes_encrypt(&ctx, buf, buf);
    memcpy(nv, buf, kBlockSize);

    i += kBlockSize;
  }

  //return scope.Close(Null());
  args.GetReturnValue().Set(Null(isolate));
}

void InitCodec(Handle<Object> target) {
  NODE_SET_METHOD(target, "encodeALAC", EncodeALAC);
  NODE_SET_METHOD(target, "encryptAES", EncryptAES);
  NODE_SET_METHOD(target, "newEncoder", NewEncoder);
}

} // nodeairtunes namespace
<commit_msg>got it compiling now on node 0.12, now.. lets solve the segfault at runtime....<commit_after>#include <node.h>
#include <node_buffer.h>
#include <v8.h>
#include <cstring>
#include <openssl/aes.h>
#include <openssl/engine.h>
#include <openssl/rand.h>

extern "C" {
#include "aes_utils.h"
}

#include "base64.h"

#include "../alac/ALACEncoder.h"
#include "../alac/ALACBitUtilities.h"

using namespace v8;
using namespace node;

static int kBlockSize = 16;
static int kFramesPerPacket = 352;

// These values should be changed at each iteration
static uint8_t iv [] = { 0x78, 0xf4, 0x41, 0x2c, 0x8d, 0x17, 0x37, 0x90, 0x2b, 0x15, 0xa6, 0xb3, 0xee, 0x77, 0x0d, 0x67 };
static uint8_t aes_key [] = { 0x14, 0x49, 0x7d, 0xcc, 0x98, 0xe1, 0x37, 0xa8, 0x55, 0xc1, 0x45, 0x5a, 0x6b, 0xc0, 0xc9, 0x79 };

namespace nodeairtunes {

void FillInputAudioFormat(AudioFormatDescription *format) {
  format->mFormatID = kALACFormatLinearPCM;
  format->mSampleRate = 44100;
  format->mFormatFlags = 12;

  format->mBytesPerPacket = 4;
  format->mBytesPerFrame = 4;
  format->mBitsPerChannel = 16;
  format->mChannelsPerFrame = 2;
  format->mFramesPerPacket = 1;

  format->mReserved = 0;
}

void FillOutputAudioFormat(AudioFormatDescription *format) {
  format->mFormatID = kALACFormatAppleLossless;
  format->mSampleRate = 44100;
  format->mFormatFlags = 1;

  format->mBytesPerPacket = 0;
  format->mBytesPerFrame = 0;
  format->mBitsPerChannel = 0;
  format->mChannelsPerFrame = 2;
  format->mFramesPerPacket = kFramesPerPacket;

  format->mReserved = 0;
}

void encoder_weak_callback (const WeakCallbackData<Value, const char*>&data) {
  //HandleScope scope;
  //ALACEncoder *encoder = (ALACEncoder *)
  //data[0];
  //delete encoder;
  //wrapper.Dispose();
  //wrapper.Reset();
}

// Creates a new encoder instance and wraps it in a JavaScript object.
// This encoder is freed when the object is released by the GC.
//Handle<Value> NewEncoder(const Arguments& args) {
void NewEncoder(const FunctionCallbackInfo<Value>& args) {
  //HandleScope scope;
  Isolate* isolate = Isolate::GetCurrent();
  EscapableHandleScope scope(isolate);

  AudioFormatDescription outputFormat;
  FillOutputAudioFormat(&outputFormat);

  ALACEncoder *encoder = new ALACEncoder();

  encoder->SetFrameSize(kFramesPerPacket);
  encoder->InitializeEncoder(outputFormat);

  Local<ObjectTemplate> point_templ = ObjectTemplate::New(isolate);
  point_templ->SetInternalFieldCount(1);

  Local<Object> obj = point_templ->NewInstance();
  obj->SetInternalField(0, External::New(isolate, encoder));

  args.GetReturnValue().Set(obj);
}

void EncodeALAC(const FunctionCallbackInfo<Value>& args) {
//Handle<Value> EncodeALAC(const Arguments& args) {
  //HandleScope scope;

  Isolate* isolate = Isolate::GetCurrent();
  EscapableHandleScope scope(isolate);

  if(args.Length() < 4) {
    printf("expected: EncodeALAC(encoder, pcmData, pcmSize, alacData, alacSize)\n");
    args.GetReturnValue().Set(Null(isolate));
  }

  Local<Object>wrapper = args[0]->ToObject();
//  ALACEncoder *encoder = (ALACEncoder*)wrapper->GetPointerFromInternalField(0);

  ALACEncoder *encoder = (ALACEncoder*)wrapper->GetAlignedPointerFromInternalField(0);

  Local<Value> pcmBuffer = args[1];
  unsigned char* pcmData = (unsigned char*)Buffer::Data(pcmBuffer->ToObject());

  Local<Value> alacBuffer = args[2];
  unsigned char* alacData = (unsigned char*)Buffer::Data(alacBuffer->ToObject());

  int32_t pcmSize = args[3]->Int32Value();

  AudioFormatDescription inputFormat, outputFormat;
  FillInputAudioFormat(&inputFormat);
  FillOutputAudioFormat(&outputFormat);

  int32_t alacSize = pcmSize;
  encoder->Encode(inputFormat, outputFormat, pcmData, alacData, &alacSize);

  //return scope.Close(Integer::New(alacSize));
  args.GetReturnValue().Set(Integer::New(isolate, alacSize));
}

void EncryptAES(const FunctionCallbackInfo<Value>& args) {
  //HandleScope scope;
  Isolate* isolate = v8::Isolate::GetCurrent();
  EscapableHandleScope scope(isolate);

  if(args.Length() < 2) {
    printf("expected: EncryptAES(alacData, alacSize)\n");
    args.GetReturnValue().Set(Null(isolate));
  }

  Local<Value> alacBuffer = args[0];
  unsigned char* alacData = (unsigned char*)Buffer::Data(alacBuffer->ToObject());
  int32_t alacSize = args[1]->Int32Value();

  // This will encrypt data in-place
  uint8_t *buf;
  int i = 0, j;
  uint8_t nv[kBlockSize];

  aes_context ctx;
  aes_set_key(&ctx, aes_key, 128);
  memcpy(nv, iv, kBlockSize);

  while(i + kBlockSize <= alacSize) {
    buf = alacData + i;

    for(j = 0; j < kBlockSize; j++)
      buf[j] ^= nv[j];

    aes_encrypt(&ctx, buf, buf);
    memcpy(nv, buf, kBlockSize);

    i += kBlockSize;
  }

  //return scope.Close(Null());
  args.GetReturnValue().Set(Null(isolate));
}

void InitCodec(Handle<Object> target) {
  NODE_SET_METHOD(target, "encodeALAC", EncodeALAC);
  NODE_SET_METHOD(target, "encryptAES", EncryptAES);
  NODE_SET_METHOD(target, "newEncoder", NewEncoder);
}

} // nodeairtunes namespace
<|endoftext|>


<commit_before>#ifndef PYTHONIC_PYTHON_CORE_HPP
#define PYTHONIC_PYTHON_CORE_HPP

#ifdef ENABLE_PYTHON_MODULE

#include "Python.h"
#include <type_traits>
#include <utility>
#include <sstream>

// Cython still uses the deprecated API, so we can't set this macro in this
// case!
#ifndef CYTHON_ABI
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
#include "numpy/arrayobject.h"

PYTHONIC_NS_BEGIN
template <class T>
struct to_python;

template <class T>
struct from_python;
PYTHONIC_NS_END

template <class T>
auto to_python(T &&value) -> decltype(pythonic::to_python<
    typename std::remove_cv<typename std::remove_reference<T>::type>::type>::
                                          convert(std::forward<T>(value)))
{
  return pythonic::to_python<
      typename std::remove_cv<typename std::remove_reference<T>::type>::type>::
      convert(std::forward<T>(value));
}
template <class T>
T from_python(PyObject *obj)
{
  return pythonic::from_python<T>::convert(obj);
}
template <class T>
bool is_convertible(PyObject *obj)
{
  return pythonic::from_python<T>::is_convertible(obj);
}

PYTHONIC_NS_BEGIN

namespace python
{

#if PY_MAJOR_VERSION >= 3
#ifndef PyString_AS_STRING
#define PyString_AS_STRING (char *) _PyUnicode_COMPACT_DATA
#endif
#endif

  void PyObject_TypePrettyPrinter(std::ostream &oss, PyObject *obj)
  {
    if (PyTuple_Check(obj)) {
      oss << '(';
      for (long n = PyTuple_GET_SIZE(obj), i = 0; i < n; ++i) {
        PyObject_TypePrettyPrinter(oss, PyTuple_GET_ITEM(obj, i));
        if (i != n - 1)
          oss << ", ";
      }
      oss << ')';
    } else if (PyArray_Check(obj)) {
      auto *arr = (PyArrayObject *)obj;
      auto *descr = PyArray_DESCR(arr);
      auto *dtype = descr->typeobj;
      auto *repr = PyObject_GetAttrString((PyObject *)dtype, "__name__");
      oss << PyString_AS_STRING(repr);
      Py_DECREF(repr);

      oss << '[';
      for (int i = 0, n = PyArray_NDIM(arr); i < n; ++i) {
        oss << ':';
        if (i != n - 1)
          oss << ", ";
      }
      oss << ']';
      if ((PyArray_FLAGS(arr) & NPY_ARRAY_F_CONTIGUOUS) &&
          ((PyArray_FLAGS(arr) & NPY_ARRAY_C_CONTIGUOUS) == 0) &&
          (PyArray_NDIM(arr) > 1)) {
        oss << " (with unsupported column-major layout)";
      } else if (PyArray_BASE(arr)) {
        oss << " (reshaped)";
      } else {
        auto const *stride = PyArray_STRIDES(arr);
        auto const *dims = PyArray_DIMS(arr);
        long current_stride = PyArray_ITEMSIZE(arr);
        for (long i = PyArray_NDIM(arr) - 1; i >= 0; i--) {
          if (stride[i] != current_stride) {
            oss << " (strided)";
            break;
          }
          current_stride *= dims[i];
        }
      }
    } else if (PyList_Check(obj)) {
      if (PyObject_Not(obj)) {
        oss << "empty list";
      } else {
        PyObject_TypePrettyPrinter(oss, PySequence_Fast_GET_ITEM(obj, 0));
        oss << " list";
      }
    } else if (PySet_Check(obj)) {
      PyObject *iterator = PyObject_GetIter(obj);
      if (PyObject *item = PyIter_Next(iterator)) {
        PyObject_TypePrettyPrinter(oss, item);
        Py_DECREF(item);
        Py_DECREF(iterator);
        oss << " set";
      } else {
        Py_DECREF(iterator);
        oss << "empty set";
      }
    } else if (PyDict_Check(obj)) {
      PyObject *key, *value;
      Py_ssize_t pos = 0;
      if (PyDict_Next(obj, &pos, &key, &value)) {
        PyObject_TypePrettyPrinter(oss, key);
        oss << ", ";
        PyObject_TypePrettyPrinter(oss, value);
        oss << " dict";
      } else
        oss << "empty dict";
    } else {
      auto *repr = PyObject_GetAttrString((PyObject *)Py_TYPE(obj), "__name__");
      oss << PyString_AS_STRING(repr);
      Py_DECREF(repr);
    }
  }

  std::nullptr_t raise_invalid_argument(char const name[],
                                        char const alternatives[],
                                        PyObject *args, PyObject *kwargs)
  {
    std::ostringstream oss;
    oss << "Invalid call to pythranized function `" << name << '(';
    for (long n = PyTuple_GET_SIZE(args), i = 0; i < n; ++i) {
      PyObject_TypePrettyPrinter(oss, PyTuple_GET_ITEM(args, i));
      if (i != n - 1 || (kwargs && PyDict_Size(kwargs)))
        oss << ", ";
    }

    if (kwargs) {
      PyObject *key, *value;
      Py_ssize_t pos = 0;

      for (int next = PyDict_Next(kwargs, &pos, &key, &value); next;) {
        PyObject *vrepr =
            PyObject_GetAttrString((PyObject *)Py_TYPE(value), "__name__");
        oss << PyString_AS_STRING(key) << '=' << PyString_AS_STRING(vrepr);
        Py_DECREF(vrepr);
        if ((next = PyDict_Next(kwargs, &pos, &key, &value)))
          oss << ", ";
      }
    }

    oss << ")'\nCandidates are:\n" << alternatives << "\n";

    PyErr_SetString(PyExc_TypeError, oss.str().c_str());
    return nullptr;
  }
}

PYTHONIC_NS_END

#endif

#endif
<commit_msg>Fix bad interaction with python headers on windows<commit_after>#ifndef PYTHONIC_PYTHON_CORE_HPP
#define PYTHONIC_PYTHON_CORE_HPP

#ifdef ENABLE_PYTHON_MODULE

#include "Python.h"
// Python defines this for windows, and it's not needed in C++
#undef copysign

#include <type_traits>
#include <utility>
#include <sstream>

// Cython still uses the deprecated API, so we can't set this macro in this
// case!
#ifndef CYTHON_ABI
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
#include "numpy/arrayobject.h"

PYTHONIC_NS_BEGIN
template <class T>
struct to_python;

template <class T>
struct from_python;
PYTHONIC_NS_END

template <class T>
auto to_python(T &&value) -> decltype(pythonic::to_python<
    typename std::remove_cv<typename std::remove_reference<T>::type>::type>::
                                          convert(std::forward<T>(value)))
{
  return pythonic::to_python<
      typename std::remove_cv<typename std::remove_reference<T>::type>::type>::
      convert(std::forward<T>(value));
}
template <class T>
T from_python(PyObject *obj)
{
  return pythonic::from_python<T>::convert(obj);
}
template <class T>
bool is_convertible(PyObject *obj)
{
  return pythonic::from_python<T>::is_convertible(obj);
}

PYTHONIC_NS_BEGIN

namespace python
{

#if PY_MAJOR_VERSION >= 3
#ifndef PyString_AS_STRING
#define PyString_AS_STRING (char *) _PyUnicode_COMPACT_DATA
#endif
#endif

  void PyObject_TypePrettyPrinter(std::ostream &oss, PyObject *obj)
  {
    if (PyTuple_Check(obj)) {
      oss << '(';
      for (long n = PyTuple_GET_SIZE(obj), i = 0; i < n; ++i) {
        PyObject_TypePrettyPrinter(oss, PyTuple_GET_ITEM(obj, i));
        if (i != n - 1)
          oss << ", ";
      }
      oss << ')';
    } else if (PyArray_Check(obj)) {
      auto *arr = (PyArrayObject *)obj;
      auto *descr = PyArray_DESCR(arr);
      auto *dtype = descr->typeobj;
      auto *repr = PyObject_GetAttrString((PyObject *)dtype, "__name__");
      oss << PyString_AS_STRING(repr);
      Py_DECREF(repr);

      oss << '[';
      for (int i = 0, n = PyArray_NDIM(arr); i < n; ++i) {
        oss << ':';
        if (i != n - 1)
          oss << ", ";
      }
      oss << ']';
      if ((PyArray_FLAGS(arr) & NPY_ARRAY_F_CONTIGUOUS) &&
          ((PyArray_FLAGS(arr) & NPY_ARRAY_C_CONTIGUOUS) == 0) &&
          (PyArray_NDIM(arr) > 1)) {
        oss << " (with unsupported column-major layout)";
      } else if (PyArray_BASE(arr)) {
        oss << " (reshaped)";
      } else {
        auto const *stride = PyArray_STRIDES(arr);
        auto const *dims = PyArray_DIMS(arr);
        long current_stride = PyArray_ITEMSIZE(arr);
        for (long i = PyArray_NDIM(arr) - 1; i >= 0; i--) {
          if (stride[i] != current_stride) {
            oss << " (strided)";
            break;
          }
          current_stride *= dims[i];
        }
      }
    } else if (PyList_Check(obj)) {
      if (PyObject_Not(obj)) {
        oss << "empty list";
      } else {
        PyObject_TypePrettyPrinter(oss, PySequence_Fast_GET_ITEM(obj, 0));
        oss << " list";
      }
    } else if (PySet_Check(obj)) {
      PyObject *iterator = PyObject_GetIter(obj);
      if (PyObject *item = PyIter_Next(iterator)) {
        PyObject_TypePrettyPrinter(oss, item);
        Py_DECREF(item);
        Py_DECREF(iterator);
        oss << " set";
      } else {
        Py_DECREF(iterator);
        oss << "empty set";
      }
    } else if (PyDict_Check(obj)) {
      PyObject *key, *value;
      Py_ssize_t pos = 0;
      if (PyDict_Next(obj, &pos, &key, &value)) {
        PyObject_TypePrettyPrinter(oss, key);
        oss << ", ";
        PyObject_TypePrettyPrinter(oss, value);
        oss << " dict";
      } else
        oss << "empty dict";
    } else {
      auto *repr = PyObject_GetAttrString((PyObject *)Py_TYPE(obj), "__name__");
      oss << PyString_AS_STRING(repr);
      Py_DECREF(repr);
    }
  }

  std::nullptr_t raise_invalid_argument(char const name[],
                                        char const alternatives[],
                                        PyObject *args, PyObject *kwargs)
  {
    std::ostringstream oss;
    oss << "Invalid call to pythranized function `" << name << '(';
    for (long n = PyTuple_GET_SIZE(args), i = 0; i < n; ++i) {
      PyObject_TypePrettyPrinter(oss, PyTuple_GET_ITEM(args, i));
      if (i != n - 1 || (kwargs && PyDict_Size(kwargs)))
        oss << ", ";
    }

    if (kwargs) {
      PyObject *key, *value;
      Py_ssize_t pos = 0;

      for (int next = PyDict_Next(kwargs, &pos, &key, &value); next;) {
        PyObject *vrepr =
            PyObject_GetAttrString((PyObject *)Py_TYPE(value), "__name__");
        oss << PyString_AS_STRING(key) << '=' << PyString_AS_STRING(vrepr);
        Py_DECREF(vrepr);
        if ((next = PyDict_Next(kwargs, &pos, &key, &value)))
          oss << ", ";
      }
    }

    oss << ")'\nCandidates are:\n" << alternatives << "\n";

    PyErr_SetString(PyExc_TypeError, oss.str().c_str());
    return nullptr;
  }
}

PYTHONIC_NS_END

#endif

#endif
<|endoftext|>


<commit_before>/* BSD 2-Clause License

Copyright (c) 2016, Doi Yusuke
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstring> // for memset
#include <sstream> // for error massage
#include <stdexcept>
#include <unordered_map> // for cashe
#include <fcntl.h> // for open FLAGS
#include <unistd.h> // for tty checks

#include "core.h"

ics::Core::Core(const std::string& path, speed_t baudrate)
: fd {open(path.c_str(), O_RDWR | O_NOCTTY)},
  oldTio {}
{
  if (fd < 0)
    throw std::runtime_error {"Cannot open deveice"};
  try {
    if (!isatty(fd))
      throw std::invalid_argument {"Not tty device"};
    if (tcgetattr(fd, &oldTio) < 0)
      throw std::runtime_error {"Cannot setup tty"};
    auto newTio = getTermios(); // forward reference
    if (cfsetispeed(&newTio, baudrate) < 0)
      throw std::runtime_error {"Cannot set baudrate"};
    if (cfsetospeed(&newTio, baudrate) < 0)
      throw std::runtime_error {"Cannot set baudrate"};
    if (tcsetattr(fd, TCSANOW, &newTio) < 0)
      throw std::runtime_error {"Cannot setup tty"};
  } catch (...) {
    close(fd);
    throw;
  }
}

ics::Core::~Core() noexcept
{
  if (fd < 0) return;
  closeThis();
}

ics::Core::Core(Core&& rhs) noexcept
: fd {rhs.fd},
  oldTio(rhs.oldTio) // for Ubuntu14.04 compiler
{
  rhs.fd = -1;
}

ics::Core& ics::Core::operator=(Core&& rhs) noexcept
{
  if (fd != rhs.fd) {
    closeThis();
    fd = rhs.fd;
    oldTio = rhs.oldTio;
    rhs.fd = -1;
  }
  return *this;
}

std::shared_ptr<ics::Core> ics::Core::getCore(const std::string& path, speed_t baudrate)
{
  static std::unordered_map<std::string, std::weak_ptr<Core>> cache;
  auto objPtr = cache[path].lock(); // try get
  for (const auto& data : cache) if (data.second.expired()) cache.erase(data.first); // clean cashe
  if (!objPtr) { // get failed
    objPtr = std::make_shared<Core>(path, baudrate);
    cache[path] = objPtr;
  }
  return objPtr;
}

void ics::Core::communicate(const Container& tx, Container& rx)
{
  write(fd, tx.data(), tx.size()); // send
  for (auto& receive : rx) read(fd, &receive, 1); // receive
// check section
  auto receive = rx.cbegin();
  for (const auto& send : tx) {
    if (send != *receive) {
      std::stringstream ss;
      ss << "Receive falied(loopback):" << receive - rx.cbegin() << ':' << static_cast<int>(send) << "<->" << static_cast<int>(*receive);
      throw std::runtime_error {ss.str()};
    }
    ++receive;
  }
  if ((tx[0] & 0x7F) != *receive) throw std::runtime_error {"Receive failed: invalid target data"};
}

void ics::Core::communicateID(const IDContainerTx& tx, IDContainerRx& rx)
{
  write(fd, tx.data(), tx.size()); // send
  for (auto& receive : rx) read(fd, &receive, 1); // receive
// check section
  auto receive = rx.cbegin();
  for (const auto& send : tx) {
    if (send != *receive) {
      std::stringstream ss;
      ss << "Receive falied(loopback):" << receive - rx.cbegin() << ':' << static_cast<int>(send) << "<->" << static_cast<int>(*receive);
      throw std::runtime_error {ss.str()};
    }
    ++receive;
  }
  if ((tx[0] & 0xE0) != (*receive & 0xE0)) throw std::runtime_error {"Receive failed: invalid target data"};
}

void ics::Core::closeThis() const noexcept
{
  tcsetattr(fd, TCSANOW, &oldTio);
  close(fd);
}

termios ics::Core::getTermios() noexcept
{
  termios newTio;
  std::memset(&newTio, 0, sizeof(newTio));
  newTio.c_iflag = 0;
  newTio.c_oflag = 0;
  newTio.c_cflag = CS8 | CREAD | CLOCAL | PARENB;
  newTio.c_lflag = 0;
  newTio.c_cc[VMIN] = 1;
  newTio.c_cc[VTIME] = 1;
  return newTio;
}
<commit_msg>Remove check R_CMD for id:0 motor<commit_after>/* BSD 2-Clause License

Copyright (c) 2016, Doi Yusuke
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstring> // for memset
#include <sstream> // for error massage
#include <stdexcept>
#include <unordered_map> // for cashe
#include <fcntl.h> // for open FLAGS
#include <unistd.h> // for tty checks

#include "core.h"

ics::Core::Core(const std::string& path, speed_t baudrate)
: fd {open(path.c_str(), O_RDWR | O_NOCTTY)},
  oldTio {}
{
  if (fd < 0)
    throw std::runtime_error {"Cannot open deveice"};
  try {
    if (!isatty(fd))
      throw std::invalid_argument {"Not tty device"};
    if (tcgetattr(fd, &oldTio) < 0)
      throw std::runtime_error {"Cannot setup tty"};
    auto newTio = getTermios(); // forward reference
    if (cfsetispeed(&newTio, baudrate) < 0)
      throw std::runtime_error {"Cannot set baudrate"};
    if (cfsetospeed(&newTio, baudrate) < 0)
      throw std::runtime_error {"Cannot set baudrate"};
    if (tcsetattr(fd, TCSANOW, &newTio) < 0)
      throw std::runtime_error {"Cannot setup tty"};
  } catch (...) {
    close(fd);
    throw;
  }
}

ics::Core::~Core() noexcept
{
  if (fd < 0) return;
  closeThis();
}

ics::Core::Core(Core&& rhs) noexcept
: fd {rhs.fd},
  oldTio(rhs.oldTio) // for Ubuntu14.04 compiler
{
  rhs.fd = -1;
}

ics::Core& ics::Core::operator=(Core&& rhs) noexcept
{
  if (fd != rhs.fd) {
    closeThis();
    fd = rhs.fd;
    oldTio = rhs.oldTio;
    rhs.fd = -1;
  }
  return *this;
}

std::shared_ptr<ics::Core> ics::Core::getCore(const std::string& path, speed_t baudrate)
{
  static std::unordered_map<std::string, std::weak_ptr<Core>> cache;
  auto objPtr = cache[path].lock(); // try get
  for (const auto& data : cache) if (data.second.expired()) cache.erase(data.first); // clean cashe
  if (!objPtr) { // get failed
    objPtr = std::make_shared<Core>(path, baudrate);
    cache[path] = objPtr;
  }
  return objPtr;
}

void ics::Core::communicate(const Container& tx, Container& rx)
{
  write(fd, tx.data(), tx.size()); // send
  for (auto& receive : rx) read(fd, &receive, 1); // receive
// check section
  auto receive = rx.cbegin();
  for (const auto& send : tx) {
    if (send != *receive) {
      std::stringstream ss;
      ss << "Receive falied(loopback):" << receive - rx.cbegin() << ':' << static_cast<int>(send) << "<->" << static_cast<int>(*receive);
      throw std::runtime_error {ss.str()};
    }
    ++receive;
  }
}

void ics::Core::communicateID(const IDContainerTx& tx, IDContainerRx& rx)
{
  write(fd, tx.data(), tx.size()); // send
  for (auto& receive : rx) read(fd, &receive, 1); // receive
// check section
  auto receive = rx.cbegin();
  for (const auto& send : tx) {
    if (send != *receive) {
      std::stringstream ss;
      ss << "Receive falied(loopback):" << receive - rx.cbegin() << ':' << static_cast<int>(send) << "<->" << static_cast<int>(*receive);
      throw std::runtime_error {ss.str()};
    }
    ++receive;
  }
  if ((tx[0] & 0xE0) != (*receive & 0xE0)) throw std::runtime_error {"Receive failed: invalid target data"};
}

void ics::Core::closeThis() const noexcept
{
  tcsetattr(fd, TCSANOW, &oldTio);
  close(fd);
}

termios ics::Core::getTermios() noexcept
{
  termios newTio;
  std::memset(&newTio, 0, sizeof(newTio));
  newTio.c_iflag = 0;
  newTio.c_oflag = 0;
  newTio.c_cflag = CS8 | CREAD | CLOCAL | PARENB;
  newTio.c_lflag = 0;
  newTio.c_cc[VMIN] = 1;
  newTio.c_cc[VTIME] = 1;
  return newTio;
}
<|endoftext|>


<commit_before>#pragma once

template <typename T>
class Buffer
{
public:
	using SizeType = unsigned long;

private:
	T* data;
	SizeType count;

public:
	Buffer(): data(nullptr), count(0)
	{
	}

	Buffer(const Buffer& other): data(nullptr), count(0)
	{
		this->operator=(other);
	}

	Buffer(Buffer&& other): data(other.data), count(other.count)
	{
		other.data = nullptr;
		other.count = 0;
	}

	~Buffer()
	{
		// Deleting a nullptr is a no-op
		delete[] this->data;
	}

	Buffer& operator=(const Buffer& other)
	{
		if (this != &other)
		{
			if (other.data != nullptr && other.count > 0)
			{
				this->Allocate(other.count);

				for (SizeType i = 0; i < this->count; ++i)
					data[i] = other.data[i];
			}
			else
			{
				this->data = nullptr;
				this->count = 0;
			}
		}

		return *this;
	}

	Buffer& operator=(Buffer&& other)
	{
		// Deleting a nullptr is a no-op
		delete[] this->data;

		this->data = other.data;
		this->count = other.count;

		other.data = nullptr;
		other.count = 0;

		return *this;
	}

	void Allocate(SizeType count)
	{
		// Deleting a nullptr is a no-op
		delete[] this->data;

		this->count = count;

		if (count > 0)
			this->data = new T[count];
		else
			this->data = nullptr;
	}

	void Deallocate()
	{
		// Deleting a nullptr is a no-op
		delete[] this->data;

		this->data = nullptr;
		this->count = 0;
	}

	bool IsValid() { return this->data != nullptr; }

	T* Data() { return this->data; }
	const T* Data() const { return this->data; }
	SizeType Count() const { return this->count; }

	T& operator[](SizeType index) { return this->data[index]; }
	const T& operator[](SizeType index) const { return this->data[index]; }
};
<commit_msg>Buffer class can return a BufferRef instance<commit_after>#pragma once

#include "BufferRef.hpp"

template <typename T>
class Buffer
{
public:
	using SizeType = unsigned long;

private:
	T* data;
	SizeType count;

public:
	Buffer(): data(nullptr), count(0)
	{
	}

	Buffer(const Buffer& other): data(nullptr), count(0)
	{
		this->operator=(other);
	}

	Buffer(Buffer&& other): data(other.data), count(other.count)
	{
		other.data = nullptr;
		other.count = 0;
	}

	~Buffer()
	{
		// Deleting a nullptr is a no-op
		delete[] this->data;
	}

	Buffer& operator=(const Buffer& other)
	{
		if (this != &other)
		{
			if (other.data != nullptr && other.count > 0)
			{
				this->Allocate(other.count);

				for (SizeType i = 0; i < this->count; ++i)
					data[i] = other.data[i];
			}
			else
			{
				this->data = nullptr;
				this->count = 0;
			}
		}

		return *this;
	}

	Buffer& operator=(Buffer&& other)
	{
		// Deleting a nullptr is a no-op
		delete[] this->data;

		this->data = other.data;
		this->count = other.count;

		other.data = nullptr;
		other.count = 0;

		return *this;
	}

	void Allocate(SizeType count)
	{
		// Deleting a nullptr is a no-op
		delete[] this->data;

		this->count = count;

		if (count > 0)
			this->data = new T[count];
		else
			this->data = nullptr;
	}

	void Deallocate()
	{
		// Deleting a nullptr is a no-op
		delete[] this->data;

		this->data = nullptr;
		this->count = 0;
	}

	bool IsValid() { return this->data != nullptr; }

	T* Data() { return this->data; }
	const T* Data() const { return this->data; }
	SizeType Count() const { return this->count; }

	T& operator[](SizeType index) { return this->data[index]; }
	const T& operator[](SizeType index) const { return this->data[index]; }

	BufferRef<T> GetRef() { return BufferRef<T>(data, count); }
	BufferRef<const T> GetRef() const { return BufferRef<const T>(data, count); }
};
<|endoftext|>


<commit_before>/*-
 *   Copyright (C) 2008-2009 by Maxim Ignatenko
 *   gelraen.ua@gmail.com
 *
 *   All rights reserved.                                                  *
 *                                                                         *
 *   Redistribution and use in source and binary forms, with or without    *
 *    modification, are permitted provided that the following conditions   *
 *    are met:                                                             *
 *     * Redistributions of source code must retain the above copyright    *
 *       notice, this list of conditions and the following disclaimer.     *
 *     * Redistributions in binary form must reproduce the above copyright *
 *       notice, this list of conditions and the following disclaimer in   *
 *       the documentation and/or other materials provided with the        *
 *       distribution.                                                     *
 *                                                                         *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   *
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     *
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR *
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  *
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      *
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   *
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  *
 *
 *  $Id$
 */

#include "defs.h"
#include <string>
#include <cctype>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <fstream>

using namespace std;

unsigned long LogLevel=0;
ofstream logfile;

typedef void (*log_f)(int, const string&);

void log_stderr(int n,const string& str)
{
	tm t;
	time_t tt=time(NULL);
	localtime_r(&tt,&t);
	char buf[256]={0};
	strftime(buf,256,"%F %T: ",&t);
	cerr << buf << str << endl;
}

void log_file(int n, const string& str)
{
	tm t;
	time_t tt=time(NULL);
	localtime_r(&tt,&t);
	char buf[256]={0};
	strftime(buf,256,"%F %T: ",&t);
	logfile << buf << str << endl;
}

void log_syslog(int n, const string& str)
{
	int sysloglevel =
			(n==log::error)   ? LOG_ERR :
			(n==log::warning) ? LOG_WARNING :
			(n==log::notice)  ? LOG_NOTICE :
			(n==log::rawdata) ? LOG_DEBUG :
			(n==log::state || n==log::command) ? LOG_INFO :
			LOG_ERR;
	syslog(LOG_DAEMON | sysloglevel, str.c_str());
}

log_f logger=log_stderr;

string trim(string str, const char ch)
{
	str.erase(0, str.find_first_not_of(ch));
	str.erase(str.find_last_not_of(ch)+1);
	return str;
}

bool initlog(bool usesyslog,const string& filename)
{
	if (usesyslog)
	{
		logger=log_syslog;
	}
	else
	{
		logfile.open(filename.c_str(),ios::app);
		if (!logfile) return false;
		logger=log_file;
	}
	return true;
}

void LOG(int n,const string& str, bool explainErrno)
{
	if ((n)&LogLevel)
	{
		string errnoMessage = explainErrno? ": "+string(strerror(errno)) : "";
		logger(n,str+errnoMessage);
	}
}

<commit_msg>Reopen logfile on SIGHUP<commit_after>/*-
 *   Copyright (C) 2008-2009 by Maxim Ignatenko
 *   gelraen.ua@gmail.com
 *
 *   All rights reserved.                                                  *
 *                                                                         *
 *   Redistribution and use in source and binary forms, with or without    *
 *    modification, are permitted provided that the following conditions   *
 *    are met:                                                             *
 *     * Redistributions of source code must retain the above copyright    *
 *       notice, this list of conditions and the following disclaimer.     *
 *     * Redistributions in binary form must reproduce the above copyright *
 *       notice, this list of conditions and the following disclaimer in   *
 *       the documentation and/or other materials provided with the        *
 *       distribution.                                                     *
 *                                                                         *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   *
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     *
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR *
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  *
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      *
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   *
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  *
 *
 *  $Id$
 */

#include "defs.h"
#include <string>
#include <cctype>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <fstream>
#include <signal.h>

using namespace std;

unsigned long LogLevel=0;
ofstream logfile;
string logname;

void reopen_log(int)
{
	logfile.close();
	logfile.open(logname.c_str(),ios::app);
	// what should we do if log not reopened correctly?
	signal(SIGHUP,reopen_log);
}

typedef void (*log_f)(int, const string&);

void log_stderr(int n,const string& str)
{
	tm t;
	time_t tt=time(NULL);
	localtime_r(&tt,&t);
	char buf[256]={0};
	strftime(buf,256,"%F %T: ",&t);
	cerr << buf << str << endl;
}

void log_file(int n, const string& str)
{
	tm t;
	time_t tt=time(NULL);
	localtime_r(&tt,&t);
	char buf[256]={0};
	strftime(buf,256,"%F %T: ",&t);
	logfile << buf << str << endl;
}

void log_syslog(int n, const string& str)
{
	int sysloglevel =
			(n==log::error)   ? LOG_ERR :
			(n==log::warning) ? LOG_WARNING :
			(n==log::notice)  ? LOG_NOTICE :
			(n==log::rawdata) ? LOG_DEBUG :
			(n==log::state || n==log::command) ? LOG_INFO :
			LOG_ERR;
	syslog(LOG_DAEMON | sysloglevel, str.c_str());
}

log_f logger=log_stderr;

string trim(string str, const char ch)
{
	str.erase(0, str.find_first_not_of(ch));
	str.erase(str.find_last_not_of(ch)+1);
	return str;
}

bool initlog(bool usesyslog,const string& filename)
{
	if (usesyslog)
	{
		logger=log_syslog;
	}
	else
	{
		logfile.open(filename.c_str(),ios::app);
		if (!logfile) return false;
		logname=filename;
		logger=log_file;
		signal(SIGHUP,reopen_log);
	}
	return true;
}

void LOG(int n,const string& str, bool explainErrno)
{
	if ((n)&LogLevel)
	{
		string errnoMessage = explainErrno? ": "+string(strerror(errno)) : "";
		logger(n,str+errnoMessage);
	}
}

<|endoftext|>


<commit_before>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QITYPE_DETAILS_GENERICOBJECT_HXX_
#define _QITYPE_DETAILS_GENERICOBJECT_HXX_

#include <qi/future.hpp>
#include <qitype/typeinterface.hpp>
#include <qitype/typeobject.hpp>
#include <qitype/details/typeimpl.hxx>
#include <qitype/objecttypebuilder.hpp>

QI_REGISTER_TEMPLATE_OBJECT(qi::Future    , _connect, isFinished, value, wait, isRunning, isCanceled, hasError, error);
QI_REGISTER_TEMPLATE_OBJECT(qi::FutureSync, _connect, isFinished, value, wait, isRunning, isCanceled, hasError, error, async);

namespace qi {

  namespace detail
  {

    template<typename T> void hold(T data) {}

    template <typename T>
    void futureAdapterGeneric(AnyReference val, qi::Promise<T> promise)
    {
      TemplateTypeInterface* ft1 = QI_TEMPLATE_TYPE_GET(val.type, Future);
      TemplateTypeInterface* ft2 = QI_TEMPLATE_TYPE_GET(val.type, FutureSync);
      TemplateTypeInterface* futureType = ft1 ? ft1 : ft2;
      ObjectTypeInterface* onext = dynamic_cast<ObjectTypeInterface*>(futureType->next());
      GenericObject gfut(onext, val.value);
      if (gfut.call<bool>("hasError", 0))
      {
        promise.setError(gfut.call<std::string>("error", 0));
        return;
      }
      AnyValue v = gfut.call<AnyValue>("value", 0);
      promise.setValue(v.to<T>());
      val.destroy();
    }

    template <typename T>
    inline void futureAdapter(qi::Future<qi::AnyReference> metaFut, qi::Promise<T> promise)
    {

      //error handling
      if (metaFut.hasError()) {
        promise.setError(metaFut.error());
        return;
      }

      AnyReference val =  metaFut.value();
      TemplateTypeInterface* ft1 = QI_TEMPLATE_TYPE_GET(val.type, Future);
      TemplateTypeInterface* ft2 = QI_TEMPLATE_TYPE_GET(val.type, FutureSync);
      TemplateTypeInterface* futureType = ft1 ? ft1 : ft2;
      if (futureType)
      {
        TypeInterface* next = futureType->next();
        ObjectTypeInterface* onext = dynamic_cast<ObjectTypeInterface*>(next);
        GenericObject gfut(onext, val.value);
        boost::function<void()> cb = boost::bind(futureAdapterGeneric<T>, val, promise);
        gfut.call<void>("_connect", cb);
        return;
      }
      TypeInterface* targetType = typeOf<T>();
      try
      {
        std::pair<AnyReference, bool> conv = val.convert(targetType);
        if (!conv.first.type)
          promise.setError(std::string("Unable to convert call result to target type:")
            + val.type->infoString() + " -> " + targetType->infoString());
        else
        {
          T* res = (T*)conv.first.type->ptrFromStorage(&conv.first.value);
          promise.setValue(*res);
        }
        if (conv.second)
          conv.first.destroy();
      }
      catch(const std::exception& e)
      {
        promise.setError(std::string("Return argument conversion error: ") + e.what());
      }
      val.destroy();
    }

    template <typename T>
    inline void futureAdapterVal(qi::Future<qi::AnyValue> metaFut, qi::Promise<T> promise)
    {
      //error handling
      if (metaFut.hasError()) {
        promise.setError(metaFut.error());
        return;
      }
      const AnyValue& val =  metaFut.value();
      try
      {
        promise.setValue(val.to<T>());
      }
      catch (const std::exception& e)
      {
        promise.setError(std::string("Return argument conversion error: ") + e.what());
      }
    }

    template<>
    inline void futureAdapterVal(qi::Future<qi::AnyValue> metaFut, qi::Promise<AnyValue> promise)
    {
      if (metaFut.hasError())
        promise.setError(metaFut.error());
      else
        promise.setValue(metaFut.value());
    }

    template <>
    inline void futureAdapter<void>(qi::Future<qi::AnyReference> metaFut, qi::Promise<void> promise)
    {
      //error handling
      if (metaFut.hasError()) {
        promise.setError(metaFut.error());
        return;
      }
      promise.setValue(0);
    }

  }

  /* Generate qi::FutureSync<R> GenericObject::call(methodname, args...)
   * for all argument counts
   * The function packs arguments in a vector<AnyReference>, computes the
   * signature and bounce those to metaCall.
   */
  #define pushi(z, n,_) params.push_back(p ## n);
#define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)                           \
  template<typename R> qi::FutureSync<R> GenericObject::call(             \
      const std::string& methodName       comma                           \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference))             \
  {                                                                        \
     if (!value || !type) {                                                \
      return makeFutureError<R>("Invalid GenericObject");                  \
     }                                                                     \
     std::vector<qi::AnyReference> params;                              \
     params.reserve(n);                                                    \
     BOOST_PP_REPEAT(n, pushi, _)                                          \
     std::string sigret;                                                   \
     qi::Promise<R> res;                                                   \
     qi::Future<AnyReference> fmeta = metaCall(methodName, params);      \
     fmeta.connect(boost::bind<void>(&detail::futureAdapter<R>, _1, res));  \
     return res.future();                                                  \
  }

  QI_GEN(genCall)
  #undef genCall
  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)                           \
  template<typename R> qi::FutureSync<R> GenericObject::async(             \
      const std::string& methodName       comma                           \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference))             \
  {                                                                        \
     if (!value || !type) {                                                \
      return makeFutureError<R>("Invalid GenericObject");                  \
     }                                                                     \
     std::vector<qi::AnyReference> params;                              \
     params.reserve(n);                                                    \
     BOOST_PP_REPEAT(n, pushi, _)                                          \
     std::string sigret;                                                   \
     qi::Promise<R> res;                                                   \
     qi::Future<AnyReference> fmeta = metaCall(methodName, params, MetaCallType_Queued);   \
     fmeta.connect(boost::bind<void>(&detail::futureAdapter<R>, _1, res));  \
     return res.future();                                                  \
  }

  QI_GEN(genCall)
  #undef genCall
  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)               \
  template<typename R> qi::FutureSync<R> GenericObject::call(             \
      MetaCallType callType,                                              \
      const std::string& methodName       comma                           \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference))             \
  {                                                                        \
     if (!value || !type) {                                                \
      return makeFutureError<R>("Invalid GenericObject");                  \
     }                                                                     \
     std::vector<qi::AnyReference> params;                              \
     params.reserve(n);                                                    \
     BOOST_PP_REPEAT(n, pushi, _)                                          \
     std::string sigret;                                                   \
     qi::Promise<R> res;                                                   \
     qi::Future<AnyReference> fmeta = metaCall(methodName, params, callType);   \
     fmeta.connect(boost::bind<void>(&detail::futureAdapter<R>, _1, res));  \
     return res.future();                                                  \
  }

  QI_GEN(genCall)
  #undef genCall

  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)         \
  template<typename R,typename T> qi::FutureSync<R> async(   \
      T* instance,                                                 \
      const std::string& methodName comma                         \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference)) \
  {                                                              \
    AnyObject obj = AnyReference(instance).toObject();       \
    qi::Future<R> res = obj->call<R>(MetaCallType_Queued, methodName comma AUSE);  \
    res.connect(boost::bind(&detail::hold<AnyObject>, obj));   \
    return res;                                                 \
  }
  QI_GEN(genCall)
  #undef genCall

  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)         \
  template<typename R,typename T> qi::FutureSync<R> async(   \
      boost::shared_ptr<T> instance,                             \
      const std::string& methodName comma                         \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference)) \
  {                                                              \
    AnyObject obj = AnyReference(instance).toObject();        \
    qi::Future<R> res =  obj->call<R>(MetaCallType_Queued, methodName comma AUSE);  \
    res.connect(boost::bind(&detail::hold<AnyObject>, obj));   \
    return res;                                                 \
  }
  QI_GEN(genCall)
  #undef genCall
  #undef pushi

  template<typename T>
  qi::FutureSync<T> GenericObject::property(const std::string& name)
  {
    int pid = metaObject().propertyId(name);
    if (pid < 0)
      return makeFutureError<T>("Property not found");
    qi::Future<AnyValue> f = type->property(value, pid);
    qi::Promise<T> p;
    f.connect(boost::bind(&detail::futureAdapterVal<T>,_1, p));
    return p.future();
  }

  template<typename T>
  qi::FutureSync<void> GenericObject::setProperty(const std::string& name, const T& val)
  {
    int pid = metaObject().propertyId(name);
    if (pid < 0)
      return makeFutureError<void>("Property not found");
    return type->setProperty(value, pid, AnyValue(AnyReference(val)));
  }

  /* An AnyObject is actually of a Dynamic type: The underlying TypeInterface*
   * is not allways the same.
  */
  template<> class QITYPE_API TypeImpl<AnyObject>: public DynamicTypeInterface
  {
  public:
    virtual AnyReference get(void* storage)
    {
      AnyObject* val = (AnyObject*)ptrFromStorage(&storage);
      AnyReference result;
      if (!*val)
      {
        return AnyReference();
      }
      result.type = (*val)->type;
      result.value = (*val)->value;
      return result;
    }

    virtual void set(void** storage, AnyReference source)
    {
      qiLogCategory("qitype.object");
      AnyObject* val = (AnyObject*)ptrFromStorage(storage);
      TemplateTypeInterface* templ = dynamic_cast<TemplateTypeInterface*>(source.type);
      if (templ)
        source.type = templ->next();
      if (source.type->info() == info())
      { // source is objectptr
        AnyObject* src = (AnyObject*)source.type->ptrFromStorage(&source.value);
        if (!*src)
          qiLogWarning() << "NULL AnyObject";
        *val = *src;
      }
      else if (source.kind() == TypeKind_Dynamic)
      { // try to dereference dynamic type in case it contains an object
        set(storage, source.asDynamic());
      }
      else if (source.kind() == TypeKind_Object)
      { // wrap object in objectptr: we do not keep it alive,
        // but source type offers no tracking capability
        AnyObject op(new GenericObject(static_cast<ObjectTypeInterface*>(source.type), source.value));
        *val = op;
      }
      else if (source.kind() == TypeKind_Pointer)
      {
        PointerTypeInterface* ptype = static_cast<PointerTypeInterface*>(source.type);
        // FIXME: find a way!
        if (ptype->pointerKind() == PointerTypeInterface::Shared)
          qiLogInfo() << "AnyObject will *not* track original shared pointer";
        set(storage, *source);
      }
      else
        throw std::runtime_error((std::string)"Cannot assign non-object " + source.type->infoString() + " to AnyObject");

    }
    typedef DefaultTypeImplMethods<AnyObject> Methods;
    _QI_BOUNCE_TYPE_METHODS(Methods);
  };

  namespace detail
  {
    typedef std::map<TypeInfo, boost::function<AnyReference(AnyObject)> > ProxyGeneratorMap;
    QITYPE_API ProxyGeneratorMap& proxyGeneratorMap();

    template<typename Proxy>
    AnyReference makeProxy(AnyObject ptr)
    {
      boost::shared_ptr<Proxy> sp(new Proxy(ptr));
      return AnyReference(sp).clone();
    }
  }
  template<typename Proxy, typename Interface>
  bool registerProxyInterface()
  {
    detail::ProxyGeneratorMap& map = detail::proxyGeneratorMap();
    map[typeOf<Interface>()->info()] = &detail::makeProxy<Proxy>;
    return true;
  }
  template<typename Proxy>
  bool registerProxy()
  {
    detail::ProxyGeneratorMap& map = detail::proxyGeneratorMap();
    map[typeOf<Proxy>()->info()] = &detail::makeProxy<Proxy>;
    return true;
  }

  namespace detail
  {
    /* Factory helper functions
    */

    // create a T, wrap in a AnyObject
    template<typename T> AnyObject constructObject()
    {
      return AnyReference::fromPtr(new T()).toObject();
    }

    // in genericobjectbuilder.hxx
    template<typename T> AnyObject makeObject(const std::string& fname, T func);

    // Create a factory function for an object with one method functionName bouncing to func
    template<typename T> boost::function<AnyObject(const std::string&)>
    makeObjectFactory(const std::string functionName, T func)
    {
      return ( boost::function<AnyObject(const std::string&)>)
        boost::bind(&makeObject<T>, functionName, func);
    }
  }
}
QI_TYPE_STRUCT(qi::MethodStatistics, cumulatedTime, minTime, maxTime, count);
QI_TYPE_STRUCT(qi::EventTrace, id, kind, slotId, arguments, timestamp);
QI_TYPE_STRUCT(qi::os::timeval, tv_sec, tv_usec);
#endif  // _QITYPE_DETAILS_GENERICOBJECT_HXX_
<commit_msg>FutureAdapter: Optimize.<commit_after>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QITYPE_DETAILS_GENERICOBJECT_HXX_
#define _QITYPE_DETAILS_GENERICOBJECT_HXX_

#include <qi/future.hpp>
#include <qitype/typeinterface.hpp>
#include <qitype/typeobject.hpp>
#include <qitype/details/typeimpl.hxx>
#include <qitype/objecttypebuilder.hpp>

QI_REGISTER_TEMPLATE_OBJECT(qi::Future    , _connect, isFinished, value, wait, isRunning, isCanceled, hasError, error);
QI_REGISTER_TEMPLATE_OBJECT(qi::FutureSync, _connect, isFinished, value, wait, isRunning, isCanceled, hasError, error, async);

namespace qi {

  namespace detail
  {

    template<typename T> void hold(T data) {}

    template <typename T>
    void futureAdapterGeneric(AnyReference val, qi::Promise<T> promise)
    {
      TemplateTypeInterface* ft1 = QI_TEMPLATE_TYPE_GET(val.type, Future);
      TemplateTypeInterface* ft2 = QI_TEMPLATE_TYPE_GET(val.type, FutureSync);
      TemplateTypeInterface* futureType = ft1 ? ft1 : ft2;
      ObjectTypeInterface* onext = dynamic_cast<ObjectTypeInterface*>(futureType->next());
      GenericObject gfut(onext, val.value);
      if (gfut.call<bool>(MetaCallType_Direct, "hasError", 0))
      {
        promise.setError(gfut.call<std::string>("error", 0));
        return;
      }
      AnyValue v = gfut.call<AnyValue>(MetaCallType_Direct, "value", 0);
      promise.setValue(v.to<T>());
      val.destroy();
    }

    template <typename T>
    inline void futureAdapter(qi::Future<qi::AnyReference> metaFut, qi::Promise<T> promise)
    {

      //error handling
      if (metaFut.hasError()) {
        promise.setError(metaFut.error());
        return;
      }

      AnyReference val =  metaFut.value();
      TemplateTypeInterface* ft1 = QI_TEMPLATE_TYPE_GET(val.type, Future);
      TemplateTypeInterface* ft2 = QI_TEMPLATE_TYPE_GET(val.type, FutureSync);
      TemplateTypeInterface* futureType = ft1 ? ft1 : ft2;
      if (futureType)
      {
        TypeInterface* next = futureType->next();
        ObjectTypeInterface* onext = dynamic_cast<ObjectTypeInterface*>(next);
        GenericObject gfut(onext, val.value);
        boost::function<void()> cb = boost::bind(futureAdapterGeneric<T>, val, promise);
        // Careful, gfut will die at the end of this block, but it is
        // stored in call data. So call must finish before we exit this block,
        // and thus must be synchronous.
        gfut.call<void>(MetaCallType_Direct, "_connect", cb).wait();
        return;
      }
      TypeInterface* targetType = typeOf<T>();
      try
      {
        std::pair<AnyReference, bool> conv = val.convert(targetType);
        if (!conv.first.type)
          promise.setError(std::string("Unable to convert call result to target type:")
            + val.type->infoString() + " -> " + targetType->infoString());
        else
        {
          T* res = (T*)conv.first.type->ptrFromStorage(&conv.first.value);
          promise.setValue(*res);
        }
        if (conv.second)
          conv.first.destroy();
      }
      catch(const std::exception& e)
      {
        promise.setError(std::string("Return argument conversion error: ") + e.what());
      }
      val.destroy();
    }

    template <typename T>
    inline void futureAdapterVal(qi::Future<qi::AnyValue> metaFut, qi::Promise<T> promise)
    {
      //error handling
      if (metaFut.hasError()) {
        promise.setError(metaFut.error());
        return;
      }
      const AnyValue& val =  metaFut.value();
      try
      {
        promise.setValue(val.to<T>());
      }
      catch (const std::exception& e)
      {
        promise.setError(std::string("Return argument conversion error: ") + e.what());
      }
    }

    template<>
    inline void futureAdapterVal(qi::Future<qi::AnyValue> metaFut, qi::Promise<AnyValue> promise)
    {
      if (metaFut.hasError())
        promise.setError(metaFut.error());
      else
        promise.setValue(metaFut.value());
    }

    template <>
    inline void futureAdapter<void>(qi::Future<qi::AnyReference> metaFut, qi::Promise<void> promise)
    {
      //error handling
      if (metaFut.hasError()) {
        promise.setError(metaFut.error());
        return;
      }
      promise.setValue(0);
    }

  }

  /* Generate qi::FutureSync<R> GenericObject::call(methodname, args...)
   * for all argument counts
   * The function packs arguments in a vector<AnyReference>, computes the
   * signature and bounce those to metaCall.
   */
  #define pushi(z, n,_) params.push_back(p ## n);
#define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)                           \
  template<typename R> qi::FutureSync<R> GenericObject::call(             \
      const std::string& methodName       comma                           \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference))             \
  {                                                                        \
     if (!value || !type) {                                                \
      return makeFutureError<R>("Invalid GenericObject");                  \
     }                                                                     \
     std::vector<qi::AnyReference> params;                              \
     params.reserve(n);                                                    \
     BOOST_PP_REPEAT(n, pushi, _)                                          \
     std::string sigret;                                                   \
     qi::Promise<R> res;                                                   \
     qi::Future<AnyReference> fmeta = metaCall(methodName, params);      \
     fmeta.connect(boost::bind<void>(&detail::futureAdapter<R>, _1, res));  \
     return res.future();                                                  \
  }

  QI_GEN(genCall)
  #undef genCall
  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)                           \
  template<typename R> qi::FutureSync<R> GenericObject::async(             \
      const std::string& methodName       comma                           \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference))             \
  {                                                                        \
     if (!value || !type) {                                                \
      return makeFutureError<R>("Invalid GenericObject");                  \
     }                                                                     \
     std::vector<qi::AnyReference> params;                              \
     params.reserve(n);                                                    \
     BOOST_PP_REPEAT(n, pushi, _)                                          \
     std::string sigret;                                                   \
     qi::Promise<R> res;                                                   \
     qi::Future<AnyReference> fmeta = metaCall(methodName, params, MetaCallType_Queued);   \
     fmeta.connect(boost::bind<void>(&detail::futureAdapter<R>, _1, res));  \
     return res.future();                                                  \
  }

  QI_GEN(genCall)
  #undef genCall
  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)               \
  template<typename R> qi::FutureSync<R> GenericObject::call(             \
      MetaCallType callType,                                              \
      const std::string& methodName       comma                           \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference))             \
  {                                                                        \
     if (!value || !type) {                                                \
      return makeFutureError<R>("Invalid GenericObject");                  \
     }                                                                     \
     std::vector<qi::AnyReference> params;                              \
     params.reserve(n);                                                    \
     BOOST_PP_REPEAT(n, pushi, _)                                          \
     std::string sigret;                                                   \
     qi::Promise<R> res;                                                   \
     qi::Future<AnyReference> fmeta = metaCall(methodName, params, callType);   \
     fmeta.connect(boost::bind<void>(&detail::futureAdapter<R>, _1, res));  \
     return res.future();                                                  \
  }

  QI_GEN(genCall)
  #undef genCall

  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)         \
  template<typename R,typename T> qi::FutureSync<R> async(   \
      T* instance,                                                 \
      const std::string& methodName comma                         \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference)) \
  {                                                              \
    AnyObject obj = AnyReference(instance).toObject();       \
    qi::Future<R> res = obj->call<R>(MetaCallType_Queued, methodName comma AUSE);  \
    res.connect(boost::bind(&detail::hold<AnyObject>, obj));   \
    return res;                                                 \
  }
  QI_GEN(genCall)
  #undef genCall

  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)         \
  template<typename R,typename T> qi::FutureSync<R> async(   \
      boost::shared_ptr<T> instance,                             \
      const std::string& methodName comma                         \
      QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference)) \
  {                                                              \
    AnyObject obj = AnyReference(instance).toObject();        \
    qi::Future<R> res =  obj->call<R>(MetaCallType_Queued, methodName comma AUSE);  \
    res.connect(boost::bind(&detail::hold<AnyObject>, obj));   \
    return res;                                                 \
  }
  QI_GEN(genCall)
  #undef genCall
  #undef pushi

  template<typename T>
  qi::FutureSync<T> GenericObject::property(const std::string& name)
  {
    int pid = metaObject().propertyId(name);
    if (pid < 0)
      return makeFutureError<T>("Property not found");
    qi::Future<AnyValue> f = type->property(value, pid);
    qi::Promise<T> p;
    f.connect(boost::bind(&detail::futureAdapterVal<T>,_1, p));
    return p.future();
  }

  template<typename T>
  qi::FutureSync<void> GenericObject::setProperty(const std::string& name, const T& val)
  {
    int pid = metaObject().propertyId(name);
    if (pid < 0)
      return makeFutureError<void>("Property not found");
    return type->setProperty(value, pid, AnyValue(AnyReference(val)));
  }

  /* An AnyObject is actually of a Dynamic type: The underlying TypeInterface*
   * is not allways the same.
  */
  template<> class QITYPE_API TypeImpl<AnyObject>: public DynamicTypeInterface
  {
  public:
    virtual AnyReference get(void* storage)
    {
      AnyObject* val = (AnyObject*)ptrFromStorage(&storage);
      AnyReference result;
      if (!*val)
      {
        return AnyReference();
      }
      result.type = (*val)->type;
      result.value = (*val)->value;
      return result;
    }

    virtual void set(void** storage, AnyReference source)
    {
      qiLogCategory("qitype.object");
      AnyObject* val = (AnyObject*)ptrFromStorage(storage);
      TemplateTypeInterface* templ = dynamic_cast<TemplateTypeInterface*>(source.type);
      if (templ)
        source.type = templ->next();
      if (source.type->info() == info())
      { // source is objectptr
        AnyObject* src = (AnyObject*)source.type->ptrFromStorage(&source.value);
        if (!*src)
          qiLogWarning() << "NULL AnyObject";
        *val = *src;
      }
      else if (source.kind() == TypeKind_Dynamic)
      { // try to dereference dynamic type in case it contains an object
        set(storage, source.asDynamic());
      }
      else if (source.kind() == TypeKind_Object)
      { // wrap object in objectptr: we do not keep it alive,
        // but source type offers no tracking capability
        AnyObject op(new GenericObject(static_cast<ObjectTypeInterface*>(source.type), source.value));
        *val = op;
      }
      else if (source.kind() == TypeKind_Pointer)
      {
        PointerTypeInterface* ptype = static_cast<PointerTypeInterface*>(source.type);
        // FIXME: find a way!
        if (ptype->pointerKind() == PointerTypeInterface::Shared)
          qiLogInfo() << "AnyObject will *not* track original shared pointer";
        set(storage, *source);
      }
      else
        throw std::runtime_error((std::string)"Cannot assign non-object " + source.type->infoString() + " to AnyObject");

    }
    typedef DefaultTypeImplMethods<AnyObject> Methods;
    _QI_BOUNCE_TYPE_METHODS(Methods);
  };

  namespace detail
  {
    typedef std::map<TypeInfo, boost::function<AnyReference(AnyObject)> > ProxyGeneratorMap;
    QITYPE_API ProxyGeneratorMap& proxyGeneratorMap();

    template<typename Proxy>
    AnyReference makeProxy(AnyObject ptr)
    {
      boost::shared_ptr<Proxy> sp(new Proxy(ptr));
      return AnyReference(sp).clone();
    }
  }
  template<typename Proxy, typename Interface>
  bool registerProxyInterface()
  {
    detail::ProxyGeneratorMap& map = detail::proxyGeneratorMap();
    map[typeOf<Interface>()->info()] = &detail::makeProxy<Proxy>;
    return true;
  }
  template<typename Proxy>
  bool registerProxy()
  {
    detail::ProxyGeneratorMap& map = detail::proxyGeneratorMap();
    map[typeOf<Proxy>()->info()] = &detail::makeProxy<Proxy>;
    return true;
  }

  namespace detail
  {
    /* Factory helper functions
    */

    // create a T, wrap in a AnyObject
    template<typename T> AnyObject constructObject()
    {
      return AnyReference::fromPtr(new T()).toObject();
    }

    // in genericobjectbuilder.hxx
    template<typename T> AnyObject makeObject(const std::string& fname, T func);

    // Create a factory function for an object with one method functionName bouncing to func
    template<typename T> boost::function<AnyObject(const std::string&)>
    makeObjectFactory(const std::string functionName, T func)
    {
      return ( boost::function<AnyObject(const std::string&)>)
        boost::bind(&makeObject<T>, functionName, func);
    }
  }
}
QI_TYPE_STRUCT(qi::MethodStatistics, cumulatedTime, minTime, maxTime, count);
QI_TYPE_STRUCT(qi::EventTrace, id, kind, slotId, arguments, timestamp);
QI_TYPE_STRUCT(qi::os::timeval, tv_sec, tv_usec);
#endif  // _QITYPE_DETAILS_GENERICOBJECT_HXX_
<|endoftext|>