1 #ifndef _JPEGLIB_ERROR_WRAPPER
2 #define _JPEGLIB_ERROR_WRAPPER 1
5 A wrapper class for libjpeg's very cumbersome error handling.
6 By default, any error will simply exit(); you can set your own
7 error handler, but it can't return. You can't throw exceptions
8 through C code legally, so the only real choice is setjmp/longjmp,
9 which is also what libjpeg recommends. However, longjmp has
10 undefined behavior if a similar try/catch pair would invoke
11 running any nontrivial destructors, so it's better to wrap it
12 into a common class where we know for sure there are no such
13 destructors; we choose to simply convert it into a normal
14 true/false idiom for success/failure.
18 JPEGWrapErrorManager error_mgr(&cinfo);
19 if (!error_mgr.run([&cinfo]{ jpeg_read_header(&cinfo, true); })) {
20 // Something went wrong.
23 if (!error_mgr.run([&cinfo]{ jpeg_start_decompress(&cinfo); })) {
24 // Something went wrong.
29 If you call libjpeg calls outside of run() and they fail, or if
30 you declare objects with nontrivial destructors in your lambda
31 (including in the capture), you end up in undefined behavior.
37 struct JPEGWrapErrorManager {
38 struct jpeg_error_mgr pub;
39 jmp_buf setjmp_buffer;
41 explicit JPEGWrapErrorManager(jpeg_compress_struct *cinfo) // Does not take ownership.
43 cinfo->err = jpeg_std_error(&pub);
44 pub.error_exit = error_exit_thunk;
47 explicit JPEGWrapErrorManager(jpeg_decompress_struct *dinfo) // Does not take ownership.
49 dinfo->err = jpeg_std_error(&pub);
50 pub.error_exit = error_exit_thunk;
53 static void error_exit_thunk(jpeg_common_struct *cinfo)
55 ((JPEGWrapErrorManager *)cinfo->err)->error_exit(cinfo);
58 void error_exit(jpeg_common_struct *cinfo)
60 (pub.output_message)(cinfo);
61 longjmp(setjmp_buffer, 1);
64 // Returns false if and only if the call failed.
66 inline bool run(T &&func)
68 if (setjmp(setjmp_buffer)) {