1 // Copyright (c) 2009, Niels Martin Hansen
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //   * Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //   * Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //   * Neither the name of the Aegisub Group nor the names of its contributors
13 //     may be used to endorse or promote products derived from this software
14 //     without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 // POSSIBILITY OF SUCH DAMAGE.
27 //
28 // Aegisub Project http://www.aegisub.org/
29 
30 #pragma once
31 
32 #include <string>
33 
34 namespace agi {
35 	/// @class Exception
36 	/// @brief Base class for all exceptions in Aegisub.
37 	///
38 	/// All exceptions thrown by Aegisub should derive from this class.
39 	/// It is incorrect to throw anything that is not a subclass of this.
40 	///
41 	/// However, there are no public constructors for this class, it should
42 	/// not be instantiated and thrown directly. Throw instances of a
43 	/// relevant sub class, declare a new one if necessary. It is allowed to
44 	/// declare sub classes of Exception and derivates in private headers
45 	/// and even inside source files, as long as a caller has a chance to
46 	/// catch the exception thrown.
47 	///
48 	/// When throwing exceptions, throw temporaries, not heap allocated
49 	/// objects. (C++ FAQ Lite 17.6.) I.e. this is correct:
50 	/// @code
51 	/// throw agi::SomeException("Message for exception");
52 	/// @endcode
53 	/// This is wrong:
54 	/// @code
55 	/// throw new agi::SomeException("Remember this is the wrong way!");
56 	/// @endcode
57 	/// Exceptions must not be allocated on heap, because of the risks of
58 	/// leaking memory that way. (C++ FAQ Lite 17.8.)
59 	///
60 	/// When catching exceptions, make sure you catch them by reference,
61 	/// otherwise polymorphism will not work. (The C++ Programming
62 	/// Language Special Edition 14.2.1, C++ FAQ Lite 17.7.)
63 	///
64 	/// Catch like this:
65 	/// @code
66 	/// try {
67 	///     /* ... */
68 	/// }
69 	/// catch (agi::UserCancelException &e) {
70 	///     /* handle the fact that the user cancelled */
71 	/// }
72 	/// catch (agi::VideoInputException &e) {
73 	///     /* handle the video provider failing */
74 	/// }
75 	/// @endcode
76 	/// Don't always handle all exceptions the code you're protected might
77 	/// throw, sometimes it's better to let an exception slip through and
78 	/// let code further out handle it. Sometimes you might want to catch and
79 	/// package an exception into something else, for example to represent
80 	/// cases such as "subtitle file could not be read @e because the file
81 	/// could not be opened for reading". This is the purpose of the "inner"
82 	/// exceptions.
83 	class Exception {
84 		/// The error message
85 		std::string message;
86 
87 	protected:
88 		/// @brief Protected constructor initialising members
89 		/// @param msg The error message
90 		///
91 		/// Deriving classes should always use this constructor for initialising
92 		/// the base class.
Exception(std::string msg)93 		Exception(std::string msg) : message(std::move(msg)) { }
94 
95 	public:
96 		/// @brief Destructor
~Exception()97 		virtual ~Exception() { }
98 
99 		/// @brief Get the outer exception error message
100 		/// @return Error message
GetMessage()101 		std::string const& GetMessage() const { return message; }
102 	};
103 
104 /// @brief Convenience macro to include the current location in code
105 ///
106 /// Intended for use in error messages where it can sometimes be convenient to
107 /// indicate the exact position the error occurred at.
108 #define AG_WHERE " (at " __FILE__ ":" #__LINE__ ")"
109 
110 /// @brief Convenience macro for declaring exceptions
111 /// @param classname   Name of the exception class to declare
112 /// @param baseclass   Class to derive from
113 #define DEFINE_EXCEPTION(classname, baseclass)                 \
114 class classname : public baseclass {                           \
115 public:                                                        \
116 	classname(std::string msg) : baseclass(std::move(msg)) { } \
117 }
118 
119 	/// @class agi::UserCancelException
120 	/// @extends agi::Exception
121 	/// @brief Exception for "user cancel" events
122 	///
123 	/// I.e. when we want to abort an operation because the user requested that we do so.
124 	/// Not actually an error and should not be handled as such.
125 	///
126 	/// This is intended to signal that an operation should be completely aborted at the
127 	/// request of the user, and should usually be handled as close to the main UI as
128 	/// possible, user cancel exceptions should unwind anything that was going on at the
129 	/// moment. For this to work, RAII methodology has to be used consequently in the
130 	/// code in question.
131 	DEFINE_EXCEPTION(UserCancelException, Exception);
132 
133 	/// @class agi::InternalError
134 	/// @extends agi:Exception
135 	/// @brief Errors that should never happen and point to some invalid assumption in the code
136 	///
137 	/// Throw an internal error when a sanity check fails, and the insanity should have
138 	/// been caught and handled at an earlier stage, i.e. when something seems to
139 	/// have become inconsistent. All internal errors are of the type "this should never
140 	/// happen", most often you'll want this kind of error unwind all the way past the main UI
141 	/// and eventually cause an abort().
142 	DEFINE_EXCEPTION(InternalError, Exception);
143 
144 	/// @class agi::EnvironmentError
145 	/// @extends agi:Exception
146 	/// @brief The execution environment is broken in some fundamental way
147 	///
148 	/// Throw an environment error when a call to the platform API has failed
149 	/// in some way that should normally never happen or suggests that the
150 	/// runtime environment is too insane to support.
151 	DEFINE_EXCEPTION(EnvironmentError, Exception);
152 
153 	/// @class agi::InvalidInputException
154 	/// @extends agi::Exception
155 	/// @brief Some input data were invalid and could not be processed
156 	DEFINE_EXCEPTION(InvalidInputException, Exception);
157 }
158