|
12 | 12 |
|
13 | 13 | #include <cassert> |
14 | 14 | #include <filesystem> |
| 15 | +#include <functional> |
15 | 16 | #include <limits> |
16 | 17 | #include <memory> |
17 | 18 | #include <optional> |
@@ -250,6 +251,15 @@ namespace fi |
250 | 251 | eSrcAlpha = FIAO_SrcAlpha |
251 | 252 | }; |
252 | 253 |
|
| 254 | + enum class Severity |
| 255 | + { |
| 256 | + eVerbose = FISEV_VERBOSE, |
| 257 | + eInfo = FISEV_INFO, |
| 258 | + eWarning = FISEV_WARNING, |
| 259 | + eError = FISEV_ERROR, |
| 260 | + eNone = FISEV_NONE |
| 261 | + }; |
| 262 | + |
253 | 263 |
|
254 | 264 | class ImageError |
255 | 265 | : public std::runtime_error |
@@ -325,6 +335,148 @@ namespace fi |
325 | 335 | } |
326 | 336 |
|
327 | 337 |
|
| 338 | + /** |
| 339 | + * Const access to a message allocated inside FreeImage |
| 340 | + */ |
| 341 | + class MessageView |
| 342 | + { |
| 343 | + public: |
| 344 | + explicit |
| 345 | + MessageView(const FIMESSAGE* handle) |
| 346 | + : mHandle(handle) |
| 347 | + { } |
| 348 | + |
| 349 | + MessageView(const MessageView&) = default; |
| 350 | + MessageView(MessageView&&) noexcept = default; |
| 351 | + |
| 352 | + // no need to release |
| 353 | + ~MessageView() = default; |
| 354 | + |
| 355 | + MessageView& operator=(const MessageView&) = default; |
| 356 | + MessageView& operator=(MessageView&&) noexcept = default; |
| 357 | + |
| 358 | + operator bool() const { |
| 359 | + return (mHandle != nullptr); |
| 360 | + } |
| 361 | + |
| 362 | + const char* GetCString() const { |
| 363 | + return FreeImage_GetMessageString(mHandle); |
| 364 | + } |
| 365 | + |
| 366 | + std::string GetString() const { |
| 367 | + const char* str = FreeImage_GetMessageString(mHandle); |
| 368 | + return str ? std::string(str) : std::string(); |
| 369 | + } |
| 370 | + |
| 371 | + Severity GetSeverity() const { |
| 372 | + return static_cast<Severity>(FreeImage_GetMessageSeverity(mHandle)); |
| 373 | + } |
| 374 | + |
| 375 | + ImageFormat GetScope() const { |
| 376 | + return static_cast<ImageFormat>(FreeImage_GetMessageScope(mHandle)); |
| 377 | + } |
| 378 | + |
| 379 | + protected: |
| 380 | + const FIMESSAGE* mHandle; |
| 381 | + }; |
| 382 | + |
| 383 | + |
| 384 | + /** |
| 385 | + * Mutable user allocated message instance |
| 386 | + */ |
| 387 | + class Message |
| 388 | + : public MessageView |
| 389 | + { |
| 390 | + public: |
| 391 | + Message(ImageFormat scope, Severity severity, const char* what) |
| 392 | + : MessageView(FREEIMAGERE_CHECKED_CALL(FreeImage_CreateMessage, static_cast<FREE_IMAGE_FORMAT>(scope), static_cast<FREE_IMAGE_SEVERITY>(severity), what)) |
| 393 | + { } |
| 394 | + |
| 395 | + Message(ImageFormat scope, Severity severity, const std::string& what) |
| 396 | + : Message(scope, severity, what.c_str()) |
| 397 | + { } |
| 398 | + |
| 399 | + Message(const Message&) = delete; |
| 400 | + |
| 401 | + Message(Message&& other) noexcept |
| 402 | + : MessageView(other.mHandle) |
| 403 | + { |
| 404 | + other.mHandle = nullptr; |
| 405 | + } |
| 406 | + |
| 407 | + // not virtual, just reusing methods MessageView |
| 408 | + ~Message() { |
| 409 | + FreeImage_DeleteMessage(GetMutable()); |
| 410 | + } |
| 411 | + |
| 412 | + Message& operator=(const Message&) = delete; |
| 413 | + |
| 414 | + Message& operator=(Message&& other) noexcept |
| 415 | + { |
| 416 | + if (this != &other) { |
| 417 | + FreeImage_DeleteMessage(GetMutable()); |
| 418 | + mHandle = other.mHandle; |
| 419 | + other.mHandle = nullptr; |
| 420 | + } |
| 421 | + return *this; |
| 422 | + } |
| 423 | + |
| 424 | + private: |
| 425 | + FIMESSAGE* GetMutable() { |
| 426 | + // Message created by FreeImage_CreateMessage() is actually a dynamic object, so can safely remove const |
| 427 | + return const_cast<FIMESSAGE*>(mHandle); |
| 428 | + } |
| 429 | + }; |
| 430 | + |
| 431 | + |
| 432 | + using MessageProcessFunction = std::function<void(const MessageView&)>; |
| 433 | + |
| 434 | + |
| 435 | + /** |
| 436 | + * Registers a message processor for life time of this guard instance |
| 437 | + */ |
| 438 | + class MessageProcessFunctionGuard |
| 439 | + { |
| 440 | + public: |
| 441 | + MessageProcessFunctionGuard(MessageProcessFunction func) |
| 442 | + : mFunc(std::move(func)) |
| 443 | + { |
| 444 | + mProcId = FREEIMAGERE_CHECKED_CALL(FreeImage_AddProcessMessageFunction, this, &MessageProcessFunctionGuard::Wrapper); |
| 445 | + } |
| 446 | + |
| 447 | + MessageProcessFunctionGuard(const MessageProcessFunctionGuard&) = delete; |
| 448 | + MessageProcessFunctionGuard(MessageProcessFunctionGuard&& other) noexcept = delete; |
| 449 | + |
| 450 | + ~MessageProcessFunctionGuard() |
| 451 | + { |
| 452 | + if (mProcId) { |
| 453 | + FreeImage_RemoveProcessMessageFunction(mProcId); |
| 454 | + } |
| 455 | + } |
| 456 | + |
| 457 | + MessageProcessFunctionGuard& operator=(const MessageProcessFunctionGuard&) = delete; |
| 458 | + MessageProcessFunctionGuard& operator=(MessageProcessFunctionGuard&& other) noexcept = delete; |
| 459 | + |
| 460 | + /** |
| 461 | + * Do not call FreeImage_RemoveProcessMessageFunction() in destcrutor |
| 462 | + */ |
| 463 | + uint32_t Release() { |
| 464 | + const uint32_t tmp = mProcId; |
| 465 | + mProcId = 0; |
| 466 | + return tmp; |
| 467 | + } |
| 468 | + |
| 469 | + private: |
| 470 | + static |
| 471 | + void DLL_CALLCONV Wrapper(void* thiz, const FIMESSAGE* msg) { |
| 472 | + static_cast<MessageProcessFunctionGuard*>(thiz)->mFunc(MessageView(msg)); |
| 473 | + } |
| 474 | + |
| 475 | + MessageProcessFunction mFunc; |
| 476 | + uint32_t mProcId{ 0 }; |
| 477 | + }; |
| 478 | + |
| 479 | + |
328 | 480 |
|
329 | 481 | class Tag |
330 | 482 | { |
@@ -359,13 +511,15 @@ namespace fi |
359 | 511 |
|
360 | 512 | Tag& operator=(Tag&& other) noexcept |
361 | 513 | { |
362 | | - if (mCallDelete && mHandle) { |
363 | | - FreeImage_DeleteTag(mHandle); |
| 514 | + if (this != &other) { |
| 515 | + if (mCallDelete) { |
| 516 | + FreeImage_DeleteTag(mHandle); |
| 517 | + } |
| 518 | + mHandle = other.mHandle; |
| 519 | + mCallDelete = other.mCallDelete; |
| 520 | + other.mHandle = nullptr; |
| 521 | + other.mCallDelete = false; |
364 | 522 | } |
365 | | - mHandle = other.mHandle; |
366 | | - mCallDelete = other.mCallDelete; |
367 | | - other.mHandle = nullptr; |
368 | | - other.mCallDelete = false; |
369 | 523 | return *this; |
370 | 524 | } |
371 | 525 |
|
|
0 commit comments