JPEGR Decoder. Inital implementation

* Implements JPEGR Decoding
* Doesn't implement XMP data parsing
* Implements retrieval of image data

Bug: b/252835416
Test: build

Change-Id: I62c7c323842b8d87866c43e85c1d7238e5b9b0d5
diff --git a/libs/jpegrecoverymap/jpegdecoder.cpp b/libs/jpegrecoverymap/jpegdecoder.cpp
index c1fb6c3..0185e55 100644
--- a/libs/jpegrecoverymap/jpegdecoder.cpp
+++ b/libs/jpegrecoverymap/jpegdecoder.cpp
@@ -20,8 +20,15 @@
 
 #include <errno.h>
 #include <setjmp.h>
+#include <string>
+
+using namespace std;
 
 namespace android::recoverymap {
+
+const uint32_t kExifMarker = JPEG_APP0 + 1;
+const uint32_t kICCMarker = JPEG_APP0 + 2;
+
 struct jpegr_source_mgr : jpeg_source_mgr {
     jpegr_source_mgr(const uint8_t* ptr, int len);
     ~jpegr_source_mgr();
@@ -88,6 +95,7 @@
     }
 
     mResultBuffer.clear();
+    mXMPBuffer.clear();
     if (!decode(image, length)) {
         return false;
     }
@@ -103,6 +111,15 @@
     return mResultBuffer.size();
 }
 
+void* JpegDecoder::getXMPPtr() {
+    return mXMPBuffer.data();
+}
+
+size_t JpegDecoder::getXMPSize() {
+    return mXMPBuffer.size();
+}
+
+
 size_t JpegDecoder::getDecompressedImageWidth() {
     return mWidth;
 }
@@ -115,6 +132,8 @@
     jpeg_decompress_struct cinfo;
     jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
     jpegrerror_mgr myerr;
+    string nameSpace = "http://ns.adobe.com/xap/1.0/";
+
     cinfo.err = jpeg_std_error(&myerr.pub);
     myerr.pub.error_exit = jpegrerror_exit;
 
@@ -124,9 +143,26 @@
     }
     jpeg_create_decompress(&cinfo);
 
+    jpeg_save_markers(&cinfo, kExifMarker, 0xFFFF);
+
     cinfo.src = &mgr;
     jpeg_read_header(&cinfo, TRUE);
 
+    // Save XMP Data
+    for (jpeg_marker_struct* marker = cinfo.marker_list; marker; marker = marker->next) {
+        if (marker->marker == kExifMarker) {
+            const unsigned int len = marker->data_length;
+            if (len > nameSpace.size() &&
+                !strncmp(reinterpret_cast<const char*>(marker->data),
+                         nameSpace.c_str(), nameSpace.size())) {
+                mXMPBuffer.resize(len+1, 0);
+                memcpy(static_cast<void*>(mXMPBuffer.data()), marker->data, len);
+                break;
+            }
+        }
+    }
+
+
     mWidth = cinfo.image_width;
     mHeight = cinfo.image_height;
 
@@ -161,6 +197,43 @@
     return decompressYUV(cinfo, dest);
 }
 
+bool JpegDecoder::getCompressedImageParameters(const void* image, int length,
+                              size_t *pWidth, size_t *pHeight,
+                              std::vector<uint8_t> *&iccData , std::vector<uint8_t> *&exifData) {
+    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, kExifMarker, 0xFFFF);
+    jpeg_save_markers(&cinfo, kICCMarker, 0xFFFF);
+
+    cinfo.src = &mgr;
+    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
+        jpeg_destroy_decompress(&cinfo);
+        return false;
+    }
+
+    *pWidth = cinfo.image_width;
+    *pHeight = cinfo.image_height;
+
+    //TODO: Parse iccProfile and exifData
+    (void)iccData;
+    (void)exifData;
+
+
+    jpeg_destroy_decompress(&cinfo);
+    return true;
+}
+
+
 bool JpegDecoder::decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest) {
 
     JSAMPROW y[kCompressBatchSize];