/[pcsx2_0.9.7]/trunk/common/include/Utilities/Exceptions.h
ViewVC logotype

Contents of /trunk/common/include/Utilities/Exceptions.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 11 months ago) by william
File MIME type: text/plain
File size: 14749 byte(s)
committing r3113 initial commit again...
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #pragma once
17
18 #include "Dependencies.h"
19 #include "StringHelpers.h"
20
21 // --------------------------------------------------------------------------------------
22 // DESTRUCTOR_CATCHALL - safe destructor helper
23 // --------------------------------------------------------------------------------------
24 // In C++ destructors *really* need to be "nothrow" garaunteed, otherwise you can have
25 // disasterous nested exception throws during the unwinding process of an originating
26 // exception. Use this macro to dispose of these dangerous exceptions, and generate a
27 // friendly error log in their wake.
28 //
29 #define __DESTRUCTOR_CATCHALL( funcname ) \
30 catch( BaseException& ex ) \
31 { \
32 Console.Error( "Unhandled BaseException in %s (ignored!):", funcname ); \
33 Console.Error( ex.FormatDiagnosticMessage() ); \
34 } \
35 catch( std::exception& ex ) \
36 { \
37 Console.Error( "Unhandled std::exception in %s (ignored!):", funcname ); \
38 Console.Error( ex.what() ); \
39 }
40
41 #define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL( __pxFUNCTION__ )
42
43 namespace Exception
44 {
45 int MakeNewType();
46
47 // --------------------------------------------------------------------------------------
48 // BaseException
49 // --------------------------------------------------------------------------------------
50 // std::exception sucks, and isn't entirely cross-platform reliable in its implementation,
51 // so I made a replacement. The internal messages are non-const, which means that a
52 // catch clause can optionally modify them and then re-throw to a top-level handler.
53 //
54 // Note, this class is "abstract" which means you shouldn't use it directly like, ever.
55 // Use Exception::RuntimeError instead for generic exceptions.
56 //
57 // Because exceptions are the (only!) really useful example of multiple inheritance,
58 // this class has only a trivial constructor, and must be manually initialized using
59 // InitBaseEx() or by individual member assignments. This is because C++ multiple inheritence
60 // is, by design, a lot of fail, especially when class initializers are mixed in.
61 //
62 // [TODO] : Add an InnerException component, and Clone() facility.
63 //
64 class BaseException
65 {
66 protected:
67 wxString m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
68 wxString m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
69 wxString m_stacktrace; // contains the stack trace string dump (unimplemented)
70
71 public:
72 virtual ~BaseException() throw()=0; // the =0; syntax forces this class into "abstract" mode.
73
74 const wxString& DiagMsg() const { return m_message_diag; }
75 const wxString& UserMsg() const { return m_message_user; }
76
77 wxString& DiagMsg() { return m_message_diag; }
78 wxString& UserMsg() { return m_message_user; }
79
80 // Returns a message suitable for diagnostic / logging purposes.
81 // This message is always in English, and includes a full stack trace.
82 virtual wxString FormatDiagnosticMessage() const;
83
84 // Returns a message suitable for end-user display.
85 // This message is usually meant for display in a user popup or such.
86 virtual wxString FormatDisplayMessage() const { return m_message_user; }
87
88 virtual void Rethrow() const=0;
89 virtual BaseException* Clone() const=0;
90
91 protected:
92 // Construction using two pre-formatted pre-translated messages
93 void InitBaseEx( const wxString& msg_eng, const wxString& msg_xlt );
94
95 // Construction using one translation key.
96 void InitBaseEx( const char* msg_eng );
97 };
98
99 // --------------------------------------------------------------------------------------
100 // Ps2Generic Exception
101 // --------------------------------------------------------------------------------------
102 // This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
103 //
104 // Implementation note: does not derive from BaseException, so that we can use different
105 // catch block hierarchies to handle them (if needed).
106 //
107 // Translation Note: Currently these exceptions are never translated. English/diagnostic
108 // format only. :)
109 //
110 class Ps2Generic
111 {
112 protected:
113 wxString m_message; // a "detailed" message of what disastrous thing has occurred!
114
115 public:
116 virtual ~Ps2Generic() throw() {}
117
118 virtual u32 GetPc() const=0;
119 virtual bool IsDelaySlot() const=0;
120 virtual wxString Message() const { return m_message; }
121 };
122
123 // Some helper macros for defining the standard constructors of internationalized constructors
124 // Parameters:
125 // classname - Yeah, the name of this class being defined. :)
126 //
127 // defmsg - default message (in english), which will be used for both english and i18n messages.
128 // The text string will be passed through the translator, so if it's int he gettext database
129 // it will be optionally translated.
130 //
131 // BUGZ?? I'd rather use 'classname' on the Clone() prototype, but for some reason it generates
132 // ambiguity errors on virtual inheritence (it really shouldn't!). So I have to force it to the
133 // BaseException base class. Not sure if this is Stupid Standard Tricks or Stupid MSVC Tricks. --air
134 //
135 // (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
136 //
137 #define DEFINE_EXCEPTION_COPYTORS( classname ) \
138 virtual ~classname() throw() {} \
139 virtual void Rethrow() const { throw *this; } \
140 virtual BaseException* Clone() const { return new classname( *this ); }
141
142 // This is here because MSVC's support for covariant return types on Clone() is broken, and will
143 // not work with virtual class inheritance (see DEFINE_EXCEPTION_COPYTORS for details)
144 #define DEFINE_EXCEPTION_COPYTORS_COVARIANT( classname ) \
145 virtual ~classname() throw() {} \
146 virtual void Rethrow() const { throw *this; } \
147 virtual classname* Clone() const { return new classname( *this ); }
148
149 #define DEFINE_RUNTIME_EXCEPTION( classname, defmsg ) \
150 DEFINE_EXCEPTION_COPYTORS( classname ) \
151 \
152 explicit classname( const char* msg=defmsg ) { BaseException::InitBaseEx( msg ); } \
153 explicit classname( const wxString& msg_eng, const wxString& msg_xlt ) { BaseException::InitBaseEx( msg_eng, msg_xlt); }
154
155 #define DEFINE_LOGIC_EXCEPTION( classname, defmsg ) \
156 DEFINE_EXCEPTION_COPYTORS( classname ) \
157 \
158 explicit classname( const char* msg=defmsg ) { BaseException::InitBaseEx( msg ); } \
159 explicit classname( const wxString& msg_eng ) { BaseException::InitBaseEx( msg_eng, wxEmptyString ); }
160
161 // ---------------------------------------------------------------------------------------
162 // RuntimeError - Generalized Exceptions with Recoverable Traits!
163 // ---------------------------------------------------------------------------------------
164
165 class RuntimeError : public virtual BaseException
166 {
167 public:
168 bool IsSilent;
169 public:
170 DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
171
172 RuntimeError( const std::runtime_error& ex, const wxString& prefix=wxEmptyString );
173 RuntimeError( const std::exception& ex, const wxString& prefix=wxEmptyString );
174 };
175
176 // --------------------------------------------------------------------------------------
177 // CancelAppEvent - Exception for canceling an event in a non-verbose fashion
178 // --------------------------------------------------------------------------------------
179 // Typically the PCSX2 interface issues popup dialogs for runtime errors. This exception
180 // instead issues a "silent" cancelation that is handled by the app gracefully (generates
181 // log, and resumes messages queue processing).
182 //
183 // I chose to have this exception derive from RuntimeError, since if one is thrown from outside
184 // an App message loop we'll still want it to be handled in a reasonably graceful manner.
185 class CancelEvent : public virtual RuntimeError
186 {
187 public:
188 DEFINE_EXCEPTION_COPYTORS( CancelEvent )
189
190 explicit CancelEvent( const char* logmsg )
191 {
192 m_message_diag = fromUTF8( logmsg );
193 // overridden message formatters only use the diagnostic version...
194 }
195
196 explicit CancelEvent( const wxString& logmsg=L"No reason given." )
197 {
198 m_message_diag = logmsg;
199 // overridden message formatters only use the diagnostic version...
200 }
201
202 virtual wxString FormatDisplayMessage() const;
203 virtual wxString FormatDiagnosticMessage() const;
204 };
205
206 // --------------------------------------------------------------------------------------
207 class ObjectIsNull : public virtual CancelEvent
208 {
209 public:
210 wxString ObjectName;
211
212 DEFINE_EXCEPTION_COPYTORS( ObjectIsNull )
213
214 explicit ObjectIsNull( const char* objname="unspecified" )
215 {
216 m_message_diag = fromUTF8( objname );
217 // overridden message formatters only use the diagnostic version...
218 }
219
220 virtual wxString FormatDisplayMessage() const;
221 virtual wxString FormatDiagnosticMessage() const;
222 };
223
224 // ---------------------------------------------------------------------------------------
225 // OutOfMemory / InvalidOperation / InvalidArgument / ParseError
226 // ---------------------------------------------------------------------------------------
227
228 class OutOfMemory : public virtual RuntimeError
229 {
230 public:
231 DEFINE_RUNTIME_EXCEPTION( OutOfMemory, wxLt("Out of Memory") )
232 };
233
234 class ParseError : public RuntimeError
235 {
236 public:
237 DEFINE_RUNTIME_EXCEPTION( ParseError, "Parse error" );
238 };
239
240 // ---------------------------------------------------------------------------------------
241 // Hardware/OS Exceptions:
242 // HardwareDeficiency / VirtualMemoryMapConflict
243 // ---------------------------------------------------------------------------------------
244
245 // This exception is a specific type of OutOfMemory error that isn't "really" an out of
246 // memory error. More likely it's caused by a plugin or driver reserving a range of memory
247 // we'd really like to have access to.
248 class VirtualMemoryMapConflict : public virtual OutOfMemory
249 {
250 public:
251 DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") )
252 };
253
254 class HardwareDeficiency : public virtual RuntimeError
255 {
256 public:
257 DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") );
258 };
259
260 // ---------------------------------------------------------------------------------------
261 // Streaming (file) Exceptions:
262 // Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
263 // ---------------------------------------------------------------------------------------
264
265 #define DEFINE_STREAM_EXCEPTION( classname, defmsg ) \
266 DEFINE_EXCEPTION_COPYTORS( classname ) \
267 \
268 explicit classname( const wxString& objname=wxString(), const char* msg=defmsg ) \
269 { \
270 BaseException::InitBaseEx( msg ); \
271 StreamName = objname; \
272 } \
273 explicit classname( const wxString& objname, const wxString& msg_eng, const wxString& msg_xlt ) \
274 { \
275 BaseException::InitBaseEx( msg_eng, msg_xlt ); \
276 StreamName = objname; \
277 } \
278 explicit classname( const char* objname, const char* msg=defmsg ) \
279 { \
280 BaseException::InitBaseEx( msg ); \
281 StreamName = fromUTF8( objname ); \
282 } \
283 explicit classname( const char* objname, const wxString& msg_eng, const wxString& msg_xlt ) \
284 { \
285 BaseException::InitBaseEx( msg_eng, msg_xlt ); \
286 StreamName = fromUTF8( objname ); \
287 } \
288 explicit classname( const char* objname, const wxString& msg_eng ) \
289 { \
290 BaseException::InitBaseEx( msg_eng, msg_eng ); \
291 StreamName = fromUTF8( objname ); \
292 } \
293 explicit classname( const wxString& objname, const wxString& msg_eng ) \
294 { \
295 BaseException::InitBaseEx( msg_eng, msg_eng ); \
296 StreamName = objname; \
297 }
298
299 // Generic stream error. Contains the name of the stream and a message.
300 // This exception is usually thrown via derived classes, except in the (rare) case of a
301 // generic / unknown error.
302 //
303 class Stream : public virtual RuntimeError
304 {
305 public:
306 wxString StreamName; // name of the stream (if applicable)
307
308 public:
309 DEFINE_STREAM_EXCEPTION( Stream, "General file operation error." )
310
311 virtual wxString FormatDiagnosticMessage() const;
312 virtual wxString FormatDisplayMessage() const;
313 };
314
315 // A generic base error class for bad streams -- corrupted data, sudden closures, loss of
316 // connection, or anything else that would indicate a failure to read the data after the
317 // stream was successfully opened.
318 //
319 class BadStream : public virtual Stream
320 {
321 public:
322 DEFINE_STREAM_EXCEPTION( BadStream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
323 };
324
325 // A generic exception for odd-ball stream creation errors.
326 //
327 class CannotCreateStream : public virtual Stream
328 {
329 public:
330 DEFINE_STREAM_EXCEPTION( CannotCreateStream, wxLt("File could not be created or opened.") )
331 };
332
333 // Exception thrown when an attempt to open a non-existent file is made.
334 // (this exception can also mean file permissions are invalid)
335 //
336 class FileNotFound : public virtual CannotCreateStream
337 {
338 public:
339 DEFINE_STREAM_EXCEPTION( FileNotFound, wxLt("File not found.") )
340 };
341
342 class AccessDenied : public virtual CannotCreateStream
343 {
344 public:
345 DEFINE_STREAM_EXCEPTION( AccessDenied, wxLt("Permission denied to file.") )
346 };
347
348 // EndOfStream can be used either as an error, or used just as a shortcut for manual
349 // feof checks.
350 //
351 class EndOfStream : public virtual Stream
352 {
353 public:
354 DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") );
355 };
356
357 #ifdef __WXMSW__
358 // --------------------------------------------------------------------------------------
359 // Exception::WinApiError
360 // --------------------------------------------------------------------------------------
361 class WinApiError : public RuntimeError
362 {
363 public:
364 int ErrorId;
365
366 public:
367 DEFINE_EXCEPTION_COPYTORS( WinApiError )
368
369 WinApiError( const char* msg="" );
370
371 wxString GetMsgFromWindows() const;
372 virtual wxString FormatDisplayMessage() const;
373 virtual wxString FormatDiagnosticMessage() const;
374 };
375 #endif
376 }
377
378 using Exception::BaseException;

  ViewVC Help
Powered by ViewVC 1.1.22