diff --git a/source/errorlist.pl b/source/errorlist.pl index d18307e244..b663252bd0 100755 --- a/source/errorlist.pl +++ b/source/errorlist.pl @@ -31,13 +31,15 @@ print $out <<'.'; // elsewhere - trust the compiler to handle them identically . -for (sort keys %groups) { - my ($base, $name) = split /~/; +for (sort { $a->[1] cmp $b->[1] } map [$_, do{(my $c=$_)=~s/~/_/;$c} ], keys %groups) { + my ($base, $name) = split /~/, $_->[0]; print $out "class ${base}_$name : public $base {};\n"; } -for (sort keys %types) { - my ($base, $name) = split /~/; +print $out "\n"; + +for (sort { $a->[1] cmp $b->[1] } map [$_, do{(my $c=$_)=~s/~/_/;$c} ], keys %types) { + my ($base, $name) = split /~/, $_->[0]; print $out "class ${base}_$name : public $base { public: ${base}_$name(); };\n"; } @@ -47,7 +49,7 @@ print $out "\n// The relevant bits of this file:\n"; for (sort keys %types) { my ($base, $name) = split /~/; - print $out "${base}_${name}::${base}_${name}() { magic=0x50534552; code=$types{$_}; }\n"; + print $out "${base}_${name}::${base}_${name}() { magic=0x45725221; code=$types{$_}; }\n"; } print $out <<"."; diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index b899c14566..cb4fddc23a 100755 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -150,7 +150,7 @@ bool CObjectEntry::Load(const char* filename) { XeroFile.Load(filename); } - catch (...) + catch (PSERROR_Xeromyces) { return false; } diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index ffa8b908d6..ee110bd9b0 100755 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -353,8 +353,6 @@ void CGUI::DrawSprite(const CStr& SpriteName, if (SpriteName == CStr()) return; - const char * buf = SpriteName; - bool DoClipping = (Clipping != CRect()); CGUISprite Sprite; @@ -904,8 +902,8 @@ void CGUI::LoadXMLFile(const string &Filename) { XeroFile.Load(Filename.c_str()); } - catch (PSERROR_Xeromyces& err) { - UNUSED(err); + catch (PSERROR_Xeromyces) + { // Fail silently return; } @@ -916,31 +914,40 @@ void CGUI::LoadXMLFile(const string &Filename) // data we'll be expecting std::string root_name = XeroFile.getElementString(node.getNodeName()); - if (root_name == "objects") + try { - Xeromyces_ReadRootObjects(node, &XeroFile); - // Re-cache all values so these gets cached too. - //UpdateResolution(); + if (root_name == "objects") + { + Xeromyces_ReadRootObjects(node, &XeroFile); + + // Re-cache all values so these gets cached too. + //UpdateResolution(); + } + else + if (root_name == "sprites") + { + Xeromyces_ReadRootSprites(node, &XeroFile); + } + else + if (root_name == "styles") + { + Xeromyces_ReadRootStyles(node, &XeroFile); + } + else + if (root_name == "setup") + { + Xeromyces_ReadRootSetup(node, &XeroFile); + } + else + { + // TODO Gee: Output in log + } } - else - if (root_name == "sprites") + catch (PSERROR_GUI) { - Xeromyces_ReadRootSprites(node, &XeroFile); - } - else - if (root_name == "styles") - { - Xeromyces_ReadRootStyles(node, &XeroFile); - } - else - if (root_name == "setup") - { - Xeromyces_ReadRootSetup(node, &XeroFile); - } - else - { - // TODO Gee: Output in log + LOG(ERROR, "Errors loading GUI file %s", Filename.c_str()); + return; } // Now report if any other errors occured @@ -1104,7 +1111,7 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec continue; // Ignore "type" and "style", we've already checked it - if (attr.Name == attr_type || attr.Name == attr_style ) + if (attr.Name == attr_type || attr.Name == attr_style) continue; // Also the name needs some special attention @@ -1118,6 +1125,44 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec if (attr.Name == attr_z) ManuallySetZ = true; + + // Generate "stretched:filename" sprites. + // + // Check whether it's actually one of the many sprite... parameters. + if (pFile->getAttributeString(attr.Name).substr(0, 6) == "sprite") + { + // Check whether it's a special stretched one + std::string SpriteName = CStr8(attr.Value); + if (SpriteName.substr(0, 10) == "stretched:" && + m_Sprites.find(SpriteName) == m_Sprites.end() ) + { + + CGUISprite sprite; + SGUIImage image; + + CStr DefaultSize ("0 0 100% 100%"); + image.m_TextureSize = CClientArea(DefaultSize); + image.m_Size = CClientArea(DefaultSize); + + std::string TexFilename = "art/textures/ui/"; + TexFilename += SpriteName.substr(10); + + image.m_TextureName = TexFilename; + Handle tex = tex_load(TexFilename.c_str()); + if (tex <= 0) + { + LOG(ERROR, "Error opening texture '%s': %lld", TexFilename.c_str(), tex); + throw PSERROR_GUI_TextureLoadFailed(); + } + image.m_Texture = tex; + // TODO: more error handling + tex_upload(tex); + + sprite.AddImage(image); + m_Sprites[SpriteName] = sprite; + } + } + // Try setting the value try { @@ -1192,20 +1237,24 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec { Handle h = vfs_open(file); if (h <= 0) - // TODO: Error handling - assert(! "File open failed"); - else { - void* data; - size_t len; - int err = vfs_map(h, 0, data, len); - assert(err == 0); - - code = (char*)data; - - vfs_unmap(h); - vfs_close(h); + LOG(ERROR, "Error opening action file '%s': %lld", file, h); + throw PSERROR_GUI_JSOpenFailed(); } + + void* data; + size_t len; + int err = vfs_map(h, 0, data, len); + if (err) + { + LOG(ERROR, "Error mapping action file '%s': %lld", file, err); + throw PSERROR_GUI_JSOpenFailed(); + } + + code = (char*)data; + + vfs_unmap(h); + vfs_close(h); } // Read the inline code (concatenating to the file code, if both are specified) @@ -1274,21 +1323,25 @@ void CGUI::Xeromyces_ReadScript(XMBElement Element, CXeromyces* pFile) { Handle h = vfs_open(file); if (h <= 0) - // TODO: Error handling - assert(! "File open failed"); - else { - void* data; - size_t len; - int err = vfs_map(h, 0, data, len); - assert(err == 0); - - jsval result; - JS_EvaluateScript(g_ScriptingHost.getContext(), (JSObject*)m_ScriptObject, (const char*)data, (int)len, file, 1, &result); - - vfs_unmap(h); - vfs_close(h); + LOG(ERROR, "Error opening script file '%s': %lld", file, h); + throw PSERROR_GUI_JSOpenFailed(); } + + void* data; + size_t len; + int err = vfs_map(h, 0, data, len); + if (err) + { + LOG(ERROR, "Error mapping script file '%s': %lld", file, err); + throw PSERROR_GUI_JSOpenFailed(); + } + + jsval result; + JS_EvaluateScript(g_ScriptingHost.getContext(), (JSObject*)m_ScriptObject, (const char*)data, (int)len, file, 1, &result); + + vfs_unmap(h); + vfs_close(h); } // Execute inline scripts @@ -1376,8 +1429,8 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite Handle tex = tex_load(TexFilename.c_str()); if (tex <= 0) { - // TODO: Error - assert(! "Failed to load texture"); + LOG(ERROR, "Error opening texture '%s': %lld", TexFilename.c_str(), tex); + throw PSERROR_GUI_TextureLoadFailed(); } image.m_Texture = tex; tex_upload(tex); diff --git a/source/gui/CGUI.h b/source/gui/CGUI.h index f56b0d6c4b..d06828d458 100755 --- a/source/gui/CGUI.h +++ b/source/gui/CGUI.h @@ -17,6 +17,10 @@ gee@pyro.nu #ifndef CGUI_H #define CGUI_H +ERROR_GROUP(PSERROR, GUI); +ERROR_TYPE(PSERROR_GUI, JSOpenFailed); +ERROR_TYPE(PSERROR_GUI, TextureLoadFailed); + //-------------------------------------------------------- // Includes / Compiler directives //-------------------------------------------------------- diff --git a/source/gui/scripting/JSInterface_IGUIObject.cpp b/source/gui/scripting/JSInterface_IGUIObject.cpp index e3c6221c96..68a3ed7b58 100755 --- a/source/gui/scripting/JSInterface_IGUIObject.cpp +++ b/source/gui/scripting/JSInterface_IGUIObject.cpp @@ -1,4 +1,4 @@ -// $Id: JSInterface_IGUIObject.cpp,v 1.5 2004/07/12 15:52:53 philip Exp $ +// $Id: JSInterface_IGUIObject.cpp,v 1.6 2004/07/17 17:05:10 philip Exp $ #include "precompiled.h" @@ -71,8 +71,8 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval EGUISettingType Type; if (e->GetSettingType(propName, Type) != PS_OK) { - // Possibly a function, but they should have been individually - // handled above, so complain about it + // Potentially a function, but they should have been + // individually handled above, so complain about it JS_ReportError(cx, "Invalid GUIObject property '%s'", propName.c_str()); return JS_FALSE; } @@ -128,6 +128,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval CClientArea area; GUI::GetSetting(e, propName, area); JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL); + #define P(x, y, z) jsval z = INT_TO_JSVAL(area.x.y); JS_SetProperty(cx, obj, #z, &z) P(pixel, left, left); P(pixel, top, top); @@ -138,6 +139,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval P(percent, right, rright); P(percent, bottom, rbottom); #undef P + *vp = OBJECT_TO_JSVAL(obj); break; } diff --git a/source/lib/sysdep/win/wdbg.cpp b/source/lib/sysdep/win/wdbg.cpp index 69f45766bd..d6dba8d244 100755 --- a/source/lib/sysdep/win/wdbg.cpp +++ b/source/lib/sysdep/win/wdbg.cpp @@ -81,12 +81,17 @@ static void DumpMiniDump(HANDLE hFile, PEXCEPTION_POINTERS excpInfo); static HANDLE hProcess; static uintptr_t mod_base; -static wchar_t buf[64000]; /* buffer for stack trace */ +const int bufsize = 64000; +static wchar_t buf[bufsize]; /* buffer for stack trace */ static wchar_t* pos; /* current pos in buf */ static void out(wchar_t* fmt, ...) { + // Don't overflow the buffer + if (pos-buf+1000 > bufsize) + return; + va_list args; va_start(args, fmt); pos += vswprintf(pos, 1000, fmt, args); @@ -209,6 +214,8 @@ static void print_var(u32 type_idx, uint level, u64 addr) out(L"{ "); } + u32 totalelements = elements; + next_element: /* zero extend to 64 bit (little endian) */ @@ -244,8 +251,13 @@ next_element: addr += len; /* add stride */ elements--; - if(elements == 0) + /* don't display too many elements of huge arrays */ + if (totalelements-elements > 32) + out(L" ... }"); + + else if(elements == 0) out(L" }"); + else { out(L", "); @@ -264,15 +276,31 @@ static void dump_sym(u32 type_idx, uint level, u64 addr) WCHAR* type_name; if(_SymGetTypeInfo(hProcess, mod_base, type_idx, TI_GET_SYMNAME, &type_name)) { - /* HACK: ignore things that look like member functions */ + /* ignore things that look like member functions, because + there's no point in outputting them */ if (wcsstr(type_name, L"::")) + { + LocalFree(type_name); return; + } /* indent */ for(uint i = 0; i < level+2; i++) out(L" "); out(L"%ls ", type_name); + + /* exclude some specific variable types, because + they just fill the stack trace with rubbish */ + if (!wcscmp(type_name, L"JSType") + || !wcscmp(type_name, L"JSVersion") + ) + { + LocalFree(type_name); + out(L"\r\n"); + return; + } + LocalFree(type_name); } @@ -378,7 +406,7 @@ static void walk_stack(int skip, wchar_t* out_buf, CONTEXT* override_context = N bool type_avail = _SymFromAddr != 0; pos = out_buf; - out(L"\r\nCall stack:\r\n"); + out(L"\r\nCall stack:\r\n\r\n"); if(!type_avail) out(L"warning: older dbghelp.dll loaded; no type information available.\r\n"); @@ -623,28 +651,53 @@ static void set_exception_handler() // the crash log more useful, and takes the responsibility of // suiciding away from main.cpp. +void abort_timer(); // from wtime.cpp + int debug_main_exception_filter(unsigned int code, struct _EXCEPTION_POINTERS *ep) { + // If something crashes after we've already crashed (i.e. when shutting + // down everything), don't bother logging it, because the first crash + // is the most important one to fix. + static bool already_crashed = false; + if (already_crashed) + { + return EXCEPTION_EXECUTE_HANDLER; + } + already_crashed = true; + + // The timer thread sometimes dies from EXCEPTION_PRIV_INSTRUCTION + // when debugging this exception handler code (which gets quite + // annoying), so kill it before it gets a chance. + __try + { + abort_timer(); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + const wchar_t* error = NULL; // C++ exceptions put a pointer to the exception object // into ExceptionInformation[1] -- so see if it looks like // a PSERROR*, and use the relevant message if it is. - try + __try { if (ep->ExceptionRecord->NumberParameters == 3) { PSERROR* err = (PSERROR*) ep->ExceptionRecord->ExceptionInformation[1]; - if (err->magic == 0x50534552) + if (err->magic == 0x45725221) { int code = err->code; error = GetErrorString(code); } } } - catch (...) { + __except (EXCEPTION_EXECUTE_HANDLER) + { // Presumably it wasn't a PSERROR and resulted in - // accessing some invalid pointers. + // accessing invalid memory locations. + error = NULL; } // Try getting nice names for other types of error: @@ -666,7 +719,7 @@ int debug_main_exception_filter(unsigned int code, struct _EXCEPTION_POINTERS *e case EXCEPTION_FLT_UNDERFLOW: error = L"Float Underflow"; break; case EXCEPTION_INT_DIVIDE_BY_ZERO: error = L"Integer Divide By Zero"; break; case EXCEPTION_INT_OVERFLOW: error = L"Integer Overflow"; break; - case EXCEPTION_PRIV_INSTRUCTION: error = L"Private Instruction"; break; + case EXCEPTION_PRIV_INSTRUCTION: error = L"Privileged Instruction"; break; case EXCEPTION_IN_PAGE_ERROR: error = L"In Page Error"; break; case EXCEPTION_ILLEGAL_INSTRUCTION: error = L"Illegal Instruction"; break; case EXCEPTION_NONCONTINUABLE_EXCEPTION:error = L"Noncontinuable Exception"; break; @@ -697,12 +750,25 @@ int debug_main_exception_filter(unsigned int code, struct _EXCEPTION_POINTERS *e wdisplay_msg(L"0 A.D. failure", message); - debug_write_crashlog("crashlog.txt", errortext, ep->ContextRecord); + __try + { + debug_write_crashlog("crashlog.txt", errortext, ep->ContextRecord); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + wdisplay_msg(L"0 A.D. failure", L"Error generating crash log."); + } - - HANDLE hFile = CreateFile("crashlog.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0); - DumpMiniDump(hFile, ep); - CloseHandle(hFile); + __try + { + HANDLE hFile = CreateFile("crashlog.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0); + DumpMiniDump(hFile, ep); + CloseHandle(hFile); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + wdisplay_msg(L"0 A.D. failure", L"Error generating crash dump."); + } // Disable memory-leak reporting, because it's going to // leak like an upside-down bucket when it crashes. @@ -783,7 +849,7 @@ static void DumpMiniDump(HANDLE hFile, PEXCEPTION_POINTERS excpInfo) // } } -// From sysdep.h +// Imported from sysdep.cpp extern wchar_t MicroBuffer[]; extern int MicroBuffer_off; @@ -808,7 +874,7 @@ int debug_write_crashlog(const char* file, wchar_t* header, void* context) } fwrite(buf, pos-buf, 2, f); - const wchar_t* footer = L"\r\n\r\nLast known activity:\r\n\r\n"; + const wchar_t* footer = L"\r\n====================================\r\n\r\nLast known activity:\r\n\r\n"; fwrite(footer, wcslen(footer), sizeof(wchar_t), f); fwrite(MicroBuffer, MicroBuffer_off, sizeof(wchar_t), f); fclose(f); diff --git a/source/lib/sysdep/win/wtime.cpp b/source/lib/sysdep/win/wtime.cpp index c885f7c2c2..7ac3df896d 100755 --- a/source/lib/sysdep/win/wtime.cpp +++ b/source/lib/sysdep/win/wtime.cpp @@ -669,9 +669,21 @@ static int wtime_init() static int wtime_shutdown() { + static bool already_shutdown = false; + if (already_shutdown) + return -1; + + already_shutdown = true; return hrt_shutdown(); } +// Called by the crash code to kill the thread, +// because it disrupts debugging. +void abort_timer() +{ + wtime_shutdown(); +} + void wtime_reset_impl() { hrt_override_impl(HRT_DEFAULT, HRT_NONE); diff --git a/source/maths/scripting/JSInterface_Vector3D.cpp b/source/maths/scripting/JSInterface_Vector3D.cpp index e56dc9d3e9..49ef025617 100755 --- a/source/maths/scripting/JSInterface_Vector3D.cpp +++ b/source/maths/scripting/JSInterface_Vector3D.cpp @@ -98,7 +98,7 @@ JSBool JSI_Vector3D::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* case component_z: vectorData->Z = (float)g_ScriptingHost.ValueToDouble( *vp ); break; } } - catch (...) + catch (PSERROR_Scripting_ConversionFailed) { JS_ReportError(cx, "Invalid parameter value for Vector3D"); return( JS_FALSE ); @@ -126,7 +126,7 @@ JSBool JSI_Vector3D::construct( JSContext* cx, JSObject* obj, uintN argc, jsval* JS_SetPrivate( cx, obj, new Vector3D_Info( x, y, z ) ); return( JS_TRUE ); } - catch (...) + catch (PSERROR_Scripting_ConversionFailed) { // Invalid input (i.e. can't be coerced into doubles) - fail JS_ReportError( cx, "Invalid parameters to Vector3D constructor" ); diff --git a/source/ps/Errors.cpp b/source/ps/Errors.cpp index f0d6822cea..c21c41f9c1 100755 --- a/source/ps/Errors.cpp +++ b/source/ps/Errors.cpp @@ -5,20 +5,76 @@ // Slightly hacky section to redeclare things that are declared // elsewhere - trust the compiler to handle them identically +class PSERROR_GUI : public PSERROR {}; +class PSERROR_Scripting : public PSERROR {}; +class PSERROR_Scripting_DefineType : public PSERROR_Scripting {}; +class PSERROR_Scripting_LoadFile : public PSERROR_Scripting {}; class PSERROR_Xeromyces : public PSERROR {}; + +class PSERROR_GUI_JSOpenFailed : public PSERROR_GUI { public: PSERROR_GUI_JSOpenFailed(); }; +class PSERROR_GUI_TextureLoadFailed : public PSERROR_GUI { public: PSERROR_GUI_TextureLoadFailed(); }; +class PSERROR_Scripting_CallFunctionFailed : public PSERROR_Scripting { public: PSERROR_Scripting_CallFunctionFailed(); }; +class PSERROR_Scripting_ContextCreationFailed : public PSERROR_Scripting { public: PSERROR_Scripting_ContextCreationFailed(); }; +class PSERROR_Scripting_ConversionFailed : public PSERROR_Scripting { public: PSERROR_Scripting_ConversionFailed(); }; +class PSERROR_Scripting_CreateObjectFailed : public PSERROR_Scripting { public: PSERROR_Scripting_CreateObjectFailed(); }; +class PSERROR_Scripting_DefineConstantFailed : public PSERROR_Scripting { public: PSERROR_Scripting_DefineConstantFailed(); }; +class PSERROR_Scripting_DefineType_AlreadyExists : public PSERROR_Scripting_DefineType { public: PSERROR_Scripting_DefineType_AlreadyExists(); }; +class PSERROR_Scripting_DefineType_CreationFailed : public PSERROR_Scripting_DefineType { public: PSERROR_Scripting_DefineType_CreationFailed(); }; +class PSERROR_Scripting_GlobalObjectCreationFailed : public PSERROR_Scripting { public: PSERROR_Scripting_GlobalObjectCreationFailed(); }; +class PSERROR_Scripting_LoadFile_EvalErrors : public PSERROR_Scripting_LoadFile { public: PSERROR_Scripting_LoadFile_EvalErrors(); }; +class PSERROR_Scripting_LoadFile_OpenFailed : public PSERROR_Scripting_LoadFile { public: PSERROR_Scripting_LoadFile_OpenFailed(); }; +class PSERROR_Scripting_NativeFunctionSetupFailed : public PSERROR_Scripting { public: PSERROR_Scripting_NativeFunctionSetupFailed(); }; +class PSERROR_Scripting_RegisterFunctionFailed : public PSERROR_Scripting { public: PSERROR_Scripting_RegisterFunctionFailed(); }; +class PSERROR_Scripting_RuntimeCreationFailed : public PSERROR_Scripting { public: PSERROR_Scripting_RuntimeCreationFailed(); }; +class PSERROR_Scripting_StandardClassSetupFailed : public PSERROR_Scripting { public: PSERROR_Scripting_StandardClassSetupFailed(); }; +class PSERROR_Scripting_TypeDoesNotExist : public PSERROR_Scripting { public: PSERROR_Scripting_TypeDoesNotExist(); }; class PSERROR_Xeromyces_XMLOpenFailed : public PSERROR_Xeromyces { public: PSERROR_Xeromyces_XMLOpenFailed(); }; class PSERROR_Xeromyces_XMLParseError : public PSERROR_Xeromyces { public: PSERROR_Xeromyces_XMLParseError(); }; // The relevant bits of this file: -PSERROR_Xeromyces_XMLOpenFailed::PSERROR_Xeromyces_XMLOpenFailed() { magic=0x50534552; code=0; } -PSERROR_Xeromyces_XMLParseError::PSERROR_Xeromyces_XMLParseError() { magic=0x50534552; code=1; } +PSERROR_GUI_JSOpenFailed::PSERROR_GUI_JSOpenFailed() { magic=0x45725221; code=0; } +PSERROR_GUI_TextureLoadFailed::PSERROR_GUI_TextureLoadFailed() { magic=0x45725221; code=1; } +PSERROR_Scripting_DefineType_AlreadyExists::PSERROR_Scripting_DefineType_AlreadyExists() { magic=0x45725221; code=2; } +PSERROR_Scripting_DefineType_CreationFailed::PSERROR_Scripting_DefineType_CreationFailed() { magic=0x45725221; code=3; } +PSERROR_Scripting_LoadFile_EvalErrors::PSERROR_Scripting_LoadFile_EvalErrors() { magic=0x45725221; code=4; } +PSERROR_Scripting_LoadFile_OpenFailed::PSERROR_Scripting_LoadFile_OpenFailed() { magic=0x45725221; code=5; } +PSERROR_Scripting_CallFunctionFailed::PSERROR_Scripting_CallFunctionFailed() { magic=0x45725221; code=6; } +PSERROR_Scripting_ContextCreationFailed::PSERROR_Scripting_ContextCreationFailed() { magic=0x45725221; code=7; } +PSERROR_Scripting_ConversionFailed::PSERROR_Scripting_ConversionFailed() { magic=0x45725221; code=8; } +PSERROR_Scripting_CreateObjectFailed::PSERROR_Scripting_CreateObjectFailed() { magic=0x45725221; code=9; } +PSERROR_Scripting_DefineConstantFailed::PSERROR_Scripting_DefineConstantFailed() { magic=0x45725221; code=10; } +PSERROR_Scripting_GlobalObjectCreationFailed::PSERROR_Scripting_GlobalObjectCreationFailed() { magic=0x45725221; code=11; } +PSERROR_Scripting_NativeFunctionSetupFailed::PSERROR_Scripting_NativeFunctionSetupFailed() { magic=0x45725221; code=12; } +PSERROR_Scripting_RegisterFunctionFailed::PSERROR_Scripting_RegisterFunctionFailed() { magic=0x45725221; code=13; } +PSERROR_Scripting_RuntimeCreationFailed::PSERROR_Scripting_RuntimeCreationFailed() { magic=0x45725221; code=14; } +PSERROR_Scripting_StandardClassSetupFailed::PSERROR_Scripting_StandardClassSetupFailed() { magic=0x45725221; code=15; } +PSERROR_Scripting_TypeDoesNotExist::PSERROR_Scripting_TypeDoesNotExist() { magic=0x45725221; code=16; } +PSERROR_Xeromyces_XMLOpenFailed::PSERROR_Xeromyces_XMLOpenFailed() { magic=0x45725221; code=17; } +PSERROR_Xeromyces_XMLParseError::PSERROR_Xeromyces_XMLParseError() { magic=0x45725221; code=18; } const wchar_t* GetErrorString(int code) { switch (code) { - case 0: return L"Xeromyces_XMLOpenFailed"; break; - case 1: return L"Xeromyces_XMLParseError"; break; + case 0: return L"GUI_JSOpenFailed"; break; + case 1: return L"GUI_TextureLoadFailed"; break; + case 2: return L"Scripting_DefineType_AlreadyExists"; break; + case 3: return L"Scripting_DefineType_CreationFailed"; break; + case 4: return L"Scripting_LoadFile_EvalErrors"; break; + case 5: return L"Scripting_LoadFile_OpenFailed"; break; + case 6: return L"Scripting_CallFunctionFailed"; break; + case 7: return L"Scripting_ContextCreationFailed"; break; + case 8: return L"Scripting_ConversionFailed"; break; + case 9: return L"Scripting_CreateObjectFailed"; break; + case 10: return L"Scripting_DefineConstantFailed"; break; + case 11: return L"Scripting_GlobalObjectCreationFailed"; break; + case 12: return L"Scripting_NativeFunctionSetupFailed"; break; + case 13: return L"Scripting_RegisterFunctionFailed"; break; + case 14: return L"Scripting_RuntimeCreationFailed"; break; + case 15: return L"Scripting_StandardClassSetupFailed"; break; + case 16: return L"Scripting_TypeDoesNotExist"; break; + case 17: return L"Xeromyces_XMLOpenFailed"; break; + case 18: return L"Xeromyces_XMLParseError"; break; } return L"Unrecognised error"; } diff --git a/source/ps/Errors.h b/source/ps/Errors.h index 65cbfec1ee..96725a0803 100755 --- a/source/ps/Errors.h +++ b/source/ps/Errors.h @@ -6,8 +6,9 @@ class PSERROR { public: - int magic; // = 0x50534552, so the exception handler can recognise that it's a PSERROR - int code; + int magic; // = 0x45725221, so the exception handler can recognise + // that it's a PSERROR and not some other random object. + int code; // unique (but arbitrary) code, for translation tables etc }; #define ERROR_GROUP(a,b) class a##_##b : public a {} diff --git a/source/ps/Xeromyces.h b/source/ps/Xeromyces.h index 961bc6efc6..9159c79d81 100755 --- a/source/ps/Xeromyces.h +++ b/source/ps/Xeromyces.h @@ -1,4 +1,4 @@ -/* $Id: Xeromyces.h,v 1.3 2004/07/15 19:08:28 philip Exp $ +/* $Id: Xeromyces.h,v 1.4 2004/07/17 17:06:21 philip Exp $ Xeromyces file-loading interface. Automatically creates and caches relatively @@ -25,13 +25,12 @@ public: ~CXeromyces(); // Load from an XML file (with invisible XMB caching). - // Throws a const char* if stuff breaks. + // Throws a PSERROR_Xeromyces upon failure. void Load(const char* filename); - // Call once when shutting down the program. + // Call once when shutting down the program, to unload Xerces. static void Terminate(); - private: bool ReadXMBFile(const char* filename, bool CheckCRC, unsigned long CRC); diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 0e13ea5c24..7a28cbf887 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -85,7 +85,7 @@ JSBool getEntityByHandle( JSContext* context, JSObject* globalObject, unsigned i { handle = g_ScriptingHost.ValueToInt( argv[0] ); } - catch( ... ) + catch( PSERROR_Scripting_ConversionFailed ) { *rval = JSVAL_NULL; return( JS_TRUE ); @@ -110,7 +110,7 @@ JSBool getEntityTemplate( JSContext* context, JSObject* globalObject, unsigned i { templateName = g_ScriptingHost.ValueToString( argv[0] ); } - catch( ... ) + catch( PSERROR_Scripting_ConversionFailed ) { *rval = JSVAL_NULL; return( JS_TRUE ); diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp index 4ecd6e2966..6eec7e9466 100755 --- a/source/scripting/ScriptingHost.cpp +++ b/source/scripting/ScriptingHost.cpp @@ -41,36 +41,26 @@ ScriptingHost::ScriptingHost() : m_RunTime(NULL), m_Context(NULL), m_GlobalObjec { m_RunTime = JS_NewRuntime(RUNTIME_MEMORY_ALLOWANCE); - if (m_RunTime == NULL) - { - throw (std::string("ScriptingHost: Failed to create JavaScript runtime")); - } + if (m_RunTime == NULL) + throw PSERROR_Scripting_RuntimeCreationFailed(); m_Context = JS_NewContext(m_RunTime, STACK_CHUNK_SIZE); - if (m_Context == NULL) - { - throw (std::string("ScriptingHost: Failed to create JavaScript context")); - } + if (m_Context == NULL) + throw PSERROR_Scripting_ContextCreationFailed(); JS_SetErrorReporter(m_Context, ScriptingHost::ErrorReporter); m_GlobalObject = JS_NewObject(m_Context, &GlobalClass, NULL, NULL); if (m_GlobalObject == NULL) - { - throw (std::string("ScriptingHost: Failed to create global object")); - } + throw PSERROR_Scripting_GlobalObjectCreationFailed(); if (JS_InitStandardClasses(m_Context, m_GlobalObject) == JSVAL_FALSE) - { - throw (std::string("ScriptingHost: Failed to init standard classes")); - } + throw PSERROR_Scripting_StandardClassSetupFailed(); if (JS_DefineFunctions(m_Context, m_GlobalObject, ScriptFunctionTable) == JS_FALSE) - { - throw (std::string("ScriptingHost: Failed to setup native functions")); - } + throw PSERROR_Scripting_NativeFunctionSetupFailed(); std::cout << "Scripting environment initialized" << std::endl; } @@ -103,9 +93,7 @@ void ScriptingHost::LoadScriptFromDisk(const std::string & fileName) std::ifstream scriptFile(fileName.c_str()); if (scriptFile.is_open() == false) - { - throw (std::string("Could not open file: ") + fileName); - } + throw PSERROR_Scripting_LoadFile_OpenFailed(); while (scriptFile.eof() == false) { @@ -118,9 +106,7 @@ void ScriptingHost::LoadScriptFromDisk(const std::string & fileName) JSBool ok = JS_EvaluateScript(m_Context, m_GlobalObject, script.c_str(), (unsigned int)script.length(), fileName.c_str(), 0, &rval); if (ok == JS_FALSE) - { - throw (std::string("Error loading script from disk: ") + fileName); - } + throw PSERROR_Scripting_LoadFile_EvalErrors(); } jsval ScriptingHost::CallFunction(const std::string & functionName, jsval * params, int numParams) @@ -130,9 +116,7 @@ jsval ScriptingHost::CallFunction(const std::string & functionName, jsval * para JSBool ok = JS_CallFunctionName(m_Context, m_GlobalObject, functionName.c_str(), numParams, params, &result); if (ok == JS_FALSE) - { - throw (std::string("Failure whilst calling script funtion: ") + functionName); - } + throw PSERROR_Scripting_CallFunctionFailed(); return result; } @@ -153,9 +137,7 @@ void ScriptingHost::RegisterFunction(const std::string & functionName, JSNative JSFunction * func = JS_DefineFunction(m_Context, m_GlobalObject, functionName.c_str(), function, numArgs, 0); if (func == NULL) - { - throw (std::string("Could not register function ") + functionName); - } + throw PSERROR_Scripting_RegisterFunctionFailed(); } void ScriptingHost::DefineConstant(const std::string & name, int value) @@ -167,9 +149,7 @@ void ScriptingHost::DefineConstant(const std::string & name, int value) NULL, NULL, JSPROP_READONLY); if (ok == JS_FALSE) - { - throw (std::string("Could not create constant")); - } + throw PSERROR_Scripting_DefineConstantFailed(); } void ScriptingHost::DefineConstant(const std::string & name, double value) @@ -190,9 +170,7 @@ void ScriptingHost::DefineConstant(const std::string & name, double value) JSBool ok = JS_DefineConstDoubles(m_Context, m_GlobalObject, spec); if (ok == JS_FALSE) - { - throw (std::string("Could not create constant")); - } + throw PSERROR_Scripting_DefineConstantFailed(); } void ScriptingHost::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uintN minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) @@ -202,7 +180,7 @@ void ScriptingHost::DefineCustomObjectType(JSClass *clasp, JSNative constructor, if (m_CustomObjectTypes.find(typeName) != m_CustomObjectTypes.end()) { // This type already exists - throw std::string("Type already exists"); + throw PSERROR_Scripting_DefineType_AlreadyExists(); } JSObject * obj = JS_InitClass( m_Context, m_GlobalObject, 0, @@ -222,7 +200,7 @@ void ScriptingHost::DefineCustomObjectType(JSClass *clasp, JSNative constructor, } else { - throw std::string("Type creation failed"); + throw PSERROR_Scripting_DefineType_CreationFailed(); } } @@ -231,9 +209,7 @@ JSObject * ScriptingHost::CreateCustomObject(const std::string & typeName) std::map < std::string, CustomType > ::iterator it = m_CustomObjectTypes.find(typeName); if (it == m_CustomObjectTypes.end()) - { - throw std::string("Tried to create a type that doesn't exist"); - } + throw PSERROR_Scripting_TypeDoesNotExist(); return JS_ConstructObject(m_Context, (*it).second.m_Class, (*it).second.m_Object, NULL); @@ -270,9 +246,7 @@ int ScriptingHost::ValueToInt(const jsval value) JSBool ok = JS_ValueToInt32(m_Context, value, &i); if (ok == JS_FALSE) - { - throw (std::string("Convert to int failed")); - } + throw PSERROR_Scripting_ConversionFailed(); return i; } @@ -284,9 +258,7 @@ bool ScriptingHost::ValueToBool(const jsval value) JSBool ok = JS_ValueToBoolean(m_Context, value, &b); if (ok == JS_FALSE) - { - throw (std::string("Convert to bool failed")); - } + throw PSERROR_Scripting_ConversionFailed(); return b == JS_TRUE; } @@ -295,7 +267,11 @@ std::string ScriptingHost::ValueToString(const jsval value) { JSString * string = JS_ValueToString(m_Context, value); - return std::string(JS_GetStringBytes(string)); + char * bytes = JS_GetStringBytes(string); + if (bytes == NULL) + throw PSERROR_Scripting_ConversionFailed(); + + return std::string(bytes); } double ScriptingHost::ValueToDouble(const jsval value) @@ -305,9 +281,7 @@ double ScriptingHost::ValueToDouble(const jsval value) JSBool ok = JS_ValueToNumber(m_Context, value, &d); if (ok == JS_FALSE || !finite( d ) ) - { - throw (std::string("Convert to double failed")); - } + throw PSERROR_Scripting_ConversionFailed(); return d; } diff --git a/source/scripting/ScriptingHost.h b/source/scripting/ScriptingHost.h index 3772a0e634..2dcd00ea0c 100755 --- a/source/scripting/ScriptingHost.h +++ b/source/scripting/ScriptingHost.h @@ -12,6 +12,28 @@ # endif #endif +ERROR_GROUP(PSERROR, Scripting); +ERROR_TYPE(PSERROR_Scripting, RuntimeCreationFailed); +ERROR_TYPE(PSERROR_Scripting, ContextCreationFailed); +ERROR_TYPE(PSERROR_Scripting, GlobalObjectCreationFailed); +ERROR_TYPE(PSERROR_Scripting, StandardClassSetupFailed); +ERROR_TYPE(PSERROR_Scripting, NativeFunctionSetupFailed); + +ERROR_GROUP(PSERROR_Scripting, LoadFile); +ERROR_TYPE(PSERROR_Scripting_LoadFile, OpenFailed); +ERROR_TYPE(PSERROR_Scripting_LoadFile, EvalErrors); + +ERROR_TYPE(PSERROR_Scripting, ConversionFailed); +ERROR_TYPE(PSERROR_Scripting, CallFunctionFailed); +ERROR_TYPE(PSERROR_Scripting, RegisterFunctionFailed); +ERROR_TYPE(PSERROR_Scripting, DefineConstantFailed); +ERROR_TYPE(PSERROR_Scripting, CreateObjectFailed); +ERROR_TYPE(PSERROR_Scripting, TypeDoesNotExist); + +ERROR_GROUP(PSERROR_Scripting, DefineType); +ERROR_TYPE(PSERROR_Scripting_DefineType, AlreadyExists); +ERROR_TYPE(PSERROR_Scripting_DefineType, CreationFailed); + #include #include diff --git a/source/simulation/BaseEntity.cpp b/source/simulation/BaseEntity.cpp index fcd5e36c19..b1a50a014a 100755 --- a/source/simulation/BaseEntity.cpp +++ b/source/simulation/BaseEntity.cpp @@ -33,8 +33,8 @@ bool CBaseEntity::loadXML( CStr filename ) { XeroFile.Load(filename); } - catch (...) - { + catch (PSERROR_Xeromyces) { + // Fail return false; } diff --git a/source/simulation/EntityProperties.cpp b/source/simulation/EntityProperties.cpp index 125770102d..f4b9232e74 100755 --- a/source/simulation/EntityProperties.cpp +++ b/source/simulation/EntityProperties.cpp @@ -54,7 +54,7 @@ void CProperty_i32::set( jsval value ) { *modifier = (float)g_ScriptingHost.ValueToInt( value ); } - catch( ... ) + catch( PSERROR_Scripting_ConversionFailed ) { *modifier = 0; } @@ -116,7 +116,7 @@ void CProperty_float::set( const jsval value ) { *modifier = (float)g_ScriptingHost.ValueToDouble( value ); } - catch( ... ) + catch( PSERROR_Scripting_ConversionFailed ) { *modifier = 0.0f; } @@ -218,7 +218,7 @@ void CProperty_CStr::set( jsval value ) { *modifier = g_ScriptingHost.ValueToString( value ); } - catch( ... ) + catch( PSERROR_Scripting_ConversionFailed ) { *modifier = CStr(); m_String.clear(); diff --git a/source/simulation/scripting/JSInterface_Entity.cpp b/source/simulation/scripting/JSInterface_Entity.cpp index ff0e7eeb5f..daea7284d3 100755 --- a/source/simulation/scripting/JSInterface_Entity.cpp +++ b/source/simulation/scripting/JSInterface_Entity.cpp @@ -79,7 +79,7 @@ JSBool JSI_Entity::construct( JSContext* cx, JSObject* obj, unsigned int argc, j { templateName = g_ScriptingHost.ValueToString( argv[0] ); } - catch( ... ) + catch( PSERROR_Scripting_ConversionFailed ) { *rval = JSVAL_NULL; return( JS_TRUE ); @@ -100,7 +100,7 @@ JSBool JSI_Entity::construct( JSContext* cx, JSObject* obj, unsigned int argc, j { orientation = (float)g_ScriptingHost.ValueToDouble( argv[2] ); } - catch( ... ) + catch( PSERROR_Scripting_ConversionFailed ) { orientation = 0.0f; }