1 /*
2     RawSpeed - RAW file decoder.
3 
4     Copyright (C) 2009-2014 Klaus Post
5     Copyright (C) 2017 Roman Lebedev
6 
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.
16 
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
22 #pragma once
23 
24 #include "rawspeedconfig.h" // for RAWSPEED_NOINLINE, RAWSPEED_UNLIKELY_FUN...
25 
26 #include "common/Common.h" // for writeLog, DEBUG_PRIO_EXTRA
27 #include <array>           // for array
28 #include <cstdarg>         // for va_end, va_list, va_start
29 #include <cstdio>          // for vsnprintf, size_t
30 #include <stdexcept>       // for runtime_error
31 
32 namespace rawspeed {
33 
34 template <typename T>
35 [[noreturn]] void RAWSPEED_UNLIKELY_FUNCTION RAWSPEED_NOINLINE
36     __attribute__((noreturn, format(printf, 1, 2)))
ThrowException(const char * fmt,...)37     ThrowException(const char* fmt, ...) {
38   static constexpr size_t bufSize = 8192;
39 #if defined(HAVE_CXX_THREAD_LOCAL)
40   static thread_local std::array<char, bufSize> buf;
41 #elif defined(HAVE_GCC_THREAD_LOCAL)
42   static __thread char buf[bufSize];
43 #else
44 #pragma message                                                                \
45     "Don't have thread-local-storage! Exception text may be garbled if used multithreaded"
46   static char buf[bufSize];
47 #endif
48 
49   va_list val;
50   va_start(val, fmt);
51   vsnprintf(buf.data(), sizeof(buf), fmt, val);
52   va_end(val);
53   writeLog(DEBUG_PRIO_EXTRA, "EXCEPTION: %s", buf.data());
54   throw T(buf.data());
55 }
56 
57 class RawspeedException : public std::runtime_error {
58 private:
59   static void RAWSPEED_UNLIKELY_FUNCTION RAWSPEED_NOINLINE
log(const char * msg)60   log(const char* msg) {
61     writeLog(DEBUG_PRIO_EXTRA, "EXCEPTION: %s", msg);
62   }
63 
64 public:
65   explicit RAWSPEED_UNLIKELY_FUNCTION RAWSPEED_NOINLINE
RawspeedException(const char * msg)66   RawspeedException(const char* msg)
67       : std::runtime_error(msg) {
68     log(msg);
69   }
70 };
71 
72 #undef XSTR
73 #define XSTR(a) #a
74 
75 #undef STR
76 #define STR(a) XSTR(a)
77 
78 #ifndef DEBUG
79 #define ThrowExceptionHelper(CLASS, fmt, ...)                                  \
80   rawspeed::ThrowException<CLASS>("%s, line " STR(__LINE__) ": " fmt,          \
81                                   __PRETTY_FUNCTION__, ##__VA_ARGS__)
82 #else
83 #define ThrowExceptionHelper(CLASS, fmt, ...)                                  \
84   rawspeed::ThrowException<CLASS>(__FILE__ ":" STR(__LINE__) ": %s: " fmt,     \
85                                   __PRETTY_FUNCTION__, ##__VA_ARGS__)
86 #endif
87 
88 #define ThrowRSE(...)                                                          \
89   ThrowExceptionHelper(rawspeed::RawspeedException, __VA_ARGS__)
90 
91 } // namespace rawspeed
92