1 /***************************************************************************
2  *   Copyright (C) 2006 by Dominik Seichter                                *
3  *   domseichter@web.de                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU Library General Public License as       *
7  *   published by the Free Software Foundation; either version 2 of the    *
8  *   License, or (at your option) any later version.                       *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU Library General Public     *
16  *   License along with this program; if not, write to the                 *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  *                                                                         *
20  *   In addition, as a special exception, the copyright holders give       *
21  *   permission to link the code of portions of this program with the      *
22  *   OpenSSL library under certain conditions as described in each         *
23  *   individual source file, and distribute linked combinations            *
24  *   including the two.                                                    *
25  *   You must obey the GNU General Public License in all respects          *
26  *   for all of the code used other than OpenSSL.  If you modify           *
27  *   file(s) with this exception, you may extend this exception to your    *
28  *   version of the file(s), but you are not obligated to do so.  If you   *
29  *   do not wish to do so, delete this exception statement from your       *
30  *   version.  If you delete this exception statement from all source      *
31  *   files in the program, then also delete it here.                       *
32  ***************************************************************************/
33 
34 #ifndef _PDF_ERROR_H_
35 #define _PDF_ERROR_H_
36 
37 // PdfError.h should not include PdfDefines.h, since it is included by it.
38 // It should avoid depending on anything defined in PdfDefines.h .
39 
40 #include "podofoapi.h"
41 #include <string>
42 #include <queue>
43 #include <cstdarg>
44 
45 #if defined(_MSC_VER)  &&  _MSC_VER <= 1200 // same pragma as in PdfDefines.h which we cannot include here
46 #pragma warning(disable: 4251)
47 #pragma warning(disable: 4275)
48 #endif
49 
50 /** \file PdfError.h
51  *  Error information and logging is implemented in this file.
52  */
53 
54 namespace PoDoFo {
55 
56 /** Error Code enum values which are used in PdfError to describe the error.
57  *
58  *  If you add an error code to this enum, please also add it
59  *  to PdfError::ErrorName() and PdfError::ErrorMessage().
60  *
61  *  \see PdfError
62  */
63 enum EPdfError {
64     ePdfError_ErrOk = 0,                /**< The default value indicating no error. */
65 
66     ePdfError_TestFailed,               /**< Used in PoDoFo tests, to indicate that a test failed for some reason. */
67 
68     ePdfError_InvalidHandle,            /**< Null pointer was passed, but null pointer is not allowed. */
69     ePdfError_FileNotFound,             /**< A file was not found or cannot be opened. */
70     ePdfError_InvalidDeviceOperation,	/**< Tried to do something unsupported to an I/O device like seek a non-seekable input device */
71     ePdfError_UnexpectedEOF,            /**< End of file was reached but data was expected. */
72     ePdfError_OutOfMemory,              /**< Not enough memory to complete an operation. */
73     ePdfError_ValueOutOfRange,          /**< The specified memory is out of the allowed range. */
74     ePdfError_InternalLogic,            /**< An internal sanity check or assertion failed. */
75     ePdfError_InvalidEnumValue,         /**< An invalid enum value was specified. */
76     ePdfError_BrokenFile,               /**< The file content is broken. */
77 
78     ePdfError_PageNotFound,             /**< The requested page could not be found in the PDF. */
79 
80     ePdfError_NoPdfFile,                /**< The file is no PDF file. */
81     ePdfError_NoXRef,                   /**< The PDF file has no or an invalid XRef table. */
82     ePdfError_NoTrailer,                /**< The PDF file has no or an invalid trailer. */
83     ePdfError_NoNumber,                 /**< A number was expected in the PDF file, but the read string is no number. */
84     ePdfError_NoObject,                 /**< A object was expected and none was found. */
85     ePdfError_NoEOFToken,               /**< The PDF file has no or an invalid EOF marker. */
86 
87     ePdfError_InvalidTrailerSize,       /**< The trailer size is invalid. */
88     ePdfError_InvalidLinearization,     /**< The linearization directory of a web-optimized PDF file is invalid. */
89     ePdfError_InvalidDataType,          /**< The passed datatype is invalid or was not recognized */
90     ePdfError_InvalidXRef,              /**< The XRef table is invalid */
91     ePdfError_InvalidXRefStream,        /**< A XRef steam is invalid */
92     ePdfError_InvalidXRefType,          /**< The XRef type is invalid or was not found */
93     ePdfError_InvalidPredictor,         /**< Invalid or unimplemented predictor */
94     ePdfError_InvalidStrokeStyle,       /**< Invalid stroke style during drawing */
95     ePdfError_InvalidHexString,         /**< Invalid hex string */
96     ePdfError_InvalidStream,            /**< The stream is invalid */
97     ePdfError_InvalidStreamLength,      /**< The stream length is invalid */
98     ePdfError_InvalidKey,               /**< The specified key is invalid */
99     ePdfError_InvalidName,              /**< The specified Name is not valid in this context */
100     ePdfError_InvalidEncryptionDict,    /**< The encryption dictionary is invalid or misses a required key */
101     ePdfError_InvalidPassword,          /**< The password used to open the PDF file was invalid */
102     ePdfError_InvalidFontFile,          /**< The font file is invalid */
103     ePdfError_InvalidContentStream,     /**< The content stream is invalid due to mismatched context pairing or other problems */
104 
105     ePdfError_UnsupportedFilter,        /**< The requested filter is not yet implemented. */
106     ePdfError_UnsupportedFontFormat,    /**< This font format is not supported by PoDoFo. */
107     ePdfError_ActionAlreadyPresent,     /**< An Action was already present when trying to add a Destination */
108     ePdfError_WrongDestinationType,     /**< The requested field is not available for the given destination type */
109 
110     ePdfError_MissingEndStream,         /**< The required token endstream was not found. */
111     ePdfError_Date,                     /**< Date/time error */
112     ePdfError_Flate,                    /**< Error in zlib */
113     ePdfError_FreeType,                 /**< Error in FreeType */
114     ePdfError_SignatureError,           /**< Error in signature */
115 
116     ePdfError_MutexError,               /**< Error during a mutex operation */
117 
118     ePdfError_UnsupportedImageFormat,   /**< This image format is not supported by PoDoFo. */
119     ePdfError_CannotConvertColor,       /**< This color format cannot be converted. */
120 
121     ePdfError_NotImplemented,           /**< This feature is currently not implemented. */
122 
123     ePdfError_DestinationAlreadyPresent,/**< A destination was already present when trying to add an Action */
124     ePdfError_ChangeOnImmutable,        /**< Changing values on immutable objects is not allowed. */
125 
126     ePdfError_NotCompiled,              /**< This feature was disabled at compile time. */
127 
128     ePdfError_OutlineItemAlreadyPresent,/**< An outline item to be inserted was already in that outlines tree. */
129     ePdfError_NotLoadedForUpdate,       /**< The document had not been loaded for update. */
130     ePdfError_CannotEncryptedForUpdate, /**< Cannot load encrypted documents for update. */
131 
132     ePdfError_Unknown = 0xffff          /**< Unknown error */
133 };
134 
135 /**
136  * Used in PdfError::LogMessage to specify the log level.
137  *
138  * \see PdfError::LogMessage
139  */
140 enum ELogSeverity {
141     eLogSeverity_Critical,            /**< Critical unexpected error */
142     eLogSeverity_Error,               /**< Error */
143     eLogSeverity_Warning,             /**< Warning */
144     eLogSeverity_Information,         /**< Information message */
145     eLogSeverity_Debug,               /**< Debug information */
146     eLogSeverity_None,                /**< No specified level */
147 
148     eLogSeverity_Unknown = 0xffff     /**< Unknown log level */
149 };
150 
151 /** \def PODOFO_RAISE_ERROR( x )
152  *
153  *  Throw an exception of type PdfError with the error code x, which should be
154  *  one of the values of the enum EPdfError. File and line info are included.
155  */
156 #define PODOFO_RAISE_ERROR( x ) throw ::PoDoFo::PdfError( x, __FILE__, __LINE__ );
157 
158 /** \def PODOFO_RAISE_ERROR_INFO( x, y )
159  *
160  *  Throw an exception of type PdfError with the error code x, which should be
161  *  one of the values of the enum EPdfError. File and line info are included.
162  *  Additionally extra information on the error, y is set, which will also be
163  *  output by PdfError::PrintErrorMsg().
164  *  y can be a C string, but can also be a C++ std::string.
165  */
166 #define PODOFO_RAISE_ERROR_INFO( x, y ) throw ::PoDoFo::PdfError( x, __FILE__, __LINE__, y );
167 
168 /** \def PODOFO_RAISE_LOGIC_IF( x, y )
169  *
170  *  Evaluate `x' as a binary predicate and if it is true, raise a logic error with the
171  *  info string `y' .
172  */
173 #define PODOFO_RAISE_LOGIC_IF( x, y ) { if (x) throw ::PoDoFo::PdfError( ePdfError_InternalLogic, __FILE__, __LINE__, y ); };
174 
175 class PODOFO_API PdfErrorInfo {
176  public:
177     PdfErrorInfo();
178     PdfErrorInfo( int line, const char* pszFile, const char* pszInfo );
179     PdfErrorInfo( int line, const char* pszFile, std::string pszInfo );
180     PdfErrorInfo( int line, const char* pszFile, const wchar_t* pszInfo );
181     PdfErrorInfo( const PdfErrorInfo & rhs );
182 
183     const PdfErrorInfo & operator=( const PdfErrorInfo & rhs );
184 
GetLine()185     inline int GetLine() const { return m_nLine; }
GetFilename()186     inline const std::string & GetFilename() const { return m_sFile; }
GetInformation()187     inline const std::string & GetInformation() const { return m_sInfo; }
GetInformationW()188     inline const std::wstring & GetInformationW() const { return m_swInfo; }
189 
SetInformation(const char * pszInfo)190     inline void SetInformation( const char* pszInfo ) { m_sInfo = pszInfo ? pszInfo : ""; }
SetInformation(std::string pszInfo)191     inline void SetInformation( std::string pszInfo ) { m_sInfo = pszInfo; }
SetInformation(const wchar_t * pszInfo)192     inline void SetInformation( const wchar_t* pszInfo ) { m_swInfo = pszInfo ? pszInfo : L""; }
193 
194  private:
195     int          m_nLine;
196     std::string  m_sFile;
197     std::string  m_sInfo;
198     std::wstring m_swInfo;
199 };
200 
201 
202 typedef std::deque<PdfErrorInfo>        TDequeErrorInfo;
203 typedef TDequeErrorInfo::iterator       TIDequeErrorInfo;
204 typedef TDequeErrorInfo::const_iterator TCIDequeErrorInfo;
205 
206 
207 // This is required to generate the documentation with Doxygen.
208 // Without this define doxygen thinks we have a class called PODOFO_EXCEPTION_API(PODOFO_API) ...
209 #define PODOFO_EXCEPTION_API_DOXYGEN PODOFO_EXCEPTION_API(PODOFO_API)
210 
211 /** The error handling class of the PoDoFo library.
212  *  If a method encounters an error,
213  *  a PdfError object is thrown as a C++ exception.
214  *
215  *  This class does not inherit from std::exception.
216  *
217  *  This class also provides meaningful error descriptions
218  *  for the error codes which are values of the enum EPdfError,
219  *  which are all codes PoDoFo uses (except the first and last one).
220  */
221 class PODOFO_EXCEPTION_API_DOXYGEN PdfError {
222  public:
223 
224     // OC 17.08.2010 New to optionally replace stderr output by a callback:
225     class LogMessageCallback
226     {
227     public:
~LogMessageCallback()228         virtual ~LogMessageCallback() {} // every class with virtual methods needs a virtual destructor
229         virtual void LogMessage( ELogSeverity eLogSeverity, const char* pszPrefix, const char* pszMsg, va_list & args ) = 0;
230         virtual void LogMessage( ELogSeverity eLogSeverity, const wchar_t* pszPrefix, const wchar_t* pszMsg, va_list & args ) = 0;
231     };
232 
233     /** Set a global static LogMessageCallback functor to replace stderr output in LogMessageInternal.
234      *  \param fLogMessageCallback the pointer to the new callback functor object
235      *  \returns the pointer to the previous callback functor object
236      */
237     static LogMessageCallback* SetLogMessageCallback(LogMessageCallback* fLogMessageCallback);
238 
239     /** Create a PdfError object initialized to ePdfError_ErrOk.
240      */
241     PdfError();
242 
243     /** Create a PdfError object with a given error code.
244      *  \param eCode the error code of this object
245      *  \param pszFile the file in which the error has occured.
246      *         Use the compiler macro __FILE__ to initialize the field.
247      *  \param line the line in which the error has occured.
248      *         Use the compiler macro __LINE__ to initialize the field.
249      *  \param pszInformation additional information on this error
250      */
251     PdfError( const EPdfError & eCode, const char* pszFile = NULL, int line = 0,
252               const char* pszInformation = NULL );
253 
254     /** Create a PdfError object with a given error code.
255      *  \param eCode the error code of this object
256      *  \param pszFile the file in which the error has occured.
257      *         Use the compiler macro __FILE__ to initialize the field.
258      *  \param line the line in which the error has occured.
259      *         Use the compiler macro __LINE__ to initialize the field.
260      *  \param sInformation additional information on this error
261      */
262     explicit PdfError( const EPdfError & eCode, const char* pszFile, int line,
263                         std::string sInformation );
264 
265     /** Copy constructor
266      *  \param rhs copy the contents of rhs into this object
267      */
268     PdfError( const PdfError & rhs );
269 
270     virtual ~PdfError() throw();
271 
272     /** Assignment operator
273      *  \param rhs another PdfError object
274      *  \returns this object
275      */
276     const PdfError & operator=( const PdfError & rhs );
277 
278     /** Overloaded assignment operator
279      *  \param eCode a EPdfError code
280      *  \returns this object
281      */
282     const PdfError & operator=( const EPdfError & eCode );
283 
284     /** Comparison operator, compares 2 PdfError objects
285      *  \param rhs another PdfError object
286      *  \returns true if both objects have the same error code.
287      */
288     bool operator==( const PdfError & rhs );
289 
290     /** Overloaded comparison operator, compares this PdfError object
291      *  with an error code
292      *  \param eCode an error code (value of the enum EPdfError)
293      *  \returns true if this object has the same error code.
294      */
295     bool operator==( const EPdfError & eCode );
296 
297     /** Comparison operator, compares 2 PdfError objects
298      *  \param rhs another PdfError object
299      *  \returns true if the objects have different error codes.
300      */
301     bool operator!=( const PdfError & rhs );
302 
303     /** Overloaded comparison operator, compares this PdfError object
304      *  with an error code
305      *  \param eCode an error code (value of the enum EPdfError)
306      *  \returns true if this object has a different error code.
307      */
308     bool operator!=( const EPdfError & eCode );
309 
310     /** Return the error code of this object.
311      *  \returns the error code of this object
312      */
313     inline EPdfError GetError() const;
314 
315     /** Get access to the internal callstack of this error.
316      *  \returns the callstack deque of PdfErrorInfo objects.
317      */
318     inline const TDequeErrorInfo & GetCallstack() const;
319 
320     /** Set the error code of this object.
321      *  \param eCode the error code of this object
322      *  \param pszFile the filename of the source file causing
323      *                 the error or NULL. Typically you will use
324      *                 the gcc macro __FILE__ here.
325      *  \param line    the line of source causing the error
326      *                 or 0. Typically you will use the gcc
327      *                 macro __LINE__ here.
328      *  \param sInformation additional information on the error.
329      *         e.g. how to fix the error. This string is intended to
330      *         be shown to the user.
331      */
332     inline void SetError( const EPdfError & eCode, const char* pszFile, int line,
333                         std::string sInformation );
334 
335     /** Set the error code of this object.
336      *  \param eCode the error code of this object
337      *  \param pszFile the filename of the source file causing
338      *                 the error or NULL. Typically you will use
339      *                 the gcc macro __FILE__ here.
340      *  \param line    the line of source causing the error
341      *                 or 0. Typically you will use the gcc
342      *                 macro __LINE__ here.
343      *  \param pszInformation additional information on the error,
344      *         e.g. how to fix the error. This string is intended to
345      *         be shown to the user.
346      */
347     inline void SetError( const EPdfError & eCode, const char* pszFile = NULL, int line = 0, const char* pszInformation = NULL );
348 
349     /** Set additional error information.
350      *  \param pszInformation additional information on the error,
351      *         e.g. how to fix the error. This string is intended to
352      *         be shown to the user.
353      */
354     inline void SetErrorInformation( const char* pszInformation );
355 
356     /** Set additional error information.
357      *  \param pszInformation additional information on the error,
358      *         e.g. how to fix the error. This string is intended to
359      *         be shown to the user.
360      */
361     inline void SetErrorInformation( const wchar_t* pszInformation );
362 
363 	/** Add callstack information to an error object. Always call this function
364      *  if you get an error object but do not handle the error but throw it again.
365      *
366      *  \param pszFile the filename of the source file causing
367      *                 the error or NULL. Typically you will use
368      *                 the gcc macro __FILE__ here.
369      *  \param line    the line of source causing the error
370      *                 or 0. Typically you will use the gcc
371      *                 macro __LINE__ here.
372      *  \param pszInformation additional information on the error,
373      *         e.g. how to fix the error. This string is intended to
374      *         be shown to the user.
375      */
376     inline void AddToCallstack( const char* pszFile = NULL, int line = 0, const char* pszInformation = NULL );
377 
378 	/** Add callstack information to an error object. Always call this function
379      *  if you get an error object but do not handle the error but throw it again.
380      *
381      *  \param pszFile the filename of the source file causing
382      *                 the error or NULL. Typically you will use
383      *                 the gcc macro __FILE__ here.
384      *  \param line    the line of source causing the error
385      *                 or 0. Typically you will use the gcc
386      *                 macro __LINE__ here.
387      *  \param sInformation additional information on the error,
388      *         e.g. how to fix the error. This string is intended to
389      *         be shown to the user.
390      */
391     inline void AddToCallstack( const char* pszFile, int line, std::string sInformation );
392 
393     /** \returns true if an error code was set
394      *           and false if the error code is ePdfError_ErrOk.
395      */
396     inline bool IsError() const;
397 
398     /** Print an error message to stderr. This includes callstack
399      *  and extra info, if any of either was set.
400      */
401     void PrintErrorMsg() const;
402 
403     /** Obtain error description.
404      *  \returns a C string describing the error.
405      */
406     const char* what() const;
407 
408     /** Get the name for a certain error code.
409      *  \returns the name or NULL if no name for the specified
410      *           error code is available.
411      */
412     PODOFO_NOTHROW static const char* ErrorName( EPdfError eCode );
413 
414     /** Get the error message for a certain error code.
415      *  \returns the error message or NULL if no error
416      *           message for the specified error code
417      *           is available.
418      */
419     static const char* ErrorMessage( EPdfError eCode );
420 
421     /** Log a message to the logging system defined for PoDoFo.
422      *  \param eLogSeverity the severity of the log message
423      *  \param pszMsg       the message to be logged
424      */
425     static void LogMessage( ELogSeverity eLogSeverity, const char* pszMsg, ... );
426 
427     /** Log a message to the logging system defined for PoDoFo.
428      *  \param eLogSeverity the severity of the log message
429      *  \param pszMsg       the message to be logged
430      */
431     static void LogMessage( ELogSeverity eLogSeverity, const wchar_t* pszMsg, ... );
432 
433      /** Enable or disable logging.
434      *  \param bEnable       enable (true) or disable (false)
435      */
436     static void EnableLogging( bool bEnable );
437 
438     /** Is the display of debugging messages enabled or not?
439      */
440     static bool LoggingEnabled();
441 
442     /** Log a message to the logging system defined for PoDoFo for debugging.
443      *  \param pszMsg       the message to be logged
444      */
445     static void DebugMessage( const char* pszMsg, ... );
446 
447     /** Enable or disable the display of debugging messages.
448      *  \param bEnable       enable (true) or disable (false)
449      */
450     static void EnableDebug( bool bEnable );
451 
452     /** Is the display of debugging messages enabled or not?
453      */
454     static bool DebugEnabled();
455 
456  private:
457     /** Log a message to the logging system defined for PoDoFo.
458      *
459      *  This call does not check if logging is enabled and always
460      *  prints the error message.
461      *
462      *  \param eLogSeverity the severity of the log message
463      *  \param pszMsg       the message to be logged
464      */
465     static void LogErrorMessage( ELogSeverity eLogSeverity, const char* pszMsg, ... );
466 
467     /** Log a message to the logging system defined for PoDoFo.
468      *
469      *  This call does not check if logging is enabled and always
470      *  prints the error message
471      *
472      *  \param eLogSeverity the severity of the log message
473      *  \param pszMsg       the message to be logged
474      */
475     static void LogErrorMessage( ELogSeverity eLogSeverity, const wchar_t* pszMsg, ... );
476 
477     static void LogMessageInternal( ELogSeverity eLogSeverity, const char* pszMsg, va_list & args );
478     static void LogMessageInternal( ELogSeverity eLogSeverity, const wchar_t* pszMsg, va_list & args );
479 
480  private:
481     EPdfError          m_error;
482 
483     TDequeErrorInfo    m_callStack;
484 
485     static bool        s_DgbEnabled;
486     static bool        s_LogEnabled;
487 
488     // OC 17.08.2010 New to optionally replace stderr output by a callback:
489     static LogMessageCallback* m_fLogMessageCallback;
490 };
491 
492 // -----------------------------------------------------
493 //
494 // -----------------------------------------------------
GetError()495 EPdfError PdfError::GetError() const
496 {
497     return m_error;
498 }
499 
500 // -----------------------------------------------------
501 //
502 // -----------------------------------------------------
GetCallstack()503 const TDequeErrorInfo & PdfError::GetCallstack() const
504 {
505     return m_callStack;
506 }
507 
508 // -----------------------------------------------------
509 //
510 // -----------------------------------------------------
SetError(const EPdfError & eCode,const char * pszFile,int line,const char * pszInformation)511 void PdfError::SetError( const EPdfError & eCode, const char* pszFile, int line, const char* pszInformation )
512 {
513     m_error = eCode;
514     this->AddToCallstack( pszFile, line, pszInformation );
515 }
516 
517 // -----------------------------------------------------
518 //
519 // -----------------------------------------------------
AddToCallstack(const char * pszFile,int line,const char * pszInformation)520 void PdfError::AddToCallstack( const char* pszFile, int line, const char* pszInformation )
521 {
522     m_callStack.push_front( PdfErrorInfo( line, pszFile, pszInformation ) );
523 }
524 
525 // -----------------------------------------------------
526 //
527 // -----------------------------------------------------
SetError(const EPdfError & eCode,const char * pszFile,int line,std::string sInformation)528 void PdfError::SetError( const EPdfError & eCode, const char* pszFile, int line, std::string sInformation )
529 {
530     m_error = eCode;
531     this->AddToCallstack( pszFile, line, sInformation );
532 }
533 
534 // -----------------------------------------------------
535 //
536 // -----------------------------------------------------
AddToCallstack(const char * pszFile,int line,std::string sInformation)537 void PdfError::AddToCallstack( const char* pszFile, int line, std::string sInformation )
538 {
539     m_callStack.push_front( PdfErrorInfo( line, pszFile, sInformation ) );
540 }
541 // -----------------------------------------------------
542 //
543 // -----------------------------------------------------
SetErrorInformation(const char * pszInformation)544 void PdfError::SetErrorInformation( const char* pszInformation )
545 {
546     if( m_callStack.size() )
547         m_callStack.front().SetInformation( pszInformation ? pszInformation : "" );
548 }
549 
550 // -----------------------------------------------------
551 //
552 // -----------------------------------------------------
SetErrorInformation(const wchar_t * pszInformation)553 void PdfError::SetErrorInformation( const wchar_t* pszInformation )
554 {
555     if( m_callStack.size() )
556         m_callStack.front().SetInformation( pszInformation ? pszInformation : L"" );
557 }
558 
559 // -----------------------------------------------------
560 //
561 // -----------------------------------------------------
IsError()562 bool PdfError::IsError() const
563 {
564     return (m_error != ePdfError_ErrOk);
565 }
566 
567 };
568 
569 #endif /* _PDF_ERROR_H_ */
570 
571 
572 
573