From aaf8874c8e653b4ee8bce7576f55d10e3d747993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= Date: Mon, 13 Dec 2021 16:44:11 +0000 Subject: [PATCH] Initial import (#2029219) --- .gitignore | 1 + ...ild-against-system-versions-of-depen.patch | 76 + 269.patch | 1647 +++++++++++++++++ sources | 1 + zxing-cpp.spec | 94 + 5 files changed, 1819 insertions(+) create mode 100644 .gitignore create mode 100644 0001-Add-a-mode-to-build-against-system-versions-of-depen.patch create mode 100644 269.patch create mode 100644 sources create mode 100644 zxing-cpp.spec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..270c097 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/zxing-cpp-1.2.0.tar.gz diff --git a/0001-Add-a-mode-to-build-against-system-versions-of-depen.patch b/0001-Add-a-mode-to-build-against-system-versions-of-depen.patch new file mode 100644 index 0000000..78e4410 --- /dev/null +++ b/0001-Add-a-mode-to-build-against-system-versions-of-depen.patch @@ -0,0 +1,76 @@ +From 8db14eeead45e0f1961532f55061d5e4dd0f78be Mon Sep 17 00:00:00 2001 +From: Paul Wise +Date: Thu, 26 Aug 2021 22:03:00 +0800 +Subject: [PATCH] Add a mode to build against system versions of dependencies + +Make the default be to use system versions when available, +but allow always using them or never using them. + +Add searching for and using system versions of fmt/googletest/pybind11, +which are currently pulled directly from git using FetchContent. + +This will allow distributions that do not allow network access at build +time to depend on and build against these packages. + +Fixes: https://github.com/nu-book/zxing-cpp/issues/248 +--- + CMakeLists.txt | 7 +++++++ + test/blackbox/CMakeLists.txt | 18 +++++++++++++----- + 1 files changed, 54 insertions(+), 21 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1361792..2b522e0 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -8,6 +8,7 @@ option (BUILD_EXAMPLES "Build the example barcode reader/writer applicatons" ON) + option (BUILD_BLACKBOX_TESTS "Build the black box reader/writer tests" ON) + option (BUILD_UNIT_TESTS "Build the unit tests (don't enable for production builds)" OFF) + option (BUILD_PYTHON_MODULE "Build the python module" OFF) ++set(BUILD_SYSTEM_DEPS "AUTO" CACHE STRING "Use system dependencies (AUTO/ALWAYS/NEVER)") + + if (WIN32) + option (BUILD_SHARED_LIBS "Build and link as shared library" OFF) +@@ -53,6 +54,12 @@ if (BUILD_UNIT_TESTS) + endif() + endif() + ++set(BUILD_SYSTEM_DEPS_LIST AUTO ALWAYS NEVER) ++set_property(CACHE BUILD_SYSTEM_DEPS PROPERTY STRINGS ${BUILD_SYSTEM_DEPS_LIST}) ++if(NOT BUILD_SYSTEM_DEPS IN_LIST BUILD_SYSTEM_DEPS_LIST) ++ message(FATAL_ERROR "BUILD_SYSTEM_DEPS must be one of ${BUILD_SYSTEM_DEPS_LIST}") ++endif() ++ + add_subdirectory (core) + + enable_testing() +diff --git a/test/blackbox/CMakeLists.txt b/test/blackbox/CMakeLists.txt +index 3da26dd..9d79e8e 100644 +--- a/test/blackbox/CMakeLists.txt ++++ b/test/blackbox/CMakeLists.txt +@@ -1,10 +1,18 @@ + cmake_minimum_required(VERSION 3.14) + +-include(FetchContent) +-FetchContent_Declare (fmtlib +- GIT_REPOSITORY https://github.com/fmtlib/fmt.git +- GIT_TAG 7.1.2) +-FetchContent_MakeAvailable (fmtlib) # Adds fmt::fmt ++if (BUILD_SYSTEM_DEPS STREQUAL "AUTO") ++ find_package (fmt) ++elseif (BUILD_SYSTEM_DEPS STREQUAL "ALWAYS") ++ find_package (fmt REQUIRED) ++endif() ++ ++if (NOT fmt_FOUND) ++ include(FetchContent) ++ FetchContent_Declare (fmtlib ++ GIT_REPOSITORY https://github.com/fmtlib/fmt.git ++ GIT_TAG 7.1.2) ++ FetchContent_MakeAvailable (fmtlib) # Adds fmt::fmt ++endif() + + if (BUILD_READERS) + add_executable (ReaderTest +-- +2.33.1 + diff --git a/269.patch b/269.patch new file mode 100644 index 0000000..ea0864c --- /dev/null +++ b/269.patch @@ -0,0 +1,1647 @@ +From 1d031966e08aef92ef742ae3cf91e1addaf95a47 Mon Sep 17 00:00:00 2001 +From: "Benjamin A. Beasley" +Date: Wed, 8 Dec 2021 18:14:54 -0500 +Subject: [PATCH 1/4] Use a patch file to document changes from upstream + stb_image.h + +--- + thirdparty/stb/stb_image.patch | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + create mode 100644 thirdparty/stb/stb_image.patch + +diff --git a/thirdparty/stb/stb_image.patch b/thirdparty/stb/stb_image.patch +new file mode 100644 +index 00000000..51537287 +--- /dev/null ++++ b/thirdparty/stb/stb_image.patch +@@ -0,0 +1,15 @@ ++diff -Naur upstream/stb_image.h zxing/stb_image.h ++--- upstream/stb_image.h 2021-12-08 18:11:28.170529096 -0500 +++++ zxing/stb_image.h 2021-12-08 18:06:42.706717697 -0500 ++@@ -1644,7 +1644,11 @@ ++ ++ static stbi_uc stbi__compute_y(int r, int g, int b) ++ { +++#if 0 // ori ++ return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +++#else // zxing (see ReadBarcode.cpp:RGBToGray) +++ return (stbi_uc) ((306 * r + 601 * g + 117 * b + 0x200) >> 10); +++#endif ++ } ++ #endif ++ + +From 38f86eecd1e790329d56a4491ee0498d75d61c42 Mon Sep 17 00:00:00 2001 +From: "Benjamin A. Beasley" +Date: Wed, 8 Dec 2021 18:16:46 -0500 +Subject: [PATCH 2/4] Update stb_image_write from 1.14 to 1.16 + + 1.16 (2021-07-11) + make Deflate code emit uncompressed blocks when it would + otherwise expand support writing BMPs with alpha channel + 1.15 (2020-07-13) unknown +--- + thirdparty/stb/stb_image_write.h | 132 ++++++++++++++++++++++--------- + 1 file changed, 95 insertions(+), 37 deletions(-) + +diff --git a/thirdparty/stb/stb_image_write.h b/thirdparty/stb/stb_image_write.h +index cffd473c..e4b32ed1 100644 +--- a/thirdparty/stb/stb_image_write.h ++++ b/thirdparty/stb/stb_image_write.h +@@ -1,4 +1,4 @@ +-/* stb_image_write - v1.14 - public domain - http://nothings.org/stb ++/* stb_image_write - v1.16 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + +@@ -140,6 +140,7 @@ + Ivan Tikhonov + github:ignotion + Adam Schackart ++ Andrew Kensler + + LICENSE + +@@ -166,9 +167,9 @@ LICENSE + #endif + + #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +-extern int stbi_write_tga_with_rle; +-extern int stbi_write_png_compression_level; +-extern int stbi_write_force_png_filter; ++STBIWDEF int stbi_write_tga_with_rle; ++STBIWDEF int stbi_write_png_compression_level; ++STBIWDEF int stbi_write_force_png_filter; + #endif + + #ifndef STBI_WRITE_NO_STDIO +@@ -178,7 +179,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const + STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +-#ifdef STBI_WINDOWS_UTF8 ++#ifdef STBIW_WINDOWS_UTF8 + STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); + #endif + #endif +@@ -267,6 +268,8 @@ typedef struct + { + stbi_write_func *func; + void *context; ++ unsigned char buffer[64]; ++ int buf_used; + } stbi__write_context; + + // initialize a callback-based context +@@ -283,7 +286,7 @@ static void stbi__stdio_write(void *context, void *data, int size) + fwrite(data,1,size,(FILE*) context); + } + +-#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) ++#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) + #ifdef __cplusplus + #define STBIW_EXTERN extern "C" + #else +@@ -294,25 +297,25 @@ STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned in + + STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) + { +- return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); ++ return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); + } + #endif + + static FILE *stbiw__fopen(char const *filename, char const *mode) + { + FILE *f; +-#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) ++#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; +- if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) ++ if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + +- if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) ++ if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +-#if _MSC_VER >= 1400 +- if (0 != _wfopen_s(&f, wFilename, wMode)) +- f = 0; ++#if defined(_MSC_VER) && _MSC_VER >= 1400 ++ if (0 != _wfopen_s(&f, wFilename, wMode)) ++ f = 0; + #else + f = _wfopen(wFilename, wMode); + #endif +@@ -380,16 +383,36 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) + va_end(v); + } + ++static void stbiw__write_flush(stbi__write_context *s) ++{ ++ if (s->buf_used) { ++ s->func(s->context, &s->buffer, s->buf_used); ++ s->buf_used = 0; ++ } ++} ++ + static void stbiw__putc(stbi__write_context *s, unsigned char c) + { + s->func(s->context, &c, 1); + } + ++static void stbiw__write1(stbi__write_context *s, unsigned char a) ++{ ++ if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) ++ stbiw__write_flush(s); ++ s->buffer[s->buf_used++] = a; ++} ++ + static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) + { +- unsigned char arr[3]; +- arr[0] = a; arr[1] = b; arr[2] = c; +- s->func(s->context, arr, 3); ++ int n; ++ if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) ++ stbiw__write_flush(s); ++ n = s->buf_used; ++ s->buf_used = n+3; ++ s->buffer[n+0] = a; ++ s->buffer[n+1] = b; ++ s->buffer[n+2] = c; + } + + static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +@@ -398,7 +421,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in + int k; + + if (write_alpha < 0) +- s->func(s->context, &d[comp - 1], 1); ++ stbiw__write1(s, d[comp - 1]); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case +@@ -406,7 +429,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else +- s->func(s->context, d, 1); // monochrome TGA ++ stbiw__write1(s, d[0]); // monochrome TGA + break; + case 4: + if (!write_alpha) { +@@ -422,7 +445,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in + break; + } + if (write_alpha > 0) +- s->func(s->context, &d[comp - 1], 1); ++ stbiw__write1(s, d[comp - 1]); + } + + static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +@@ -447,6 +470,7 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } ++ stbiw__write_flush(s); + s->func(s->context, &zero, scanline_pad); + } + } +@@ -467,16 +491,27 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, + + static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) + { +- int pad = (-x*3) & 3; +- return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, +- "11 4 22 4" "4 44 22 444444", +- 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header +- 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header ++ if (comp != 4) { ++ // write RGB bitmap ++ int pad = (-x*3) & 3; ++ return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, ++ "11 4 22 4" "4 44 22 444444", ++ 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header ++ 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header ++ } else { ++ // RGBA bitmaps need a v4 header ++ // use BI_BITFIELDS mode with 32bpp and alpha mask ++ // (straight BI_RGB with alpha mask doesn't work in most readers) ++ return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, ++ "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", ++ 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header ++ 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header ++ } + } + + STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) + { +- stbi__write_context s; ++ stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); + } +@@ -484,7 +519,7 @@ STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, + #ifndef STBI_WRITE_NO_STDIO + STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) + { +- stbi__write_context s; ++ stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); +@@ -557,24 +592,25 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); +- s->func(s->context, &header, 1); ++ stbiw__write1(s, header); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); +- s->func(s->context, &header, 1); ++ stbiw__write1(s, header); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } ++ stbiw__write_flush(s); + } + return 1; + } + + STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) + { +- stbi__write_context s; ++ stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); + } +@@ -582,7 +618,7 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, + #ifndef STBI_WRITE_NO_STDIO + STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) + { +- stbi__write_context s; ++ stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); +@@ -598,6 +634,8 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const + + #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + ++#ifndef STBI_WRITE_NO_STDIO ++ + static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) + { + int exponent; +@@ -732,7 +770,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +-#ifdef __STDC_WANT_SECURE_LIB__ ++#ifdef __STDC_LIB_EXT1__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + #else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +@@ -748,15 +786,14 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f + + STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) + { +- stbi__write_context s; ++ stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); + } + +-#ifndef STBI_WRITE_NO_STDIO + STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) + { +- stbi__write_context s; ++ stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); +@@ -944,6 +981,23 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + ++ // store uncompressed instead if compression was worse ++ if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { ++ stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 ++ for (j = 0; j < data_len;) { ++ int blocklen = data_len - j; ++ if (blocklen > 32767) blocklen = 32767; ++ stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression ++ stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN ++ stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); ++ stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN ++ stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); ++ memcpy(out+stbiw__sbn(out), data+j, blocklen); ++ stbiw__sbn(out) += blocklen; ++ j += blocklen; ++ } ++ } ++ + { + // compute adler32 on input + unsigned int s1=1, s2=0; +@@ -1552,7 +1606,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in + + STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) + { +- stbi__write_context s; ++ stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); + } +@@ -1561,7 +1615,7 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, + #ifndef STBI_WRITE_NO_STDIO + STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) + { +- stbi__write_context s; ++ stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); +@@ -1574,6 +1628,10 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const + #endif // STB_IMAGE_WRITE_IMPLEMENTATION + + /* Revision history ++ 1.16 (2021-07-11) ++ make Deflate code emit uncompressed blocks when it would otherwise expand ++ support writing BMPs with alpha channel ++ 1.15 (2020-07-13) unknown + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 +@@ -1611,7 +1669,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) +- add monochrome TGA output ++ add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + +From 40f3e3eb96adb4f1bfc612837653c8e81d8ad46d Mon Sep 17 00:00:00 2001 +From: "Benjamin A. Beasley" +Date: Wed, 8 Dec 2021 18:20:00 -0500 +Subject: [PATCH 3/4] Update stb_image from 2.25 to 2.27 + + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes +--- + thirdparty/stb/stb_image.h | 475 +++++++++++++++++++++++++-------- + thirdparty/stb/stb_image.patch | 6 +- + 2 files changed, 361 insertions(+), 120 deletions(-) + +diff --git a/thirdparty/stb/stb_image.h b/thirdparty/stb/stb_image.h +index ee8f61c9..c58bc0c5 100644 +--- a/thirdparty/stb/stb_image.h ++++ b/thirdparty/stb/stb_image.h +@@ -1,4 +1,4 @@ +-/* stb_image - v2.25 - public domain image loader - http://nothings.org/stb ++/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: +@@ -48,6 +48,8 @@ LICENSE + + RECENT REVISION HISTORY: + ++ 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes ++ 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning +@@ -88,27 +90,37 @@ RECENT REVISION HISTORY: + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) +- Arseny Kapoulkine ++ Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes +- Marc LeBlanc David Woo Guillaume George Martins Mozeiko +- Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan +- Dave Moore Roy Eltham Hayaki Saito Nathan Reed +- Won Chun Luke Graham Johan Duparc Nick Verigakis +- the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh +- Janez Zemva John Bartholomew Michal Cichon github:romigrou +- Jonathan Blow Ken Hamada Tero Hanninen github:svdijk +- Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar +- Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex +- Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 +- Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw +- Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus +- Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo +- Christian Floisand Kevin Schmidt JR Smith github:darealshinji +- Brad Weinberger Matvey Cherevko github:Michaelangel007 +- Blazej Dariusz Roszkowski Alexander Veselov ++ Marc LeBlanc David Woo Guillaume George Martins Mozeiko ++ Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski ++ Phil Jordan Dave Moore Roy Eltham ++ Hayaki Saito Nathan Reed Won Chun ++ Luke Graham Johan Duparc Nick Verigakis the Horde3D community ++ Thomas Ruf Ronny Chevalier github:rlyeh ++ Janez Zemva John Bartholomew Michal Cichon github:romigrou ++ Jonathan Blow Ken Hamada Tero Hanninen github:svdijk ++ Eugene Golushkov Laurent Gomila Cort Stratton github:snagar ++ Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex ++ Cass Everitt Ryamond Barbiero github:grim210 ++ Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw ++ Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus ++ Josh Tobin Matthew Gregan github:poppolopoppo ++ Julian Raschke Gregory Mullen Christian Floisand github:darealshinji ++ Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 ++ Brad Weinberger Matvey Cherevko github:mosra ++ Luca Sas Alexander Veselov Zack Middleton [reserved] ++ Ryan C. Gordon [reserved] [reserved] ++ DO NOT ADD YOUR NAME HERE ++ ++ Jacko Dirks ++ ++ To add your name to the credits, pick a random blank space in the middle and fill it. ++ 80% of merge conflicts on stb PRs are due to people adding their name at the end ++ of the credits. + */ + + #ifndef STBI_INCLUDE_STB_IMAGE_H +@@ -167,6 +179,32 @@ RECENT REVISION HISTORY: + // + // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. + // ++// To query the width, height and component count of an image without having to ++// decode the full file, you can use the stbi_info family of functions: ++// ++// int x,y,n,ok; ++// ok = stbi_info(filename, &x, &y, &n); ++// // returns ok=1 and sets x, y, n if image is a supported format, ++// // 0 otherwise. ++// ++// Note that stb_image pervasively uses ints in its public API for sizes, ++// including sizes of memory buffers. This is now part of the API and thus ++// hard to change without causing breakage. As a result, the various image ++// loaders all have certain limits on image size; these differ somewhat ++// by format but generally boil down to either just under 2GB or just under ++// 1GB. When the decoded image would be larger than this, stb_image decoding ++// will fail. ++// ++// Additionally, stb_image will reject image files that have any of their ++// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, ++// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, ++// the only way to have an image with such dimensions load correctly ++// is for it to have a rather extreme aspect ratio. Either way, the ++// assumption here is that such larger images are likely to be malformed ++// or malicious. If you do need to load an image with individual dimensions ++// larger than that, and it still fits in the overall size limit, you can ++// #define STBI_MAX_DIMENSIONS on your own to be something larger. ++// + // =========================================================================== + // + // UNICODE: +@@ -272,11 +310,10 @@ RECENT REVISION HISTORY: + // + // iPhone PNG support: + // +-// By default we convert iphone-formatted PNGs back to RGB, even though +-// they are internally encoded differently. You can disable this conversion +-// by calling stbi_convert_iphone_png_to_rgb(0), in which case +-// you will always just get the native iphone "format" through (which +-// is BGR stored in RGB). ++// We optionally support converting iPhone-formatted PNGs (which store ++// premultiplied BGRA) back to RGB, even though they're internally encoded ++// differently. To enable this conversion, call ++// stbi_convert_iphone_png_to_rgb(1). + // + // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per + // pixel to remove any premultiplied alpha *only* if the image file explicitly +@@ -318,7 +355,14 @@ RECENT REVISION HISTORY: + // - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still + // want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB + // +- ++// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater ++// than that size (in either width or height) without further processing. ++// This is to let programs in the wild set an upper bound to prevent ++// denial-of-service attacks on untrusted data, as one could generate a ++// valid image of gigantic dimensions and force stb_image to allocate a ++// huge block of memory and spend disproportionate time decoding it. By ++// default this is set to (1 << 24), which is 16777216, but that's still ++// very big. + + #ifndef STBI_NO_STDIO + #include +@@ -473,6 +517,8 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + // as above, but only applies to images loaded on the thread that calls the function + // this function is only available if your compiler supports thread-local variables; + // calling it will fail to link if your compiler doesn't ++STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); ++STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); + STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + + // ZLIB client - used by PNG, available for other purposes +@@ -574,13 +620,19 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch + #ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local +- #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +- #define STBI_THREAD_LOCAL _Thread_local +- #elif defined(__GNUC__) ++ #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) +-#endif ++ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) ++ #define STBI_THREAD_LOCAL _Thread_local ++ #endif ++ ++ #ifndef STBI_THREAD_LOCAL ++ #if defined(__GNUC__) ++ #define STBI_THREAD_LOCAL __thread ++ #endif ++ #endif + #endif + + #ifdef _MSC_VER +@@ -612,7 +664,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + #ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) + #else +- #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) ++ #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) + #endif + + #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +@@ -726,14 +778,21 @@ static int stbi__sse2_available(void) + + #ifdef STBI_NEON + #include +-// assume GCC or Clang on ARM targets ++#ifdef _MSC_VER ++#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name ++#else + #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + #endif ++#endif + + #ifndef STBI_SIMD_ALIGN + #define STBI_SIMD_ALIGN(type, name) type name + #endif + ++#ifndef STBI_MAX_DIMENSIONS ++#define STBI_MAX_DIMENSIONS (1 << 24) ++#endif ++ + /////////////////////////////////////////////// + // + // stbi__context struct and start_xxx functions +@@ -751,6 +810,7 @@ typedef struct + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; ++ int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +@@ -764,6 +824,7 @@ static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) + { + s->io.read = NULL; + s->read_from_callbacks = 0; ++ s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; + } +@@ -775,7 +836,8 @@ static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void * + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; +- s->img_buffer_original = s->buffer_start; ++ s->callback_already_read = 0; ++ s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; + } +@@ -789,12 +851,17 @@ static int stbi__stdio_read(void *user, char *data, int size) + + static void stbi__stdio_skip(void *user, int n) + { ++ int ch; + fseek((FILE*) user, n, SEEK_CUR); ++ ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ ++ if (ch != EOF) { ++ ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ ++ } + } + + static int stbi__stdio_eof(void *user) + { +- return feof((FILE*) user); ++ return feof((FILE*) user) || ferror((FILE *) user); + } + + static stbi_io_callbacks stbi__stdio_callbacks = +@@ -890,6 +957,7 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); + static int stbi__pnm_test(stbi__context *s); + static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); + static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); ++static int stbi__pnm_is16(stbi__context *s); + #endif + + static +@@ -964,7 +1032,7 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add) + } + + // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +-#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) ++#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) + static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) + { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && +@@ -987,7 +1055,7 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add) + return stbi__malloc(a*b*c + add); + } + +-#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) ++#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) + static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) + { + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; +@@ -1053,9 +1121,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + +- #ifndef STBI_NO_JPEG +- if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); +- #endif ++ // test the formats with a very explicit header first (at least a FOURCC ++ // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif +@@ -1073,6 +1140,13 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif ++ ++ // then the formats that can end up attempting to load with just 1 or 2 ++ // bytes matching expectations; these are prone to false positives, so ++ // try them later ++ #ifndef STBI_NO_JPEG ++ if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); ++ #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif +@@ -1171,8 +1245,10 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, + if (result == NULL) + return NULL; + ++ // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. ++ STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); ++ + if (ri.bits_per_channel != 8) { +- STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } +@@ -1195,8 +1271,10 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, + if (result == NULL) + return NULL; + ++ // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. ++ STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); ++ + if (ri.bits_per_channel != 16) { +- STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } +@@ -1224,12 +1302,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in + + #ifndef STBI_NO_STDIO + +-#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) ++#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); + STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + #endif + +-#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) ++#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) + { + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +@@ -1239,16 +1317,16 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch + static FILE *stbi__fopen(char const *filename, char const *mode) + { + FILE *f; +-#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) ++#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; +- if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) ++ if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + +- if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) ++ if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +-#if _MSC_VER >= 1400 ++#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; + #else +@@ -1499,6 +1577,7 @@ enum + static void stbi__refill_buffer(stbi__context *s) + { + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); ++ s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file +@@ -1544,6 +1623,7 @@ stbi_inline static int stbi__at_eof(stbi__context *s) + #else + static void stbi__skip(stbi__context *s, int n) + { ++ if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; +@@ -1622,7 +1702,8 @@ static int stbi__get16le(stbi__context *s) + static stbi__uint32 stbi__get32le(stbi__context *s) + { + stbi__uint32 z = stbi__get16le(s); +- return z + (stbi__get16le(s) << 16); ++ z += (stbi__uint32)stbi__get16le(s) << 16; ++ return z; + } + #endif + +@@ -1690,7 +1771,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; +- default: STBI_ASSERT(0); ++ default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } +@@ -1747,7 +1828,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; +- default: STBI_ASSERT(0); ++ default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } +@@ -2054,13 +2135,12 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) + int sgn; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + +- sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB ++ sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); +- STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; +- return k + (stbi__jbias[n] & ~sgn); ++ return k + (stbi__jbias[n] & (sgn - 1)); + } + + // get some unsigned bits +@@ -2110,7 +2190,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); +- if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); ++ if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); +@@ -2167,11 +2247,12 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); ++ if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; +- data[0] = (short) (dc << j->succ_low); ++ data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) +@@ -2208,7 +2289,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; +- data[zig] = (short) ((r >> 8) << shift); ++ data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); +@@ -2226,7 +2307,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; +- data[zig] = (short) (stbi__extend_receive(j,s) << shift); ++ data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); +@@ -3157,6 +3238,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires ++ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); ++ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; +@@ -3188,6 +3271,13 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + ++ // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios ++ // and I've never seen a non-corrupted JPEG file actually use them ++ for (i=0; i < s->img_n; ++i) { ++ if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); ++ if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); ++ } ++ + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; +@@ -3743,6 +3833,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp + else + decode_n = z->s->img_n; + ++ // nothing to do if no components requested; check this now to avoid ++ // accessing uninitialized coutput[0] later ++ if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } ++ + // resample and color-convert + { + int k; +@@ -3885,6 +3979,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re + { + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); ++ if (!j) return stbi__errpuc("outofmem", "Out of memory"); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); +@@ -3897,6 +3992,7 @@ static int stbi__jpeg_test(stbi__context *s) + { + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); ++ if (!j) return stbi__err("outofmem", "Out of memory"); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); +@@ -3921,6 +4017,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) + { + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); ++ if (!j) return stbi__err("outofmem", "Out of memory"); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); +@@ -3940,6 +4037,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) + // fast-way is faster to check than jpeg huffman, but slow way is slower + #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables + #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) ++#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + + // zlib-style huffman encoding + // (jpegs packs from left, zlib from right, so can't share code) +@@ -3949,8 +4047,8 @@ typedef struct + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; +- stbi_uc size[288]; +- stbi__uint16 value[288]; ++ stbi_uc size[STBI__ZNSYMS]; ++ stbi__uint16 value[STBI__ZNSYMS]; + } stbi__zhuffman; + + stbi_inline static int stbi__bitreverse16(int n) +@@ -4037,16 +4135,23 @@ typedef struct + stbi__zhuffman z_length, z_distance; + } stbi__zbuf; + ++stbi_inline static int stbi__zeof(stbi__zbuf *z) ++{ ++ return (z->zbuffer >= z->zbuffer_end); ++} ++ + stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) + { +- if (z->zbuffer >= z->zbuffer_end) return 0; +- return *z->zbuffer++; ++ return stbi__zeof(z) ? 0 : *z->zbuffer++; + } + + static void stbi__fill_bits(stbi__zbuf *z) + { + do { +- STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); ++ if (z->code_buffer >= (1U << z->num_bits)) { ++ z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ ++ return; ++ } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +@@ -4071,10 +4176,11 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; +- if (s == 16) return -1; // invalid code! ++ if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; +- STBI_ASSERT(z->size[b] == s); ++ if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! ++ if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +@@ -4083,7 +4189,12 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) + stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) + { + int b,s; +- if (a->num_bits < 16) stbi__fill_bits(a); ++ if (a->num_bits < 16) { ++ if (stbi__zeof(a)) { ++ return -1; /* report error for unexpected end of data. */ ++ } ++ stbi__fill_bits(a); ++ } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; +@@ -4097,13 +4208,16 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) + static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes + { + char *q; +- int cur, limit, old_limit; ++ unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); +- cur = (int) (z->zout - z->zout_start); +- limit = old_limit = (int) (z->zout_end - z->zout_start); +- while (cur + n > limit) ++ cur = (unsigned int) (z->zout - z->zout_start); ++ limit = old_limit = (unsigned) (z->zout_end - z->zout_start); ++ if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); ++ while (cur + n > limit) { ++ if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; ++ } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); +@@ -4201,11 +4315,12 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; +- } else if (c == 17) ++ } else if (c == 17) { + c = stbi__zreceive(a,3)+3; +- else { +- STBI_ASSERT(c == 18); ++ } else if (c == 18) { + c = stbi__zreceive(a,7)+11; ++ } else { ++ return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); +@@ -4231,7 +4346,7 @@ static int stbi__parse_uncompressed_block(stbi__zbuf *a) + a->code_buffer >>= 8; + a->num_bits -= 8; + } +- STBI_ASSERT(a->num_bits == 0); ++ if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); +@@ -4253,6 +4368,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); ++ if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png +@@ -4260,7 +4376,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) + return 1; + } + +-static const stbi_uc stbi__zdefault_length[288] = ++static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = + { + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +@@ -4306,7 +4422,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) + } else { + if (type == 1) { + // use fixed code lengths +- if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; ++ if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; +@@ -4514,7 +4630,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { +- STBI_ASSERT(img_width_bytes <= x); ++ if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; +@@ -4702,6 +4818,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); ++ if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; +@@ -4822,19 +4939,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int + return 1; + } + +-static int stbi__unpremultiply_on_load = 0; +-static int stbi__de_iphone_flag = 0; ++static int stbi__unpremultiply_on_load_global = 0; ++static int stbi__de_iphone_flag_global = 0; + + STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) + { +- stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; ++ stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; + } + + STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) + { +- stbi__de_iphone_flag = flag_true_if_should_convert; ++ stbi__de_iphone_flag_global = flag_true_if_should_convert; ++} ++ ++#ifndef STBI_THREAD_LOCAL ++#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global ++#define stbi__de_iphone_flag stbi__de_iphone_flag_global ++#else ++static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; ++static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; ++ ++STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) ++{ ++ stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; ++ stbi__unpremultiply_on_load_set = 1; + } + ++STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) ++{ ++ stbi__de_iphone_flag_local = flag_true_if_should_convert; ++ stbi__de_iphone_flag_set = 1; ++} ++ ++#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ ++ ? stbi__unpremultiply_on_load_local \ ++ : stbi__unpremultiply_on_load_global) ++#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ ++ ? stbi__de_iphone_flag_local \ ++ : stbi__de_iphone_flag_global) ++#endif // STBI_THREAD_LOCAL ++ + static void stbi__de_iphone(stbi__png *z) + { + stbi__context *s = z->s; +@@ -4909,8 +5053,10 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); +- s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); +- s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); ++ s->img_x = stbi__get32be(s); ++ s->img_y = stbi__get32be(s); ++ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); ++ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); +@@ -5059,10 +5205,12 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { +- if (p->depth < 8) ++ if (p->depth <= 8) + ri->bits_per_channel = 8; ++ else if (p->depth == 16) ++ ri->bits_per_channel = 16; + else +- ri->bits_per_channel = p->depth; ++ return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { +@@ -5211,6 +5359,32 @@ typedef struct + int extra_read; + } stbi__bmp_data; + ++static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) ++{ ++ // BI_BITFIELDS specifies masks explicitly, don't override ++ if (compress == 3) ++ return 1; ++ ++ if (compress == 0) { ++ if (info->bpp == 16) { ++ info->mr = 31u << 10; ++ info->mg = 31u << 5; ++ info->mb = 31u << 0; ++ } else if (info->bpp == 32) { ++ info->mr = 0xffu << 16; ++ info->mg = 0xffu << 8; ++ info->mb = 0xffu << 0; ++ info->ma = 0xffu << 24; ++ info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 ++ } else { ++ // otherwise, use defaults, which is all-0 ++ info->mr = info->mg = info->mb = info->ma = 0; ++ } ++ return 1; ++ } ++ return 0; // error ++} ++ + static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) + { + int hsz; +@@ -5223,6 +5397,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + ++ if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); ++ + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); +@@ -5236,6 +5412,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); ++ if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes ++ if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres +@@ -5250,17 +5428,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { +- if (info->bpp == 32) { +- info->mr = 0xffu << 16; +- info->mg = 0xffu << 8; +- info->mb = 0xffu << 0; +- info->ma = 0xffu << 24; +- info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 +- } else { +- info->mr = 31u << 10; +- info->mg = 31u << 5; +- info->mb = 31u << 0; +- } ++ stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); +@@ -5275,6 +5443,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { ++ // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); +@@ -5282,6 +5451,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); ++ if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs ++ stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters +@@ -5314,6 +5485,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + ++ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ + mr = info.mr; + mg = info.mg; + mb = info.mb; +@@ -5328,7 +5502,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { +- STBI_ASSERT(info.offset == (s->img_buffer - s->buffer_start)); ++ if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { ++ return stbi__errpuc("bad offset", "Corrupt BMP"); ++ } + } + + if (info.bpp == 24 && ma == 0xff000000) +@@ -5423,6 +5599,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); ++ if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { +@@ -5647,6 +5824,9 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + ++ if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { +@@ -5686,6 +5866,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req + // do I need to load a palette? + if ( tga_indexed) + { ++ if (tga_palette_len == 0) { /* you have to have at least one entry! */ ++ STBI_FREE(tga_data); ++ return stbi__errpuc("bad palette", "Corrupt TGA"); ++ } ++ + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette +@@ -5894,6 +6079,9 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req + h = stbi__get32be(s); + w = stbi__get32be(s); + ++ if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) +@@ -6248,6 +6436,10 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c + + x = stbi__get16be(s); + y = stbi__get16be(s); ++ ++ if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + +@@ -6257,6 +6449,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); ++ if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { +@@ -6356,6 +6549,9 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in + g->ratio = stbi__get8(s); + g->transparent = -1; + ++ if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); ++ if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); ++ + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; +@@ -6369,6 +6565,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in + static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) + { + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); ++ if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); +@@ -6533,7 +6730,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { +- // second frame - how do we dispoase of the previous one? ++ // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + +@@ -6678,6 +6875,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i + } + } + ++static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) ++{ ++ STBI_FREE(g->out); ++ STBI_FREE(g->history); ++ STBI_FREE(g->background); ++ ++ if (out) STBI_FREE(out); ++ if (delays && *delays) STBI_FREE(*delays); ++ return stbi__errpuc("outofmem", "Out of memory"); ++} ++ + static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) + { + if (stbi__gif_test(s)) { +@@ -6687,6 +6895,12 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, + stbi_uc *two_back = 0; + stbi__gif g; + int stride; ++ int out_size = 0; ++ int delays_size = 0; ++ ++ STBI_NOTUSED(out_size); ++ STBI_NOTUSED(delays_size); ++ + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; +@@ -6703,22 +6917,31 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, + stride = g.w * g.h * 4; + + if (out) { +- void *tmp = (stbi_uc*) STBI_REALLOC( out, layers * stride ); +- if (NULL == tmp) { +- STBI_FREE(g.out); +- STBI_FREE(g.history); +- STBI_FREE(g.background); +- return stbi__errpuc("outofmem", "Out of memory"); ++ void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); ++ if (!tmp) ++ return stbi__load_gif_main_outofmem(&g, out, delays); ++ else { ++ out = (stbi_uc*) tmp; ++ out_size = layers * stride; + } +- else +- out = (stbi_uc*) tmp; ++ + if (delays) { +- *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); ++ int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); ++ if (!new_delays) ++ return stbi__load_gif_main_outofmem(&g, out, delays); ++ *delays = new_delays; ++ delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); ++ if (!out) ++ return stbi__load_gif_main_outofmem(&g, out, delays); ++ out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); ++ if (!*delays) ++ return stbi__load_gif_main_outofmem(&g, out, delays); ++ delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); +@@ -6897,6 +7120,9 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re + token += 3; + width = (int) strtol(token, NULL, 10); + ++ if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); ++ if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); ++ + *x = width; + *y = height; + +@@ -7039,9 +7265,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); +- stbi__rewind( s ); +- if (p == NULL) ++ if (p == NULL) { ++ stbi__rewind( s ); + return 0; ++ } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { +@@ -7107,8 +7334,8 @@ static int stbi__psd_is16(stbi__context *s) + stbi__rewind( s ); + return 0; + } +- (void) stbi__get32be(s); +- (void) stbi__get32be(s); ++ STBI_NOTUSED(stbi__get32be(s)); ++ STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); +@@ -7187,7 +7414,6 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) + // Known limitations: + // Does not support comments in the header section + // Does not support ASCII image data (formats P2 and P3) +-// Does not support 16-bit-per-channel + + #ifndef STBI_NO_PNM + +@@ -7208,19 +7434,23 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req + stbi_uc *out; + STBI_NOTUSED(ri); + +- if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) ++ ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); ++ if (ri->bits_per_channel == 0) + return 0; + ++ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); ++ + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + +- if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) ++ if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + +- out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); ++ out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); +- stbi__getn(s, out, s->img_n * s->img_x * s->img_y); ++ stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); +@@ -7296,11 +7526,19 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value +- +- if (maxv > 255) +- return stbi__err("max value > 255", "PPM image not 8-bit"); ++ if (maxv > 65535) ++ return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); ++ else if (maxv > 255) ++ return 16; + else +- return 1; ++ return 8; ++} ++ ++static int stbi__pnm_is16(stbi__context *s) ++{ ++ if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) ++ return 1; ++ return 0; + } + #endif + +@@ -7356,6 +7594,9 @@ static int stbi__is_16_main(stbi__context *s) + if (stbi__psd_is16(s)) return 1; + #endif + ++ #ifndef STBI_NO_PNM ++ if (stbi__pnm_is16(s)) return 1; ++ #endif + return 0; + } + +diff --git a/thirdparty/stb/stb_image.patch b/thirdparty/stb/stb_image.patch +index 51537287..f1fee52a 100644 +--- a/thirdparty/stb/stb_image.patch ++++ b/thirdparty/stb/stb_image.patch +@@ -1,7 +1,7 @@ + diff -Naur upstream/stb_image.h zxing/stb_image.h +---- upstream/stb_image.h 2021-12-08 18:11:28.170529096 -0500 +-+++ zxing/stb_image.h 2021-12-08 18:06:42.706717697 -0500 +-@@ -1644,7 +1644,11 @@ ++--- upstream/stb_image.h 2021-12-08 18:18:07.485461782 -0500 +++++ zxing/stb_image.h 2021-12-08 18:18:29.596689004 -0500 ++@@ -1725,7 +1725,11 @@ + + static stbi_uc stbi__compute_y(int r, int g, int b) + { + +From 5ca63122c53fa0703cad9a8257f123a1ca4c43b1 Mon Sep 17 00:00:00 2001 +From: "Benjamin A. Beasley" +Date: Wed, 8 Dec 2021 18:24:31 -0500 +Subject: [PATCH 4/4] Apply stb PR#1223 to stb_image + +Fixes a crash and an infinite loop in stb_image that could occur with +specially constructed PGM and HDR files + +https://github.com/nothings/stb/pull/1223 + +This is a candidate fix for: + + https://nvd.nist.gov/vuln/detail/CVE-2021-42715 + + In stb_image's HDR reader, loading a specially constructed invalid HDR + file can result in an infinite loop within the RLE decoder + https://github.com/nothings/stb/issues/1224 + +Additionally, this is a candidate fix for: + + https://nvd.nist.gov/vuln/detail/CVE-2021-42716 + + stbi__pnm_load heap-buffer-overflow bug + https://github.com/nothings/stb/issues/1166 + + In stb_image's PNM reader, loading a specially constructed valid + 16-bit PGM file with 4 channels can cause a crash due to an + out-of-bounds read + https://github.com/nothings/stb/issues/1225 +--- + thirdparty/stb/stb_image.h | 17 ++++++++++++----- + thirdparty/stb/stb_image.patch | 4 ++-- + 2 files changed, 14 insertions(+), 7 deletions(-) + +diff --git a/thirdparty/stb/stb_image.h b/thirdparty/stb/stb_image.h +index c58bc0c5..612bc4c1 100644 +--- a/thirdparty/stb/stb_image.h ++++ b/thirdparty/stb/stb_image.h +@@ -108,7 +108,7 @@ RECENT REVISION HISTORY: + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus +- Josh Tobin Matthew Gregan github:poppolopoppo ++ Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra +@@ -7191,12 +7191,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re + // Run + value = stbi__get8(s); + count -= 128; +- if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } ++ if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump +- if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } ++ if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } +@@ -7450,10 +7450,17 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); +- stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); ++ if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { ++ STBI_FREE(out); ++ return stbi__errpuc("bad PNM", "PNM file truncated"); ++ } + + if (req_comp && req_comp != s->img_n) { +- out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); ++ if (ri->bits_per_channel == 16) { ++ out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); ++ } else { ++ out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); ++ } + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +diff --git a/thirdparty/stb/stb_image.patch b/thirdparty/stb/stb_image.patch +index f1fee52a..1768ba86 100644 +--- a/thirdparty/stb/stb_image.patch ++++ b/thirdparty/stb/stb_image.patch +@@ -1,6 +1,6 @@ + diff -Naur upstream/stb_image.h zxing/stb_image.h +---- upstream/stb_image.h 2021-12-08 18:18:07.485461782 -0500 +-+++ zxing/stb_image.h 2021-12-08 18:18:29.596689004 -0500 ++--- upstream/stb_image.h 2021-12-08 18:22:56.724466161 -0500 +++++ zxing/stb_image.h 2021-12-08 18:23:15.084657043 -0500 + @@ -1725,7 +1725,11 @@ + + static stbi_uc stbi__compute_y(int r, int g, int b) diff --git a/sources b/sources new file mode 100644 index 0000000..f4bc8fd --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (zxing-cpp-1.2.0.tar.gz) = e61b4e44ccaf0871b5d8badf9ce0a81576f55e5d6a9458907b9b599a66227adceabb8d51a0c47b32319d8aeff93e758b4785d3bd0440375247471d95999de487 diff --git a/zxing-cpp.spec b/zxing-cpp.spec new file mode 100644 index 0000000..aac107e --- /dev/null +++ b/zxing-cpp.spec @@ -0,0 +1,94 @@ +Name: zxing-cpp +Version: 1.2.0 +Release: 1%{?dist} +Summary: C++ port of the ZXing ("Zebra Crossing") barcode scanning library + +# The entire source is ASL 2.0, except: +# +# - TextCodec files, that is, core/src/textcodec/*, are +# (LGPLv2 with exceptions or LGPLv3 with exceptions). +# - core/src/textcodec/JPText{En,De}coder.* are, formally, +# ((LGPLv2 with exceptions or LGPLv3 with exceptions) and BSD), +# which still forms an effective license of +# (LGPLv2 with exceptions or LGPLv3 with exceptions) +# - wrappers/wasm/base64ArrayBuffer.js is MIT (but is not used) +# - thirdparty/stb/stb_image.h and thirdparty/stb/stb_image_write.h are MIT +# (but are unbundled) +# +# The resulting effective license for the combined library is: +License: LGPLv2 with exceptions or LGPLv3 with exceptions +Url: https://github.com/nu-book/zxing-cpp +Source0: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz + +BuildRequires: gcc-c++ +BuildRequires: cmake +BuildRequires: cmake(fmt) +# -static BR’s required by guidelines for tracking of header-only libraries: +BuildRequires: stb_image-devel +BuildRequires: stb_image-static +BuildRequires: stb_image_write-devel +BuildRequires: stb_image_write-static +# https://github.com/nu-book/zxing-cpp/issues/248 +Patch0: 0001-Add-a-mode-to-build-against-system-versions-of-depen.patch +# Update stb_image/stb_image_write +# https://github.com/nu-book/zxing-cpp/pull/269 +# Fixes CVE-2021-28021, CVE-2021-42715, and CVE-2021-42716, and adds a patch +# file for zxing-cpp-specific changes +Patch1: %{url}/pull/269.patch + +%description +ZXing-C++ ("zebra crossing") is an open-source, multi-format 1D/2D barcode +image processing library implemented in C++. + +%package devel +# The entire contents are ASL 2.0, except: +# +# - %%{_includedir}/ZXing/textcodec/*.h are exactly or effectively +# (LGPLv2 with exceptions or LGPLv3 with exceptions) +# +# See licensing breakdown above base package’s License field for further +# details. +License: ASL 2.0 and (LGPLv2 with exceptions or LGPLv3 with exceptions) +Summary: Development files for %{name} +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + +%prep +%autosetup -p1 +# remove bundled stb libraries: +rm -v thirdparty/stb/stb_image_write.h thirdparty/stb/stb_image.h +# stb_image.h is trivially forked: reconstruct the changes with the latest +# unbundled copy +cp -p %{_includedir}/stb/stb_image.h thirdparty/stb/ +pushd thirdparty/stb +patch -p1 < stb_image.patch +popd + +%build +%cmake -DBUILD_EXAMPLES=OFF +%cmake_build + +%install +%cmake_install + +%check +%ctest + +%files +%license LICENSE LICENSE.ZXing LICENSE.Qt LGPL_EXCEPTION.Qt NOTICE +%{_libdir}/libZXing.so.1 +%{_libdir}/libZXing.so.%{version} + +%files devel +%doc README.md +%{_includedir}/ZXing/ +%{_libdir}/libZXing.so +%{_libdir}/cmake/ZXing/ +%{_libdir}/pkgconfig/zxing.pc + +%changelog +* Fri Dec 10 2021 Caolán McNamara 1.2.0-1 +- initial import