1 // ***************************************************************** -*- C++ -*- 2 /* 3 * Copyright (C) 2004-2021 Exiv2 authors 4 * This program is part of the Exiv2 distribution. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. 19 */ 20 /*! 21 @file error.hpp 22 @brief Error class for exceptions, log message class 23 @author Andreas Huggel (ahu) 24 <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> 25 @date 15-Jan-04, ahu: created<BR> 26 11-Feb-04, ahu: isolated as a component 27 */ 28 #ifndef ERROR_HPP_ 29 #define ERROR_HPP_ 30 31 // ***************************************************************************** 32 #include "exiv2lib_export.h" 33 34 // included header files 35 #include "types.hpp" 36 37 // + standard includes 38 #include <exception> 39 #include <string> 40 41 // ***************************************************************************** 42 // namespace extensions 43 namespace Exiv2 { 44 45 // ***************************************************************************** 46 // class definitions 47 48 /*! 49 @brief Class for a log message, used by the library. Applications can set 50 the log level and provide a customer log message handler (callback 51 function). 52 53 This class is meant to be used as a temporary object with the 54 related macro-magic like this: 55 56 <code> 57 EXV_WARNING << "Warning! Something looks fishy.\n"; 58 </code> 59 60 which translates to 61 62 <code> 63 if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) 64 LogMsg(LogMsg::warn).os() << "Warning! Something looks fishy.\n"; 65 </code> 66 67 The macros EXV_DEBUG, EXV_INFO, EXV_WARNING and EXV_ERROR are 68 shorthands and ensure efficient use of the logging facility: If a 69 log message doesn't need to be generated because of the log level 70 setting, the temp object is not even created. 71 72 Caveat: The entire log message is not processed in this case. So don't 73 make that call any logic that always needs to be executed. 74 */ 75 class EXIV2API LogMsg { 76 //! Prevent copy-construction: not implemented. 77 LogMsg(const LogMsg&); 78 //! Prevent assignment: not implemented. 79 LogMsg& operator=(const LogMsg&); 80 public: 81 /*! 82 @brief Defined log levels. To suppress all log messages, either set the 83 log level to \c mute or set the log message handler to 0. 84 */ 85 enum Level { debug = 0, info = 1, warn = 2, error = 3, mute = 4 }; 86 /*! 87 @brief Type for a log message handler function. The function receives 88 the log level and message and can process it in an application 89 specific way. The default handler sends the log message to 90 standard error. 91 */ 92 typedef void (*Handler)(int, const char*); 93 94 //! @name Creators 95 //@{ 96 //! Constructor, takes the log message type as an argument 97 explicit LogMsg(Level msgType); 98 99 //! Destructor, passes the log message to the message handler depending on the log level 100 ~LogMsg(); 101 //@} 102 103 //! @name Manipulators 104 //@{ 105 //! Return a reference to the ostringstream which holds the log message 106 std::ostringstream& os(); 107 //@} 108 109 /*! 110 @brief Set the log level. Only log messages with a level greater or 111 equal \em level are sent to the log message handler. Default 112 log level is \c warn. To suppress all log messages, set the log 113 level to \c mute (or set the log message handler to 0). 114 */ 115 static void setLevel(Level level); 116 /*! 117 @brief Set the log message handler. The default handler writes log 118 messages to standard error. To suppress all log messages, set 119 the log message handler to 0 (or set the log level to \c mute). 120 */ 121 static void setHandler(Handler handler); 122 //! Return the current log level 123 static Level level(); 124 //! Return the current log message handler 125 static Handler handler(); 126 //! The default log handler. Sends the log message to standard error. 127 static void defaultHandler(int level, const char* s); 128 129 private: 130 // DATA 131 // The output level. Only messages with type >= level_ will be written 132 static Level level_; 133 // The log handler in use 134 static Handler handler_; 135 // The type of this log message 136 const Level msgType_; 137 // Holds the log message until it is passed to the message handler 138 std::ostringstream os_; 139 140 }; // class LogMsg 141 142 // Macros for simple access 143 //! Shorthand to create a temp debug log message object and return its ostringstream 144 #define EXV_DEBUG if (LogMsg::debug >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::debug).os() 145 //! Shorthand for a temp info log message object and return its ostringstream 146 #define EXV_INFO if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::info).os() 147 //! Shorthand for a temp warning log message object and return its ostringstream 148 #define EXV_WARNING if (LogMsg::warn >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::warn).os() 149 //! Shorthand for a temp error log message object and return its ostringstream 150 #define EXV_ERROR if (LogMsg::error >= LogMsg::level() && LogMsg::handler()) LogMsg(LogMsg::error).os() 151 152 #ifdef _MSC_VER 153 // Disable MSVC warnings "non - DLL-interface classkey 'identifier' used as base 154 // for DLL-interface classkey 'identifier'" 155 # pragma warning( disable : 4275 ) 156 #endif 157 158 //! Generalised toString function 159 template<typename charT, typename T> toBasicString(const T & arg)160 std::basic_string<charT> toBasicString(const T& arg) 161 { 162 std::basic_ostringstream<charT> os; 163 os << arg; 164 return os.str(); 165 } 166 167 /*! 168 @brief Error class interface. Allows the definition and use of a hierarchy 169 of error classes which can all be handled in one catch block. 170 Inherits from the standard exception base-class, to make life 171 easier for library users (they have the option of catching most 172 things via std::exception). 173 */ 174 class EXIV2API AnyError : public std::exception { 175 public: 176 AnyError(); 177 AnyError(const AnyError& o); 178 179 virtual ~AnyError() throw(); 180 ///@brief Return the error code. 181 virtual int code() const throw() =0; 182 }; 183 184 //! %AnyError output operator operator <<(std::ostream & os,const AnyError & error)185 inline std::ostream& operator<<(std::ostream& os, const AnyError& error) 186 { 187 return os << error.what(); 188 } 189 190 //! Complete list of all Exiv2 error codes 191 enum ErrorCode { 192 kerGeneralError = -1, 193 kerSuccess = 0, 194 kerErrorMessage, 195 kerCallFailed, 196 kerNotAnImage, 197 kerInvalidDataset, 198 kerInvalidRecord, 199 kerInvalidKey, 200 kerInvalidTag, 201 kerValueNotSet, 202 kerDataSourceOpenFailed, 203 kerFileOpenFailed, 204 kerFileContainsUnknownImageType, 205 kerMemoryContainsUnknownImageType, 206 kerUnsupportedImageType, 207 kerFailedToReadImageData, 208 kerNotAJpeg, 209 kerFailedToMapFileForReadWrite, 210 kerFileRenameFailed, 211 kerTransferFailed, 212 kerMemoryTransferFailed, 213 kerInputDataReadFailed, 214 kerImageWriteFailed, 215 kerNoImageInInputData, 216 kerInvalidIfdId, 217 //! Entry::setValue: Value too large 218 kerValueTooLarge, 219 //! Entry::setDataArea: Value too large 220 kerDataAreaValueTooLarge, 221 kerOffsetOutOfRange, 222 kerUnsupportedDataAreaOffsetType, 223 kerInvalidCharset, 224 kerUnsupportedDateFormat, 225 kerUnsupportedTimeFormat, 226 kerWritingImageFormatUnsupported, 227 kerInvalidSettingForImage, 228 kerNotACrwImage, 229 kerFunctionNotSupported, 230 kerNoNamespaceInfoForXmpPrefix, 231 kerNoPrefixForNamespace, 232 kerTooLargeJpegSegment, 233 kerUnhandledXmpdatum, 234 kerUnhandledXmpNode, 235 kerXMPToolkitError, 236 kerDecodeLangAltPropertyFailed, 237 kerDecodeLangAltQualifierFailed, 238 kerEncodeLangAltPropertyFailed, 239 kerPropertyNameIdentificationFailed, 240 kerSchemaNamespaceNotRegistered, 241 kerNoNamespaceForPrefix, 242 kerAliasesNotSupported, 243 kerInvalidXmpText, 244 kerTooManyTiffDirectoryEntries, 245 kerMultipleTiffArrayElementTagsInDirectory, 246 kerWrongTiffArrayElementTagType, 247 kerInvalidKeyXmpValue, 248 kerInvalidIccProfile, 249 kerInvalidXMP, 250 kerTiffDirectoryTooLarge, 251 kerInvalidTypeValue, 252 kerInvalidLangAltValue, 253 kerInvalidMalloc, 254 kerCorruptedMetadata, 255 kerArithmeticOverflow, 256 kerMallocFailed, 257 }; 258 259 /*! 260 @brief Simple error class used for exceptions. An output operator is 261 provided to print errors to a stream. 262 */ 263 template<typename charT> 264 class EXIV2API BasicError : public AnyError { 265 public: 266 //! @name Creators 267 //@{ 268 //! Constructor taking only an error code 269 explicit inline BasicError(ErrorCode code); 270 271 //! Constructor taking an error code and one argument 272 template<typename A> 273 inline BasicError(ErrorCode code, const A& arg1); 274 275 //! Constructor taking an error code and two arguments 276 template<typename A, typename B> 277 inline BasicError(ErrorCode code, const A& arg1, const B& arg2); 278 279 //! Constructor taking an error code and three arguments 280 template<typename A, typename B, typename C> 281 inline BasicError(ErrorCode code, const A& arg1, const B& arg2, const C& arg3); 282 283 //! Virtual destructor. (Needed because of throw()) 284 virtual inline ~BasicError() throw(); 285 //@} 286 287 //! @name Accessors 288 //@{ 289 virtual inline int code() const throw(); 290 /*! 291 @brief Return the error message as a C-string. The pointer returned by what() 292 is valid only as long as the BasicError object exists. 293 */ 294 virtual inline const char* what() const throw(); 295 #ifdef EXV_UNICODE_PATH 296 /*! 297 @brief Return the error message as a wchar_t-string. The pointer returned by 298 wwhat() is valid only as long as the BasicError object exists. 299 */ 300 virtual inline const wchar_t* wwhat() const throw(); 301 #endif 302 //@} 303 304 private: 305 //! @name Manipulators 306 //@{ 307 //! Assemble the error message from the arguments 308 void setMsg(); 309 //@} 310 311 // DATA 312 ErrorCode code_; //!< Error code 313 int count_; //!< Number of arguments 314 std::basic_string<charT> arg1_; //!< First argument 315 std::basic_string<charT> arg2_; //!< Second argument 316 std::basic_string<charT> arg3_; //!< Third argument 317 std::string msg_; //!< Complete error message 318 #ifdef EXV_UNICODE_PATH 319 std::wstring wmsg_; //!< Complete error message as a wide string 320 #endif 321 }; // class BasicError 322 323 //! Error class used for exceptions (std::string based) 324 typedef BasicError<char> Error; 325 #ifdef EXV_UNICODE_PATH 326 //! Error class used for exceptions (std::wstring based) 327 typedef BasicError<wchar_t> WError; 328 #endif 329 330 // ***************************************************************************** 331 // free functions, template and inline definitions 332 333 //! Return the error message for the error with code \em code. 334 const char* errMsg(int code); 335 336 template<typename charT> BasicError(ErrorCode code)337 BasicError<charT>::BasicError(ErrorCode code) 338 : code_(code), count_(0) 339 { 340 setMsg(); 341 } 342 343 template<typename charT> template<typename A> BasicError(ErrorCode code,const A & arg1)344 BasicError<charT>::BasicError(ErrorCode code, const A& arg1) 345 : code_(code), count_(1), arg1_(toBasicString<charT>(arg1)) 346 { 347 setMsg(); 348 } 349 350 template<typename charT> template<typename A, typename B> BasicError(ErrorCode code,const A & arg1,const B & arg2)351 BasicError<charT>::BasicError(ErrorCode code, const A& arg1, const B& arg2) 352 : code_(code), count_(2), 353 arg1_(toBasicString<charT>(arg1)), 354 arg2_(toBasicString<charT>(arg2)) 355 { 356 setMsg(); 357 } 358 359 template<typename charT> template<typename A, typename B, typename C> BasicError(ErrorCode code,const A & arg1,const B & arg2,const C & arg3)360 BasicError<charT>::BasicError(ErrorCode code, const A& arg1, const B& arg2, const C& arg3) 361 : code_(code), count_(3), 362 arg1_(toBasicString<charT>(arg1)), 363 arg2_(toBasicString<charT>(arg2)), 364 arg3_(toBasicString<charT>(arg3)) 365 { 366 setMsg(); 367 } 368 369 template<typename charT> ~BasicError()370 BasicError<charT>::~BasicError() throw() 371 { 372 } 373 374 template<typename charT> code() const375 int BasicError<charT>::code() const throw() 376 { 377 return code_; 378 } 379 380 template<typename charT> what() const381 const char* BasicError<charT>::what() const throw() 382 { 383 return msg_.c_str(); 384 } 385 386 #ifdef EXV_UNICODE_PATH 387 template<typename charT> wwhat() const388 const wchar_t* BasicError<charT>::wwhat() const throw() 389 { 390 return wmsg_.c_str(); 391 } 392 #endif 393 394 #ifdef _MSC_VER 395 # pragma warning( default : 4275 ) 396 #endif 397 398 } // namespace Exiv2 399 #endif // #ifndef ERROR_HPP_ 400