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/jpegdecoderhelper.cpp b/libs/ultrahdr/jpegdecoderhelper.cpp
index 7ccf1f3..2e7940c 100644
--- a/libs/ultrahdr/jpegdecoderhelper.cpp
+++ b/libs/ultrahdr/jpegdecoderhelper.cpp
@@ -32,12 +32,17 @@
 const uint32_t kAPP1Marker = JPEG_APP0 + 1; // EXIF, XMP
 const uint32_t kAPP2Marker = JPEG_APP0 + 2; // ICC
 
-const std::string kXmpNameSpace = "http://ns.adobe.com/xap/1.0/";
-const std::string kExifIdCode = "Exif";
 constexpr uint32_t kICCMarkerHeaderSize = 14;
 constexpr uint8_t kICCSig[] = {
         'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0',
 };
+constexpr uint8_t kXmpNameSpace[] = {
+        'h', 't', 't', 'p', ':', '/', '/', 'n', 's', '.', 'a', 'd', 'o', 'b', 'e',
+        '.', 'c', 'o', 'm', '/', 'x', 'a', 'p', '/', '1', '.', '0', '/', '\0',
+};
+constexpr uint8_t kExifIdCode[] = {
+        'E', 'x', 'i', 'f', '\0', '\0',
+};
 
 struct jpegr_source_mgr : jpeg_source_mgr {
     jpegr_source_mgr(const uint8_t* ptr, int len);
@@ -146,6 +151,58 @@
     return mHeight;
 }
 
+// Here we only handle the first EXIF package, and in theary EXIF (or JFIF) must be the first
+// in the image file.
+// We assume that all packages are starting with two bytes marker (eg FF E1 for EXIF package),
+// two bytes of package length which is stored in marker->original_length, and the real data
+// which is stored in marker->data.
+bool JpegDecoderHelper::extractEXIF(const void* image, int length) {
+    jpeg_decompress_struct cinfo;
+    jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
+    jpegrerror_mgr myerr;
+
+    cinfo.err = jpeg_std_error(&myerr.pub);
+    myerr.pub.error_exit = jpegrerror_exit;
+
+    if (setjmp(myerr.setjmp_buffer)) {
+        jpeg_destroy_decompress(&cinfo);
+        return false;
+    }
+    jpeg_create_decompress(&cinfo);
+
+    jpeg_save_markers(&cinfo, kAPP0Marker, 0xFFFF);
+    jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF);
+
+    cinfo.src = &mgr;
+    jpeg_read_header(&cinfo, TRUE);
+
+    size_t pos = 2;  // position after SOI
+    for (jpeg_marker_struct* marker = cinfo.marker_list;
+         marker;
+         marker = marker->next) {
+
+        pos += 4;
+        pos += marker->original_length;
+
+        if (marker->marker != kAPP1Marker) {
+            continue;
+        }
+
+        const unsigned int len = marker->data_length;
+
+        if (len > sizeof(kExifIdCode) &&
+            !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) {
+            mEXIFBuffer.resize(len, 0);
+            memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len);
+            mExifPos = pos - marker->original_length;
+            break;
+        }
+    }
+
+    jpeg_destroy_decompress(&cinfo);
+    return true;
+}
+
 bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) {
     bool status = true;
     jpeg_decompress_struct cinfo;
@@ -178,25 +235,31 @@
     bool exifAppears = false;
     bool xmpAppears = false;
     bool iccAppears = false;
+    size_t pos = 2;  // position after SOI
     for (jpeg_marker_struct* marker = cinfo.marker_list;
-         marker && !(exifAppears && xmpAppears && iccAppears); marker = marker->next) {
+         marker && !(exifAppears && xmpAppears && iccAppears);
+         marker = marker->next) {
+         pos += 4;
+         pos += marker->original_length;
         if (marker->marker != kAPP1Marker && marker->marker != kAPP2Marker) {
             continue;
         }
         const unsigned int len = marker->data_length;
-        if (!xmpAppears && len > kXmpNameSpace.size() &&
-            !strncmp(reinterpret_cast<const char*>(marker->data), kXmpNameSpace.c_str(),
-                     kXmpNameSpace.size())) {
-            mXMPBuffer.resize(len + 1, 0);
+        if (!xmpAppears &&
+            len > sizeof(kXmpNameSpace) &&
+            !memcmp(marker->data, kXmpNameSpace, sizeof(kXmpNameSpace))) {
+            mXMPBuffer.resize(len+1, 0);
             memcpy(static_cast<void*>(mXMPBuffer.data()), marker->data, len);
             xmpAppears = true;
-        } else if (!exifAppears && len > kExifIdCode.size() &&
-                   !strncmp(reinterpret_cast<const char*>(marker->data), kExifIdCode.c_str(),
-                            kExifIdCode.size())) {
+        } else if (!exifAppears &&
+                   len > sizeof(kExifIdCode) &&
+                   !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) {
             mEXIFBuffer.resize(len, 0);
             memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len);
             exifAppears = true;
-        } else if (!iccAppears && len > sizeof(kICCSig) &&
+            mExifPos = pos - marker->original_length;
+        } else if (!iccAppears &&
+                   len > sizeof(kICCSig) &&
                    !memcmp(marker->data, kICCSig, sizeof(kICCSig))) {
             mICCBuffer.resize(len, 0);
             memcpy(static_cast<void*>(mICCBuffer.data()), marker->data, len);
@@ -325,9 +388,8 @@
             }
 
             const unsigned int len = marker->data_length;
-            if (len >= kExifIdCode.size() &&
-                !strncmp(reinterpret_cast<const char*>(marker->data), kExifIdCode.c_str(),
-                         kExifIdCode.size())) {
+            if (len >= sizeof(kExifIdCode) &&
+                !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) {
                 exifData->resize(len, 0);
                 memcpy(static_cast<void*>(exifData->data()), marker->data, len);
                 exifAppears = true;