Merge branch '2.6.x' into master

This commit is contained in:
Lukas Dürrenberger 2023-04-02 00:30:16 +02:00 committed by GitHub
commit d500eee682
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 268 additions and 89 deletions

View File

@ -43,6 +43,7 @@ configure_file(${DOXYGEN_INPUT_DIR}/doc/header.html.in ${DOXYGEN_OUTPUT_DIR}/hea
# copy the files needed by the documentation # copy the files needed by the documentation
configure_file(${DOXYGEN_INPUT_DIR}/doc/doxygen.css ${DOXYGEN_OUTPUT_DIR}/html/doxygen.css COPYONLY) configure_file(${DOXYGEN_INPUT_DIR}/doc/doxygen.css ${DOXYGEN_OUTPUT_DIR}/html/doxygen.css COPYONLY)
configure_file(${DOXYGEN_INPUT_DIR}/doc/searchOverrides.css ${DOXYGEN_OUTPUT_DIR}/html/searchOverrides.css COPYONLY)
# target setup # target setup
add_custom_target(doc add_custom_target(doc

View File

@ -1,4 +1,4 @@
# Doxyfile 1.9.4 # Doxyfile 1.9.6
# This file describes the settings to be used by the documentation system # This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project. # doxygen (www.doxygen.org) for a project.
@ -19,7 +19,8 @@
# configuration file: # configuration file:
# doxygen -x [configFile] # doxygen -x [configFile]
# Use doxygen to compare the used configuration file with the template # Use doxygen to compare the used configuration file with the template
# configuration file without replacing the environment variables: # configuration file without replacing the environment variables or CMake type
# replacement variables:
# doxygen -x_noenv [configFile] # doxygen -x_noenv [configFile]
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -85,7 +86,7 @@ CREATE_SUBDIRS = NO
# level increment doubles the number of directories, resulting in 4096 # level increment doubles the number of directories, resulting in 4096
# directories at level 8 which is the default and also the maximum value. The # directories at level 8 which is the default and also the maximum value. The
# sub-directories are organized in 2 levels, the first level always has a fixed # sub-directories are organized in 2 levels, the first level always has a fixed
# numer of 16 directories. # number of 16 directories.
# Minimum value: 0, maximum value: 8, default value: 8. # Minimum value: 0, maximum value: 8, default value: 8.
# This tag requires that the tag CREATE_SUBDIRS is set to YES. # This tag requires that the tag CREATE_SUBDIRS is set to YES.
@ -584,7 +585,8 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set # undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option # to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled. # will also hide undocumented C++ concepts if enabled. This option has no effect
# if EXTRACT_ALL is enabled.
# The default value is: NO. # The default value is: NO.
HIDE_UNDOC_CLASSES = NO HIDE_UNDOC_CLASSES = NO
@ -622,7 +624,8 @@ INTERNAL_DOCS = NO
# Windows (including Cygwin) and MacOS, users should typically set this option # Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to # to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES. # YES.
# The default value is: system dependent. # Possible values are: SYSTEM, NO and YES.
# The default value is: SYSTEM.
CASE_SENSE_NAMES = YES CASE_SENSE_NAMES = YES
@ -874,6 +877,14 @@ WARN_IF_INCOMPLETE_DOC = YES
WARN_NO_PARAMDOC = YES WARN_NO_PARAMDOC = YES
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
# undocumented enumeration values. If set to NO, doxygen will accept
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: NO.
WARN_IF_UNDOC_ENUM_VAL = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
@ -931,10 +942,21 @@ INPUT = "@DOXYGEN_INPUT_DIR@/include/SFML" \
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv # libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: # documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings. # https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# See also: INPUT_FILE_ENCODING
# The default value is: UTF-8. # The default value is: UTF-8.
INPUT_ENCODING = UTF-8 INPUT_ENCODING = UTF-8
# This tag can be used to specify the character encoding of the source files
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
# character encoding on a per file pattern basis. Doxygen will compare the file
# name with each pattern and apply the encoding instead of the default
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
# "INPUT_ENCODING" for further information on supported encodings.
INPUT_FILE_ENCODING =
# If the value of the INPUT tag contains directories, you can use the # If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories. # *.h) to filter out the source-files in the directories.
@ -1045,6 +1067,11 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added # code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly. # or removed, the anchors will not be placed correctly.
# #
# Note that doxygen will use the data processed and written to standard output
# for further processing, therefore nothing else, like debug statements or used
# commands (so in case of a Windows batch file always use @echo OFF), should be
# written to standard output.
#
# Note that for custom extensions or not directly supported extensions you also # Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not # need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen. # properly processed by doxygen.
@ -1086,6 +1113,15 @@ FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE = USE_MDFILE_AS_MAINPAGE =
# The Fortran standard specifies that for fixed formatted Fortran code all
# characters from position 72 are to be considered as comment. A common
# extension is to allow longer lines before the automatic comment starts. The
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
# be processed before the automatic comment starts.
# Minimum value: 7, maximum value: 10000, default value: 72.
FORTRAN_COMMENT_AFTER = 72
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to source browsing # Configuration options related to source browsing
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -1223,10 +1259,11 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES ALPHABETICAL_INDEX = YES
# In case all classes in a project start with a common prefix, all classes will # The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # that should be ignored while generating the index headers. The IGNORE_PREFIX
# can be used to specify a prefix (or a list of prefixes) that should be ignored # tag works for classes, function and member names. The entity will be placed in
# while generating the index headers. # the alphabetical list under the first letter of the entity name that remains
# after removing the prefix.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX = IGNORE_PREFIX =
@ -1305,7 +1342,12 @@ HTML_STYLESHEET = "@DOXYGEN_INPUT_DIR@/doc/doxygen.css"
# Doxygen will copy the style sheet files to the output directory. # Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last # Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the # style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation. # list).
# Note: Since the styling of scrollbars can currently not be overruled in
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
# one or more extra stylesheets have been specified. So if scrollbar
# customization is desired it has to be added explicitly. For an example see the
# documentation.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET = HTML_EXTRA_STYLESHEET =
@ -1320,6 +1362,19 @@ HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES = HTML_EXTRA_FILES =
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
# should be rendered with a dark or light theme.
# Possible values are: LIGHT always generate light mode output, DARK always
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
# the user preference, use light mode if no preference is set (the default),
# AUTO_DARK automatically set the mode according to the user preference, use
# dark mode if no preference is set and TOGGLE allow to user to switch between
# light and dark mode via a button.
# The default value is: AUTO_LIGHT.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE = LIGHT
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to # will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a color-wheel, see # this color. Hue is specified as an angle on a color-wheel, see
@ -1683,17 +1738,6 @@ HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10 FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See # to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details. # the section "Including formulas" for details.
@ -1755,8 +1799,8 @@ MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example # extension names that should be enabled during MathJax rendering. For example
# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html # for MathJax version 2 (see
# #tex-and-latex-extensions): # https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# For example for MathJax version 3 (see # For example for MathJax version 3 (see
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): # http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
@ -2210,6 +2254,10 @@ DOCBOOK_OUTPUT = docbook
GENERATE_AUTOGEN_DEF = NO GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to Sqlite3 output
#---------------------------------------------------------------------------
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the Perl module output # Configuration options related to the Perl module output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -2414,26 +2462,38 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0 DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen # DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
# generates you can specify the font name using DOT_FONTNAME. You need to make # subgraphs. When you want a differently looking font in the dot files that
# sure dot is able to find the font, which can be done by putting it in a # doxygen generates you can specify fontname, fontcolor and fontsize attributes.
# standard location or by setting the DOTFONTPATH environment variable or by # For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
# setting DOT_FONTPATH to the directory containing the font. # Edge and Graph Attributes specification</a> You need to make sure dot is able
# The default value is: Helvetica. # to find the font, which can be done by putting it in a standard location or by
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font. Default graphviz fontsize is 14.
# The default value is: fontname=Helvetica,fontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of # DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
# dot graphs. # add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
# Minimum value: 4, maximum value: 24, default value: 10. # href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
# arrows shapes.</a>
# The default value is: labelfontname=Helvetica,labelfontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10 DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
# By default doxygen will tell dot to use the default font as specified with # DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # around nodes set 'shape=plain' or 'shape=plaintext' <a
# the path where dot can find it using this tag. # href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
# The default value is: shape=box,height=0.2,width=0.4.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
# You can set the path where dot can find font specified with fontname in
# DOT_COMMON_ATTR and others dot attributes.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH = DOT_FONTPATH =
@ -2676,18 +2736,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0 MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This # files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support # makes dot run faster, but since only newer versions of dot (>1.8.10) support

View File

@ -7,18 +7,8 @@
<link rel="stylesheet" type="text/css" href="doxygen.css" title="default" media="screen,print" /> <link rel="stylesheet" type="text/css" href="doxygen.css" title="default" media="screen,print" />
<script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script> <script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/> <link rel="stylesheet" type="text/css" href="search/search.css" />
<style> <link rel="stylesheet" type="text/css" href="searchOverrides.css" />
/* Override search/search.css rules to adjust seach box placement */
#MSearchBox {
position: relative;
display: block;
}
.right #MSearchClose {
margin: 0;
right: auto;
}
</style>
<script type="text/javascript" src="search/searchdata.js"></script> <script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script> <script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript"> <script type="text/javascript">

45
doc/searchOverrides.css Normal file
View File

@ -0,0 +1,45 @@
/* Override search/search.css rules to adjust seach box placement */
#MSearchBox {
position: relative;
display: block;
border-radius: 0;
box-shadow: none;
border-width: 1px;
border-color: #BBB;
border-style: solid;
}
.right #MSearchClose {
margin: 0;
right: auto;
}
#MSearchResultsWindow {
background-color: #EAF5DB;
border-color: #999;
}
#MSearchResults > .SRPage {
background-color: #EAF5DB;
}
a.SRSymbol {
color: rgb(70, 100, 30);
}
a.SRSymbol:hover {
text-decoration: underline;
}
a.SRScope {
color: rgb(70, 100, 30);
}
a.SRScope:hover {
text-decoration: underline;
}
#MSearchSelectWindow {
background-color: #EAF5DB;
}
#MSearchSelectWindow > a.SelectItem {
color: #333;
text-decoration: none;
}
#MSearchSelectWindow > a.SelectItem:hover {
color: white;
background-color: #8CC841;
text-decoration: none;
}

View File

@ -1,4 +1,4 @@
/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb /* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk no warranty implied; use at your own risk
Do this: Do this:
@ -48,6 +48,7 @@ LICENSE
RECENT REVISION HISTORY: RECENT REVISION HISTORY:
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
2.26 (2020-07-13) many minor fixes 2.26 (2020-07-13) many minor fixes
2.25 (2020-02-02) fix warnings 2.25 (2020-02-02) fix warnings
@ -108,7 +109,7 @@ RECENT REVISION HISTORY:
Cass Everitt Ryamond Barbiero github:grim210 Cass Everitt Ryamond Barbiero github:grim210
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus 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 Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
Brad Weinberger Matvey Cherevko github:mosra Brad Weinberger Matvey Cherevko github:mosra
@ -140,7 +141,7 @@ RECENT REVISION HISTORY:
// // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... x = width, y = height, n = # 8-bit components per pixel ...
// // ... replace '0' with '1'..'4' to force that many components per pixel // // ... replace '0' with '1'..'4' to force that many components per pixel
// // ... but 'n' will always be the number that it would have been if you said 0 // // ... but 'n' will always be the number that it would have been if you said 0
// stbi_image_free(data) // stbi_image_free(data);
// //
// Standard parameters: // Standard parameters:
// int *x -- outputs image width in pixels // int *x -- outputs image width in pixels
@ -635,7 +636,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#endif #endif
#endif #endif
#ifdef _MSC_VER #if defined(_MSC_VER) || defined(__SYMBIAN32__)
typedef unsigned short stbi__uint16; typedef unsigned short stbi__uint16;
typedef signed short stbi__int16; typedef signed short stbi__int16;
typedef unsigned int stbi__uint32; typedef unsigned int stbi__uint32;
@ -1063,6 +1064,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
} }
#endif #endif
// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow.
static int stbi__addints_valid(int a, int b)
{
if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow
if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0.
return a <= INT_MAX - b;
}
// returns 1 if the product of two signed shorts is valid, 0 on overflow.
static int stbi__mul2shorts_valid(short a, short b)
{
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN
return a >= SHRT_MIN / b;
}
// stbi__err - error // stbi__err - error
// stbi__errpf - error returning pointer to float // stbi__errpf - error returning pointer to float
// stbi__errpuc - error returning pointer to unsigned char // stbi__errpuc - error returning pointer to unsigned char
@ -1985,9 +2003,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count)
int i,j,k=0; int i,j,k=0;
unsigned int code; unsigned int code;
// build size list for each symbol (from JPEG spec) // build size list for each symbol (from JPEG spec)
for (i=0; i < 16; ++i) for (i=0; i < 16; ++i) {
for (j=0; j < count[i]; ++j) for (j=0; j < count[i]; ++j) {
h->size[k++] = (stbi_uc) (i+1); h->size[k++] = (stbi_uc) (i+1);
if(k >= 257) return stbi__err("bad size list","Corrupt JPEG");
}
}
h->size[k] = 0; h->size[k] = 0;
// compute actual symbols (from jpeg spec) // compute actual symbols (from jpeg spec)
@ -2112,6 +2133,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
// convert the huffman code to the symbol id // convert the huffman code to the symbol id
c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
if(c < 0 || c >= 256) // symbol id out of bounds!
return -1;
STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
// convert the id to a symbol // convert the id to a symbol
@ -2130,6 +2153,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
unsigned int k; unsigned int k;
int sgn; int sgn;
if (j->code_bits < n) stbi__grow_buffer_unsafe(j); if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing
sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) 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); k = stbi_lrot(j->code_buffer, n);
@ -2144,6 +2168,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
{ {
unsigned int k; unsigned int k;
if (j->code_bits < n) stbi__grow_buffer_unsafe(j); if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing
k = stbi_lrot(j->code_buffer, n); k = stbi_lrot(j->code_buffer, n);
j->code_buffer = k & ~stbi__bmask[n]; j->code_buffer = k & ~stbi__bmask[n];
k &= stbi__bmask[n]; k &= stbi__bmask[n];
@ -2155,6 +2180,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
{ {
unsigned int k; unsigned int k;
if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing
k = j->code_buffer; k = j->code_buffer;
j->code_buffer <<= 1; j->code_buffer <<= 1;
--j->code_bits; --j->code_bits;
@ -2192,8 +2218,10 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
memset(data,0,64*sizeof(data[0])); memset(data,0,64*sizeof(data[0]));
diff = t ? stbi__extend_receive(j, t) : 0; diff = t ? stbi__extend_receive(j, t) : 0;
if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG");
dc = j->img_comp[b].dc_pred + diff; dc = j->img_comp[b].dc_pred + diff;
j->img_comp[b].dc_pred = dc; j->img_comp[b].dc_pred = dc;
if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
data[0] = (short) (dc * dequant[0]); data[0] = (short) (dc * dequant[0]);
// decode AC components, see JPEG spec // decode AC components, see JPEG spec
@ -2207,6 +2235,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
if (r) { // fast-AC path if (r) { // fast-AC path
k += (r >> 4) & 15; // run k += (r >> 4) & 15; // run
s = r & 15; // combined length s = r & 15; // combined length
if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available");
j->code_buffer <<= s; j->code_buffer <<= s;
j->code_bits -= s; j->code_bits -= s;
// decode into unzigzag'd location // decode into unzigzag'd location
@ -2246,8 +2275,10 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__
if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
diff = t ? stbi__extend_receive(j, t) : 0; diff = t ? stbi__extend_receive(j, t) : 0;
if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG");
dc = j->img_comp[b].dc_pred + diff; dc = j->img_comp[b].dc_pred + diff;
j->img_comp[b].dc_pred = dc; j->img_comp[b].dc_pred = dc;
if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
data[0] = (short) (dc * (1 << j->succ_low)); data[0] = (short) (dc * (1 << j->succ_low));
} else { } else {
// refinement scan for DC coefficient // refinement scan for DC coefficient
@ -2282,6 +2313,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
if (r) { // fast-AC path if (r) { // fast-AC path
k += (r >> 4) & 15; // run k += (r >> 4) & 15; // run
s = r & 15; // combined length s = r & 15; // combined length
if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available");
j->code_buffer <<= s; j->code_buffer <<= s;
j->code_bits -= s; j->code_bits -= s;
zig = stbi__jpeg_dezigzag[k++]; zig = stbi__jpeg_dezigzag[k++];
@ -3102,6 +3134,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m)
sizes[i] = stbi__get8(z->s); sizes[i] = stbi__get8(z->s);
n += sizes[i]; n += sizes[i];
} }
if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values!
L -= 17; L -= 17;
if (tc == 0) { if (tc == 0) {
if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
@ -3351,6 +3384,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
return 1; return 1;
} }
static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
{
// some JPEGs have junk at end, skip over it but if we find what looks
// like a valid marker, resume there
while (!stbi__at_eof(j->s)) {
int x = stbi__get8(j->s);
while (x == 255) { // might be a marker
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
x = stbi__get8(j->s);
if (x != 0x00 && x != 0xff) {
// not a stuffed zero or lead-in to another marker, looks
// like an actual marker, return it
return x;
}
// stuffed zero has x=0 now which ends the loop, meaning we go
// back to regular scan loop.
// repeated 0xff keeps trying to read the next byte of the marker.
}
}
return STBI__MARKER_none;
}
// decode image to YCbCr format // decode image to YCbCr format
static int stbi__decode_jpeg_image(stbi__jpeg *j) static int stbi__decode_jpeg_image(stbi__jpeg *j)
{ {
@ -3367,25 +3422,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
if (!stbi__process_scan_header(j)) return 0; if (!stbi__process_scan_header(j)) return 0;
if (!stbi__parse_entropy_coded_data(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0;
if (j->marker == STBI__MARKER_none ) { if (j->marker == STBI__MARKER_none ) {
// handle 0s at the end of image data from IP Kamera 9060 j->marker = stbi__skip_jpeg_junk_at_end(j);
while (!stbi__at_eof(j->s)) {
int x = stbi__get8(j->s);
if (x == 255) {
j->marker = stbi__get8(j->s);
break;
}
}
// if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
} }
m = stbi__get_marker(j);
if (STBI__RESTART(m))
m = stbi__get_marker(j);
} else if (stbi__DNL(m)) { } else if (stbi__DNL(m)) {
int Ld = stbi__get16be(j->s); int Ld = stbi__get16be(j->s);
stbi__uint32 NL = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s);
if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
m = stbi__get_marker(j);
} else { } else {
if (!stbi__process_marker(j, m)) return 0; if (!stbi__process_marker(j, m)) return 1;
m = stbi__get_marker(j);
} }
m = stbi__get_marker(j);
} }
if (j->progressive) if (j->progressive)
stbi__jpeg_finish(j); stbi__jpeg_finish(j);
@ -3976,6 +4028,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re
unsigned char* result; unsigned char* result;
stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
if (!j) return stbi__errpuc("outofmem", "Out of memory"); if (!j) return stbi__errpuc("outofmem", "Out of memory");
memset(j, 0, sizeof(stbi__jpeg));
STBI_NOTUSED(ri); STBI_NOTUSED(ri);
j->s = s; j->s = s;
stbi__setup_jpeg(j); stbi__setup_jpeg(j);
@ -3989,6 +4042,7 @@ static int stbi__jpeg_test(stbi__context *s)
int r; int r;
stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
if (!j) return stbi__err("outofmem", "Out of memory"); if (!j) return stbi__err("outofmem", "Out of memory");
memset(j, 0, sizeof(stbi__jpeg));
j->s = s; j->s = s;
stbi__setup_jpeg(j); stbi__setup_jpeg(j);
r = stbi__decode_jpeg_header(j, STBI__SCAN_type); r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
@ -4014,6 +4068,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
int result; int result;
stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
if (!j) return stbi__err("outofmem", "Out of memory"); if (!j) return stbi__err("outofmem", "Out of memory");
memset(j, 0, sizeof(stbi__jpeg));
j->s = s; j->s = s;
result = stbi__jpeg_info_raw(j, x, y, comp); result = stbi__jpeg_info_raw(j, x, y, comp);
STBI_FREE(j); STBI_FREE(j);
@ -4256,11 +4311,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
a->zout = zout; a->zout = zout;
return 1; return 1;
} }
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
z -= 257; z -= 257;
len = stbi__zlength_base[z]; len = stbi__zlength_base[z];
if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
z = stbi__zhuffman_decode(a, &a->z_distance); z = stbi__zhuffman_decode(a, &a->z_distance);
if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data
dist = stbi__zdist_base[z]; dist = stbi__zdist_base[z];
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
@ -4955,7 +5011,7 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; 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; 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) STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
{ {
stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;
stbi__unpremultiply_on_load_set = 1; stbi__unpremultiply_on_load_set = 1;
@ -5064,14 +5120,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (!pal_img_n) { if (!pal_img_n) {
s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
if (scan == STBI__SCAN_header) return 1;
} else { } else {
// if paletted, then pal_n is our final components, and // if paletted, then pal_n is our final components, and
// img_n is # components to decompress/filter. // img_n is # components to decompress/filter.
s->img_n = 1; s->img_n = 1;
if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
// if SCAN_header, have to scan to see if we have a tRNS
} }
// even with SCAN_header, have to scan to see if we have a tRNS
break; break;
} }
@ -5103,6 +5158,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
has_trans = 1; has_trans = 1;
// non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
if (z->depth == 16) { if (z->depth == 16) {
for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
} else { } else {
@ -5115,7 +5172,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
case STBI__PNG_TYPE('I','D','A','T'): { case STBI__PNG_TYPE('I','D','A','T'): {
if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (first) return stbi__err("first not IHDR", "Corrupt PNG");
if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } if (scan == STBI__SCAN_header) {
// header scan definitely stops at first IDAT
if (pal_img_n)
s->img_n = pal_img_n;
return 1;
}
if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes");
if ((int)(ioff + c.length) < (int)ioff) return 0; if ((int)(ioff + c.length) < (int)ioff) return 0;
if (ioff + c.length > idata_limit) { if (ioff + c.length > idata_limit) {
stbi__uint32 idata_limit_old = idata_limit; stbi__uint32 idata_limit_old = idata_limit;
@ -5498,8 +5561,22 @@ 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; psize = (info.offset - info.extra_read - info.hsz) >> 2;
} }
if (psize == 0) { if (psize == 0) {
if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { // accept some number of extra bytes after the header, but if the offset points either to before
return stbi__errpuc("bad offset", "Corrupt BMP"); // the header ends or implies a large amount of extra data, reject the file as malformed
int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original);
int header_limit = 1024; // max we actually read is below 256 bytes currently.
int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size.
if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) {
return stbi__errpuc("bad header", "Corrupt BMP");
}
// we established that bytes_read_so_far is positive and sensible.
// the first half of this test rejects offsets that are either too small positives, or
// negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn
// ensures the number computed in the second half of the test can't overflow.
if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) {
return stbi__errpuc("bad offset", "Corrupt BMP");
} else {
stbi__skip(s, info.offset - bytes_read_so_far);
} }
} }
@ -7187,12 +7264,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
// Run // Run
value = stbi__get8(s); value = stbi__get8(s);
count -= 128; 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) for (z = 0; z < count; ++z)
scanline[i++ * 4 + k] = value; scanline[i++ * 4 + k] = value;
} else { } else {
// Dump // 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) for (z = 0; z < count; ++z)
scanline[i++ * 4 + k] = stbi__get8(s); scanline[i++ * 4 + k] = stbi__get8(s);
} }
@ -7446,10 +7523,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); 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"); 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) { 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 if (out == NULL) return out; // stbi__convert_format frees input on failure
} }
return out; return out;
@ -7486,6 +7570,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c)
while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
value = value*10 + (*c - '0'); value = value*10 + (*c - '0');
*c = (char) stbi__get8(s); *c = (char) stbi__get8(s);
if((value > 214748364) || (value == 214748364 && *c > '7'))
return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int");
} }
return value; return value;
@ -7516,9 +7602,13 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
stbi__pnm_skip_whitespace(s, &c); stbi__pnm_skip_whitespace(s, &c);
*x = stbi__pnm_getinteger(s, &c); // read width *x = stbi__pnm_getinteger(s, &c); // read width
if(*x == 0)
return stbi__err("invalid width", "PPM image header had zero or overflowing width");
stbi__pnm_skip_whitespace(s, &c); stbi__pnm_skip_whitespace(s, &c);
*y = stbi__pnm_getinteger(s, &c); // read height *y = stbi__pnm_getinteger(s, &c); // read height
if (*y == 0)
return stbi__err("invalid width", "PPM image header had zero or overflowing width");
stbi__pnm_skip_whitespace(s, &c); stbi__pnm_skip_whitespace(s, &c);
maxv = stbi__pnm_getinteger(s, &c); // read max value maxv = stbi__pnm_getinteger(s, &c); // read max value

View File

@ -34,12 +34,17 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4242 4244 4267 4456 4706) #pragma warning(disable : 4242 4244 4267 4456 4706)
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif #endif
#include <minimp3_ex.h> #include <minimp3_ex.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#else
#pragma GCC diagnostic pop
#endif #endif
#undef NOMINMAX #undef NOMINMAX