diff --git a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj index 730247409..e28a5c90a 100644 --- a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj +++ b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj @@ -1819,6 +1819,10 @@ RelativePath="..\..\src\include\aegisub\audio_provider.h" > + + diff --git a/aegisub/src/ass_dialogue.cpp b/aegisub/src/ass_dialogue.cpp index 2b6b1e231..6b93a428e 100644 --- a/aegisub/src/ass_dialogue.cpp +++ b/aegisub/src/ass_dialogue.cpp @@ -726,7 +726,7 @@ void AssDialogue::SetMarginString(const wxString origvalue,int which) { if (value > 9999) value = 9999; // Assign - if (which < 0 || which >= 4) throw _T("Invalid margin id"); + if (which < 0 || which >= 4) throw new Aegisub::InvalidMarginIdError; Margin[which] = value; } @@ -734,7 +734,7 @@ void AssDialogue::SetMarginString(const wxString origvalue,int which) { ////////////////////////// // Gets string for margin wxString AssDialogue::GetMarginString(int which,bool pad) { - if (which < 0 || which >= 4) throw _T("Invalid margin id"); + if (which < 0 || which >= 4) throw new Aegisub::InvalidMarginIdError; int value = Margin[which]; if (pad) return wxString::Format(_T("%04i"),value); else return wxString::Format(_T("%i"),value); diff --git a/aegisub/src/ass_entry.h b/aegisub/src/ass_entry.h index 15c865ab3..3081f6539 100644 --- a/aegisub/src/ass_entry.h +++ b/aegisub/src/ass_entry.h @@ -41,6 +41,7 @@ // Headers #include #include +#include "include/aegisub/exception.h" ////////////// @@ -60,6 +61,17 @@ enum ASS_EntryType { }; +namespace Aegisub { + // Thrown when someone supplies an invalid margin ID to a function expecting one + // (Usually limited to range 0..3.) + class InvalidMarginIdError : public InternalError { + public: + InvalidMarginIdError() : InternalError(_T("Invalid margin id"), 0) { } + const wxChar *GetName() { return _T("internal_error/invalid_margin_id"); } + }; +}; + + //////////////////////////////////// // Base class for each line in file class AssEntry { diff --git a/aegisub/src/ass_style.cpp b/aegisub/src/ass_style.cpp index 7b2c4737a..2a2089d22 100644 --- a/aegisub/src/ass_style.cpp +++ b/aegisub/src/ass_style.cpp @@ -439,7 +439,7 @@ void AssStyle::UpdateData() { ///////////////////////////// // Sets margin from a string void AssStyle::SetMarginString(const wxString str,int which) { - if (which < 0 || which >= 4) throw _T("Invalid margin id"); + if (which < 0 || which >= 4) throw new Aegisub::InvalidMarginIdError; if (!str.IsNumber()) throw _T("Invalid margin value"); long value; str.ToLong(&value); @@ -453,7 +453,7 @@ void AssStyle::SetMarginString(const wxString str,int which) { ////////////////////////// // Gets string for margin wxString AssStyle::GetMarginString(int which) { - if (which < 0 || which >= 4) throw _T("Invalid margin id"); + if (which < 0 || which >= 4) throw new Aegisub::InvalidMarginIdError; wxString result = wxString::Format(_T("%04i"),Margin[which]); return result; } diff --git a/aegisub/src/include/aegisub/exception.h b/aegisub/src/include/aegisub/exception.h new file mode 100644 index 000000000..df18c3cc6 --- /dev/null +++ b/aegisub/src/include/aegisub/exception.h @@ -0,0 +1,120 @@ +// Copyright (c) 2009, Niels Martin Hansen +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + + +#include + + +namespace Aegisub { + + // Base class for exceptions + // No public creators, all exceptions throws must be specific + class Exception { + Exception *inner; + wxString message; + + protected: + Exception(const wxString &msg, Exception *inr = 0) : message(msg), inner(inr) { } + Exception(); // not implemented, not wanted + virtual ~Exception() { if (inner) delete inner; } + + public: + // Error message for outer exception + virtual wxString GetMessage() const { return message; } + // Error message for outer exception, and chained message for inner exception + wxString GetChainedMessage() const { if (inner) return inner->GetChainedMessage() + _T("\r\n") + GetMessage(); else return GetMessage(); } + // Name of exception class, should only be implemented by specific classes + virtual const wxChar * GetName() const = 0; + + operator const wxChar * () { return GetMessage().c_str(); } + operator wxString () { return GetMessage(); } + }; + + + // Macro to quickly add location information to an error message +#define AG_WHERE _T(" (at ") _T(__FILE__) _T(":") _T(#__LINE__) _T(")") + + + // Macros to define basic exception classes that do nothing fancy + // These should always be used inside the Aegisub namespace +#define DEFINE_SIMPLE_EXCEPTION_NOINNER(classname,baseclass,displayname) \ + class classname : public baseclass { \ + public: \ + classname(const wxString &msg) : baseclass(msg) { } \ + const wxChar * GetName() const { return _T(displayname); } \ + }; +#define DEFINE_SIMPLE_EXCEPTION(classname,baseclass,displayname) \ + class classname : public baseclass { \ + public: \ + classname(const wxString &msg, Exception *inner) : baseclass(msg, inner) { } \ + const wxChar * GetName() const { return _T(displayname); } \ + }; +#define DEFINE_BASE_EXCEPTION_NOINNER(classname,baseclass) \ + class classname : public baseclass { \ + public: \ + classname(const wxString &msg) : baseclass(msg) { } \ + }; +#define DEFINE_BASE_EXCEPTION(classname,baseclass) \ + class classname : public baseclass { \ + public: \ + classname(const wxString &msg, Exception *inner) : baseclass(msg, inner) { } \ + }; + + + // Exception for "user cancel" events + // I.e. when we want to abort an operation because the user requested that we do so + // Not actually an error and should not be handled as such + DEFINE_SIMPLE_EXCEPTION_NOINNER(UserCancelException,Exception,"nonerror/user_cancel") + + + // Errors that should never happen and point to some invalid assumption in the code + DEFINE_SIMPLE_EXCEPTION(InternalError, Exception, "internal_error") + + + // Some error related to the filesystem + // These should always be original causes and as such do not support inner exceptions + DEFINE_BASE_EXCEPTION_NOINNER(FileSystemError,Exception) + + // A file can't be accessed for some reason + DEFINE_SIMPLE_EXCEPTION_NOINNER(FileNotAccessibleError,FileSystemError,"filesystem/not_accessible") + + // A file isn't accessible because it doesn't exist + class FileNotFoundError : public FileNotAccessibleError { + public: + FileNotFoundError(const wxString &filename) : FileNotAccessibleError(wxString(_T("File not found: ")) + filename) { } + const wxChar * GetName() const { return _T("filesystem/not_accessible/not_found"); } + }; + + + // A problem with some input data + DEFINE_BASE_EXCEPTION(InvalidInputException,Exception) + + + // There is no "generic exception" class, everything must be a specific one + // Define new classes if none fit the error you're reporting + +};