Update libjpeg-turbo to upstream stable release 2.1.3

This release consists mostly of bug fixes and changes to make the
codebase comply with the various C standards.

There is also a very modest improvement to AArch64 Neon Huffman
encoding performance.

Change-Id: I21aa2dcb0f80a8095b77eb07b34e8ee02f9fb55d
diff --git a/BUILD.gn b/BUILD.gn
index 428cc1f..5acf523 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -249,6 +249,7 @@
   defines = [
     "WITH_SIMD",
     "NO_GETENV",
+    "NO_PUTENV",
   ]
 
   configs += [ ":libjpeg_config" ]
@@ -343,5 +344,9 @@
 
     configs -= [ "//build/config/compiler:chromium_code" ]
     configs += [ "//build/config/compiler:no_chromium_code" ]
+
+    if (is_win) {
+      cflags = ["-U_CRT_SECURE_NO_DEPRECATE"]
+    }
   }
 }
diff --git a/BUILDING.md b/BUILDING.md
index f91abcd..e682769 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -10,36 +10,25 @@
 
 - [CMake](http://www.cmake.org) v2.8.12 or later
 
-- [NASM](http://www.nasm.us) or [YASM](http://yasm.tortall.net)
+- [NASM](http://www.nasm.us) or [Yasm](http://yasm.tortall.net)
   (if building x86 or x86-64 SIMD extensions)
   * If using NASM, 2.13 or later is required.
-  * If using YASM, 1.2.0 or later is required.
-  * If building on macOS, NASM or YASM can be obtained from
+  * If using Yasm, 1.2.0 or later is required.
+  * If building on macOS, NASM or Yasm can be obtained from
     [MacPorts](http://www.macports.org/) or [Homebrew](http://brew.sh/).
      - NOTE: Currently, if it is desirable to hide the SIMD function symbols in
        Mac executables or shared libraries that statically link with
-       libjpeg-turbo, then NASM 2.14 or later or YASM must be used when
+       libjpeg-turbo, then NASM 2.14 or later or Yasm must be used when
        building libjpeg-turbo.
-  * If building on Windows, **nasm.exe**/**yasm.exe** should be in your `PATH`.
-  * NASM and YASM are located in the CRB (Code Ready Builder) repository on
+  * If NASM or Yasm is not in your `PATH`, then you can specify the full path
+    to the assembler by using either the `CMAKE_ASM_NASM_COMPILER` CMake
+    variable or the `ASM_NASM` environment variable.  On Windows, use forward
+    slashes rather than backslashes in the path (for example,
+    **c:/nasm/nasm.exe**).
+  * NASM and Yasm are located in the CRB (Code Ready Builder) repository on
     Red Hat Enterprise Linux 8 and in the PowerTools repository on CentOS 8,
     which is not enabled by default.
 
-  The binary RPMs released by the NASM project do not work on older Linux
-  systems, such as Red Hat Enterprise Linux 5.  On such systems, you can easily
-  build and install NASM from a source RPM by downloading one of the SRPMs from
-
-  <http://www.nasm.us/pub/nasm/releasebuilds>
-
-  and executing the following as root:
-
-        ARCH=`uname -m`
-        rpmbuild --rebuild nasm-{version}.src.rpm
-        rpm -Uvh /usr/src/redhat/RPMS/$ARCH/nasm-{version}.$ARCH.rpm
-
-  NOTE: the NASM build will fail if texinfo is not installed.
-
-
 ### Un*x Platforms (including Linux, Mac, FreeBSD, Solaris, and Cygwin)
 
 - GCC v4.1 (or later) or Clang recommended for best performance
@@ -106,8 +95,9 @@
 Ninja
 -----
 
-In all of the procedures and recipes below, replace `make` with `ninja` and
-`Unix Makefiles` with `Ninja` if using Ninja.
+If using Ninja, then replace `make` or `nmake` with `ninja`, and replace the
+CMake generator (specified with the `-G` option) with `Ninja`, in all of the
+procedures and recipes below.
 
 
 Build Procedure
diff --git a/ChangeLog.md b/ChangeLog.md
index 7902d46..e6700c3 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,27 @@
+2.1.3
+=====
+
+### Significant changes relative to 2.1.2
+
+1. Fixed a regression introduced by 2.0 beta1[7] whereby cjpeg compressed PGM
+input files into full-color JPEG images unless the `-grayscale` option was
+used.
+
+2. cjpeg now automatically compresses GIF and 8-bit BMP input files into
+grayscale JPEG images if the input files contain only shades of gray.
+
+3. The build system now enables the intrinsics implementation of the AArch64
+(Arm 64-bit) Neon SIMD extensions by default when using GCC 12 or later.
+
+4. Fixed a segfault that occurred while decompressing a 4:2:0 JPEG image using
+the merged (non-fancy) upsampling algorithms (that is, with
+`cinfo.do_fancy_upsampling` set to `FALSE`) along with `jpeg_crop_scanline()`.
+Specifically, the segfault occurred if the number of bytes remaining in the
+output buffer was less than the number of bytes required to represent one
+uncropped scanline of the output image.  For that reason, the issue could only
+be reproduced using the libjpeg API, not using djpeg.
+
+
 2.1.2
 =====
 
@@ -641,7 +665,7 @@
 now produces bitwise-identical results to the unmerged algorithms.
 
 12. The SIMD function symbols for x86[-64]/ELF, MIPS/ELF, macOS/x86[-64] (if
-libjpeg-turbo is built with YASM), and iOS/Arm[64] builds are now private.
+libjpeg-turbo is built with Yasm), and iOS/Arm[64] builds are now private.
 This prevents those symbols from being exposed in applications or shared
 libraries that link statically with libjpeg-turbo.
 
@@ -1526,8 +1550,8 @@
 
 ### Significant changes relative to 1.2 beta1:
 
-1. Fixed build issue with YASM on Unix systems (the libjpeg-turbo build system
-was not adding the current directory to the assembler include path, so YASM
+1. Fixed build issue with Yasm on Unix systems (the libjpeg-turbo build system
+was not adding the current directory to the assembler include path, so Yasm
 was not able to find jsimdcfg.inc.)
 
 2. Fixed out-of-bounds read in SSE2 SIMD code that occurred when decompressing
@@ -1595,7 +1619,7 @@
 8. All legacy VirtualGL code has been re-factored, and this has allowed
 libjpeg-turbo, in its entirety, to be re-licensed under a BSD-style license.
 
-9. libjpeg-turbo can now be built with YASM.
+9. libjpeg-turbo can now be built with Yasm.
 
 10. Added SIMD acceleration for ARM Linux and iOS platforms that support
 NEON instructions.
diff --git a/LICENSE.md b/LICENSE.md
index a1cdad5..d753e1d 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -91,7 +91,7 @@
 The Modified (3-clause) BSD License
 ===================================
 
-Copyright (C)2009-2021 D. R. Commander.  All Rights Reserved.<br>
+Copyright (C)2009-2022 D. R. Commander.  All Rights Reserved.<br>
 Copyright (C)2015 Viktor Szathmáry.  All Rights Reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/README.chromium b/README.chromium
index 33028fc..4a0cbdf 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,6 +1,6 @@
 Name: libjpeg-turbo
 URL: https://github.com/libjpeg-turbo/libjpeg-turbo/
-Version: 2.1.2
+Version: 2.1.3
 License: Custom license
 License File: LICENSE.md
 Security Critical: yes
@@ -8,18 +8,20 @@
 
 Description:
 This consists of the components:
-* libjpeg-turbo 2.1.2
+* libjpeg-turbo 2.1.3
 * This file (README.chromium)
 * A build file (BUILD.gn)
 * An OWNERS file
 * A codereview.settings file
+* A DIR_METADATA file
 * Patched header files used by Chromium
 * Deleted unused directories: cmakescripts, doc, fuzz, java, release,
   sharedlib, simd/mips, simd/mips64, simd/powerpc, and win
-* Deleted unused files: appveyor.yml, CMakeLists.txt, doxygen.config,
-  doxygen-extra.css, .gitattributes, md5/CMakeLists.txt, md5/md5cmp.c,
-  simd/CMakeLists.txt, tjexample.c, tjexampletest.in, tjexampletest.java.in and
-  .travis.yml
+* Deleted unused files: appveyor.yml, CMakeLists.txt, cjpeg.1, croptest.in,
+  djpeg.1, doxygen.config, doxygen-extra.css, .gitattributes, jpegtran.1,
+  md5/CMakeLists.txt, md5/md5cmp.c, rdjpgcom.1, simd/CMakeLists.txt, strtest.c,
+  tjbenchtest.in, tjbenchtest.java.in, tjexample.c, tjexampletest.in,
+  tjexampletest.java.in and wrjpgcom.1
 * Deleted legacy Arm Neon assembly files (supporting old compiler versions that
   do not generate performant code from intrinsics):
   simd/arm/aarch32/jsimd_neon.S, simd/arm/aarch64/jsimd_neon.S.
diff --git a/cdjpeg.c b/cdjpeg.c
index 5278c1d..304a665 100644
--- a/cdjpeg.c
+++ b/cdjpeg.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2019, D. R. Commander.
+ * Copyright (C) 2019, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -34,7 +34,7 @@
     int scan_no = ((j_decompress_ptr)cinfo)->input_scan_number;
 
     if (scan_no > (int)prog->max_scans) {
-      fprintf(stderr, "Scan number %d exceeds maximum scans (%d)\n", scan_no,
+      fprintf(stderr, "Scan number %d exceeds maximum scans (%u)\n", scan_no,
               prog->max_scans);
       exit(EXIT_FAILURE);
     }
diff --git a/cjpeg.1 b/cjpeg.1
deleted file mode 100644
index 75a9cce..0000000
--- a/cjpeg.1
+++ /dev/null
@@ -1,365 +0,0 @@
-.TH CJPEG 1 "18 November 2021"
-.SH NAME
-cjpeg \- compress an image file to a JPEG file
-.SH SYNOPSIS
-.B cjpeg
-[
-.I options
-]
-[
-.I filename
-]
-.LP
-.SH DESCRIPTION
-.LP
-.B cjpeg
-compresses the named image file, or the standard input if no file is
-named, and produces a JPEG/JFIF file on the standard output.
-The currently supported input file formats are: PPM (PBMPLUS color
-format), PGM (PBMPLUS grayscale format), BMP, GIF, and Targa.
-.SH OPTIONS
-All switch names may be abbreviated; for example,
-.B \-grayscale
-may be written
-.B \-gray
-or
-.BR \-gr .
-Most of the "basic" switches can be abbreviated to as little as one letter.
-Upper and lower case are equivalent (thus
-.B \-BMP
-is the same as
-.BR \-bmp ).
-British spellings are also accepted (e.g.,
-.BR \-greyscale ),
-though for brevity these are not mentioned below.
-.PP
-The basic switches are:
-.TP
-.BI \-quality " N[,...]"
-Scale quantization tables to adjust image quality.  Quality is 0 (worst) to
-100 (best); default is 75.  (See below for more info.)
-.TP
-.B \-grayscale
-Create monochrome JPEG file from color input.  Be sure to use this switch when
-compressing a grayscale BMP or GIF file, because
-.B cjpeg
-isn't bright enough to notice whether a BMP or GIF file uses only shades of
-gray.  By saying
-.BR \-grayscale,
-you'll get a smaller JPEG file that takes less time to process.
-.TP
-.B \-rgb
-Create RGB JPEG file.
-Using this switch suppresses the conversion from RGB
-colorspace input to the default YCbCr JPEG colorspace.
-.TP
-.B \-optimize
-Perform optimization of entropy encoding parameters.  Without this, default
-encoding parameters are used.
-.B \-optimize
-usually makes the JPEG file a little smaller, but
-.B cjpeg
-runs somewhat slower and needs much more memory.  Image quality and speed of
-decompression are unaffected by
-.BR \-optimize .
-.TP
-.B \-progressive
-Create progressive JPEG file (see below).
-.TP
-.B \-targa
-Input file is Targa format.  Targa files that contain an "identification"
-field will not be automatically recognized by
-.BR cjpeg ;
-for such files you must specify
-.B \-targa
-to make
-.B cjpeg
-treat the input as Targa format.
-For most Targa files, you won't need this switch.
-.PP
-The
-.B \-quality
-switch lets you trade off compressed file size against quality of the
-reconstructed image: the higher the quality setting, the larger the JPEG file,
-and the closer the output image will be to the original input.  Normally you
-want to use the lowest quality setting (smallest file) that decompresses into
-something visually indistinguishable from the original image.  For this
-purpose the quality setting should generally be between 50 and 95 (the default
-is 75) for photographic images.  If you see defects at
-.B \-quality
-75, then go up 5 or 10 counts at a time until you are happy with the output
-image.  (The optimal setting will vary from one image to another.)
-.PP
-.B \-quality
-100 will generate a quantization table of all 1's, minimizing loss in the
-quantization step (but there is still information loss in subsampling, as well
-as roundoff error.)  For most images, specifying a quality value above
-about 95 will increase the size of the compressed file dramatically, and while
-the quality gain from these higher quality values is measurable (using metrics
-such as PSNR or SSIM), it is rarely perceivable by human vision.
-.PP
-In the other direction, quality values below 50 will produce very small files
-of low image quality.  Settings around 5 to 10 might be useful in preparing an
-index of a large image library, for example.  Try
-.B \-quality
-2 (or so) for some amusing Cubist effects.  (Note: quality
-values below about 25 generate 2-byte quantization tables, which are
-considered optional in the JPEG standard.
-.B cjpeg
-emits a warning message when you give such a quality value, because some
-other JPEG programs may be unable to decode the resulting file.  Use
-.B \-baseline
-if you need to ensure compatibility at low quality values.)
-.PP
-The \fB-quality\fR option has been extended in this version of \fBcjpeg\fR to
-support separate quality settings for luminance and chrominance (or, in
-general, separate settings for every quantization table slot.)  The principle
-is the same as chrominance subsampling:  since the human eye is more sensitive
-to spatial changes in brightness than spatial changes in color, the chrominance
-components can be quantized more than the luminance components without
-incurring any visible image quality loss.  However, unlike subsampling, this
-feature reduces data in the frequency domain instead of the spatial domain,
-which allows for more fine-grained control.  This option is useful in
-quality-sensitive applications, for which the artifacts generated by
-subsampling may be unacceptable.
-.PP
-The \fB-quality\fR option accepts a comma-separated list of parameters, which
-respectively refer to the quality levels that should be assigned to the
-quantization table slots.  If there are more q-table slots than parameters,
-then the last parameter is replicated.  Thus, if only one quality parameter is
-given, this is used for both luminance and chrominance (slots 0 and 1,
-respectively), preserving the legacy behavior of cjpeg v6b and prior.
-More (or customized) quantization tables can be set with the \fB-qtables\fR
-option and assigned to components with the \fB-qslots\fR option (see the
-"wizard" switches below.)
-.PP
-JPEG files generated with separate luminance and chrominance quality are fully
-compliant with standard JPEG decoders.
-.PP
-.BR CAUTION:
-For this setting to be useful, be sure to pass an argument of \fB-sample 1x1\fR
-to \fBcjpeg\fR to disable chrominance subsampling.  Otherwise, the default
-subsampling level (2x2, AKA "4:2:0") will be used.
-.PP
-The
-.B \-progressive
-switch creates a "progressive JPEG" file.  In this type of JPEG file, the data
-is stored in multiple scans of increasing quality.  If the file is being
-transmitted over a slow communications link, the decoder can use the first
-scan to display a low-quality image very quickly, and can then improve the
-display with each subsequent scan.  The final image is exactly equivalent to a
-standard JPEG file of the same quality setting, and the total file size is
-about the same --- often a little smaller.
-.PP
-Switches for advanced users:
-.TP
-.B \-arithmetic
-Use arithmetic coding.
-.B Caution:
-arithmetic coded JPEG is not yet widely implemented, so many decoders will be
-unable to view an arithmetic coded JPEG file at all.
-.TP
-.B \-dct int
-Use accurate integer DCT method (default).
-.TP
-.B \-dct fast
-Use less accurate integer DCT method [legacy feature].
-When the Independent JPEG Group's software was first released in 1991, the
-compression time for a 1-megapixel JPEG image on a mainstream PC was measured
-in minutes.  Thus, the \fBfast\fR integer DCT algorithm provided noticeable
-performance benefits.  On modern CPUs running libjpeg-turbo, however, the
-compression time for a 1-megapixel JPEG image is measured in milliseconds, and
-thus the performance benefits of the \fBfast\fR algorithm are much less
-noticeable.  On modern x86/x86-64 CPUs that support AVX2 instructions, the
-\fBfast\fR and \fBint\fR methods have similar performance.  On other types of
-CPUs, the \fBfast\fR method is generally about 5-15% faster than the \fBint\fR
-method.
-
-For quality levels of 90 and below, there should be little or no perceptible
-quality difference between the two algorithms.  For quality levels above 90,
-however, the difference between the \fBfast\fR and \fBint\fR methods becomes
-more pronounced.  With quality=97, for instance, the \fBfast\fR method incurs
-generally about a 1-3 dB loss in PSNR relative to the \fBint\fR method, but
-this can be larger for some images.  Do not use the \fBfast\fR method with
-quality levels above 97.  The algorithm often degenerates at quality=98 and
-above and can actually produce a more lossy image than if lower quality levels
-had been used.  Also, in libjpeg-turbo, the \fBfast\fR method is not fully
-accelerated for quality levels above 97, so it will be slower than the
-\fBint\fR method.
-.TP
-.B \-dct float
-Use floating-point DCT method [legacy feature].
-The \fBfloat\fR method does not produce significantly more accurate results
-than the \fBint\fR method, and it is much slower.  The \fBfloat\fR method may
-also give different results on different machines due to varying roundoff
-behavior, whereas the integer methods should give the same results on all
-machines.
-.TP
-.BI \-icc " file"
-Embed ICC color management profile contained in the specified file.
-.TP
-.BI \-restart " N"
-Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
-attached to the number.
-.B \-restart 0
-(the default) means no restart markers.
-.TP
-.BI \-smooth " N"
-Smooth the input image to eliminate dithering noise.  N, ranging from 1 to
-100, indicates the strength of smoothing.  0 (the default) means no smoothing.
-.TP
-.BI \-maxmemory " N"
-Set limit for amount of memory to use in processing large images.  Value is
-in thousands of bytes, or millions of bytes if "M" is attached to the
-number.  For example,
-.B \-max 4m
-selects 4000000 bytes.  If more space is needed, an error will occur.
-.TP
-.BI \-outfile " name"
-Send output image to the named file, not to standard output.
-.TP
-.BI \-memdst
-Compress to memory instead of a file.  This feature was implemented mainly as a
-way of testing the in-memory destination manager (jpeg_mem_dest()), but it is
-also useful for benchmarking, since it reduces the I/O overhead.
-.TP
-.BI \-report
-Report compression progress.
-.TP
-.BI \-strict
-Treat all warnings as fatal.  Enabling this option will cause the compressor to
-abort if an LZW-compressed GIF input image contains incomplete or corrupt image
-data.
-.TP
-.B \-verbose
-Enable debug printout.  More
-.BR \-v 's
-give more output.  Also, version information is printed at startup.
-.TP
-.B \-debug
-Same as
-.BR \-verbose .
-.TP
-.B \-version
-Print version information and exit.
-.PP
-The
-.B \-restart
-option inserts extra markers that allow a JPEG decoder to resynchronize after
-a transmission error.  Without restart markers, any damage to a compressed
-file will usually ruin the image from the point of the error to the end of the
-image; with restart markers, the damage is usually confined to the portion of
-the image up to the next restart marker.  Of course, the restart markers
-occupy extra space.  We recommend
-.B \-restart 1
-for images that will be transmitted across unreliable networks such as Usenet.
-.PP
-The
-.B \-smooth
-option filters the input to eliminate fine-scale noise.  This is often useful
-when converting dithered images to JPEG: a moderate smoothing factor of 10 to
-50 gets rid of dithering patterns in the input file, resulting in a smaller
-JPEG file and a better-looking image.  Too large a smoothing factor will
-visibly blur the image, however.
-.PP
-Switches for wizards:
-.TP
-.B \-baseline
-Force baseline-compatible quantization tables to be generated.  This clamps
-quantization values to 8 bits even at low quality settings.  (This switch is
-poorly named, since it does not ensure that the output is actually baseline
-JPEG.  For example, you can use
-.B \-baseline
-and
-.B \-progressive
-together.)
-.TP
-.BI \-qtables " file"
-Use the quantization tables given in the specified text file.
-.TP
-.BI \-qslots " N[,...]"
-Select which quantization table to use for each color component.
-.TP
-.BI \-sample " HxV[,...]"
-Set JPEG sampling factors for each color component.
-.TP
-.BI \-scans " file"
-Use the scan script given in the specified text file.
-.PP
-The "wizard" switches are intended for experimentation with JPEG.  If you
-don't know what you are doing, \fBdon't use them\fR.  These switches are
-documented further in the file wizard.txt.
-.SH EXAMPLES
-.LP
-This example compresses the PPM file foo.ppm with a quality factor of
-60 and saves the output as foo.jpg:
-.IP
-.B cjpeg \-quality
-.I 60 foo.ppm
-.B >
-.I foo.jpg
-.SH HINTS
-Color GIF files are not the ideal input for JPEG; JPEG is really intended for
-compressing full-color (24-bit) images.  In particular, don't try to convert
-cartoons, line drawings, and other images that have only a few distinct
-colors.  GIF works great on these, JPEG does not.  If you want to convert a
-GIF to JPEG, you should experiment with
-.BR cjpeg 's
-.B \-quality
-and
-.B \-smooth
-options to get a satisfactory conversion.
-.B \-smooth 10
-or so is often helpful.
-.PP
-Avoid running an image through a series of JPEG compression/decompression
-cycles.  Image quality loss will accumulate; after ten or so cycles the image
-may be noticeably worse than it was after one cycle.  It's best to use a
-lossless format while manipulating an image, then convert to JPEG format when
-you are ready to file the image away.
-.PP
-The
-.B \-optimize
-option to
-.B cjpeg
-is worth using when you are making a "final" version for posting or archiving.
-It's also a win when you are using low quality settings to make very small
-JPEG files; the percentage improvement is often a lot more than it is on
-larger files.  (At present,
-.B \-optimize
-mode is always selected when generating progressive JPEG files.)
-.SH ENVIRONMENT
-.TP
-.B JPEGMEM
-If this environment variable is set, its value is the default memory limit.
-The value is specified as described for the
-.B \-maxmemory
-switch.
-.B JPEGMEM
-overrides the default value specified when the program was compiled, and
-itself is overridden by an explicit
-.BR \-maxmemory .
-.SH SEE ALSO
-.BR djpeg (1),
-.BR jpegtran (1),
-.BR rdjpgcom (1),
-.BR wrjpgcom (1)
-.br
-.BR ppm (5),
-.BR pgm (5)
-.br
-Wallace, Gregory K.  "The JPEG Still Picture Compression Standard",
-Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
-.SH AUTHOR
-Independent JPEG Group
-.PP
-This file was modified by The libjpeg-turbo Project to include only information
-relevant to libjpeg-turbo, to wordsmith certain sections, and to describe
-features not present in libjpeg.
-.SH ISSUES
-Not all variants of BMP and Targa file formats are supported.
-.PP
-The
-.B \-targa
-switch is not a bug, it's a feature.  (It would be a bug if the Targa format
-designers had not been clueless.)
diff --git a/cjpeg.c b/cjpeg.c
index beda367..156b67d 100644
--- a/cjpeg.c
+++ b/cjpeg.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1998, Thomas G. Lane.
  * Modified 2003-2011 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2013-2014, 2017, 2019-2021, D. R. Commander.
+ * Copyright (C) 2010, 2013-2014, 2017, 2019-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -27,6 +27,10 @@
  * works regardless of which command line style is used.
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #ifdef CJPEG_FUZZER
 #define JPEG_INTERNALS
 #endif
@@ -34,11 +38,6 @@
 #include "jversion.h"           /* for version message */
 #include "jconfigint.h"
 
-#ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare malloc(),free() */
-extern void *malloc(size_t size);
-extern void free(void *ptr);
-#endif
-
 #ifdef USE_CCOMMAND             /* command-line reader for Macintosh */
 #ifdef __MWERKS__
 #include <SIOUX.h>              /* Metrowerks needs this */
@@ -166,7 +165,7 @@
   longjmp(myerr->setjmp_buffer, 1);
 }
 
-static void my_emit_message(j_common_ptr cinfo, int msg_level)
+static void my_emit_message_fuzzer(j_common_ptr cinfo, int msg_level)
 {
   if (msg_level < 0)
     cinfo->err->num_warnings++;
@@ -703,7 +702,7 @@
 
 #ifdef CJPEG_FUZZER
   jerr.error_exit = my_error_exit;
-  jerr.emit_message = my_emit_message;
+  jerr.emit_message = my_emit_message_fuzzer;
   if (setjmp(myerr.setjmp_buffer))
     HANDLE_ERROR()
 #endif
diff --git a/croptest.in b/croptest.in
deleted file mode 100644
index 7e3c293..0000000
--- a/croptest.in
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/bin/bash
-
-set -u
-set -e
-trap onexit INT
-trap onexit TERM
-trap onexit EXIT
-
-onexit()
-{
-	if [ -d $OUTDIR ]; then
-		rm -rf $OUTDIR
-	fi
-}
-
-runme()
-{
-	echo \*\*\* $*
-	$*
-}
-
-IMAGE=vgl_6548_0026a.bmp
-WIDTH=128
-HEIGHT=95
-IMGDIR=@CMAKE_CURRENT_SOURCE_DIR@/testimages
-OUTDIR=`mktemp -d /tmp/__croptest_output.XXXXXX`
-EXEDIR=@CMAKE_CURRENT_BINARY_DIR@
-
-if [ -d $OUTDIR ]; then
-	rm -rf $OUTDIR
-fi
-mkdir -p $OUTDIR
-
-exec >$EXEDIR/croptest.log
-
-echo "============================================================"
-echo "$IMAGE ($WIDTH x $HEIGHT)"
-echo "============================================================"
-echo
-
-for PROGARG in "" -progressive; do
-
-	cp $IMGDIR/$IMAGE $OUTDIR
-	basename=`basename $IMAGE .bmp`
-	echo "------------------------------------------------------------"
-	echo "Generating test images"
-	echo "------------------------------------------------------------"
-	echo
-	runme $EXEDIR/cjpeg $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg $PROGARG -sample 1x2 -outfile $OUTDIR/${basename}_440.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444.jpg $IMGDIR/${basename}.bmp
-	echo
-
-	for NSARG in "" -nosmooth; do
-
-		for COLORSARG in "" "-colors 256 -dither none -onepass"; do
-
-			for Y in {0..16}; do
-
-				for H in {1..16}; do
-
-					X=$(( (Y*16)%128 ))
-					W=$(( WIDTH-X-7 ))
-					if [ $Y -le 15 ]; then
-						CROPSPEC="${W}x${H}+${X}+${Y}"
-					else
-						Y2=$(( HEIGHT-H ));
-						CROPSPEC="${W}x${H}+${X}+${Y2}"
-					fi
-
-					echo "------------------------------------------------------------"
-					echo $PROGARG $NSARG $COLORSARG -crop $CROPSPEC
-					echo "------------------------------------------------------------"
-					echo
-					for samp in GRAY 420 422 440 444; do
-						$EXEDIR/djpeg $NSARG $COLORSARG -rgb -outfile $OUTDIR/${basename}_${samp}_full.ppm $OUTDIR/${basename}_${samp}.jpg
-						convert -crop $CROPSPEC $OUTDIR/${basename}_${samp}_full.ppm $OUTDIR/${basename}_${samp}_ref.ppm
-						runme $EXEDIR/djpeg $NSARG $COLORSARG -crop $CROPSPEC -rgb -outfile $OUTDIR/${basename}_${samp}.ppm $OUTDIR/${basename}_${samp}.jpg
-						runme cmp $OUTDIR/${basename}_${samp}.ppm $OUTDIR/${basename}_${samp}_ref.ppm
-					done
-					echo
-
-				done
-
-			done
-
-		done
-
-	done
-
-done
-
-echo SUCCESS!
diff --git a/djpeg.1 b/djpeg.1
deleted file mode 100644
index 31431b9..0000000
--- a/djpeg.1
+++ /dev/null
@@ -1,320 +0,0 @@
-.TH DJPEG 1 "4 November 2020"
-.SH NAME
-djpeg \- decompress a JPEG file to an image file
-.SH SYNOPSIS
-.B djpeg
-[
-.I options
-]
-[
-.I filename
-]
-.LP
-.SH DESCRIPTION
-.LP
-.B djpeg
-decompresses the named JPEG file, or the standard input if no file is named,
-and produces an image file on the standard output.  PBMPLUS (PPM/PGM), BMP,
-GIF, or Targa output format can be selected.
-.SH OPTIONS
-All switch names may be abbreviated; for example,
-.B \-grayscale
-may be written
-.B \-gray
-or
-.BR \-gr .
-Most of the "basic" switches can be abbreviated to as little as one letter.
-Upper and lower case are equivalent (thus
-.B \-BMP
-is the same as
-.BR \-bmp ).
-British spellings are also accepted (e.g.,
-.BR \-greyscale ),
-though for brevity these are not mentioned below.
-.PP
-The basic switches are:
-.TP
-.BI \-colors " N"
-Reduce image to at most N colors.  This reduces the number of colors used in
-the output image, so that it can be displayed on a colormapped display or
-stored in a colormapped file format.  For example, if you have an 8-bit
-display, you'd need to reduce to 256 or fewer colors.
-.TP
-.BI \-quantize " N"
-Same as
-.BR \-colors .
-.B \-colors
-is the recommended name,
-.B \-quantize
-is provided only for backwards compatibility.
-.TP
-.B \-fast
-Select recommended processing options for fast, low quality output.  (The
-default options are chosen for highest quality output.)  Currently, this is
-equivalent to \fB\-dct fast \-nosmooth \-onepass \-dither ordered\fR.
-.TP
-.B \-grayscale
-Force grayscale output even if JPEG file is color.  Useful for viewing on
-monochrome displays; also,
-.B djpeg
-runs noticeably faster in this mode.
-.TP
-.B \-rgb
-Force RGB output even if JPEG file is grayscale.
-.TP
-.BI \-scale " M/N"
-Scale the output image by a factor M/N.  Currently the scale factor must be
-M/8, where M is an integer between 1 and 16 inclusive, or any reduced fraction
-thereof (such as 1/2, 3/4, etc.)  Scaling is handy if the image is larger than
-your screen; also,
-.B djpeg
-runs much faster when scaling down the output.
-.TP
-.B \-bmp
-Select BMP output format (Windows flavor).  8-bit colormapped format is
-emitted if
-.B \-colors
-or
-.B \-grayscale
-is specified, or if the JPEG file is grayscale; otherwise, 24-bit full-color
-format is emitted.
-.TP
-.B \-gif
-Select GIF output format (LZW-compressed).  Since GIF does not support more
-than 256 colors,
-.B \-colors 256
-is assumed (unless you specify a smaller number of colors).  If you specify
-.BR \-fast,
-the default number of colors is 216.
-.TP
-.B \-gif0
-Select GIF output format (uncompressed).  Since GIF does not support more than
-256 colors,
-.B \-colors 256
-is assumed (unless you specify a smaller number of colors).  If you specify
-.BR \-fast,
-the default number of colors is 216.
-.TP
-.B \-os2
-Select BMP output format (OS/2 1.x flavor).  8-bit colormapped format is
-emitted if
-.B \-colors
-or
-.B \-grayscale
-is specified, or if the JPEG file is grayscale; otherwise, 24-bit full-color
-format is emitted.
-.TP
-.B \-pnm
-Select PBMPLUS (PPM/PGM) output format (this is the default format).
-PGM is emitted if the JPEG file is grayscale or if
-.B \-grayscale
-is specified; otherwise PPM is emitted.
-.TP
-.B \-targa
-Select Targa output format.  Grayscale format is emitted if the JPEG file is
-grayscale or if
-.B \-grayscale
-is specified; otherwise, colormapped format is emitted if
-.B \-colors
-is specified; otherwise, 24-bit full-color format is emitted.
-.PP
-Switches for advanced users:
-.TP
-.B \-dct int
-Use accurate integer DCT method (default).
-.TP
-.B \-dct fast
-Use less accurate integer DCT method [legacy feature].
-When the Independent JPEG Group's software was first released in 1991, the
-decompression time for a 1-megapixel JPEG image on a mainstream PC was measured
-in minutes.  Thus, the \fBfast\fR integer DCT algorithm provided noticeable
-performance benefits.  On modern CPUs running libjpeg-turbo, however, the
-decompression time for a 1-megapixel JPEG image is measured in milliseconds,
-and thus the performance benefits of the \fBfast\fR algorithm are much less
-noticeable.  On modern x86/x86-64 CPUs that support AVX2 instructions, the
-\fBfast\fR and \fBint\fR methods have similar performance.  On other types of
-CPUs, the \fBfast\fR method is generally about 5-15% faster than the \fBint\fR
-method.
-
-If the JPEG image was compressed using a quality level of 85 or below, then
-there should be little or no perceptible quality difference between the two
-algorithms.  When decompressing images that were compressed using quality
-levels above 85, however, the difference between the \fBfast\fR and \fBint\fR
-methods becomes more pronounced.  With images compressed using quality=97, for
-instance, the \fBfast\fR method incurs generally about a 4-6 dB loss in PSNR
-relative to the \fBint\fR method, but this can be larger for some images.  If
-you can avoid it, do not use the \fBfast\fR method when decompressing images
-that were compressed using quality levels above 97.  The algorithm often
-degenerates for such images and can actually produce a more lossy output image
-than if the JPEG image had been compressed using lower quality levels.
-.TP
-.B \-dct float
-Use floating-point DCT method [legacy feature].
-The \fBfloat\fR method does not produce significantly more accurate results
-than the \fBint\fR method, and it is much slower.  The \fBfloat\fR method may
-also give different results on different machines due to varying roundoff
-behavior, whereas the integer methods should give the same results on all
-machines.
-.TP
-.B \-dither fs
-Use Floyd-Steinberg dithering in color quantization.
-.TP
-.B \-dither ordered
-Use ordered dithering in color quantization.
-.TP
-.B \-dither none
-Do not use dithering in color quantization.
-By default, Floyd-Steinberg dithering is applied when quantizing colors; this
-is slow but usually produces the best results.  Ordered dither is a compromise
-between speed and quality; no dithering is fast but usually looks awful.  Note
-that these switches have no effect unless color quantization is being done.
-Ordered dither is only available in
-.B \-onepass
-mode.
-.TP
-.BI \-icc " file"
-Extract ICC color management profile to the specified file.
-.TP
-.BI \-map " file"
-Quantize to the colors used in the specified image file.  This is useful for
-producing multiple files with identical color maps, or for forcing a
-predefined set of colors to be used.  The
-.I file
-must be a GIF or PPM file. This option overrides
-.B \-colors
-and
-.BR \-onepass .
-.TP
-.B \-nosmooth
-Use a faster, lower-quality upsampling routine.
-.TP
-.B \-onepass
-Use one-pass instead of two-pass color quantization.  The one-pass method is
-faster and needs less memory, but it produces a lower-quality image.
-.B \-onepass
-is ignored unless you also say
-.B \-colors
-.IR N .
-Also, the one-pass method is always used for grayscale output (the two-pass
-method is no improvement then).
-.TP
-.BI \-maxmemory " N"
-Set limit for amount of memory to use in processing large images.  Value is
-in thousands of bytes, or millions of bytes if "M" is attached to the
-number.  For example,
-.B \-max 4m
-selects 4000000 bytes.  If more space is needed, an error will occur.
-.TP
-.BI \-maxscans " N"
-Abort if the JPEG image contains more than
-.I N
-scans.  This feature demonstrates a method by which applications can guard
-against denial-of-service attacks instigated by specially-crafted malformed
-JPEG images containing numerous scans with missing image data or image data
-consisting only of "EOB runs" (a feature of progressive JPEG images that allows
-potentially hundreds of thousands of adjoining zero-value pixels to be
-represented using only a few bytes.)  Attempting to decompress such malformed
-JPEG images can cause excessive CPU activity, since the decompressor must fully
-process each scan (even if the scan is corrupt) before it can proceed to the
-next scan.
-.TP
-.BI \-outfile " name"
-Send output image to the named file, not to standard output.
-.TP
-.BI \-memsrc
-Load input file into memory before decompressing.  This feature was implemented
-mainly as a way of testing the in-memory source manager (jpeg_mem_src().)
-.TP
-.BI \-report
-Report decompression progress.
-.TP
-.BI \-skip " Y0,Y1"
-Decompress all rows of the JPEG image except those between Y0 and Y1
-(inclusive.)  Note that if decompression scaling is being used, then Y0 and Y1
-are relative to the scaled image dimensions.
-.TP
-.BI \-crop " WxH+X+Y"
-Decompress only a rectangular subregion of the image, starting at point X,Y
-with width W and height H.  If necessary, X will be shifted left to the nearest
-iMCU boundary, and the width will be increased accordingly.  Note that if
-decompression scaling is being used, then X, Y, W, and H are relative to the
-scaled image dimensions.  Currently this option only works with the
-PBMPLUS (PPM/PGM), GIF, and Targa output formats.
-.TP
-.BI \-strict
-Treat all warnings as fatal.  This feature also demonstrates a method by which
-applications can guard against attacks instigated by specially-crafted
-malformed JPEG images.  Enabling this option will cause the decompressor to
-abort if the JPEG image contains incomplete or corrupt image data.
-.TP
-.B \-verbose
-Enable debug printout.  More
-.BR \-v 's
-give more output.  Also, version information is printed at startup.
-.TP
-.B \-debug
-Same as
-.BR \-verbose .
-.TP
-.B \-version
-Print version information and exit.
-.SH EXAMPLES
-.LP
-This example decompresses the JPEG file foo.jpg, quantizes it to
-256 colors, and saves the output in 8-bit BMP format in foo.bmp:
-.IP
-.B djpeg \-colors 256 \-bmp
-.I foo.jpg
-.B >
-.I foo.bmp
-.SH HINTS
-To get a quick preview of an image, use the
-.B \-grayscale
-and/or
-.B \-scale
-switches.
-.B \-grayscale \-scale 1/8
-is the fastest case.
-.PP
-Several options are available that trade off image quality to gain speed.
-.B \-fast
-turns on the recommended settings.
-.PP
-.B \-dct fast
-and/or
-.B \-nosmooth
-gain speed at a small sacrifice in quality.
-When producing a color-quantized image,
-.B \-onepass \-dither ordered
-is fast but much lower quality than the default behavior.
-.B \-dither none
-may give acceptable results in two-pass mode, but is seldom tolerable in
-one-pass mode.
-.SH ENVIRONMENT
-.TP
-.B JPEGMEM
-If this environment variable is set, its value is the default memory limit.
-The value is specified as described for the
-.B \-maxmemory
-switch.
-.B JPEGMEM
-overrides the default value specified when the program was compiled, and
-itself is overridden by an explicit
-.BR \-maxmemory .
-.SH SEE ALSO
-.BR cjpeg (1),
-.BR jpegtran (1),
-.BR rdjpgcom (1),
-.BR wrjpgcom (1)
-.br
-.BR ppm (5),
-.BR pgm (5)
-.br
-Wallace, Gregory K.  "The JPEG Still Picture Compression Standard",
-Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
-.SH AUTHOR
-Independent JPEG Group
-.PP
-This file was modified by The libjpeg-turbo Project to include only information
-relevant to libjpeg-turbo, to wordsmith certain sections, and to describe
-features not present in libjpeg.
diff --git a/djpeg.c b/djpeg.c
index cc2eb9d..bbd9d18 100644
--- a/djpeg.c
+++ b/djpeg.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * Modified 2013-2019 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010-2011, 2013-2017, 2019-2020, D. R. Commander.
+ * Copyright (C) 2010-2011, 2013-2017, 2019-2020, 2022, D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
@@ -28,14 +28,14 @@
  * works regardless of which command line style is used.
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
 #include "jversion.h"           /* for version message */
 #include "jconfigint.h"
 
-#ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare free() */
-extern void free(void *ptr);
-#endif
-
 #include <ctype.h>              /* to declare isprint() */
 
 #ifdef USE_CCOMMAND             /* command-line reader for Macintosh */
@@ -655,7 +655,7 @@
         fprintf(stderr, "%s: memory allocation failure\n", progname);
         return EXIT_FAILURE;
       }
-      nbytes = JFREAD(input_file, &inbuffer[insize], INPUT_BUF_SIZE);
+      nbytes = fread(&inbuffer[insize], 1, INPUT_BUF_SIZE, input_file);
       if (nbytes < INPUT_BUF_SIZE && ferror(input_file)) {
         if (file_index < argc)
           fprintf(stderr, "%s: can't read from %s\n", progname,
@@ -725,7 +725,7 @@
      * that skip_start <= skip_end.
      */
     if (skip_end > cinfo.output_height - 1) {
-      fprintf(stderr, "%s: skip region exceeds image height %d\n", progname,
+      fprintf(stderr, "%s: skip region exceeds image height %u\n", progname,
               cinfo.output_height);
       return EXIT_FAILURE;
     }
@@ -746,7 +746,7 @@
     }
     if ((tmp = jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1)) !=
         skip_end - skip_start + 1) {
-      fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n",
+      fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
               progname, tmp, skip_end - skip_start + 1);
       return EXIT_FAILURE;
     }
@@ -765,7 +765,7 @@
      */
     if (crop_x + crop_width > cinfo.output_width ||
         crop_y + crop_height > cinfo.output_height) {
-      fprintf(stderr, "%s: crop dimensions exceed image dimensions %d x %d\n",
+      fprintf(stderr, "%s: crop dimensions exceed image dimensions %u x %u\n",
               progname, cinfo.output_width, cinfo.output_height);
       return EXIT_FAILURE;
     }
@@ -786,7 +786,7 @@
 
     /* Process data */
     if ((tmp = jpeg_skip_scanlines(&cinfo, crop_y)) != crop_y) {
-      fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n",
+      fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
               progname, tmp, crop_y);
       return EXIT_FAILURE;
     }
@@ -799,7 +799,7 @@
          jpeg_skip_scanlines(&cinfo,
                              cinfo.output_height - crop_y - crop_height)) !=
         cinfo.output_height - crop_y - crop_height) {
-      fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n",
+      fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n",
               progname, tmp, cinfo.output_height - crop_y - crop_height);
       return EXIT_FAILURE;
     }
diff --git a/jcapimin.c b/jcapimin.c
index 178c55b..84e7ecc 100644
--- a/jcapimin.c
+++ b/jcapimin.c
@@ -4,8 +4,8 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1998, Thomas G. Lane.
  * Modified 2003-2010 by Guido Vollbeding.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -52,7 +52,7 @@
   {
     struct jpeg_error_mgr *err = cinfo->err;
     void *client_data = cinfo->client_data; /* ignore Purify complaint here */
-    MEMZERO(cinfo, sizeof(struct jpeg_compress_struct));
+    memset(cinfo, 0, sizeof(struct jpeg_compress_struct));
     cinfo->err = err;
     cinfo->client_data = client_data;
   }
diff --git a/jcarith.c b/jcarith.c
index b6d093f..b172052 100644
--- a/jcarith.c
+++ b/jcarith.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Developed 1997-2009 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2015, 2018, D. R. Commander.
+ * Copyright (C) 2015, 2018, 2021-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -338,14 +338,14 @@
     compptr = cinfo->cur_comp_info[ci];
     /* DC needs no table for refinement scan */
     if (cinfo->progressive_mode == 0 || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
-      MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+      memset(entropy->dc_stats[compptr->dc_tbl_no], 0, DC_STAT_BINS);
       /* Reset DC predictions to 0 */
       entropy->last_dc_val[ci] = 0;
       entropy->dc_context[ci] = 0;
     }
     /* AC needs no table when not present */
     if (cinfo->progressive_mode == 0 || cinfo->Se) {
-      MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+      memset(entropy->ac_stats[compptr->ac_tbl_no], 0, AC_STAT_BINS);
     }
   }
 
@@ -836,7 +836,7 @@
      * We are fully adaptive here and need no extra
      * statistics gathering pass!
      */
-    ERREXIT(cinfo, JERR_NOT_COMPILED);
+    ERREXIT(cinfo, JERR_NOTIMPL);
 
   /* We assume jcmaster.c already validated the progressive scan parameters. */
 
@@ -867,7 +867,7 @@
       if (entropy->dc_stats[tbl] == NULL)
         entropy->dc_stats[tbl] = (unsigned char *)(*cinfo->mem->alloc_small)
           ((j_common_ptr)cinfo, JPOOL_IMAGE, DC_STAT_BINS);
-      MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+      memset(entropy->dc_stats[tbl], 0, DC_STAT_BINS);
       /* Initialize DC predictions to 0 */
       entropy->last_dc_val[ci] = 0;
       entropy->dc_context[ci] = 0;
@@ -880,7 +880,7 @@
       if (entropy->ac_stats[tbl] == NULL)
         entropy->ac_stats[tbl] = (unsigned char *)(*cinfo->mem->alloc_small)
           ((j_common_ptr)cinfo, JPOOL_IMAGE, AC_STAT_BINS);
-      MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+      memset(entropy->ac_stats[tbl], 0, AC_STAT_BINS);
 #ifdef CALCULATE_SPECTRAL_CONDITIONING
       if (cinfo->progressive_mode)
         /* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */
diff --git a/jchuff.c b/jchuff.c
index 8ff817b..f4dfa1c 100644
--- a/jchuff.c
+++ b/jchuff.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2014-2016, 2018-2021, D. R. Commander.
+ * Copyright (C) 2009-2011, 2014-2016, 2018-2022, D. R. Commander.
  * Copyright (C) 2015, Matthieu Darbois.
  * Copyright (C) 2018, Matthias Räncker.
  * Copyright (C) 2020, Arm Limited.
@@ -200,12 +200,12 @@
         entropy->dc_count_ptrs[dctbl] = (long *)
           (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                       257 * sizeof(long));
-      MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * sizeof(long));
+      memset(entropy->dc_count_ptrs[dctbl], 0, 257 * sizeof(long));
       if (entropy->ac_count_ptrs[actbl] == NULL)
         entropy->ac_count_ptrs[actbl] = (long *)
           (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                       257 * sizeof(long));
-      MEMZERO(entropy->ac_count_ptrs[actbl], 257 * sizeof(long));
+      memset(entropy->ac_count_ptrs[actbl], 0, 257 * sizeof(long));
 #endif
     } else {
       /* Compute derived values for Huffman tables */
@@ -315,8 +315,8 @@
    * this lets us detect duplicate VAL entries here, and later
    * allows emit_bits to detect any attempt to emit such symbols.
    */
-  MEMZERO(dtbl->ehufco, sizeof(dtbl->ehufco));
-  MEMZERO(dtbl->ehufsi, sizeof(dtbl->ehufsi));
+  memset(dtbl->ehufco, 0, sizeof(dtbl->ehufco));
+  memset(dtbl->ehufsi, 0, sizeof(dtbl->ehufsi));
 
   /* This is also a convenient place to check for out-of-range
    * and duplicated VAL entries.  We allow 0..255 for AC symbols
@@ -478,7 +478,7 @@
     buffer = _buffer; \
     while (bytes > 0) { \
       bytestocopy = MIN(bytes, state->free_in_buffer); \
-      MEMCOPY(state->next_output_byte, buffer, bytestocopy); \
+      memcpy(state->next_output_byte, buffer, bytestocopy); \
       state->next_output_byte += bytestocopy; \
       buffer += bytestocopy; \
       state->free_in_buffer -= bytestocopy; \
@@ -941,8 +941,8 @@
 
   /* This algorithm is explained in section K.2 of the JPEG standard */
 
-  MEMZERO(bits, sizeof(bits));
-  MEMZERO(codesize, sizeof(codesize));
+  memset(bits, 0, sizeof(bits));
+  memset(codesize, 0, sizeof(codesize));
   for (i = 0; i < 257; i++)
     others[i] = -1;             /* init links to empty */
 
@@ -1044,7 +1044,7 @@
   bits[i]--;
 
   /* Return final symbol counts (only for lengths 0..16) */
-  MEMCOPY(htbl->bits, bits, sizeof(htbl->bits));
+  memcpy(htbl->bits, bits, sizeof(htbl->bits));
 
   /* Return a list of the symbols sorted by code length */
   /* It's not real clear to me why we don't need to consider the codelength
@@ -1083,8 +1083,8 @@
   /* It's important not to apply jpeg_gen_optimal_table more than once
    * per table, because it clobbers the input frequency counts!
    */
-  MEMZERO(did_dc, sizeof(did_dc));
-  MEMZERO(did_ac, sizeof(did_ac));
+  memset(did_dc, 0, sizeof(did_dc));
+  memset(did_ac, 0, sizeof(did_ac));
 
   for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
     compptr = cinfo->cur_comp_info[ci];
diff --git a/jconfig.h b/jconfig.h
index 71c4a77..7eb5f5f 100644
--- a/jconfig.h
+++ b/jconfig.h
@@ -4,10 +4,10 @@
 #define JPEG_LIB_VERSION  62
 
 /* libjpeg-turbo version */
-#define LIBJPEG_TURBO_VERSION  2.1.2
+#define LIBJPEG_TURBO_VERSION  2.1.3
 
 /* libjpeg-turbo version in integer form */
-#define LIBJPEG_TURBO_VERSION_NUMBER  2001002
+#define LIBJPEG_TURBO_VERSION_NUMBER  2001003
 
 /* Support arithmetic encoding */
 /* #define C_ARITH_CODING_SUPPORTED 1 */
@@ -32,37 +32,6 @@
 
 #define BITS_IN_JSAMPLE  8      /* use 8 or 12 */
 
-/* Define to 1 if you have the <locale.h> header file. */
-#define HAVE_LOCALE_H 1
-
-/* Define to 1 if you have the <stddef.h> header file. */
-#define HAVE_STDDEF_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define if you need to include <sys/types.h> to get size_t. */
-/* #undef NEED_SYS_TYPES_H 1 */
-
-/* Define if you have BSD-like bzero and bcopy in <strings.h> rather than
-   memset/memcpy in <string.h>. */
-/* #undef NEED_BSD_STRINGS */
-
-/* Define to 1 if the system has the type `unsigned char'. */
-#define HAVE_UNSIGNED_CHAR 1
-
-/* Define to 1 if the system has the type `unsigned short'. */
-#define HAVE_UNSIGNED_SHORT 1
-
-/* Compiler does not support pointers to undefined structures. */
-/* #undef INCOMPLETE_TYPES_BROKEN */
-
 /* Define if your (broken) compiler shifts signed values as if they were
    unsigned. */
 /* #undef RIGHT_SHIFT_IS_UNSIGNED */
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef const */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef size_t */
diff --git a/jconfig.h.in b/jconfig.h.in
index d4284d9..e018012 100644
--- a/jconfig.h.in
+++ b/jconfig.h.in
@@ -32,37 +32,6 @@
 
 #define BITS_IN_JSAMPLE  @BITS_IN_JSAMPLE@      /* use 8 or 12 */
 
-/* Define to 1 if you have the <locale.h> header file. */
-#cmakedefine HAVE_LOCALE_H 1
-
-/* Define to 1 if you have the <stddef.h> header file. */
-#cmakedefine HAVE_STDDEF_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#cmakedefine HAVE_STDLIB_H 1
-
-/* Define if you need to include <sys/types.h> to get size_t. */
-#cmakedefine NEED_SYS_TYPES_H 1
-
-/* Define if you have BSD-like bzero and bcopy in <strings.h> rather than
-   memset/memcpy in <string.h>. */
-#cmakedefine NEED_BSD_STRINGS 1
-
-/* Define to 1 if the system has the type `unsigned char'. */
-#cmakedefine HAVE_UNSIGNED_CHAR 1
-
-/* Define to 1 if the system has the type `unsigned short'. */
-#cmakedefine HAVE_UNSIGNED_SHORT 1
-
-/* Compiler does not support pointers to undefined structures. */
-#cmakedefine INCOMPLETE_TYPES_BROKEN 1
-
 /* Define if your (broken) compiler shifts signed values as if they were
    unsigned. */
 #cmakedefine RIGHT_SHIFT_IS_UNSIGNED 1
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef const */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef size_t */
diff --git a/jconfig.txt b/jconfig.txt
index 21f35c1..d593da9 100644
--- a/jconfig.txt
+++ b/jconfig.txt
@@ -26,50 +26,6 @@
  * #define the symbol if yes, #undef it if no.
  */
 
-/* Does your compiler support the declaration "unsigned char" ?
- * How about "unsigned short" ?
- */
-#define HAVE_UNSIGNED_CHAR
-#define HAVE_UNSIGNED_SHORT
-
-/* Define "void" as "char" if your compiler doesn't know about type void.
- * NOTE: be sure to define void such that "void *" represents the most general
- * pointer type, e.g., that returned by malloc().
- */
-/* #define void char */
-
-/* Define "const" as empty if your compiler doesn't know the "const" keyword.
- */
-/* #define const */
-
-/* Define this if your system has an ANSI-conforming <stddef.h> file.
- */
-#define HAVE_STDDEF_H
-
-/* Define this if your system has an ANSI-conforming <stdlib.h> file.
- */
-#define HAVE_STDLIB_H
-
-/* Define this if your system does not have an ANSI/SysV <string.h>,
- * but does have a BSD-style <strings.h>.
- */
-#undef NEED_BSD_STRINGS
-
-/* Define this if your system does not provide typedef size_t in any of the
- * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
- * <sys/types.h> instead.
- */
-#undef NEED_SYS_TYPES_H
-
-/* Although a real ANSI C compiler can deal perfectly well with pointers to
- * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
- * and pseudo-ANSI compilers get confused.  To keep one of these bozos happy,
- * define INCOMPLETE_TYPES_BROKEN.  This is not recommended unless you
- * actually get "missing structure definition" warnings or errors while
- * compiling the JPEG code.
- */
-#undef INCOMPLETE_TYPES_BROKEN
-
 /* Define "boolean" as unsigned char, not int, on Windows systems.
  */
 #ifdef _WIN32
diff --git a/jconfigint.h b/jconfigint.h
index af834ff..41952fc 100644
--- a/jconfigint.h
+++ b/jconfigint.h
@@ -26,9 +26,10 @@
 #define PACKAGE_NAME  "libjpeg-turbo"
 
 /* Version number of package */
-#define VERSION  "2.1.2"
+#define VERSION  "2.1.3"
 
 /* The size of `size_t', as computed by sizeof. */
+#include <stdint.h>
 #if __WORDSIZE==64 || defined(_WIN64)
 #define SIZEOF_SIZE_T  8
 #else
diff --git a/jcphuff.c b/jcphuff.c
index 1101987..872e570 100644
--- a/jcphuff.c
+++ b/jcphuff.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1995-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2015, 2018, 2021, D. R. Commander.
+ * Copyright (C) 2011, 2015, 2018, 2021-2022, D. R. Commander.
  * Copyright (C) 2016, 2018, Matthieu Darbois.
  * Copyright (C) 2020, Arm Limited.
  * Copyright (C) 2021, Alex Richardson.
@@ -275,7 +275,7 @@
         entropy->count_ptrs[tbl] = (long *)
           (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                       257 * sizeof(long));
-      MEMZERO(entropy->count_ptrs[tbl], 257 * sizeof(long));
+      memset(entropy->count_ptrs[tbl], 0, 257 * sizeof(long));
     } else {
       /* Compute derived values for Huffman table */
       /* We may do this more than once for a table, but it's not expensive */
@@ -584,8 +584,8 @@
       continue; \
     /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ \
     temp2 ^= temp; \
-    values[k] = temp; \
-    values[k + DCTSIZE2] = temp2; \
+    values[k] = (JCOEF)temp; \
+    values[k + DCTSIZE2] = (JCOEF)temp2; \
     zerobits |= ((size_t)1U) << k; \
   } \
 }
@@ -1062,7 +1062,7 @@
   /* It's important not to apply jpeg_gen_optimal_table more than once
    * per table, because it clobbers the input frequency counts!
    */
-  MEMZERO(did, sizeof(did));
+  memset(did, 0, sizeof(did));
 
   for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
     compptr = cinfo->cur_comp_info[ci];
diff --git a/jcprepct.c b/jcprepct.c
index d59713a..f27cc34 100644
--- a/jcprepct.c
+++ b/jcprepct.c
@@ -3,8 +3,8 @@
  *
  * This file is part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1996, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -289,8 +289,8 @@
                      cinfo->max_h_samp_factor) / compptr->h_samp_factor),
        (JDIMENSION)(3 * rgroup_height));
     /* Copy true buffer row pointers into the middle of the fake row array */
-    MEMCOPY(fake_buffer + rgroup_height, true_buffer,
-            3 * rgroup_height * sizeof(JSAMPROW));
+    memcpy(fake_buffer + rgroup_height, true_buffer,
+           3 * rgroup_height * sizeof(JSAMPROW));
     /* Fill in the above and below wraparound pointers */
     for (i = 0; i < rgroup_height; i++) {
       fake_buffer[i] = true_buffer[2 * rgroup_height + i];
diff --git a/jctrans.c b/jctrans.c
index ab6a218..e121028 100644
--- a/jctrans.c
+++ b/jctrans.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1995-1998, Thomas G. Lane.
  * Modified 2000-2009 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2020, D. R. Commander.
+ * Copyright (C) 2020, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -100,8 +100,8 @@
       qtblptr = &dstinfo->quant_tbl_ptrs[tblno];
       if (*qtblptr == NULL)
         *qtblptr = jpeg_alloc_quant_table((j_common_ptr)dstinfo);
-      MEMCOPY((*qtblptr)->quantval, srcinfo->quant_tbl_ptrs[tblno]->quantval,
-              sizeof((*qtblptr)->quantval));
+      memcpy((*qtblptr)->quantval, srcinfo->quant_tbl_ptrs[tblno]->quantval,
+             sizeof((*qtblptr)->quantval));
       (*qtblptr)->sent_table = FALSE;
     }
   }
diff --git a/jdapimin.c b/jdapimin.c
index 4609b13..f50c27e 100644
--- a/jdapimin.c
+++ b/jdapimin.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1998, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2016, D. R. Commander.
+ * Copyright (C) 2016, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -53,7 +53,7 @@
   {
     struct jpeg_error_mgr *err = cinfo->err;
     void *client_data = cinfo->client_data; /* ignore Purify complaint here */
-    MEMZERO(cinfo, sizeof(struct jpeg_decompress_struct));
+    memset(cinfo, 0, sizeof(struct jpeg_decompress_struct));
     cinfo->err = err;
     cinfo->client_data = client_data;
   }
@@ -92,7 +92,7 @@
   cinfo->master = (struct jpeg_decomp_master *)
     (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
                                 sizeof(my_decomp_master));
-  MEMZERO(cinfo->master, sizeof(my_decomp_master));
+  memset(cinfo->master, 0, sizeof(my_decomp_master));
 }
 
 
diff --git a/jdapistd.c b/jdapistd.c
index 695a620..8827d8a 100644
--- a/jdapistd.c
+++ b/jdapistd.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2015-2020, D. R. Commander.
+ * Copyright (C) 2010, 2015-2020, 2022, D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
@@ -159,6 +159,7 @@
   JDIMENSION input_xoffset;
   boolean reinit_upsampler = FALSE;
   jpeg_component_info *compptr;
+  my_master_ptr master = (my_master_ptr)cinfo->master;
 
   if (cinfo->global_state != DSTATE_SCANNING || cinfo->output_scanline != 0)
     ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
@@ -208,6 +209,11 @@
    */
   *width = *width + input_xoffset - *xoffset;
   cinfo->output_width = *width;
+  if (master->using_merged_upsample && cinfo->max_v_samp_factor == 2) {
+    my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
+    upsample->out_row_width =
+      cinfo->output_width * cinfo->out_color_components;
+  }
 
   /* Set the first and last iMCU columns that we must decompress.  These values
    * will be used in single-scan decompressions.
diff --git a/jdarith.c b/jdarith.c
index 7f0d3a7..21575e8 100644
--- a/jdarith.c
+++ b/jdarith.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Developed 1997-2015 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2015-2020, D. R. Commander.
+ * Copyright (C) 2015-2020, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -210,13 +210,13 @@
   for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
     compptr = cinfo->cur_comp_info[ci];
     if (!cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
-      MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+      memset(entropy->dc_stats[compptr->dc_tbl_no], 0, DC_STAT_BINS);
       /* Reset DC predictions to 0 */
       entropy->last_dc_val[ci] = 0;
       entropy->dc_context[ci] = 0;
     }
     if (!cinfo->progressive_mode || cinfo->Ss) {
-      MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+      memset(entropy->ac_stats[compptr->ac_tbl_no], 0, AC_STAT_BINS);
     }
   }
 
@@ -471,17 +471,17 @@
       if (*thiscoef) {                          /* previously nonzero coef */
         if (arith_decode(cinfo, st + 2)) {
           if (*thiscoef < 0)
-            *thiscoef += m1;
+            *thiscoef += (JCOEF)m1;
           else
-            *thiscoef += p1;
+            *thiscoef += (JCOEF)p1;
         }
         break;
       }
       if (arith_decode(cinfo, st + 1)) {        /* newly nonzero coef */
         if (arith_decode(cinfo, entropy->fixed_bin))
-          *thiscoef = m1;
+          *thiscoef = (JCOEF)m1;
         else
-          *thiscoef = p1;
+          *thiscoef = (JCOEF)p1;
         break;
       }
       st += 3;  k++;
@@ -698,8 +698,8 @@
     /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
      * This ought to be an error condition, but we make it a warning.
      */
-    if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
-        (cinfo->Se < DCTSIZE2 && cinfo->Se != DCTSIZE2 - 1))
+    if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2 - 1 ||
+        cinfo->Ah != 0 || cinfo->Al != 0)
       WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
     /* Select MCU decoding routine */
     entropy->pub.decode_mcu = decode_mcu;
@@ -715,7 +715,7 @@
       if (entropy->dc_stats[tbl] == NULL)
         entropy->dc_stats[tbl] = (unsigned char *)(*cinfo->mem->alloc_small)
           ((j_common_ptr)cinfo, JPOOL_IMAGE, DC_STAT_BINS);
-      MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+      memset(entropy->dc_stats[tbl], 0, DC_STAT_BINS);
       /* Initialize DC predictions to 0 */
       entropy->last_dc_val[ci] = 0;
       entropy->dc_context[ci] = 0;
@@ -727,7 +727,7 @@
       if (entropy->ac_stats[tbl] == NULL)
         entropy->ac_stats[tbl] = (unsigned char *)(*cinfo->mem->alloc_small)
           ((j_common_ptr)cinfo, JPOOL_IMAGE, AC_STAT_BINS);
-      MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+      memset(entropy->ac_stats[tbl], 0, AC_STAT_BINS);
     }
   }
 
diff --git a/jdatadst-tj.c b/jdatadst-tj.c
index fdaa2de..e10d981 100644
--- a/jdatadst-tj.c
+++ b/jdatadst-tj.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * Modified 2009-2012 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2014, 2016, 2019, D. R. Commander.
+ * Copyright (C) 2011, 2014, 2016, 2019, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -23,10 +23,6 @@
 #include "jpeglib.h"
 #include "jerror.h"
 
-#ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare malloc(),free() */
-extern void *malloc(size_t size);
-extern void free(void *ptr);
-#endif
 void jpeg_mem_dest_tj(j_compress_ptr cinfo, unsigned char **outbuffer,
                       unsigned long *outsize, boolean alloc);
 
@@ -101,7 +97,7 @@
   if (nextbuffer == NULL)
     ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
 
-  MEMCOPY(nextbuffer, dest->buffer, dest->bufsize);
+  memcpy(nextbuffer, dest->buffer, dest->bufsize);
 
   free(dest->newbuffer);
 
diff --git a/jdatadst.c b/jdatadst.c
index 246fffb..6b4fed2 100644
--- a/jdatadst.c
+++ b/jdatadst.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * Modified 2009-2012 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2013, 2016, D. R. Commander.
+ * Copyright (C) 2013, 2016, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -23,11 +23,6 @@
 #include "jpeglib.h"
 #include "jerror.h"
 
-#ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare malloc(),free() */
-extern void *malloc(size_t size);
-extern void free(void *ptr);
-#endif
-
 
 /* Expanded data destination object for stdio output */
 
@@ -116,7 +111,7 @@
 {
   my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
 
-  if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) !=
+  if (fwrite(dest->buffer, 1, OUTPUT_BUF_SIZE, dest->outfile) !=
       (size_t)OUTPUT_BUF_SIZE)
     ERREXIT(cinfo, JERR_FILE_WRITE);
 
@@ -141,7 +136,7 @@
   if (nextbuffer == NULL)
     ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
 
-  MEMCOPY(nextbuffer, dest->buffer, dest->bufsize);
+  memcpy(nextbuffer, dest->buffer, dest->bufsize);
 
   free(dest->newbuffer);
 
@@ -175,7 +170,7 @@
 
   /* Write any data remaining in the buffer */
   if (datacount > 0) {
-    if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount)
+    if (fwrite(dest->buffer, 1, datacount, dest->outfile) != datacount)
       ERREXIT(cinfo, JERR_FILE_WRITE);
   }
   fflush(dest->outfile);
diff --git a/jdatasrc.c b/jdatasrc.c
index eadb4a2..e36a30d 100644
--- a/jdatasrc.c
+++ b/jdatasrc.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * Modified 2009-2011 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2013, 2016, D. R. Commander.
+ * Copyright (C) 2013, 2016, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -104,7 +104,7 @@
   my_src_ptr src = (my_src_ptr)cinfo->src;
   size_t nbytes;
 
-  nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);
+  nbytes = fread(src->buffer, 1, INPUT_BUF_SIZE, src->infile);
 
   if (nbytes <= 0) {
     if (src->start_of_file)     /* Treat empty input file as fatal error */
diff --git a/jddctmgr.c b/jddctmgr.c
index 266f446..e78d7be 100644
--- a/jddctmgr.c
+++ b/jddctmgr.c
@@ -6,7 +6,7 @@
  * Modified 2002-2010 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2010, 2015, D. R. Commander.
+ * Copyright (C) 2010, 2015, 2022, D. R. Commander.
  * Copyright (C) 2013, MIPS Technologies, Inc., California.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
@@ -345,7 +345,7 @@
     compptr->dct_table =
       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                   sizeof(multiplier_table));
-    MEMZERO(compptr->dct_table, sizeof(multiplier_table));
+    memset(compptr->dct_table, 0, sizeof(multiplier_table));
     /* Mark multiplier table not yet set up for any method */
     idct->cur_method[ci] = -1;
   }
diff --git a/jdicc.c b/jdicc.c
index a1a5b86..50aa9a9 100644
--- a/jdicc.c
+++ b/jdicc.c
@@ -18,10 +18,6 @@
 #include "jpeglib.h"
 #include "jerror.h"
 
-#ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare malloc() */
-extern void *malloc(size_t size);
-#endif
-
 
 #define ICC_MARKER  (JPEG_APP0 + 2)     /* JPEG marker code for ICC */
 #define ICC_OVERHEAD_LEN  14            /* size of non-profile data in APP2 */
diff --git a/jdinput.c b/jdinput.c
index deec618..1bc5aff 100644
--- a/jdinput.c
+++ b/jdinput.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2016, 2018, D. R. Commander.
+ * Copyright (C) 2010, 2016, 2018, 2022, D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
@@ -264,7 +264,7 @@
     qtbl = (JQUANT_TBL *)
       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                   sizeof(JQUANT_TBL));
-    MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], sizeof(JQUANT_TBL));
+    memcpy(qtbl, cinfo->quant_tbl_ptrs[qtblno], sizeof(JQUANT_TBL));
     compptr->quant_table = qtbl;
   }
 }
diff --git a/jdmarker.c b/jdmarker.c
index b964c3a..f7eba61 100644
--- a/jdmarker.c
+++ b/jdmarker.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1998, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2012, 2015, D. R. Commander.
+ * Copyright (C) 2012, 2015, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -473,7 +473,7 @@
     for (i = 0; i < count; i++)
       INPUT_BYTE(cinfo, huffval[i], return FALSE);
 
-    MEMZERO(&huffval[count], (256 - count) * sizeof(UINT8));
+    memset(&huffval[count], 0, (256 - count) * sizeof(UINT8));
 
     length -= count;
 
@@ -491,8 +491,8 @@
     if (*htblptr == NULL)
       *htblptr = jpeg_alloc_huff_table((j_common_ptr)cinfo);
 
-    MEMCOPY((*htblptr)->bits, bits, sizeof((*htblptr)->bits));
-    MEMCOPY((*htblptr)->huffval, huffval, sizeof((*htblptr)->huffval));
+    memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits));
+    memcpy((*htblptr)->huffval, huffval, sizeof((*htblptr)->huffval));
   }
 
   if (length != 0)
diff --git a/jdmaster.c b/jdmaster.c
index cbc8774..a3690bf 100644
--- a/jdmaster.c
+++ b/jdmaster.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * Modified 2002-2009 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2016, 2019, D. R. Commander.
+ * Copyright (C) 2009-2011, 2016, 2019, 2022, D. R. Commander.
  * Copyright (C) 2013, Linaro Limited.
  * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README.ijg
@@ -417,7 +417,7 @@
   table += (MAXJSAMPLE + 1);    /* allow negative subscripts of simple table */
   cinfo->sample_range_limit = table;
   /* First segment of "simple" table: limit[x] = 0 for x < 0 */
-  MEMZERO(table - (MAXJSAMPLE + 1), (MAXJSAMPLE + 1) * sizeof(JSAMPLE));
+  memset(table - (MAXJSAMPLE + 1), 0, (MAXJSAMPLE + 1) * sizeof(JSAMPLE));
   /* Main part of "simple" table: limit[x] = x */
   for (i = 0; i <= MAXJSAMPLE; i++)
     table[i] = (JSAMPLE)i;
@@ -426,10 +426,10 @@
   for (i = CENTERJSAMPLE; i < 2 * (MAXJSAMPLE + 1); i++)
     table[i] = MAXJSAMPLE;
   /* Second half of post-IDCT table */
-  MEMZERO(table + (2 * (MAXJSAMPLE + 1)),
-          (2 * (MAXJSAMPLE + 1) - CENTERJSAMPLE) * sizeof(JSAMPLE));
-  MEMCOPY(table + (4 * (MAXJSAMPLE + 1) - CENTERJSAMPLE),
-          cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE));
+  memset(table + (2 * (MAXJSAMPLE + 1)), 0,
+         (2 * (MAXJSAMPLE + 1) - CENTERJSAMPLE) * sizeof(JSAMPLE));
+  memcpy(table + (4 * (MAXJSAMPLE + 1) - CENTERJSAMPLE),
+         cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE));
 }
 
 
diff --git a/jdphuff.c b/jdphuff.c
index c6d82ca..9680ebc 100644
--- a/jdphuff.c
+++ b/jdphuff.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1995-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2015-2016, 2018-2021, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -578,9 +578,9 @@
             if (GET_BITS(1)) {
               if ((*thiscoef & p1) == 0) { /* do nothing if already set it */
                 if (*thiscoef >= 0)
-                  *thiscoef += p1;
+                  *thiscoef += (JCOEF)p1;
                 else
-                  *thiscoef += m1;
+                  *thiscoef += (JCOEF)m1;
               }
             }
           } else {
@@ -612,9 +612,9 @@
           if (GET_BITS(1)) {
             if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */
               if (*thiscoef >= 0)
-                *thiscoef += p1;
+                *thiscoef += (JCOEF)p1;
               else
-                *thiscoef += m1;
+                *thiscoef += (JCOEF)m1;
             }
           }
         }
diff --git a/jerror.c b/jerror.c
index 936c4f5..d544702 100644
--- a/jerror.c
+++ b/jerror.c
@@ -3,8 +3,8 @@
  *
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1998, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -189,13 +189,13 @@
 
   /* Format the message into the passed buffer */
   if (isstring)
-    sprintf(buffer, msgtext, err->msg_parm.s);
+    snprintf(buffer, JMSG_LENGTH_MAX, msgtext, err->msg_parm.s);
   else
-    sprintf(buffer, msgtext,
-            err->msg_parm.i[0], err->msg_parm.i[1],
-            err->msg_parm.i[2], err->msg_parm.i[3],
-            err->msg_parm.i[4], err->msg_parm.i[5],
-            err->msg_parm.i[6], err->msg_parm.i[7]);
+    snprintf(buffer, JMSG_LENGTH_MAX, msgtext,
+             err->msg_parm.i[0], err->msg_parm.i[1],
+             err->msg_parm.i[2], err->msg_parm.i[3],
+             err->msg_parm.i[4], err->msg_parm.i[5],
+             err->msg_parm.i[6], err->msg_parm.i[7]);
 }
 
 
diff --git a/jerror.h b/jerror.h
index 4476df2..eb44a11 100644
--- a/jerror.h
+++ b/jerror.h
@@ -5,7 +5,7 @@
  * Copyright (C) 1994-1997, Thomas G. Lane.
  * Modified 1997-2009 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2014, 2017, D. R. Commander.
+ * Copyright (C) 2014, 2017, 2021-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -103,7 +103,7 @@
          "Cannot transcode due to multiple use of quantization table %d")
 JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
 JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
-JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
+JMESSAGE(JERR_NOTIMPL, "Requested features are incompatible")
 JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
 #if JPEG_LIB_VERSION >= 70
 JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
@@ -268,6 +268,7 @@
 #define ERREXITS(cinfo, code, str) \
   ((cinfo)->err->msg_code = (code), \
    strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+   (cinfo)->err->msg_parm.s[JMSG_STR_PARM_MAX - 1] = '\0', \
    (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo)))
 
 #define MAKESTMT(stuff)         do { stuff } while (0)
@@ -324,6 +325,7 @@
 #define TRACEMSS(cinfo, lvl, code, str) \
   ((cinfo)->err->msg_code = (code), \
    strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+   (cinfo)->err->msg_parm.s[JMSG_STR_PARM_MAX - 1] = '\0', \
    (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl)))
 
 #endif /* JERROR_H */
diff --git a/jinclude.h b/jinclude.h
index c1bcf7d..120614b 100644
--- a/jinclude.h
+++ b/jinclude.h
@@ -3,8 +3,8 @@
  *
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1994, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -17,72 +17,117 @@
  * JPEG library.  Most applications need only include jpeglib.h.
  */
 
+#ifndef __JINCLUDE_H__
+#define __JINCLUDE_H__
 
 /* Include auto-config file to find out which system include files we need. */
 
 #include "jconfig.h"            /* auto configuration options */
+#include "jconfigint.h"
 #define JCONFIG_INCLUDED        /* so that jpeglib.h doesn't do it again */
 
 /*
- * We need the NULL macro and size_t typedef.
- * On an ANSI-conforming system it is sufficient to include <stddef.h>.
- * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
- * pull in <sys/types.h> as well.
  * Note that the core JPEG library does not require <stdio.h>;
  * only the default error handler and data source/destination modules do.
  * But we must pull it in because of the references to FILE in jpeglib.h.
  * You can remove those references if you want to compile without <stdio.h>.
  */
 
-#ifdef HAVE_STDDEF_H
 #include <stddef.h>
-#endif
-
-#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
-#endif
-
-#ifdef NEED_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
 #include <stdio.h>
-
-/*
- * We need memory copying and zeroing functions, plus strncpy().
- * ANSI and System V implementations declare these in <string.h>.
- * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
- * Some systems may declare memset and memcpy in <memory.h>.
- *
- * NOTE: we assume the size parameters to these functions are of type size_t.
- * Change the casts in these macros if not!
- */
-
-#ifdef NEED_BSD_STRINGS
-
-#include <strings.h>
-#define MEMZERO(target, size) \
-  bzero((void *)(target), (size_t)(size))
-#define MEMCOPY(dest, src, size) \
-  bcopy((const void *)(src), (void *)(dest), (size_t)(size))
-
-#else /* not BSD, assume ANSI/SysV string lib */
-
 #include <string.h>
-#define MEMZERO(target, size) \
-  memset((void *)(target), 0, (size_t)(size))
-#define MEMCOPY(dest, src, size) \
-  memcpy((void *)(dest), (const void *)(src), (size_t)(size))
-
-#endif
 
 /*
- * The modules that use fread() and fwrite() always invoke them through
- * these macros.  On some systems you may need to twiddle the argument casts.
- * CAUTION: argument order is different from underlying functions!
+ * These macros/inline functions facilitate using Microsoft's "safe string"
+ * functions with Visual Studio builds without the need to scatter #ifdefs
+ * throughout the code base.
  */
 
-#define JFREAD(file, buf, sizeofbuf) \
-  ((size_t)fread((void *)(buf), (size_t)1, (size_t)(sizeofbuf), (file)))
-#define JFWRITE(file, buf, sizeofbuf) \
-  ((size_t)fwrite((const void *)(buf), (size_t)1, (size_t)(sizeofbuf), (file)))
+
+#ifndef NO_GETENV
+
+#ifdef _MSC_VER
+
+static INLINE int GETENV_S(char *buffer, size_t buffer_size, const char *name)
+{
+  size_t required_size;
+
+  return (int)getenv_s(&required_size, buffer, buffer_size, name);
+}
+
+#else /* _MSC_VER */
+
+#include <errno.h>
+
+/* This provides a similar interface to the Microsoft/C11 getenv_s() function,
+ * but other than parameter validation, it has no advantages over getenv().
+ */
+
+static INLINE int GETENV_S(char *buffer, size_t buffer_size, const char *name)
+{
+  char *env;
+
+  if (!buffer) {
+    if (buffer_size == 0)
+      return 0;
+    else
+      return (errno = EINVAL);
+  }
+  if (buffer_size == 0)
+    return (errno = EINVAL);
+  if (!name) {
+    *buffer = 0;
+    return 0;
+  }
+
+  env = getenv(name);
+  if (!env)
+  {
+    *buffer = 0;
+    return 0;
+  }
+
+  if (strlen(env) + 1 > buffer_size) {
+    *buffer = 0;
+    return ERANGE;
+  }
+
+  strncpy(buffer, env, buffer_size);
+
+  return 0;
+}
+
+#endif /* _MSC_VER */
+
+#endif /* NO_GETENV */
+
+
+#ifndef NO_PUTENV
+
+#ifdef _WIN32
+
+#define PUTENV_S(name, value)  _putenv_s(name, value)
+
+#else
+
+/* This provides a similar interface to the Microsoft _putenv_s() function, but
+ * other than parameter validation, it has no advantages over setenv().
+ */
+
+static INLINE int PUTENV_S(const char *name, const char *value)
+{
+  if (!name || !value)
+    return (errno = EINVAL);
+
+  setenv(name, value, 1);
+
+  return errno;
+}
+
+#endif /* _WIN32 */
+
+#endif /* NO_PUTENV */
+
+
+#endif /* JINCLUDE_H */
diff --git a/jmemmgr.c b/jmemmgr.c
index 70b8ec0..8f5a4ab 100644
--- a/jmemmgr.c
+++ b/jmemmgr.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2016, 2021, D. R. Commander.
+ * Copyright (C) 2016, 2021-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -37,12 +37,6 @@
 #endif
 #include <limits.h>
 
-#ifndef NO_GETENV
-#ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare getenv() */
-extern char *getenv(const char *name);
-#endif
-#endif
-
 
 LOCAL(size_t)
 round_up_pow2(size_t a, size_t b)
@@ -1162,12 +1156,16 @@
    */
 #ifndef NO_GETENV
   {
-    char *memenv;
+    char memenv[30] = { 0 };
 
-    if ((memenv = getenv("JPEGMEM")) != NULL) {
+    if (!GETENV_S(memenv, 30, "JPEGMEM") && strlen(memenv) > 0) {
       char ch = 'x';
 
+#ifdef _MSC_VER
+      if (sscanf_s(memenv, "%ld%c", &max_to_use, &ch, 1) > 0) {
+#else
       if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {
+#endif
         if (ch == 'm' || ch == 'M')
           max_to_use *= 1000L;
         mem->pub.max_memory_to_use = max_to_use * 1000L;
diff --git a/jmemnobs.c b/jmemnobs.c
index 089be8f..cd6571b 100644
--- a/jmemnobs.c
+++ b/jmemnobs.c
@@ -22,11 +22,6 @@
 #include "jpeglib.h"
 #include "jmemsys.h"            /* import the system-dependent declarations */
 
-#ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare malloc(),free() */
-extern void *malloc(size_t size);
-extern void free(void *ptr);
-#endif
-
 
 /*
  * Memory allocation and freeing are controlled by the regular library
diff --git a/jmorecfg.h b/jmorecfg.h
index fb3a9cf..b33a991 100644
--- a/jmorecfg.h
+++ b/jmorecfg.h
@@ -100,11 +100,7 @@
 
 /* UINT16 must hold at least the values 0..65535. */
 
-#ifdef HAVE_UNSIGNED_SHORT
 typedef unsigned short UINT16;
-#else /* not HAVE_UNSIGNED_SHORT */
-typedef unsigned int UINT16;
-#endif /* HAVE_UNSIGNED_SHORT */
 
 /* INT16 must hold at least the values -32768..32767. */
 
diff --git a/jpegint.h b/jpegint.h
index 8c85347..6af9e2a 100644
--- a/jpegint.h
+++ b/jpegint.h
@@ -373,12 +373,3 @@
 
 /* Arithmetic coding probability estimation tables in jaricom.c */
 extern const JLONG jpeg_aritab[];
-
-/* Suppress undefined-structure complaints if necessary. */
-
-#ifdef INCOMPLETE_TYPES_BROKEN
-#ifndef AM_MEMORY_MANAGER       /* only jmemmgr.c defines these */
-struct jvirt_sarray_control { long dummy; };
-struct jvirt_barray_control { long dummy; };
-#endif
-#endif /* INCOMPLETE_TYPES_BROKEN */
diff --git a/jpegtran.1 b/jpegtran.1
deleted file mode 100644
index 5b1ded2..0000000
--- a/jpegtran.1
+++ /dev/null
@@ -1,362 +0,0 @@
-.TH JPEGTRAN 1 "13 July 2021"
-.SH NAME
-jpegtran \- lossless transformation of JPEG files
-.SH SYNOPSIS
-.B jpegtran
-[
-.I options
-]
-[
-.I filename
-]
-.LP
-.SH DESCRIPTION
-.LP
-.B jpegtran
-performs various useful transformations of JPEG files.
-It can translate the coded representation from one variant of JPEG to another,
-for example from baseline JPEG to progressive JPEG or vice versa.  It can also
-perform some rearrangements of the image data, for example turning an image
-from landscape to portrait format by rotation.
-.PP
-For EXIF files and JPEG files containing Exif data, you may prefer to use
-.B exiftran
-instead.
-.PP
-.B jpegtran
-works by rearranging the compressed data (DCT coefficients), without
-ever fully decoding the image.  Therefore, its transformations are lossless:
-there is no image degradation at all, which would not be true if you used
-.B djpeg
-followed by
-.B cjpeg
-to accomplish the same conversion.  But by the same token,
-.B jpegtran
-cannot perform lossy operations such as changing the image quality.  However,
-while the image data is losslessly transformed, metadata can be removed.  See
-the
-.B \-copy
-option for specifics.
-.PP
-.B jpegtran
-reads the named JPEG/JFIF file, or the standard input if no file is
-named, and produces a JPEG/JFIF file on the standard output.
-.SH OPTIONS
-All switch names may be abbreviated; for example,
-.B \-optimize
-may be written
-.B \-opt
-or
-.BR \-o .
-Upper and lower case are equivalent.
-British spellings are also accepted (e.g.,
-.BR \-optimise ),
-though for brevity these are not mentioned below.
-.PP
-To specify the coded JPEG representation used in the output file,
-.B jpegtran
-accepts a subset of the switches recognized by
-.BR cjpeg :
-.TP
-.B \-optimize
-Perform optimization of entropy encoding parameters.
-.TP
-.B \-progressive
-Create progressive JPEG file.
-.TP
-.BI \-restart " N"
-Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
-attached to the number.
-.TP
-.B \-arithmetic
-Use arithmetic coding.
-.TP
-.BI \-scans " file"
-Use the scan script given in the specified text file.
-.PP
-See
-.BR cjpeg (1)
-for more details about these switches.
-If you specify none of these switches, you get a plain baseline-JPEG output
-file.  The quality setting and so forth are determined by the input file.
-.PP
-The image can be losslessly transformed by giving one of these switches:
-.TP
-.B \-flip horizontal
-Mirror image horizontally (left-right).
-.TP
-.B \-flip vertical
-Mirror image vertically (top-bottom).
-.TP
-.B \-rotate 90
-Rotate image 90 degrees clockwise.
-.TP
-.B \-rotate 180
-Rotate image 180 degrees.
-.TP
-.B \-rotate 270
-Rotate image 270 degrees clockwise (or 90 ccw).
-.TP
-.B \-transpose
-Transpose image (across UL-to-LR axis).
-.TP
-.B \-transverse
-Transverse transpose (across UR-to-LL axis).
-.PP
-The transpose transformation has no restrictions regarding image dimensions.
-The other transformations operate rather oddly if the image dimensions are not
-a multiple of the iMCU size (usually 8 or 16 pixels), because they can only
-transform complete blocks of DCT coefficient data in the desired way.
-.PP
-.BR jpegtran 's
-default behavior when transforming an odd-size image is designed
-to preserve exact reversibility and mathematical consistency of the
-transformation set.  As stated, transpose is able to flip the entire image
-area.  Horizontal mirroring leaves any partial iMCU column at the right edge
-untouched, but is able to flip all rows of the image.  Similarly, vertical
-mirroring leaves any partial iMCU row at the bottom edge untouched, but is
-able to flip all columns.  The other transforms can be built up as sequences
-of transpose and flip operations; for consistency, their actions on edge
-pixels are defined to be the same as the end result of the corresponding
-transpose-and-flip sequence.
-.PP
-For practical use, you may prefer to discard any untransformable edge pixels
-rather than having a strange-looking strip along the right and/or bottom edges
-of a transformed image.  To do this, add the
-.B \-trim
-switch:
-.TP
-.B \-trim
-Drop non-transformable edge blocks.
-.IP
-Obviously, a transformation with
-.B \-trim
-is not reversible, so strictly speaking
-.B jpegtran
-with this switch is not lossless.  Also, the expected mathematical
-equivalences between the transformations no longer hold.  For example,
-.B \-rot 270 -trim
-trims only the bottom edge, but
-.B \-rot 90 -trim
-followed by
-.B \-rot 180 -trim
-trims both edges.
-.TP
-.B \-perfect
-If you are only interested in perfect transformations, add the
-.B \-perfect
-switch.  This causes
-.B jpegtran
-to fail with an error if the transformation is not perfect.
-.IP
-For example, you may want to do
-.IP
-.B (jpegtran \-rot 90 -perfect
-.I foo.jpg
-.B || djpeg
-.I foo.jpg
-.B | pnmflip \-r90 | cjpeg)
-.IP
-to do a perfect rotation, if available, or an approximated one if not.
-.PP
-This version of \fBjpegtran\fR also offers a lossless crop option, which
-discards data outside of a given image region but losslessly preserves what is
-inside.  Like the rotate and flip transforms, lossless crop is restricted by
-the current JPEG format; the upper left corner of the selected region must fall
-on an iMCU boundary.  If it doesn't, then it is silently moved up and/or left
-to the nearest iMCU boundary (the lower right corner is unchanged.)  Thus, the
-output image covers at least the requested region, but it may cover more.  The
-adjustment of the region dimensions may be optionally disabled by attaching an
-'f' character ("force") to the width or height number.
-
-The image can be losslessly cropped by giving the switch:
-.TP
-.B \-crop WxH+X+Y
-Crop the image to a rectangular region of width W and height H, starting at
-point X,Y.  The lossless crop feature discards data outside of a given image
-region but losslessly preserves what is inside.  Like the rotate and flip
-transforms, lossless crop is restricted by the current JPEG format; the upper
-left corner of the selected region must fall on an iMCU boundary.  If it
-doesn't, then it is silently moved up and/or left to the nearest iMCU boundary
-(the lower right corner is unchanged.)
-.PP
-If W or H is larger than the width/height of the input image, then the output
-image is expanded in size, and the expanded region is filled in with zeros
-(neutral gray).  Attaching an 'f' character ("flatten") to the width number
-will cause each block in the expanded region to be filled in with the DC
-coefficient of the nearest block in the input image rather than grayed out.
-Attaching an 'r' character ("reflect") to the width number will cause the
-expanded region to be filled in with repeated reflections of the input image
-rather than grayed out.
-.PP
-A complementary lossless wipe option is provided to discard (gray out) data
-inside a given image region while losslessly preserving what is outside:
-.TP
-.B \-wipe WxH+X+Y
-Wipe (gray out) a rectangular region of width W and height H from the input
-image, starting at point X,Y.
-.PP
-Attaching an 'f' character ("flatten") to the width number will cause the
-region to be filled with the average of adjacent blocks rather than grayed out.
-If the wipe region and the region outside the wipe region, when adjusted to the
-nearest iMCU boundary, form two horizontally adjacent rectangles, then
-attaching an 'r' character ("reflect") to the width number will cause the wipe
-region to be filled with repeated reflections of the outside region rather than
-grayed out.
-.PP
-A lossless drop option is also provided, which allows another JPEG image to be
-inserted ("dropped") into the input image data at a given position, replacing
-the existing image data at that position:
-.TP
-.B \-drop +X+Y filename
-Drop (insert) another image at point X,Y
-.PP
-Both the input image and the drop image must have the same subsampling level.
-It is best if they also have the same quantization (quality.)  Otherwise, the
-quantization of the output image will be adapted to accommodate the higher of
-the input image quality and the drop image quality.  The trim option can be
-used with the drop option to requantize the drop image to match the input
-image.  Note that a grayscale image can be dropped into a full-color image or
-vice versa, as long as the full-color image has no vertical subsampling.  If
-the input image is grayscale and the drop image is full-color, then the
-chrominance channels from the drop image will be discarded.
-.PP
-Other not-strictly-lossless transformation switches are:
-.TP
-.B \-grayscale
-Force grayscale output.
-.IP
-This option discards the chrominance channels if the input image is YCbCr
-(ie, a standard color JPEG), resulting in a grayscale JPEG file.  The
-luminance channel is preserved exactly, so this is a better method of reducing
-to grayscale than decompression, conversion, and recompression.  This switch
-is particularly handy for fixing a monochrome picture that was mistakenly
-encoded as a color JPEG.  (In such a case, the space savings from getting rid
-of the near-empty chroma channels won't be large; but the decoding time for
-a grayscale JPEG is substantially less than that for a color JPEG.)
-.PP
-.B jpegtran
-also recognizes these switches that control what to do with "extra" markers,
-such as comment blocks:
-.TP
-.B \-copy none
-Copy no extra markers from source file.  This setting suppresses all
-comments and other metadata in the source file.
-.TP
-.B \-copy comments
-Copy only comment markers.  This setting copies comments from the source file
-but discards any other metadata.
-.TP
-.B \-copy icc
-Copy only ICC profile markers.  This setting copies the ICC profile from the
-source file but discards any other metadata.
-.TP
-.B \-copy all
-Copy all extra markers.  This setting preserves miscellaneous markers
-found in the source file, such as JFIF thumbnails, Exif data, and Photoshop
-settings.  In some files, these extra markers can be sizable.  Note that this
-option will copy thumbnails as-is; they will not be transformed.
-.PP
-The default behavior is \fB-copy comments\fR.  (Note: in IJG releases v6 and
-v6a, \fBjpegtran\fR always did the equivalent of \fB-copy none\fR.)
-.PP
-Additional switches recognized by jpegtran are:
-.TP
-.BI \-icc " file"
-Embed ICC color management profile contained in the specified file.  Note that
-this will cause \fBjpegtran\fR to ignore any APP2 markers in the input file,
-even if \fB-copy all\fR or \fB-copy icc\fR is specified.
-.TP
-.BI \-maxmemory " N"
-Set limit for amount of memory to use in processing large images.  Value is
-in thousands of bytes, or millions of bytes if "M" is attached to the
-number.  For example,
-.B \-max 4m
-selects 4000000 bytes.  If more space is needed, an error will occur.
-.TP
-.BI \-maxscans " N"
-Abort if the input image contains more than
-.I N
-scans.  This feature demonstrates a method by which applications can guard
-against denial-of-service attacks instigated by specially-crafted malformed
-JPEG images containing numerous scans with missing image data or image data
-consisting only of "EOB runs" (a feature of progressive JPEG images that allows
-potentially hundreds of thousands of adjoining zero-value pixels to be
-represented using only a few bytes.)  Attempting to transform such malformed
-JPEG images can cause excessive CPU activity, since the decompressor must fully
-process each scan (even if the scan is corrupt) before it can proceed to the
-next scan.
-.TP
-.BI \-outfile " name"
-Send output image to the named file, not to standard output.
-.TP
-.BI \-report
-Report transformation progress.
-.TP
-.BI \-strict
-Treat all warnings as fatal.  This feature also demonstrates a method by which
-applications can guard against attacks instigated by specially-crafted
-malformed JPEG images.  Enabling this option will cause the decompressor to
-abort if the input image contains incomplete or corrupt image data.
-.TP
-.B \-verbose
-Enable debug printout.  More
-.BR \-v 's
-give more output.  Also, version information is printed at startup.
-.TP
-.B \-debug
-Same as
-.BR \-verbose .
-.TP
-.B \-version
-Print version information and exit.
-.SH EXAMPLES
-.LP
-This example converts a baseline JPEG file to progressive form:
-.IP
-.B jpegtran \-progressive
-.I foo.jpg
-.B >
-.I fooprog.jpg
-.PP
-This example rotates an image 90 degrees clockwise, discarding any
-unrotatable edge pixels:
-.IP
-.B jpegtran \-rot 90 -trim
-.I foo.jpg
-.B >
-.I foo90.jpg
-.SH ENVIRONMENT
-.TP
-.B JPEGMEM
-If this environment variable is set, its value is the default memory limit.
-The value is specified as described for the
-.B \-maxmemory
-switch.
-.B JPEGMEM
-overrides the default value specified when the program was compiled, and
-itself is overridden by an explicit
-.BR \-maxmemory .
-.SH SEE ALSO
-.BR cjpeg (1),
-.BR djpeg (1),
-.BR rdjpgcom (1),
-.BR wrjpgcom (1)
-.br
-Wallace, Gregory K.  "The JPEG Still Picture Compression Standard",
-Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
-.SH AUTHOR
-Independent JPEG Group
-.PP
-This file was modified by The libjpeg-turbo Project to include only information
-relevant to libjpeg-turbo and to wordsmith certain sections.
-.SH BUGS
-The transform options can't transform odd-size images perfectly.  Use
-.B \-trim
-or
-.B \-perfect
-if you don't like the results.
-.PP
-The entire image is read into memory and then written out again, even in
-cases where this isn't really necessary.  Expect swapping on large images,
-especially when using the more complex transform options.
diff --git a/jpegtran.c b/jpegtran.c
index 4af0349..0d89a0a 100644
--- a/jpegtran.c
+++ b/jpegtran.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1995-2019, Thomas G. Lane, Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2014, 2017, 2019-2021, D. R. Commander.
+ * Copyright (C) 2010, 2014, 2017, 2019-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -14,6 +14,10 @@
  * provides some lossless and sort-of-lossless transformations of JPEG data.
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
 #include "transupp.h"           /* Support routines for jpegtran */
 #include "jversion.h"           /* for version message */
diff --git a/jstdhuff.c b/jstdhuff.c
index 036d649..345b513 100644
--- a/jstdhuff.c
+++ b/jstdhuff.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1998, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2013, D. R. Commander.
+ * Copyright (C) 2013, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -29,7 +29,7 @@
     return;
 
   /* Copy the number-of-symbols-of-each-code-length counts */
-  MEMCOPY((*htblptr)->bits, bits, sizeof((*htblptr)->bits));
+  memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits));
 
   /* Validate the counts.  We do this here mainly so we can copy the right
    * number of symbols from the val[] array, without risking marching off
@@ -41,8 +41,9 @@
   if (nsymbols < 1 || nsymbols > 256)
     ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
 
-  MEMCOPY((*htblptr)->huffval, val, nsymbols * sizeof(UINT8));
-  MEMZERO(&((*htblptr)->huffval[nsymbols]), (256 - nsymbols) * sizeof(UINT8));
+  memcpy((*htblptr)->huffval, val, nsymbols * sizeof(UINT8));
+  memset(&((*htblptr)->huffval[nsymbols]), 0,
+         (256 - nsymbols) * sizeof(UINT8));
 
   /* Initialize sent_table FALSE so table will be written to JPEG file. */
   (*htblptr)->sent_table = FALSE;
diff --git a/jutils.c b/jutils.c
index 5c5bb17..d862716 100644
--- a/jutils.c
+++ b/jutils.c
@@ -3,8 +3,8 @@
  *
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1996, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code
- * relevant to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -110,7 +110,7 @@
   for (row = num_rows; row > 0; row--) {
     inptr = *input_array++;
     outptr = *output_array++;
-    MEMCOPY(outptr, inptr, count);
+    memcpy(outptr, inptr, count);
   }
 }
 
@@ -120,7 +120,7 @@
                 JDIMENSION num_blocks)
 /* Copy a row of coefficient blocks from one place to another. */
 {
-  MEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * sizeof(JCOEF)));
+  memcpy(output_row, input_row, num_blocks * (DCTSIZE2 * sizeof(JCOEF)));
 }
 
 
@@ -129,5 +129,5 @@
 /* Zero out a chunk of memory. */
 /* This might be sample-array data, block-array data, or alloc_large data. */
 {
-  MEMZERO(target, bytestozero);
+  memset(target, 0, bytestozero);
 }
diff --git a/jversion.h b/jversion.h
index 2ab534a..63db95b 100644
--- a/jversion.h
+++ b/jversion.h
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2012-2021, D. R. Commander.
+ * Copyright (C) 2010, 2012-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -37,7 +37,7 @@
  */
 
 #define JCOPYRIGHT \
-  "Copyright (C) 2009-2021 D. R. Commander\n" \
+  "Copyright (C) 2009-2022 D. R. Commander\n" \
   "Copyright (C) 2015, 2020 Google, Inc.\n" \
   "Copyright (C) 2019-2020 Arm Limited\n" \
   "Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
@@ -51,4 +51,4 @@
   "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
 
 #define JCOPYRIGHT_SHORT \
-  "Copyright (C) 1991-2021 The libjpeg-turbo Project and many others"
+  "Copyright (C) 1991-2022 The libjpeg-turbo Project and many others"
diff --git a/md5/md5hl.c b/md5/md5hl.c
index 8a4a762..849a136 100644
--- a/md5/md5hl.c
+++ b/md5/md5hl.c
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  * libjpeg-turbo Modifications:
- * Copyright (C)2016, 2018-2019 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2016, 2018-2019, 2022 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -34,6 +34,10 @@
  * ----------------------------------------------------------------------------
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
diff --git a/rdbmp.c b/rdbmp.c
index 358a026..433ebe2 100644
--- a/rdbmp.c
+++ b/rdbmp.c
@@ -6,7 +6,7 @@
  * Modified 2009-2017 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
  * Modified 2011 by Siarhei Siamashka.
- * Copyright (C) 2015, 2017-2018, 2021, D. R. Commander.
+ * Copyright (C) 2015, 2017-2018, 2021-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -39,7 +39,7 @@
 
 
 #define ReadOK(file, buffer, len) \
-  (JFREAD(file, buffer, len) == ((size_t)(len)))
+  (fread(buffer, 1, len, file) == ((size_t)(len)))
 
 static int alpha_index[JPEG_NUMCS] = {
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
@@ -125,7 +125,8 @@
     break;
   }
 
-  if (sinfo->cinfo->in_color_space == JCS_UNKNOWN && gray)
+  if ((sinfo->cinfo->in_color_space == JCS_UNKNOWN ||
+       sinfo->cinfo->in_color_space == JCS_RGB) && gray)
     sinfo->cinfo->in_color_space = JCS_GRAYSCALE;
 
   if (sinfo->cinfo->in_color_space == JCS_GRAYSCALE && !gray)
@@ -245,7 +246,7 @@
    */
   outptr = source->pub.buffer[0];
   if (cinfo->in_color_space == JCS_EXT_BGR) {
-    MEMCOPY(outptr, inptr, source->row_width);
+    memcpy(outptr, inptr, source->row_width);
   } else if (cinfo->in_color_space == JCS_CMYK) {
     for (col = cinfo->image_width; col > 0; col--) {
       JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
@@ -309,7 +310,7 @@
   outptr = source->pub.buffer[0];
   if (cinfo->in_color_space == JCS_EXT_BGRX ||
       cinfo->in_color_space == JCS_EXT_BGRA) {
-    MEMCOPY(outptr, inptr, source->row_width);
+    memcpy(outptr, inptr, source->row_width);
   } else if (cinfo->in_color_space == JCS_CMYK) {
     for (col = cinfo->image_width; col > 0; col--) {
       JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++;
diff --git a/rdgif.c b/rdgif.c
index c814c6b..bdf7401 100644
--- a/rdgif.c
+++ b/rdgif.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * Modified 2019 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2021, D. R. Commander.
+ * Copyright (C) 2021-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -45,7 +45,7 @@
 
 
 #define ReadOK(file, buffer, len) \
-  (JFREAD(file, buffer, len) == ((size_t)(len)))
+  (fread(buffer, 1, len, file) == ((size_t)(len)))
 
 
 #define MAXCOLORMAPSIZE  256    /* max # of colors in a GIF colormap */
@@ -345,7 +345,7 @@
 ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap)
 /* Read a GIF colormap */
 {
-  int i;
+  int i, gray = 1;
 
   for (i = 0; i < cmaplen; i++) {
 #if BITS_IN_JSAMPLE == 8
@@ -356,6 +356,14 @@
     cmap[CM_RED][i]   = (JSAMPLE)UPSCALE(ReadByte(sinfo));
     cmap[CM_GREEN][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo));
     cmap[CM_BLUE][i]  = (JSAMPLE)UPSCALE(ReadByte(sinfo));
+    if (cmap[CM_RED][i] != cmap[CM_GREEN][i] ||
+        cmap[CM_GREEN][i] != cmap[CM_BLUE][i])
+      gray = 0;
+  }
+
+  if (sinfo->cinfo->in_color_space == JCS_RGB && gray) {
+    sinfo->cinfo->in_color_space = JCS_GRAYSCALE;
+    sinfo->cinfo->input_components = 1;
   }
 }
 
@@ -516,10 +524,15 @@
     source->pub.get_pixel_rows = get_pixel_rows;
   }
 
+  if (cinfo->in_color_space != JCS_GRAYSCALE) {
+    cinfo->in_color_space = JCS_RGB;
+    cinfo->input_components = NUMCOLORS;
+  }
+
   /* Create compressor input buffer. */
   source->pub.buffer = (*cinfo->mem->alloc_sarray)
-    ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)width * NUMCOLORS,
-     (JDIMENSION)1);
+    ((j_common_ptr)cinfo, JPOOL_IMAGE,
+     (JDIMENSION)width * cinfo->input_components, (JDIMENSION)1);
   source->pub.buffer_height = 1;
 
   /* Pad colormap for safety. */
@@ -530,8 +543,6 @@
   }
 
   /* Return info about the image. */
-  cinfo->in_color_space = JCS_RGB;
-  cinfo->input_components = NUMCOLORS;
   cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
   cinfo->image_width = width;
   cinfo->image_height = height;
@@ -556,11 +567,18 @@
   register JSAMPARRAY colormap = source->colormap;
 
   ptr = source->pub.buffer[0];
-  for (col = cinfo->image_width; col > 0; col--) {
-    c = LZWReadByte(source);
-    *ptr++ = colormap[CM_RED][c];
-    *ptr++ = colormap[CM_GREEN][c];
-    *ptr++ = colormap[CM_BLUE][c];
+  if (cinfo->in_color_space == JCS_GRAYSCALE) {
+    for (col = cinfo->image_width; col > 0; col--) {
+      c = LZWReadByte(source);
+      *ptr++ = colormap[CM_RED][c];
+    }
+  } else {
+    for (col = cinfo->image_width; col > 0; col--) {
+      c = LZWReadByte(source);
+      *ptr++ = colormap[CM_RED][c];
+      *ptr++ = colormap[CM_GREEN][c];
+      *ptr++ = colormap[CM_BLUE][c];
+    }
   }
   return 1;
 }
@@ -646,11 +664,18 @@
      FALSE);
   /* Scan the row, expand colormap, and output */
   ptr = source->pub.buffer[0];
-  for (col = cinfo->image_width; col > 0; col--) {
-    c = *sptr++;
-    *ptr++ = colormap[CM_RED][c];
-    *ptr++ = colormap[CM_GREEN][c];
-    *ptr++ = colormap[CM_BLUE][c];
+  if (cinfo->in_color_space == JCS_GRAYSCALE) {
+    for (col = cinfo->image_width; col > 0; col--) {
+      c = *sptr++;
+      *ptr++ = colormap[CM_RED][c];
+    }
+  } else {
+    for (col = cinfo->image_width; col > 0; col--) {
+      c = *sptr++;
+      *ptr++ = colormap[CM_RED][c];
+      *ptr++ = colormap[CM_GREEN][c];
+      *ptr++ = colormap[CM_BLUE][c];
+    }
   }
   source->cur_row_number++;     /* for next time */
   return 1;
diff --git a/rdjpgcom.1 b/rdjpgcom.1
deleted file mode 100644
index 97611df..0000000
--- a/rdjpgcom.1
+++ /dev/null
@@ -1,63 +0,0 @@
-.TH RDJPGCOM 1 "02 April 2009"
-.SH NAME
-rdjpgcom \- display text comments from a JPEG file
-.SH SYNOPSIS
-.B rdjpgcom
-[
-.B \-raw
-]
-[
-.B \-verbose
-]
-[
-.I filename
-]
-.LP
-.SH DESCRIPTION
-.LP
-.B rdjpgcom
-reads the named JPEG/JFIF file, or the standard input if no file is named,
-and prints any text comments found in the file on the standard output.
-.PP
-The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
-Although the standard doesn't actually define what COM blocks are for, they
-are widely used to hold user-supplied text strings.  This lets you add
-annotations, titles, index terms, etc to your JPEG files, and later retrieve
-them as text.  COM blocks do not interfere with the image stored in the JPEG
-file.  The maximum size of a COM block is 64K, but you can have as many of
-them as you like in one JPEG file.
-.SH OPTIONS
-.TP
-.B \-raw
-Normally
-.B rdjpgcom
-escapes non-printable characters in comments, for security reasons.
-This option avoids that.
-.PP
-.B \-verbose
-Causes
-.B rdjpgcom
-to also display the JPEG image dimensions.
-.PP
-Switch names may be abbreviated, and are not case sensitive.
-.SH HINTS
-.B rdjpgcom
-does not depend on the IJG JPEG library.  Its source code is intended as an
-illustration of the minimum amount of code required to parse a JPEG file
-header correctly.
-.PP
-In
-.B \-verbose
-mode,
-.B rdjpgcom
-will also attempt to print the contents of any "APP12" markers as text.
-Some digital cameras produce APP12 markers containing useful textual
-information.  If you like, you can modify the source code to print
-other APPn marker types as well.
-.SH SEE ALSO
-.BR cjpeg (1),
-.BR djpeg (1),
-.BR jpegtran (1),
-.BR wrjpgcom (1)
-.SH AUTHOR
-Independent JPEG Group
diff --git a/rdjpgcom.c b/rdjpgcom.c
index 620270e..9910a63 100644
--- a/rdjpgcom.c
+++ b/rdjpgcom.c
@@ -4,8 +4,8 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1997, Thomas G. Lane.
  * Modified 2009 by Bill Allombert, Guido Vollbeding.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -15,12 +15,14 @@
  * JPEG markers.
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #define JPEG_CJPEG_DJPEG        /* to get the command-line config symbols */
 #include "jinclude.h"           /* get auto-config symbols, <stdio.h> */
 
-#ifdef HAVE_LOCALE_H
 #include <locale.h>             /* Bill Allombert: use locale for isprint */
-#endif
 #include <ctype.h>              /* to declare isupper(), tolower() */
 #ifdef USE_SETMODE
 #include <fcntl.h>              /* to declare setmode()'s parameter macros */
@@ -223,9 +225,7 @@
   int lastch = 0;
 
   /* Bill Allombert: set locale properly for isprint */
-#ifdef HAVE_LOCALE_H
   setlocale(LC_CTYPE, "");
-#endif
 
   /* Get the marker parameter length count */
   length = read_2_bytes();
@@ -253,7 +253,7 @@
     } else if (isprint(ch)) {
       putc(ch, stdout);
     } else {
-      printf("\\%03o", ch);
+      printf("\\%03o", (unsigned int)ch);
     }
     lastch = ch;
     length--;
@@ -261,9 +261,7 @@
   printf("\n");
 
   /* Bill Allombert: revert to C locale */
-#ifdef HAVE_LOCALE_H
   setlocale(LC_CTYPE, "C");
-#endif
 }
 
 
diff --git a/rdppm.c b/rdppm.c
index 9699ca5..294749a 100644
--- a/rdppm.c
+++ b/rdppm.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * Modified 2009 by Bill Allombert, Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2015-2017, 2020-2021, D. R. Commander.
+ * Copyright (C) 2015-2017, 2020-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -48,7 +48,7 @@
 
 
 #define ReadOK(file, buffer, len) \
-  (JFREAD(file, buffer, len) == ((size_t)(len)))
+  (fread(buffer, 1, len, file) == ((size_t)(len)))
 
 static int alpha_index[JPEG_NUMCS] = {
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
@@ -178,16 +178,16 @@
   ptr = source->pub.buffer[0];
   if (maxval == MAXJSAMPLE) {
     if (aindex >= 0)
-      GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),
+      GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
                          ptr[aindex] = 0xFF;)
     else
-      GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),)
+      GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
   } else {
     if (aindex >= 0)
       GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
                          ptr[aindex] = 0xFF;)
     else
-      GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],)
+      GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
   }
   return 1;
 }
@@ -208,7 +208,7 @@
   ptr = source->pub.buffer[0];
   if (maxval == MAXJSAMPLE) {
     for (col = cinfo->image_width; col > 0; col--) {
-      JSAMPLE gray = read_pbm_integer(cinfo, infile, maxval);
+      JSAMPLE gray = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
       rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
       ptr += 4;
     }
@@ -252,16 +252,16 @@
   ptr = source->pub.buffer[0];
   if (maxval == MAXJSAMPLE) {
     if (aindex >= 0)
-      RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),
+      RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
                     ptr[aindex] = 0xFF;)
     else
-      RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),)
+      RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
   } else {
     if (aindex >= 0)
       RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
                     ptr[aindex] = 0xFF;)
     else
-      RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],)
+      RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
   }
   return 1;
 }
@@ -282,9 +282,9 @@
   ptr = source->pub.buffer[0];
   if (maxval == MAXJSAMPLE) {
     for (col = cinfo->image_width; col > 0; col--) {
-      JSAMPLE r = read_pbm_integer(cinfo, infile, maxval);
-      JSAMPLE g = read_pbm_integer(cinfo, infile, maxval);
-      JSAMPLE b = read_pbm_integer(cinfo, infile, maxval);
+      JSAMPLE r = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
+      JSAMPLE g = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
+      JSAMPLE b = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
       rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3);
       ptr += 4;
     }
@@ -347,12 +347,12 @@
     if (aindex >= 0)
       GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;)
     else
-      GRAY_RGB_READ_LOOP(*bufferptr++,)
+      GRAY_RGB_READ_LOOP(*bufferptr++, {})
   } else {
     if (aindex >= 0)
       GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;)
     else
-      GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)],)
+      GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
   }
   return 1;
 }
@@ -415,12 +415,12 @@
     if (aindex >= 0)
       RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;)
     else
-      RGB_READ_LOOP(*bufferptr++,)
+      RGB_READ_LOOP(*bufferptr++, {})
   } else {
     if (aindex >= 0)
       RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;)
     else
-      RGB_READ_LOOP(rescale[UCH(*bufferptr++)],)
+      RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
   }
   return 1;
 }
@@ -603,7 +603,8 @@
 
   switch (c) {
   case '2':                     /* it's a text-format PGM file */
-    if (cinfo->in_color_space == JCS_UNKNOWN)
+    if (cinfo->in_color_space == JCS_UNKNOWN ||
+        cinfo->in_color_space == JCS_RGB)
       cinfo->in_color_space = JCS_GRAYSCALE;
     TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
     if (cinfo->in_color_space == JCS_GRAYSCALE)
@@ -631,7 +632,8 @@
     break;
 
   case '5':                     /* it's a raw-format PGM file */
-    if (cinfo->in_color_space == JCS_UNKNOWN)
+    if (cinfo->in_color_space == JCS_UNKNOWN ||
+        cinfo->in_color_space == JCS_RGB)
       cinfo->in_color_space = JCS_GRAYSCALE;
     TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
     if (maxval > 255) {
@@ -730,8 +732,8 @@
       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                   (size_t)(((long)MAX(maxval, 255) + 1L) *
                                            sizeof(JSAMPLE)));
-    MEMZERO(source->rescale, (size_t)(((long)MAX(maxval, 255) + 1L) *
-                                      sizeof(JSAMPLE)));
+    memset(source->rescale, 0, (size_t)(((long)MAX(maxval, 255) + 1L) *
+                                        sizeof(JSAMPLE)));
     half_maxval = maxval / 2;
     for (val = 0; val <= (long)maxval; val++) {
       /* The multiplication here must be done in 32 bits to avoid overflow */
diff --git a/rdswitch.c b/rdswitch.c
index 886fec3..33449c8 100644
--- a/rdswitch.c
+++ b/rdswitch.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1996, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2018, D. R. Commander.
+ * Copyright (C) 2010, 2018, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -17,6 +17,10 @@
  *      -sample HxV[,HxV,...]   Set component sampling factors
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
 #include <ctype.h>              /* to declare isdigit(), isspace() */
 
@@ -263,7 +267,7 @@
     scanptr = (jpeg_scan_info *)
       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
                                   scanno * sizeof(jpeg_scan_info));
-    MEMCOPY(scanptr, scans, scanno * sizeof(jpeg_scan_info));
+    memcpy(scanptr, scans, scanno * sizeof(jpeg_scan_info));
     cinfo->scan_info = scanptr;
     cinfo->num_scans = scanno;
   }
diff --git a/rdtarga.c b/rdtarga.c
index 8f2d031..3ed7eb3 100644
--- a/rdtarga.c
+++ b/rdtarga.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1996, Thomas G. Lane.
  * Modified 2017 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2018, 2021, D. R. Commander.
+ * Copyright (C) 2018, 2021-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -33,7 +33,7 @@
 
 
 #define ReadOK(file, buffer, len) \
-  (JFREAD(file, buffer, len) == ((size_t)(len)))
+  (fread(buffer, 1, len, file) == ((size_t)(len)))
 
 
 /* Private version of data source object */
diff --git a/simd/arm/aarch32/jsimd.c b/simd/arm/aarch32/jsimd.c
index fac55df..e3adf23 100644
--- a/simd/arm/aarch32/jsimd.c
+++ b/simd/arm/aarch32/jsimd.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
  * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander.
  * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
  * Copyright (C) 2019, Google LLC.
  * Copyright (C) 2020, Arm Limited.
@@ -105,7 +105,7 @@
 init_simd(void)
 {
 #ifndef NO_GETENV
-  char *env = NULL;
+  char env[2] = { 0 };
 #endif
 #if !defined(__ARM_NEON__) && (defined(__linux__) || defined(ANDROID) || defined(__ANDROID__))
   int bufsize = 1024; /* an initial guess for the line buffer size limit */
@@ -131,14 +131,11 @@
 
 #ifndef NO_GETENV
   /* Force different settings through environment variables */
-  env = getenv("JSIMD_FORCENEON");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCENEON") && !strcmp(env, "1"))
     simd_support = JSIMD_NEON;
-  env = getenv("JSIMD_FORCENONE");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCENONE") && !strcmp(env, "1"))
     simd_support = 0;
-  env = getenv("JSIMD_NOHUFFENC");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_NOHUFFENC") && !strcmp(env, "1"))
     simd_huffman = 0;
 #endif
 }
diff --git a/simd/arm/aarch64/jchuff-neon.c b/simd/arm/aarch64/jchuff-neon.c
index f13fd1b..607a116 100644
--- a/simd/arm/aarch64/jchuff-neon.c
+++ b/simd/arm/aarch64/jchuff-neon.c
@@ -2,7 +2,7 @@
  * jchuff-neon.c - Huffman entropy encoding (64-bit Arm Neon)
  *
  * Copyright (C) 2020-2021, Arm Limited.  All Rights Reserved.
- * Copyright (C) 2020, D. R. Commander.  All Rights Reserved.
+ * Copyright (C) 2020, 2022, D. R. Commander.  All Rights Reserved.
  *
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
@@ -59,6 +59,17 @@
    14,  15,  30,  31,  44,  45,  46,  47
 };
 
+/* The AArch64 implementation of the FLUSH() macro triggers a UBSan misaligned
+ * address warning because the macro sometimes writes a 64-bit value to a
+ * non-64-bit-aligned address.  That behavior is technically undefined per
+ * the C specification, but it is supported by the AArch64 architecture and
+ * compilers.
+ */
+#if defined(__has_feature)
+#if __has_feature(undefined_behavior_sanitizer)
+__attribute__((no_sanitize("alignment")))
+#endif
+#endif
 JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer,
                                          JCOEFPTR block, int last_dc_val,
                                          c_derived_tbl *dctbl,
@@ -158,73 +169,43 @@
                                   7), row6, 5);
 
   /* DCT block is now in zig-zag order; start Huffman encoding process. */
-  int16x8_t abs_row0 = vabsq_s16(row0);
-  int16x8_t abs_row1 = vabsq_s16(row1);
-  int16x8_t abs_row2 = vabsq_s16(row2);
-  int16x8_t abs_row3 = vabsq_s16(row3);
-  int16x8_t abs_row4 = vabsq_s16(row4);
-  int16x8_t abs_row5 = vabsq_s16(row5);
-  int16x8_t abs_row6 = vabsq_s16(row6);
-  int16x8_t abs_row7 = vabsq_s16(row7);
-
-  /* For negative coeffs: diff = abs(coeff) -1 = ~abs(coeff) */
-  uint16x8_t row0_diff =
-    vreinterpretq_u16_s16(veorq_s16(abs_row0, vshrq_n_s16(row0, 15)));
-  uint16x8_t row1_diff =
-    vreinterpretq_u16_s16(veorq_s16(abs_row1, vshrq_n_s16(row1, 15)));
-  uint16x8_t row2_diff =
-    vreinterpretq_u16_s16(veorq_s16(abs_row2, vshrq_n_s16(row2, 15)));
-  uint16x8_t row3_diff =
-    vreinterpretq_u16_s16(veorq_s16(abs_row3, vshrq_n_s16(row3, 15)));
-  uint16x8_t row4_diff =
-    vreinterpretq_u16_s16(veorq_s16(abs_row4, vshrq_n_s16(row4, 15)));
-  uint16x8_t row5_diff =
-    vreinterpretq_u16_s16(veorq_s16(abs_row5, vshrq_n_s16(row5, 15)));
-  uint16x8_t row6_diff =
-    vreinterpretq_u16_s16(veorq_s16(abs_row6, vshrq_n_s16(row6, 15)));
-  uint16x8_t row7_diff =
-    vreinterpretq_u16_s16(veorq_s16(abs_row7, vshrq_n_s16(row7, 15)));
 
   /* Construct bitmap to accelerate encoding of AC coefficients.  A set bit
    * means that the corresponding coefficient != 0.
    */
-  uint8x8_t abs_row0_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row0),
-                                               vdupq_n_u16(0)));
-  uint8x8_t abs_row1_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row1),
-                                               vdupq_n_u16(0)));
-  uint8x8_t abs_row2_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row2),
-                                               vdupq_n_u16(0)));
-  uint8x8_t abs_row3_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row3),
-                                               vdupq_n_u16(0)));
-  uint8x8_t abs_row4_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row4),
-                                               vdupq_n_u16(0)));
-  uint8x8_t abs_row5_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row5),
-                                               vdupq_n_u16(0)));
-  uint8x8_t abs_row6_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row6),
-                                               vdupq_n_u16(0)));
-  uint8x8_t abs_row7_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row7),
-                                               vdupq_n_u16(0)));
+  uint16x8_t row0_ne_0 = vtstq_s16(row0, row0);
+  uint16x8_t row1_ne_0 = vtstq_s16(row1, row1);
+  uint16x8_t row2_ne_0 = vtstq_s16(row2, row2);
+  uint16x8_t row3_ne_0 = vtstq_s16(row3, row3);
+  uint16x8_t row4_ne_0 = vtstq_s16(row4, row4);
+  uint16x8_t row5_ne_0 = vtstq_s16(row5, row5);
+  uint16x8_t row6_ne_0 = vtstq_s16(row6, row6);
+  uint16x8_t row7_ne_0 = vtstq_s16(row7, row7);
+
+  uint8x16_t row10_ne_0 = vuzp1q_u8(vreinterpretq_u8_u16(row1_ne_0),
+                                    vreinterpretq_u8_u16(row0_ne_0));
+  uint8x16_t row32_ne_0 = vuzp1q_u8(vreinterpretq_u8_u16(row3_ne_0),
+                                    vreinterpretq_u8_u16(row2_ne_0));
+  uint8x16_t row54_ne_0 = vuzp1q_u8(vreinterpretq_u8_u16(row5_ne_0),
+                                    vreinterpretq_u8_u16(row4_ne_0));
+  uint8x16_t row76_ne_0 = vuzp1q_u8(vreinterpretq_u8_u16(row7_ne_0),
+                                    vreinterpretq_u8_u16(row6_ne_0));
 
   /* { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 } */
-  const uint8x8_t bitmap_mask =
-    vreinterpret_u8_u64(vmov_n_u64(0x0102040810204080));
+  const uint8x16_t bitmap_mask =
+    vreinterpretq_u8_u64(vdupq_n_u64(0x0102040810204080));
 
-  abs_row0_gt0 = vand_u8(abs_row0_gt0, bitmap_mask);
-  abs_row1_gt0 = vand_u8(abs_row1_gt0, bitmap_mask);
-  abs_row2_gt0 = vand_u8(abs_row2_gt0, bitmap_mask);
-  abs_row3_gt0 = vand_u8(abs_row3_gt0, bitmap_mask);
-  abs_row4_gt0 = vand_u8(abs_row4_gt0, bitmap_mask);
-  abs_row5_gt0 = vand_u8(abs_row5_gt0, bitmap_mask);
-  abs_row6_gt0 = vand_u8(abs_row6_gt0, bitmap_mask);
-  abs_row7_gt0 = vand_u8(abs_row7_gt0, bitmap_mask);
+  uint8x16_t bitmap_rows_10 = vandq_u8(row10_ne_0, bitmap_mask);
+  uint8x16_t bitmap_rows_32 = vandq_u8(row32_ne_0, bitmap_mask);
+  uint8x16_t bitmap_rows_54 = vandq_u8(row54_ne_0, bitmap_mask);
+  uint8x16_t bitmap_rows_76 = vandq_u8(row76_ne_0, bitmap_mask);
 
-  uint8x8_t bitmap_rows_10 = vpadd_u8(abs_row1_gt0, abs_row0_gt0);
-  uint8x8_t bitmap_rows_32 = vpadd_u8(abs_row3_gt0, abs_row2_gt0);
-  uint8x8_t bitmap_rows_54 = vpadd_u8(abs_row5_gt0, abs_row4_gt0);
-  uint8x8_t bitmap_rows_76 = vpadd_u8(abs_row7_gt0, abs_row6_gt0);
-  uint8x8_t bitmap_rows_3210 = vpadd_u8(bitmap_rows_32, bitmap_rows_10);
-  uint8x8_t bitmap_rows_7654 = vpadd_u8(bitmap_rows_76, bitmap_rows_54);
-  uint8x8_t bitmap_all = vpadd_u8(bitmap_rows_7654, bitmap_rows_3210);
+  uint8x16_t bitmap_rows_3210 = vpaddq_u8(bitmap_rows_32, bitmap_rows_10);
+  uint8x16_t bitmap_rows_7654 = vpaddq_u8(bitmap_rows_76, bitmap_rows_54);
+  uint8x16_t bitmap_rows_76543210 = vpaddq_u8(bitmap_rows_7654,
+                                              bitmap_rows_3210);
+  uint8x8_t bitmap_all = vpadd_u8(vget_low_u8(bitmap_rows_76543210),
+                                  vget_high_u8(bitmap_rows_76543210));
 
   /* Shift left to remove DC bit. */
   bitmap_all =
@@ -241,16 +222,16 @@
 
   /* Encode DC coefficient. */
 
+  /* For negative coeffs: diff = abs(coeff) -1 = ~abs(coeff) */
+  int16x8_t abs_row0 = vabsq_s16(row0);
+  int16x8_t row0_lz = vclzq_s16(abs_row0);
+  uint16x8_t row0_mask = vshlq_u16(vcltzq_s16(row0), vnegq_s16(row0_lz));
+  uint16x8_t row0_diff = veorq_u16(vreinterpretq_u16_s16(abs_row0), row0_mask);
   /* Find nbits required to specify sign and amplitude of coefficient. */
-#if defined(_MSC_VER) && !defined(__clang__)
-  unsigned int lz = BUILTIN_CLZ(vgetq_lane_s16(abs_row0, 0));
-#else
-  unsigned int lz;
-  __asm__("clz %w0, %w1" : "=r"(lz) : "r"(vgetq_lane_s16(abs_row0, 0)));
-#endif
-  unsigned int nbits = 32 - lz;
+  unsigned int lz = vgetq_lane_u16(vreinterpretq_u16_s16(row0_lz), 0);
+  unsigned int nbits = 16 - lz;
   /* Emit Huffman-coded symbol and additional diff bits. */
-  unsigned int diff = (unsigned int)(vgetq_lane_u16(row0_diff, 0) << lz) >> lz;
+  unsigned int diff = vgetq_lane_u16(row0_diff, 0);
   PUT_CODE(dctbl->ehufco[nbits], dctbl->ehufsi[nbits], diff)
 
   /* Encode AC coefficients. */
@@ -263,13 +244,20 @@
 
   /* The most efficient method of computing nbits and diff depends on the
    * number of non-zero coefficients.  If the bitmap is not too sparse (> 8
-   * non-zero AC coefficients), it is beneficial to use Neon; else we compute
-   * nbits and diff on demand using scalar code.
+   * non-zero AC coefficients), it is beneficial to do all of the work using
+   * Neon; else we do some of the work using Neon and the rest on demand using
+   * scalar code.
    */
   if (non_zero_coefficients > 8) {
     uint8_t block_nbits[DCTSIZE2];
 
-    int16x8_t row0_lz = vclzq_s16(abs_row0);
+    int16x8_t abs_row1 = vabsq_s16(row1);
+    int16x8_t abs_row2 = vabsq_s16(row2);
+    int16x8_t abs_row3 = vabsq_s16(row3);
+    int16x8_t abs_row4 = vabsq_s16(row4);
+    int16x8_t abs_row5 = vabsq_s16(row5);
+    int16x8_t abs_row6 = vabsq_s16(row6);
+    int16x8_t abs_row7 = vabsq_s16(row7);
     int16x8_t row1_lz = vclzq_s16(abs_row1);
     int16x8_t row2_lz = vclzq_s16(abs_row2);
     int16x8_t row3_lz = vclzq_s16(abs_row3);
@@ -277,49 +265,48 @@
     int16x8_t row5_lz = vclzq_s16(abs_row5);
     int16x8_t row6_lz = vclzq_s16(abs_row6);
     int16x8_t row7_lz = vclzq_s16(abs_row7);
+    /* Narrow leading zero count to 8 bits. */
+    uint8x16_t row01_lz = vuzp1q_u8(vreinterpretq_u8_s16(row0_lz),
+                                    vreinterpretq_u8_s16(row1_lz));
+    uint8x16_t row23_lz = vuzp1q_u8(vreinterpretq_u8_s16(row2_lz),
+                                    vreinterpretq_u8_s16(row3_lz));
+    uint8x16_t row45_lz = vuzp1q_u8(vreinterpretq_u8_s16(row4_lz),
+                                    vreinterpretq_u8_s16(row5_lz));
+    uint8x16_t row67_lz = vuzp1q_u8(vreinterpretq_u8_s16(row6_lz),
+                                    vreinterpretq_u8_s16(row7_lz));
     /* Compute nbits needed to specify magnitude of each coefficient. */
-    uint8x8_t row0_nbits = vsub_u8(vdup_n_u8(16),
-                                   vmovn_u16(vreinterpretq_u16_s16(row0_lz)));
-    uint8x8_t row1_nbits = vsub_u8(vdup_n_u8(16),
-                                   vmovn_u16(vreinterpretq_u16_s16(row1_lz)));
-    uint8x8_t row2_nbits = vsub_u8(vdup_n_u8(16),
-                                   vmovn_u16(vreinterpretq_u16_s16(row2_lz)));
-    uint8x8_t row3_nbits = vsub_u8(vdup_n_u8(16),
-                                   vmovn_u16(vreinterpretq_u16_s16(row3_lz)));
-    uint8x8_t row4_nbits = vsub_u8(vdup_n_u8(16),
-                                   vmovn_u16(vreinterpretq_u16_s16(row4_lz)));
-    uint8x8_t row5_nbits = vsub_u8(vdup_n_u8(16),
-                                   vmovn_u16(vreinterpretq_u16_s16(row5_lz)));
-    uint8x8_t row6_nbits = vsub_u8(vdup_n_u8(16),
-                                   vmovn_u16(vreinterpretq_u16_s16(row6_lz)));
-    uint8x8_t row7_nbits = vsub_u8(vdup_n_u8(16),
-                                   vmovn_u16(vreinterpretq_u16_s16(row7_lz)));
+    uint8x16_t row01_nbits = vsubq_u8(vdupq_n_u8(16), row01_lz);
+    uint8x16_t row23_nbits = vsubq_u8(vdupq_n_u8(16), row23_lz);
+    uint8x16_t row45_nbits = vsubq_u8(vdupq_n_u8(16), row45_lz);
+    uint8x16_t row67_nbits = vsubq_u8(vdupq_n_u8(16), row67_lz);
     /* Store nbits. */
-    vst1_u8(block_nbits + 0 * DCTSIZE, row0_nbits);
-    vst1_u8(block_nbits + 1 * DCTSIZE, row1_nbits);
-    vst1_u8(block_nbits + 2 * DCTSIZE, row2_nbits);
-    vst1_u8(block_nbits + 3 * DCTSIZE, row3_nbits);
-    vst1_u8(block_nbits + 4 * DCTSIZE, row4_nbits);
-    vst1_u8(block_nbits + 5 * DCTSIZE, row5_nbits);
-    vst1_u8(block_nbits + 6 * DCTSIZE, row6_nbits);
-    vst1_u8(block_nbits + 7 * DCTSIZE, row7_nbits);
+    vst1q_u8(block_nbits + 0 * DCTSIZE, row01_nbits);
+    vst1q_u8(block_nbits + 2 * DCTSIZE, row23_nbits);
+    vst1q_u8(block_nbits + 4 * DCTSIZE, row45_nbits);
+    vst1q_u8(block_nbits + 6 * DCTSIZE, row67_nbits);
     /* Mask bits not required to specify sign and amplitude of diff. */
-    row0_diff = vshlq_u16(row0_diff, row0_lz);
-    row1_diff = vshlq_u16(row1_diff, row1_lz);
-    row2_diff = vshlq_u16(row2_diff, row2_lz);
-    row3_diff = vshlq_u16(row3_diff, row3_lz);
-    row4_diff = vshlq_u16(row4_diff, row4_lz);
-    row5_diff = vshlq_u16(row5_diff, row5_lz);
-    row6_diff = vshlq_u16(row6_diff, row6_lz);
-    row7_diff = vshlq_u16(row7_diff, row7_lz);
-    row0_diff = vshlq_u16(row0_diff, vnegq_s16(row0_lz));
-    row1_diff = vshlq_u16(row1_diff, vnegq_s16(row1_lz));
-    row2_diff = vshlq_u16(row2_diff, vnegq_s16(row2_lz));
-    row3_diff = vshlq_u16(row3_diff, vnegq_s16(row3_lz));
-    row4_diff = vshlq_u16(row4_diff, vnegq_s16(row4_lz));
-    row5_diff = vshlq_u16(row5_diff, vnegq_s16(row5_lz));
-    row6_diff = vshlq_u16(row6_diff, vnegq_s16(row6_lz));
-    row7_diff = vshlq_u16(row7_diff, vnegq_s16(row7_lz));
+    uint16x8_t row1_mask = vshlq_u16(vcltzq_s16(row1), vnegq_s16(row1_lz));
+    uint16x8_t row2_mask = vshlq_u16(vcltzq_s16(row2), vnegq_s16(row2_lz));
+    uint16x8_t row3_mask = vshlq_u16(vcltzq_s16(row3), vnegq_s16(row3_lz));
+    uint16x8_t row4_mask = vshlq_u16(vcltzq_s16(row4), vnegq_s16(row4_lz));
+    uint16x8_t row5_mask = vshlq_u16(vcltzq_s16(row5), vnegq_s16(row5_lz));
+    uint16x8_t row6_mask = vshlq_u16(vcltzq_s16(row6), vnegq_s16(row6_lz));
+    uint16x8_t row7_mask = vshlq_u16(vcltzq_s16(row7), vnegq_s16(row7_lz));
+    /* diff = abs(coeff) ^ sign(coeff) [no-op for positive coefficients] */
+    uint16x8_t row1_diff = veorq_u16(vreinterpretq_u16_s16(abs_row1),
+                                     row1_mask);
+    uint16x8_t row2_diff = veorq_u16(vreinterpretq_u16_s16(abs_row2),
+                                     row2_mask);
+    uint16x8_t row3_diff = veorq_u16(vreinterpretq_u16_s16(abs_row3),
+                                     row3_mask);
+    uint16x8_t row4_diff = veorq_u16(vreinterpretq_u16_s16(abs_row4),
+                                     row4_mask);
+    uint16x8_t row5_diff = veorq_u16(vreinterpretq_u16_s16(abs_row5),
+                                     row5_mask);
+    uint16x8_t row6_diff = veorq_u16(vreinterpretq_u16_s16(abs_row6),
+                                     row6_mask);
+    uint16x8_t row7_diff = veorq_u16(vreinterpretq_u16_s16(abs_row7),
+                                     row7_mask);
     /* Store diff bits. */
     vst1q_u16(block_diff + 0 * DCTSIZE, row0_diff);
     vst1q_u16(block_diff + 1 * DCTSIZE, row1_diff);
@@ -349,7 +336,14 @@
     }
   } else if (bitmap != 0) {
     uint16_t block_abs[DCTSIZE2];
-    /* Store absolute value of coefficients. */
+    /* Compute and store absolute value of coefficients. */
+    int16x8_t abs_row1 = vabsq_s16(row1);
+    int16x8_t abs_row2 = vabsq_s16(row2);
+    int16x8_t abs_row3 = vabsq_s16(row3);
+    int16x8_t abs_row4 = vabsq_s16(row4);
+    int16x8_t abs_row5 = vabsq_s16(row5);
+    int16x8_t abs_row6 = vabsq_s16(row6);
+    int16x8_t abs_row7 = vabsq_s16(row7);
     vst1q_u16(block_abs + 0 * DCTSIZE, vreinterpretq_u16_s16(abs_row0));
     vst1q_u16(block_abs + 1 * DCTSIZE, vreinterpretq_u16_s16(abs_row1));
     vst1q_u16(block_abs + 2 * DCTSIZE, vreinterpretq_u16_s16(abs_row2));
@@ -358,7 +352,21 @@
     vst1q_u16(block_abs + 5 * DCTSIZE, vreinterpretq_u16_s16(abs_row5));
     vst1q_u16(block_abs + 6 * DCTSIZE, vreinterpretq_u16_s16(abs_row6));
     vst1q_u16(block_abs + 7 * DCTSIZE, vreinterpretq_u16_s16(abs_row7));
-    /* Store diff bits. */
+    /* Compute diff bits (without nbits mask) and store. */
+    uint16x8_t row1_diff = veorq_u16(vreinterpretq_u16_s16(abs_row1),
+                                     vcltzq_s16(row1));
+    uint16x8_t row2_diff = veorq_u16(vreinterpretq_u16_s16(abs_row2),
+                                     vcltzq_s16(row2));
+    uint16x8_t row3_diff = veorq_u16(vreinterpretq_u16_s16(abs_row3),
+                                     vcltzq_s16(row3));
+    uint16x8_t row4_diff = veorq_u16(vreinterpretq_u16_s16(abs_row4),
+                                     vcltzq_s16(row4));
+    uint16x8_t row5_diff = veorq_u16(vreinterpretq_u16_s16(abs_row5),
+                                     vcltzq_s16(row5));
+    uint16x8_t row6_diff = veorq_u16(vreinterpretq_u16_s16(abs_row6),
+                                     vcltzq_s16(row6));
+    uint16x8_t row7_diff = veorq_u16(vreinterpretq_u16_s16(abs_row7),
+                                     vcltzq_s16(row7));
     vst1q_u16(block_diff + 0 * DCTSIZE, row0_diff);
     vst1q_u16(block_diff + 1 * DCTSIZE, row1_diff);
     vst1q_u16(block_diff + 2 * DCTSIZE, row2_diff);
@@ -375,7 +383,7 @@
       bitmap <<= r;
       lz = BUILTIN_CLZ(block_abs[i]);
       nbits = 32 - lz;
-      diff = (unsigned int)(block_diff[i] << lz) >> lz;
+      diff = ((unsigned int)block_diff[i] << lz) >> lz;
       while (r > 15) {
         /* If run length > 15, emit special run-length-16 codes. */
         PUT_BITS(code_0xf0, size_0xf0)
diff --git a/simd/arm/aarch64/jsimd.c b/simd/arm/aarch64/jsimd.c
index 8570b82..604d547 100644
--- a/simd/arm/aarch64/jsimd.c
+++ b/simd/arm/aarch64/jsimd.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
  * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2020, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2020, 2022, D. R. Commander.
  * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
  * Copyright (C) 2020, Arm Limited.
  *
@@ -125,7 +125,7 @@
 init_simd(void)
 {
 #ifndef NO_GETENV
-  char *env = NULL;
+  char env[2] = { 0 };
 #endif
 #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
   int bufsize = 1024; /* an initial guess for the line buffer size limit */
@@ -147,24 +147,19 @@
 
 #ifndef NO_GETENV
   /* Force different settings through environment variables */
-  env = getenv("JSIMD_FORCENEON");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCENEON") && !strcmp(env, "1"))
     simd_support = JSIMD_NEON;
-  env = getenv("JSIMD_FORCENONE");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCENONE") && !strcmp(env, "1"))
     simd_support = 0;
-  env = getenv("JSIMD_NOHUFFENC");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_NOHUFFENC") && !strcmp(env, "1"))
     simd_huffman = 0;
-  env = getenv("JSIMD_FASTLD3");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FASTLD3") && !strcmp(env, "1"))
     simd_features |= JSIMD_FASTLD3;
-  if ((env != NULL) && (strcmp(env, "0") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FASTLD3") && !strcmp(env, "0"))
     simd_features &= ~JSIMD_FASTLD3;
-  env = getenv("JSIMD_FASTST3");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FASTST3") && !strcmp(env, "1"))
     simd_features |= JSIMD_FASTST3;
-  if ((env != NULL) && (strcmp(env, "0") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FASTST3") && !strcmp(env, "0"))
     simd_features &= ~JSIMD_FASTST3;
 #endif
 }
diff --git a/simd/arm/jquanti-neon.c b/simd/arm/jquanti-neon.c
index a7eb6f1..d5d95d8 100644
--- a/simd/arm/jquanti-neon.c
+++ b/simd/arm/jquanti-neon.c
@@ -1,7 +1,7 @@
 /*
  * jquanti-neon.c - sample data conversion and quantization (Arm Neon)
  *
- * Copyright (C) 2020, Arm Limited.  All Rights Reserved.
+ * Copyright (C) 2020-2021, Arm Limited.  All Rights Reserved.
  *
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
@@ -100,6 +100,9 @@
   DCTELEM *shift_ptr = divisors + 3 * DCTSIZE2;
   int i;
 
+#if defined(__clang__) && (defined(__aarch64__) || defined(_M_ARM64))
+#pragma unroll
+#endif
   for (i = 0; i < DCTSIZE; i += DCTSIZE / 2) {
     /* Load DCT coefficients. */
     int16x8_t row0 = vld1q_s16(workspace + (i + 0) * DCTSIZE);
diff --git a/simd/i386/jsimd.c b/simd/i386/jsimd.c
index 563949a..80bc821 100644
--- a/simd/i386/jsimd.c
+++ b/simd/i386/jsimd.c
@@ -2,7 +2,7 @@
  * jsimd_i386.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander.
  * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
@@ -44,7 +44,7 @@
 init_simd(void)
 {
 #ifndef NO_GETENV
-  char *env = NULL;
+  char env[2] = { 0 };
 #endif
 
   if (simd_support != ~0U)
@@ -54,26 +54,19 @@
 
 #ifndef NO_GETENV
   /* Force different settings through environment variables */
-  env = getenv("JSIMD_FORCEMMX");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCEMMX") && !strcmp(env, "1"))
     simd_support &= JSIMD_MMX;
-  env = getenv("JSIMD_FORCE3DNOW");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCE3DNOW") && !strcmp(env, "1"))
     simd_support &= JSIMD_3DNOW | JSIMD_MMX;
-  env = getenv("JSIMD_FORCESSE");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCESSE") && !strcmp(env, "1"))
     simd_support &= JSIMD_SSE | JSIMD_MMX;
-  env = getenv("JSIMD_FORCESSE2");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCESSE2") && !strcmp(env, "1"))
     simd_support &= JSIMD_SSE2;
-  env = getenv("JSIMD_FORCEAVX2");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCEAVX2") && !strcmp(env, "1"))
     simd_support &= JSIMD_AVX2;
-  env = getenv("JSIMD_FORCENONE");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCENONE") && !strcmp(env, "1"))
     simd_support = 0;
-  env = getenv("JSIMD_NOHUFFENC");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_NOHUFFENC") && !strcmp(env, "1"))
     simd_huffman = 0;
 #endif
 }
diff --git a/simd/x86_64/jsimd.c b/simd/x86_64/jsimd.c
index eb76679..584a010 100644
--- a/simd/x86_64/jsimd.c
+++ b/simd/x86_64/jsimd.c
@@ -2,7 +2,7 @@
  * jsimd_x86_64.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, 2016, 2018, D. R. Commander.
+ * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022, D. R. Commander.
  * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
@@ -44,7 +44,7 @@
 init_simd(void)
 {
 #ifndef NO_GETENV
-  char *env = NULL;
+  char env[2] = { 0 };
 #endif
 
   if (simd_support != ~0U)
@@ -54,17 +54,13 @@
 
 #ifndef NO_GETENV
   /* Force different settings through environment variables */
-  env = getenv("JSIMD_FORCESSE2");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCESSE2") && !strcmp(env, "1"))
     simd_support &= JSIMD_SSE2;
-  env = getenv("JSIMD_FORCEAVX2");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCEAVX2") && !strcmp(env, "1"))
     simd_support &= JSIMD_AVX2;
-  env = getenv("JSIMD_FORCENONE");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_FORCENONE") && !strcmp(env, "1"))
     simd_support = 0;
-  env = getenv("JSIMD_NOHUFFENC");
-  if ((env != NULL) && (strcmp(env, "1") == 0))
+  if (!GETENV_S(env, 2, "JSIMD_NOHUFFENC") && !strcmp(env, "1"))
     simd_huffman = 0;
 #endif
 }
diff --git a/tjbench.c b/tjbench.c
index 97475ec..5381f92 100644
--- a/tjbench.c
+++ b/tjbench.c
@@ -26,6 +26,10 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -62,8 +66,10 @@
     if (strncmp(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX) || \
         strncmp(tjErrorMsg, m, JMSG_LENGTH_MAX) || \
         tjErrorCode != _tjErrorCode || tjErrorLine != __LINE__) { \
-      strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX - 1); \
-      strncpy(tjErrorMsg, m, JMSG_LENGTH_MAX - 1); \
+      strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX); \
+      tjErrorStr[JMSG_LENGTH_MAX - 1] = '\0'; \
+      strncpy(tjErrorMsg, m, JMSG_LENGTH_MAX); \
+      tjErrorMsg[JMSG_LENGTH_MAX - 1] = '\0'; \
       tjErrorCode = _tjErrorCode; \
       tjErrorLine = __LINE__; \
       fprintf(stderr, "WARNING in line %d while %s:\n%s\n", __LINE__, m, \
@@ -291,16 +297,17 @@
 
           if (y > 255) y = 255;
           if (y < 0) y = 0;
-          dstBuf[rindex] = abs(dstBuf[rindex] - y);
-          dstBuf[gindex] = abs(dstBuf[gindex] - y);
-          dstBuf[bindex] = abs(dstBuf[bindex] - y);
+          dstBuf[rindex] = (unsigned char)abs(dstBuf[rindex] - y);
+          dstBuf[gindex] = (unsigned char)abs(dstBuf[gindex] - y);
+          dstBuf[bindex] = (unsigned char)abs(dstBuf[bindex] - y);
         }
       }
     } else {
       for (row = 0; row < h; row++)
         for (col = 0; col < w * ps; col++)
           dstBuf[pitch * row + col] =
-            abs(dstBuf[pitch * row + col] - srcBuf[pitch * row + col]);
+            (unsigned char)abs(dstBuf[pitch * row + col] -
+                               srcBuf[pitch * row + col]);
     }
     if (tjSaveImage(tempStr, dstBuf, w, 0, h, pf, flags) == -1)
       THROW_TJG("saving bitmap");
@@ -699,7 +706,7 @@
                 sigfig((double)(w * h * ps) / (double)totalJpegSize, 4,
                        tempStr2, 80),
                 quiet == 2 ? "\n" : "  ");
-      } else if (!quiet) {
+      } else {
         fprintf(stderr, "Transform     --> Frame rate:         %f fps\n",
                 1.0 / elapsed);
         fprintf(stderr, "                  Output image size:  %lu bytes\n",
diff --git a/tjbenchtest.in b/tjbenchtest.in
deleted file mode 100644
index 1c08b37..0000000
--- a/tjbenchtest.in
+++ /dev/null
@@ -1,256 +0,0 @@
-#!/bin/bash
-
-set -u
-set -e
-trap onexit INT
-trap onexit TERM
-trap onexit EXIT
-
-onexit()
-{
-	if [ -d $OUTDIR ]; then
-		rm -rf $OUTDIR
-	fi
-}
-
-runme()
-{
-	echo \*\*\* $*
-	$*
-}
-
-EXT=bmp
-IMAGES="vgl_5674_0098.${EXT} vgl_6434_0018a.${EXT} vgl_6548_0026a.${EXT} nightshot_iso_100.${EXT}"
-IMGDIR=@CMAKE_CURRENT_SOURCE_DIR@/testimages
-OUTDIR=`mktemp -d /tmp/__tjbenchtest_output.XXXXXX`
-EXEDIR=@CMAKE_CURRENT_BINARY_DIR@
-BMPARG=
-NSARG=
-YUVARG=
-ALLOC=0
-ALLOCARG=
-PROGARG=
-if [ "$EXT" = "bmp" ]; then BMPARG=-bmp; fi
-
-if [ -d $OUTDIR ]; then
-	rm -rf $OUTDIR
-fi
-mkdir -p $OUTDIR
-
-while [ $# -gt 0 ]; do
-	case "$1" in
-	-yuv)
-		NSARG=-nosmooth
-		YUVARG=-yuv
-
-# NOTE: The combination of tjEncodeYUV*() and tjCompressFromYUV*() does not
-# always produce bitwise-identical results to tjCompress*() if subsampling is
-# enabled.  In both cases, if the image width or height are not evenly
-# divisible by the MCU width/height, then the bottom and/or right edge are
-# expanded.  However, the libjpeg code performs this expansion prior to
-# downsampling, and TurboJPEG performs it in tjCompressFromYUV*(), which is
-# after downsampling.  Thus, the two will agree only if the width/height along
-# each downsampled dimension is an odd number or is evenly divisible by the MCU
-# width/height.  This disagreement basically amounts to a round-off error, but
-# there is no easy way around it, so for now, we just test the only image that
-# works.  (NOTE: nightshot_iso_100 does not suffer from the above issue, but
-# it suffers from an unrelated problem whereby the combination of
-# tjDecompressToYUV*() and tjDecodeYUV*() do not produce bitwise-identical
-# results to tjDecompress*() if decompression scaling is enabled.  This latter
-# phenomenon is not yet fully understood but is also believed to be some sort
-# of round-off error.)
-		IMAGES="vgl_6548_0026a.${EXT}"
-		;;
-	-alloc)
-		ALLOCARG=-alloc
-		ALLOC=1
-		;;
-	-progressive)
-		PROGARG=-progressive
-		;;
-	esac
-	shift
-done
-
-exec >$EXEDIR/tjbenchtest$YUVARG$ALLOCARG$PROGARG.log
-
-# Standard tests
-for image in $IMAGES; do
-
-	cp $IMGDIR/$image $OUTDIR
-	basename=`basename $image .${EXT}`
-	runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-	runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-	runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-	runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-	runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-	runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-	runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-	runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-	for samp in GRAY 420 422 444; do
-		runme $EXEDIR/djpeg -rgb $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_default_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-		runme $EXEDIR/djpeg -dct fast -rgb $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_fast_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-		runme $EXEDIR/djpeg -dct int -rgb $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_accurate_djpeg.${EXT} $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
-	done
-	for samp in 420 422; do
-		runme $EXEDIR/djpeg -nosmooth $BMPARG -outfile $OUTDIR/${basename}_${samp}_default_nosmooth_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-		runme $EXEDIR/djpeg -dct fast -nosmooth $BMPARG -outfile $OUTDIR/${basename}_${samp}_fast_nosmooth_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-		runme $EXEDIR/djpeg -dct int -nosmooth $BMPARG -outfile $OUTDIR/${basename}_${samp}_accurate_nosmooth_djpeg.${EXT} $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
-	done
-
-	# Compression
-	for dct in accurate fast; do
-		runme $EXEDIR/tjbench $OUTDIR/$image 95 -rgb -quiet -benchtime 0.01 -warmup 0 -${dct}dct $YUVARG $ALLOCARG $PROGARG
-		for samp in GRAY 420 422 444; do
-			runme cmp $OUTDIR/${basename}_${samp}_Q95.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg
-		done
-	done
-
-	for dct in fast accurate default; do
-		dctarg=-${dct}dct
-		if [ "${dct}" = "default" ]; then
-			dctarg=
-		fi
-
-		# Tiled compression & decompression
-		runme $EXEDIR/tjbench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $PROGARG
-		for samp in GRAY 444; do
-			if [ $ALLOC = 1 ]; then
-				runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
-				rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-			else
-				for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-					$OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-					runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
-					rm $i
-				done
-			fi
-		done
-		runme $EXEDIR/tjbench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $PROGARG
-		for samp in 420 422; do
-			if [ $ALLOC = 1 ]; then
-				runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
-				rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-			else
-				for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-					$OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-					runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
-					rm $i
-				done
-			fi
-		done
-
-		# Tiled decompression
-		for samp in GRAY 444; do
-			runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $PROGARG
-			if [ $ALLOC = 1 ]; then
-				runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
-				rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-			else
-				for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-					$OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-					runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
-					rm $i
-				done
-			fi
-		done
-		for samp in 420 422; do
-			runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $PROGARG
-			if [ $ALLOC = 1 ]; then
-				runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
-				rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-			else
-				for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-					$OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-					runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
-					rm $i
-				done
-			fi
-		done
-	done
-
-	# Scaled decompression
-	for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-		scalearg=`echo $scale | sed 's/\_/\//g'`
-		for samp in GRAY 420 422 444; do
-			runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_${scale}_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-			runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $PROGARG
-			runme cmp $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT} $OUTDIR/${basename}_${samp}_${scale}_djpeg.${EXT}
-			rm $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT}
-		done
-	done
-
-	# Transforms
-	for samp in GRAY 420 422 444; do
-		runme $EXEDIR/jpegtran -flip horizontal -trim -outfile $OUTDIR/${basename}_${samp}_hflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -flip vertical -trim -outfile $OUTDIR/${basename}_${samp}_vflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -transpose -trim -outfile $OUTDIR/${basename}_${samp}_transpose_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -transverse -trim -outfile $OUTDIR/${basename}_${samp}_transverse_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -rotate 90 -trim -outfile $OUTDIR/${basename}_${samp}_rot90_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -rotate 180 -trim -outfile $OUTDIR/${basename}_${samp}_rot180_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -rotate 270 -trim -outfile $OUTDIR/${basename}_${samp}_rot270_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-	done
-	for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-		for samp in GRAY 444; do
-			runme $EXEDIR/djpeg -rgb $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-			runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $PROGARG
-			if [ $ALLOC = 1 ]; then
-				runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
-				rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-			else
-				for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-					$OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-					runme cmp $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
-					rm $i
-				done
-			fi
-		done
-		for samp in 420 422; do
-			runme $EXEDIR/djpeg -nosmooth -rgb $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-			runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample $YUVARG $ALLOCARG $PROGARG
-			if [ $ALLOC = 1 ]; then
-				runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
-				rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-			else
-				for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-					$OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-					runme cmp $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
-					rm $i
-				done
-			fi
-		done
-	done
-
-	# Grayscale transform
-	for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-		for samp in GRAY 444 422 420; do
-			runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 -grayscale $YUVARG $ALLOCARG $PROGARG
-			if [ $ALLOC = 1 ]; then
-				runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_GRAY_${xform}_jpegtran.${EXT}
-				rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-			else
-				for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-					$OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-					runme cmp $i $OUTDIR/${basename}_GRAY_${xform}_jpegtran.${EXT}
-					rm $i
-				done
-			fi
-		done
-	done
-
-	# Transforms with scaling
-	for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-		for samp in GRAY 444 422 420; do
-			for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-				scalearg=`echo $scale | sed 's/\_/\//g'`
-				runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-				runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $PROGARG
-				runme cmp $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT} $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.${EXT}
-				rm $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT}
-			done
-		done
-	done
-
-done
-
-echo SUCCESS!
diff --git a/tjbenchtest.java.in b/tjbenchtest.java.in
deleted file mode 100644
index 689561d..0000000
--- a/tjbenchtest.java.in
+++ /dev/null
@@ -1,215 +0,0 @@
-#!/bin/bash
-
-set -u
-set -e
-trap onexit INT
-trap onexit TERM
-trap onexit EXIT
-
-onexit()
-{
-	if [ -d $OUTDIR ]; then
-		rm -rf $OUTDIR
-	fi
-}
-
-runme()
-{
-	echo \*\*\* $*
-	"$@"
-}
-
-IMAGES="vgl_5674_0098.bmp vgl_6434_0018a.bmp vgl_6548_0026a.bmp nightshot_iso_100.bmp"
-IMGDIR=@CMAKE_CURRENT_SOURCE_DIR@/testimages
-OUTDIR=`mktemp -d /tmp/__tjbenchtest_java_output.XXXXXX`
-EXEDIR=@CMAKE_CURRENT_BINARY_DIR@
-JAVA="@Java_JAVA_EXECUTABLE@"
-JAVAARGS="-cp $EXEDIR/java/turbojpeg.jar -Djava.library.path=$EXEDIR"
-BMPARG=
-NSARG=
-YUVARG=
-PROGARG=
-
-if [ -d $OUTDIR ]; then
-	rm -rf $OUTDIR
-fi
-mkdir -p $OUTDIR
-
-while [ $# -gt 0 ]; do
-	case "$1" in
-	-yuv)
-		NSARG=-nosmooth
-		YUVARG=-yuv
-
-# NOTE: The combination of tjEncodeYUV*() and tjCompressFromYUV*() does not
-# always produce bitwise-identical results to tjCompress*() if subsampling is
-# enabled.  In both cases, if the image width or height are not evenly
-# divisible by the MCU width/height, then the bottom and/or right edge are
-# expanded.  However, the libjpeg code performs this expansion prior to
-# downsampling, and TurboJPEG performs it in tjCompressFromYUV*(), which is
-# after downsampling.  Thus, the two will agree only if the width/height along
-# each downsampled dimension is an odd number or is evenly divisible by the MCU
-# width/height.  This disagreement basically amounts to a round-off error, but
-# there is no easy way around it, so for now, we just test the only image that
-# works.  (NOTE: nightshot_iso_100 does not suffer from the above issue, but
-# it suffers from an unrelated problem whereby the combination of
-# tjDecompressToYUV*() and tjDecodeYUV*() do not produce bitwise-identical
-# results to tjDecompress*() if decompression scaling is enabled.  This latter
-# phenomenon is not yet fully understood but is also believed to be some sort
-# of round-off error.)
-		IMAGES="vgl_6548_0026a.bmp"
-		;;
-	-progressive)
-		PROGARG=-progressive
-		;;
-	esac
-	shift
-done
-
-exec >$EXEDIR/tjbenchtest-java$YUVARG$PROGARG.log
-
-# Standard tests
-for image in $IMAGES; do
-
-	cp $IMGDIR/$image $OUTDIR
-	basename=`basename $image .bmp`
-	runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-	runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-	for samp in GRAY 420 422 444; do
-		runme $EXEDIR/djpeg -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_default_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-		runme $EXEDIR/djpeg -dct fast -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_fast_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-		runme $EXEDIR/djpeg -dct int -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_accurate_djpeg.bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
-	done
-	for samp in 420 422; do
-		runme $EXEDIR/djpeg -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_default_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-		runme $EXEDIR/djpeg -dct fast -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_fast_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-		runme $EXEDIR/djpeg -dct int -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_accurate_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
-	done
-
-	# Compression
-	for dct in accurate fast; do
-		runme "$JAVA" $JAVAARGS TJBench $OUTDIR/$image 95 -rgb -quiet -benchtime 0.01 -warmup 0 -${dct}dct $YUVARG $PROGARG
-		for samp in GRAY 420 422 444; do
-			runme cmp $OUTDIR/${basename}_${samp}_Q95.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg
-		done
-	done
-
-	for dct in fast accurate default; do
-		dctarg=-${dct}dct
-		if [ "${dct}" = "default" ]; then
-			dctarg=
-		fi
-
-		# Tiled compression & decompression
-		runme "$JAVA" $JAVAARGS TJBench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $PROGARG
-		for samp in GRAY 444; do
-			for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-				$OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-				runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.bmp
-				rm $i
-			done
-		done
-		runme "$JAVA" $JAVAARGS TJBench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $PROGARG
-		for samp in 420 422; do
-			for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-				$OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-				runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.bmp
-				rm $i
-			done
-		done
-
-		# Tiled decompression
-		for samp in GRAY 444; do
-			runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $PROGARG
-			for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-				$OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-				runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.bmp
-				rm $i
-			done
-		done
-		for samp in 420 422; do
-			runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $PROGARG
-			for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-				$OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-				runme cmp $i -i 54:54 $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.bmp
-				rm $i
-			done
-		done
-	done
-
-	# Scaled decompression
-	for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-		scalearg=`echo $scale | sed 's/\_/\//g'`
-		for samp in GRAY 420 422 444; do
-			runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG -bmp -outfile $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-			runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $PROGARG
-			runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp
-			rm $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp
-		done
-	done
-
-	# Transforms
-	for samp in GRAY 420 422 444; do
-		runme $EXEDIR/jpegtran -flip horizontal -trim -outfile $OUTDIR/${basename}_${samp}_hflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -flip vertical -trim -outfile $OUTDIR/${basename}_${samp}_vflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -transpose -trim -outfile $OUTDIR/${basename}_${samp}_transpose_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -transverse -trim -outfile $OUTDIR/${basename}_${samp}_transverse_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -rotate 90 -trim -outfile $OUTDIR/${basename}_${samp}_rot90_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -rotate 180 -trim -outfile $OUTDIR/${basename}_${samp}_rot180_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-		runme $EXEDIR/jpegtran -rotate 270 -trim -outfile $OUTDIR/${basename}_${samp}_rot270_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-	done
-	for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-		for samp in GRAY 444; do
-			runme $EXEDIR/djpeg -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-			runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 -warmup 0 $YUVARG $PROGARG
-			for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-				$OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-				runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp
-				rm $i
-			done
-		done
-		for samp in 420 422; do
-			runme $EXEDIR/djpeg -nosmooth -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-			runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample $YUVARG $PROGARG
-			for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-				$OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-				runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp
-				rm $i
-			done
-		done
-	done
-
-	# Grayscale transform
-	for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-		for samp in GRAY 444 422 420; do
-			runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 -warmup 0 -grayscale $YUVARG $PROGARG
-			for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-				$OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-				runme cmp -i 54:54 $i $OUTDIR/${basename}_GRAY_${xform}_jpegtran.bmp
-				rm $i
-			done
-		done
-	done
-
-	# Transforms with scaling
-	for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-		for samp in GRAY 444 422 420; do
-			for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-				scalearg=`echo $scale | sed 's/\_/\//g'`
-				runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-				runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $PROGARG
-				runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp
-				rm $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp
-			done
-		done
-	done
-
-done
-
-echo SUCCESS!
diff --git a/tjunittest.c b/tjunittest.c
index af409a5..29ecc46 100644
--- a/tjunittest.c
+++ b/tjunittest.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (C)2009-2014, 2017-2019 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2009-2014, 2017-2019, 2022 D. R. Commander.
+ *                                         All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -30,6 +31,10 @@
  * This program tests the various code paths in the TurboJPEG C Wrapper
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/tjutil.h b/tjutil.h
index 8542bab..fc8a17a 100644
--- a/tjutil.h
+++ b/tjutil.h
@@ -27,11 +27,6 @@
  */
 
 #ifdef _WIN32
-#ifndef __MINGW32__
-#include <stdio.h>
-#define snprintf(str, n, format, ...) \
-  _snprintf_s(str, n, _TRUNCATE, format, ##__VA_ARGS__)
-#endif
 #define strcasecmp  stricmp
 #define strncasecmp  strnicmp
 #endif
diff --git a/transupp.c b/transupp.c
index ce30ab7..a3d878c 100644
--- a/transupp.c
+++ b/transupp.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2017, 2021, D. R. Commander.
+ * Copyright (C) 2010, 2017, 2021-2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -262,8 +262,8 @@
         }
       } else {
         for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
-          MEMZERO(dst_buffer[offset_y] + x_drop_blocks,
-                  comp_width * sizeof(JBLOCK));
+          memset(dst_buffer[offset_y] + x_drop_blocks, 0,
+                 comp_width * sizeof(JBLOCK));
         }
       }
     }
@@ -345,8 +345,8 @@
         if (dst_blk_y < y_crop_blocks ||
             dst_blk_y >= y_crop_blocks + comp_height) {
           for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
-            MEMZERO(dst_buffer[offset_y],
-                    compptr->width_in_blocks * sizeof(JBLOCK));
+            memset(dst_buffer[offset_y], 0,
+                   compptr->width_in_blocks * sizeof(JBLOCK));
           }
           continue;
         }
@@ -363,14 +363,14 @@
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
         if (dstinfo->_jpeg_width > srcinfo->output_width) {
           if (x_crop_blocks > 0) {
-            MEMZERO(dst_buffer[offset_y], x_crop_blocks * sizeof(JBLOCK));
+            memset(dst_buffer[offset_y], 0, x_crop_blocks * sizeof(JBLOCK));
           }
           jcopy_block_row(src_buffer[offset_y],
                           dst_buffer[offset_y] + x_crop_blocks, comp_width);
           if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
-            MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width,
-                    (compptr->width_in_blocks - x_crop_blocks - comp_width) *
-                    sizeof(JBLOCK));
+            memset(dst_buffer[offset_y] + x_crop_blocks + comp_width, 0,
+                   (compptr->width_in_blocks - x_crop_blocks - comp_width) *
+                   sizeof(JBLOCK));
           }
         } else {
           jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
@@ -421,8 +421,8 @@
         if (dst_blk_y < y_crop_blocks ||
             dst_blk_y >= y_crop_blocks + comp_height) {
           for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
-            MEMZERO(dst_buffer[offset_y],
-                    compptr->width_in_blocks * sizeof(JBLOCK));
+            memset(dst_buffer[offset_y], 0,
+                   compptr->width_in_blocks * sizeof(JBLOCK));
           }
           continue;
         }
@@ -438,7 +438,7 @@
       }
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
         if (x_crop_blocks > 0) {
-          MEMZERO(dst_buffer[offset_y], x_crop_blocks * sizeof(JBLOCK));
+          memset(dst_buffer[offset_y], 0, x_crop_blocks * sizeof(JBLOCK));
           dc = src_buffer[offset_y][0][0];
           for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) {
             dst_buffer[offset_y][dst_blk_x][0] = dc;
@@ -447,9 +447,9 @@
         jcopy_block_row(src_buffer[offset_y],
                         dst_buffer[offset_y] + x_crop_blocks, comp_width);
         if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
-          MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width,
-                  (compptr->width_in_blocks - x_crop_blocks - comp_width) *
-                  sizeof(JBLOCK));
+          memset(dst_buffer[offset_y] + x_crop_blocks + comp_width, 0,
+                 (compptr->width_in_blocks - x_crop_blocks - comp_width) *
+                 sizeof(JBLOCK));
           dc = src_buffer[offset_y][comp_width - 1][0];
           for (dst_blk_x = x_crop_blocks + comp_width;
                dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
@@ -502,8 +502,8 @@
         if (dst_blk_y < y_crop_blocks ||
             dst_blk_y >= y_crop_blocks + comp_height) {
           for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
-            MEMZERO(dst_buffer[offset_y],
-                    compptr->width_in_blocks * sizeof(JBLOCK));
+            memset(dst_buffer[offset_y], 0,
+                   compptr->width_in_blocks * sizeof(JBLOCK));
           }
           continue;
         }
@@ -591,7 +591,8 @@
         ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
          (JDIMENSION)compptr->v_samp_factor, TRUE);
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
-        MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK));
+        memset(buffer[offset_y] + x_wipe_blocks, 0,
+               wipe_width * sizeof(JBLOCK));
       }
     }
   }
@@ -626,7 +627,8 @@
         ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
          (JDIMENSION)compptr->v_samp_factor, TRUE);
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
-        MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK));
+        memset(buffer[offset_y] + x_wipe_blocks, 0,
+               wipe_width * sizeof(JBLOCK));
         if (x_wipe_blocks > 0) {
           dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0];
           if (wipe_right < compptr->width_in_blocks) {
@@ -709,8 +711,8 @@
             }
           }
         } else {
-          MEMZERO(buffer[offset_y] + x_wipe_blocks,
-                  wipe_width * sizeof(JBLOCK));
+          memset(buffer[offset_y] + x_wipe_blocks, 0,
+                 wipe_width * sizeof(JBLOCK));
         }
       }
     }
diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c
index 4fa6dfd..ba76634 100644
--- a/turbojpeg-jni.c
+++ b/turbojpeg-jni.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011-2021 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011-2022 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -29,9 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include "turbojpeg.h"
-#ifdef WIN32
-#include "tjutil.h"
-#endif
+#include "jinclude.h"
 #include <jni.h>
 #include "java/org_libjpegturbo_turbojpeg_TJCompressor.h"
 #include "java/org_libjpegturbo_turbojpeg_TJDecompressor.h"
@@ -88,10 +86,7 @@
   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "handle", "J")); \
   handle = (tjhandle)(size_t)(*env)->GetLongField(env, obj, _fid);
 
-#ifdef _WIN32
-#define setenv(envvar, value, dummy)  _putenv_s(envvar, value)
-#endif
-
+#ifndef NO_PUTENV
 #define PROP2ENV(property, envvar) { \
   if ((jName = (*env)->NewStringUTF(env, property)) != NULL) { \
     jboolean exception; \
@@ -99,11 +94,12 @@
     exception = (*env)->ExceptionCheck(env); \
     if (jValue && !exception && \
         (value = (*env)->GetStringUTFChars(env, jValue, 0)) != NULL) { \
-      setenv(envvar, value, 1); \
+      PUTENV_S(envvar, value); \
       (*env)->ReleaseStringUTFChars(env, jValue, value); \
     } \
   } \
 }
+#endif
 
 #define SAFE_RELEASE(javaArray, cArray) { \
   if (javaArray && cArray) \
@@ -122,10 +118,12 @@
   BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "getProperty",
     "(Ljava/lang/String;)Ljava/lang/String;"));
 
+#ifndef NO_PUTENV
   PROP2ENV("turbojpeg.optimize", "TJ_OPTIMIZE");
   PROP2ENV("turbojpeg.arithmetic", "TJ_ARITHMETIC");
   PROP2ENV("turbojpeg.restart", "TJ_RESTART");
   PROP2ENV("turbojpeg.progressive", "TJ_PROGRESSIVE");
+#endif
   return 0;
 
 bailout:
@@ -336,6 +334,7 @@
   jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
   const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL };
   const unsigned char *srcPlanes[3] = { NULL, NULL, NULL };
+  jint srcOffsetsTmp[3] = { 0, 0, 0 }, srcStridesTmp[3] = { 0, 0, 0 };
   int srcOffsets[3] = { 0, 0, 0 }, srcStrides[3] = { 0, 0, 0 };
   unsigned char *jpegBuf = NULL;
   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
@@ -360,11 +359,15 @@
 
   if (ProcessSystemProperties(env) < 0) goto bailout;
 
-  (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsets);
+  (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsetsTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
+  for (i = 0; i < 3; i++)
+    srcOffsets[i] = srcOffsetsTmp[i];
 
-  (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStrides);
+  (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStridesTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
+  for (i = 0; i < 3; i++)
+    srcStrides[i] = srcStridesTmp[i];
 
   for (i = 0; i < nc; i++) {
     int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
@@ -417,6 +420,7 @@
   jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
   unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL };
   unsigned char *dstPlanes[3] = { NULL, NULL, NULL };
+  jint dstOffsetsTmp[3] = { 0, 0, 0 }, dstStridesTmp[3] = { 0, 0, 0 };
   int dstOffsets[3] = { 0, 0, 0 }, dstStrides[3] = { 0, 0, 0 };
   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
 
@@ -442,11 +446,15 @@
   if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
     THROW_ARG("Source buffer is not large enough");
 
-  (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsets);
+  (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsetsTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
+  for (i = 0; i < 3; i++)
+    dstOffsets[i] = dstOffsetsTmp[i];
 
-  (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStrides);
+  (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStridesTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
+  for (i = 0; i < 3; i++)
+    dstStrides[i] = dstStridesTmp[i];
 
   for (i = 0; i < nc; i++) {
     int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp);
@@ -786,6 +794,7 @@
   jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
   unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL };
   unsigned char *dstPlanes[3] = { NULL, NULL, NULL };
+  jint dstOffsetsTmp[3] = { 0, 0, 0 }, dstStridesTmp[3] = { 0, 0, 0 };
   int dstOffsets[3] = { 0, 0, 0 }, dstStrides[3] = { 0, 0, 0 };
   int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
   int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0;
@@ -820,11 +829,15 @@
   if (i >= nsf)
     THROW_ARG("Could not scale down to desired image dimensions");
 
-  (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsets);
+  (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsetsTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
+  for (i = 0; i < 3; i++)
+    dstOffsets[i] = dstOffsetsTmp[i];
 
-  (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStrides);
+  (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStridesTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
+  for (i = 0; i < 3; i++)
+    dstStrides[i] = dstStridesTmp[i];
 
   for (i = 0; i < nc; i++) {
     int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight,
@@ -914,6 +927,7 @@
   jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
   const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL };
   const unsigned char *srcPlanes[3] = { NULL, NULL, NULL };
+  jint srcOffsetsTmp[3] = { 0, 0, 0 }, srcStridesTmp[3] = { 0, 0, 0 };
   int srcOffsets[3] = { 0, 0, 0 }, srcStrides[3] = { 0, 0, 0 };
   unsigned char *dstBuf = NULL;
   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
@@ -939,11 +953,15 @@
   if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
     THROW_ARG("Destination buffer is not large enough");
 
-  (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsets);
+  (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsetsTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
+  for (i = 0; i < 3; i++)
+    srcOffsets[i] = srcOffsetsTmp[i];
 
-  (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStrides);
+  (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStridesTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
+  for (i = 0; i < 3; i++)
+    srcStrides[i] = srcStridesTmp[i];
 
   for (i = 0; i < nc; i++) {
     int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
diff --git a/turbojpeg.c b/turbojpeg.c
index 4f9e1f6..d5e3136 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2009-2021 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2009-2022 D. R. Commander.  All Rights Reserved.
  * Copyright (C)2021 Alex Richardson.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -196,10 +196,19 @@
   snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
   retval = -1;  goto bailout; \
 }
+#ifdef _MSC_VER
+#define THROW_UNIX(m) { \
+  char strerrorBuf[80] = { 0 }; \
+  strerror_s(strerrorBuf, 80, errno); \
+  snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerrorBuf); \
+  retval = -1;  goto bailout; \
+}
+#else
 #define THROW_UNIX(m) { \
   snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \
   retval = -1;  goto bailout; \
 }
+#endif
 #define THROW(m) { \
   snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
   this->isInstanceError = TRUE;  THROWG(m) \
@@ -271,7 +280,7 @@
                             int flags)
 {
 #ifndef NO_GETENV
-  char *env = NULL;
+  char env[7] = { 0 };
 #endif
 
   cinfo->in_color_space = pf2cs[pixelFormat];
@@ -279,18 +288,21 @@
   jpeg_set_defaults(cinfo);
 
 #ifndef NO_GETENV
-  if ((env = getenv("TJ_OPTIMIZE")) != NULL && strlen(env) > 0 &&
-      !strcmp(env, "1"))
+  if (!GETENV_S(env, 7, "TJ_OPTIMIZE") && !strcmp(env, "1"))
     cinfo->optimize_coding = TRUE;
-  if ((env = getenv("TJ_ARITHMETIC")) != NULL && strlen(env) > 0 &&
-      !strcmp(env, "1"))
+  if (!GETENV_S(env, 7, "TJ_ARITHMETIC") && !strcmp(env, "1"))
     cinfo->arith_code = TRUE;
-  if ((env = getenv("TJ_RESTART")) != NULL && strlen(env) > 0) {
+  if (!GETENV_S(env, 7, "TJ_RESTART") && strlen(env) > 0) {
     int temp = -1;
     char tempc = 0;
 
+#ifdef _MSC_VER
+    if (sscanf_s(env, "%d%c", &temp, &tempc, 1) >= 1 && temp >= 0 &&
+        temp <= 65535) {
+#else
     if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 &&
         temp <= 65535) {
+#endif
       if (toupper(tempc) == 'B') {
         cinfo->restart_interval = temp;
         cinfo->restart_in_rows = 0;
@@ -317,8 +329,7 @@
   if (flags & TJFLAG_PROGRESSIVE)
     jpeg_simple_progression(cinfo);
 #ifndef NO_GETENV
-  else if ((env = getenv("TJ_PROGRESSIVE")) != NULL && strlen(env) > 0 &&
-           !strcmp(env, "1"))
+  else if (!GETENV_S(env, 7, "TJ_PROGRESSIVE") && !strcmp(env, "1"))
     jpeg_simple_progression(cinfo);
 #endif
 
@@ -514,7 +525,7 @@
              "tjInitCompress(): Memory allocation failure");
     return NULL;
   }
-  MEMZERO(this, sizeof(tjinstance));
+  memset(this, 0, sizeof(tjinstance));
   snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
   return _tjInitCompress(this);
 }
@@ -669,7 +680,8 @@
                           unsigned char **jpegBuf, unsigned long *jpegSize,
                           int jpegSubsamp, int jpegQual, int flags)
 {
-  int i, retval = 0, alloc = 1;
+  int i, retval = 0;
+  boolean alloc = TRUE;
   JSAMPROW *row_pointer = NULL;
 
   GET_CINSTANCE(handle)
@@ -697,13 +709,13 @@
   cinfo->image_height = height;
 
 #ifndef NO_PUTENV
-  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
-  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
-  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
+  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
+  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
 #endif
 
   if (flags & TJFLAG_NOREALLOC) {
-    alloc = 0;  *jpegSize = tjBufSize(width, height, jpegSubsamp);
+    alloc = FALSE;  *jpegSize = tjBufSize(width, height, jpegSubsamp);
   }
   jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
   setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags);
@@ -799,9 +811,9 @@
   cinfo->image_height = height;
 
 #ifndef NO_PUTENV
-  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
-  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
-  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
+  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
+  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
 #endif
 
   setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags);
@@ -977,7 +989,8 @@
                                       unsigned long *jpegSize, int jpegQual,
                                       int flags)
 {
-  int i, row, retval = 0, alloc = 1;
+  int i, row, retval = 0;
+  boolean alloc = TRUE;
   int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
     tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
   JSAMPLE *_tmpbuf = NULL, *ptr;
@@ -1009,13 +1022,13 @@
   cinfo->image_height = height;
 
 #ifndef NO_PUTENV
-  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
-  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
-  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
+  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
+  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
 #endif
 
   if (flags & TJFLAG_NOREALLOC) {
-    alloc = 0;  *jpegSize = tjBufSize(width, height, subsamp);
+    alloc = FALSE;  *jpegSize = tjBufSize(width, height, subsamp);
   }
   jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
   setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags);
@@ -1186,7 +1199,7 @@
              "tjInitDecompress(): Memory allocation failure");
     return NULL;
   }
-  MEMZERO(this, sizeof(tjinstance));
+  memset(this, 0, sizeof(tjinstance));
   snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
   return _tjInitDecompress(this);
 }
@@ -1295,13 +1308,13 @@
     THROW("tjDecompress2(): Invalid argument");
 
 #ifndef NO_PUTENV
-  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
-  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
-  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
+  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
+  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
 #endif
 
   if (flags & TJFLAG_LIMITSCANS) {
-    MEMZERO(&progress, sizeof(struct my_progress_mgr));
+    memset(&progress, 0, sizeof(struct my_progress_mgr));
     progress.pub.progress_monitor = my_progress_monitor;
     progress.this = this;
     dinfo->progress = &progress.pub;
@@ -1471,9 +1484,9 @@
   dinfo->image_height = height;
 
 #ifndef NO_PUTENV
-  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
-  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
-  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
+  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
+  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
 #endif
 
   dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
@@ -1643,13 +1656,13 @@
     THROW("tjDecompressToYUVPlanes(): Invalid argument");
 
 #ifndef NO_PUTENV
-  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
-  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
-  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
+  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
+  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
 #endif
 
   if (flags & TJFLAG_LIMITSCANS) {
-    MEMZERO(&progress, sizeof(struct my_progress_mgr));
+    memset(&progress, 0, sizeof(struct my_progress_mgr));
     progress.pub.progress_monitor = my_progress_monitor;
     progress.this = this;
     dinfo->progress = &progress.pub;
@@ -1877,7 +1890,7 @@
              "tjInitTransform(): Memory allocation failure");
     return NULL;
   }
-  MEMZERO(this, sizeof(tjinstance));
+  memset(this, 0, sizeof(tjinstance));
   snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
   handle = _tjInitCompress(this);
   if (!handle) return NULL;
@@ -1893,7 +1906,8 @@
 {
   jpeg_transform_info *xinfo = NULL;
   jvirt_barray_ptr *srccoefs, *dstcoefs;
-  int retval = 0, alloc = 1, i, jpegSubsamp, saveMarkers = 0;
+  int retval = 0, i, jpegSubsamp, saveMarkers = 0;
+  boolean alloc = TRUE;
   struct my_progress_mgr progress;
 
   GET_INSTANCE(handle);
@@ -1906,13 +1920,13 @@
     THROW("tjTransform(): Invalid argument");
 
 #ifndef NO_PUTENV
-  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
-  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
-  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
+  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
+  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
 #endif
 
   if (flags & TJFLAG_LIMITSCANS) {
-    MEMZERO(&progress, sizeof(struct my_progress_mgr));
+    memset(&progress, 0, sizeof(struct my_progress_mgr));
     progress.pub.progress_monitor = my_progress_monitor;
     progress.this = this;
     dinfo->progress = &progress.pub;
@@ -1922,7 +1936,7 @@
   if ((xinfo =
        (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
     THROW("tjTransform(): Memory allocation failure");
-  MEMZERO(xinfo, sizeof(jpeg_transform_info) * n);
+  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -1989,7 +2003,7 @@
       w = xinfo[i].crop_width;  h = xinfo[i].crop_height;
     }
     if (flags & TJFLAG_NOREALLOC) {
-      alloc = 0;  dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
+      alloc = FALSE;  dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
     }
     if (!(t[i].options & TJXOPT_NOOUTPUT))
       jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
@@ -2010,13 +2024,13 @@
 
       for (ci = 0; ci < cinfo->num_components; ci++) {
         jpeg_component_info *compptr = &cinfo->comp_info[ci];
-        tjregion arrayRegion = {
-          0, 0, compptr->width_in_blocks * DCTSIZE, DCTSIZE
-        };
-        tjregion planeRegion = {
-          0, 0, compptr->width_in_blocks * DCTSIZE,
-          compptr->height_in_blocks * DCTSIZE
-        };
+        tjregion arrayRegion = { 0, 0, 0, 0 };
+        tjregion planeRegion = { 0, 0, 0, 0 };
+
+        arrayRegion.w = compptr->width_in_blocks * DCTSIZE;
+        arrayRegion.h = DCTSIZE;
+        planeRegion.w = compptr->width_in_blocks * DCTSIZE;
+        planeRegion.h = compptr->height_in_blocks * DCTSIZE;
 
         for (by = 0; by < compptr->height_in_blocks;
              by += compptr->v_samp_factor) {
@@ -2075,7 +2089,11 @@
   this = (tjinstance *)handle;
   cinfo = &this->cinfo;
 
+#ifdef _MSC_VER
+  if (fopen_s(&file, filename, "rb") || file == NULL)
+#else
   if ((file = fopen(filename, "rb")) == NULL)
+#endif
     THROW_UNIX("tjLoadImage(): Cannot open input file");
 
   if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
@@ -2171,7 +2189,11 @@
   this = (tjinstance *)handle;
   dinfo = &this->dinfo;
 
+#ifdef _MSC_VER
+  if (fopen_s(&file, filename, "wb") || file == NULL)
+#else
   if ((file = fopen(filename, "wb")) == NULL)
+#endif
     THROW_UNIX("tjSaveImage(): Cannot open output file");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
diff --git a/turbojpeg.h b/turbojpeg.h
index c2f6b51..5b33ad8 100644
--- a/turbojpeg.h
+++ b/turbojpeg.h
@@ -673,7 +673,7 @@
  * scalingFactor)</tt>.
  */
 #define TJSCALED(dimension, scalingFactor) \
-  ((dimension * scalingFactor.num + scalingFactor.denom - 1) / \
+  (((dimension) * scalingFactor.num + scalingFactor.denom - 1) / \
    scalingFactor.denom)
 
 
diff --git a/usage.txt b/usage.txt
index b60a593..bc2253f 100644
--- a/usage.txt
+++ b/usage.txt
@@ -72,12 +72,9 @@
                           Quality is 0 (worst) to 100 (best); default is 75.
                           (See below for more info.)
 
-        -grayscale      Create monochrome JPEG file from color input.
-                        Be sure to use this switch when compressing a grayscale
-                        BMP or GIF file, because cjpeg isn't bright enough to
-                        notice whether a BMP or GIF file uses only shades of
-                        gray.  By saying -grayscale, you'll get a smaller JPEG
-                        file that takes less time to process.
+        -grayscale      Create monochrome JPEG file from color input.  By
+                        saying -grayscale, you'll get a smaller JPEG file that
+                        takes less time to process.
 
         -rgb            Create RGB JPEG file.
                         Using this switch suppresses the conversion from RGB
diff --git a/wrbmp.c b/wrbmp.c
index 408a722..45fff68 100644
--- a/wrbmp.c
+++ b/wrbmp.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * libjpeg-turbo Modifications:
  * Copyright (C) 2013, Linaro Limited.
- * Copyright (C) 2014-2015, 2017, 2019, D. R. Commander.
+ * Copyright (C) 2014-2015, 2017, 2019, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -121,7 +121,7 @@
   inptr = dest->pub.buffer[0];
 
   if (cinfo->out_color_space == JCS_EXT_BGR) {
-    MEMCOPY(outptr, inptr, dest->row_width);
+    memcpy(outptr, inptr, dest->row_width);
     outptr += cinfo->output_width * 3;
   } else if (cinfo->out_color_space == JCS_RGB565) {
     boolean big_endian = is_big_endian();
@@ -165,7 +165,7 @@
     *outptr++ = 0;
 
   if (!dest->use_inversion_array)
-    (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->row_width);
+    fwrite(dest->iobuffer, 1, dest->row_width, dest->pub.output_file);
 }
 
 METHODDEF(void)
@@ -191,7 +191,7 @@
 
   /* Transfer data. */
   inptr = dest->pub.buffer[0];
-  MEMCOPY(outptr, inptr, cinfo->output_width);
+  memcpy(outptr, inptr, cinfo->output_width);
   outptr += cinfo->output_width;
 
   /* Zero out the pad bytes. */
@@ -200,7 +200,7 @@
     *outptr++ = 0;
 
   if (!dest->use_inversion_array)
-    (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->row_width);
+    fwrite(dest->iobuffer, 1, dest->row_width, dest->pub.output_file);
 }
 
 
@@ -256,8 +256,8 @@
   bfSize = headersize + (long)dest->row_width * (long)cinfo->output_height;
 
   /* Set unused fields of header to 0 */
-  MEMZERO(bmpfileheader, sizeof(bmpfileheader));
-  MEMZERO(bmpinfoheader, sizeof(bmpinfoheader));
+  memset(bmpfileheader, 0, sizeof(bmpfileheader));
+  memset(bmpinfoheader, 0, sizeof(bmpinfoheader));
 
   /* Fill the file header */
   bmpfileheader[0] = 0x42;      /* first 2 bytes are ASCII 'B', 'M' */
@@ -281,9 +281,9 @@
   PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
   /* we leave biClrImportant = 0 */
 
-  if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t)14)
+  if (fwrite(bmpfileheader, 1, 14, dest->pub.output_file) != (size_t)14)
     ERREXIT(cinfo, JERR_FILE_WRITE);
-  if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t)40)
+  if (fwrite(bmpinfoheader, 1, 40, dest->pub.output_file) != (size_t)40)
     ERREXIT(cinfo, JERR_FILE_WRITE);
 
   if (cmap_entries > 0)
@@ -325,8 +325,8 @@
   bfSize = headersize + (long)dest->row_width * (long)cinfo->output_height;
 
   /* Set unused fields of header to 0 */
-  MEMZERO(bmpfileheader, sizeof(bmpfileheader));
-  MEMZERO(bmpcoreheader, sizeof(bmpcoreheader));
+  memset(bmpfileheader, 0, sizeof(bmpfileheader));
+  memset(bmpcoreheader, 0, sizeof(bmpcoreheader));
 
   /* Fill the file header */
   bmpfileheader[0] = 0x42;      /* first 2 bytes are ASCII 'B', 'M' */
@@ -342,9 +342,9 @@
   PUT_2B(bmpcoreheader, 8, 1);  /* bcPlanes - must be 1 */
   PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */
 
-  if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t)14)
+  if (fwrite(bmpfileheader, 1, 14, dest->pub.output_file) != (size_t)14)
     ERREXIT(cinfo, JERR_FILE_WRITE);
-  if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t)12)
+  if (fwrite(bmpcoreheader, 1, 12, dest->pub.output_file) != (size_t)12)
     ERREXIT(cinfo, JERR_FILE_WRITE);
 
   if (cmap_entries > 0)
@@ -456,7 +456,7 @@
         ((j_common_ptr)cinfo, dest->whole_image, row - 1, (JDIMENSION)1,
          FALSE);
       data_ptr = image_ptr[0];
-      (void)JFWRITE(outfile, data_ptr, dest->row_width);
+      fwrite(data_ptr, 1, dest->row_width, outfile);
     }
     if (progress != NULL)
       progress->completed_extra_passes++;
diff --git a/wrgif.c b/wrgif.c
index 82a2429..620a3ba 100644
--- a/wrgif.c
+++ b/wrgif.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * Modified 2015-2019 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2015, 2017, D. R. Commander.
+ * Copyright (C) 2015, 2017, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -114,8 +114,8 @@
 {
   if (dinfo->bytesinpkt > 0) {  /* never write zero-length packet */
     dinfo->packetbuf[0] = (char)dinfo->bytesinpkt++;
-    if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt) !=
-        (size_t)dinfo->bytesinpkt)
+    if (fwrite(dinfo->packetbuf, 1, dinfo->bytesinpkt,
+               dinfo->pub.output_file) != (size_t)dinfo->bytesinpkt)
       ERREXIT(dinfo->cinfo, JERR_FILE_WRITE);
     dinfo->bytesinpkt = 0;
   }
@@ -169,7 +169,7 @@
 /* Fill the hash table with empty entries */
 {
   /* It's sufficient to zero hash_code[] */
-  MEMZERO(dinfo->hash_code, HSIZE * sizeof(code_int));
+  memset(dinfo->hash_code, 0, HSIZE * sizeof(code_int));
 }
 
 
diff --git a/wrjpgcom.1 b/wrjpgcom.1
deleted file mode 100644
index a255cab..0000000
--- a/wrjpgcom.1
+++ /dev/null
@@ -1,103 +0,0 @@
-.TH WRJPGCOM 1 "15 June 1995"
-.SH NAME
-wrjpgcom \- insert text comments into a JPEG file
-.SH SYNOPSIS
-.B wrjpgcom
-[
-.B \-replace
-]
-[
-.BI \-comment " text"
-]
-[
-.BI \-cfile " name"
-]
-[
-.I filename
-]
-.LP
-.SH DESCRIPTION
-.LP
-.B wrjpgcom
-reads the named JPEG/JFIF file, or the standard input if no file is named,
-and generates a new JPEG/JFIF file on standard output.  A comment block is
-added to the file.
-.PP
-The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
-Although the standard doesn't actually define what COM blocks are for, they
-are widely used to hold user-supplied text strings.  This lets you add
-annotations, titles, index terms, etc to your JPEG files, and later retrieve
-them as text.  COM blocks do not interfere with the image stored in the JPEG
-file.  The maximum size of a COM block is 64K, but you can have as many of
-them as you like in one JPEG file.
-.PP
-.B wrjpgcom
-adds a COM block, containing text you provide, to a JPEG file.
-Ordinarily, the COM block is added after any existing COM blocks; but you
-can delete the old COM blocks if you wish.
-.SH OPTIONS
-Switch names may be abbreviated, and are not case sensitive.
-.TP
-.B \-replace
-Delete any existing COM blocks from the file.
-.TP
-.BI \-comment " text"
-Supply text for new COM block on command line.
-.TP
-.BI \-cfile " name"
-Read text for new COM block from named file.
-.PP
-If you have only one line of comment text to add, you can provide it on the
-command line with
-.BR \-comment .
-The comment text must be surrounded with quotes so that it is treated as a
-single argument.  Longer comments can be read from a text file.
-.PP
-If you give neither
-.B \-comment
-nor
-.BR \-cfile,
-then
-.B wrjpgcom
-will read the comment text from standard input.  (In this case an input image
-file name MUST be supplied, so that the source JPEG file comes from somewhere
-else.)  You can enter multiple lines, up to 64KB worth.  Type an end-of-file
-indicator (usually control-D) to terminate the comment text entry.
-.PP
-.B wrjpgcom
-will not add a COM block if the provided comment string is empty.  Therefore
-\fB\-replace \-comment ""\fR can be used to delete all COM blocks from a file.
-.SH EXAMPLES
-.LP
-Add a short comment to in.jpg, producing out.jpg:
-.IP
-.B wrjpgcom \-c
-\fI"View of my back yard" in.jpg
-.B >
-.I out.jpg
-.PP
-Attach a long comment previously stored in comment.txt:
-.IP
-.B wrjpgcom
-.I in.jpg
-.B <
-.I comment.txt
-.B >
-.I out.jpg
-.PP
-or equivalently
-.IP
-.B wrjpgcom
-.B -cfile
-.I comment.txt
-.B <
-.I in.jpg
-.B >
-.I out.jpg
-.SH SEE ALSO
-.BR cjpeg (1),
-.BR djpeg (1),
-.BR jpegtran (1),
-.BR rdjpgcom (1)
-.SH AUTHOR
-Independent JPEG Group
diff --git a/wrjpgcom.c b/wrjpgcom.c
index 8a4e741..3ee08a0 100644
--- a/wrjpgcom.c
+++ b/wrjpgcom.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2014, D. R. Commander.
+ * Copyright (C) 2014, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -14,12 +14,13 @@
  * JPEG markers.
  */
 
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
 #define JPEG_CJPEG_DJPEG        /* to get the command-line config symbols */
 #include "jinclude.h"           /* get auto-config symbols, <stdio.h> */
 
-#ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare malloc() */
-extern void *malloc();
-#endif
 #include <ctype.h>              /* to declare isupper(), tolower() */
 #ifdef USE_SETMODE
 #include <fcntl.h>              /* to declare setmode()'s parameter macros */
diff --git a/wrppm.c b/wrppm.c
index 3081ec3..57c8aaf 100644
--- a/wrppm.c
+++ b/wrppm.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1996, Thomas G. Lane.
  * Modified 2009 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2017, 2019-2020, D. R. Commander.
+ * Copyright (C) 2017, 2019-2020, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -92,7 +92,7 @@
 {
   ppm_dest_ptr dest = (ppm_dest_ptr)dinfo;
 
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }
 
 
@@ -115,13 +115,13 @@
   ptr = dest->pub.buffer[0];
   bufferptr = dest->iobuffer;
 #if BITS_IN_JSAMPLE == 8
-  MEMCOPY(bufferptr, ptr, dest->samples_per_row);
+  memcpy(bufferptr, ptr, dest->samples_per_row);
 #else
   for (col = dest->samples_per_row; col > 0; col--) {
     PUTPPMSAMPLE(bufferptr, *ptr++);
   }
 #endif
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }
 
 
@@ -149,7 +149,7 @@
     PUTPPMSAMPLE(bufferptr, ptr[bindex]);
     ptr += ps;
   }
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }
 
 
@@ -175,7 +175,7 @@
     PUTPPMSAMPLE(bufferptr, g);
     PUTPPMSAMPLE(bufferptr, b);
   }
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }
 
 
@@ -205,7 +205,7 @@
     PUTPPMSAMPLE(bufferptr, color_map1[pixval]);
     PUTPPMSAMPLE(bufferptr, color_map2[pixval]);
   }
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }
 
 
@@ -224,7 +224,7 @@
   for (col = cinfo->output_width; col > 0; col--) {
     PUTPPMSAMPLE(bufferptr, color_map[*ptr++]);
   }
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }
 
 
diff --git a/wrtarga.c b/wrtarga.c
index 7a654ff..67ca1f0 100644
--- a/wrtarga.c
+++ b/wrtarga.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1996, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2017, 2019, D. R. Commander.
+ * Copyright (C) 2017, 2019, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -51,7 +51,7 @@
   char targaheader[18];
 
   /* Set unused fields of header to 0 */
-  MEMZERO(targaheader, sizeof(targaheader));
+  memset(targaheader, 0, sizeof(targaheader));
 
   if (num_colors > 0) {
     targaheader[1] = 1;         /* color map type 1 */
@@ -79,7 +79,7 @@
     }
   }
 
-  if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t)18)
+  if (fwrite(targaheader, 1, 18, dinfo->output_file) != (size_t)18)
     ERREXIT(cinfo, JERR_FILE_WRITE);
 }
 
@@ -107,7 +107,7 @@
     outptr[2] = inptr[0];
     inptr += 3, outptr += 3;
   }
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }
 
 METHODDEF(void)
@@ -121,8 +121,8 @@
 
   inptr = dest->pub.buffer[0];
   outptr = dest->iobuffer;
-  MEMCOPY(outptr, inptr, cinfo->output_width);
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  memcpy(outptr, inptr, cinfo->output_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }
 
 
@@ -146,7 +146,7 @@
   for (col = cinfo->output_width; col > 0; col--) {
     *outptr++ = color_map0[*inptr++];
   }
-  (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+  fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file);
 }