Skip to content

Commit 08567c4

Browse files
committed
Allow multiple message processors
1 parent 48f09ea commit 08567c4

2 files changed

Lines changed: 71 additions & 20 deletions

File tree

Source/FreeImage.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -918,11 +918,17 @@ DLL_API void DLL_CALLCONV FreeImage_OutputMessageProc(int fif, const char *fmt,
918918
typedef void (DLL_CALLCONV *FreeImage_ProcessMessageFunction)(void* ctx, const FIMESSAGE* msg);
919919

920920
/**
921-
* Set message processing function for this thread only.
922-
* Pass NULL to reset to default processor. The default processor invokes currently set FreeImage_OutputMessageFunction.
923-
* Returns currently used function.
921+
* Adds a message processing function for this thread only.
922+
* The `func` must not be nullptr.
923+
* On success retuns non-zero ID of the registered processor, that can later be used in FreeImage_RemoveProcessMessageFunction()
924924
*/
925-
DLL_API void DLL_CALLCONV FreeImage_SetProcessMessageFunction(void* new_ctx, FreeImage_ProcessMessageFunction new_func, void** old_ctx FI_DEFAULT(NULL), FreeImage_ProcessMessageFunction* old_func FI_DEFAULT(NULL));
925+
DLL_API uint32_t DLL_CALLCONV FreeImage_AddProcessMessageFunction(void* ctx, FreeImage_ProcessMessageFunction func);
926+
927+
/**
928+
* Removes a previously added message processor.
929+
* Returns true on success, false if processor ID is not valid.
930+
*/
931+
DLL_API FIBOOL DLL_CALLCONV FreeImage_RemoveProcessMessageFunction(uint32_t id);
926932

927933
/**
928934
* Invokes message processor for this message instance

Source/FreeImage/FreeImage.cpp

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
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

235241
static FreeImage_OutputMessageFunction freeimage_outputmessage_proc{};
@@ -249,7 +255,7 @@ void DLL_CALLCONV
249255
FreeImage_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

Comments
 (0)