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
+
+};