Update libjpeg-turbo to 2.0.0

Bug: 78329453

Update to upstream at https://github.com/libjpeg-turbo/libjpeg-turbo/tree/2.0.0

This includes a fix for a bug that could result in an infinite loop.

ChangeLog.md contains detailed changes about the upstream library. Changes
I made are below:
- Remove files that are no longer in upstream, and include all current
  files from upstream.
- Update various references to the version.

Android.bp:
- Update to build new files/files in new locations.
- Run bpfmt

README.android:
- Remove cherry-pick references, as they are no longer needed.
- Remove modification in jsimdext.inc, which no longer appears to be
  necessary.

README.version:
- Use the github URL, as it is now the official upstream build
- Replace msarett as OWNER, as he no longer works on this project
- Update the version

Change-Id: Ie6cfee5a8f820f28656bbb305f500e75e7ce7915
diff --git a/java/TJExample.java b/java/TJExample.java
index 835a5b9..7859886 100644
--- a/java/TJExample.java
+++ b/java/TJExample.java
@@ -1,6 +1,6 @@
 /*
- * Copyright (C)2011-2012, 2014-2015, 2017 D. R. Commander.
- *                                         All Rights Reserved.
+ * Copyright (C)2011-2012, 2014-2015, 2017-2018 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:
@@ -28,8 +28,8 @@
  */
 
 /*
- * This program demonstrates how to compress and decompress JPEG files using
- * the TurboJPEG JNI wrapper
+ * This program demonstrates how to compress, decompress, and transform JPEG
+ * images using the TurboJPEG Java API
  */
 
 import java.io.*;
@@ -40,138 +40,178 @@
 import javax.swing.*;
 import org.libjpegturbo.turbojpeg.*;
 
-public class TJExample implements TJCustomFilter {
 
-  public static final String classname = new TJExample().getClass().getName();
+@SuppressWarnings("checkstyle:JavadocType")
+class TJExample implements TJCustomFilter {
 
-  private static void usage() throws Exception {
-    System.out.println("\nUSAGE: java " + classname + " <Input file> <Output file> [options]\n");
-    System.out.println("Input and output files can be any image format that the Java Image I/O");
+  static final String CLASS_NAME =
+    new TJExample().getClass().getName();
+
+  static final int DEFAULT_SUBSAMP = TJ.SAMP_444;
+  static final int DEFAULT_QUALITY = 95;
+
+
+  static final String[] SUBSAMP_NAME = {
+    "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0", "4:1:1"
+  };
+
+  static final String[] COLORSPACE_NAME = {
+    "RGB", "YCbCr", "GRAY", "CMYK", "YCCK"
+  };
+
+
+  /* DCT filter example.  This produces a negative of the image. */
+
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
+                           Rectangle planeRegion, int componentIndex,
+                           int transformIndex, TJTransform transform)
+                           throws TJException {
+    for (int i = 0; i < bufferRegion.width * bufferRegion.height; i++) {
+      coeffBuffer.put(i, (short)(-coeffBuffer.get(i)));
+    }
+  }
+
+
+  static void usage() throws Exception {
+    System.out.println("\nUSAGE: java [Java options] " + CLASS_NAME +
+                       " <Input image> <Output image> [options]\n");
+
+    System.out.println("Input and output images can be in any image format that the Java Image I/O");
     System.out.println("extensions understand.  If either filename ends in a .jpg extension, then");
-    System.out.println("TurboJPEG will be used to compress or decompress the file.\n");
-    System.out.println("Options:\n");
-    System.out.println("-scale M/N = if the input image is a JPEG file, scale the width/height of the");
-    System.out.print("             output image by a factor of M/N (M/N = ");
-    for (int i = 0; i < sf.length; i++) {
-      System.out.print(sf[i].getNum() + "/" + sf[i].getDenom());
-      if (sf.length == 2 && i != sf.length - 1)
+    System.out.println("the TurboJPEG API will be used to compress or decompress the image.\n");
+
+    System.out.println("Compression Options (used if the output image is a JPEG image)");
+    System.out.println("--------------------------------------------------------------\n");
+
+    System.out.println("-subsamp <444|422|420|gray> = Apply this level of chrominance subsampling when");
+    System.out.println("     compressing the output image.  The default is to use the same level of");
+    System.out.println("     subsampling as in the input image, if the input image is also a JPEG");
+    System.out.println("     image, or to use grayscale if the input image is a grayscale non-JPEG");
+    System.out.println("     image, or to use " +
+                       SUBSAMP_NAME[DEFAULT_SUBSAMP] +
+                       " subsampling otherwise.\n");
+
+    System.out.println("-q <1-100> = Compress the output image with this JPEG quality level");
+    System.out.println("     (default = " + DEFAULT_QUALITY + ").\n");
+
+    System.out.println("Decompression Options (used if the input image is a JPEG image)");
+    System.out.println("---------------------------------------------------------------\n");
+
+    System.out.println("-scale M/N = Scale the input image by a factor of M/N when decompressing it.");
+    System.out.print("(M/N = ");
+    for (int i = 0; i < SCALING_FACTORS.length; i++) {
+      System.out.print(SCALING_FACTORS[i].getNum() + "/" +
+                       SCALING_FACTORS[i].getDenom());
+      if (SCALING_FACTORS.length == 2 && i != SCALING_FACTORS.length - 1)
         System.out.print(" or ");
-      else if (sf.length > 2) {
-        if (i != sf.length - 1)
+      else if (SCALING_FACTORS.length > 2) {
+        if (i != SCALING_FACTORS.length - 1)
           System.out.print(", ");
-        if (i == sf.length - 2)
+        if (i == SCALING_FACTORS.length - 2)
           System.out.print("or ");
       }
     }
     System.out.println(")\n");
-    System.out.println("-samp <444|422|420|gray> = If the output image is a JPEG file, this specifies");
-    System.out.println("                           the level of chrominance subsampling to use when");
-    System.out.println("                           recompressing it.  Default is to use the same level");
-    System.out.println("                           of subsampling as the input, if the input is a JPEG");
-    System.out.println("                           file, or 4:4:4 otherwise.\n");
-    System.out.println("-q <1-100> = If the output image is a JPEG file, this specifies the JPEG");
-    System.out.println("             quality to use when recompressing it (default = 95).\n");
+
     System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =");
-    System.out.println("     If the input image is a JPEG file, perform the corresponding lossless");
-    System.out.println("     transform prior to decompression (these options are mutually exclusive)\n");
-    System.out.println("-grayscale = If the input image is a JPEG file, perform lossless grayscale");
-    System.out.println("     conversion prior to decompression (can be combined with the other");
-    System.out.println("     transforms above)\n");
-    System.out.println("-crop X,Y,WxH = If the input image is a JPEG file, perform lossless cropping");
-    System.out.println("     prior to decompression.  X,Y specifies the upper left corner of the");
-    System.out.println("     cropping region, and WxH specifies its width and height.  X,Y must be");
-    System.out.println("     evenly divible by the MCU block size (8x8 if the source image was");
-    System.out.println("     compressed using no subsampling or grayscale, or 16x8 for 4:2:2 or 16x16");
-    System.out.println("     for 4:2:0.)\n");
-    System.out.println("-display = Display output image (Output file need not be specified in this");
+    System.out.println("     Perform one of these lossless transform operations on the input image");
+    System.out.println("     prior to decompressing it (these options are mutually exclusive.)\n");
+
+    System.out.println("-grayscale = Perform lossless grayscale conversion on the input image prior");
+    System.out.println("     to decompressing it (can be combined with the other transform operations");
+    System.out.println("     above.)\n");
+
+    System.out.println("-crop WxH+X+Y = Perform lossless cropping on the input image prior to");
+    System.out.println("     decompressing it.  X and Y specify the upper left corner of the cropping");
+    System.out.println("     region, and W and H specify the width and height of the cropping region.");
+    System.out.println("     X and Y must be evenly divible by the MCU block size (8x8 if the input");
+    System.out.println("     image was compressed using no subsampling or grayscale, 16x8 if it was");
+    System.out.println("     compressed using 4:2:2 subsampling, or 16x16 if it was compressed using");
+    System.out.println("     4:2:0 subsampling.)\n");
+
+    System.out.println("General Options");
+    System.out.println("---------------\n");
+
+    System.out.println("-display = Display output image (Output filename need not be specified in this");
     System.out.println("     case.)\n");
+
     System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available in");
-    System.out.println("     the underlying codec\n");
+    System.out.println("     the underlying codec.\n");
+
     System.out.println("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying");
-    System.out.println("     codec\n");
+    System.out.println("     codec.\n");
+
     System.out.println("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the");
-    System.out.println("     underlying codec\n");
+    System.out.println("     underlying codec.\n");
+
     System.exit(1);
   }
 
-  private static final String[] sampName = {
-    "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0", "4:1:1"
-  };
 
   public static void main(String[] argv) {
 
-    BufferedImage img = null;
-    byte[] bmpBuf = null;
-    TJTransform xform = new TJTransform();
-    int flags = 0;
-
     try {
 
-      sf = TJ.getScalingFactors();
-
-      if (argv.length < 2) {
-        usage();
-      }
-
-      TJScalingFactor scaleFactor = new TJScalingFactor(1, 1);
-      String inFormat = "jpg", outFormat = "jpg";
-      int outSubsamp = -1, outQual = 95;
+      TJScalingFactor scalingFactor = new TJScalingFactor(1, 1);
+      int outSubsamp = -1, outQual = -1;
+      TJTransform xform = new TJTransform();
       boolean display = false;
+      int flags = 0;
+      int width, height;
+      String inFormat = "jpg", outFormat = "jpg";
+      BufferedImage img = null;
+      byte[] imgBuf = null;
+
+      if (argv.length < 2)
+        usage();
 
       if (argv[1].substring(0, 2).equalsIgnoreCase("-d"))
         display = true;
 
+      /* Parse arguments. */
       for (int i = 2; i < argv.length; i++) {
         if (argv[i].length() < 2)
           continue;
         else if (argv[i].length() > 2 &&
-            argv[i].substring(0, 3).equalsIgnoreCase("-sc")) {
+                 argv[i].substring(0, 3).equalsIgnoreCase("-sc") &&
+                 i < argv.length - 1) {
           int match = 0;
-          if (i < argv.length - 1) {
-            String[] scaleArg = argv[++i].split("/");
-            if (scaleArg.length == 2) {
-              TJScalingFactor tempsf =
-                new TJScalingFactor(Integer.parseInt(scaleArg[0]),
-                                    Integer.parseInt(scaleArg[1]));
-              for (int j = 0; j < sf.length; j++) {
-                if (tempsf.equals(sf[j])) {
-                  scaleFactor = sf[j];
-                  match = 1;
-                  break;
-                }
+          String[] scaleArg = argv[++i].split("/");
+          if (scaleArg.length == 2) {
+            TJScalingFactor tempsf =
+              new TJScalingFactor(Integer.parseInt(scaleArg[0]),
+                                  Integer.parseInt(scaleArg[1]));
+            for (int j = 0; j < SCALING_FACTORS.length; j++) {
+              if (tempsf.equals(SCALING_FACTORS[j])) {
+                scalingFactor = SCALING_FACTORS[j];
+                match = 1;
+                break;
               }
             }
           }
-          if (match != 1) usage();
-        }
-        else if (argv[i].length() > 2 &&
-            argv[i].substring(0, 3).equalsIgnoreCase("-sa")) {
-          if (i < argv.length - 1) {
-            i++;
-            if (argv[i].substring(0, 1).equalsIgnoreCase("g"))
-              outSubsamp = TJ.SAMP_GRAY;
-            else if (argv[i].equals("444"))
-              outSubsamp = TJ.SAMP_444;
-            else if (argv[i].equals("422"))
-              outSubsamp = TJ.SAMP_422;
-            else if (argv[i].equals("420"))
-              outSubsamp = TJ.SAMP_420;
-            else
-              usage();
-          } else
+          if (match != 1)
             usage();
-        }
-        else if (argv[i].substring(0, 2).equalsIgnoreCase("-q")) {
-          if (i < argv.length - 1) {
-            int qual = Integer.parseInt(argv[++i]);
-            if (qual >= 1 && qual <= 100)
-              outQual = qual;
-            else
-              usage();
-          } else
+        } else if (argv[i].length() > 2 &&
+                   argv[i].substring(0, 3).equalsIgnoreCase("-su") &&
+                   i < argv.length - 1) {
+          i++;
+          if (argv[i].substring(0, 1).equalsIgnoreCase("g"))
+            outSubsamp = TJ.SAMP_GRAY;
+          else if (argv[i].equals("444"))
+            outSubsamp = TJ.SAMP_444;
+          else if (argv[i].equals("422"))
+            outSubsamp = TJ.SAMP_422;
+          else if (argv[i].equals("420"))
+            outSubsamp = TJ.SAMP_420;
+          else
             usage();
-        }
-        else if (argv[i].substring(0, 2).equalsIgnoreCase("-g"))
+        } else if (argv[i].substring(0, 2).equalsIgnoreCase("-q") &&
+                   i < argv.length - 1) {
+          outQual = Integer.parseInt(argv[++i]);
+          if (outQual < 1 || outQual > 100)
+            usage();
+        } else if (argv[i].substring(0, 2).equalsIgnoreCase("-g"))
           xform.options |= TJTransform.OPT_GRAY;
         else if (argv[i].equalsIgnoreCase("-hflip"))
           xform.op = TJTransform.OP_HFLIP;
@@ -190,43 +230,34 @@
         else if (argv[i].equalsIgnoreCase("-custom"))
           xform.cf = new TJExample();
         else if (argv[i].length() > 2 &&
-                 argv[i].substring(0, 2).equalsIgnoreCase("-c")) {
-          if (i >= argv.length - 1)
+                 argv[i].substring(0, 2).equalsIgnoreCase("-c") &&
+                 i < argv.length - 1) {
+          String[] cropArg = argv[++i].split("[x\\+]");
+          if (cropArg.length != 4)
             usage();
-          String[] cropArg = argv[++i].split(",");
-          if (cropArg.length != 3)
+          xform.width = Integer.parseInt(cropArg[0]);
+          xform.height = Integer.parseInt(cropArg[1]);
+          xform.x = Integer.parseInt(cropArg[2]);
+          xform.y = Integer.parseInt(cropArg[3]);
+          if (xform.x < 0 || xform.y < 0 || xform.width < 1 ||
+              xform.height < 1)
             usage();
-          String[] dimArg = cropArg[2].split("[xX]");
-          if (dimArg.length != 2)
-            usage();
-          int tempx = Integer.parseInt(cropArg[0]);
-          int tempy = Integer.parseInt(cropArg[1]);
-          int tempw = Integer.parseInt(dimArg[0]);
-          int temph = Integer.parseInt(dimArg[1]);
-          if (tempx < 0 || tempy < 0 || tempw < 0 || temph < 0)
-            usage();
-          xform.x = tempx;
-          xform.y = tempy;
-          xform.width = tempw;
-          xform.height = temph;
           xform.options |= TJTransform.OPT_CROP;
-        }
-        else if (argv[i].substring(0, 2).equalsIgnoreCase("-d"))
+        } else if (argv[i].substring(0, 2).equalsIgnoreCase("-d"))
           display = true;
         else if (argv[i].equalsIgnoreCase("-fastupsample")) {
           System.out.println("Using fast upsampling code");
           flags |= TJ.FLAG_FASTUPSAMPLE;
-        }
-        else if (argv[i].equalsIgnoreCase("-fastdct")) {
+        } else if (argv[i].equalsIgnoreCase("-fastdct")) {
           System.out.println("Using fastest DCT/IDCT algorithm");
           flags |= TJ.FLAG_FASTDCT;
-        }
-        else if (argv[i].equalsIgnoreCase("-accuratedct")) {
+        } else if (argv[i].equalsIgnoreCase("-accuratedct")) {
           System.out.println("Using most accurate DCT/IDCT algorithm");
           flags |= TJ.FLAG_ACCURATEDCT;
-        }
-        else usage();
+        } else usage();
       }
+
+      /* Determine input and output image formats based on file extensions. */
       String[] inFileTokens = argv[0].split("\\.");
       if (inFileTokens.length > 1)
         inFormat = inFileTokens[inFileTokens.length - 1];
@@ -239,61 +270,75 @@
           outFormat = outFileTokens[outFileTokens.length - 1];
       }
 
-      File file = new File(argv[0]);
-      int width, height;
-
       if (inFormat.equalsIgnoreCase("jpg")) {
-        FileInputStream fis = new FileInputStream(file);
-        int inputSize = fis.available();
-        if (inputSize < 1) {
+        /* Input image is a JPEG image.  Decompress and/or transform it. */
+        boolean doTransform = (xform.op != TJTransform.OP_NONE ||
+                               xform.options != 0 || xform.cf != null);
+
+        /* Read the JPEG file into memory. */
+        File jpegFile = new File(argv[0]);
+        FileInputStream fis = new FileInputStream(jpegFile);
+        int jpegSize = fis.available();
+        if (jpegSize < 1) {
           System.out.println("Input file contains no data");
           System.exit(1);
         }
-        byte[] inputBuf = new byte[inputSize];
-        fis.read(inputBuf);
+        byte[] jpegBuf = new byte[jpegSize];
+        fis.read(jpegBuf);
         fis.close();
 
         TJDecompressor tjd;
-        if (xform.op != TJTransform.OP_NONE || xform.options != 0 ||
-            xform.cf != null) {
-          TJTransformer tjt = new TJTransformer(inputBuf);
-          TJTransform[] t = new TJTransform[1];
-          t[0] = xform;
-          t[0].options |= TJTransform.OPT_TRIM;
-          TJDecompressor[] tjdx = tjt.transform(t, 0);
-          tjd = tjdx[0];
+        if (doTransform) {
+          /* Transform it. */
+          TJTransformer tjt = new TJTransformer(jpegBuf);
+          TJTransform[] xforms = new TJTransform[1];
+          xforms[0] = xform;
+          xforms[0].options |= TJTransform.OPT_TRIM;
+          TJDecompressor[] tjds = tjt.transform(xforms, 0);
+          tjd = tjds[0];
+          tjt.close();
         } else
-          tjd = new TJDecompressor(inputBuf);
+          tjd = new TJDecompressor(jpegBuf);
 
         width = tjd.getWidth();
         height = tjd.getHeight();
         int inSubsamp = tjd.getSubsamp();
-        System.out.println("Source Image: " + width + " x " + height +
-                           " pixels, " + sampName[inSubsamp] + " subsampling");
-        if (outSubsamp < 0)
-          outSubsamp = inSubsamp;
+        int inColorspace = tjd.getColorspace();
 
-        if (outFormat.equalsIgnoreCase("jpg") &&
-            (xform.op != TJTransform.OP_NONE || xform.options != 0) &&
-            scaleFactor.isOne()) {
-          file = new File(argv[1]);
-          FileOutputStream fos = new FileOutputStream(file);
+        System.out.println((doTransform ? "Transformed" : "Input") +
+                           " Image (jpg):  " + width + " x " + height +
+                           " pixels, " + SUBSAMP_NAME[inSubsamp] +
+                           " subsampling, " + COLORSPACE_NAME[inColorspace]);
+
+        if (outFormat.equalsIgnoreCase("jpg") && doTransform &&
+            scalingFactor.isOne() && outSubsamp < 0 && outQual < 0) {
+          /* Input image has been transformed, and no re-compression options
+             have been selected.  Write the transformed image to disk and
+             exit. */
+          File outFile = new File(argv[1]);
+          FileOutputStream fos = new FileOutputStream(outFile);
           fos.write(tjd.getJPEGBuf(), 0, tjd.getJPEGSize());
           fos.close();
           System.exit(0);
         }
 
-        width = scaleFactor.getScaled(width);
-        height = scaleFactor.getScaled(height);
+        /* Scaling and/or a non-JPEG output image format and/or compression
+           options have been selected, so we need to decompress the
+           input/transformed image. */
+        width = scalingFactor.getScaled(width);
+        height = scalingFactor.getScaled(height);
+        if (outSubsamp < 0)
+          outSubsamp = inSubsamp;
 
         if (!outFormat.equalsIgnoreCase("jpg"))
           img = tjd.decompress(width, height, BufferedImage.TYPE_INT_RGB,
                                flags);
         else
-          bmpBuf = tjd.decompress(width, 0, height, TJ.PF_BGRX, flags);
+          imgBuf = tjd.decompress(width, 0, height, TJ.PF_BGRX, flags);
         tjd.close();
       } else {
-        img = ImageIO.read(file);
+        /* Input image is not a JPEG image.  Load it into memory. */
+        img = ImageIO.read(new File(argv[0]));
         if (img == null)
           throw new Exception("Input image type not supported.");
         width = img.getWidth();
@@ -302,61 +347,59 @@
           if (img.getType() == BufferedImage.TYPE_BYTE_GRAY)
             outSubsamp = TJ.SAMP_GRAY;
           else
-            outSubsamp = TJ.SAMP_444;
+            outSubsamp = DEFAULT_SUBSAMP;
         }
+        System.out.println("Input Image:  " + width + " x " + height +
+                           " pixels");
       }
       System.gc();
       if (!display)
-        System.out.print("Dest. Image (" + outFormat + "):  " + width + " x " +
-                         height + " pixels");
+        System.out.print("Output Image (" + outFormat + "):  " + width +
+                         " x " + height + " pixels");
 
       if (display) {
+        /* Display the uncompressed image */
         ImageIcon icon = new ImageIcon(img);
         JLabel label = new JLabel(icon, JLabel.CENTER);
         JOptionPane.showMessageDialog(null, label, "Output Image",
                                       JOptionPane.PLAIN_MESSAGE);
       } else if (outFormat.equalsIgnoreCase("jpg")) {
-        System.out.println(", " + sampName[outSubsamp] +
+        /* Output image format is JPEG.  Compress the uncompressed image. */
+        if (outQual < 0)
+          outQual = DEFAULT_QUALITY;
+        System.out.println(", " + SUBSAMP_NAME[outSubsamp] +
                            " subsampling, quality = " + outQual);
-        TJCompressor tjc = new TJCompressor();
-        int jpegSize;
-        byte[] jpegBuf;
 
+        TJCompressor tjc = new TJCompressor();
         tjc.setSubsamp(outSubsamp);
         tjc.setJPEGQuality(outQual);
         if (img != null)
           tjc.setSourceImage(img, 0, 0, 0, 0);
-        else {
-          tjc.setSourceImage(bmpBuf, 0, 0, width, 0, height, TJ.PF_BGRX);
-        }
-        jpegBuf = tjc.compress(flags);
-        jpegSize = tjc.getCompressedSize();
+        else
+          tjc.setSourceImage(imgBuf, 0, 0, width, 0, height, TJ.PF_BGRX);
+        byte[] jpegBuf = tjc.compress(flags);
+        int jpegSize = tjc.getCompressedSize();
         tjc.close();
 
-        file = new File(argv[1]);
-        FileOutputStream fos = new FileOutputStream(file);
+        /* Write the JPEG image to disk. */
+        File outFile = new File(argv[1]);
+        FileOutputStream fos = new FileOutputStream(outFile);
         fos.write(jpegBuf, 0, jpegSize);
         fos.close();
       } else {
+        /* Output image format is not JPEG.  Save the uncompressed image
+           directly to disk. */
         System.out.print("\n");
-        file = new File(argv[1]);
-        ImageIO.write(img, outFormat, file);
+        File outFile = new File(argv[1]);
+        ImageIO.write(img, outFormat, outFile);
       }
 
-    } catch(Exception e) {
+    } catch (Exception e) {
       e.printStackTrace();
       System.exit(-1);
     }
   }
 
-  public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
-                           Rectangle planeRegion, int componentIndex,
-                           int transformIndex, TJTransform transform)
-                           throws TJException {
-    for (int i = 0; i < bufferRegion.width * bufferRegion.height; i++) {
-      coeffBuffer.put(i, (short)(-coeffBuffer.get(i)));
-    }
-  }
-
-  static TJScalingFactor[] sf = null;
+  static final TJScalingFactor[] SCALING_FACTORS =
+    TJ.getScalingFactors();
 };