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