[RESTRICT AUTOMERGE] TurboJPEG: Properly handle gigapixel images

Bug: 120551338
Test: tj64 /data/local/tmp/crash-46.jpg
See b/120551338#comment1 to get crash-46.jpg

Submitted upstream as 2a9e3b. Original commit message:

========================================================================
Prevent several integer overflow issues and subsequent segfaults that
occurred when attempting to compress or decompress gigapixel images with
the TurboJPEG API:

- Modify tjBufSize(), tjBufSizeYUV2(), and tjPlaneSizeYUV() to avoid
  integer overflow when computing the return values and to return an
  error if such an overflow is unavoidable.
- Modify tjunittest to validate the above.
- Modify tjCompress2(), tjEncodeYUVPlanes(), tjDecompress2(), and
  tjDecodeYUVPlanes() to avoid integer overflow when computing the row
  pointers in the 64-bit TurboJPEG C API.
- Modify TJBench (both C and Java versions) to avoid overflowing the
  size argument to malloc()/new and to fail gracefully if such an
  overflow is unavoidable.

In general, this allows gigapixel images to be accommodated by the
64-bit TurboJPEG C API when using automatic JPEG buffer (re)allocation.
Such images cannot currently be accommodated without automatic JPEG
buffer (re)allocation, due to the fact that tjAlloc() accepts a 32-bit
integer argument (oops.)  Such images cannot be accommodated in the
TurboJPEG Java API due to the fact that Java always uses a signed 32-bit
integer as an array index.

Fixes #361
========================================================================

In addition, this cherry-pick includes commit bce58f from upstream,
which defines the macro THROWG (used in the above commit) and simplifies
the merge. Original commit message:

========================================================================
Consistify formatting of macros in TurboJPEG code
========================================================================

Conflicts:
    ChangeLog.md
    tjunittest.c

Update README.android noting the cherry-picks.

Change-Id: I472f52c15eaaaf7995249d1fb488079955cd7c61
Merged-In: I472f52c15eaaaf7995249d1fb488079955cd7c61
diff --git a/turbojpeg.c b/turbojpeg.c
index b3caa0d..1f99786 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -50,7 +50,7 @@
                             unsigned long);
 
 #define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
-#define isPow2(x)  (((x) & (x - 1)) == 0)
+#define IS_POW2(x)  (((x) & (x - 1)) == 0)
 
 
 /* Error handling (based on example in example.txt) */
@@ -164,20 +164,20 @@
   TJPF_UNKNOWN
 };
 
-#define _throwg(m) { \
+#define THROWG(m) { \
   snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
   retval = -1;  goto bailout; \
 }
-#define _throwunix(m) { \
+#define THROW_UNIX(m) { \
   snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \
   retval = -1;  goto bailout; \
 }
-#define _throw(m) { \
+#define THROW(m) { \
   snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
-  this->isInstanceError = TRUE;  _throwg(m) \
+  this->isInstanceError = TRUE;  THROWG(m) \
 }
 
-#define getinstance(handle) \
+#define GET_INSTANCE(handle) \
   tjinstance *this = (tjinstance *)handle; \
   j_compress_ptr cinfo = NULL; \
   j_decompress_ptr dinfo = NULL; \
@@ -190,7 +190,7 @@
   this->jerr.warning = FALSE; \
   this->isInstanceError = FALSE;
 
-#define getcinstance(handle) \
+#define GET_CINSTANCE(handle) \
   tjinstance *this = (tjinstance *)handle; \
   j_compress_ptr cinfo = NULL; \
   \
@@ -202,7 +202,7 @@
   this->jerr.warning = FALSE; \
   this->isInstanceError = FALSE;
 
-#define getdinstance(handle) \
+#define GET_DINSTANCE(handle) \
   tjinstance *this = (tjinstance *)handle; \
   j_decompress_ptr dinfo = NULL; \
   \
@@ -413,7 +413,7 @@
 
 DLLEXPORT int tjDestroy(tjhandle handle)
 {
-  getinstance(handle);
+  GET_INSTANCE(handle);
 
   if (setjmp(this->jerr.setjmp_buffer)) return -1;
   if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
@@ -489,11 +489,11 @@
 
 DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
 {
-  unsigned long retval = 0;
+  unsigned long long retval = 0;
   int mcuw, mcuh, chromasf;
 
   if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT)
-    _throwg("tjBufSize(): Invalid argument");
+    THROWG("tjBufSize(): Invalid argument");
 
   /* This allows for rare corner cases in which a JPEG image can actually be
      larger than the uncompressed input (we wouldn't mention it if it hadn't
@@ -501,36 +501,41 @@
   mcuw = tjMCUWidth[jpegSubsamp];
   mcuh = tjMCUHeight[jpegSubsamp];
   chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
-  retval = PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
+  retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
+  if (retval > (unsigned long long)((unsigned long)-1))
+    THROWG("tjBufSize(): Image is too large");
 
 bailout:
-  return retval;
+  return (unsigned long)retval;
 }
 
 DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
 {
-  unsigned long retval = 0;
+  unsigned long long retval = 0;
 
   if (width < 1 || height < 1)
-    _throwg("TJBUFSIZE(): Invalid argument");
+    THROWG("TJBUFSIZE(): Invalid argument");
 
   /* This allows for rare corner cases in which a JPEG image can actually be
      larger than the uncompressed input (we wouldn't mention it if it hadn't
      happened before.) */
-  retval = PAD(width, 16) * PAD(height, 16) * 6 + 2048;
+  retval = PAD(width, 16) * PAD(height, 16) * 6ULL + 2048ULL;
+  if (retval > (unsigned long long)((unsigned long)-1))
+    THROWG("TJBUFSIZE(): Image is too large");
 
 bailout:
-  return retval;
+  return (unsigned long)retval;
 }
 
 
 DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
                                       int subsamp)
 {
-  int retval = 0, nc, i;
+  unsigned long long retval = 0;
+  int nc, i;
 
   if (subsamp < 0 || subsamp >= NUMSUBOPT)
-    _throwg("tjBufSizeYUV2(): Invalid argument");
+    THROWG("tjBufSizeYUV2(): Invalid argument");
 
   nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
   for (i = 0; i < nc; i++) {
@@ -539,11 +544,13 @@
     int ph = tjPlaneHeight(i, height, subsamp);
 
     if (pw < 0 || ph < 0) return -1;
-    else retval += stride * ph;
+    else retval += (unsigned long long)stride * ph;
   }
+  if (retval > (unsigned long long)((unsigned long)-1))
+    THROWG("tjBufSizeYUV2(): Image is too large");
 
 bailout:
-  return retval;
+  return (unsigned long)retval;
 }
 
 DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
@@ -562,10 +569,10 @@
   int pw, nc, retval = 0;
 
   if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
-    _throwg("tjPlaneWidth(): Invalid argument");
+    THROWG("tjPlaneWidth(): Invalid argument");
   nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
   if (componentID < 0 || componentID >= nc)
-    _throwg("tjPlaneWidth(): Invalid argument");
+    THROWG("tjPlaneWidth(): Invalid argument");
 
   pw = PAD(width, tjMCUWidth[subsamp] / 8);
   if (componentID == 0)
@@ -583,10 +590,10 @@
   int ph, nc, retval = 0;
 
   if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
-    _throwg("tjPlaneHeight(): Invalid argument");
+    THROWG("tjPlaneHeight(): Invalid argument");
   nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
   if (componentID < 0 || componentID >= nc)
-    _throwg("tjPlaneHeight(): Invalid argument");
+    THROWG("tjPlaneHeight(): Invalid argument");
 
   ph = PAD(height, tjMCUHeight[subsamp] / 8);
   if (componentID == 0)
@@ -602,11 +609,11 @@
 DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
                                        int height, int subsamp)
 {
-  unsigned long retval = 0;
+  unsigned long long retval = 0;
   int pw, ph;
 
   if (width < 1 || height < 1 || subsamp < 0 || subsamp >= NUMSUBOPT)
-    _throwg("tjPlaneSizeYUV(): Invalid argument");
+    THROWG("tjPlaneSizeYUV(): Invalid argument");
 
   pw = tjPlaneWidth(componentID, width, subsamp);
   ph = tjPlaneHeight(componentID, height, subsamp);
@@ -615,10 +622,12 @@
   if (stride == 0) stride = pw;
   else stride = abs(stride);
 
-  retval = stride * (ph - 1) + pw;
+  retval = (unsigned long long)stride * (ph - 1) + pw;
+  if (retval > (unsigned long long)((unsigned long)-1))
+    THROWG("tjPlaneSizeYUV(): Image is too large");
 
 bailout:
-  return retval;
+  return (unsigned long)retval;
 }
 
 
@@ -630,21 +639,21 @@
   int i, retval = 0, alloc = 1;
   JSAMPROW *row_pointer = NULL;
 
-  getcinstance(handle)
+  GET_CINSTANCE(handle)
   this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
   if ((this->init & COMPRESS) == 0)
-    _throw("tjCompress2(): Instance has not been initialized for compression");
+    THROW("tjCompress2(): Instance has not been initialized for compression");
 
   if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
       pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
       jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT ||
       jpegQual < 0 || jpegQual > 100)
-    _throw("tjCompress2(): Invalid argument");
+    THROW("tjCompress2(): Invalid argument");
 
   if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
 
   if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL)
-    _throw("tjCompress2(): Memory allocation failure");
+    THROW("tjCompress2(): Memory allocation failure");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -670,9 +679,9 @@
   jpeg_start_compress(cinfo, TRUE);
   for (i = 0; i < height; i++) {
     if (flags & TJFLAG_BOTTOMUP)
-      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * pitch];
+      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
     else
-      row_pointer[i] = (JSAMPROW)&srcBuf[i * pitch];
+      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
   }
   while (cinfo->next_scanline < cinfo->image_height)
     jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
@@ -723,7 +732,7 @@
   JSAMPLE *ptr;
   jpeg_component_info *compptr;
 
-  getcinstance(handle);
+  GET_CINSTANCE(handle);
   this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
 
   for (i = 0; i < MAX_COMPONENTS; i++) {
@@ -732,17 +741,17 @@
   }
 
   if ((this->init & COMPRESS) == 0)
-    _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
+    THROW("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
 
   if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
       pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
       !dstPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT)
-    _throw("tjEncodeYUVPlanes(): Invalid argument");
+    THROW("tjEncodeYUVPlanes(): Invalid argument");
   if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
-    _throw("tjEncodeYUVPlanes(): Invalid argument");
+    THROW("tjEncodeYUVPlanes(): Invalid argument");
 
   if (pixelFormat == TJPF_CMYK)
-    _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
+    THROW("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
 
   if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
 
@@ -767,7 +776,7 @@
      to write the file headers, which could overflow the output buffer if the
      YUV image were very small. */
   if (cinfo->global_state != CSTATE_START)
-    _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
+    THROW("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
   (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
   jinit_c_master_control(cinfo, FALSE);
   jinit_color_converter(cinfo);
@@ -778,12 +787,12 @@
   ph0 = PAD(height, cinfo->max_v_samp_factor);
 
   if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
-    _throw("tjEncodeYUVPlanes(): Memory allocation failure");
+    THROW("tjEncodeYUVPlanes(): Memory allocation failure");
   for (i = 0; i < height; i++) {
     if (flags & TJFLAG_BOTTOMUP)
-      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * pitch];
+      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
     else
-      row_pointer[i] = (JSAMPROW)&srcBuf[i * pitch];
+      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
   }
   if (height < ph0)
     for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
@@ -795,11 +804,11 @@
           compptr->h_samp_factor, 32) *
       cinfo->max_v_samp_factor + 32);
     if (!_tmpbuf[i])
-      _throw("tjEncodeYUVPlanes(): Memory allocation failure");
+      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
     tmpbuf[i] =
       (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
     if (!tmpbuf[i])
-      _throw("tjEncodeYUVPlanes(): Memory allocation failure");
+      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
     for (row = 0; row < cinfo->max_v_samp_factor; row++) {
       unsigned char *_tmpbuf_aligned =
         (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
@@ -812,10 +821,10 @@
       (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
                         compptr->v_samp_factor + 32);
     if (!_tmpbuf2[i])
-      _throw("tjEncodeYUVPlanes(): Memory allocation failure");
+      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
     tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
     if (!tmpbuf2[i])
-      _throw("tjEncodeYUVPlanes(): Memory allocation failure");
+      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
     for (row = 0; row < compptr->v_samp_factor; row++) {
       unsigned char *_tmpbuf2_aligned =
         (unsigned char *)PAD((size_t)_tmpbuf2[i], 32);
@@ -827,7 +836,7 @@
     ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
     outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
     if (!outbuf[i])
-      _throw("tjEncodeYUVPlanes(): Memory allocation failure");
+      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
     ptr = dstPlanes[i];
     for (row = 0; row < ph[i]; row++) {
       outbuf[i][row] = ptr;
@@ -877,12 +886,12 @@
   int pw0, ph0, strides[3], retval = -1;
   tjinstance *this = (tjinstance *)handle;
 
-  if (!this) _throwg("tjEncodeYUV3(): Invalid handle");
+  if (!this) THROWG("tjEncodeYUV3(): Invalid handle");
   this->isInstanceError = FALSE;
 
-  if (width <= 0 || height <= 0 || dstBuf == NULL || pad < 0 || !isPow2(pad) ||
-      subsamp < 0 || subsamp >= NUMSUBOPT)
-    _throw("tjEncodeYUV3(): Invalid argument");
+  if (width <= 0 || height <= 0 || dstBuf == NULL || pad < 0 ||
+      !IS_POW2(pad) || subsamp < 0 || subsamp >= NUMSUBOPT)
+    THROW("tjEncodeYUV3(): Invalid argument");
 
   pw0 = tjPlaneWidth(0, width, subsamp);
   ph0 = tjPlaneHeight(0, height, subsamp);
@@ -939,7 +948,7 @@
   JSAMPLE *_tmpbuf = NULL, *ptr;
   JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
 
-  getcinstance(handle)
+  GET_CINSTANCE(handle)
   this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
 
   for (i = 0; i < MAX_COMPONENTS; i++) {
@@ -947,14 +956,14 @@
   }
 
   if ((this->init & COMPRESS) == 0)
-    _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
+    THROW("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
 
   if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
       subsamp < 0 || subsamp >= NUMSUBOPT || jpegBuf == NULL ||
       jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
-    _throw("tjCompressFromYUVPlanes(): Invalid argument");
+    THROW("tjCompressFromYUVPlanes(): Invalid argument");
   if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
-    _throw("tjCompressFromYUVPlanes(): Invalid argument");
+    THROW("tjCompressFromYUVPlanes(): Invalid argument");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -993,7 +1002,7 @@
     th[i] = compptr->v_samp_factor * DCTSIZE;
     tmpbufsize += iw[i] * th[i];
     if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
-      _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
+      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
     ptr = (JSAMPLE *)srcPlanes[i];
     for (row = 0; row < ph[i]; row++) {
       inbuf[i][row] = ptr;
@@ -1002,11 +1011,11 @@
   }
   if (usetmpbuf) {
     if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
-      _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
+      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
     ptr = _tmpbuf;
     for (i = 0; i < cinfo->num_components; i++) {
       if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
-        _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
+        THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
       for (row = 0; row < th[i]; row++) {
         tmpbuf[i][row] = ptr;
         ptr += iw[i];
@@ -1070,12 +1079,12 @@
   int pw0, ph0, strides[3], retval = -1;
   tjinstance *this = (tjinstance *)handle;
 
-  if (!this) _throwg("tjCompressFromYUV(): Invalid handle");
+  if (!this) THROWG("tjCompressFromYUV(): Invalid handle");
   this->isInstanceError = FALSE;
 
   if (srcBuf == NULL || width <= 0 || pad < 1 || height <= 0 || subsamp < 0 ||
       subsamp >= NUMSUBOPT)
-    _throw("tjCompressFromYUV(): Invalid argument");
+    THROW("tjCompressFromYUV(): Invalid argument");
 
   pw0 = tjPlaneWidth(0, width, subsamp);
   ph0 = tjPlaneHeight(0, height, subsamp);
@@ -1154,13 +1163,13 @@
 {
   int retval = 0;
 
-  getdinstance(handle);
+  GET_DINSTANCE(handle);
   if ((this->init & DECOMPRESS) == 0)
-    _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
+    THROW("tjDecompressHeader3(): Instance has not been initialized for decompression");
 
   if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
       jpegSubsamp == NULL || jpegColorspace == NULL)
-    _throw("tjDecompressHeader3(): Invalid argument");
+    THROW("tjDecompressHeader3(): Invalid argument");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -1185,11 +1194,11 @@
   jpeg_abort_decompress(dinfo);
 
   if (*jpegSubsamp < 0)
-    _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
+    THROW("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
   if (*jpegColorspace < 0)
-    _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
+    THROW("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
   if (*width < 1 || *height < 1)
-    _throw("tjDecompressHeader3(): Invalid data returned in header");
+    THROW("tjDecompressHeader3(): Invalid data returned in header");
 
 bailout:
   if (this->jerr.warning) retval = -1;
@@ -1238,14 +1247,14 @@
   JSAMPROW *row_pointer = NULL;
   int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
 
-  getdinstance(handle);
+  GET_DINSTANCE(handle);
   this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
   if ((this->init & DECOMPRESS) == 0)
-    _throw("tjDecompress2(): Instance has not been initialized for decompression");
+    THROW("tjDecompress2(): Instance has not been initialized for decompression");
 
   if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
       pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
-    _throw("tjDecompress2(): Invalid argument");
+    THROW("tjDecompress2(): Invalid argument");
 
 #ifndef NO_PUTENV
   if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
@@ -1274,7 +1283,7 @@
       break;
   }
   if (i >= NUMSF)
-    _throw("tjDecompress2(): Could not scale down to desired image dimensions");
+    THROW("tjDecompress2(): Could not scale down to desired image dimensions");
   width = scaledw;  height = scaledh;
   dinfo->scale_num = sf[i].num;
   dinfo->scale_denom = sf[i].denom;
@@ -1284,16 +1293,16 @@
 
   if ((row_pointer =
        (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
-    _throw("tjDecompress2(): Memory allocation failure");
+    THROW("tjDecompress2(): Memory allocation failure");
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
     retval = -1;  goto bailout;
   }
   for (i = 0; i < (int)dinfo->output_height; i++) {
     if (flags & TJFLAG_BOTTOMUP)
-      row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * pitch];
+      row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * (size_t)pitch];
     else
-      row_pointer[i] = &dstBuf[i * pitch];
+      row_pointer[i] = &dstBuf[i * (size_t)pitch];
   }
   while (dinfo->output_scanline < dinfo->output_height)
     jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
@@ -1386,7 +1395,7 @@
   int (*old_read_markers) (j_decompress_ptr);
   void (*old_reset_marker_reader) (j_decompress_ptr);
 
-  getdinstance(handle);
+  GET_DINSTANCE(handle);
   this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
 
   for (i = 0; i < MAX_COMPONENTS; i++) {
@@ -1394,14 +1403,14 @@
   }
 
   if ((this->init & DECOMPRESS) == 0)
-    _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
+    THROW("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
 
   if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT ||
       dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
       pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
-    _throw("tjDecodeYUVPlanes(): Invalid argument");
+    THROW("tjDecodeYUVPlanes(): Invalid argument");
   if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
-    _throw("tjDecodeYUVPlanes(): Invalid argument");
+    THROW("tjDecodeYUVPlanes(): Invalid argument");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -1409,7 +1418,7 @@
   }
 
   if (pixelFormat == TJPF_CMYK)
-    _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
+    THROW("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
 
   if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
   dinfo->image_width = width;
@@ -1445,12 +1454,12 @@
   if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
 
   if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
-    _throw("tjDecodeYUVPlanes(): Memory allocation failure");
+    THROW("tjDecodeYUVPlanes(): Memory allocation failure");
   for (i = 0; i < height; i++) {
     if (flags & TJFLAG_BOTTOMUP)
-      row_pointer[i] = &dstBuf[(height - i - 1) * pitch];
+      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
     else
-      row_pointer[i] = &dstBuf[i * pitch];
+      row_pointer[i] = &dstBuf[i * (size_t)pitch];
   }
   if (height < ph0)
     for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
@@ -1461,10 +1470,10 @@
       (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
                         compptr->v_samp_factor + 32);
     if (!_tmpbuf[i])
-      _throw("tjDecodeYUVPlanes(): Memory allocation failure");
+      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
     tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
     if (!tmpbuf[i])
-      _throw("tjDecodeYUVPlanes(): Memory allocation failure");
+      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
     for (row = 0; row < compptr->v_samp_factor; row++) {
       unsigned char *_tmpbuf_aligned =
         (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
@@ -1476,7 +1485,7 @@
     ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
     inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
     if (!inbuf[i])
-      _throw("tjDecodeYUVPlanes(): Memory allocation failure");
+      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
     ptr = (JSAMPLE *)srcPlanes[i];
     for (row = 0; row < ph[i]; row++) {
       inbuf[i][row] = ptr;
@@ -1525,12 +1534,12 @@
   int pw0, ph0, strides[3], retval = -1;
   tjinstance *this = (tjinstance *)handle;
 
-  if (!this) _throwg("tjDecodeYUV(): Invalid handle");
+  if (!this) THROWG("tjDecodeYUV(): Invalid handle");
   this->isInstanceError = FALSE;
 
-  if (srcBuf == NULL || pad < 0 || !isPow2(pad) || subsamp < 0 ||
+  if (srcBuf == NULL || pad < 0 || !IS_POW2(pad) || subsamp < 0 ||
       subsamp >= NUMSUBOPT || width <= 0 || height <= 0)
-    _throw("tjDecodeYUV(): Invalid argument");
+    THROW("tjDecodeYUV(): Invalid argument");
 
   pw0 = tjPlaneWidth(0, width, subsamp);
   ph0 = tjPlaneHeight(0, height, subsamp);
@@ -1569,7 +1578,7 @@
   JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
   int dctsize;
 
-  getdinstance(handle);
+  GET_DINSTANCE(handle);
   this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
 
   for (i = 0; i < MAX_COMPONENTS; i++) {
@@ -1577,11 +1586,11 @@
   }
 
   if ((this->init & DECOMPRESS) == 0)
-    _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
+    THROW("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
 
   if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] ||
       width < 0 || height < 0)
-    _throw("tjDecompressToYUVPlanes(): Invalid argument");
+    THROW("tjDecompressToYUVPlanes(): Invalid argument");
 
 #ifndef NO_PUTENV
   if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
@@ -1601,10 +1610,10 @@
   this->headerRead = 0;
   jpegSubsamp = getSubsamp(dinfo);
   if (jpegSubsamp < 0)
-    _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
+    THROW("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
 
   if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
-    _throw("tjDecompressToYUVPlanes(): Invalid argument");
+    THROW("tjDecompressToYUVPlanes(): Invalid argument");
 
   jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
   if (width == 0) width = jpegwidth;
@@ -1616,9 +1625,9 @@
       break;
   }
   if (i >= NUMSF)
-    _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
+    THROW("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
   if (dinfo->num_components > 3)
-    _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
+    THROW("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
 
   width = scaledw;  height = scaledh;
   dinfo->scale_num = sf[i].num;
@@ -1642,7 +1651,7 @@
     th[i] = compptr->v_samp_factor * dctsize;
     tmpbufsize += iw[i] * th[i];
     if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
-      _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
+      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
     ptr = dstPlanes[i];
     for (row = 0; row < ph[i]; row++) {
       outbuf[i][row] = ptr;
@@ -1651,11 +1660,11 @@
   }
   if (usetmpbuf) {
     if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
-      _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
+      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
     ptr = _tmpbuf;
     for (i = 0; i < dinfo->num_components; i++) {
       if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
-        _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
+        THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
       for (row = 0; row < th[i]; row++) {
         tmpbuf[i][row] = ptr;
         ptr += iw[i];
@@ -1736,12 +1745,12 @@
   int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
   int i, jpegwidth, jpegheight, scaledw, scaledh;
 
-  getdinstance(handle);
+  GET_DINSTANCE(handle);
   this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
 
   if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
-      pad < 1 || !isPow2(pad) || height < 0)
-    _throw("tjDecompressToYUV2(): Invalid argument");
+      pad < 1 || !IS_POW2(pad) || height < 0)
+    THROW("tjDecompressToYUV2(): Invalid argument");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -1752,7 +1761,7 @@
   jpeg_read_header(dinfo, TRUE);
   jpegSubsamp = getSubsamp(dinfo);
   if (jpegSubsamp < 0)
-    _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
+    THROW("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
 
   jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
   if (width == 0) width = jpegwidth;
@@ -1765,7 +1774,7 @@
       break;
   }
   if (i >= NUMSF)
-    _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
+    THROW("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
 
   pw0 = tjPlaneWidth(0, width, jpegSubsamp);
   ph0 = tjPlaneHeight(0, height, jpegSubsamp);
@@ -1830,14 +1839,14 @@
   jvirt_barray_ptr *srccoefs, *dstcoefs;
   int retval = 0, i, jpegSubsamp, saveMarkers = 0;
 
-  getinstance(handle);
+  GET_INSTANCE(handle);
   this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
   if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
-    _throw("tjTransform(): Instance has not been initialized for transformation");
+    THROW("tjTransform(): Instance has not been initialized for transformation");
 
   if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
       dstSizes == NULL || t == NULL || flags < 0)
-    _throw("tjTransform(): Invalid argument");
+    THROW("tjTransform(): Invalid argument");
 
 #ifndef NO_PUTENV
   if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
@@ -1847,7 +1856,7 @@
 
   if ((xinfo =
        (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
-    _throw("tjTransform(): Memory allocation failure");
+    THROW("tjTransform(): Memory allocation failure");
   MEMZERO(xinfo, sizeof(jpeg_transform_info) * n);
 
   if (setjmp(this->jerr.setjmp_buffer)) {
@@ -1885,11 +1894,11 @@
   jpeg_read_header(dinfo, TRUE);
   jpegSubsamp = getSubsamp(dinfo);
   if (jpegSubsamp < 0)
-    _throw("tjTransform(): Could not determine subsampling type for JPEG image");
+    THROW("tjTransform(): Could not determine subsampling type for JPEG image");
 
   for (i = 0; i < n; i++) {
     if (!jtransform_request_workspace(dinfo, &xinfo[i]))
-      _throw("tjTransform(): Transform is not perfect");
+      THROW("tjTransform(): Transform is not perfect");
 
     if (xinfo[i].crop) {
       if ((t[i].r.x % xinfo[i].iMCU_sample_width) != 0 ||
@@ -1952,7 +1961,7 @@
           for (y = 0; y < compptr->v_samp_factor; y++) {
             if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
                                   i, &t[i]) == -1)
-              _throw("tjTransform(): Error in custom filter");
+              THROW("tjTransform(): Error in custom filter");
             arrayRegion.y += DCTSIZE;
           }
         }
@@ -1989,21 +1998,21 @@
 
   if (!filename || !width || align < 1 || !height || !pixelFormat ||
       *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
-    _throwg("tjLoadImage(): Invalid argument");
+    THROWG("tjLoadImage(): Invalid argument");
   if ((align & (align - 1)) != 0)
-    _throwg("tjLoadImage(): Alignment must be a power of 2");
+    THROWG("tjLoadImage(): Alignment must be a power of 2");
 
   if ((handle = tjInitCompress()) == NULL) return NULL;
   this = (tjinstance *)handle;
   cinfo = &this->cinfo;
 
   if ((file = fopen(filename, "rb")) == NULL)
-    _throwunix("tjLoadImage(): Cannot open input file");
+    THROW_UNIX("tjLoadImage(): Cannot open input file");
 
   if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
-    _throwunix("tjLoadImage(): Could not read input file")
+    THROW_UNIX("tjLoadImage(): Could not read input file")
   else if (tempc == EOF)
-    _throwg("tjLoadImage(): Input file contains no data");
+    THROWG("tjLoadImage(): Input file contains no data");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -2014,14 +2023,14 @@
   else cinfo->in_color_space = pf2cs[*pixelFormat];
   if (tempc == 'B') {
     if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
-      _throwg("tjLoadImage(): Could not initialize bitmap loader");
+      THROWG("tjLoadImage(): Could not initialize bitmap loader");
     invert = (flags & TJFLAG_BOTTOMUP) == 0;
   } else if (tempc == 'P') {
     if ((src = jinit_read_ppm(cinfo)) == NULL)
-      _throwg("tjLoadImage(): Could not initialize bitmap loader");
+      THROWG("tjLoadImage(): Could not initialize bitmap loader");
     invert = (flags & TJFLAG_BOTTOMUP) != 0;
   } else
-    _throwg("tjLoadImage(): Unsupported file type");
+    THROWG("tjLoadImage(): Unsupported file type");
 
   src->input_file = file;
   (*src->start_input) (cinfo, src);
@@ -2034,7 +2043,7 @@
   if ((unsigned long long)pitch * (unsigned long long)(*height) >
       (unsigned long long)((size_t)-1) ||
       (dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL)
-    _throwg("tjLoadImage(): Memory allocation failure");
+    THROWG("tjLoadImage(): Memory allocation failure");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -2081,7 +2090,7 @@
 
   if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 ||
       pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
-    _throwg("tjSaveImage(): Invalid argument");
+    THROWG("tjSaveImage(): Invalid argument");
 
   if ((handle = tjInitDecompress()) == NULL)
     return -1;
@@ -2089,7 +2098,7 @@
   dinfo = &this->dinfo;
 
   if ((file = fopen(filename, "wb")) == NULL)
-    _throwunix("tjSaveImage(): Cannot open output file");
+    THROW_UNIX("tjSaveImage(): Cannot open output file");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -2104,11 +2113,11 @@
   ptr = strrchr(filename, '.');
   if (ptr && !strcasecmp(ptr, ".bmp")) {
     if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL)
-      _throwg("tjSaveImage(): Could not initialize bitmap writer");
+      THROWG("tjSaveImage(): Could not initialize bitmap writer");
     invert = (flags & TJFLAG_BOTTOMUP) == 0;
   } else {
     if ((dst = jinit_write_ppm(dinfo)) == NULL)
-      _throwg("tjSaveImage(): Could not initialize PPM writer");
+      THROWG("tjSaveImage(): Could not initialize PPM writer");
     invert = (flags & TJFLAG_BOTTOMUP) != 0;
   }