import os
import sys


########## new definition ##########
function_prototypes_oleaut32 = [

    # S
    'BSTR STDMETHODCALLTYPE SysAllocString(_In_opt_ const OLECHAR *psz);',
    
    'void STDMETHODCALLTYPE SysFreeString( _In_opt_ BSTR bstrString);',

    # V
    'HRESULT STDMETHODCALLTYPE VariantClear(_Inout_ VARIANTARG *pvarg);',
    'void STDMETHODCALLTYPE VariantInit(_Out_ VARIANTARG *pvarg);'

]

function_prototypes_ole32 = [
    
    # C
    'HRESULT STDMETHODCALLTYPE CoCreateInstance(_In_  REFCLSID  rclsid,_In_  LPUNKNOWN pUnkOuter,_In_  DWORD     dwClsContext,_In_  REFIID    riid,_Out_ LPVOID    *ppv);',

    'HRESULT STDMETHODCALLTYPE CoInitializeEx(_In_opt_ LPVOID pvReserved,_In_     DWORD  dwCoInit);',


    'HRESULT STDMETHODCALLTYPE CoInitializeSecurity(_In_opt_ PSECURITY_DESCRIPTOR pSecDesc,_In_ LONG cAuthSvc,_In_opt_ SOLE_AUTHENTICATION_SERVICE *asAuthSvc,_In_opt_ void* pReserved1,_In_ DWORD   dwAuthnLevel,_In_ DWORD   dwImpLevel,_In_opt_ void*pAuthList,_In_ DWORD   dwCapabilities,_In_opt_ void*pReserved3);',

    'HRESULT STDMETHODCALLTYPE CoSetProxyBlanket(_In_ IUnknown *pProxy,_In_ DWORD dwAuthnSvc,_In_ DWORD dwAuthzSvc,_In_opt_ OLECHAR  *pServerPrincName,_In_ DWORD dwAuthnLevel,_In_ DWORD dwImpLevel,_In_opt_ RPC_AUTH_IDENTITY_HANDLE pAuthInfo,_In_ DWORD dwCapabilities);',

    'void STDMETHODCALLTYPE CoUninitialize(void);'

]

function_prototypes_advapi32 = [

    # C
    'BOOL WINAPI ConvertSidToStringSidA(_In_  PSID   Sid, _Out_ LPSTR *StringSid);',

    # G
    'BOOL WINAPI GetTokenInformation(_In_ HANDLE TokenHandle,_In_ TOKEN_INFORMATION_CLASS TokenInformationClass,_Out_opt_ LPVOID TokenInformation,_In_ DWORD TokenInformationLength,_Out_ PDWORD ReturnLength);',

    # O
    'BOOL WINAPI OpenProcessToken(_In_  HANDLE  ProcessHandle,_In_  DWORD   DesiredAccess,_Out_ PHANDLE TokenHandle);',

    # R
    'LONG WINAPI RegCloseKey(_In_ HKEY hKey);',
    'LONG WINAPI RegCreateKeyExA(_In_ HKEY hKey,  _In_ LPCSTR lpSubKey,  _Reserved_ DWORDReserved,  _In_opt_   LPCSTR  lpClass,  _In_ DWORDdwOptions,  _In_ REGSAM  samDesired,  _In_opt_   LPSECURITY_ATTRIBUTES lpSecurityAttributes,  _Out_PHKEYphkResult,  _Out_opt_  LPDWORD lpdwDisposition);',
    'LONG WINAPI RegDeleteKeyA(  _In_ HKEY    hKey,  _In_ LPCSTR lpSubKey);',
    'LONG WINAPI RegDisableReflectionKey(  _In_ HKEY hBase);',
    'LONG WINAPI RegEnableReflectionKey(_In_ HKEY hBase);',
    'LONG WINAPI RegOpenCurrentUser(_In_  REGSAM samDesired, _Out_ PHKEY  phkResult);',
    'LONG WINAPI RegOpenKeyExA(  _In_ HKEY    hKey,  _In_opt_ LPCSTR lpSubKey,  _In_ DWORD   ulOptions,  _In_ REGSAM  samDesired,  _Out_    PHKEY   phkResult);',
    'LONG WINAPI RegQueryReflectionKey(  _In_  HKEY hBase,  _Out_ BOOL *bIsReflectionDisabled);',
    'LONG WINAPI RegSetValueExA(  _In_    HKEY hKey,  _In_opt_   LPCSTR lpValueName,  _Reserved_    DWORD   Reserved,  _In_    DWORD   dwType,  _In_    const BYTE *lpData,  _In_    DWORD   cbData);',
    


]

function_prototypes_kernel32 = [
    
    # C
    'BOOL WINAPI CloseHandle(_In_ HANDLE hObject);',
    'HANDLE WINAPI CreateFileA(_In_ LPCSTR lpFileName,_In_ DWORD  dwDesiredAccess,_In_ DWORD dwShareMode,_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,_In_ DWORD dwCreationDisposition,_In_ DWORD dwFlagsAndAttributes,_In_opt_ HANDLE hTemplateFile);',
    'BOOL WINAPI CreatePipe(_Out_ PHANDLE hReadPipe,_Out_ PHANDLE hWritePipe,_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,_In_ DWORD nSize);',
    'BOOL WINAPI CreateProcessA(_In_opt_    LPCSTR lpApplicationName,  _Inout_opt_ LPCSTR  lpCommandLine,  _In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,  _In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,  _In_        BOOL    bInheritHandles,  _In_        DWORD   dwCreationFlags,  _In_opt_    LPVOID  lpEnvironment,  _In_opt_    LPCSTR lpCurrentDirectory,  _In_        LPSTARTUPINFO         lpStartupInfo,  _Out_       LPPROCESS_INFORMATION lpProcessInformation);',
    'HANDLE WINAPI CreateThread(  _In_opt_  LPSECURITY_ATTRIBUTES  lpThreadAttributes,  _In_ SIZE_T  dwStackSize,  _In_ LPTHREAD_START_ROUTINE lpStartAddress,  _In_opt_  LPVOID  lpParameter,  _In_ DWORD   dwCreationFlags,  _Out_opt_ LPDWORD lpThreadId);',

    # D
    'BOOL WINAPI DeleteFileA(_In_ LPCSTR lpFileName);',

    # E 
    'void WINAPI EnterCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);',
    'VOID WINAPI ExitThread(_In_ DWORD dwExitCode);',
    'DWORD WINAPI ExpandEnvironmentStringsA(_In_  LPCSTR lpSrc,  _Out_opt_ LPCSTR  lpDst,  _In_      DWORD   nSize);',

    # F
    'BOOL WINAPI FindClose(_Inout_ HANDLE hFindFile);',
    'HANDLE WINAPI FindFirstFileA(_In_ LPCSTR lpFileName, _Out_ LPWIN32_FIND_DATA lpFindFileData);',
    'BOOL WINAPI FindNextFileA(_In_ HANDLE hFindFile, _Out_ LPWIN32_FIND_DATA lpFindFileData);',
    'BOOL WINAPI FlushFileBuffers(_In_ HANDLE hFile);',
    'BOOL WINAPI FreeLibrary(_In_ HMODULE hModule);',


    # G
    'HANDLE WINAPI GetCurrentProcess(void);',
    'UINT WINAPI GetDriveTypeA(_In_opt_ LPCSTR lpRootPathName);',
    'DWORD WINAPI GetFileSize(_In_ HANDLE  hFile,_Out_opt_ LPDWORD lpFileSizeHigh);',
    'DWORD WINAPI GetEnvironmentVariableA(_In_opt_  LPCSTR lpName, _Out_opt_ LPSTR  lpBuffer, _In_ DWORD   nSize);',
    'DWORD WINAPI GetEnvironmentVariableW(_In_opt_  LPCWSTR lpName, _Out_opt_ LPWSTR  lpBuffer, _In_ DWORD   nSize);',
    'DWORD WINAPI GetLastError(void);',
    'FARPROC WINAPI GetProcAddress(HMODULE hModule, LPCSTR lpProcName);',
    'VOID WINAPI GetSystemTimeAsFileTime(_Out_ LPFILETIME lpSystemTimeAsFileTime);',
    'DWORD WINAPI GetTickCount(void);',
    'LPVOID WINAPI GlobalLock(_In_ HGLOBAL hMem);',
    'BOOL WINAPI GlobalUnlock(_In_ HGLOBAL hMem);',




    # I
    'void WINAPI InitializeCriticalSection(_Out_ LPCRITICAL_SECTION lpCriticalSection);',

    # L
    'void WINAPI LeaveCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);',
    'HLOCAL WINAPI LocalAlloc(_In_ UINT uFlags,_In_ SIZE_T uBytes);',
    'HMODULE WINAPI LoadLibraryA(LPSTR lpFileName);',
    'HLOCAL WINAPI LocalFree(_In_ HLOCAL hMem);',
    'HLOCAL WINAPI LocalReAlloc(_In_ HLOCAL hMem,_In_ SIZE_T uBytes,_In_ UINT   uFlags);',
    
    # O
    'HANDLE WINAPI OpenProcess(_In_ DWORD dwDesiredAccess,_In_ BOOL  bInheritHandle,_In_ DWORD dwProcessId);',
    'VOID WINAPI OutputDebugStringA(_In_opt_ LPCSTR lpOutputString);',

    # R
    'BOOL WINAPI ReadFile(_In_ HANDLE hFile, _Out_ LPVOID lpBuffer, _In_ DWORD nNumberOfBytesToRead, _Out_opt_ LPDWORD lpNumberOfBytesRead, _Inout_opt_ LPOVERLAPPED lpOverlapped);',


    # S
    'VOID WINAPI Sleep(_In_ DWORD dwMilliseconds);',

    # V
    'LPVOID WINAPIV VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);',
    'LPVOID WINAPI VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);',
    'BOOL WINAPI VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);',
    'BOOL WINAPI VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);',

    # W
    'DWORD WINAPI WaitForSingleObject(_In_ HANDLE hHandle, _In_ DWORD  dwMilliseconds);',
    'BOOL WINAPI WriteFile(_In_ HANDLE hFile, _In_ LPCVOID lpBuffer, _In_  DWORD  nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped);'
    
]

function_prototypes_msvcrt = [

    # B
    'uintptr_t __cdecl _beginthreadex(void *security, unsigned stack_size,  unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr);',

    # C
    'int __cdecl _close(int fd);',

    # I
    'int __cdecl isdigit(int c);',
    'int __cdecl isspace(int c);',
    'errno_t __cdecl _itoa_s(int value, char *buffer, size_t sizeInCharacters,  int radix );',
    'errno_t __cdecl _itow_s(int value, wchar_t *buffer, size_t sizeInCharacters,  int radix );',

    # M
    'int __cdecl memcmp(const void *buf1, const void *buf2, size_t count); ',
    'void* __cdecl memcpy(void *dest, const void *src, size_t count);',
    'errno_t __cdecl memcpy_s(void *dest, size_t numberOfElements, const void *src, size_t count);',
    'void* __cdecl memset(void *dest, int c, size_t count);',
    
    # O
    'int __cdecl _open(const char *filename, int oflag)',

    # R
    'int __cdecl rand( void );',
    'int __cdecl _read( int fd, void *buffer, unsigned int count);',

    # S
    'int __cdecl _snprintf_s(char *buffer, size_t sizeOfBuffer, size_t count,   const char *format, ... );',
    'int __cdecl _snprintf(char *buffer, size_t count, const char *format, ...);',
    'void __cdecl srand(unsigned int seed);',
    'int __cdecl strcmp(const char *string1, const char *string2);',
    'char* __cdecl _strdup(const char *s1);',
    'size_t __cdecl strlen(const char *str);',
    'char* __cdecl strrchr(const char *str, int c);',
    'int __cdecl sscanf(const char *buffer, const char *format,...);',
    'int __cdecl sscanf_s(const char *buffer, const char *format, ...);',
    'errno_t __cdecl strcat_s(char *strDestination,  size_t numberOfElements,  const char *strSource );',
    'char* __cdecl strchr(const char *str, int c); ',
    'errno_t __cdecl strncpy_s( char *strDest, size_t numberOfElements, const char *strSource, size_t count);',
    'int __cdecl strncmp(const char *string1, const char *string2,  size_t count);',
    'int __cdecl _strnicmp(const char *string1, const char *string2, size_t count);',
    'double __cdecl strtod(const char *nptr, char **endptr);',
    'int __cdecl swprintf_s(wchar_t *buffer, size_t sizeOfBuffer, const wchar_t *format , ...);',

    # T
    'time_t __cdecl time(time_t *timer);',
    'int __cdecl toupper(int c);',


    # V
    'int __cdecl _vscprintf(const char *format, va_list argptr);',
    'int __cdecl vsnprintf(char *buffer, size_t count, const char *format, va_list argptr );',
    'int __cdecl vsprintf(char *buffer, const char *format, va_list argptr);',

    # W
    'errno_t __cdecl wcscat_s(wchar_t *strDestination, size_t numberOfElements, const wchar_t *strSource );',
    'errno_t __cdecl wcscpy_s(wchar_t *strDestination, size_t numberOfElements, const wchar_t *strSource);',
    'size_t __cdecl wcslen(const wchar_t *str);',
    'int __cdecl _write(int fd, const void *buffer, unsigned int count);',
    'int __cdecl _wtoi(const wchar_t *str);',

        
    ]

function_prototypes_winhttp = [
    
    # W
    'BOOL WINAPI WinHttpCloseHandle(_In_ HINTERNET hInternet);',
    'HINTERNET WINAPI WinHttpConnect(_In_ HINTERNET hSession,_In_ LPCWSTR pswzServerName,_In_ INTERNET_PORT nServerPort,_Reserved_ DWORD dwReserved);',
    'BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser(_Inout_ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *pProxyConfig);',
    'BOOL WINAPI WinHttpGetProxyForUrl(_In_ HINTERNET hSession,_In_ LPCWSTR lpcwszUrl,_In_  WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions,_Out_ WINHTTP_PROXY_INFO *pProxyInfo);',
    'HINTERNET WINAPI WinHttpOpen(_In_opt_ LPCWSTR pwszUserAgent,_In_ DWORD dwAccessType,_In_ LPCWSTR pwszProxyName,_In_ LPCWSTR pwszProxyBypass,_In_ DWORD dwFlags);',
    'HINTERNET WINAPI WinHttpOpenRequest(_In_ HINTERNET hConnect,_In_ LPCWSTR pwszVerb,_In_ LPCWSTR pwszObjectName,_In_ LPCWSTR pwszVersion,_In_ LPCWSTR pwszReferrer,_In_ LPCWSTR *ppwszAcceptTypes,_In_ DWORD dwFlags);',
    'BOOL WINAPI WinHttpQueryHeaders(_In_ HINTERNET hRequest,_In_ DWORD dwInfoLevel,_In_opt_ LPCWSTR pwszName,_Out_ LPVOID lpBuffer,_Inout_ LPDWORD lpdwBufferLength,_Inout_ LPDWORD lpdwIndex);',
    'BOOL WINAPI WinHttpReadData(_In_ HINTERNET hRequest,_Out_ LPVOID lpBuffer,_In_  DWORD dwNumberOfBytesToRead,_Out_ LPDWORD   lpdwNumberOfBytesRead);',
    'BOOL WINAPI WinHttpReceiveResponse(_In_ HINTERNET hRequest,_Reserved_ LPVOID lpReserved);',
   ' BOOL WINAPI WinHttpSendRequest(_In_ HINTERNET hRequest,_In_opt_ LPCWSTR pwszHeaders,_In_ DWORD dwHeadersLength,_In_opt_ LPVOID lpOptional,_In_ DWORD dwOptionalLength,_In_ DWORD dwTotalLength,_In_ DWORD_PTR dwContext);',
    'BOOL WINAPI WinHttpSetOption(_In_ HINTERNET hInternet,_In_ DWORD dwOption,_In_ LPVOID lpBuffer,_In_ DWORD dwBufferLength);',
    'BOOL WINAPI WinHttpSetTimeouts(_In_ HINTERNET hInternet,_In_ int dwResolveTimeout, _In_ int dwConnectTimeout,_In_ int dwSendTimeout,_In_ int dwReceiveTimeout);',

    ]

function_prototypes_winsock = [

    # G
    'struct hostent* __stdcall gethostbyname(_In_ const char *name);',

    # I
    'unsigned long __stdcall  inet_addr(_In_ const char *cp);',
    'char* __stdcall inet_ntoa(_In_ struct in_addr in);',

    # N
    'u_long __stdcall ntohl(_In_ u_long netlong);',

    # W
    'int __stdcall WSACleanup(void);',
    'int __stdcall WSAStartup(_In_ WORD wVersionRequested,  _Out_ LPWSADATA lpWSAData);',

]

function_prototypes_user32 = [

    # A
    'BOOL WINAPI AddClipboardFormatListener(_In_ HWND hwnd);', # Minimum supported client Windows Vista
    
    # C
    'BOOL WINAPI CloseClipboard(void);',

    # G
    'HANDLE WINAPI GetClipboardData(_In_ UINT uFormat);',
    'HWND WINAPI GetClipboardOwner(void);',
    'HWND WINAPI GetForegroundWindow(void);',
    'DWORD WINAPI GetWindowThreadProcessId(_In_      HWND    hWnd, _Out_opt_ LPDWORD lpdwProcessId);',
    'int WINAPI GetWindowTextA(_In_  HWND   hWnd, _Out_ LPCSTR lpString, _In_  int    nMaxCount);',
    
    
    # O
    'BOOL WINAPI OpenClipboard(_In_opt_ HWND hWndNewOwner);',
    
    


]


####################################
STRUCT_NAME = {}
STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] = []

# 'kernel32' -> { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2',  0x0 },
def generate_stack_variable(name):
    res = ''
    for c in name:
        res += "'{}', ".format(c)
    
    res = '{{ {} 0x0 }},'.format(res)
    
    return res

def generate_unicode_stack_variable(name):
    res = ''
    for c in name:
        res += "'{}', 0x0, ".format(c)
    
    res = '{{ {} 0x0, 0x0}}, // UNICODE'.format(res)
    
    return res


def generate_actual_structure(struct_name, strs):

    struct = '{} runtimeStrings =\n{{\n'.format(struct_name)
    
    for elem in map(generate_stack_variable, strs):
        struct += '\t' + elem + '\n'

    struct += '};'

    print struct
    return struct

# 'kernel32' ->  CHAR strKernel32[9];
def generate_struct_variable_definition(name):
    
    length = len(name) + 1
    name = name[0].upper() + name[1:]

    res = 'CHAR str{}[{}];'.format(name, length)

    return res

def generate_struct(struct_name, strs):

    struct = 'typedef struct _{}\n{{\n'.format(struct_name)

    for elem in map(generate_struct_variable_definition, strs):
        struct += '\t' + elem + '\n'
    
    struct += '}} {}, *P{};'.format(struct_name, struct_name)

    print struct
    return struct

def generate_macro_functions(dll_name, strs):
    
    direct_call = '/* ---> {} <--- */\n'.format(dll_name)
    runtime_call = '/* ---> {} <--- */\n'.format(dll_name)

    for elem in strs:
        runtime_call  += '#define API_{}\t\t\t pRuntime->p{}{}->fp{}\n'.format(elem.upper(), dll_name[0].upper(), dll_name[1:], elem)
        direct_call   += '#define API_{}\t\t\t {}\n'.format(elem.upper(), elem)

    print direct_call
    print runtime_call


def generate_runtime_strs_from_prototypes(prototypes):
    
    strs_buffer = []
    for proto in prototypes:
        head = proto.split('(')[0]
        head = head.split(' ')[-1:][0]
        strs_buffer.append(head)
    return strs_buffer
        





function_prototypes_ws2_32 = [
    
    # G
    'struct hostent* FAR gethostbyname(_In_ const char *name);',

    # I
    'unsigned long inet_addr(_In_ const char *cp);',

    # W
    'int __cdecl WSACleanup(void);',
    'int __cdecl WSAStartup(_In_ WORD  wVersionRequested, _Out_ LPWSADATA lpWSAData);',
    
    ]

def generate_function_pointers_prototype(dll_name, strs):
    
    struct_buffer = 'typedef struct _VTABLE_{}\n{{\n'.format(dll_name.upper())
    definition_buffer = ''


    for elem in strs:
        splitted = elem.split(' ')
        print elem
        function_name = params = splitted[2].split('(')[0]
        params = splitted[2].split('(')[1:] + splitted[3:]
        definition = 'typedef {}({} *{})({}\n'.format(splitted[0], splitted[1], function_name.upper(), ' '.join(params))
        definition_buffer += definition

        struct_buffer += '    {} fp{};\n'.format(function_name.upper(), function_name)

    struct_buffer += '\n}} VTABLE_{}, *PVTABLE_{};'.format(dll_name.upper(), dll_name.upper())

    print definition_buffer

    print '\n'
    
    print struct_buffer
    
        
    
def generate_loader_function(dll, elements):
    
    module_name = dll[0].upper() + dll[1:]

    function = 'BOOL Load{}(PRUNTIME pRuntime, PDYNAMIC_LOADER_STRINGS pRuntimeStrings)\n{{\n'.format(module_name)

    function += '\n    HMODULE h{} = pRuntime->pKernel32->fpLoadLibraryA(pRuntimeStrings->str{});\n'.format(module_name, module_name)

    function +=	'\n    if (h{} == NULL)\n	return FALSE;\n\n'.format(module_name)

    
    for elem in elements:
        elem_cammel = elem[0].upper() + elem[1:]
        function += '    pRuntime->p{}->fp{} = ({})pRuntime->pKernel32->fpGetProcAddress(h{}, pRuntimeStrings->str{});\n'.format(module_name, elem_cammel, elem_cammel.upper(), module_name, elem_cammel)


    function += '\n\n    if (\n'

    for elem in elements:
        elem_cammel = elem[0].upper() + elem[1:]
        function += '        !pRuntime->p{}->fp{} || \n'.format(module_name, elem_cammel)


    function += '''	)
	return FALSE;

    return TRUE;\n}'''

    print function
    
def generate_variables(module_name, variables):
    
    buf = 'typedef struct _VARIABLES_{}\n{{\n'.format(module_name.upper())
    
    for v in variables:
        buf += '    {}\n'.format(v)

    buf += '}} VARIABLES_{}, *PVARIABLES_{};'.format(module_name.upper(), module_name.upper())
    print buf

def generate_strings(module_name, strings_dict):
    defintion = 'typedef struct _STRINGS_{}\n{{\n'.format(module_name.upper())
    
    actual_buffer = 'STRINGS_{} {}Strings =\n{{\n'.format(module_name.upper(), module_name.lower())
    
    
    #'L"
    for val in strings_dict.values():
        if val.startswith('L"'):
            val = val[2:-1] 
            #actual_buffer += '\t' + generate_unicode_stack_variable(val) + '\n'
            actual_buffer += '\t' + generate_stack_variable(val) + '\n'
        else:
            val = val[1:-1]
            actual_buffer += '\t' + generate_stack_variable(val) + '\n'
        
    #for elem in map(generate_stack_variable, strings_dict.values()):
    #    actual_buffer += '\t' + elem + '\n'

    actual_buffer += '};'

    
    for k,v in strings_dict.iteritems():
        n = k[0].upper() + k[1:]

        if v.startswith('L"'):
            v =  v[2:-1]
            l = (len(v) + 1) 
            defintion += '    WCHAR str{}[{}]; // UNICODE\n'.format(n, l )
        else:
            v = v[1:-1]
            l = len(v) + 1
            defintion += '    CHAR str{}[{}];\n'.format(n, l )
        
            


    defintion += '}} STRINGS_{}, *P{};'.format(module_name.upper(), module_name.upper())
    
    print defintion
    print actual_buffer
    

# API GENERATION 
def generate_advapi32():
    global STRUCT_NAME

    print '---> advapi32 <---'
    generate_function_pointers_prototype('advapi32', function_prototypes_advapi32)
    print '\n'
    
    runtime_strs_advapi32 = generate_runtime_strs_from_prototypes(function_prototypes_advapi32)
    
    print '\n'
    generate_macro_functions('advapi32', runtime_strs_advapi32)
    
    print '\n'
    generate_loader_function('advapi32', runtime_strs_advapi32)
    
    print '\n'
    generate_struct('ADVAPI32_STRINGS', runtime_strs_advapi32)
    
    print '\n'
    generate_actual_structure('ADVAPI32_STRING', runtime_strs_advapi32)

    STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] += ['advapi32'] + runtime_strs_advapi32


def generate_kernel32():
    global STRUCT_NAME

    print '---> kernel32 <---'
    generate_function_pointers_prototype('kernel32', function_prototypes_kernel32)
    print '\n'
    
    runtime_strs_kernel32 = generate_runtime_strs_from_prototypes(function_prototypes_kernel32)
    
    print '\n'
    generate_macro_functions('kernel32', runtime_strs_kernel32)
    
    print '\n'
    generate_loader_function('kernel32', runtime_strs_kernel32)
    
    print '\n'
    generate_struct('KERNEL32_STRINGS', runtime_strs_kernel32)
    
    print '\n'
    generate_actual_structure('KERNEL32_STRING', runtime_strs_kernel32)

    STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] += ['kernel32'] + runtime_strs_kernel32

def generate_msvcrt():
    global STRUCT_NAME
    
    print '---> msvcrt <---'
    generate_function_pointers_prototype('msvcrt', function_prototypes_msvcrt)
    print '\n'
    
    runtime_strs_msvcrt = generate_runtime_strs_from_prototypes(function_prototypes_msvcrt)
    
    print '\n'
    generate_macro_functions('msvcrt', runtime_strs_msvcrt)
    
    print '\n'
    generate_loader_function('msvcrt', runtime_strs_msvcrt)
    
    print '\n'
    generate_struct('MSVCRT_STRINGS', runtime_strs_msvcrt)
    
    print '\n'
    generate_actual_structure('MSVCRT_STRING', runtime_strs_msvcrt)

    STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] += ['msvcrt'] + runtime_strs_msvcrt

def generate_winhttp():
 
    print '---> winhttp <---'
    generate_function_pointers_prototype('Winhttp', function_prototypes_winhttp)
    print '\n'
    
    runtime_strs_winhttp = generate_runtime_strs_from_prototypes(function_prototypes_winhttp)
    print '\n'
    generate_macro_functions('Winhttp', runtime_strs_winhttp)
    print '\n'
    generate_loader_function('Winhttp', runtime_strs_winhttp)
    
    global STRUCT_NAME
    STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] += ['Winhttp'] + runtime_strs_winhttp


def generate_winsock():
 
    print '---> winsock <---'
    generate_function_pointers_prototype('Ws2_32', function_prototypes_winsock)
    print '\n'
    
    runtime_strs_winsock = generate_runtime_strs_from_prototypes(function_prototypes_winsock)
    print '\n'
    generate_macro_functions('Ws2_32', runtime_strs_winsock)
    print '\n'
    generate_loader_function('Ws2_32', runtime_strs_winsock)
    
    global STRUCT_NAME
    STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] += ['Ws2_32'] + runtime_strs_winsock


def generate_oleaut32():
    print '---> OleAut32 <---'
    generate_function_pointers_prototype('OleAut32', function_prototypes_oleaut32)
    print '\n'
    
    runtime_strs_oleaut32 = generate_runtime_strs_from_prototypes(function_prototypes_oleaut32)
    print '\n'
    generate_macro_functions('OleAut32', runtime_strs_oleaut32)
    print '\n'
    generate_loader_function('OleAut32', runtime_strs_oleaut32)
    
    global STRUCT_NAME
    STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] += ['OleAut32'] + runtime_strs_oleaut32

def generate_ole32():
    print '---> Ole32 <---'
    generate_function_pointers_prototype('Ole32', function_prototypes_ole32)
    print '\n'
    
    runtime_strs_ole32 = generate_runtime_strs_from_prototypes(function_prototypes_ole32)
    print '\n'
    generate_macro_functions('Ole32', runtime_strs_ole32)
    print '\n'
    generate_loader_function('Ole32', runtime_strs_ole32)
    
    global STRUCT_NAME
    STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] += ['Ole32'] + runtime_strs_ole32


def generate_user32():
    print '---> User32 <---'
    generate_function_pointers_prototype('User32', function_prototypes_user32)
    print '\n'
    
    runtime_strs_user32 = generate_runtime_strs_from_prototypes(function_prototypes_user32)
    print '\n'
    generate_macro_functions('User32', runtime_strs_user32)
    print '\n'
    generate_loader_function('User32', runtime_strs_user32)
    
    global STRUCT_NAME
    STRUCT_NAME['DYNAMIC_LOADER_STRINGS'] += ['User32'] + runtime_strs_user32


# MODULE GENERATION
def generate_module_actioneventengine():
    actioneventengine_strings = {
        # debug strings 
        'debugInitialized':'"[AM] initialized\n"',
        'debugParsingActionGroups':'"[AM] parsing %d action groups\n"',
        'debugActionUninstall':'"[AM] . action #%d.%d: uninstall\n"',
        

        # non debug strings
        'actions':'"actions"',
        'subactions':'"subactions"',
        'action':'"action"',
        'uninstall':'"uninstall"',
        
        

        }

    actioneventengine_variables = [  ]

    generate_variables('ActionEventEngine', actioneventengine_variables)
    print '\n'
    generate_strings('ActionEventEngine', actioneventengine_strings)
    

def generate_module_configuration():
    
    configuration_strings = { 'json_number_chars':'"0123456789.+-eE"',
                              'json_hex_chars':'"0123456789abcdefABCDEF"',
                              'pb':'"\\u00%c%c"',
                              'null':'"null"',
                              'curly_open':'"{"',
                              'curly_close':'"}"',
                              'space_curly_close':'" }"',
                              'newline':'"\n"',
                              'comma':'","',
                              'double_quotes':'"\""',
                              'double_quotes_colon_space':'"\": "',
                              'double_quotes_colon':'"\":"',
                              'true':'"true"',
                              'false':'"false"',
                              'escape_b':'"\\b"',
                              'escape_n':'"\\n"',
                              'escape_r':'"\\r"',
                              'escape_t':'"\\t"',
                              'escape_f':'"\\f"',
                              'escape_forward_slash':'"\\/"',
                              'NaN':'"NaN"',
                              'positive_infinity':'"Infinity"',
                              'negative_infinity':'"-Infinity"',
                              'g_17':'"%.17g"',
                              'square_open':'"["',
                              'space_square_close':'" ]"',
                              'square_close':'"]"',
                              'space':'" "',
                              'lld':'"%lld"',
                              'error_success':'"success"',
                              'error_continue':'"continue"',
                              'error_nesting':'"nesting too deep"',
                              'error_eod':'"unexpected end of data"',
                              'error_uc':'"unexpected character"',
                              'error_null':'"null expected"',
                              'error_boolean':'"boolean expected"',
                              'error_number':'"number expected"',
                              'error_array':'"array value separator \',\' expected"',
                              'error_quoted':'"quoted object property name expected"',
                              'error_property':'"object property name separator \':\' expected"',
                              'error_value':'"object value separator \',\' expected"',
                              'error_value':'"invalid string sequence"',
                              'error_value':'"expected comment"',
                              'error_value':'"buffer size overflow"',
                              'unknown_error':'"Unknown error"',
                              'locale_c':'"C"',
                              'singleEscape_b':'"\b"',
                              'singleEscape_n':'"\n"',
                              'singleEscape_r':'"\r"',
                              'singleEscape_t':'"\t"',
                              'singleEscape_f':'"\f"',
                              'spaceNegativeNumbers':'" -01234567890123456789012345"',
                              'spacePositiveNumbers':'" 01234567890123456789012345"',
                              'lf':'"%lf"',

                              # manual
                              #'escape_double_quotes':'"\\\""'
                              #'escape_escape':'"\\\\"'

                              
                              }

    configuration_variables = [
    'static const void* kObjectEndIterValue;',
    'static int sscanf_is_broken;',
    'static int sscanf_is_broken_testdone'
        ]

    generate_variables('Configuration', configuration_variables)
    print '\n'
    generate_strings('Configuration', configuration_strings)

def generate_module_protocol():
    protocol_variables = [ 'HINTERNET* hGlobalInternet;', 'HINTERNET* hSession;', 'HINTERNET* hConnect;']

    protocol_strings = { 'wTypes':'"*\\x00/\\x00*\\x00"', 
                         'formatUnicodeS':'L"%S"', 
                         'formatUnicodeHttp':'L"http://%S"',
                         'formatS':'"%S"',
                         'formatD':'"%d"',
                         'formats':'"%s"',
                         'contentLength':'L"Content-Length: %d"',
                         'post':'L"POST"',
                         'username':'L"USERNAME"',
                         'computername':'L"COMPUTERNAME"',
                         'emptyUnicode':'L""',

                         'DEBUG_response_fail':'"[!!] WinHttpReceiveResponse FAIL\\n"',
                         
                         } 

    generate_variables('Protocol', protocol_variables)
    print '\n'
    generate_strings('Protocol', protocol_strings)
    


def generate_module_events():
    events_variables = ['IWbemServices *pSvc;',
                        'IWbemObjectSink* pStubSink;',
                        'IUnknown* pStubUnk',
                        'IUnsecuredApartment* pUnsecApp',
                        'Sink *pSink', 
                        'IWbemLocator *pLoc',
                             ]


    events_strings = { 
        'Connected':'"Connected\n"',
        'ExecNotificationQueryAsync':'"ExecNotificationQueryAsync failed with = 0x%X\n"',
        'Name':'"Name : "',
        'SinkSetStatus':'"SinkSetStatus\n"',
        'addref':'"addref: %d\n"',
        'empty_name':'"empty name\n"',
        'event_occured':'"event occured\n"',
        'loader':'"loader"',
        'name_s':'"name %S\n"',
        'pSink_p':'"pSink %p\n"',
        'format_stuff':'L"%s, %s\r\n"',
        'ProcessId':'L"ProcessId"',
        'LName':'L"Name"',
        'ROOT_CIMV2':'L"ROOT\\CIMV2"',
        'InstanceDeletionEvent':'L"SELECT * FROM  __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA \'WIn32_Process\'"',
        'Win32_Process':'L"SELECT * FROM Win32_Process"',
        'TargetInstance':'L"TargetInstance"',
        'WQL':'L"WQL"',
        'IID_IUnknown':'00000000-0000-0000-C000-000000000046',
        'IID_IWbemObjectSink':'7C857801-7381-11CF-884D-00AA004B2E24',
        'IID_IWbemLocator':'DC12A687-737F-11CF-884D-00AA004B2E24'
        }

    generate_variables('Events', events_variables)
    print '\n'
    generate_strings('Events', events_strings)
    

def generate_module_storage():
    storage_variables = [
        'EVIDENCE_HANDLE sequentialEvidences[MAX_SEQUENTIAL_EVIDENCE];',
        'CRITICAL_SECTION evidenceHandlesCriticalSection;',
        ]

    storage_strings = {}

    generate_variables('Storage', storage_variables)
    print '\n'
    generate_strings('Storage', storage_strings)
    

def generate_module_eventsActionEngine():
    
    eventsActionEngine_variables = [
        'module_t* modulev;',
        ]

    eventsActionEngine_strings = {}
    
    generate_variables('EventsActionEngine', eventsActionEngine_variables)
    print '\n'
    generate_strings('EventsActionEngine', eventsActionEngine_strings)


if __name__ == '__main__':
    
   
    # 1] API 

    #generate_macro_functions('kernel32', runtime_strs_kernel32)
    #generate_macro_functions('msvcrt', runtime_strs_msvcrt)
    

    # generate header for runtime.h included headers

    #print '---> ws2_32 <---'
    #generate_function_pointers_prototype('Ws2_32', function_prototypes_ws2_32)

    # kernel32
    generate_kernel32()

    # advapi32
    generate_advapi32()

    # msvcrt
    generate_msvcrt()
    
    # winhttp
    generate_winhttp()

    # winsock
    generate_winsock()

    # oleaut32
    generate_oleaut32()

    # ole32
    generate_ole32()

    # user32
    generate_user32()

    # 2] MODULE_LOADER STRINGS
    generate_struct('DYNAMIC_LOADER_STRINGS', STRUCT_NAME['DYNAMIC_LOADER_STRINGS'])
    generate_actual_structure('DYNAMIC_LOADER_STRINGS', STRUCT_NAME['DYNAMIC_LOADER_STRINGS'])


    print '-------------------> MODULE <-------------------'

    # 3] MODULES
    generate_module_protocol()

    #generate_module_configuration()
    #generate_module_actioneventengine()
    generate_module_eventsActionEngine() 

    
    generate_module_events()
    
    generate_module_storage()

