UltraHDR: reorder MPF and EXIF

For encode API-2, 3 and 4 where input has a JPEG, we always want
the EXIF package appears in front of MPF.

This change also fixed "double null terminator" string problem in
the decoder helper.

Bug: 292561235
Test: jpegr_test.cpp
Change-Id: If6890cc499e179ba01c4e7775796111edb7a5d2f
diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp
index f27bd2d..74760d9 100644
--- a/libs/ultrahdr/jpegr.cpp
+++ b/libs/ultrahdr/jpegr.cpp
@@ -72,6 +72,32 @@
   return cpuCoreCount;
 }
 
+/*
+ * Helper function copies the JPEG image from without EXIF.
+ *
+ * @param pDest destination of the data to be written.
+ * @param pSource source of data being written.
+ * @param exif_pos position of the EXIF package, which is aligned with jpegdecoder.getEXIFPos().
+ *                 (4 bytes offset to FF sign, the byte after FF E1 XX XX <this byte>).
+ * @param exif_size exif size without the initial 4 bytes, aligned with jpegdecoder.getEXIFSize().
+ */
+static void copyJpegWithoutExif(jr_compressed_ptr pDest,
+                                jr_compressed_ptr pSource,
+                                size_t exif_pos,
+                                size_t exif_size) {
+  memcpy(pDest, pSource, sizeof(jpegr_compressed_struct));
+
+  const size_t exif_offset = 4; //exif_pos has 4 bytes offset to the FF sign
+  pDest->length = pSource->length - exif_size - exif_offset;
+  pDest->data = new uint8_t[pDest->length];
+  std::unique_ptr<uint8_t[]> dest_data;
+  dest_data.reset(reinterpret_cast<uint8_t*>(pDest->data));
+  memcpy(pDest->data, pSource->data, exif_pos - exif_offset);
+  memcpy((uint8_t*)pDest->data + exif_pos - exif_offset,
+         (uint8_t*)pSource->data + exif_pos + exif_size,
+         pSource->length - exif_pos - exif_size);
+}
+
 status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr,
                                        jr_uncompressed_ptr yuv420_image_ptr,
                                        ultrahdr_transfer_function hdr_tf,
@@ -1152,7 +1178,8 @@
 // JPEG/R structure:
 // SOI (ff d8)
 //
-// (Optional, only if EXIF package is from outside)
+// (Optional, if EXIF package is from outside (Encode API-0 API-1), or if EXIF package presents
+// in the JPEG input (Encode API-2, API-3, API-4))
 // APP1 (ff e1)
 // 2 bytes of length (2 + length of exif package)
 // EXIF package (this includes the first two bytes representing the package length)
@@ -1166,7 +1193,7 @@
 // 2 bytes of length
 // MPF
 //
-// (Required) primary image (without the first two bytes (SOI), may have other packages)
+// (Required) primary image (without the first two bytes (SOI) and EXIF, may have other packages)
 //
 // SOI (ff d8)
 //
@@ -1183,8 +1210,8 @@
 // Adobe XMP spec part 3 for XMP marker
 // ICC v4.3 spec for ICC
 status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr,
-                              jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr exif, void* icc,
-                              size_t icc_size, ultrahdr_metadata_ptr metadata,
+                              jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr pExif,
+                              void* pIcc, size_t icc_size, ultrahdr_metadata_ptr metadata,
                               jr_compressed_ptr dest) {
   if (primary_jpg_image_ptr == nullptr || gainmap_jpg_image_ptr == nullptr || metadata == nullptr ||
       dest == nullptr) {
@@ -1229,6 +1256,35 @@
   // same as primary
   const int xmp_primary_length = 2 + nameSpaceLength + xmp_primary.size();
 
+  // Check if EXIF package presents in the JPEG input.
+  // If so, extract and remove the EXIF package.
+  JpegDecoderHelper decoder;
+  if (!decoder.extractEXIF(primary_jpg_image_ptr->data, primary_jpg_image_ptr->length)) {
+    return ERROR_JPEGR_DECODE_ERROR;
+  }
+  jpegr_exif_struct exif_from_jpg;
+  exif_from_jpg.data = nullptr;
+  exif_from_jpg.length = 0;
+  jpegr_compressed_struct new_jpg_image;
+  new_jpg_image.data = nullptr;
+  new_jpg_image.length = 0;
+  if (decoder.getEXIFPos() != 0) {
+    if (pExif != nullptr) {
+      ALOGE("received EXIF from outside while the primary image already contains EXIF");
+      return ERROR_JPEGR_INVALID_INPUT_TYPE;
+    }
+    copyJpegWithoutExif(&new_jpg_image,
+                        primary_jpg_image_ptr,
+                        decoder.getEXIFPos(),
+                        decoder.getEXIFSize());
+    exif_from_jpg.data = decoder.getEXIFPtr();
+    exif_from_jpg.length = decoder.getEXIFSize();
+    pExif = &exif_from_jpg;
+  }
+
+  jr_compressed_ptr final_primary_jpg_image_ptr =
+          new_jpg_image.length == 0 ? primary_jpg_image_ptr : &new_jpg_image;
+
   int pos = 0;
   // Begin primary image
   // Write SOI
@@ -1236,15 +1292,15 @@
   JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos));
 
   // Write EXIF
-  if (exif != nullptr) {
-    const int length = 2 + exif->length;
+  if (pExif != nullptr) {
+    const int length = 2 + pExif->length;
     const uint8_t lengthH = ((length >> 8) & 0xff);
     const uint8_t lengthL = (length & 0xff);
     JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
     JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos));
     JPEGR_CHECK(Write(dest, &lengthH, 1, pos));
     JPEGR_CHECK(Write(dest, &lengthL, 1, pos));
-    JPEGR_CHECK(Write(dest, exif->data, exif->length, pos));
+    JPEGR_CHECK(Write(dest, pExif->data, pExif->length, pos));
   }
 
   // Prepare and write XMP
@@ -1261,7 +1317,7 @@
   }
 
   // Write ICC
-  if (icc != nullptr && icc_size > 0) {
+  if (pIcc != nullptr && icc_size > 0) {
     const int length = icc_size + 2;
     const uint8_t lengthH = ((length >> 8) & 0xff);
     const uint8_t lengthL = (length & 0xff);
@@ -1269,7 +1325,7 @@
     JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos));
     JPEGR_CHECK(Write(dest, &lengthH, 1, pos));
     JPEGR_CHECK(Write(dest, &lengthL, 1, pos));
-    JPEGR_CHECK(Write(dest, icc, icc_size, pos));
+    JPEGR_CHECK(Write(dest, pIcc, icc_size, pos));
   }
 
   // Prepare and write MPF
@@ -1277,7 +1333,7 @@
     const int length = 2 + calculateMpfSize();
     const uint8_t lengthH = ((length >> 8) & 0xff);
     const uint8_t lengthL = (length & 0xff);
-    int primary_image_size = pos + length + primary_jpg_image_ptr->length;
+    int primary_image_size = pos + length + final_primary_jpg_image_ptr->length;
     // between APP2 + package size + signature
     // ff e2 00 58 4d 50 46 00
     // 2 + 2 + 4 = 8 (bytes)
@@ -1293,8 +1349,8 @@
   }
 
   // Write primary image
-  JPEGR_CHECK(Write(dest, (uint8_t*)primary_jpg_image_ptr->data + 2,
-                    primary_jpg_image_ptr->length - 2, pos));
+  JPEGR_CHECK(Write(dest, (uint8_t*)final_primary_jpg_image_ptr->data + 2,
+                    final_primary_jpg_image_ptr->length - 2, pos));
   // Finish primary image
 
   // Begin secondary image (gain map)