Skip to content

Commit c417ab1

Browse files
committed
New API for diagnostic messages
1 parent d7a3f29 commit c417ab1

3 files changed

Lines changed: 133 additions & 78 deletions

File tree

Source/FreeImage.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,21 @@ FI_ENUM(FREE_IMAGE_ALPHA_OPERATION) {
859859
};
860860

861861

862+
// Message struct ---------------------------------------------------------
863+
864+
865+
FI_STRUCT(FIMESSAGE);
866+
867+
FI_ENUM(FREE_IMAGE_SEVERITY) {
868+
FISEV_VERBOSE = 0,
869+
FISEV_INFO = 200,
870+
FISEV_WARNING = 300,
871+
FISEV_ERROR = 400,
872+
FISEV_NONE = 0x1000
873+
};
874+
875+
876+
862877

863878
#ifdef __cplusplus
864879
extern "C" {
@@ -895,6 +910,34 @@ DLL_API void DLL_CALLCONV FreeImage_SetOutputMessageStdCall(FreeImage_OutputMess
895910
DLL_API void DLL_CALLCONV FreeImage_SetOutputMessage(FreeImage_OutputMessageFunction omf);
896911
DLL_API void DLL_CALLCONV FreeImage_OutputMessageProc(int fif, const char *fmt, ...);
897912

913+
914+
/**
915+
* ctx - Opaque handle for message processing context
916+
* func - Address of message processing function
917+
*/
918+
typedef void (DLL_CALLCONV *FreeImage_ProcessMessageFunction)(void* ctx, const FIMESSAGE* msg);
919+
920+
/**
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.
924+
*/
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));
926+
927+
/**
928+
* Invokes message processor for this message instance
929+
*/
930+
DLL_API void DLL_CALLCONV FreeImage_ProcessMessage(const FIMESSAGE* msg);
931+
932+
933+
DLL_API FIMESSAGE* DLL_CALLCONV FreeImage_CreateMessage(FREE_IMAGE_FORMAT scope, FREE_IMAGE_SEVERITY severity, const char* what);
934+
DLL_API void DLL_CALLCONV FreeImage_DeleteMessage(const FIMESSAGE* msg);
935+
DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetMessageScope(const FIMESSAGE* msg);
936+
DLL_API FREE_IMAGE_SEVERITY DLL_CALLCONV FreeImage_GetMessageSeverity(const FIMESSAGE* msg);
937+
DLL_API const char* DLL_CALLCONV FreeImage_GetMessageString(const FIMESSAGE* msg);
938+
939+
940+
898941
// Allocate / Clone / Unload routines ---------------------------------------
899942

900943
DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0));

Source/FreeImage/FreeImage.cpp

Lines changed: 77 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,15 @@ FreeImage_IsLittleEndian() {
223223

224224
//----------------------------------------------------------------------
225225

226+
struct MessageProcessContext
227+
{
228+
void* ctx{ nullptr };
229+
FreeImage_ProcessMessageFunction func{ nullptr };
230+
};
231+
232+
thread_local MessageProcessContext g_process_message{ };
233+
234+
226235
static FreeImage_OutputMessageFunction freeimage_outputmessage_proc{};
227236
static FreeImage_OutputMessageFunctionStdCall freeimage_outputmessagestdcall_proc{};
228237

@@ -238,108 +247,98 @@ FreeImage_SetOutputMessageStdCall(FreeImage_OutputMessageFunctionStdCall omf) {
238247

239248
void DLL_CALLCONV
240249
FreeImage_OutputMessageProc(int fif, const char *fmt, ...) {
241-
const int MSG_SIZE = 512; // 512 bytes should be more than enough for a short message
250+
constexpr size_t MSG_SIZE = 512;
242251

243-
if (fmt && (freeimage_outputmessage_proc || freeimage_outputmessagestdcall_proc)) {
244-
char message[MSG_SIZE];
245-
memset(message, 0, MSG_SIZE);
246-
247-
// initialize the optional parameter list
252+
if (fmt && (g_process_message.func || freeimage_outputmessage_proc || freeimage_outputmessagestdcall_proc)) {
253+
FIMESSAGE message{ static_cast<FREE_IMAGE_FORMAT>(fif), FISEV_WARNING };
254+
message.text.resize(MSG_SIZE);
248255

249256
va_list arg;
250257
va_start(arg, fmt);
251258

252-
// check the length of the format string
253-
254-
int str_length = (int)( (strlen(fmt) > MSG_SIZE) ? MSG_SIZE : strlen(fmt) );
255-
256-
// parse the format string and put the result in 'message'
257-
258-
for (int i = 0, j = 0; i < str_length; ++i) {
259-
if (fmt[i] == '%') {
260-
if (i + 1 < str_length) {
261-
switch (tolower(fmt[i + 1])) {
262-
case '%' :
263-
message[j++] = '%';
264-
break;
265-
266-
case 'o' : // octal numbers
267-
{
268-
char tmp[16];
269-
270-
_itoa(va_arg(arg, int), tmp, 8);
271-
272-
strcat(message, tmp);
259+
std::vsnprintf(message.text.data(), message.text.size(), fmt, arg);
273260

274-
j += (int)strlen(tmp);
275-
276-
++i;
277-
278-
break;
279-
}
280-
281-
case 'i' : // decimal numbers
282-
case 'd' :
283-
{
284-
char tmp[16];
285-
286-
_itoa(va_arg(arg, int), tmp, 10);
287-
288-
strcat(message, tmp);
261+
va_end(arg);
289262

290-
j += (int)strlen(tmp);
263+
// output the message to the user program
291264

292-
++i;
265+
if (g_process_message.func) {
266+
g_process_message.func(g_process_message.ctx, &message);
267+
}
268+
else {
269+
// legacy behaviour
293270

294-
break;
295-
}
271+
if (freeimage_outputmessage_proc)
272+
freeimage_outputmessage_proc(message.scope, message.text.c_str());
296273

297-
case 'x' : // hexadecimal numbers
298-
{
299-
char tmp[16];
274+
if (freeimage_outputmessagestdcall_proc)
275+
freeimage_outputmessagestdcall_proc(message.scope, message.text.c_str());
276+
}
277+
}
278+
}
300279

301-
_itoa(va_arg(arg, int), tmp, 16);
302280

303-
strcat(message, tmp);
281+
void FreeImage_SetProcessMessageFunction(void* new_ctx, FreeImage_ProcessMessageFunction new_func, void** old_ctx, FreeImage_ProcessMessageFunction* old_func)
282+
{
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;
287+
}
288+
if (old_func) {
289+
*old_func = new_func;
290+
}
291+
}
304292

305-
j += (int)strlen(tmp);
306293

307-
++i;
294+
void FreeImage_ProcessMessage(const FIMESSAGE* msg)
295+
{
296+
if (!msg) {
297+
return;
298+
}
308299

309-
break;
310-
}
300+
if (g_process_message.func) {
301+
g_process_message.func(g_process_message.ctx, msg);
302+
}
303+
}
311304

312-
case 's' : // strings
313-
{
314-
char *tmp = va_arg(arg, char*);
315305

316-
strcat(message, tmp);
306+
FIMESSAGE* FreeImage_CreateMessage(FREE_IMAGE_FORMAT scope, FREE_IMAGE_SEVERITY severity, const char* what)
307+
{
308+
return new FIMESSAGE(scope, severity, what ? what : "Unknown");
309+
}
317310

318-
j += (int)strlen(tmp);
319311

320-
++i;
312+
void FreeImage_DeleteMessage(const FIMESSAGE* msg)
313+
{
314+
if (msg) {
315+
delete msg;
316+
}
317+
}
321318

322-
break;
323-
}
324-
};
325-
} else {
326-
message[j++] = fmt[i];
327-
}
328-
} else {
329-
message[j++] = fmt[i];
330-
};
331-
}
332319

333-
// deinitialize the optional parameter list
320+
FREE_IMAGE_FORMAT FreeImage_GetMessageScope(const FIMESSAGE* msg)
321+
{
322+
if (msg) {
323+
return msg->scope;
324+
}
325+
return FIF_UNKNOWN;
326+
}
334327

335-
va_end(arg);
336328

337-
// output the message to the user program
329+
FREE_IMAGE_SEVERITY FreeImage_GetMessageSeverity(const FIMESSAGE* msg)
330+
{
331+
if (msg) {
332+
return msg->severity;
333+
}
334+
return FISEV_NONE;
335+
}
338336

339-
if (freeimage_outputmessage_proc)
340-
freeimage_outputmessage_proc((FREE_IMAGE_FORMAT)fif, message);
341337

342-
if (freeimage_outputmessagestdcall_proc)
343-
freeimage_outputmessagestdcall_proc((FREE_IMAGE_FORMAT)fif, message);
338+
const char* FreeImage_GetMessageString(const FIMESSAGE* msg)
339+
{
340+
if (msg) {
341+
return msg->text.c_str();
344342
}
343+
return "Unknown";
345344
}

Source/Utilities.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,4 +443,17 @@ static const char *FI_MSG_ERROR_UNSUPPORTED_FORMAT = "Unsupported format";
443443
static const char *FI_MSG_ERROR_UNSUPPORTED_COMPRESSION = "Unsupported compression type";
444444
static const char *FI_MSG_WARNING_INVALID_THUMBNAIL = "Warning: attached thumbnail cannot be written to output file (invalid format) - Thumbnail saving aborted";
445445

446+
struct FIMESSAGE
447+
{
448+
FREE_IMAGE_FORMAT scope;
449+
FREE_IMAGE_SEVERITY severity;
450+
std::string text;
451+
452+
453+
FIMESSAGE(FREE_IMAGE_FORMAT scope, FREE_IMAGE_SEVERITY severity, std::string text = {})
454+
: scope(scope), severity(severity), text(std::move(text))
455+
{ }
456+
};
457+
458+
446459
#endif // FREEIMAGE_UTILITIES_H

0 commit comments

Comments
 (0)