From ea49d2278c7c29b4ff52c7ba5962da61f99f7ff9 Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 9 Jan 2026 12:26:14 -0500 Subject: [PATCH] Fuzz: Avoid using temporary files - When built for fuzzing, expose special versions of tj3LoadImage*() that accept a FILE handle. - Rename cjpeg_main() to cjpeg_fuzzer() and allow a FILE handle to be passed to it as well. - Use fmemopen() to obtain a FILE handle from the fuzzer input data. --- CMakeLists.txt | 1 + fuzz/cjpeg.cc | 37 ++++++++------------ fuzz/compress.cc | 21 +++++------ fuzz/compress12.cc | 21 +++++------ fuzz/compress12_lossless.cc | 21 +++++------ fuzz/compress16_lossless.cc | 21 +++++------ fuzz/compress_lossless.cc | 21 +++++------ fuzz/compress_yuv.cc | 21 +++++------ src/cjpeg.c | 17 ++++++--- src/turbojpeg-mp.c | 69 ++++++++++++++++++++++++++++++------- 10 files changed, 152 insertions(+), 98 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d1db73c7..32aaa01d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -869,6 +869,7 @@ endif() ############################################################################### if(WITH_FUZZ) + add_definitions(-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) add_subdirectory(fuzz) endif() diff --git a/fuzz/cjpeg.cc b/fuzz/cjpeg.cc index 15f86ed7..e3b298e9 100644 --- a/fuzz/cjpeg.cc +++ b/fuzz/cjpeg.cc @@ -1,5 +1,5 @@ /* - * Copyright (C)2021, 2024 D. R. Commander. All Rights Reserved. + * Copyright (C)2021, 2024, 2026 D. R. Commander. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,13 +29,10 @@ /* This fuzz target wraps cjpeg in order to test esoteric compression options as well as the GIF and Targa readers. */ -#define main cjpeg_main #define CJPEG_FUZZER extern "C" { #include "../src/cjpeg.c" } -#undef main -#undef CJPEG_FUZZER #include #include @@ -43,40 +40,36 @@ extern "C" { extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - char filename[FILENAME_MAX] = { 0 }; char *argv1[] = { (char *)"cjpeg", (char *)"-dct", (char *)"float", (char *)"-memdst", (char *)"-optimize", (char *)"-quality", (char *)"100,99,98", (char *)"-restart", (char *)"2", (char *)"-sample", (char *)"4x1,2x2,1x2", - (char *)"-targa", NULL + (char *)"-targa" }; char *argv2[] = { (char *)"cjpeg", (char *)"-arithmetic", (char *)"-dct", (char *)"float", (char *)"-memdst", (char *)"-quality", (char *)"90,80,70", (char *)"-rgb", (char *)"-sample", (char *)"2x2", (char *)"-smooth", (char *)"50", - (char *)"-targa", NULL + (char *)"-targa" }; - int fd = -1; + FILE *file = NULL; - snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_cjpeg_fuzz.XXXXXX"); - if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0) + if ((file = fmemopen((void *)data, size, "r")) == NULL) goto bailout; - argv1[12] = argv2[13] = filename; + fseek(file, 0, SEEK_SET); + cjpeg_fuzzer(12, argv1, file); + fseek(file, 0, SEEK_SET); + cjpeg_fuzzer(13, argv2, file); - cjpeg_main(13, argv1); - cjpeg_main(14, argv2); + argv1[11] = argv2[12] = NULL; - argv1[12] = argv2[13] = NULL; - argv1[11] = argv2[12] = filename; - - cjpeg_main(12, argv1); - cjpeg_main(13, argv2); + fseek(file, 0, SEEK_SET); + cjpeg_fuzzer(11, argv1, file); + fseek(file, 0, SEEK_SET); + cjpeg_fuzzer(12, argv2, file); bailout: - if (fd >= 0) { - close(fd); - if (strlen(filename) > 0) unlink(filename); - } + if (file) fclose(file); return 0; } diff --git a/fuzz/compress.cc b/fuzz/compress.cc index c98521a9..b0537b30 100644 --- a/fuzz/compress.cc +++ b/fuzz/compress.cc @@ -33,6 +33,10 @@ #include #include +extern "C" unsigned char * +_tj3LoadImageFromFileHandle8(tjhandle handle, FILE *file, int *width, + int align, int *height, int *pixelFormat); + #define NUMTESTS 7 @@ -48,8 +52,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { tjhandle handle = NULL; unsigned char *srcBuf = NULL, *dstBuf = NULL; - int width = 0, height = 0, fd = -1, ti; - char filename[FILENAME_MAX] = { 0 }; + int width = 0, height = 0, ti; + FILE *file = NULL; struct test tests[NUMTESTS] = { { TJPF_RGB, TJSAMP_444, 100 }, { TJPF_BGR, TJSAMP_422, 90 }, @@ -60,8 +64,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { TJPF_CMYK, TJSAMP_440, 40 } }; - snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_fuzz.XXXXXX"); - if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0) + if ((file = fmemopen((void *)data, size, "r")) == NULL) goto bailout; if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) @@ -83,8 +86,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tj3Set(handle, TJPARAM_MAXPIXELS, 1048576); /* tj3LoadImage8() will refuse to load images larger than 1 Megapixel, so we don't need to check the width and height here. */ - if ((srcBuf = tj3LoadImage8(handle, filename, &width, 1, &height, - &pf)) == NULL) + fseek(file, 0, SEEK_SET); + if ((srcBuf = _tj3LoadImageFromFileHandle8(handle, file, &width, 1, + &height, &pf)) == NULL) continue; dstSize = maxBufSize = tj3JPEGBufSize(width, height, tests[ti].subsamp); @@ -118,10 +122,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) bailout: tj3Free(dstBuf); tj3Free(srcBuf); - if (fd >= 0) { - close(fd); - if (strlen(filename) > 0) unlink(filename); - } + if (file) fclose(file); tj3Destroy(handle); return 0; } diff --git a/fuzz/compress12.cc b/fuzz/compress12.cc index 5ee93f3f..0b3d2ef0 100644 --- a/fuzz/compress12.cc +++ b/fuzz/compress12.cc @@ -33,6 +33,10 @@ #include #include +extern "C" short * +_tj3LoadImageFromFileHandle12(tjhandle handle, FILE *file, int *width, + int align, int *height, int *pixelFormat); + #define NUMTESTS 7 @@ -49,8 +53,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tjhandle handle = NULL; short *srcBuf = NULL; unsigned char *dstBuf = NULL; - int width = 0, height = 0, fd = -1, ti; - char filename[FILENAME_MAX] = { 0 }; + int width = 0, height = 0, ti; + FILE *file = NULL; struct test tests[NUMTESTS] = { { TJPF_RGB, TJSAMP_444, 100 }, { TJPF_BGR, TJSAMP_422, 90 }, @@ -61,8 +65,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { TJPF_CMYK, TJSAMP_440, 40 } }; - snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress12_fuzz.XXXXXX"); - if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0) + if ((file = fmemopen((void *)data, size, "r")) == NULL) goto bailout; if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) @@ -83,8 +86,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tj3Set(handle, TJPARAM_MAXPIXELS, 1048576); /* tj3LoadImage12() will refuse to load images larger than 1 Megapixel, so we don't need to check the width and height here. */ - if ((srcBuf = tj3LoadImage12(handle, filename, &width, 1, &height, - &pf)) == NULL) + fseek(file, 0, SEEK_SET); + if ((srcBuf = _tj3LoadImageFromFileHandle12(handle, file, &width, 1, + &height, &pf)) == NULL) continue; dstSize = maxBufSize = tj3JPEGBufSize(width, height, tests[ti].subsamp); @@ -118,10 +122,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) bailout: tj3Free(dstBuf); tj3Free(srcBuf); - if (fd >= 0) { - close(fd); - if (strlen(filename) > 0) unlink(filename); - } + if (file) fclose(file); tj3Destroy(handle); return 0; } diff --git a/fuzz/compress12_lossless.cc b/fuzz/compress12_lossless.cc index dd4c1e18..86b3c9b1 100644 --- a/fuzz/compress12_lossless.cc +++ b/fuzz/compress12_lossless.cc @@ -33,6 +33,10 @@ #include #include +extern "C" short * +_tj3LoadImageFromFileHandle12(tjhandle handle, FILE *file, int *width, + int align, int *height, int *pixelFormat); + #define NUMTESTS 7 @@ -48,8 +52,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tjhandle handle = NULL; short *srcBuf = NULL; unsigned char *dstBuf = NULL; - int width = 0, height = 0, fd = -1, ti; - char filename[FILENAME_MAX] = { 0 }; + int width = 0, height = 0, ti; + FILE *file = NULL; struct test tests[NUMTESTS] = { { TJPF_RGB, 12, 1, 0 }, { TJPF_BGR, 11, 2, 2 }, @@ -60,8 +64,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { TJPF_CMYK, 12, 7, 0 } }; - snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_fuzz.XXXXXX"); - if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0) + if ((file = fmemopen((void *)data, size, "r")) == NULL) goto bailout; if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) @@ -80,8 +83,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tj3Set(handle, TJPARAM_MAXPIXELS, 1048576); /* tj3LoadImage12() will refuse to load images larger than 1 Megapixel, so we don't need to check the width and height here. */ - if ((srcBuf = tj3LoadImage12(handle, filename, &width, 1, &height, - &pf)) == NULL) + fseek(file, 0, SEEK_SET); + if ((srcBuf = _tj3LoadImageFromFileHandle12(handle, file, &width, 1, + &height, &pf)) == NULL) continue; dstSize = maxBufSize = tj3JPEGBufSize(width, height, TJSAMP_444); @@ -116,10 +120,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) bailout: tj3Free(dstBuf); tj3Free(srcBuf); - if (fd >= 0) { - close(fd); - if (strlen(filename) > 0) unlink(filename); - } + if (file) fclose(file); tj3Destroy(handle); return 0; } diff --git a/fuzz/compress16_lossless.cc b/fuzz/compress16_lossless.cc index df1226d8..2ba01d07 100644 --- a/fuzz/compress16_lossless.cc +++ b/fuzz/compress16_lossless.cc @@ -33,6 +33,10 @@ #include #include +extern "C" unsigned short * +_tj3LoadImageFromFileHandle16(tjhandle handle, FILE *file, int *width, + int align, int *height, int *pixelFormat); + #define NUMTESTS 7 @@ -48,8 +52,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tjhandle handle = NULL; unsigned short *srcBuf = NULL; unsigned char *dstBuf = NULL; - int width = 0, height = 0, fd = -1, ti; - char filename[FILENAME_MAX] = { 0 }; + int width = 0, height = 0, ti; + FILE *file = NULL; struct test tests[NUMTESTS] = { { TJPF_RGB, 16, 1, 0 }, { TJPF_BGR, 15, 2, 2 }, @@ -60,8 +64,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { TJPF_CMYK, 16, 7, 0 } }; - snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_fuzz.XXXXXX"); - if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0) + if ((file = fmemopen((void *)data, size, "r")) == NULL) goto bailout; if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) @@ -80,8 +83,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tj3Set(handle, TJPARAM_MAXPIXELS, 1048576); /* tj3LoadImage16() will refuse to load images larger than 1 Megapixel, so we don't need to check the width and height here. */ - if ((srcBuf = tj3LoadImage16(handle, filename, &width, 1, &height, - &pf)) == NULL) + fseek(file, 0, SEEK_SET); + if ((srcBuf = _tj3LoadImageFromFileHandle16(handle, file, &width, 1, + &height, &pf)) == NULL) continue; dstSize = maxBufSize = tj3JPEGBufSize(width, height, TJSAMP_444); @@ -116,10 +120,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) bailout: tj3Free(dstBuf); tj3Free(srcBuf); - if (fd >= 0) { - close(fd); - if (strlen(filename) > 0) unlink(filename); - } + if (file) fclose(file); tj3Destroy(handle); return 0; } diff --git a/fuzz/compress_lossless.cc b/fuzz/compress_lossless.cc index 8d4478b1..33cf85b2 100644 --- a/fuzz/compress_lossless.cc +++ b/fuzz/compress_lossless.cc @@ -33,6 +33,10 @@ #include #include +extern "C" unsigned char * +_tj3LoadImageFromFileHandle8(tjhandle handle, FILE *file, int *width, + int align, int *height, int *pixelFormat); + #define NUMTESTS 7 @@ -47,8 +51,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { tjhandle handle = NULL; unsigned char *srcBuf = NULL, *dstBuf = NULL; - int width = 0, height = 0, fd = -1, ti; - char filename[FILENAME_MAX] = { 0 }; + int width = 0, height = 0, ti; + FILE *file = NULL; struct test tests[NUMTESTS] = { { TJPF_RGB, 8, 1, 0 }, { TJPF_BGR, 7, 2, 5 }, @@ -59,8 +63,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { TJPF_CMYK, 2, 7, 0 } }; - snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_fuzz.XXXXXX"); - if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0) + if ((file = fmemopen((void *)data, size, "r")) == NULL) goto bailout; if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) @@ -79,8 +82,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tj3Set(handle, TJPARAM_MAXPIXELS, 1048576); /* tj3LoadImage8() will refuse to load images larger than 1 Megapixel, so we don't need to check the width and height here. */ - if ((srcBuf = tj3LoadImage8(handle, filename, &width, 1, &height, - &pf)) == NULL) + fseek(file, 0, SEEK_SET); + if ((srcBuf = _tj3LoadImageFromFileHandle8(handle, file, &width, 1, + &height, &pf)) == NULL) continue; dstSize = maxBufSize = tj3JPEGBufSize(width, height, TJSAMP_444); @@ -115,10 +119,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) bailout: tj3Free(dstBuf); tj3Free(srcBuf); - if (fd >= 0) { - close(fd); - if (strlen(filename) > 0) unlink(filename); - } + if (file) fclose(file); tj3Destroy(handle); return 0; } diff --git a/fuzz/compress_yuv.cc b/fuzz/compress_yuv.cc index 9677b9f3..e9ce386d 100644 --- a/fuzz/compress_yuv.cc +++ b/fuzz/compress_yuv.cc @@ -33,6 +33,10 @@ #include #include +extern "C" unsigned char * +_tj3LoadImageFromFileHandle8(tjhandle handle, FILE *file, int *width, + int align, int *height, int *pixelFormat); + #define NUMTESTS 6 @@ -48,8 +52,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { tjhandle handle = NULL; unsigned char *srcBuf = NULL, *dstBuf = NULL, *yuvBuf = NULL; - int width = 0, height = 0, fd = -1, ti; - char filename[FILENAME_MAX] = { 0 }; + int width = 0, height = 0, ti; + FILE *file = NULL; struct test tests[NUMTESTS] = { { TJPF_XBGR, TJSAMP_444, 100 }, { TJPF_XRGB, TJSAMP_422, 90 }, @@ -59,8 +63,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { TJPF_GRAY, TJSAMP_GRAY, 50 } }; - snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_yuv_fuzz.XXXXXX"); - if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0) + if ((file = fmemopen((void *)data, size, "r")) == NULL) goto bailout; if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) @@ -82,8 +85,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) tj3Set(handle, TJPARAM_MAXPIXELS, 1048576); /* tj3LoadImage8() will refuse to load images larger than 1 Megapixel, so we don't need to check the width and height here. */ - if ((srcBuf = tj3LoadImage8(handle, filename, &width, 1, &height, - &pf)) == NULL) + fseek(file, 0, SEEK_SET); + if ((srcBuf = _tj3LoadImageFromFileHandle8(handle, file, &width, 1, + &height, &pf)) == NULL) continue; dstSize = maxBufSize = tj3JPEGBufSize(width, height, tests[ti].subsamp); @@ -123,10 +127,7 @@ bailout: tj3Free(dstBuf); free(yuvBuf); tj3Free(srcBuf); - if (fd >= 0) { - close(fd); - if (strlen(filename) > 0) unlink(filename); - } + if (file) fclose(file); tj3Destroy(handle); return 0; } diff --git a/src/cjpeg.c b/src/cjpeg.c index 22da5382..8c6be2fd 100644 --- a/src/cjpeg.c +++ b/src/cjpeg.c @@ -7,7 +7,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2013-2014, 2017, 2019-2022, 2024-2025, + * Copyright (C) 2010, 2013-2014, 2017, 2019-2022, 2024-2026, * D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. @@ -162,7 +162,7 @@ struct my_error_mgr { jmp_buf setjmp_buffer; }; -void my_error_exit(j_common_ptr cinfo) +static void my_error_exit(j_common_ptr cinfo) { struct my_error_mgr *myerr = (struct my_error_mgr *)cinfo->err; @@ -182,8 +182,6 @@ static void my_emit_message_fuzzer(j_common_ptr cinfo, int msg_level) jpeg_abort_compress(&cinfo); \ } \ jpeg_destroy_compress(&cinfo); \ - if (input_file != stdin && input_file != NULL) \ - fclose(input_file); \ if (memdst) \ free(outbuffer); \ free(icc_profile); \ @@ -616,8 +614,13 @@ my_emit_message(j_common_ptr cinfo, int msg_level) * The main program. */ +#ifdef CJPEG_FUZZER +static int +cjpeg_fuzzer(int argc, char **argv, FILE *input_file) +#else int main(int argc, char **argv) +#endif { struct jpeg_compress_struct cinfo; #ifdef CJPEG_FUZZER @@ -629,7 +632,9 @@ main(int argc, char **argv) struct cdjpeg_progress_mgr progress; int file_index; cjpeg_source_ptr src_mgr; +#ifndef CJPEG_FUZZER FILE *input_file = NULL; +#endif FILE *icc_file; JOCTET *icc_profile = NULL; long icc_len = 0; @@ -696,6 +701,7 @@ main(int argc, char **argv) } #endif /* TWO_FILE_COMMANDLINE */ +#ifndef CJPEG_FUZZER /* Open the input file. */ if (file_index < argc) { if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { @@ -706,6 +712,7 @@ main(int argc, char **argv) /* default input file is stdin */ input_file = read_stdin(); } +#endif /* Open the output file. */ if (outfilename != NULL) { @@ -818,8 +825,10 @@ main(int argc, char **argv) jpeg_destroy_compress(&cinfo); /* Close files, if we opened them */ +#ifndef CJPEG_FUZZER if (input_file != stdin) fclose(input_file); +#endif if (output_file != stdout && output_file != NULL) fclose(output_file); diff --git a/src/turbojpeg-mp.c b/src/turbojpeg-mp.c index 6fecc5cb..f9d72ca7 100644 --- a/src/turbojpeg-mp.c +++ b/src/turbojpeg-mp.c @@ -1,5 +1,5 @@ /* - * Copyright (C)2009-2025 D. R. Commander. All Rights Reserved. + * Copyright (C)2009-2026 D. R. Commander. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -290,8 +290,11 @@ bailout: /*************************** Packed-Pixel Image I/O **************************/ /* TurboJPEG 3.0+ */ -DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE) - (tjhandle handle, const char *filename, int *width, int align, int *height, +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +static +#endif +_JSAMPLE *GET_NAME(_tj3LoadImageFromFileHandle, BITS_IN_JSAMPLE) + (tjhandle handle, FILE *file, int *width, int align, int *height, int *pixelFormat) { static const char FUNCTION_NAME[] = @@ -306,12 +309,11 @@ DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE) j_compress_ptr cinfo = NULL; cjpeg_source_ptr src; _JSAMPLE *dstBuf = NULL; - FILE *file = NULL; boolean invert; GET_TJINSTANCE(handle, NULL) - if (!filename || !width || align < 1 || !height || !pixelFormat || + if (!file || !width || align < 1 || !height || !pixelFormat || *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF) THROW("Invalid argument"); if ((align & (align - 1)) != 0) @@ -324,13 +326,6 @@ DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE) this2 = (tjinstance *)handle2; cinfo = &this2->cinfo; -#ifdef _MSC_VER - if (fopen_s(&file, filename, "rb") || file == NULL) -#else - if ((file = fopen(filename, "rb")) == NULL) -#endif - THROW_UNIX("Cannot open input file"); - if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF) THROW_UNIX("Could not read input file") else if (tempc == EOF) @@ -415,6 +410,56 @@ DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE) bailout: tj3Destroy(handle2); + if (retval < 0) { free(dstBuf); dstBuf = NULL; } + return dstBuf; + +#else /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */ + + static const char ERROR_MSG[] = + "16-bit data precision requires lossless JPEG,\n" + "which was disabled at build time."; + _JSAMPLE *retval = NULL; + + GET_TJINSTANCE(handle, NULL) + SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, + ERROR_MSG); + this->isInstanceError = TRUE; THROWG(ERROR_MSG, NULL) + +bailout: + return retval; + +#endif +} + +DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE) + (tjhandle handle, const char *filename, int *width, int align, int *height, + int *pixelFormat) +{ + static const char FUNCTION_NAME[] = + GET_STRING(tj3LoadImage, BITS_IN_JSAMPLE); + +#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) + + int retval = 0; + _JSAMPLE *dstBuf = NULL; + FILE *file = NULL; + + GET_TJINSTANCE(handle, NULL) + + if (!filename) + THROW("Invalid argument"); + +#ifdef _MSC_VER + if (fopen_s(&file, filename, "rb") || file == NULL) +#else + if ((file = fopen(filename, "rb")) == NULL) +#endif + THROW_UNIX("Cannot open input file"); + + dstBuf = GET_NAME(_tj3LoadImageFromFileHandle, BITS_IN_JSAMPLE) + (handle, file, width, align, height, pixelFormat); + +bailout: if (file) fclose(file); if (retval < 0) { free(dstBuf); dstBuf = NULL; } return dstBuf;