From 2c725c796edc6f19b24736fc2e37c9e2336fcc8a Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Mon, 9 Nov 2020 03:43:46 +0100
Subject: [PATCH] RagePhoto: added save for GTA

---
 RagePhoto.cpp | 174 +++++++++++++++++++++++++++++++++++++++++---------
 RagePhoto.h   |   5 ++
 2 files changed, 149 insertions(+), 30 deletions(-)

diff --git a/RagePhoto.cpp b/RagePhoto.cpp
index 8b44dfb..fa5875b 100644
--- a/RagePhoto.cpp
+++ b/RagePhoto.cpp
@@ -155,13 +155,13 @@ bool RagePhoto::load()
         size = dataBuffer.read(jsonSize, 4);
         if (size != 4)
             return false;
-        quint32 i_jsonSize = charToUInt32LE(jsonSize);
+        p_jsonSize = charToUInt32LE(jsonSize);
 
-        char jsonBytes[i_jsonSize];
-        size = dataBuffer.read(jsonBytes, i_jsonSize);
-        if (size != i_jsonSize)
+        char jsonBytes[p_jsonSize];
+        size = dataBuffer.read(jsonBytes, p_jsonSize);
+        if (size != p_jsonSize)
             return false;
-        for (quint32 i = 0; i != i_jsonSize; i++) {
+        for (quint32 i = 0; i != p_jsonSize; i++) {
             if (jsonBytes[i] == '\x00')
                 break;
             p_jsonData += jsonBytes[i];
@@ -183,13 +183,13 @@ bool RagePhoto::load()
         size = dataBuffer.read(titlSize, 4);
         if (size != 4)
             return false;
-        quint32 i_titlSize = charToUInt32LE(titlSize);
+        p_titlSize = charToUInt32LE(titlSize);
 
-        char titlBytes[i_titlSize];
-        size = dataBuffer.read(titlBytes, i_titlSize);
-        if (size != i_titlSize)
+        char titlBytes[p_titlSize];
+        size = dataBuffer.read(titlBytes, p_titlSize);
+        if (size != p_titlSize)
             return false;
-        for (const QChar &titlChar : QString::fromUtf8(titlBytes, i_titlSize)) {
+        for (const QChar &titlChar : QString::fromUtf8(titlBytes, p_titlSize)) {
             if (titlChar.isNull())
                 break;
             p_titleString += titlChar;
@@ -207,13 +207,13 @@ bool RagePhoto::load()
         size = dataBuffer.read(descSize, 4);
         if (size != 4)
             return false;
-        quint32 i_descSize = charToUInt32LE(descSize);
+        p_descSize = charToUInt32LE(descSize);
 
-        char descBytes[i_descSize];
-        size = dataBuffer.read(descBytes, i_descSize);
-        if (size != i_descSize)
+        char descBytes[p_descSize];
+        size = dataBuffer.read(descBytes, p_descSize);
+        if (size != p_descSize)
             return false;
-        for (const QChar &descChar : QString::fromUtf8(descBytes, i_descSize)) {
+        for (const QChar &descChar : QString::fromUtf8(descBytes, p_descSize)) {
             if (descChar.isNull())
                 break;
             p_descriptionString += descChar;
@@ -290,13 +290,13 @@ bool RagePhoto::load()
             size = dataBuffer.peek(jsonSize, 4);
             if (size != 4)
                 return false;
-            quint32 i_jsonSize = charToUInt32BE(jsonSize) + 4;
+            p_jsonSize = charToUInt32BE(jsonSize) + 4;
 
-            char compressedJson[i_jsonSize];
-            size = dataBuffer.read(compressedJson, i_jsonSize);
-            if (size != i_jsonSize)
+            char compressedJson[p_jsonSize];
+            size = dataBuffer.read(compressedJson, p_jsonSize);
+            if (size != p_jsonSize)
                 return false;
-            QByteArray t_jsonBytes = QByteArray::fromRawData(compressedJson, i_jsonSize);
+            QByteArray t_jsonBytes = QByteArray::fromRawData(compressedJson, p_jsonSize);
             p_jsonData = qUncompress(t_jsonBytes);
             QJsonDocument t_jsonDocument = QJsonDocument::fromJson(p_jsonData);
             if (t_jsonDocument.isNull())
@@ -313,13 +313,13 @@ bool RagePhoto::load()
             size = dataBuffer.peek(titlSize, 4);
             if (size != 4)
                 return false;
-            quint32 i_titlSize = charToUInt32BE(titlSize) + 4;
+            p_titlSize = charToUInt32BE(titlSize) + 4;
 
-            char compressedTitl[i_titlSize];
-            size = dataBuffer.read(compressedTitl, i_titlSize);
-            if (size != i_titlSize)
+            char compressedTitl[p_titlSize];
+            size = dataBuffer.read(compressedTitl, p_titlSize);
+            if (size != p_titlSize)
                 return false;
-            QByteArray t_titlBytes = QByteArray::fromRawData(compressedTitl, i_titlSize);
+            QByteArray t_titlBytes = QByteArray::fromRawData(compressedTitl, p_titlSize);
             t_titlBytes = qUncompress(t_titlBytes);
             p_titleString = QString::fromUtf8(t_titlBytes);
 
@@ -333,13 +333,13 @@ bool RagePhoto::load()
             size = dataBuffer.peek(descSize, 4);
             if (size != 4)
                 return false;
-            quint32 i_descSize = charToUInt32BE(descSize) + 4;
+            p_descSize = charToUInt32BE(descSize) + 4;
 
-            char compressedDesc[i_descSize];
-            size = dataBuffer.read(compressedDesc, i_descSize);
-            if (size != i_descSize)
+            char compressedDesc[p_descSize];
+            size = dataBuffer.read(compressedDesc, p_descSize);
+            if (size != p_descSize)
                 return false;
-            QByteArray t_descBytes = QByteArray::fromRawData(compressedDesc, i_descSize);
+            QByteArray t_descBytes = QByteArray::fromRawData(compressedDesc, p_descSize);
             t_descBytes = qUncompress(t_descBytes);
             p_descriptionString = QString::fromUtf8(t_descBytes);
 
@@ -508,6 +508,120 @@ RagePhoto::PhotoFormat RagePhoto::photoFormat()
     return p_photoFormat;
 }
 
+QByteArray RagePhoto::save(PhotoFormat photoFormat)
+{
+    QByteArray data;
+    QBuffer dataBuffer(&data);
+    dataBuffer.open(QIODevice::WriteOnly);
+    save(&dataBuffer, photoFormat);
+    return data;
+}
+
+void RagePhoto::save(QIODevice *ioDevice, PhotoFormat photoFormat)
+{
+    if (photoFormat == PhotoFormat::GTA5) {
+        char formatHeader[4];
+        quint32 format = (quint32)PhotoFormat::GTA5;
+        uInt32ToCharLE(&format, formatHeader);
+        ioDevice->write(formatHeader, 4);
+
+        QByteArray photoHeader = QTextCodec::codecForName("UTF-16LE")->fromUnicode(p_photoString);
+        if (photoHeader.left(2) == "\xFF\xFE") {
+            photoHeader.remove(0, 2);
+        }
+        qint64 photoHeaderSize = photoHeader.size();
+        if (photoHeaderSize > 256) {
+            photoHeader = photoHeader.left(256);
+            photoHeaderSize = 256;
+        }
+        ioDevice->write(photoHeader);
+        for (qint64 size = photoHeaderSize; size < 256; size++) {
+            ioDevice->write("\x00", 1);
+        }
+
+        char checksum[4];
+        uInt32ToCharLE(&p_headerSum, checksum);
+        ioDevice->write(checksum, 4);
+
+        char endOfFile[4];
+        uInt32ToCharLE(&p_endOfFile, endOfFile);
+        ioDevice->write(endOfFile, 4);
+
+        char jsonOffset[4];
+        uInt32ToCharLE(&p_jsonOffset, jsonOffset);
+        ioDevice->write(jsonOffset, 4);
+
+        char titlOffset[4];
+        uInt32ToCharLE(&p_titlOffset, titlOffset);
+        ioDevice->write(titlOffset, 4);
+
+        char descOffset[4];
+        uInt32ToCharLE(&p_descOffset, descOffset);
+        ioDevice->write(descOffset, 4);
+
+        ioDevice->write("JPEG");
+
+        char jpegBuffer[4];
+        uInt32ToCharLE(&p_jpegBuffer, jpegBuffer);
+        ioDevice->write(jpegBuffer, 4);
+
+        quint32 t_photoSize = p_photoData.size();
+        char photoSize[4];
+        uInt32ToCharLE(&t_photoSize, photoSize);
+        ioDevice->write(photoSize, 4);
+
+        ioDevice->write(p_photoData);
+        for (qint64 size = t_photoSize; size < p_jpegBuffer; size++) {
+            ioDevice->write("\x00", 1);
+        }
+
+        ioDevice->seek(p_jsonOffset + 264);
+        ioDevice->write("JSON");
+
+        char jsonSize[4];
+        uInt32ToCharLE(&p_jsonSize, jsonSize);
+        ioDevice->write(jsonSize, 4);
+
+        qint64 dataSize = p_jsonData.size();
+        ioDevice->write(p_jsonData);
+        for (qint64 size = dataSize; size < p_jsonSize; size++) {
+            ioDevice->write("\x00", 1);
+        }
+
+        ioDevice->seek(p_titlOffset + 264);
+        ioDevice->write("TITL");
+
+        char titlSize[4];
+        uInt32ToCharLE(&p_titlSize, titlSize);
+        ioDevice->write(titlSize, 4);
+
+        QByteArray data = p_titleString.toUtf8();
+        dataSize = data.size();
+        ioDevice->write(data);
+        for (qint64 size = dataSize; size < p_titlSize; size++) {
+            ioDevice->write("\x00", 1);
+        }
+
+        ioDevice->seek(p_descOffset + 264);
+        ioDevice->write("DESC");
+
+        char descSize[4];
+        uInt32ToCharLE(&p_descSize, descSize);
+        ioDevice->write(descSize, 4);
+
+        data = p_descriptionString.toUtf8();
+        dataSize = data.size();
+        ioDevice->write(data);
+        for (qint64 size = dataSize; size < p_descSize; size++) {
+            ioDevice->write("\x00", 1);
+        }
+
+        ioDevice->seek(p_endOfFile + 260);
+        ioDevice->write("JEND");
+        ioDevice->aboutToClose();
+    }
+}
+
 RagePhoto* RagePhoto::loadFile(const QString &filePath)
 {
     RagePhoto *ragePhoto = new RagePhoto(filePath);
diff --git a/RagePhoto.h b/RagePhoto.h
index cffd486..2d49c24 100644
--- a/RagePhoto.h
+++ b/RagePhoto.h
@@ -65,6 +65,8 @@ public:
     quint32 photoBuffer();
     quint32 photoSize();
     PhotoFormat photoFormat();
+    QByteArray save(PhotoFormat photoFormat);
+    void save(QIODevice *ioDevice, PhotoFormat photoFormat);
     static RagePhoto* loadFile(const QString &filePath);
 
 private:
@@ -83,11 +85,14 @@ private:
     QString p_photoString;
     QString p_titleString;
     quint32 p_descOffset;
+    quint32 p_descSize;
     quint32 p_endOfFile;
     quint32 p_headerSum;
     quint32 p_jpegBuffer;
     quint32 p_jsonOffset;
+    quint32 p_jsonSize;
     quint32 p_titlOffset;
+    quint32 p_titlSize;
     bool p_isLoaded;
     int p_inputMode;
 };