2323
2424
2525#ifdef _WIN32
26- #include < windows.h>
26+ # define NOMINMAX
27+ # include < windows.h>
2728#endif
29+ #include < array>
2830
2931#include " zlib.h"
3032
@@ -223,13 +225,17 @@ FreeImage_IsLittleEndian() {
223225
224226// ----------------------------------------------------------------------
225227
226- struct MessageProcessContext
228+ constexpr size_t kMaxMessageProcessorsNumber = 32 ;
229+
230+ struct MessageProcessorRecord
227231{
232+ uint32_t id{ };
228233 void * ctx{ nullptr };
229234 FreeImage_ProcessMessageFunction func{ nullptr };
230235};
231236
232- thread_local MessageProcessContext g_process_message{ };
237+ // ToDo: implement an object pool?
238+ thread_local std::array<MessageProcessorRecord, kMaxMessageProcessorsNumber > g_message_processors{ };
233239
234240
235241static FreeImage_OutputMessageFunction freeimage_outputmessage_proc{};
@@ -249,7 +255,7 @@ void DLL_CALLCONV
249255FreeImage_OutputMessageProc (int fif, const char *fmt, ...) {
250256 constexpr size_t MSG_SIZE = 512 ;
251257
252- if (fmt && (g_process_message. func || freeimage_outputmessage_proc || freeimage_outputmessagestdcall_proc)) {
258+ if (fmt && (!g_message_processors. empty () || freeimage_outputmessage_proc || freeimage_outputmessagestdcall_proc)) {
253259 FIMESSAGE message{ static_cast <FREE_IMAGE_FORMAT>(fif), FISEV_WARNING };
254260 message.text .resize (MSG_SIZE);
255261
@@ -262,8 +268,8 @@ FreeImage_OutputMessageProc(int fif, const char *fmt, ...) {
262268
263269 // output the message to the user program
264270
265- if (g_process_message. func ) {
266- g_process_message. func (g_process_message. ctx , & message);
271+ if (!g_message_processors. empty () ) {
272+ FreeImage_ProcessMessage (& message);
267273 }
268274 else {
269275 // legacy behaviour
@@ -278,16 +284,53 @@ FreeImage_OutputMessageProc(int fif, const char *fmt, ...) {
278284}
279285
280286
281- void FreeImage_SetProcessMessageFunction (void * new_ctx, FreeImage_ProcessMessageFunction new_func, void ** old_ctx, FreeImage_ProcessMessageFunction* old_func)
287+ DLL_API uint32_t DLL_CALLCONV FreeImage_AddProcessMessageFunction (void * ctx, FreeImage_ProcessMessageFunction func)
288+ {
289+ static_assert (kMaxMessageProcessorsNumber < std::numeric_limits<uint32_t >::max () - 1 );
290+ if (func == nullptr ) {
291+ return 0 ;
292+ }
293+
294+ size_t free_idx = 0 ;
295+ for (; free_idx < g_message_processors.size (); ++free_idx) {
296+ if (!g_message_processors[free_idx].id ) {
297+ break ;
298+ }
299+ }
300+ if (free_idx >= g_message_processors.size ()) {
301+ return 0 ;
302+ }
303+
304+ auto & rec = g_message_processors[free_idx];
305+ rec.id = static_cast <uint32_t >(free_idx) + 1 ;
306+ rec.ctx = ctx;
307+ rec.func = func;
308+
309+ return rec.id ;
310+ }
311+
312+
313+ FIBOOL FreeImage_RemoveProcessMessageFunction (uint32_t id)
282314{
283- std::swap (g_process_message.ctx , new_ctx);
284- std::swap (g_process_message.func , new_func);
285- if (old_ctx) {
286- *old_ctx = new_ctx;
315+ if (id == 0 ) {
316+ return FALSE ;
317+ }
318+
319+ const uint32_t idx = id - 1 ;
320+ if (idx >= g_message_processors.size ()) {
321+ return FALSE ;
287322 }
288- if (old_func) {
289- *old_func = new_func;
323+
324+ auto & rec = g_message_processors[idx];
325+ if (rec.id != id) {
326+ return FALSE ;
290327 }
328+
329+ rec.id = 0 ;
330+ rec.func = nullptr ;
331+ rec.ctx = nullptr ;
332+
333+ return TRUE ;
291334}
292335
293336
@@ -297,8 +340,10 @@ void FreeImage_ProcessMessage(const FIMESSAGE* msg)
297340 return ;
298341 }
299342
300- if (g_process_message.func ) {
301- g_process_message.func (g_process_message.ctx , msg);
343+ for (const auto & rec : g_message_processors) {
344+ if (rec.id && rec.func ) {
345+ rec.func (rec.ctx , msg);
346+ }
302347 }
303348}
304349
@@ -340,5 +385,5 @@ const char* FreeImage_GetMessageString(const FIMESSAGE* msg)
340385 if (msg) {
341386 return msg->text .c_str ();
342387 }
343- return " Unknown " ;
388+ return nullptr ;
344389}
0 commit comments