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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide 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 william 31 /* 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