// (c) 2003-2007 Electronic Arts Inc.

#if defined(_MSC_VER) && !defined(_XBOX) && !defined(__i386)
#include <windows.h>
#include <stdio.h>

typedef struct ExceptionDesc
{
    DWORD code;
    const char *desc;
} ExceptionDesc;

static ExceptionDesc EH_ExceptionInfo[]=
{
EXCEPTION_ACCESS_VIOLATION, "The thread tried to read from or write to a virtual address for which it does not have the appropriate access.",
EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking.",
EXCEPTION_BREAKPOINT, "A breakpoint was encountered.",
EXCEPTION_DATATYPE_MISALIGNMENT, "The thread tried to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on.",
EXCEPTION_FLT_DENORMAL_OPERAND, "One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value.",
EXCEPTION_FLT_DIVIDE_BY_ZERO, "The thread tried to divide a floating-point value by a floating-point divisor of zero.",
EXCEPTION_FLT_INEXACT_RESULT, "The result of a floating-point operation cannot be represented exactly as a decimal fraction.",
EXCEPTION_FLT_INVALID_OPERATION, "This exception represents any floating-point exception not included in this list.",
EXCEPTION_FLT_OVERFLOW, "The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.",
EXCEPTION_FLT_STACK_CHECK, "The stack overflowed or underflowed as the result of a floating-point operation.",
EXCEPTION_FLT_UNDERFLOW, "The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.",
EXCEPTION_ILLEGAL_INSTRUCTION, "The thread tried to execute an invalid instruction.",
EXCEPTION_IN_PAGE_ERROR, "The thread tried to access a page that was not present, and the system was unable to load the page. For example, this exception might occur if a network connection is lost while running a program over the network.",
EXCEPTION_INT_DIVIDE_BY_ZERO, "The thread tried to divide an integer value by an integer divisor of zero.",
EXCEPTION_INT_OVERFLOW, "The result of an integer operation caused a carry out of the most significant bit of the result.",
EXCEPTION_INVALID_DISPOSITION, "An exception handler returned an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception.",
EXCEPTION_NONCONTINUABLE_EXCEPTION, "The thread tried to continue execution after a noncontinuable exception occurred.",
EXCEPTION_PRIV_INSTRUCTION, "The thread tried to execute an instruction whose operation is not allowed in the current machine mode.",
EXCEPTION_SINGLE_STEP, "A trace trap or other single-instruction mechanism signaled that one instruction has been executed.",
EXCEPTION_STACK_OVERFLOW, "The thread used up its stack.",
0,0
};

const char *EH_LookupExceptionCode(unsigned int code)
{
    ExceptionDesc *pDesc=EH_ExceptionInfo;
    while(pDesc->code)
    {
        if(pDesc->code==code)
        {
            return pDesc->desc;
        }
        pDesc++;
    }
    return 0;
}

#define D(x)    printf("%-6s= %08x\n",#x,p->x);

static void EH_DumpRegisters(CONTEXT *p)
{
    D(Eax);
    D(Ebx);
    D(Ecx);
    D(Edx);
    D(Edi);
    D(Esi);
    D(Ebp);
    D(SegCs);
    D(SegDs);
    D(SegEs);
    D(SegFs);
    D(SegGs);
    D(SegSs);
    D(Eip);
    D(EFlags);
    D(Esp);
    return;
}

static LONG __stdcall EH_ExceptionFilter(struct _EXCEPTION_POINTERS *pInfo)
{
    DWORD code=pInfo->ExceptionRecord->ExceptionCode;
    const char *pMsg=EH_LookupExceptionCode(code);
    if(pMsg)
    {
        printf("%s\n",pMsg);
    }
    else
    {
        printf("Unknown exception: %08x\n",code);
    }
    EH_DumpRegisters(pInfo->ContextRecord);
    return EXCEPTION_EXECUTE_HANDLER;
}

void EH_Enable(bool bFlag)
{
    if (bFlag)
    {
        SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
        SetUnhandledExceptionFilter(EH_ExceptionFilter);
    }
    else
    {
        SetErrorMode(0);
        SetUnhandledExceptionFilter(0);
    }
}

#else

// stub entire API for non-windows builds
void EH_Enable(bool bFlag)
{
    return;
}

const char *EH_LookupExceptionCode(unsigned int code)
{
    return NULL;
}

#endif


