#
# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import struct
import os
import stat
import time
import string
import logging
from zlib import crc32
from StringIO import StringIO
import time
import datetime

try:
    from Crypto.Hash import MD5, SHA
except ImportError:
    print "cannot find crypto, skipping"

from miasm2.jitter.csts import PAGE_READ, PAGE_WRITE, PAGE_EXEC
from miasm2.core.utils import pck16, pck32, hexdump, whoami
from miasm2.os_dep.common import heap, windows_to_sbpath
from miasm2.os_dep.common import set_str_unic, set_str_ansi
from miasm2.os_dep.common import get_fmt_args as _get_fmt_args
from miasm2.os_dep.win_api_x86_32_seh import tib_address

log = logging.getLogger("win_api_x86_32")
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s"))
log.addHandler(console_handler)
log.setLevel(logging.WARN)

DATE_1601_TO_1970 = 116444736000000000

MAX_PATH = 260


"""
typedef struct tagPROCESSENTRY32 {
  DWORD     dwSize;
  DWORD     cntUsage;
  DWORD     th32ProcessID;
  ULONG_PTR th32DefaultHeapID;
  DWORD     th32ModuleID;
  DWORD     cntThreads;
  DWORD     th32ParentProcessID;
  LONG      pcPriClassBase;
  DWORD     dwFlags;
  TCHAR     szExeFile[MAX_PATH];
} PROCESSENTRY32, *PPROCESSENTRY32;
"""


ACCESS_DICT = {0x0: 0,
               0x1: 0,
               0x2: PAGE_READ,
               0x4: PAGE_READ | PAGE_WRITE,
               0x10: PAGE_EXEC,
               0x20: PAGE_EXEC | PAGE_READ,
               0x40: PAGE_EXEC | PAGE_READ | PAGE_WRITE,
               0x80: PAGE_EXEC | PAGE_READ | PAGE_WRITE,
               # 0x80: PAGE_EXECUTE_WRITECOPY
               0x100: 0
               }

ACCESS_DICT_INV = dict((x[1], x[0]) for x in ACCESS_DICT.iteritems())


class whandle():

    def __init__(self, name, info):
        self.name = name
        self.info = info

    def __repr__(self):
        return '<%r %r %r>' % (self.__class__.__name__, self.name, self.info)


class handle_generator():

    def __init__(self):
        self.offset = 600
        self.all_handles = {}

    def add(self, name, info=None):
        self.offset += 1
        h = whandle(name, info)
        self.all_handles[self.offset] = h

        log.debug(repr(self))
        return self.offset

    def __repr__(self):
        out = '<%r\n' % self.__class__.__name__
        ks = self.all_handles.keys()
        ks.sort()

        for k in ks:
            out += "    %r %r\n" % (k, self.all_handles[k])
        out += '>'
        return out

    def __contains__(self, e):
        return e in self.all_handles

    def __getitem__(self, item):
        return self.all_handles.__getitem__(item)

    def __delitem__(self, item):
        self.all_handles.__delitem__(item)


class c_winobjs:

    def __init__(self):
        self.alloc_ad = 0x20000000
        self.alloc_align = 0x1000
        self.heap = heap()
        self.handle_toolhelpsnapshot = 0xaaaa00
        self.toolhelpsnapshot_info = {}
        self.handle_curprocess = 0xaaaa01
        self.dbg_present = 0
        self.tickcount = 0
        self.dw_pid_dummy1 = 0x111
        self.dw_pid_explorer = 0x222
        self.dw_pid_dummy2 = 0x333
        self.dw_pid_cur = 0x444
        self.module_fname_nux = None
        self.module_name = "test.exe"
        self.module_path = "c:\\mydir\\" + self.module_name
        self.hcurmodule = None
        self.module_filesize = None
        self.getversion = 0x0A280105
        self.getforegroundwindow = 0x333333
        self.cryptcontext_hwnd = 0x44400
        self.cryptcontext_bnum = 0x44000
        self.cryptcontext_num = 0
        self.cryptcontext = {}
        self.phhash_crypt_md5 = 0x55555
        self.files_hwnd = {}
        self.windowlong_dw = 0x77700
        self.module_cur_hwnd = 0x88800
        self.module_file_nul = 0x999000
        self.runtime_dll = None
        self.current_pe = None
        self.tls_index = 0xf
        self.tls_values = {}
        self.handle_pool = handle_generator()
        self.handle_mapped = {}
        self.hkey_handles = {0x80000001: "hkey_current_user", 0x80000002: "hkey_local_machine"}
        self.cur_dir = "c:\\tmp"

        self.nt_mdl = {}
        self.nt_mdl_ad = None
        self.nt_mdl_cur = 0
        self.win_event_num = 0x13370
        self.cryptdll_md5_h = {}

        self.lastwin32error = 0
        self.mutex = {}
        self.env_variables = {}
        self.events_pool = {}
        self.find_data = None

        self.current_datetime = datetime.datetime(year=2017, month=8, day=21,
                                                  hour=13, minute=37,
                                                  second=11, microsecond=123456)

winobjs = c_winobjs()


process_list = [
    [
        0x40,  # DWORD     dwSize;
        0,  # DWORD     cntUsage;
        winobjs.dw_pid_dummy1,  # DWORD     th32ProcessID;
        0x11111111,  # ULONG_PTR th32DefaultHeapID;
        0x11111112,  # DWORD     th32ModuleID;
        1,  # DWORD     cntThreads;
        winobjs.dw_pid_explorer,  # DWORD     th32ParentProcessID;
        0xbeef,  # LONG      pcPriClassBase;
        0x0,  # DWORD     dwFlags;
        "dummy1.exe"  # TCHAR     szExeFile[MAX_PATH];
    ],
    [
        0x40,  # DWORD     dwSize;
        0,  # DWORD     cntUsage;
        winobjs.dw_pid_explorer,  # DWORD     th32ProcessID;
        0x11111111,  # ULONG_PTR th32DefaultHeapID;
        0x11111112,  # DWORD     th32ModuleID;
        1,  # DWORD     cntThreads;
        4,  # DWORD     th32ParentProcessID;
        0xbeef,  # LONG      pcPriClassBase;
        0x0,  # DWORD     dwFlags;
        "explorer.exe"  # TCHAR     szExeFile[MAX_PATH];
    ],

    [
        0x40,  # DWORD     dwSize;
        0,  # DWORD     cntUsage;
        winobjs.dw_pid_dummy2,  # DWORD     th32ProcessID;
        0x11111111,  # ULONG_PTR th32DefaultHeapID;
        0x11111112,  # DWORD     th32ModuleID;
        1,  # DWORD     cntThreads;
        winobjs.dw_pid_explorer,  # DWORD     th32ParentProcessID;
        0xbeef,  # LONG      pcPriClassBase;
        0x0,  # DWORD     dwFlags;
        "dummy2.exe"  # TCHAR     szExeFile[MAX_PATH];
    ],

    [
        0x40,  # DWORD     dwSize;
        0,  # DWORD     cntUsage;
        winobjs.dw_pid_cur,  # DWORD     th32ProcessID;
        0x11111111,  # ULONG_PTR th32DefaultHeapID;
        0x11111112,  # DWORD     th32ModuleID;
        1,  # DWORD     cntThreads;
        winobjs.dw_pid_explorer,  # DWORD     th32ParentProcessID;
        0xbeef,  # LONG      pcPriClassBase;
        0x0,  # DWORD     dwFlags;
        winobjs.module_name  # TCHAR     szExeFile[MAX_PATH];
    ],


]


class hobj:
    pass


class mdl:

    def __init__(self, ad, l):
        self.ad = ad
        self.l = l

    def __str__(self):
        return struct.pack('LL', self.ad, self.l)


def kernel32_HeapAlloc(jitter):
    ret_ad, args = jitter.func_args_stdcall(["heap", "flags", "size"])
    alloc_addr = winobjs.heap.alloc(jitter, args.size)
    jitter.func_ret_stdcall(ret_ad, alloc_addr)


def kernel32_HeapFree(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["heap", "flags", "pmem"])
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_GlobalAlloc(jitter):
    ret_ad, args = jitter.func_args_stdcall(["uflags", "msize"])
    alloc_addr = winobjs.heap.alloc(jitter, args.msize)
    jitter.func_ret_stdcall(ret_ad, alloc_addr)


def kernel32_LocalFree(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["lpvoid"])
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_LocalAlloc(jitter):
    ret_ad, args = jitter.func_args_stdcall(["uflags", "msize"])
    alloc_addr = winobjs.heap.alloc(jitter, args.msize)
    jitter.func_ret_stdcall(ret_ad, alloc_addr)

def msvcrt_new(jitter):
    ret_ad, args = jitter.func_args_cdecl(["size"])
    alloc_addr = winobjs.heap.alloc(jitter, args.size)
    jitter.func_ret_cdecl(ret_ad, alloc_addr)

globals()['msvcrt_??2@YAPAXI@Z'] = msvcrt_new

def msvcrt_delete(jitter):
    ret_ad, args = jitter.func_args_cdecl(["ptr"])
    jitter.func_ret_cdecl(ret_ad, 0)

globals()['msvcrt_??3@YAXPAX@Z'] = msvcrt_delete

def kernel32_GlobalFree(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["addr"])
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_IsDebuggerPresent(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, winobjs.dbg_present)


def kernel32_CreateToolhelp32Snapshot(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["dwflags", "th32processid"])
    jitter.func_ret_stdcall(ret_ad, winobjs.handle_toolhelpsnapshot)


def kernel32_GetCurrentProcess(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, winobjs.handle_curprocess)


def kernel32_GetCurrentProcessId(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, winobjs.dw_pid_cur)


def kernel32_Process32First(jitter):
    ret_ad, args = jitter.func_args_stdcall(["s_handle", "ad_pentry"])

    pentry = struct.pack(
        'IIIIIIIII', *process_list[0][:-1]) + process_list[0][-1]
    jitter.vm.set_mem(args.ad_pentry, pentry)
    winobjs.toolhelpsnapshot_info[args.s_handle] = 0

    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_Process32Next(jitter):
    ret_ad, args = jitter.func_args_stdcall(["s_handle", "ad_pentry"])

    winobjs.toolhelpsnapshot_info[args.s_handle] += 1
    if winobjs.toolhelpsnapshot_info[args.s_handle] >= len(process_list):
        ret = 0
    else:
        ret = 1
        n = winobjs.toolhelpsnapshot_info[args.s_handle]
        pentry = struct.pack(
            'IIIIIIIII', *process_list[n][:-1]) + process_list[n][-1]
        jitter.vm.set_mem(args.ad_pentry, pentry)
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_GetTickCount(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    winobjs.tickcount += 1
    jitter.func_ret_stdcall(ret_ad, winobjs.tickcount)


def kernel32_GetVersion(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, winobjs.getversion)


def kernel32_GetVersionEx(jitter, str_size, set_str):
    ret_ad, args = jitter.func_args_stdcall(["ptr_struct"])

    size = jitter.vm.get_u32(args.ptr_struct)
    if size in [0x14+str_size, 0x1c+str_size]:
        tmp = struct.pack("IIIII%dsHHHBB" % str_size,
                          0x114,            # struct size
                          0x5,              # maj vers
                          0x2,              # min vers
                          0xa28,            # build nbr
                          0x2,              # platform id
                          set_str("Service pack 4"),
                          3,                # wServicePackMajor
                          0,                # wServicePackMinor
                          0x100,            # wSuiteMask
                          1,                # wProductType
                          0                 # wReserved
                          )
        tmp = tmp[:size]
        jitter.vm.set_mem(args.ptr_struct, tmp)
        ret = 1
    else:
        ret = 0
    jitter.func_ret_stdcall(ret_ad, ret)


kernel32_GetVersionExA = lambda jitter: kernel32_GetVersionEx(jitter, 128,
                                                              set_str_ansi)
kernel32_GetVersionExW = lambda jitter: kernel32_GetVersionEx(jitter, 256,
                                                              set_str_unic)


def kernel32_GetPriorityClass(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hwnd"])
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_SetPriorityClass(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hwnd", "dwpclass"])
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_CloseHandle(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hwnd"])
    jitter.func_ret_stdcall(ret_ad, 1)


def user32_GetForegroundWindow(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, winobjs.getforegroundwindow)


def user32_FindWindowA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["pclassname", "pwindowname"])
    if args.pclassname:
        classname = jitter.get_str_ansi(args.pclassname)
        log.info("FindWindowA classname %s", classname)
    if args.pwindowname:
        windowname = jitter.get_str_ansi(args.pwindowname)
        log.info("FindWindowA windowname %s", windowname)
    jitter.func_ret_stdcall(ret_ad, 0)


def user32_GetTopWindow(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hwnd"])
    jitter.func_ret_stdcall(ret_ad, 0)


def user32_BlockInput(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["blockit"])
    jitter.func_ret_stdcall(ret_ad, 1)


def advapi32_CryptAcquireContext(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["phprov", "pszcontainer",
                                             "pszprovider", "dwprovtype",
                                             "dwflags"])
    prov = get_str(args.pszprovider) if args.pszprovider else "NONE"
    log.debug('prov: %r', prov)
    jitter.vm.set_u32(args.phprov, winobjs.cryptcontext_hwnd)
    jitter.func_ret_stdcall(ret_ad, 1)


def advapi32_CryptAcquireContextA(jitter):
    advapi32_CryptAcquireContext(jitter, whoami(), jitter.get_str_ansi)


def advapi32_CryptAcquireContextW(jitter):
    advapi32_CryptAcquireContext(jitter, whoami(), jitter.get_str_unic)


def advapi32_CryptCreateHash(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hprov", "algid", "hkey",
                                             "dwflags", "phhash"])

    winobjs.cryptcontext_num += 1

    if args.algid == 0x00008003:
        log.debug('algo is MD5')
        jitter.vm.set_u32(
            args.phhash,
            winobjs.cryptcontext_bnum + winobjs.cryptcontext_num
        )
        winobjs.cryptcontext[
            winobjs.cryptcontext_bnum + winobjs.cryptcontext_num] = hobj()
        winobjs.cryptcontext[
            winobjs.cryptcontext_bnum + winobjs.cryptcontext_num].h = MD5.new()
    elif args.algid == 0x00008004:
        log.debug('algo is SHA1')
        jitter.vm.set_u32(
            args.phhash,
            winobjs.cryptcontext_bnum + winobjs.cryptcontext_num
        )
        winobjs.cryptcontext[
            winobjs.cryptcontext_bnum + winobjs.cryptcontext_num] = hobj()
        winobjs.cryptcontext[
            winobjs.cryptcontext_bnum + winobjs.cryptcontext_num].h = SHA.new()
    else:
        raise ValueError('un impl algo1')
    jitter.func_ret_stdcall(ret_ad, 1)


def advapi32_CryptHashData(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hhash", "pbdata", "dwdatalen",
                                             "dwflags"])

    if not args.hhash in winobjs.cryptcontext:
        raise ValueError("unknown crypt context")

    data = jitter.vm.get_mem(args.pbdata, args.dwdatalen)
    log.debug('will hash %X', args.dwdatalen)
    log.debug(repr(data[:10]) + "...")
    winobjs.cryptcontext[args.hhash].h.update(data)
    jitter.func_ret_stdcall(ret_ad, 1)


def advapi32_CryptGetHashParam(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hhash", "param", "pbdata",
                                             "dwdatalen", "dwflags"])

    if not args.hhash in winobjs.cryptcontext:
        raise ValueError("unknown crypt context")

    if args.param == 2:
        # XXX todo: save h state?
        h = winobjs.cryptcontext[args.hhash].h.digest()
    else:
        raise ValueError('not impl', args.param)
    jitter.vm.set_mem(args.pbdata, h)
    jitter.vm.set_u32(args.dwdatalen, len(h))

    jitter.func_ret_stdcall(ret_ad, 1)


def advapi32_CryptReleaseContext(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hhash", "flags"])
    jitter.func_ret_stdcall(ret_ad, 0)


def advapi32_CryptDeriveKey(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hprov", "algid", "hbasedata",
                                             "dwflags", "phkey"])

    if args.algid == 0x6801:
        log.debug('using DES')
    else:
        raise ValueError('un impl algo2')
    h = winobjs.cryptcontext[args.hbasedata].h.digest()
    log.debug('hash %r', h)
    winobjs.cryptcontext[args.hbasedata].h_result = h
    jitter.vm.set_u32(args.phkey, args.hbasedata)
    jitter.func_ret_stdcall(ret_ad, 1)


def advapi32_CryptDestroyHash(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hhash"])
    jitter.func_ret_stdcall(ret_ad, 1)


def advapi32_CryptDecrypt(jitter):
    # ret_ad, _ = jitter.func_args_stdcall(["hkey", "hhash", "final",
    #                                       "dwflags", "pbdata",
    #                                       "pdwdatalen"])
    raise ValueError("Not implemented")
    # jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_CreateFile(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["lpfilename", "access",
                                             "dwsharedmode",
                                             "lpsecurityattr",
                                             "dwcreationdisposition",
                                             "dwflagsandattr",
                                             "htemplatefile"])
    if args.lpfilename == 0:
        jitter.func_ret_stdcall(ret_ad, 0xffffffff)
        return

    fname = get_str(args.lpfilename)
    log.info('CreateFile fname %s', fname)
    ret = 0xffffffff

    log.debug("%r %r", fname.lower(), winobjs.module_path.lower())
    is_original_file = fname.lower() == winobjs.module_path.lower()

    if fname.upper() in [r"\\.\SICE", r"\\.\NTICE", r"\\.\SIWVID", r'\\.\SIWDEBUG']:
        pass
    elif fname.upper() in ['NUL']:
        ret = winobjs.module_cur_hwnd
    else:
        # sandox path
        sb_fname = windows_to_sbpath(fname)
        if args.access & 0x80000000 or args.access == 1:
            # read
            if args.dwcreationdisposition == 2:
                # create_always
                if os.access(sb_fname, os.R_OK):
                    # but file exist
                    pass
                else:
                    raise NotImplementedError("Untested case")  # to test
                    # h = open(sb_fname, 'rb+')
            elif args.dwcreationdisposition == 3:
                # open_existing
                if os.access(sb_fname, os.R_OK):
                    s = os.stat(sb_fname)
                    if stat.S_ISDIR(s.st_mode):
                        ret = winobjs.handle_pool.add(sb_fname, 0x1337)
                    else:
                        h = open(sb_fname, 'r+b')
                        ret = winobjs.handle_pool.add(sb_fname, h)
                else:
                    log.warning("FILE %r DOES NOT EXIST!", fname)
            elif args.dwcreationdisposition == 1:
                # create new
                if os.access(sb_fname, os.R_OK):
                    # file exist
                    # ret = 80
                    winobjs.lastwin32error = 80
                else:
                    # first create an empty file
                    open(sb_fname, 'w').close()
                    # then open
                    h = open(sb_fname, 'r+b')
                    ret = winobjs.handle_pool.add(sb_fname, h)
            elif args.dwcreationdisposition == 4:
                # open_always
                if os.access(sb_fname, os.R_OK):
                    s = os.stat(sb_fname)
                    if stat.S_ISDIR(s.st_mode):
                        ret = winobjs.handle_pool.add(sb_fname, 0x1337)
                    else:
                        h = open(sb_fname, 'r+b')
                        ret = winobjs.handle_pool.add(sb_fname, h)
                else:
                    raise NotImplementedError("Untested case")
            else:
                raise NotImplementedError("Untested case")
        elif args.access & 0x40000000:
            # write
            if args.dwcreationdisposition == 3:
                # open existing
                if is_original_file:
                    # cannot open self in write mode!
                    pass
                elif os.access(sb_fname, os.R_OK):
                    s = os.stat(sb_fname)
                    if stat.S_ISDIR(s.st_mode):
                        # open dir
                        ret = winobjs.handle_pool.add(sb_fname, 0x1337)
                    else:
                        h = open(sb_fname, 'r+b')
                        ret = winobjs.handle_pool.add(sb_fname, h)
                else:
                    raise NotImplementedError("Untested case")  # to test
            elif args.dwcreationdisposition == 5:
                # truncate_existing
                if is_original_file:
                    pass
                else:
                    raise NotImplementedError("Untested case")  # to test
            else:
                # raise NotImplementedError("Untested case") # to test
                h = open(sb_fname, 'w')
                ret = winobjs.handle_pool.add(sb_fname, h)
        else:
            raise NotImplementedError("Untested case")

        # h = open(sb_fname, 'rb+')
        # ret = winobjs.handle_pool.add(sb_fname, h)
    log.debug('CreateFile ret %x', ret)
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_CreateFileA(jitter):
    kernel32_CreateFile(jitter, whoami(), jitter.get_str_ansi)


def kernel32_CreateFileW(jitter):
    kernel32_CreateFile(jitter, whoami(), jitter.get_str_unic)


def kernel32_ReadFile(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hwnd", "lpbuffer",
                                             "nnumberofbytestoread",
                                             "lpnumberofbytesread",
                                             "lpoverlapped"])
    if args.hwnd == winobjs.module_cur_hwnd:
        pass
    elif args.hwnd in winobjs.handle_pool:
        pass
    else:
        raise ValueError('unknown hwnd!')

    data = None
    if args.hwnd in winobjs.files_hwnd:
        data = winobjs.files_hwnd[
            winobjs.module_cur_hwnd].read(args.nnumberofbytestoread)
    elif args.hwnd in winobjs.handle_pool:
        wh = winobjs.handle_pool[args.hwnd]
        data = wh.info.read(args.nnumberofbytestoread)
    else:
        raise ValueError('unknown filename')

    if data is not None:
        if (args.lpnumberofbytesread):
            jitter.vm.set_u32(args.lpnumberofbytesread, len(data))
        jitter.vm.set_mem(args.lpbuffer, data)

    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_GetFileSize(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hwnd", "lpfilesizehight"])

    if args.hwnd == winobjs.module_cur_hwnd:
        ret = len(open(winobjs.module_fname_nux).read())
    elif args.hwnd in winobjs.handle_pool:
        wh = winobjs.handle_pool[args.hwnd]
        ret = len(open(wh.name).read())
    else:
        raise ValueError('unknown hwnd!')

    if args.lpfilesizehight != 0:
        jitter.vm.set_u32(args.lpfilesizehight, ret)
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_GetFileSizeEx(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hwnd", "lpfilesizehight"])

    if args.hwnd == winobjs.module_cur_hwnd:
        l = len(open(winobjs.module_fname_nux).read())
    elif args.hwnd in winobjs.handle_pool:
        wh = winobjs.handle_pool[args.hwnd]
        l = len(open(wh.name).read())
    else:
        raise ValueError('unknown hwnd!')

    if args.lpfilesizehight == 0:
        raise NotImplementedError("Untested case")
    jitter.vm.set_mem(args.lpfilesizehight, pck32(
        l & 0xffffffff) + pck32((l >> 32) & 0xffffffff))
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_FlushInstructionCache(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hprocess", "lpbasead", "dwsize"])
    jitter.func_ret_stdcall(ret_ad, 0x1337)


def kernel32_VirtualProtect(jitter):
    ret_ad, args = jitter.func_args_stdcall(['lpvoid', 'dwsize',
                                             'flnewprotect',
                                             'lpfloldprotect'])
    # XXX mask hpart
    flnewprotect = args.flnewprotect & 0xFFF
    if not flnewprotect in ACCESS_DICT:
        raise ValueError('unknown access dw!')

    if args.lpfloldprotect:
        old = jitter.vm.get_mem_access(args.lpvoid)
        jitter.vm.set_u32(args.lpfloldprotect, ACCESS_DICT_INV[old])

    for addr in jitter.vm.get_all_memory():
        # Multi-page
        if args.lpvoid <= addr < args.lpvoid + args.dwsize:
            jitter.vm.set_mem_access(addr, ACCESS_DICT[flnewprotect])

    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_VirtualAlloc(jitter):
    ret_ad, args = jitter.func_args_stdcall(['lpvoid', 'dwsize',
                                             'alloc_type', 'flprotect'])


    if not args.flprotect in ACCESS_DICT:
        raise ValueError('unknown access dw!')

    if args.lpvoid == 0:
        alloc_addr = winobjs.heap.next_addr(args.dwsize)
        jitter.vm.add_memory_page(
            alloc_addr, ACCESS_DICT[args.flprotect], "\x00" * args.dwsize,
            "Alloc in %s ret 0x%X" % (whoami(), ret_ad))
    else:
        all_mem = jitter.vm.get_all_memory()
        if args.lpvoid in all_mem:
            alloc_addr = args.lpvoid
            jitter.vm.set_mem_access(args.lpvoid, ACCESS_DICT[args.flprotect])
        else:
            alloc_addr = winobjs.heap.next_addr(args.dwsize)
            # alloc_addr = args.lpvoid
            jitter.vm.add_memory_page(
                alloc_addr, ACCESS_DICT[args.flprotect], "\x00" * args.dwsize,
                "Alloc in %s ret 0x%X" % (whoami(), ret_ad))

    log.info('VirtualAlloc addr: 0x%x', alloc_addr)
    jitter.func_ret_stdcall(ret_ad, alloc_addr)


def kernel32_VirtualFree(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["lpvoid", "dwsize", "alloc_type"])
    jitter.func_ret_stdcall(ret_ad, 0)


def user32_GetWindowLongA(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hwnd", "nindex"])
    jitter.func_ret_stdcall(ret_ad, winobjs.windowlong_dw)


def user32_SetWindowLongA(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["hwnd", "nindex", "newlong"])
    jitter.func_ret_stdcall(ret_ad, winobjs.windowlong_dw)


def kernel32_GetModuleFileName(jitter, funcname, set_str):
    ret_ad, args = jitter.func_args_stdcall(["hmodule", "lpfilename", "nsize"])

    if args.hmodule in [0, winobjs.hcurmodule]:
        p = winobjs.module_path[:]
    elif (winobjs.runtime_dll and
          args.hmodule in winobjs.runtime_dll.name2off.values()):
        name_inv = dict([(x[1], x[0])
                        for x in winobjs.runtime_dll.name2off.items()])
        p = name_inv[args.hmodule]
    else:
        log.warning(('Unknown module 0x%x.' +
                     'Set winobjs.hcurmodule and retry'), args.hmodule)
        p = None

    if p is None:
        l = 0
    elif args.nsize < len(p):
        p = p[:args.nsize]
        l = len(p)
    else:
        l = len(p)

    if p:
        set_str(args.lpfilename, p)

    jitter.func_ret_stdcall(ret_ad, l)


def kernel32_GetModuleFileNameA(jitter):
    kernel32_GetModuleFileName(jitter, whoami(), jitter.set_str_ansi)


def kernel32_GetModuleFileNameW(jitter):
    kernel32_GetModuleFileName(jitter, whoami(), jitter.set_str_unic)


def kernel32_CreateMutex(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["mutexattr", "initowner",
                                             "lpname"])

    if args.lpname:
        name = get_str(args.lpname)
        log.info("CreateMutex %r", name)
    else:
        name = None
    if args.initowner:
        if name in winobjs.mutex:
            raise NotImplementedError("Untested case")
            # ret = 0
        else:
            winobjs.mutex[name] = id(name)
            ret = winobjs.mutex[name]
    else:
        if name in winobjs.mutex:
            raise NotImplementedError("Untested case")
            # ret = 0
        else:
            winobjs.mutex[name] = id(name)
            ret = winobjs.mutex[name]
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_CreateMutexA(jitter):
    kernel32_CreateMutex(jitter, whoami(), jitter.get_str_ansi)


def kernel32_CreateMutexW(jitter):
    kernel32_CreateMutex(jitter, whoami(), jitter.get_str_unic)


def shell32_SHGetSpecialFolderLocation(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hwndowner", "nfolder", "ppidl"])
    jitter.vm.set_u32(args.ppidl, args.nfolder)
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_SHGetPathFromIDList(jitter, funcname, set_str):
    ret_ad, args = jitter.func_args_stdcall(["pidl", "ppath"])

    if args.pidl == 7:  # CSIDL_STARTUP:
        s = "c:\\doc\\user\\startmenu\\programs\\startup"
        set_str(args.ppath, s)
    else:
        raise ValueError('pidl not implemented', args.pidl)
    jitter.func_ret_stdcall(ret_ad, 1)


def shell32_SHGetPathFromIDListW(jitter):
    kernel32_SHGetPathFromIDList(jitter, whoami(), jitter.set_str_unic)


def shell32_SHGetPathFromIDListA(jitter):
    kernel32_SHGetPathFromIDList(jitter, whoami(), jitter.set_str_ansi)


def kernel32_GetLastError(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, winobjs.lastwin32error)


def kernel32_SetLastError(jitter):
    ret_ad, args = jitter.func_args_stdcall(["errcode"])
    # lasterr addr
    # ad = tib_address + 0x34
    # jitter.vm.set_mem(ad, pck32(args.errcode))
    winobjs.lastwin32error = args.errcode
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_RestoreLastError(jitter):
    kernel32_SetLastError(jitter)


def kernel32_LoadLibrary(jitter, get_str):
    ret_ad, args = jitter.func_args_stdcall(["dllname"])

    libname = get_str(args.dllname, 0x100)
    ret = winobjs.runtime_dll.lib_get_add_base(libname)
    log.info("Loading %r ret 0x%x", libname, ret)
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_LoadLibraryA(jitter):
    kernel32_LoadLibrary(jitter, jitter.get_str_ansi)


def kernel32_LoadLibraryW(jitter):
    kernel32_LoadLibrary(jitter, jitter.get_str_unic)


def kernel32_LoadLibraryEx(jitter, get_str):
    ret_ad, args = jitter.func_args_stdcall(["dllname", "hfile", "flags"])

    if args.hfile != 0:
        raise NotImplementedError("Untested case")
    libname = get_str(args.dllname, 0x100)
    ret = winobjs.runtime_dll.lib_get_add_base(libname)
    log.info("Loading %r ret 0x%x", libname, ret)
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_LoadLibraryExA(jitter):
    kernel32_LoadLibraryEx(jitter, jitter.get_str_ansi)


def kernel32_LoadLibraryExW(jitter):
    kernel32_LoadLibraryEx(jitter, jitter.get_str_unic)


def kernel32_GetProcAddress(jitter):
    ret_ad, args = jitter.func_args_stdcall(["libbase", "fname"])
    fname = args.fname
    if fname >= 0x10000:
        fname = jitter.get_str_ansi(fname, 0x100)
        if not fname:
            fname = None
    if fname is not None:
        ad = winobjs.runtime_dll.lib_get_add_func(args.libbase, fname)
    else:
        ad = 0
    log.info("GetProcAddress %r %r ret 0x%x", args.libbase, fname, ad)
    jitter.add_breakpoint(ad, jitter.handle_lib)
    jitter.func_ret_stdcall(ret_ad, ad)


def kernel32_GetModuleHandle(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["dllname"])

    if args.dllname:
        libname = get_str(args.dllname)
        if libname:
            ret = winobjs.runtime_dll.lib_get_add_base(libname)
        else:
            log.warning('unknown module!')
            ret = 0
        log.info("GetModuleHandle %r ret 0x%x", libname, ret)
    else:
        ret = winobjs.current_pe.NThdr.ImageBase
        log.info("GetModuleHandle default ret 0x%x", ret)
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_GetModuleHandleA(jitter):
    kernel32_GetModuleHandle(jitter, whoami(), jitter.get_str_ansi)


def kernel32_GetModuleHandleW(jitter):
    kernel32_GetModuleHandle(jitter, whoami(), jitter.get_str_unic)


def kernel32_VirtualLock(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["lpaddress", "dwsize"])
    jitter.func_ret_stdcall(ret_ad, 1)


class systeminfo:
    oemId = 0
    dwPageSize = 0x1000
    lpMinimumApplicationAddress = 0x10000
    lpMaximumApplicationAddress = 0x7ffeffff
    dwActiveProcessorMask = 0x1
    numberOfProcessors = 0x1
    ProcessorsType = 586
    dwAllocationgranularity = 0x10000
    wProcessorLevel = 0x6
    ProcessorRevision = 0xf0b

    def pack(self):
        return struct.pack('IIIIIIIIHH',
                           self.oemId,
                           self.dwPageSize,
                           self.lpMinimumApplicationAddress,
                           self.lpMaximumApplicationAddress,
                           self.dwActiveProcessorMask,
                           self.numberOfProcessors,
                           self.ProcessorsType,
                           self.dwAllocationgranularity,
                           self.wProcessorLevel,
                           self.ProcessorRevision)


def kernel32_GetSystemInfo(jitter):
    ret_ad, args = jitter.func_args_stdcall(["sys_ptr"])
    sysinfo = systeminfo()
    jitter.vm.set_mem(args.sys_ptr, sysinfo.pack())
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_IsWow64Process(jitter):
    ret_ad, args = jitter.func_args_stdcall(["process", "bool_ptr"])
    jitter.vm.set_u32(args.bool_ptr, 0)
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_GetCommandLine(jitter, set_str):
    ret_ad, _ = jitter.func_args_stdcall(0)
    alloc_addr = winobjs.heap.alloc(jitter, 0x1000)
    s = set_str('"%s"' % winobjs.module_path)
    jitter.vm.set_mem(alloc_addr, s)
    jitter.func_ret_stdcall(ret_ad, alloc_addr)


def kernel32_GetCommandLineA(jitter):
    kernel32_GetCommandLine(jitter, set_str_ansi)


def kernel32_GetCommandLineW(jitter):
    kernel32_GetCommandLine(jitter, set_str_unic)


def shell32_CommandLineToArgvW(jitter):
    ret_ad, args = jitter.func_args_stdcall(["pcmd", "pnumargs"])
    cmd = jitter.get_str_unic(args.pcmd)
    log.info("CommandLineToArgv %r", cmd)
    tks = cmd.split(' ')
    addr = winobjs.heap.alloc(jitter, len(cmd) * 2 + 4 * len(tks))
    addr_ret = winobjs.heap.alloc(jitter, 4 * (len(tks) + 1))
    o = 0
    for i, t in enumerate(tks):
        jitter.set_str_unic(addr + o, t)
        jitter.vm.set_u32(addr_ret + 4 * i, addr + o)
        o += len(t)*2 + 2

    jitter.vm.set_u32(addr_ret + 4 * i, 0)
    jitter.vm.set_u32(args.pnumargs, len(tks))
    jitter.func_ret_stdcall(ret_ad, addr_ret)


def cryptdll_MD5Init(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ad_ctx"])
    index = len(winobjs.cryptdll_md5_h)
    h = MD5.new()
    winobjs.cryptdll_md5_h[index] = h

    jitter.vm.set_u32(args.ad_ctx, index)
    jitter.func_ret_stdcall(ret_ad, 0)


def cryptdll_MD5Update(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ad_ctx", "ad_input", "inlen"])

    index = jitter.vm.get_u32(args.ad_ctx)
    if not index in winobjs.cryptdll_md5_h:
        raise ValueError('unknown h context', index)

    data = jitter.vm.get_mem(args.ad_input, args.inlen)
    winobjs.cryptdll_md5_h[index].update(data)
    log.debug(hexdump(data))

    jitter.func_ret_stdcall(ret_ad, 0)


def cryptdll_MD5Final(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ad_ctx"])

    index = jitter.vm.get_u32(args.ad_ctx)
    if not index in winobjs.cryptdll_md5_h:
        raise ValueError('unknown h context', index)
    h = winobjs.cryptdll_md5_h[index].digest()
    jitter.vm.set_mem(args.ad_ctx + 88, h)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_RtlInitAnsiString(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ad_ctx", "ad_str"])

    s = jitter.get_str_ansi(args.ad_str)
    l = len(s)
    jitter.vm.set_mem(args.ad_ctx,
                      pck16(l) + pck16(l + 1) + pck32(args.ad_str))
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_RtlHashUnicodeString(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ad_ctxu", "case_i", "h_id",
                                             "phout"])

    if args.h_id != 1:
        raise ValueError('unk hash unicode', args.h_id)

    l1, l2, ptra = struct.unpack('HHL', jitter.vm.get_mem(args.ad_ctxu, 8))
    s = jitter.vm.get_mem(ptra, l1)
    s = s[:-1]
    hv = 0

    if args.case_i:
        s = s.lower()
    for c in s:
        hv = ((65599 * hv) + ord(c)) & 0xffffffff
    jitter.vm.set_u32(args.phout, hv)
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_RtlMoveMemory(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ad_dst", "ad_src", "m_len"])
    data = jitter.vm.get_mem(args.ad_src, args.m_len)
    jitter.vm.set_mem(args.ad_dst, data)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_RtlAnsiCharToUnicodeChar(jitter):
    ret_ad, args = jitter.func_args_stdcall(['ad_ad_ch'])
    ad_ch = jitter.vm.get_u32(args.ad_ad_ch)
    ch = ord(jitter.vm.get_mem(ad_ch, 1))
    jitter.vm.set_u32(args.ad_ad_ch, ad_ch + 1)
    jitter.func_ret_stdcall(ret_ad, ch)


def ntdll_RtlFindCharInUnicodeString(jitter):
    ret_ad, args = jitter.func_args_stdcall(["flags", "main_str_ad",
                                             "search_chars_ad", "pos_ad"])

    if args.flags != 0:
        raise ValueError('unk flags')

    ml1, ml2, mptra = struct.unpack('HHL',
                                    jitter.vm.get_mem(args.main_str_ad, 8))
    sl1, sl2, sptra = struct.unpack(
        'HHL', jitter.vm.get_mem(args.search_chars_ad, 8))
    main_data = jitter.vm.get_mem(mptra, ml1)[:-1]
    search_data = jitter.vm.get_mem(sptra, sl1)[:-1]

    pos = None
    for i, c in enumerate(main_data):
        for s in search_data:
            if s == c:
                pos = i
                break
        if pos:
            break
    if pos is None:
        ret = 0xC0000225
        jitter.vm.set_u32(args.pos_ad, 0)
    else:
        ret = 0
        jitter.vm.set_u32(args.pos_ad, pos)

    jitter.func_ret_stdcall(ret_ad, ret)


def ntdll_RtlComputeCrc32(jitter):
    ret_ad, args = jitter.func_args_stdcall(["dwinit", "pdata", "ilen"])
    data = jitter.vm.get_mem(args.pdata, args.ilen)
    crc_r = crc32(data, args.dwinit)
    jitter.func_ret_stdcall(ret_ad, crc_r)


def ntdll_RtlExtendedIntegerMultiply(jitter):
    ret_ad, args = jitter.func_args_stdcall(['multiplicand_low',
                                             'multiplicand_high',
                                             'multiplier'])
    a = (args.multiplicand_high << 32) + args.multiplicand_low
    a = a * args.multiplier
    jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff)


def ntdll_RtlLargeIntegerAdd(jitter):
    ret_ad, args = jitter.func_args_stdcall(['a_low', 'a_high',
                                             'b_low', 'b_high'])
    a = (args.a_high << 32) + args.a_low + (args.b_high << 32) + args.b_low
    jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff)


def ntdll_RtlLargeIntegerShiftRight(jitter):
    ret_ad, args = jitter.func_args_stdcall(['a_low', 'a_high', 's_count'])
    a = ((args.a_high << 32) + args.a_low) >> args.s_count
    jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff)


def ntdll_RtlEnlargedUnsignedMultiply(jitter):
    ret_ad, args = jitter.func_args_stdcall(['a', 'b'])
    a = args.a * args.b
    jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff)


def ntdll_RtlLargeIntegerSubtract(jitter):
    ret_ad, args = jitter.func_args_stdcall(['a_low', 'a_high',
                                             'b_low', 'b_high'])
    a = (args.a_high << 32) + args.a_low - (args.b_high << 32) + args.b_low
    jitter.func_ret_stdcall(ret_ad, a & 0xffffffff, (a >> 32) & 0xffffffff)


def ntdll_RtlCompareMemory(jitter):
    ret_ad, args = jitter.func_args_stdcall(['ad1', 'ad2', 'm_len'])
    data1 = jitter.vm.get_mem(args.ad1, args.m_len)
    data2 = jitter.vm.get_mem(args.ad2, args.m_len)

    i = 0
    while data1[i] == data2[i]:
        i += 1
        if i >= args.m_len:
            break

    jitter.func_ret_stdcall(ret_ad, i)


def user32_GetMessagePos(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, 0x00110022)


def kernel32_Sleep(jitter):
    ret_ad, _ = jitter.func_args_stdcall(['t'])
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_ZwUnmapViewOfSection(jitter):
    ret_ad, _ = jitter.func_args_stdcall(['h', 'ad'])
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_IsBadReadPtr(jitter):
    ret_ad, _ = jitter.func_args_stdcall(['lp', 'ucb'])
    jitter.func_ret_stdcall(ret_ad, 0)


def ntoskrnl_KeInitializeEvent(jitter):
    ret_ad, args = jitter.func_args_stdcall(['my_event', 'my_type',
                                             'my_state'])
    jitter.vm.set_u32(args.my_event, winobjs.win_event_num)
    winobjs.win_event_num += 1

    jitter.func_ret_stdcall(ret_ad, 0)


def ntoskrnl_RtlGetVersion(jitter):
    ret_ad, args = jitter.func_args_stdcall(['ptr_version'])

    s = struct.pack("IIIII",
                    0x114,  # struct size
                    0x5,   # maj vers
                    0x2,  # min vers
                    0x666,  # build nbr
                    0x2,   # platform id
                    ) + jitter.set_str_unic("Service pack 4")

    jitter.vm.set_mem(args.ptr_version, s)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntoskrnl_RtlVerifyVersionInfo(jitter):
    ret_ad, args = jitter.func_args_stdcall(['ptr_version'])

    s = jitter.vm.get_mem(args.ptr_version, 0x5 * 4)
    s_size, s_majv, s_minv, s_buildn, s_platform = struct.unpack('IIIII', s)
    raise NotImplementedError("Untested case")
    # jitter.vm.set_mem(args.ptr_version, s)
    # jitter.func_ret_stdcall(ret_ad, 0)


def hal_ExAcquireFastMutex(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, 0)


def mdl2ad(n):
    return winobjs.nt_mdl_ad + 0x10 * n


def ad2mdl(ad):
    return ((ad - winobjs.nt_mdl_ad) & 0xFFFFFFFFL) / 0x10


def ntoskrnl_IoAllocateMdl(jitter):
    ret_ad, args = jitter.func_args_stdcall(["v_addr", "l", "second_buf",
                                             "chargequota", "pirp"])
    m = mdl(args.v_addr, args.l)
    winobjs.nt_mdl[winobjs.nt_mdl_cur] = m
    jitter.vm.set_mem(mdl2ad(winobjs.nt_mdl_cur), str(m))
    jitter.func_ret_stdcall(ret_ad, mdl2ad(winobjs.nt_mdl_cur))
    winobjs.nt_mdl_cur += 1


def ntoskrnl_MmProbeAndLockPages(jitter):
    ret_ad, args = jitter.func_args_stdcall(["p_mdl", "access_mode", "op"])

    if not ad2mdl(args.p_mdl) in winobjs.nt_mdl:
        raise ValueError('unk mdl', hex(args.p_mdl))
    jitter.func_ret_stdcall(ret_ad, 0)


def ntoskrnl_MmMapLockedPagesSpecifyCache(jitter):
    ret_ad, args = jitter.func_args_stdcall(["p_mdl", "access_mode",
                                             "cache_type", "base_ad",
                                             "bugcheckonfailure",
                                             "priority"])
    if not ad2mdl(args.p_mdl) in winobjs.nt_mdl:
        raise ValueError('unk mdl', hex(args.p_mdl))

    jitter.func_ret_stdcall(ret_ad, winobjs.nt_mdl[ad2mdl(args.p_mdl)].ad)


def ntoskrnl_MmProtectMdlSystemAddress(jitter):
    ret_ad, args = jitter.func_args_stdcall(["p_mdl", "prot"])
    if not ad2mdl(args.p_mdl) in winobjs.nt_mdl:
        raise ValueError('unk mdl', hex(args.p_mdl))

    jitter.func_ret_stdcall(ret_ad, 0)


def ntoskrnl_MmUnlockPages(jitter):
    ret_ad, args = jitter.func_args_stdcall(['p_mdl'])
    if not ad2mdl(args.p_mdl) in winobjs.nt_mdl:
        raise ValueError('unk mdl', hex(args.p_mdl))

    jitter.func_ret_stdcall(ret_ad, 0)


def ntoskrnl_IoFreeMdl(jitter):
    ret_ad, args = jitter.func_args_stdcall(['p_mdl'])
    if not ad2mdl(args.p_mdl) in winobjs.nt_mdl:
        raise ValueError('unk mdl', hex(args.p_mdl))
    del(winobjs.nt_mdl[ad2mdl(args.p_mdl)])
    jitter.func_ret_stdcall(ret_ad, 0)


def hal_ExReleaseFastMutex(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntoskrnl_RtlQueryRegistryValues(jitter):
    ret_ad, args = jitter.func_args_stdcall(["relativeto", "path",
                                             "querytable",
                                             "context",
                                             "environ"])
    # path = get_str_unic(jitter, args.path)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntoskrnl_ExAllocatePoolWithTagPriority(jitter):
    ret_ad, args = jitter.func_args_stdcall(["pool_type",
                                             "nbr_of_bytes",
                                             "tag", "priority"])
    alloc_addr = winobjs.heap.next_addr(args.nbr_of_bytes)
    jitter.vm.add_memory_page(
        alloc_addr, PAGE_READ | PAGE_WRITE, "\x00" * args.nbr_of_bytes,
        "Alloc in %s ret 0x%X" % (whoami(), ret_ad))

    jitter.func_ret_stdcall(ret_ad, alloc_addr)


def my_lstrcmp(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2"])
    s1 = get_str(args.ptr_str1)
    s2 = get_str(args.ptr_str2)
    log.info("Compare %r with %r", s1, s2)
    jitter.func_ret_stdcall(ret_ad, cmp(s1, s2))

def msvcrt_wcscmp(jitter):
    ret_ad, args = jitter.func_args_cdecl(["ptr_str1", "ptr_str2"])
    s1 = jitter.get_str_unic(args.ptr_str1)
    s2 = jitter.get_str_unic(args.ptr_str2)
    log.debug("%s('%s','%s')" % (whoami(), s1, s2))
    jitter.func_ret_cdecl(ret_ad, cmp(s1, s2))

def msvcrt__wcsicmp(jitter):
    ret_ad, args = jitter.func_args_cdecl(["ptr_str1", "ptr_str2"])
    s1 = jitter.get_str_unic(args.ptr_str1)
    s2 = jitter.get_str_unic(args.ptr_str2)
    log.debug("%s('%s','%s')" % (whoami(), s1, s2))
    jitter.func_ret_cdecl(ret_ad, cmp(s1.lower(), s2.lower()))

def msvcrt__wcsnicmp(jitter):
    ret_ad, args = jitter.func_args_cdecl(["ptr_str1", "ptr_str2", "count"])
    s1 = jitter.get_str_unic(args.ptr_str1)
    s2 = jitter.get_str_unic(args.ptr_str2)
    log.debug("%s('%s','%s',%d)" % (whoami(), s1, s2, args.count))
    jitter.func_ret_cdecl(ret_ad, cmp(s1.lower()[:args.count], s2.lower()[:args.count]))

def msvcrt_wcsncpy(jitter):
    ret_ad, args = jitter.func_args_cdecl(["dst", "src", "n"])
    src = jitter.get_str_unic(args.src)
    dst = src[:args.n]
    dst += "\x00\x00" * (args.n-len(dst)+1)
    jitter.vm.set_mem(args.dst, dst)
    jitter.func_ret_cdecl(ret_ad, args.dst)

def kernel32_lstrcmpA(jitter):
    my_lstrcmp(jitter, whoami(), jitter.get_str_ansi)


def kernel32_lstrcmpiA(jitter):
    my_lstrcmp(jitter, whoami(), lambda x: jitter.get_str_ansi(x).lower())


def kernel32_lstrcmpW(jitter):
    my_lstrcmp(jitter, whoami(), jitter.get_str_unic)


def kernel32_lstrcmpiW(jitter):
    my_lstrcmp(jitter, whoami(), lambda x: jitter.get_str_unic(x).lower())


def kernel32_lstrcmpi(jitter):
    my_lstrcmp(jitter, whoami(), lambda x: jitter.get_str_ansi(x).lower())


def my_strcpy(jitter, funcname, get_str, set_str):
    ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2"])
    s2 = get_str(args.ptr_str2)
    set_str(args.ptr_str1, s2)
    log.info("Copy '%r'", s2)
    jitter.func_ret_stdcall(ret_ad, args.ptr_str1)


def kernel32_lstrcpyW(jitter):
    my_strcpy(jitter, whoami(), jitter.get_str_unic, jitter.set_str_unic)


def kernel32_lstrcpyA(jitter):
    my_strcpy(jitter, whoami(), jitter.get_str_ansi, jitter.set_str_ansi)


def kernel32_lstrcpy(jitter):
    my_strcpy(jitter, whoami(), jitter.get_str_ansi, jitter.set_str_ansi)

def msvcrt__mbscpy(jitter):
    ret_ad, args = jitter.func_args_cdecl(["ptr_str1", "ptr_str2"])
    s2 = jitter.get_str_unic(args.ptr_str2)
    jitter.set_str_unic(args.ptr_str1, s2)
    jitter.func_ret_cdecl(ret_ad, args.ptr_str1)

def msvcrt_wcscpy(jitter):
    return msvcrt__mbscpy(jitter)


def kernel32_lstrcpyn(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2",
                                             "mlen"])
    s2 = jitter.get_str_ansi(args.ptr_str2)
    if len(s2) >= args.mlen:
        s2 = s2[:args.mlen - 1]
    log.info("Copy '%r'", s2)
    jitter.set_str_ansi(args.ptr_str1, s2)
    jitter.func_ret_stdcall(ret_ad, args.ptr_str1)


def my_strlen(jitter, funcname, get_str, mylen):
    ret_ad, args = jitter.func_args_stdcall(["src"])
    src = get_str(args.src)
    length = mylen(src)
    log.info("Len of '%r' -> 0x%x", src, length)
    jitter.func_ret_stdcall(ret_ad, length)


def kernel32_lstrlenA(jitter):
    my_strlen(jitter, whoami(), jitter.get_str_ansi, len)


def kernel32_lstrlenW(jitter):
    my_strlen(jitter, whoami(), jitter.get_str_unic, len)


def kernel32_lstrlen(jitter):
    my_strlen(jitter, whoami(), jitter.get_str_ansi, len)


def my_lstrcat(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(['ptr_str1', 'ptr_str2'])
    s1 = get_str(args.ptr_str1)
    s2 = get_str(args.ptr_str2)
    jitter.vm.set_mem(args.ptr_str1, s1 + s2)
    jitter.func_ret_stdcall(ret_ad, args.ptr_str1)


def kernel32_lstrcatA(jitter):
    my_lstrcat(jitter, whoami(), jitter.get_str_ansi)


def kernel32_lstrcatW(jitter):
    my_lstrcat(jitter, whoami(), jitter.get_str_unic)


def kernel32_GetUserGeoID(jitter):
    ret_ad, args = jitter.func_args_stdcall(["geoclass"])
    if args.geoclass == 14:
        ret = 12345678
    elif args.geoclass == 16:
        ret = 55667788
    else:
        raise ValueError('unknown geolcass')
    jitter.func_ret_stdcall(ret_ad, ret)


def my_GetVolumeInformation(jitter, funcname, get_str, set_str):
    ret_ad, args = jitter.func_args_stdcall(["lprootpathname",
                                             "lpvolumenamebuffer",
                                             "nvolumenamesize",
                                             "lpvolumeserialnumber",
                                             "lpmaximumcomponentlength",
                                             "lpfilesystemflags",
                                             "lpfilesystemnamebuffer",
                                             "nfilesystemnamesize"])
    if args.lprootpathname:
        s = get_str(args.lprootpathname)
        log.info('GetVolumeInformation %r', s)


    if args.lpvolumenamebuffer:
        s = "volumename"
        s = s[:args.nvolumenamesize]
        set_str(args.lpvolumenamebuffer, s)

    if args.lpvolumeserialnumber:
        jitter.vm.set_u32(args.lpvolumeserialnumber, 11111111)
    if args.lpmaximumcomponentlength:
        jitter.vm.set_u32(args.lpmaximumcomponentlength, 0xff)
    if args.lpfilesystemflags:
        jitter.vm.set_u32(args.lpfilesystemflags, 22222222)

    if args.lpfilesystemnamebuffer:
        s = "filesystemname"
        s = s[:args.nfilesystemnamesize]
        set_str(args.lpfilesystemnamebuffer, s)

    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_GetVolumeInformationA(jitter):
    my_GetVolumeInformation(
        jitter, whoami(), jitter.get_str_ansi, jitter.set_str_ansi)


def kernel32_GetVolumeInformationW(jitter):
    my_GetVolumeInformation(jitter, whoami(), jitter.get_str_unic, jitter.set_str_unic)


def kernel32_MultiByteToWideChar(jitter):
    ret_ad, args = jitter.func_args_stdcall(["codepage", "dwflags",
                                             "lpmultibytestr",
                                             "cbmultibyte",
                                             "lpwidecharstr",
                                             "cchwidechar"])
    src = jitter.get_str_ansi(args.lpmultibytestr) + '\x00'
    l = len(src)

    src = "\x00".join(list(src))
    jitter.vm.set_mem(args.lpwidecharstr, src)
    jitter.func_ret_stdcall(ret_ad, l)


def my_GetEnvironmentVariable(jitter, funcname, get_str, set_str, mylen):
    ret_ad, args = jitter.func_args_stdcall(["lpname", "lpbuffer",
                                             "nsize"])

    s = get_str(args.lpname)
    log.info('GetEnvironmentVariable %r', s)
    if s in winobjs.env_variables:
        v = winobjs.env_variables[s]
    else:
        log.warning('WARNING unknown env variable %r', s)
        v = ""
    set_str(args.lpbuffer, v)
    jitter.func_ret_stdcall(ret_ad, mylen(v))


def kernel32_GetEnvironmentVariableA(jitter):
    my_GetEnvironmentVariable(jitter, whoami(),
                              jitter.get_str_ansi,
                              jitter.set_str_ansi,
                              len)


def kernel32_GetEnvironmentVariableW(jitter):
    my_GetEnvironmentVariable(jitter, whoami(),
                              jitter.get_str_unic,
                              jitter.set_str_ansi,
                              len)


def my_GetSystemDirectory(jitter, funcname, set_str):
    ret_ad, args = jitter.func_args_stdcall(["lpbuffer", "usize"])
    s = "c:\\windows\\system32"
    l = len(s)
    set_str(args.lpbuffer, s)
    jitter.func_ret_stdcall(ret_ad, l)



def kernel32_GetSystemDirectoryA(jitter):
    my_GetSystemDirectory(jitter, whoami(), jitter.set_str_ansi)


def kernel32_GetSystemDirectoryW(jitter):
    my_GetSystemDirectory(jitter, whoami(), jitter.set_str_unic)


def my_CreateDirectory(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(['lppath', 'secattrib'])
    # path = get_str(jitter, args.lppath)
    jitter.func_ret_stdcall(ret_ad, 0x1337)


def kernel32_CreateDirectoryW(jitter):
    my_CreateDirectory(jitter, whoami(), jitter.get_str_unic)


def kernel32_CreateDirectoryA(jitter):
    my_CreateDirectory(jitter, whoami(), jitter.get_str_ansi)



def my_CreateEvent(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["lpeventattributes",
                                             "bmanualreset",
                                             "binitialstate",
                                             "lpname"])
    s = get_str(args.lpname) if args.lpname else None
    if not s in winobjs.events_pool:
        winobjs.events_pool[s] = (args.bmanualreset, args.binitialstate)
    else:
        log.warning('WARNING: known event')
    jitter.func_ret_stdcall(ret_ad, id(s))


def kernel32_CreateEventA(jitter):
    my_CreateEvent(jitter, whoami(), jitter.get_str_ansi)


def kernel32_CreateEventW(jitter):
    my_CreateEvent(jitter, whoami(), jitter.get_str_unic)


def kernel32_WaitForSingleObject(jitter):
    ret_ad, args = jitter.func_args_stdcall(['handle', 'dwms'])

    t_start = time.time() * 1000
    found = False
    while True:
        if args.dwms and args.dwms + t_start > time.time() * 1000:
            ret = 0x102
            break
        for key, value in winobjs.events_pool.iteritems():
            if key != args.handle:
                continue
            found = True
            if value[1] == 1:
                ret = 0
                break
        if not found:
            log.warning('unknown handle')
            ret = 0xffffffff
            break
        time.sleep(0.1)
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_SetFileAttributesA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["lpfilename",
                                             "dwfileattributes"])
    if args.lpfilename:
        # fname = get_str_ansi(jitter, args.lpfilename)
        ret = 1
    else:
        ret = 0
        jitter.vm.set_u32(tib_address + 0x34, 3)

    jitter.func_ret_stdcall(ret_ad, ret)


def ntdll_RtlMoveMemory(jitter):
    ret_ad, args = jitter.func_args_stdcall(["dst", "src", "l"])
    s = jitter.vm.get_mem(args.src, args.l)
    jitter.vm.set_mem(args.dst, s)
    jitter.func_ret_stdcall(ret_ad, 1)


def ntdll_ZwQuerySystemInformation(jitter):
    ret_ad, args = jitter.func_args_stdcall(["systeminformationclass",
                                             "systeminformation",
                                             "systeminformationl",
                                             "returnl"])
    if args.systeminformationclass == 2:
        # SYSTEM_PERFORMANCE_INFORMATION
        o = struct.pack('II', 0x22222222, 0x33333333)
        o += "\x00" * args.systeminformationl
        o = o[:args.systeminformationl]
        jitter.vm.set_mem(args.systeminformation, o)
    else:
        raise ValueError('unknown sysinfo class',
                         args.systeminformationclass)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_ZwProtectVirtualMemory(jitter):
    ret_ad, args = jitter.func_args_stdcall(["handle", "lppvoid",
                                             "pdwsize",
                                             "flnewprotect",
                                             "lpfloldprotect"])

    ad = jitter.vm.get_u32(args.lppvoid)
    # dwsize = upck32(jitter.vm.get_mem(args.pdwsize, 4))
    # XXX mask hpart
    flnewprotect = args.flnewprotect & 0xFFF

    if not flnewprotect in ACCESS_DICT:
        raise ValueError('unknown access dw!')
    jitter.vm.set_mem_access(ad, ACCESS_DICT[flnewprotect])

    # XXX todo real old protect
    jitter.vm.set_u32(args.lpfloldprotect, 0x40)

    jitter.func_ret_stdcall(ret_ad, 1)


def ntdll_ZwAllocateVirtualMemory(jitter):
    ret_ad, args = jitter.func_args_stdcall(["handle", "lppvoid",
                                             "zerobits", "pdwsize",
                                             "alloc_type",
                                             "flprotect"])

    # ad = upck32(jitter.vm.get_mem(args.lppvoid, 4))
    dwsize = jitter.vm.get_u32(args.pdwsize)

    if not args.flprotect in ACCESS_DICT:
        raise ValueError('unknown access dw!')

    alloc_addr = winobjs.heap.next_addr(dwsize)
    jitter.vm.add_memory_page(
        alloc_addr, ACCESS_DICT[args.flprotect], "\x00" * dwsize,
        "Alloc in %s ret 0x%X" % (whoami(), ret_ad))
    jitter.vm.set_u32(args.lppvoid, alloc_addr)

    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_ZwFreeVirtualMemory(jitter):
    ret_ad, args = jitter.func_args_stdcall(["handle", "lppvoid",
                                             "pdwsize", "alloc_type"])
    # ad = upck32(jitter.vm.get_mem(args.lppvoid, 4))
    # dwsize = upck32(jitter.vm.get_mem(args.pdwsize, 4))
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_RtlInitString(jitter):
    ret_ad, args = jitter.func_args_stdcall(["pstring", "source"])
    s = jitter.get_str_ansi(args.source)
    l = len(s) + 1
    o = struct.pack('HHI', l, l, args.source)
    jitter.vm.set_mem(args.pstring, o)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_RtlAnsiStringToUnicodeString(jitter):
    ret_ad, args = jitter.func_args_stdcall(["dst", "src", "alloc_str"])

    l1, l2, p_src = struct.unpack('HHI', jitter.vm.get_mem(args.src, 0x8))
    s = jitter.get_str_ansi(p_src)
    s = ("\x00".join(s + "\x00"))
    l = len(s) + 1
    if args.alloc_str:
        alloc_addr = winobjs.heap.next_addr(l)
        jitter.vm.add_memory_page(
            alloc_addr, PAGE_READ | PAGE_WRITE, "\x00" * l,
            "Alloc in %s ret 0x%X" % (whoami(), ret_ad))
    else:
        alloc_addr = p_src
    jitter.vm.set_mem(alloc_addr, s)
    o = struct.pack('HHI', l, l, alloc_addr)
    jitter.vm.set_mem(args.dst, o)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_LdrLoadDll(jitter):
    ret_ad, args = jitter.func_args_stdcall(["path", "flags",
                                             "modname", "modhandle"])

    l1, l2, p_src = struct.unpack('HHI',
                                  jitter.vm.get_mem(args.modname, 0x8))
    s = jitter.get_str_unic(p_src)
    libname = s.lower()

    ad = winobjs.runtime_dll.lib_get_add_base(libname)
    jitter.vm.set_u32(args.modhandle, ad)

    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_RtlFreeUnicodeString(jitter):
    ret_ad, args = jitter.func_args_stdcall(['src'])
    # l1, l2, p_src = struct.unpack('HHI', jitter.vm.get_mem(args.src, 0x8))
    # s = get_str_unic(jitter, p_src)
    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_LdrGetProcedureAddress(jitter):
    ret_ad, args = jitter.func_args_stdcall(["libbase", "pfname",
                                             "opt", "p_ad"])

    l1, l2, p_src = struct.unpack('HHI', jitter.vm.get_mem(args.pfname, 0x8))
    fname = jitter.get_str_ansi(p_src)

    ad = winobjs.runtime_dll.lib_get_add_func(args.libbase, fname)
    jitter.add_breakpoint(ad, jitter.handle_lib)

    jitter.vm.set_u32(args.p_ad, ad)

    jitter.func_ret_stdcall(ret_ad, 0)


def ntdll_memset(jitter):
    ret_ad, args = jitter.func_args_cdecl(['addr', 'c', 'size'])
    jitter.vm.set_mem(args.addr, chr(args.c) * args.size)
    jitter.func_ret_cdecl(ret_ad, args.addr)


def msvcrt_memset(jitter):
    ret_ad, args = jitter.func_args_cdecl(['addr', 'c', 'size'])
    jitter.vm.set_mem(args.addr, chr(args.c) * args.size)
    jitter.func_ret_cdecl(ret_ad, args.addr)

def msvcrt_strrchr(jitter):
    ret_ad, args = jitter.func_args_cdecl(['pstr','c'])
    s = jitter.get_str_ansi(args.pstr)
    c = chr(args.c)
    ret = args.pstr + s.rfind(c)
    log.info("strrchr(%x '%s','%s') = %x" % (args.pstr,s,c,ret))
    jitter.func_ret_cdecl(ret_ad, ret)

def msvcrt_wcsrchr(jitter):
    ret_ad, args = jitter.func_args_cdecl(['pstr','c'])
    s = jitter.get_str_unic(args.pstr)
    c = chr(args.c)
    ret = args.pstr + (s.rfind(c)*2)
    log.info("wcsrchr(%x '%s',%s) = %x" % (args.pstr,s,c,ret))
    jitter.func_ret_cdecl(ret_ad, ret)

def msvcrt_memcpy(jitter):
    ret_ad, args = jitter.func_args_cdecl(['dst', 'src', 'size'])
    s = jitter.vm.get_mem(args.src, args.size)
    #log.info("memcpy buf %s" % s.encode("hex"))
    jitter.vm.set_mem(args.dst, s)
    jitter.func_ret_cdecl(ret_ad, args.dst)

def msvcrt_realloc(jitter):
    ret_ad,args = jitter.func_args_cdecl(['ptr','new_size'])
    if args.ptr == 0:
        addr = winobjs.heap.alloc(jitter, args.new_size)
    else:
        addr = winobjs.heap.alloc(jitter, args.new_size)
        size = winobjs.heap.get_size(jitter.vm, args.ptr)
        data = jitter.vm.get_mem(args.ptr, size)
        jitter.vm.set_mem(addr, data)
    jitter.func_ret_cdecl(ret_ad, addr)

def msvcrt_memcmp(jitter):
    ret_ad, args = jitter.func_args_cdecl(['ps1', 'ps2', 'size'])
    s1 = jitter.vm.get_mem(args.ps1, args.size)
    s2 = jitter.vm.get_mem(args.ps2, args.size)
    ret = cmp(s1, s2)
    jitter.func_ret_cdecl(ret_ad, ret)


def shlwapi_PathFindExtensionA(jitter):
    ret_ad, args = jitter.func_args_stdcall(['path_ad'])
    path = jitter.get_str_ansi(args.path_ad)
    i = path.rfind('.')
    if i == -1:
        i = args.path_ad + len(path)
    else:
        i = args.path_ad + i
    jitter.func_ret_stdcall(ret_ad, i)


def shlwapi_PathRemoveFileSpecW(jitter):
    ret_ad, args = jitter.func_args_stdcall(['path_ad'])
    path = jitter.get_str_unic(args.path_ad)
    i = path.rfind('\\')
    if i == -1:
        i = 0
    jitter.vm.set_mem(args.path_ad + i * 2, "\x00\x00")
    path = jitter.get_str_unic(args.path_ad)
    jitter.func_ret_stdcall(ret_ad, 1)


def shlwapi_PathIsPrefixW(jitter):
    ret_ad, args = jitter.func_args_stdcall(['ptr_prefix', 'ptr_path'])
    prefix = jitter.get_str_unic(args.ptr_prefix)
    path = jitter.get_str_unic(args.ptr_path)

    if path.startswith(prefix):
        ret = 1
    else:
        ret = 0
    jitter.func_ret_stdcall(ret_ad, ret)


def shlwapi_PathIsDirectoryW(jitter):
    ret_ad, args = jitter.func_args_stdcall(['ptr_path'])
    fname = jitter.get_str_unic(args.ptr_path)

    sb_fname = windows_to_sbpath(fname)

    s = os.stat(sb_fname)
    ret = 0
    if stat.S_ISDIR(s.st_mode):
        ret = 1

    jitter.func_ret_cdecl(ret_ad, ret)


def shlwapi_PathIsFileSpec(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(['path_ad'])
    path = get_str(args.path_ad)
    if path.find(':') != -1 and path.find('\\') != -1:
        ret = 0
    else:
        ret = 1

    jitter.func_ret_stdcall(ret_ad, ret)


def shlwapi_PathGetDriveNumber(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(['path_ad'])
    path = get_str(args.path_ad)
    l = ord(path[0].upper()) - ord('A')
    if 0 <= l <= 25:
        ret = l
    else:
        ret = -1

    jitter.func_ret_stdcall(ret_ad, ret)


def shlwapi_PathGetDriveNumberA(jitter):
    shlwapi_PathGetDriveNumber(jitter, whoami(), jitter.get_str_ansi)


def shlwapi_PathGetDriveNumberW(jitter):
    shlwapi_PathGetDriveNumber(jitter, whoami(), jitter.get_str_unic)


def shlwapi_PathIsFileSpecA(jitter):
    shlwapi_PathIsFileSpec(jitter, whoami(), jitter.get_str_ansi)


def shlwapi_PathIsFileSpecW(jitter):
    shlwapi_PathIsFileSpec(jitter, whoami(), jitter.get_str_unic)


def shlwapi_StrToIntA(jitter):
    ret_ad, args = jitter.func_args_stdcall(['i_str_ad'])
    i_str = jitter.get_str_ansi(args.i_str_ad)
    try:
        i = int(i_str)
    except:
        log.warning('WARNING cannot convert int')
        i = 0

    jitter.func_ret_stdcall(ret_ad, i)


def shlwapi_StrToInt64Ex(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(['pstr', 'flags', 'pret'])
    i_str = get_str(args.pstr)

    if args.flags == 0:
        r = int(i_str)
    elif args.flags == 1:
        r = int(i_str, 16)
    else:
        raise ValueError('cannot decode int')

    jitter.vm.set_mem(args.pret, struct.pack('q', r))
    jitter.func_ret_stdcall(ret_ad, 1)


def shlwapi_StrToInt64ExA(jitter):
    shlwapi_StrToInt64Ex(jitter, whoami(), jitter.get_str_ansi)


def shlwapi_StrToInt64ExW(jitter):
    shlwapi_StrToInt64Ex(jitter, whoami(), jitter.get_str_unic)


def user32_IsCharAlpha(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["c"])
    try:
        c = chr(args.c)
    except:
        log.error('bad char %r', args.c)
        c = "\x00"
    if c.isalpha(jitter):
        ret = 1
    else:
        ret = 0
    jitter.func_ret_stdcall(ret_ad, ret)


def user32_IsCharAlphaA(jitter):
    user32_IsCharAlpha(jitter, whoami(), jitter.get_str_ansi)


def user32_IsCharAlphaW(jitter):
    user32_IsCharAlpha(jitter, whoami(), jitter.get_str_unic)


def user32_IsCharAlphaNumericA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["c"])
    c = chr(args.c)
    if c.isalnum(jitter):
        ret = 1
    else:
        ret = 0
    jitter.func_ret_stdcall(ret_ad, ret)

def get_fmt_args(jitter, fmt, cur_arg, get_str):
    return _get_fmt_args(fmt, cur_arg, get_str, jitter.get_arg_n_cdecl)

def msvcrt_sprintf_str(jitter, get_str):
    ret_ad, args = jitter.func_args_cdecl(['string', 'fmt'])
    cur_arg, fmt = 2, args.fmt
    return ret_ad, args, get_fmt_args(jitter, fmt, cur_arg, get_str)

def msvcrt_sprintf(jitter):
    ret_ad, args, output = msvcrt_sprintf_str(jitter, jitter.get_str_ansi)
    ret = len(output)
    log.info("sprintf() = '%s'" % (output))
    jitter.vm.set_mem(args.string, output + '\x00')
    return jitter.func_ret_cdecl(ret_ad, ret)

def msvcrt_swprintf(jitter):
    ret_ad, args = jitter.func_args_cdecl(['string', 'fmt'])
    cur_arg, fmt = 2, args.fmt
    output = get_fmt_args(jitter, fmt, cur_arg, jitter.get_str_unic)
    ret = len(output)
    log.info("swprintf('%s') = '%s'" % (jitter.get_str_unic(args.fmt), output))
    jitter.vm.set_mem(args.string, output.encode("utf-16le") + '\x00\x00')
    return jitter.func_ret_cdecl(ret_ad, ret)

def msvcrt_fprintf(jitter):
    ret_addr, args = jitter.func_args_cdecl(['file', 'fmt'])
    cur_arg, fmt = 2, args.fmt
    output = get_fmt_args(jitter, fmt, cur_arg, jitter.get_str_ansi)
    ret = len(output)
    log.info("fprintf(%x, '%s') = '%s'" % (args.file, jitter.get_str_ansi(args.fmt), output))

    fd = jitter.vm.get_u32(args.file + 0x10)
    if not fd in winobjs.handle_pool:
        raise NotImplementedError("Untested case")
    winobjs.handle_pool[fd].info.write(output)

    return jitter.func_ret_cdecl(ret_addr, ret)

def shlwapi_StrCmpNIA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ptr_str1", "ptr_str2",
                                             "nchar"])
    s1 = jitter.get_str_ansi(args.ptr_str1).lower()
    s2 = jitter.get_str_ansi(args.ptr_str2).lower()
    s1 = s1[:args.nchar]
    s2 = s2[:args.nchar]
    jitter.func_ret_stdcall(ret_ad, cmp(s1, s2))


def advapi32_RegCreateKeyW(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hkey", "subkey",
                                             "phandle"])
    s_subkey = jitter.get_str_unic(args.subkey).lower() if args.subkey else ""

    ret_hkey = 0
    ret = 2
    if args.hkey in winobjs.hkey_handles:
        ret = 0
        if s_subkey:
            ret_hkey = hash(s_subkey) & 0xffffffff
            winobjs.hkey_handles[ret_hkey] = s_subkey
        else:
            ret_hkey = args.hkey

    log.info("RegCreateKeyW(%x, '%s') = (%x,%d)" % (args.hkey, s_subkey, ret_hkey, ret))
    jitter.vm.set_u32(args.phandle, ret_hkey)

    jitter.func_ret_stdcall(ret_ad, ret)

def kernel32_GetCurrentDirectoryA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["size","buf"])
    dir_ = winobjs.cur_dir
    log.debug("GetCurrentDirectory() = '%s'" % dir_)
    jitter.vm.set_mem(args.buf, dir_[:args.size-1] + "\x00")
    ret = len(dir_)
    if args.size <= len(dir_):
        ret += 1
    jitter.func_ret_stdcall(ret_ad, ret)

def advapi32_RegOpenKeyEx(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["hkey", "subkey",
                                             "reserved", "access",
                                             "phandle"])
    s_subkey = get_str(args.subkey).lower() if args.subkey else ""

    ret_hkey = 0
    ret = 2
    if args.hkey in winobjs.hkey_handles:
        if s_subkey:
            h = hash(s_subkey) & 0xffffffff
            if h in winobjs.hkey_handles:
                ret_hkey = h
                ret = 0
        else:
            log.error('unknown skey')

    jitter.vm.set_u32(args.phandle, ret_hkey)

    jitter.func_ret_stdcall(ret_ad, ret)


def advapi32_RegOpenKeyExA(jitter):
    advapi32_RegOpenKeyEx(jitter, whoami(), jitter.get_str_ansi)


def advapi32_RegOpenKeyExW(jitter):
    advapi32_RegOpenKeyEx(jitter, whoami(), jitter.get_str_unic)


def advapi32_RegSetValue(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["hkey", "psubkey",
                                             "valuetype", "pvalue",
                                             "vlen"])
    if args.psubkey:
        log.info("Subkey %s", get_str(args.psubkey))
    if args.pvalue:
        log.info("Value %s", get_str(args.pvalue))
    jitter.func_ret_stdcall(ret_ad, 0)

def advapi32_RegSetValueEx(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["hkey", "lpvaluename",
                                             "reserved", "dwtype",
                                             "lpdata", "cbData"])
    hkey = winobjs.hkey_handles.get(args.hkey, "unknown HKEY")
    value_name = get_str(args.lpvaluename) if args.lpvaluename else ""
    data = get_str(args.lpdata) if args.lpdata else ""
    log.info("%s('%s','%s'='%s',%x)" % (funcname, hkey, value_name, data, args.dwtype))
    jitter.func_ret_stdcall(ret_ad, 0)

def advapi32_RegCloseKey(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hkey"])
    del winobjs.hkey_handles[args.hkey]
    log.info("RegCloseKey(%x)" % args.hkey)
    jitter.func_ret_stdcall(ret_ad, 0)

def advapi32_RegSetValueExA(jitter):
    advapi32_RegSetValueEx(jitter, whoami(), jitter.get_str_ansi)


def advapi32_RegSetValueExW(jitter):
    advapi32_RegOpenKeyEx(jitter, whoami(), jitter.get_str_unic)


def advapi32_RegSetValueA(jitter):
    advapi32_RegSetValue(jitter, whoami(), jitter.get_str_ansi)


def advapi32_RegSetValueW(jitter):
    advapi32_RegSetValue(jitter, whoami(), jitter.get_str_unic)


def kernel32_GetThreadLocale(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, 0x40c)

def kernel32_SetCurrentDirectory(jitter, get_str):
    ret_ad, args = jitter.func_args_stdcall(['dir'])
    dir_ = get_str(args.dir)
    log.debug("SetCurrentDirectory('%s') = 1" % dir_)
    winobjs.cur_dir = dir_
    jitter.func_ret_stdcall(ret_ad, 1)

def kernel32_SetCurrentDirectoryW(jitter):
    return kernel32_SetCurrentDirectory(jitter, jitter.get_str_unic)

def kernel32_SetCurrentDirectoryA(jitter):
    return kernel32_SetCurrentDirectory(jitter, jitter.get_str_ansi)

def msvcrt_wcscat(jitter):
    ret_ad, args = jitter.func_args_cdecl(['ptr_str1', 'ptr_str2'])
    s1 = jitter.get_str_unic(args.ptr_str1)
    s2 = jitter.get_str_unic(args.ptr_str2)
    log.info("strcat('%s','%s')" % (s1,s2))
    jitter.vm.set_mem(args.ptr_str1, (s1 + s2).encode("utf-16le") + "\x00\x00")
    jitter.func_ret_cdecl(ret_ad, args.ptr_str1)


def kernel32_GetLocaleInfo(jitter, funcname, set_str):
    ret_ad, args = jitter.func_args_stdcall(["localeid", "lctype",
                                             "lplcdata", "cchdata"])

    buf = None
    ret = 0
    if args.localeid == 0x40c:
        if args.lctype == 0x3:
            buf = "ENGLISH"
            buf = buf[:args.cchdata - 1]
            set_str(args.lplcdata, buf)
            ret = len(buf)
    else:
        raise ValueError('unimpl localeid')

    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_GetLocaleInfoA(jitter):
    kernel32_GetLocaleInfo(jitter, whoami(), jitter.set_str_ansi)


def kernel32_GetLocaleInfoW(jitter):
    kernel32_GetLocaleInfo(jitter, whoami(), jitter.set_str_unic)


def kernel32_TlsAlloc(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    winobjs.tls_index += 1
    jitter.func_ret_stdcall(ret_ad, winobjs.tls_index)


def kernel32_TlsFree(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["tlsindex"])
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_TlsSetValue(jitter):
    ret_ad, args = jitter.func_args_stdcall(["tlsindex", "tlsvalue"])
    winobjs.tls_values[args.tlsindex] = args.tlsvalue
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_TlsGetValue(jitter):
    ret_ad, args = jitter.func_args_stdcall(["tlsindex"])
    if not args.tlsindex in winobjs.tls_values:
        raise ValueError("unknown tls val", repr(args.tlsindex))
    jitter.func_ret_stdcall(ret_ad, winobjs.tls_values[args.tlsindex])


def user32_GetKeyboardType(jitter):
    ret_ad, args = jitter.func_args_stdcall(["typeflag"])

    ret = 0
    if args.typeflag == 0:
        ret = 4
    else:
        raise ValueError('unimpl keyboard type')

    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_GetStartupInfo(jitter, funcname, set_str):
    ret_ad, args = jitter.func_args_stdcall(["ptr"])

    s = "\x00" * 0x2c + "\x81\x00\x00\x00" + "\x0a"

    jitter.vm.set_mem(args.ptr, s)
    jitter.func_ret_stdcall(ret_ad, args.ptr)


def kernel32_GetStartupInfoA(jitter):
    kernel32_GetStartupInfo(jitter, whoami(), jitter.set_str_ansi)


def kernel32_GetStartupInfoW(jitter):
    kernel32_GetStartupInfo(jitter, whoami(), jitter.set_str_unic)


def kernel32_GetCurrentThreadId(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, 0x113377)


def kernel32_InitializeCriticalSection(jitter):
    ret_ad, _ = jitter.func_args_stdcall(["lpcritic"])
    jitter.func_ret_stdcall(ret_ad, 0)


def user32_GetSystemMetrics(jitter):
    ret_ad, args = jitter.func_args_stdcall(["nindex"])

    ret = 0
    if args.nindex in [0x2a, 0x4a]:
        ret = 0
    else:
        raise ValueError('unimpl index')
    jitter.func_ret_stdcall(ret_ad, ret)


def wsock32_WSAStartup(jitter):
    ret_ad, args = jitter.func_args_stdcall(["version", "pwsadata"])
    jitter.vm.set_mem(args.pwsadata, "\x01\x01\x02\x02WinSock 2.0\x00")
    jitter.func_ret_stdcall(ret_ad, 0)


def get_current_filetime():
    """
    Get current filetime
    https://msdn.microsoft.com/en-us/library/ms724228
    """
    curtime = winobjs.current_datetime
    unixtime = int(time.mktime(curtime.timetuple()))
    filetime = (int(unixtime * 1000000 + curtime.microsecond) * 10 +
                DATE_1601_TO_1970)
    return filetime


def unixtime_to_filetime(unixtime):
    """
    Convert unixtime to filetime
    https://msdn.microsoft.com/en-us/library/ms724228
    """
    return (unixtime * 10000000) + DATE_1601_TO_1970


def filetime_to_unixtime(filetime):
    """
    Convert filetime to unixtime
    # https://msdn.microsoft.com/en-us/library/ms724228
    """
    return int((filetime - DATE_1601_TO_1970) / 10000000)


def datetime_to_systemtime(curtime):

    s = struct.pack('HHHHHHHH',
                    curtime.year,      # year
                    curtime.month,     # month
                    curtime.weekday(), # dayofweek
                    curtime.day,       # day
                    curtime.hour,      # hour
                    curtime.minute ,   # minutes
                    curtime.second,    # seconds
                    int(curtime.microsecond / 1000),  # millisec
                    )
    return s


def kernel32_GetSystemTimeAsFileTime(jitter):
    ret_ad, args = jitter.func_args_stdcall(["lpSystemTimeAsFileTime"])

    current_filetime = get_current_filetime()
    filetime = struct.pack('II',
                           current_filetime & 0xffffffff,
                           (current_filetime>>32) & 0xffffffff)

    jitter.vm.set_mem(args.lpSystemTimeAsFileTime, filetime)
    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_GetLocalTime(jitter):
    ret_ad, args = jitter.func_args_stdcall(["lpsystemtime"])
    systemtime = datetime_to_systemtime(winobjs.current_datetime)
    jitter.vm.set_mem(args.lpsystemtime, systemtime)
    jitter.func_ret_stdcall(ret_ad, args.lpsystemtime)


def kernel32_GetSystemTime(jitter):
    ret_ad, args = jitter.func_args_stdcall(["lpsystemtime"])
    systemtime = datetime_to_systemtime(winobjs.current_datetime)
    jitter.vm.set_mem(args.lpsystemtime, systemtime)
    jitter.func_ret_stdcall(ret_ad, args.lpsystemtime)


def kernel32_CreateFileMapping(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["hfile", "lpattr", "flprotect",
                                             "dwmaximumsizehigh",
                                             "dwmaximumsizelow", "lpname"])

    if args.hfile == 0xffffffff:
        # Create null mapping
        if args.dwmaximumsizehigh:
            raise NotImplementedError("Untested case")
        hmap = StringIO("\x00" * args.dwmaximumsizelow)
        hmap_handle = winobjs.handle_pool.add('filemem', hmap)

        ret = winobjs.handle_pool.add('filemapping', hmap_handle)
    else:
        if not args.hfile in winobjs.handle_pool:
            raise ValueError('unknown handle')
        ret = winobjs.handle_pool.add('filemapping', args.hfile)
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_CreateFileMappingA(jitter):
    kernel32_CreateFileMapping(jitter, whoami(), jitter.get_str_ansi)


def kernel32_CreateFileMappingW(jitter):
    kernel32_CreateFileMapping(jitter, whoami(), jitter.get_str_unic)


def kernel32_MapViewOfFile(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hfile", "flprotect",
                                             "dwfileoffsethigh",
                                             "dwfileoffsetlow",
                                             "length"])

    if not args.hfile in winobjs.handle_pool:
        raise ValueError('unknown handle')
    hmap = winobjs.handle_pool[args.hfile]
    if not hmap.info in winobjs.handle_pool:
        raise ValueError('unknown file handle')

    hfile_o = winobjs.handle_pool[hmap.info]
    fd = hfile_o.info
    fd.seek((args.dwfileoffsethigh << 32) | args.dwfileoffsetlow)
    data = fd.read(args.length) if args.length else fd.read()
    length = len(data)

    log.debug('MapViewOfFile len: %x', len(data))

    if not args.flprotect in ACCESS_DICT:
        raise ValueError('unknown access dw!')

    alloc_addr = winobjs.heap.alloc(jitter, len(data))
    jitter.vm.set_mem(alloc_addr, data)

    winobjs.handle_mapped[alloc_addr] = (hfile_o, args.dwfileoffsethigh,
                                         args.dwfileoffsetlow, length)

    jitter.func_ret_stdcall(ret_ad, alloc_addr)


def kernel32_UnmapViewOfFile(jitter):
    ret_ad, args = jitter.func_args_stdcall(['ad'])

    if not args.ad in winobjs.handle_mapped:
        raise NotImplementedError("Untested case")
    """
    hfile_o, dwfileoffsethigh, dwfileoffsetlow, length = winobjs.handle_mapped[ad]
    off = (dwfileoffsethigh<<32) | dwfileoffsetlow
    s = jitter.vm.get_mem(ad, length)
    hfile_o.info.seek(off)
    hfile_o.info.write(s)
    hfile_o.info.close()
    """
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_GetDriveType(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(['pathname'])

    p = get_str(args.pathname)
    p = p.upper()

    log.debug('Drive: %r', p)

    ret = 0
    if p[0] == "C":
        ret = 3

    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_GetDriveTypeA(jitter):
    kernel32_GetDriveType(jitter, whoami(), jitter.get_str_ansi)


def kernel32_GetDriveTypeW(jitter):
    kernel32_GetDriveType(jitter, whoami(), jitter.get_str_unic)


def kernel32_GetDiskFreeSpace(jitter, funcname, get_str):
    ret_ad, args = jitter.func_args_stdcall(["lprootpathname",
                                             "lpsectorpercluster",
                                             "lpbytespersector",
                                             "lpnumberoffreeclusters",
                                             "lptotalnumberofclusters"])
    jitter.vm.set_u32(args.lpsectorpercluster, 8)
    jitter.vm.set_u32(args.lpbytespersector, 0x200)
    jitter.vm.set_u32(args.lpnumberoffreeclusters, 0x222222)
    jitter.vm.set_u32(args.lptotalnumberofclusters, 0x333333)
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_GetDiskFreeSpaceA(jitter):
    kernel32_GetDiskFreeSpace(jitter, whoami(), jitter.get_str_ansi)


def kernel32_GetDiskFreeSpaceW(jitter):
    kernel32_GetDiskFreeSpace(jitter, whoami(), jitter.get_str_unic)


def kernel32_VirtualQuery(jitter):
    ret_ad, args = jitter.func_args_stdcall(["ad", "lpbuffer", "dwl"])

    all_mem = jitter.vm.get_all_memory()
    found = None
    for basead, m in all_mem.iteritems():
        if basead <= args.ad < basead + m['size']:
            found = args.ad, m
            break
    if not found:
        raise ValueError('cannot find mem', hex(args.ad))

    if args.dwl != 0x1c:
        raise ValueError('strange mem len', hex(args.dwl))
    s = struct.pack('IIIIIII',
                    args.ad,
                    basead,
                    ACCESS_DICT_INV[m['access']],
                    m['size'],
                    0x1000,
                    ACCESS_DICT_INV[m['access']],
                    0x01000000)
    jitter.vm.set_mem(args.lpbuffer, s)
    jitter.func_ret_stdcall(ret_ad, args.dwl)


def kernel32_GetProcessAffinityMask(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hprocess",
                                             "procaffmask",
                                             "systemaffmask"])
    jitter.vm.set_u32(args.procaffmask, 1)
    jitter.vm.set_u32(args.systemaffmask, 1)
    jitter.func_ret_stdcall(ret_ad, 1)


def msvcrt_rand(jitter):
    ret_ad, _ = jitter.func_args_cdecl(0)
    jitter.func_ret_stdcall(ret_ad, 0x666)

def msvcrt_srand(jitter):
    ret_ad, _ = jitter.func_args_cdecl(['seed'])
    jitter.func_ret_stdcall(ret_ad, 0)

def msvcrt_wcslen(jitter):
    ret_ad, args = jitter.func_args_cdecl(["pwstr"])
    s = jitter.get_str_unic(args.pwstr)
    jitter.func_ret_cdecl(ret_ad, len(s))

def kernel32_SetFilePointer(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hwnd", "dinstance",
                                             "p_dinstance_high",
                                             "movemethod"])

    if args.hwnd == winobjs.module_cur_hwnd:
        pass
    elif args.hwnd in winobjs.handle_pool:
        pass
    else:
        raise ValueError('unknown hwnd!')

    # data = None
    if args.hwnd in winobjs.files_hwnd:
        winobjs.files_hwnd[winobjs.module_cur_hwnd].seek(args.dinstance, args.movemethod)
    elif args.hwnd in winobjs.handle_pool:
        wh = winobjs.handle_pool[args.hwnd]
        wh.info.seek(args.dinstance, args.movemethod)
    else:
        raise ValueError('unknown filename')
    jitter.func_ret_stdcall(ret_ad, args.dinstance)


def kernel32_SetFilePointerEx(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hwnd", "dinstance_l",
                                             "dinstance_h",
                                             "pnewfileptr",
                                             "movemethod"])
    dinstance = args.dinstance_l | (args.dinstance_h << 32)
    if dinstance:
        raise ValueError('Not implemented')
    if args.pnewfileptr:
        raise ValueError('Not implemented')
    if args.hwnd == winobjs.module_cur_hwnd:
        pass
    elif args.hwnd in winobjs.handle_pool:
        pass
    else:
        raise ValueError('unknown hwnd!')

    # data = None
    if args.hwnd in winobjs.files_hwnd:
        winobjs.files_hwnd[winobjs.module_cur_hwnd].seek(dinstance, args.movemethod)
    elif args.hwnd in winobjs.handle_pool:
        wh = winobjs.handle_pool[args.hwnd]
        wh.info.seek(dinstance, args.movemethod)
    else:
        raise ValueError('unknown filename')
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_SetEndOfFile(jitter):
    ret_ad, args = jitter.func_args_stdcall(['hwnd'])
    if args.hwnd in winobjs.handle_pool:
        wh = winobjs.handle_pool[args.hwnd]
        wh.info.seek(0, 2)
    else:
        raise ValueError('unknown filename')
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_FlushFileBuffers(jitter):
    ret_ad, args = jitter.func_args_stdcall(['hwnd'])
    if args.hwnd in winobjs.handle_pool:
        pass
    else:
        raise ValueError('unknown filename')
    jitter.func_ret_stdcall(ret_ad, 1)


def kernel32_WriteFile(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hwnd", "lpbuffer",
                                             "nnumberofbytestowrite",
                                             "lpnumberofbyteswrite",
                                             "lpoverlapped"])
    data = jitter.vm.get_mem(args.lpbuffer, args.nnumberofbytestowrite)

    if args.hwnd == winobjs.module_cur_hwnd:
        pass
    elif args.hwnd in winobjs.handle_pool:
        pass
    else:
        raise ValueError('unknown hwnd!')

    if args.hwnd in winobjs.files_hwnd:
        winobjs.files_hwnd[winobjs.module_cur_hwnd].write(data)
    elif args.hwnd in winobjs.handle_pool:
        wh = winobjs.handle_pool[args.hwnd]
        wh.info.write(data)
    else:
        raise ValueError('unknown filename')

    if (args.lpnumberofbyteswrite):
        jitter.vm.set_u32(args.lpnumberofbyteswrite, len(data))

    jitter.func_ret_stdcall(ret_ad, 1)


def user32_IsCharUpperA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["c"])
    ret = 0 if args.c & 0x20 else 1
    jitter.func_ret_stdcall(ret_ad, ret)


def user32_IsCharLowerA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["c"])
    ret = 1 if args.c & 0x20 else 0
    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_GetSystemDefaultLangID(jitter):
    ret_ad, _ = jitter.func_args_stdcall(0)
    jitter.func_ret_stdcall(ret_ad, 0x409)  # encglish


def msvcrt_malloc(jitter):
    ret_ad, args = jitter.func_args_cdecl(["msize"])
    addr = winobjs.heap.alloc(jitter, args.msize)
    jitter.func_ret_cdecl(ret_ad, addr)


def msvcrt_free(jitter):
    ret_ad, _ = jitter.func_args_cdecl(["ptr"])
    jitter.func_ret_cdecl(ret_ad, 0)


def msvcrt_fseek(jitter):
    ret_ad, args = jitter.func_args_cdecl(['stream', 'offset', 'orig'])
    fd = jitter.vm.get_u32(args.stream + 0x10)

    if not fd in winobjs.handle_pool:
        raise NotImplementedError("Untested case")
    o = winobjs.handle_pool[fd]
    o.info.seek(args.offset, args.orig)
    jitter.func_ret_cdecl(ret_ad, 0)


def msvcrt_ftell(jitter):
    ret_ad, args = jitter.func_args_cdecl(["stream"])
    fd = jitter.vm.get_u32(args.stream + 0x10)

    if not fd in winobjs.handle_pool:
        raise NotImplementedError("Untested case")
    o = winobjs.handle_pool[fd]
    off = o.info.tell()
    jitter.func_ret_cdecl(ret_ad, off)


def msvcrt_rewind(jitter):
    ret_ad, args = jitter.func_args_cdecl(["stream"])
    fd = jitter.vm.get_u32(args.stream + 0x10)
    if not fd in winobjs.handle_pool:
        raise NotImplementedError("Untested case")
    o = winobjs.handle_pool[fd]
    # off = o.info.seek(0, 0)
    jitter.func_ret_cdecl(ret_ad, 0)


def msvcrt_fread(jitter):
    ret_ad, args = jitter.func_args_cdecl(["buf", "size", "nmemb", "stream"])
    fd = jitter.vm.get_u32(args.stream + 0x10)
    if not fd in winobjs.handle_pool:
        raise NotImplementedError("Untested case")

    data = winobjs.handle_pool[fd].info.read(args.size * args.nmemb)
    jitter.vm.set_mem(args.buf, data)
    jitter.func_ret_cdecl(ret_ad, args.nmemb)


def msvcrt_fwrite(jitter):
    ret_ad, args = jitter.func_args_cdecl(["buf", "size", "nmemb", "stream"])
    fd = jitter.vm.get_u32(args.stream + 0x10)
    if not fd in winobjs.handle_pool:
        raise NotImplementedError("Unknown file handle!")

    data = jitter.vm.get_mem(args.buf, args.size*args.nmemb)
    winobjs.handle_pool[fd].info.write(data)
    jitter.func_ret_cdecl(ret_ad, args.nmemb)


def msvcrt_fclose(jitter):
    ret_ad, args = jitter.func_args_cdecl(['stream'])
    fd = jitter.vm.get_u32(args.stream + 0x10)

    if not fd in winobjs.handle_pool:
        raise NotImplementedError("Untested case")
    o = winobjs.handle_pool[fd]
    # off = o.info.close()
    jitter.func_ret_cdecl(ret_ad, 0)


def msvcrt_atexit(jitter):
    ret_ad, _ = jitter.func_args_cdecl(["func"])
    jitter.func_ret_cdecl(ret_ad, 0)


def user32_MessageBoxA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["hwnd", "lptext",
                                             "lpcaption", "utype"])

    text = jitter.get_str_ansi(args.lptext)
    caption = jitter.get_str_ansi(args.lpcaption)

    log.info('Caption: %r Text: %r', caption, text)

    jitter.func_ret_stdcall(ret_ad, 0)


def kernel32_myGetTempPath(jitter, set_str):
    ret_ad, args = jitter.func_args_stdcall(["l", "buf"])
    l = 'c:\\temp\\'
    if len(l) < args.l:
        set_str(args.buf, l)
    jitter.func_ret_stdcall(ret_ad, len(l))


def kernel32_GetTempPathA(jitter):
    kernel32_myGetTempPath(jitter, jitter.set_str_ansi)


def kernel32_GetTempPathW(jitter):
    kernel32_myGetTempPath(jitter, jitter.set_str_unic)


temp_num = 0


def kernel32_GetTempFileNameA(jitter):
    global temp_num
    ret_ad, args = jitter.func_args_stdcall(["path", "ext", "unique", "buf"])

    temp_num += 1
    ext = jitter.get_str_ansi(args.ext) if args.ext else 'tmp'
    path = jitter.get_str_ansi(args.path) if args.path else "xxx"
    fname = path + "\\" + "temp%.4d" % temp_num + "." + ext
    jitter.vm.set_mem(args.buf, fname)

    jitter.func_ret_stdcall(ret_ad, 0)


class win32_find_data:
    fileattrib = 0
    creationtime = 0
    lastaccesstime = 0
    lastwritetime = 0
    filesizehigh = 0
    filesizelow = 0
    dwreserved0 = 0
    dwreserved1 = 0x1337beef
    cfilename = ""
    alternamefilename = ""

    def __init__(self, **kargs):
        for k, v in kargs.items():
            setattr(self, k, v)

    def toStruct(self):
        s = struct.pack('=IQQQIIII',
                        self.fileattrib,
                        self.creationtime,
                        self.lastaccesstime,
                        self.lastwritetime,
                        self.filesizehigh,
                        self.filesizelow,
                        self.dwreserved0,
                        self.dwreserved1)
        fname = self.cfilename + '\x00' * MAX_PATH
        fname = fname[:MAX_PATH]
        s += fname
        fname = self.alternamefilename + '\x00' * 14
        fname = fname[:14]
        s += fname
        return s


class find_data_mngr:

    def __init__(self):
        self.patterns = {}
        self.flist = []
        # handle number -> (flist index, current index in list)
        self.handles = {}

    def add_list(self, pattern, flist):
        index = len(self.flist)
        self.flist.append(flist)

        self.patterns[pattern] = index

    def findfirst(self, pattern):
        assert(pattern in self.patterns)
        findex = self.patterns[pattern]
        h = len(self.handles) + 1
        self.handles[h] = [findex, 0]
        return h

    def findnext(self, h):
        assert(h in self.handles)
        findex, index = self.handles[h]
        if index >= len(self.flist[findex]):
            return None
        fname = self.flist[findex][index]
        self.handles[h][1] += 1

        return fname


def kernel32_FindFirstFileA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["pfilepattern", "pfindfiledata"])

    filepattern = jitter.get_str_ansi(args.pfilepattern)
    h = winobjs.find_data.findfirst(filepattern)

    fname = winobjs.find_data.findnext(h)
    fdata = win32_find_data(cfilename=fname)

    jitter.vm.set_mem(args.pfindfiledata, fdata.toStruct())
    jitter.func_ret_stdcall(ret_ad, h)


def kernel32_FindNextFileA(jitter):
    ret_ad, args = jitter.func_args_stdcall(["handle", "pfindfiledata"])

    fname = winobjs.find_data.findnext(args.handle)
    if fname is None:
        ret = 0
    else:
        ret = 1
        fdata = win32_find_data(cfilename=fname)
        jitter.vm.set_mem(args.pfindfiledata, fdata.toStruct())

    jitter.func_ret_stdcall(ret_ad, ret)


def kernel32_GetNativeSystemInfo(jitter):
    ret_ad, args = jitter.func_args_stdcall(["sys_ptr"])
    sysinfo = systeminfo()
    jitter.vm.set_mem(args.sys_ptr, sysinfo.pack())
    jitter.func_ret_stdcall(ret_ad, 0)


def raw2guid(r):
    o = struct.unpack('IHHHBBBBBB', r)
    return '{%.8X-%.4X-%.4X-%.4X-%.2X%.2X%.2X%.2X%.2X%.2X}' % o


digs = string.digits + string.lowercase


def int2base(x, base):
    if x < 0:
        sign = -1
    elif x == 0:
        return '0'
    else:
        sign = 1
    x *= sign
    digits = []
    while x:
        digits.append(digs[x % base])
        x /= base
    if sign < 0:
        digits.append('-')
    digits.reverse()
    return ''.join(digits)


def msvcrt__ultow(jitter):
    ret_ad, args = jitter.func_args_cdecl(["value", "p", "radix"])

    value = args.value & 0xFFFFFFFF
    if not args.radix in [10, 16, 20]:
        raise ValueError("Not tested")
    s = int2base(value, args.radix)
    jitter.vm.set_mem(args.p, jitter.set_str_unic(s + "\x00"))
    jitter.func_ret_cdecl(ret_ad, args.p)


def msvcrt_myfopen(jitter, get_str):
    ret_ad, args = jitter.func_args_cdecl(["pfname", "pmode"])

    fname = get_str(args.pfname)
    rw = get_str(args.pmode)
    log.info("fopen %r, %r", fname, rw)

    if rw in ['r', 'rb', 'wb+','wb','wt']:
        sb_fname = windows_to_sbpath(fname)
        h = open(sb_fname, rw)
        eax = winobjs.handle_pool.add(sb_fname, h)
        dwsize = 0x20
        alloc_addr = winobjs.heap.alloc(jitter, dwsize)
        pp = pck32(0x11112222) + pck32(0) + pck32(0) + pck32(0) + pck32(eax)
        jitter.vm.set_mem(alloc_addr, pp)

    else:
        raise ValueError('unknown access mode %s' % rw)

    jitter.func_ret_cdecl(ret_ad, alloc_addr)


def msvcrt__wfopen(jitter):
    msvcrt_myfopen(jitter, jitter.get_str_unic)


def msvcrt_fopen(jitter):
    msvcrt_myfopen(jitter, jitter.get_str_ansi)


def msvcrt_strlen(jitter):
    ret_ad, args = jitter.func_args_cdecl(["src"])

    s = jitter.get_str_ansi(args.src)
    jitter.func_ret_cdecl(ret_ad, len(s))
