2017-10-09 08:35:48 +02:00
|
|
|
/*****************************************************************************
|
2023-01-27 20:09:43 +01:00
|
|
|
* gta5view Grand Theft Auto V Profile Viewer
|
|
|
|
* Copyright (C) 2016-2023 Syping
|
2017-10-09 08:35:48 +02:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "SnapmaticPicture.h"
|
|
|
|
#include <QStringBuilder>
|
|
|
|
#include <QJsonDocument>
|
|
|
|
#include <QJsonObject>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QVariantMap>
|
|
|
|
#include <QJsonArray>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QString>
|
|
|
|
#include <QBuffer>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QImage>
|
|
|
|
#include <QSize>
|
|
|
|
#include <QFile>
|
|
|
|
|
2020-09-28 05:33:04 +02:00
|
|
|
#if QT_VERSION < 0x060000
|
|
|
|
#include <QTextCodec>
|
2022-08-21 21:39:19 +02:00
|
|
|
#else
|
|
|
|
#include <QStringDecoder>
|
2020-09-28 05:33:04 +02:00
|
|
|
#endif
|
2017-10-12 22:21:45 +02:00
|
|
|
#include <QSaveFile>
|
|
|
|
|
2017-10-09 08:35:48 +02:00
|
|
|
// IMAGES VALUES
|
|
|
|
#define snapmaticResolutionW 960
|
|
|
|
#define snapmaticResolutionH 536
|
|
|
|
#define snapmaticResolution QSize(snapmaticResolutionW, snapmaticResolutionH)
|
|
|
|
|
2023-01-27 20:09:43 +01:00
|
|
|
// GTA5VIEW RELATED INTERNAL FUNCTIONS
|
|
|
|
inline quint32 gta5view_charToUInt32LE(char *x)
|
|
|
|
{
|
|
|
|
return (static_cast<unsigned char>(x[3]) << 24 |
|
|
|
|
static_cast<unsigned char>(x[2]) << 16 |
|
|
|
|
static_cast<unsigned char>(x[1]) << 8 |
|
|
|
|
static_cast<unsigned char>(x[0]));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void gta5view_uInt32ToCharLE(quint32 x, char *y)
|
|
|
|
{
|
|
|
|
y[0] = x;
|
|
|
|
y[1] = x >> 8;
|
|
|
|
y[2] = x >> 16;
|
|
|
|
y[3] = x >> 24;
|
|
|
|
}
|
|
|
|
|
2023-02-20 14:04:17 +01:00
|
|
|
ragephoto_bool_t gta5view_export_load(RagePhotoData *rp_data, const char *data, size_t length)
|
2023-01-27 20:09:43 +01:00
|
|
|
{
|
2023-02-20 14:04:17 +01:00
|
|
|
const QByteArray fileData = QByteArray::fromRawData(data, length);
|
|
|
|
|
2023-01-27 20:09:43 +01:00
|
|
|
QBuffer dataBuffer;
|
|
|
|
dataBuffer.setData(fileData);
|
|
|
|
if (!dataBuffer.open(QIODevice::ReadOnly))
|
|
|
|
return false;
|
|
|
|
dataBuffer.seek(4);
|
|
|
|
|
|
|
|
char uInt32Buffer[4];
|
2023-02-20 14:04:17 +01:00
|
|
|
size_t size = dataBuffer.read(uInt32Buffer, 4);
|
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::NoFormatIdentifier;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
|
2023-02-20 14:04:17 +01:00
|
|
|
uint32_t format = gta5view_charToUInt32LE(uInt32Buffer);
|
2023-01-27 20:09:43 +01:00
|
|
|
if (format == G5EExportFormat::G5E3P) {
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteHeader;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
quint32 compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
|
|
|
|
|
|
|
|
char *compressedPhotoHeader = static_cast<char*>(std::malloc(compressedSize));
|
2023-02-20 14:04:17 +01:00
|
|
|
if (!compressedPhotoHeader) {
|
|
|
|
rp_data->error = RagePhoto::HeaderMallocError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
size = dataBuffer.read(compressedPhotoHeader, compressedSize);
|
|
|
|
if (size != compressedSize) {
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedPhotoHeader);
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->error = RagePhoto::UnicodeHeaderError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QByteArray t_photoHeader = QByteArray::fromRawData(compressedPhotoHeader, compressedSize);
|
|
|
|
t_photoHeader = qUncompress(t_photoHeader);
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedPhotoHeader);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (t_photoHeader.isEmpty()) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteHeader;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteHeader;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
|
|
|
rp_data->headerSum = gta5view_charToUInt32LE(uInt32Buffer);
|
|
|
|
rp_data->header = static_cast<char*>(std::malloc(t_photoHeader.size() + 1));
|
|
|
|
if (!rp_data->header) {
|
|
|
|
rp_data->error = RagePhoto::HeaderMallocError;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::memcpy(rp_data->header, t_photoHeader.constData(), t_photoHeader.size() + 1);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompletePhotoBuffer;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
|
|
|
rp_data->jpegBuffer = gta5view_charToUInt32LE(uInt32Buffer);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompletePhotoBuffer;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
|
|
|
|
|
|
|
|
char *compressedPhoto = static_cast<char*>(std::malloc(compressedSize));
|
2023-02-20 14:04:17 +01:00
|
|
|
if (!compressedPhoto) {
|
|
|
|
rp_data->error = RagePhoto::PhotoMallocError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
size = dataBuffer.read(compressedPhoto, compressedSize);
|
|
|
|
if (size != compressedSize) {
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedPhoto);
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->error = RagePhoto::PhotoReadError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QByteArray t_photoData = QByteArray::fromRawData(compressedPhoto, compressedSize);
|
|
|
|
t_photoData = qUncompress(t_photoData);
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedPhoto);
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->jpeg = static_cast<char*>(std::malloc(t_photoData.size()));
|
|
|
|
if (!rp_data->jpeg) {
|
|
|
|
rp_data->error = RagePhoto::PhotoMallocError;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::memcpy(rp_data->jpeg, t_photoData.constData(), t_photoData.size());
|
|
|
|
rp_data->jpegSize = t_photoData.size();
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
// JSON offset will be calculated later, offsets will be removed in G5E4P
|
|
|
|
size = dataBuffer.skip(4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteJsonOffset;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteJsonBuffer;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
|
|
|
rp_data->jsonBuffer = gta5view_charToUInt32LE(uInt32Buffer);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteJsonBuffer;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
|
|
|
|
|
|
|
|
char *compressedJson = static_cast<char*>(std::malloc(compressedSize));
|
2023-02-20 14:04:17 +01:00
|
|
|
if (!compressedJson) {
|
|
|
|
rp_data->error = RagePhoto::JsonMallocError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
size = dataBuffer.read(compressedJson, compressedSize);
|
|
|
|
if (size != compressedSize) {
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedJson);
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->error = RagePhoto::JsonReadError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QByteArray t_jsonData = QByteArray::fromRawData(compressedJson, compressedSize);
|
|
|
|
t_jsonData = qUncompress(t_jsonData);
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedJson);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (t_jsonData.isEmpty()) {
|
|
|
|
rp_data->error = RagePhoto::JsonReadError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
|
|
|
rp_data->json = static_cast<char*>(std::malloc(t_jsonData.size() + 1));
|
|
|
|
if (!rp_data->json) {
|
|
|
|
rp_data->error = RagePhoto::JsonMallocError;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::memcpy(rp_data->json, t_jsonData.constData(), t_jsonData.size() + 1);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
// TITL offset will be calculated later, offsets will be removed in G5E4P
|
|
|
|
size = dataBuffer.skip(4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteTitleOffset;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteTitleBuffer;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
|
|
|
rp_data->titlBuffer = gta5view_charToUInt32LE(uInt32Buffer);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteTitleBuffer;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
|
|
|
|
|
|
|
|
char *compressedTitl = static_cast<char*>(std::malloc(compressedSize));
|
2023-02-20 14:04:17 +01:00
|
|
|
if (!compressedTitl) {
|
|
|
|
rp_data->error = RagePhoto::TitleMallocError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
size = dataBuffer.read(compressedTitl, compressedSize);
|
|
|
|
if (size != compressedSize) {
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedTitl);
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->error = RagePhoto::TitleReadError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QByteArray t_titlData = QByteArray::fromRawData(compressedTitl, compressedSize);
|
|
|
|
t_titlData = qUncompress(t_titlData);
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedTitl);
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->title = static_cast<char*>(std::malloc(t_titlData.size() + 1));
|
|
|
|
if (!rp_data->title) {
|
|
|
|
rp_data->error = RagePhoto::TitleMallocError;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::memcpy(rp_data->title, t_titlData.constData(), t_titlData.size() + 1);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
// DESC offset will be calculated later, offsets will be removed in G5E4P
|
|
|
|
size = dataBuffer.skip(4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteDescOffset;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteDescBuffer;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
|
|
|
rp_data->descBuffer = gta5view_charToUInt32LE(uInt32Buffer);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
size = dataBuffer.read(uInt32Buffer, 4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteDescBuffer;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
|
|
|
|
|
|
|
|
char *compressedDesc = static_cast<char*>(std::malloc(compressedSize));
|
2023-02-20 14:04:17 +01:00
|
|
|
if (!compressedDesc) {
|
|
|
|
rp_data->error = RagePhoto::DescMallocError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
size = dataBuffer.read(compressedDesc, compressedSize);
|
|
|
|
if (size != compressedSize) {
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedDesc);
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->error = RagePhoto::DescReadError;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QByteArray t_descData = QByteArray::fromRawData(compressedDesc, compressedSize);
|
2023-02-20 14:04:17 +01:00
|
|
|
t_descData = qUncompress(t_descData);
|
2023-01-27 21:39:12 +01:00
|
|
|
std::free(compressedDesc);
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->description = static_cast<char*>(std::malloc(t_descData.size() + 1));
|
|
|
|
if (!rp_data->description) {
|
|
|
|
rp_data->error = RagePhoto::DescMallocError;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::memcpy(rp_data->description, t_descData.constData(), t_descData.size() + 1);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
// EOF will be calculated later, EOF marker will be removed in G5E4P
|
|
|
|
size = dataBuffer.skip(4);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 4) {
|
|
|
|
rp_data->error = RagePhoto::IncompleteEOF;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
// libragephoto needs to know we gave it a GTA V Snapmatic
|
2023-02-20 14:04:17 +01:00
|
|
|
rp_data->photoFormat = RagePhoto::GTA5;
|
|
|
|
rp_data->error = RagePhoto::NoError;
|
|
|
|
RagePhoto::setBufferOffsets(rp_data);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (format == G5EExportFormat::G5E2P) {
|
|
|
|
const QByteArray t_fileData = qUncompress(dataBuffer.readAll());
|
2023-02-20 14:04:17 +01:00
|
|
|
if (t_fileData.isEmpty()) {
|
|
|
|
rp_data->error = RagePhoto::IncompatibleFormat;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
|
|
|
return RagePhoto::load(rp_data, nullptr, t_fileData.constData(), t_fileData.size());
|
2023-01-27 20:09:43 +01:00
|
|
|
}
|
|
|
|
else if (format == G5EExportFormat::G5E1P) {
|
|
|
|
size = dataBuffer.skip(1);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 1) {
|
|
|
|
rp_data->error = RagePhoto::IncompatibleFormat;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
char length[1];
|
|
|
|
size = dataBuffer.read(length, 1);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != 1) {
|
|
|
|
rp_data->error = RagePhoto::IncompatibleFormat;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
int i_length = QByteArray::number(static_cast<int>(length[0]), 16).toInt() + 6;
|
|
|
|
|
|
|
|
size = dataBuffer.skip(i_length);
|
2023-02-20 14:04:17 +01:00
|
|
|
if (size != i_length) {
|
|
|
|
rp_data->error = RagePhoto::IncompatibleFormat;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
const QByteArray t_fileData = qUncompress(dataBuffer.readAll());
|
2023-02-20 14:04:17 +01:00
|
|
|
if (t_fileData.isEmpty()) {
|
|
|
|
rp_data->error = RagePhoto::IncompatibleFormat;
|
2023-01-27 20:09:43 +01:00
|
|
|
return false;
|
2023-02-20 14:04:17 +01:00
|
|
|
}
|
|
|
|
return RagePhoto::load(rp_data, nullptr, t_fileData.constData(), t_fileData.size());
|
2023-01-27 20:09:43 +01:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void gta5view_export_save(QIODevice *ioDevice, RagePhotoData *data)
|
|
|
|
{
|
|
|
|
char uInt32Buffer[4];
|
|
|
|
quint32 format = G5EPhotoFormat::G5EX;
|
|
|
|
gta5view_uInt32ToCharLE(format, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
format = G5EExportFormat::G5E3P;
|
|
|
|
gta5view_uInt32ToCharLE(format, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
|
|
|
QByteArray compressedData = qCompress(QByteArray::fromRawData(data->header, strlen(data->header)), 9);
|
|
|
|
quint32 compressedSize = compressedData.size();
|
|
|
|
gta5view_uInt32ToCharLE(compressedSize, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
ioDevice->write(compressedData);
|
|
|
|
|
|
|
|
gta5view_uInt32ToCharLE(data->headerSum, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
2023-02-08 20:05:15 +01:00
|
|
|
gta5view_uInt32ToCharLE(data->jpegBuffer, uInt32Buffer);
|
2023-01-27 20:09:43 +01:00
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
|
|
|
compressedData = qCompress(QByteArray::fromRawData(data->jpeg, data->jpegSize), 9);
|
|
|
|
compressedSize = compressedData.size();
|
|
|
|
gta5view_uInt32ToCharLE(compressedSize, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
ioDevice->write(compressedData);
|
|
|
|
|
|
|
|
gta5view_uInt32ToCharLE(data->jsonOffset, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
|
|
|
gta5view_uInt32ToCharLE(data->jsonBuffer, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
|
|
|
compressedData = qCompress(QByteArray::fromRawData(data->json, strlen(data->json)), 9);
|
|
|
|
compressedSize = compressedData.size();
|
|
|
|
gta5view_uInt32ToCharLE(compressedSize, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
ioDevice->write(compressedData);
|
|
|
|
|
|
|
|
gta5view_uInt32ToCharLE(data->titlOffset, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
|
|
|
gta5view_uInt32ToCharLE(data->titlBuffer, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
|
|
|
compressedData = qCompress(QByteArray::fromRawData(data->title, strlen(data->title)), 9);
|
|
|
|
compressedSize = compressedData.size();
|
|
|
|
gta5view_uInt32ToCharLE(compressedSize, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
ioDevice->write(compressedData);
|
|
|
|
|
|
|
|
gta5view_uInt32ToCharLE(data->descOffset, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
|
|
|
gta5view_uInt32ToCharLE(data->descBuffer, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
|
|
|
|
compressedData = qCompress(QByteArray::fromRawData(data->description, strlen(data->description)), 9);
|
|
|
|
compressedSize = compressedData.size();
|
|
|
|
gta5view_uInt32ToCharLE(compressedSize, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
ioDevice->write(compressedData);
|
|
|
|
|
|
|
|
gta5view_uInt32ToCharLE(data->endOfFile, uInt32Buffer);
|
|
|
|
ioDevice->write(uInt32Buffer, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// SNAPMATIC PICTURE CLASS
|
2017-10-09 08:35:48 +02:00
|
|
|
SnapmaticPicture::SnapmaticPicture(const QString &fileName, QObject *parent) : QObject(parent), picFilePath(fileName)
|
|
|
|
{
|
2023-02-20 14:04:17 +01:00
|
|
|
RagePhotoFormatParser g5eParser[1]{};
|
|
|
|
g5eParser[0].photoFormat = G5EPhotoFormat::G5EX;
|
|
|
|
g5eParser[0].funcLoad = >a5view_export_load;
|
|
|
|
p_ragePhoto.addParser(&g5eParser[0]);
|
|
|
|
|
2017-10-09 08:35:48 +02:00
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
SnapmaticPicture::~SnapmaticPicture()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void SnapmaticPicture::reset()
|
|
|
|
{
|
|
|
|
// INIT PIC
|
2020-11-15 12:29:33 +01:00
|
|
|
p_ragePhoto.clear();
|
2017-10-09 08:35:48 +02:00
|
|
|
cachePicture = QImage();
|
|
|
|
picExportFileName = QString();
|
|
|
|
pictureStr = QString();
|
|
|
|
lastStep = QString();
|
|
|
|
sortStr = QString();
|
|
|
|
|
2023-01-27 20:09:43 +01:00
|
|
|
// INIT PIC FORMAT
|
|
|
|
picFormat = 0;
|
|
|
|
|
2017-10-09 08:35:48 +02:00
|
|
|
// INIT PIC BOOLS
|
2017-11-22 20:23:36 +01:00
|
|
|
isFormatSwitch = false;
|
2023-01-27 20:09:43 +01:00
|
|
|
isPreLoaded = false;
|
2017-10-09 08:35:48 +02:00
|
|
|
picOk = false;
|
|
|
|
|
|
|
|
// INIT JSON
|
|
|
|
jsonOk = false;
|
|
|
|
|
|
|
|
// SNAPMATIC PROPERTIES
|
2017-12-12 04:45:46 +01:00
|
|
|
localProperties = {};
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
// JSON OBJECT
|
|
|
|
jsonObject = QJsonObject();
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SnapmaticPicture::preloadFile()
|
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
QFile picFile(picFilePath);
|
2017-10-09 08:35:48 +02:00
|
|
|
picFileName = QFileInfo(picFilePath).fileName();
|
2017-11-22 20:23:36 +01:00
|
|
|
isFormatSwitch = false;
|
|
|
|
|
2023-01-27 20:09:43 +01:00
|
|
|
if (!picFile.open(QIODevice::ReadOnly)) {
|
2018-05-24 22:32:00 +02:00
|
|
|
lastStep = "1;/1,OpenFile," % convertDrawStringForLog(picFilePath);
|
2017-10-09 08:35:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-11-09 01:08:51 +01:00
|
|
|
|
2023-02-08 20:05:15 +01:00
|
|
|
const qint64 fileSize = picFile.size();
|
|
|
|
const QByteArray fileData = picFile.read(fileSize);
|
2023-01-27 20:09:43 +01:00
|
|
|
|
|
|
|
bool ok = p_ragePhoto.load(fileData.constData(), fileData.size());
|
|
|
|
picFormat = p_ragePhoto.format();
|
|
|
|
|
2023-01-27 21:10:17 +01:00
|
|
|
if (!ok) {
|
2023-02-20 14:04:17 +01:00
|
|
|
const int32_t error = p_ragePhoto.error();
|
2023-01-27 21:10:17 +01:00
|
|
|
switch (error) {
|
|
|
|
case RagePhoto::Uninitialised:
|
|
|
|
lastStep = "1;/1,OpenFile," % convertDrawStringForLog(picFilePath);
|
|
|
|
break;
|
|
|
|
case RagePhoto::NoFormatIdentifier:
|
|
|
|
case RagePhoto::IncompleteHeader:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",1,NOHEADER";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompatibleFormat:
|
|
|
|
lastStep = "2;/4,ReadingFile," % convertDrawStringForLog(picFilePath) % ",1,MALFORMEDHEADER,LIBRAGEPHOTO_INCOMPATIBLE_FORMAT";
|
|
|
|
break;
|
|
|
|
case RagePhoto::UnicodeInitError:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",1,LIBRAGEPHOTO_UNICODE_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::UnicodeHeaderError:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",1,MALFORMEDHEADER";
|
|
|
|
break;
|
|
|
|
case RagePhoto::HeaderMallocError:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",1,LIBRAGEPHOTO_MALLOC_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteChecksum:
|
|
|
|
case RagePhoto::IncompleteEOF:
|
|
|
|
case RagePhoto::IncompleteJsonOffset:
|
|
|
|
case RagePhoto::IncompleteTitleOffset:
|
|
|
|
case RagePhoto::IncompleteDescOffset:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",2,NOHEADER";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteJpegMarker:
|
|
|
|
case RagePhoto::IncorrectJpegMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",2,NOJPEG";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompletePhotoBuffer:
|
|
|
|
case RagePhoto::IncompletePhotoSize:
|
|
|
|
case RagePhoto::PhotoReadError:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",2,NOPIC";
|
|
|
|
break;
|
|
|
|
case RagePhoto::PhotoMallocError:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",2,LIBRAGEPHOTO_MALLOC_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteJsonMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",3,NOJSON";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncorrectJsonMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",3,CTJSON";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteJsonBuffer:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",3,LIBRAGEPHOTO_INCOMPLETE_BUFFER_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::JsonReadError:
|
|
|
|
lastStep = "2;/4,ReadingFile," % convertDrawStringForLog(picFilePath) % ",3,NOJSON,LIBRAGEPHOTO_READ_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::JsonMallocError:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",3,LIBRAGEPHOTO_MALLOC_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteTitleMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",4,NOTITL";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncorrectTitleMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",4,CTTITL";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteTitleBuffer:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",4,LIBRAGEPHOTO_INCOMPLETE_BUFFER_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::TitleReadError:
|
|
|
|
lastStep = "2;/4,ReadingFile," % convertDrawStringForLog(picFilePath) % ",4,NOTITL,LIBRAGEPHOTO_READ_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::TitleMallocError:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",4,LIBRAGEPHOTO_MALLOC_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteDescMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",5,NODESC";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncorrectDescMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",5,CTDESC";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteDescBuffer:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",5,LIBRAGEPHOTO_INCOMPLETE_BUFFER_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::DescReadError:
|
|
|
|
lastStep = "2;/4,ReadingFile," % convertDrawStringForLog(picFilePath) % ",5,NODESC,LIBRAGEPHOTO_READ_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::DescMallocError:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",5,LIBRAGEPHOTO_MALLOC_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncompleteJendMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",6,LIBRAGEPHOTO_INCOMPLETE_JEND_ERROR";
|
|
|
|
break;
|
|
|
|
case RagePhoto::IncorrectJendMarker:
|
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",6,LIBRAGEPHOTO_INCORRECT_JEND_ERROR";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2020-11-09 01:08:51 +01:00
|
|
|
return false;
|
2023-01-27 21:10:17 +01:00
|
|
|
}
|
2020-11-09 01:08:51 +01:00
|
|
|
|
2023-01-27 20:09:43 +01:00
|
|
|
const QJsonDocument t_jsonDocument = QJsonDocument::fromJson(p_ragePhoto.json());
|
|
|
|
if (t_jsonDocument.isNull())
|
|
|
|
return false;
|
|
|
|
jsonObject = t_jsonDocument.object();
|
|
|
|
|
|
|
|
if (!picFilePath.endsWith(".g5e", Qt::CaseInsensitive)) {
|
|
|
|
if (picFormat == G5EPhotoFormat::G5EX)
|
2017-11-22 20:23:36 +01:00
|
|
|
isFormatSwitch = true;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
isPreLoaded = true;
|
2017-10-09 08:35:48 +02:00
|
|
|
emit preloaded();
|
2020-11-09 01:08:51 +01:00
|
|
|
return ok;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
2020-11-09 01:42:11 +01:00
|
|
|
bool SnapmaticPicture::readingPicture(bool cacheEnabled_)
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
|
|
|
// Start opening file
|
|
|
|
// lastStep is like currentStep
|
|
|
|
|
|
|
|
// Set boolean values
|
|
|
|
cacheEnabled = cacheEnabled_;
|
|
|
|
|
2020-11-09 01:08:51 +01:00
|
|
|
bool ok = true;
|
2023-01-27 20:09:43 +01:00
|
|
|
if (!isPreLoaded)
|
2020-11-09 01:08:51 +01:00
|
|
|
ok = preloadFile();
|
2017-10-09 08:35:48 +02:00
|
|
|
|
2020-11-09 01:08:51 +01:00
|
|
|
if (!ok)
|
2017-10-09 08:35:48 +02:00
|
|
|
return false;
|
2018-07-12 10:52:33 +02:00
|
|
|
|
2021-02-15 23:12:44 +01:00
|
|
|
if (cacheEnabled)
|
2023-01-27 20:09:43 +01:00
|
|
|
picOk = cachePicture.loadFromData(QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize()), "JPEG");
|
2021-02-15 23:12:44 +01:00
|
|
|
if (!cacheEnabled) {
|
2017-10-09 08:35:48 +02:00
|
|
|
QImage tempPicture;
|
2023-01-27 20:09:43 +01:00
|
|
|
picOk = tempPicture.loadFromData(QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize()), "JPEG");
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
parseJsonContent(); // JSON parsing is own function
|
|
|
|
updateStrings();
|
|
|
|
|
|
|
|
emit loaded();
|
|
|
|
return picOk;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SnapmaticPicture::updateStrings()
|
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
QString cmpPicTitl(p_ragePhoto.title());
|
2017-10-09 08:35:48 +02:00
|
|
|
cmpPicTitl.replace('\"', "''");
|
|
|
|
cmpPicTitl.replace(' ', '_');
|
|
|
|
cmpPicTitl.replace(':', '-');
|
|
|
|
cmpPicTitl.remove('\\');
|
|
|
|
cmpPicTitl.remove('{');
|
|
|
|
cmpPicTitl.remove('}');
|
|
|
|
cmpPicTitl.remove('/');
|
|
|
|
cmpPicTitl.remove('<');
|
|
|
|
cmpPicTitl.remove('>');
|
|
|
|
cmpPicTitl.remove('*');
|
|
|
|
cmpPicTitl.remove('?');
|
|
|
|
cmpPicTitl.remove('.');
|
2017-12-12 04:45:46 +01:00
|
|
|
pictureStr = tr("PHOTO - %1").arg(localProperties.createdDateTime.toString("MM/dd/yy HH:mm:ss"));
|
|
|
|
sortStr = localProperties.createdDateTime.toString("yyMMddHHmmss") % QString::number(localProperties.uid);
|
2023-01-27 20:09:43 +01:00
|
|
|
const QString exportStr = localProperties.createdDateTime.toString("yyyyMMdd") % "-" % QString::number(localProperties.uid);
|
2021-02-15 23:12:44 +01:00
|
|
|
if (getSnapmaticFormat() == SnapmaticFormat::G5E_Format)
|
|
|
|
picFileName = "PGTA5" % QString::number(localProperties.uid);
|
2017-10-09 08:35:48 +02:00
|
|
|
picExportFileName = exportStr % "_" % cmpPicTitl;
|
|
|
|
}
|
|
|
|
|
2020-11-09 01:42:11 +01:00
|
|
|
bool SnapmaticPicture::readingPictureFromFile(const QString &fileName, bool cacheEnabled_)
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
2021-02-15 23:12:44 +01:00
|
|
|
if (!fileName.isEmpty()) {
|
2017-10-09 08:35:48 +02:00
|
|
|
picFilePath = fileName;
|
2020-11-09 01:42:11 +01:00
|
|
|
return readingPicture(cacheEnabled_);
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
else
|
2017-10-09 08:35:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-15 13:15:16 +01:00
|
|
|
bool SnapmaticPicture::setImage(const QImage &picture, bool eXtendMode)
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
#ifdef GTA5SYNC_DYNAMIC_PHOTOBUFFER // It's not properly implemented yet, please don't define
|
|
|
|
quint32 jpegPicStreamLength = p_ragePhoto.data()->photoBuffer();
|
2021-05-23 05:06:32 +02:00
|
|
|
#else
|
2023-01-27 20:09:43 +01:00
|
|
|
quint32 jpegPicStreamLength = RagePhoto::DEFAULT_GTA5_PHOTOBUFFER;
|
2021-05-23 05:06:32 +02:00
|
|
|
#endif
|
2020-11-09 01:08:51 +01:00
|
|
|
QByteArray picByteArray;
|
|
|
|
int comLvl = 100;
|
|
|
|
bool saveSuccess = false;
|
|
|
|
while (comLvl != 0 && !saveSuccess) {
|
|
|
|
QByteArray picByteArrayT;
|
|
|
|
QBuffer picStreamT(&picByteArrayT);
|
|
|
|
picStreamT.open(QIODevice::WriteOnly);
|
|
|
|
saveSuccess = picture.save(&picStreamT, "JPEG", comLvl);
|
|
|
|
picStreamT.close();
|
2020-11-11 07:04:39 +01:00
|
|
|
if (saveSuccess) {
|
2020-11-15 13:15:16 +01:00
|
|
|
quint32 size = picByteArrayT.length();
|
|
|
|
if (size > jpegPicStreamLength) {
|
|
|
|
if (!eXtendMode) {
|
|
|
|
comLvl--;
|
|
|
|
saveSuccess = false;
|
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
else
|
2020-11-15 13:55:06 +01:00
|
|
|
picByteArray = picByteArrayT;
|
2020-11-09 01:08:51 +01:00
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
else
|
2020-11-09 01:08:51 +01:00
|
|
|
picByteArray = picByteArrayT;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
}
|
2020-11-09 01:08:51 +01:00
|
|
|
if (saveSuccess)
|
|
|
|
return setPictureStream(picByteArray);
|
2017-10-09 08:35:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-12 04:45:46 +01:00
|
|
|
bool SnapmaticPicture::setPictureStream(const QByteArray &streamArray) // clean method
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
#ifdef GTA5SYNC_DYNAMIC_PHOTOBUFFER // It's not properly implemented yet, please don't define
|
|
|
|
quint32 jpegPicStreamLength = p_ragePhoto.data()->photoBuffer();
|
|
|
|
#else
|
|
|
|
quint32 jpegPicStreamLength = RagePhoto::DEFAULT_GTA5_PHOTOBUFFER;
|
|
|
|
#endif
|
|
|
|
if (streamArray.size() > jpegPicStreamLength)
|
|
|
|
jpegPicStreamLength = streamArray.size();
|
|
|
|
#ifdef GTA5SYNC_COMPACT_PHOTOBUFFER // Experiment to save less than the default photo buffer
|
|
|
|
if (streamArray.size() < jpegPicStreamLength)
|
|
|
|
jpegPicStreamLength = streamArray.size();
|
|
|
|
#endif
|
|
|
|
bool success = p_ragePhoto.setPhoto(streamArray.data(), streamArray.size(), jpegPicStreamLength);
|
2020-11-11 07:04:39 +01:00
|
|
|
if (success) {
|
|
|
|
if (cacheEnabled) {
|
|
|
|
QImage replacedPicture;
|
|
|
|
replacedPicture.loadFromData(streamArray);
|
|
|
|
cachePicture = replacedPicture;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
else
|
2020-11-11 07:04:39 +01:00
|
|
|
return false;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SnapmaticPicture::setPictureTitl(const QString &newTitle_)
|
|
|
|
{
|
2020-11-11 07:04:39 +01:00
|
|
|
QString newTitle = newTitle_;
|
2023-01-27 20:09:43 +01:00
|
|
|
if (newTitle.length() > 39)
|
2020-11-11 07:04:39 +01:00
|
|
|
newTitle = newTitle.left(39);
|
2023-01-27 20:09:43 +01:00
|
|
|
p_ragePhoto.setTitle(newTitle.toStdString().c_str());
|
2020-11-11 07:04:39 +01:00
|
|
|
return true;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::getExportPictureFileName()
|
|
|
|
{
|
|
|
|
return picExportFileName;
|
|
|
|
}
|
|
|
|
|
2017-10-12 22:21:45 +02:00
|
|
|
QString SnapmaticPicture::getOriginalPictureFileName()
|
|
|
|
{
|
|
|
|
QString newPicFileName = picFileName;
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFileName.right(4) == ".bak")
|
2017-10-12 22:21:45 +02:00
|
|
|
newPicFileName = QString(picFileName).remove(picFileName.length() - 4, 4);
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFileName.right(7) == ".hidden")
|
2017-10-12 22:21:45 +02:00
|
|
|
newPicFileName = QString(picFileName).remove(picFileName.length() - 7, 7);
|
|
|
|
return newPicFileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::getOriginalPictureFilePath()
|
|
|
|
{
|
|
|
|
QString newPicFilePath = picFilePath;
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFilePath.right(4) == ".bak")
|
2017-10-12 22:21:45 +02:00
|
|
|
newPicFilePath = QString(picFilePath).remove(picFilePath.length() - 4, 4);
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFilePath.right(7) == ".hidden")
|
2017-10-12 22:21:45 +02:00
|
|
|
newPicFilePath = QString(picFilePath).remove(picFilePath.length() - 7, 7);
|
|
|
|
return newPicFilePath;
|
|
|
|
}
|
|
|
|
|
2017-10-09 08:35:48 +02:00
|
|
|
QString SnapmaticPicture::getPictureFileName()
|
|
|
|
{
|
|
|
|
return picFileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::getPictureFilePath()
|
|
|
|
{
|
|
|
|
return picFilePath;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::getPictureSortStr()
|
|
|
|
{
|
|
|
|
return sortStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::getPictureTitl()
|
|
|
|
{
|
2020-11-15 12:29:33 +01:00
|
|
|
return p_ragePhoto.title();
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::getPictureStr()
|
|
|
|
{
|
|
|
|
return pictureStr;
|
|
|
|
}
|
|
|
|
|
2017-12-12 04:45:46 +01:00
|
|
|
QString SnapmaticPicture::getLastStep(bool readable)
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
2021-02-15 23:12:44 +01:00
|
|
|
if (readable) {
|
2017-12-12 04:45:46 +01:00
|
|
|
QStringList lastStepList = lastStep.split(";/");
|
2021-02-15 23:12:44 +01:00
|
|
|
if (lastStepList.length() < 2)
|
|
|
|
return lastStep;
|
2017-12-12 04:45:46 +01:00
|
|
|
bool intOk;
|
|
|
|
QStringList descStepList = lastStepList.at(1).split(",");
|
2021-02-15 23:12:44 +01:00
|
|
|
if (descStepList.length() < 1)
|
|
|
|
return lastStep;
|
2017-12-12 04:45:46 +01:00
|
|
|
int argsCount = descStepList.at(0).toInt(&intOk);
|
2023-01-27 20:09:43 +01:00
|
|
|
if (!intOk)
|
|
|
|
return lastStep;
|
2021-02-15 23:12:44 +01:00
|
|
|
if (argsCount == 1) {
|
2017-12-12 04:45:46 +01:00
|
|
|
QString currentAction = descStepList.at(1);
|
|
|
|
QString actionFile = descStepList.at(2);
|
2023-01-27 20:09:43 +01:00
|
|
|
if (currentAction == "OpenFile")
|
2017-12-12 04:45:46 +01:00
|
|
|
return tr("open file %1").arg(actionFile);
|
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else if (argsCount == 3 || argsCount == 4) {
|
2017-12-12 04:45:46 +01:00
|
|
|
QString currentAction = descStepList.at(1);
|
|
|
|
QString actionFile = descStepList.at(2);
|
|
|
|
QString actionError = descStepList.at(4);
|
|
|
|
QString actionError2;
|
|
|
|
if (argsCount == 4) { actionError2 = descStepList.at(5); }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (currentAction == "ReadingFile") {
|
2017-12-12 04:45:46 +01:00
|
|
|
QString readableError = actionError;
|
2023-01-27 20:09:43 +01:00
|
|
|
if (actionError == "NOHEADER")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("header not exists");
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (actionError == "MALFORMEDHEADER")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("header is malformed");
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (actionError == "NOJPEG" || actionError == "NOPIC")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("picture not exists (%1)").arg(actionError);
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (actionError == "NOJSON" || actionError == "CTJSON")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("JSON not exists (%1)").arg(actionError);
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (actionError == "NOTITL" || actionError == "CTTITL")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("title not exists (%1)").arg(actionError);
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (actionError == "NODESC" || actionError == "CTDESC")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("description not exists (%1)").arg(actionError);
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (actionError == "JSONINCOMPLETE" && actionError2 == "JSONERROR")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("JSON is incomplete and malformed");
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (actionError == "JSONINCOMPLETE")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("JSON is incomplete");
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (actionError == "JSONERROR")
|
2017-12-12 04:45:46 +01:00
|
|
|
readableError = tr("JSON is malformed");
|
|
|
|
return tr("reading file %1 because of %2", "Example for %2: JSON is malformed error").arg(actionFile, readableError);
|
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
else
|
2017-12-12 04:45:46 +01:00
|
|
|
return lastStep;
|
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
else
|
2017-12-12 04:45:46 +01:00
|
|
|
return lastStep;
|
|
|
|
}
|
2017-10-09 08:35:48 +02:00
|
|
|
return lastStep;
|
2017-12-12 04:45:46 +01:00
|
|
|
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
2020-11-25 00:36:12 +01:00
|
|
|
QImage SnapmaticPicture::getImage()
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
if (cacheEnabled)
|
2017-10-09 08:35:48 +02:00
|
|
|
return cachePicture;
|
2023-01-27 20:09:43 +01:00
|
|
|
else
|
|
|
|
return QImage::fromData(QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize()), "JPEG");
|
2017-10-09 08:35:48 +02:00
|
|
|
return QImage();
|
|
|
|
}
|
|
|
|
|
2020-11-09 01:08:51 +01:00
|
|
|
QByteArray SnapmaticPicture::getPictureStream()
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
return QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize());
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SnapmaticPicture::isPicOk()
|
|
|
|
{
|
|
|
|
return picOk;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SnapmaticPicture::clearCache()
|
|
|
|
{
|
|
|
|
cacheEnabled = false;
|
|
|
|
cachePicture = QImage();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SnapmaticPicture::emitUpdate()
|
|
|
|
{
|
|
|
|
emit updated();
|
|
|
|
}
|
|
|
|
|
2017-12-17 13:03:43 +01:00
|
|
|
void SnapmaticPicture::emitCustomSignal(const QString &signal)
|
|
|
|
{
|
|
|
|
emit customSignal(signal);
|
|
|
|
}
|
|
|
|
|
2017-10-09 08:35:48 +02:00
|
|
|
// JSON part
|
|
|
|
|
|
|
|
bool SnapmaticPicture::isJsonOk()
|
|
|
|
{
|
|
|
|
return jsonOk;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::getJsonStr()
|
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
return QString::fromUtf8(p_ragePhoto.json());
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SnapmaticProperties SnapmaticPicture::getSnapmaticProperties()
|
|
|
|
{
|
2017-12-12 04:45:46 +01:00
|
|
|
return localProperties;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SnapmaticPicture::parseJsonContent()
|
|
|
|
{
|
2017-11-22 14:59:40 +01:00
|
|
|
QVariantMap jsonMap = jsonObject.toVariantMap();
|
2017-10-09 08:35:48 +02:00
|
|
|
|
2017-11-22 14:59:40 +01:00
|
|
|
bool jsonIncomplete = false;
|
|
|
|
bool jsonError = false;
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("loc")) {
|
|
|
|
if (jsonObject["loc"].isObject()) {
|
2017-11-22 14:59:40 +01:00
|
|
|
QJsonObject locObject = jsonObject["loc"].toObject();
|
2021-02-15 23:12:44 +01:00
|
|
|
if (locObject.contains("x")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (locObject["x"].isDouble()) { localProperties.location.x = locObject["x"].toDouble(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
|
|
|
}
|
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (locObject.contains("y")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (locObject["y"].isDouble()) { localProperties.location.y = locObject["y"].toDouble(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
|
|
|
}
|
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (locObject.contains("z")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (locObject["z"].isDouble()) { localProperties.location.z = locObject["z"].toDouble(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
|
|
|
}
|
|
|
|
else { jsonIncomplete = true; }
|
|
|
|
}
|
|
|
|
else { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("uid")) {
|
2017-11-22 14:59:40 +01:00
|
|
|
bool uidOk;
|
2017-12-12 04:45:46 +01:00
|
|
|
localProperties.uid = jsonMap["uid"].toInt(&uidOk);
|
2017-11-22 14:59:40 +01:00
|
|
|
if (!uidOk) { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("area")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (jsonObject["area"].isString()) { localProperties.location.area = jsonObject["area"].toString(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("crewid")) {
|
2017-11-22 14:59:40 +01:00
|
|
|
bool crewIDOk;
|
2017-12-12 04:45:46 +01:00
|
|
|
localProperties.crewID = jsonMap["crewid"].toInt(&crewIDOk);
|
2017-11-22 14:59:40 +01:00
|
|
|
if (!crewIDOk) { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("street")) {
|
2017-11-22 14:59:40 +01:00
|
|
|
bool streetIDOk;
|
2017-12-12 04:45:46 +01:00
|
|
|
localProperties.streetID = jsonMap["street"].toInt(&streetIDOk);
|
2017-11-22 14:59:40 +01:00
|
|
|
if (!streetIDOk) { jsonError = true; }
|
|
|
|
}
|
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("creat")) {
|
2017-11-22 14:59:40 +01:00
|
|
|
bool timestampOk;
|
2017-10-09 08:35:48 +02:00
|
|
|
QDateTime createdTimestamp;
|
2017-12-12 04:45:46 +01:00
|
|
|
localProperties.createdTimestamp = jsonMap["creat"].toUInt(×tampOk);
|
2020-09-28 05:33:04 +02:00
|
|
|
#if QT_VERSION >= 0x060000
|
2020-11-05 18:32:20 +01:00
|
|
|
createdTimestamp.setSecsSinceEpoch(localProperties.createdTimestamp);
|
2020-09-28 05:33:04 +02:00
|
|
|
#else
|
2017-12-12 04:45:46 +01:00
|
|
|
createdTimestamp.setTime_t(localProperties.createdTimestamp);
|
2020-09-28 05:33:04 +02:00
|
|
|
#endif
|
2017-12-12 04:45:46 +01:00
|
|
|
localProperties.createdDateTime = createdTimestamp;
|
2017-11-22 14:59:40 +01:00
|
|
|
if (!timestampOk) { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("plyrs")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (jsonObject["plyrs"].isArray()) { localProperties.playersList = jsonMap["plyrs"].toStringList(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-12-12 04:45:46 +01:00
|
|
|
// else { jsonIncomplete = true; } // 2016 Snapmatic pictures left out plyrs when none are captured, so don't force exists on that one
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("meme")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (jsonObject["meme"].isBool()) { localProperties.isMeme = jsonObject["meme"].toBool(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("mug")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (jsonObject["mug"].isBool()) { localProperties.isMug = jsonObject["mug"].toBool(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("slf")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (jsonObject["slf"].isBool()) { localProperties.isSelfie = jsonObject["slf"].toBool(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("drctr")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (jsonObject["drctr"].isBool()) { localProperties.isFromDirector = jsonObject["drctr"].toBool(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonIncomplete = true; }
|
2021-02-15 23:12:44 +01:00
|
|
|
if (jsonObject.contains("rsedtr")) {
|
2017-12-12 04:45:46 +01:00
|
|
|
if (jsonObject["rsedtr"].isBool()) { localProperties.isFromRSEditor = jsonObject["rsedtr"].toBool(); }
|
2017-11-22 14:59:40 +01:00
|
|
|
else { jsonError = true; }
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else { localProperties.isFromRSEditor = false; }
|
|
|
|
if (jsonObject.contains("onislandx")) {
|
|
|
|
if (jsonObject["onislandx"].isBool()) { localProperties.location.isCayoPerico = jsonObject["onislandx"].toBool(); }
|
|
|
|
else { jsonError = true; }
|
|
|
|
}
|
|
|
|
else { localProperties.location.isCayoPerico = false; }
|
2017-10-09 08:35:48 +02:00
|
|
|
|
2021-02-15 23:12:44 +01:00
|
|
|
if (!jsonIncomplete && !jsonError) {
|
2017-11-22 14:59:40 +01:00
|
|
|
jsonOk = true;
|
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else {
|
|
|
|
if (jsonIncomplete && jsonError) {
|
2018-05-24 22:32:00 +02:00
|
|
|
lastStep = "2;/4,ReadingFile," % convertDrawStringForLog(picFilePath) % ",3,JSONINCOMPLETE,JSONERROR";
|
2017-12-12 04:45:46 +01:00
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else if (jsonIncomplete) {
|
2018-05-24 22:32:00 +02:00
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",3,JSONINCOMPLETE";
|
2017-12-12 04:45:46 +01:00
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else if (jsonError) {
|
2018-05-24 22:32:00 +02:00
|
|
|
lastStep = "2;/3,ReadingFile," % convertDrawStringForLog(picFilePath) % ",3,JSONERROR";
|
2017-12-12 04:45:46 +01:00
|
|
|
}
|
2017-11-22 14:59:40 +01:00
|
|
|
jsonOk = false;
|
|
|
|
}
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
2017-12-12 04:45:46 +01:00
|
|
|
bool SnapmaticPicture::setSnapmaticProperties(SnapmaticProperties properties)
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
QJsonObject t_jsonObject = jsonObject;
|
2017-10-09 08:35:48 +02:00
|
|
|
|
|
|
|
QJsonObject locObject;
|
2017-12-12 04:45:46 +01:00
|
|
|
locObject["x"] = properties.location.x;
|
|
|
|
locObject["y"] = properties.location.y;
|
|
|
|
locObject["z"] = properties.location.z;
|
2017-10-09 08:35:48 +02:00
|
|
|
|
2023-01-27 20:09:43 +01:00
|
|
|
t_jsonObject["loc"] = locObject;
|
|
|
|
t_jsonObject["uid"] = properties.uid;
|
|
|
|
t_jsonObject["area"] = properties.location.area;
|
|
|
|
t_jsonObject["crewid"] = properties.crewID;
|
|
|
|
t_jsonObject["street"] = properties.streetID;
|
|
|
|
t_jsonObject["creat"] = QJsonValue::fromVariant(properties.createdTimestamp);
|
|
|
|
t_jsonObject["plyrs"] = QJsonValue::fromVariant(properties.playersList);
|
|
|
|
t_jsonObject["meme"] = properties.isMeme;
|
|
|
|
t_jsonObject["mug"] = properties.isMug;
|
|
|
|
t_jsonObject["slf"] = properties.isSelfie;
|
|
|
|
t_jsonObject["drctr"] = properties.isFromDirector;
|
|
|
|
t_jsonObject["rsedtr"] = properties.isFromRSEditor;
|
|
|
|
t_jsonObject["onislandx"] = properties.location.isCayoPerico;
|
|
|
|
|
|
|
|
const QJsonDocument jsonDocument(t_jsonObject);
|
2021-02-15 23:12:44 +01:00
|
|
|
if (setJsonStr(QString::fromUtf8(jsonDocument.toJson(QJsonDocument::Compact)))) {
|
2017-12-12 04:45:46 +01:00
|
|
|
localProperties = properties;
|
2017-10-09 08:35:48 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-11-22 14:59:40 +01:00
|
|
|
bool SnapmaticPicture::setJsonStr(const QString &newJsonStr, bool updateProperties)
|
2017-10-09 08:35:48 +02:00
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
const QJsonDocument t_jsonDocument = QJsonDocument::fromJson(newJsonStr.toStdString().c_str());
|
|
|
|
if (t_jsonDocument.isNull())
|
2020-11-09 01:08:51 +01:00
|
|
|
return false;
|
2023-01-27 20:09:43 +01:00
|
|
|
const QByteArray t_jsonData = t_jsonDocument.toJson(QJsonDocument::Compact);
|
|
|
|
jsonObject = t_jsonDocument.object();
|
|
|
|
|
|
|
|
p_ragePhoto.setJson(t_jsonData.constData());
|
|
|
|
if (updateProperties)
|
|
|
|
parseJsonContent();
|
|
|
|
return true;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// FILE MANAGEMENT
|
|
|
|
|
|
|
|
bool SnapmaticPicture::exportPicture(const QString &fileName, SnapmaticFormat format_)
|
|
|
|
{
|
2020-11-11 07:04:39 +01:00
|
|
|
// Keep current format when Auto_Format is used
|
|
|
|
SnapmaticFormat format = format_;
|
2021-02-15 23:12:44 +01:00
|
|
|
if (format_ == SnapmaticFormat::Auto_Format) {
|
2023-01-27 20:09:43 +01:00
|
|
|
if (p_ragePhoto.format() == G5EPhotoFormat::G5EX) {
|
2020-11-11 07:04:39 +01:00
|
|
|
format = SnapmaticFormat::G5E_Format;
|
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else {
|
2020-11-11 07:04:39 +01:00
|
|
|
format = SnapmaticFormat::PGTA_Format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool saveSuccess = false;
|
2023-01-27 20:09:43 +01:00
|
|
|
QSaveFile picFile(fileName);
|
|
|
|
if (picFile.open(QIODevice::WriteOnly)) {
|
2021-02-15 23:12:44 +01:00
|
|
|
if (format == SnapmaticFormat::G5E_Format) {
|
2023-01-27 20:09:43 +01:00
|
|
|
gta5view_export_save(&picFile, p_ragePhoto.data());
|
|
|
|
saveSuccess = picFile.commit();
|
2020-11-11 07:04:39 +01:00
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else if (format == SnapmaticFormat::JPEG_Format) {
|
2023-01-27 20:09:43 +01:00
|
|
|
picFile.write(QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize()));
|
|
|
|
saveSuccess = picFile.commit();
|
2020-11-11 07:04:39 +01:00
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else {
|
2023-01-27 20:09:43 +01:00
|
|
|
bool ok;
|
|
|
|
const std::string photo = p_ragePhoto.save(&ok);
|
|
|
|
if (ok)
|
|
|
|
picFile.write(photo.data(), photo.size());
|
|
|
|
saveSuccess = picFile.commit();
|
2020-11-11 07:04:39 +01:00
|
|
|
}
|
|
|
|
return saveSuccess;
|
|
|
|
}
|
2023-01-27 20:09:43 +01:00
|
|
|
else
|
2020-11-11 07:04:39 +01:00
|
|
|
return saveSuccess;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SnapmaticPicture::setPicFileName(const QString &picFileName_)
|
|
|
|
{
|
|
|
|
picFileName = picFileName_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SnapmaticPicture::setPicFilePath(const QString &picFilePath_)
|
|
|
|
{
|
|
|
|
picFilePath = picFilePath_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SnapmaticPicture::deletePicFile()
|
|
|
|
{
|
2020-11-05 18:32:20 +01:00
|
|
|
bool success = false;
|
2023-01-27 20:09:43 +01:00
|
|
|
if (!QFile::exists(picFilePath))
|
2020-11-05 18:32:20 +01:00
|
|
|
success = true;
|
2023-01-27 20:09:43 +01:00
|
|
|
else if (QFile::remove(picFilePath))
|
2020-11-05 18:32:20 +01:00
|
|
|
success = true;
|
2021-02-15 23:12:44 +01:00
|
|
|
if (isHidden()) {
|
2020-11-05 18:32:20 +01:00
|
|
|
const QString picBakPath = QString(picFilePath).remove(picFilePath.length() - 7, 7) % ".bak";
|
2023-01-27 20:09:43 +01:00
|
|
|
if (QFile::exists(picBakPath))
|
|
|
|
QFile::remove(picBakPath);
|
2020-11-05 18:32:20 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
const QString picBakPath = picFilePath % ".bak";
|
2023-01-27 20:09:43 +01:00
|
|
|
if (QFile::exists(picBakPath))
|
|
|
|
QFile::remove(picBakPath);
|
2020-11-05 18:32:20 +01:00
|
|
|
}
|
|
|
|
return success;
|
2017-10-09 08:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// VISIBILITY
|
|
|
|
|
|
|
|
bool SnapmaticPicture::isHidden()
|
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFilePath.right(7) == QLatin1String(".hidden"))
|
2017-10-09 08:35:48 +02:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-12 04:45:46 +01:00
|
|
|
bool SnapmaticPicture::isVisible()
|
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFilePath.right(7) == QLatin1String(".hidden"))
|
2017-12-12 04:45:46 +01:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-10-09 08:35:48 +02:00
|
|
|
bool SnapmaticPicture::setPictureHidden()
|
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFormat == G5EPhotoFormat::G5EX) {
|
2017-10-09 08:35:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
if (!isHidden()) {
|
2017-10-09 08:35:48 +02:00
|
|
|
QString newPicFilePath = QString(picFilePath % ".hidden");
|
2021-02-15 23:12:44 +01:00
|
|
|
if (QFile::rename(picFilePath, newPicFilePath)) {
|
2017-10-09 08:35:48 +02:00
|
|
|
picFilePath = newPicFilePath;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SnapmaticPicture::setPictureVisible()
|
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFormat == G5EPhotoFormat::G5EX)
|
2017-10-09 08:35:48 +02:00
|
|
|
return false;
|
2021-02-15 23:12:44 +01:00
|
|
|
if (isHidden()) {
|
2017-10-09 08:35:48 +02:00
|
|
|
QString newPicFilePath = QString(picFilePath).remove(picFilePath.length() - 7, 7);
|
2021-02-15 23:12:44 +01:00
|
|
|
if (QFile::rename(picFilePath, newPicFilePath)) {
|
2017-10-09 08:35:48 +02:00
|
|
|
picFilePath = newPicFilePath;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// PREDEFINED PROPERTIES
|
|
|
|
|
|
|
|
QSize SnapmaticPicture::getSnapmaticResolution()
|
|
|
|
{
|
|
|
|
return snapmaticResolution;
|
|
|
|
}
|
|
|
|
|
2017-11-22 20:23:36 +01:00
|
|
|
// SNAPMATIC FORMAT
|
|
|
|
|
|
|
|
SnapmaticFormat SnapmaticPicture::getSnapmaticFormat()
|
|
|
|
{
|
2023-01-27 20:09:43 +01:00
|
|
|
if (picFormat == G5EPhotoFormat::G5EX)
|
2017-11-22 20:23:36 +01:00
|
|
|
return SnapmaticFormat::G5E_Format;
|
|
|
|
return SnapmaticFormat::PGTA_Format;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SnapmaticPicture::setSnapmaticFormat(SnapmaticFormat format)
|
|
|
|
{
|
2021-02-15 23:12:44 +01:00
|
|
|
if (format == SnapmaticFormat::G5E_Format) {
|
2023-01-27 20:09:43 +01:00
|
|
|
picFormat = G5EPhotoFormat::G5EX;
|
2017-11-22 20:23:36 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-02-15 23:12:44 +01:00
|
|
|
else if (format == SnapmaticFormat::PGTA_Format) {
|
2023-01-27 20:09:43 +01:00
|
|
|
picFormat = RagePhoto::PhotoFormat::GTA5;
|
2017-11-22 20:23:36 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
qDebug() << "setSnapmaticFormat: Invalid SnapmaticFormat defined, valid SnapmaticFormats are G5E_Format and PGTA_Format";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SnapmaticPicture::isFormatSwitched()
|
|
|
|
{
|
|
|
|
return isFormatSwitch;
|
|
|
|
}
|
|
|
|
|
2017-10-09 08:35:48 +02:00
|
|
|
// VERIFY CONTENT
|
|
|
|
|
|
|
|
bool SnapmaticPicture::verifyTitle(const QString &title)
|
|
|
|
{
|
|
|
|
// VERIFY TITLE FOR BE A VALID SNAPMATIC TITLE
|
2021-02-15 23:12:44 +01:00
|
|
|
if (title.length() <= 39 && title.length() > 0) {
|
|
|
|
for (const QChar &titleChar : title) {
|
2017-10-09 08:35:48 +02:00
|
|
|
if (!verifyTitleChar(titleChar)) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SnapmaticPicture::verifyTitleChar(const QChar &titleChar)
|
|
|
|
{
|
|
|
|
// VERIFY CHAR FOR BE A VALID SNAPMATIC CHARACTER
|
2021-02-15 23:12:44 +01:00
|
|
|
if (titleChar.isLetterOrNumber() || titleChar.isPrint()) {
|
2023-01-27 20:09:43 +01:00
|
|
|
if (titleChar == '<' || titleChar == '>' || titleChar == '\\')
|
|
|
|
return false;
|
2017-10-09 08:35:48 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2018-05-24 22:32:00 +02:00
|
|
|
|
|
|
|
// STRING OPERATIONS
|
|
|
|
|
2023-01-27 20:09:43 +01:00
|
|
|
QString SnapmaticPicture::parseTitleString(const QByteArray &commitBytes)
|
2018-05-24 22:32:00 +02:00
|
|
|
{
|
2020-09-28 05:33:04 +02:00
|
|
|
#if QT_VERSION >= 0x060000
|
|
|
|
QStringDecoder strDecoder = QStringDecoder(QStringDecoder::Utf16LE);
|
|
|
|
QString retStr = strDecoder(commitBytes);
|
2020-10-11 17:46:45 +02:00
|
|
|
retStr = retStr.trimmed();
|
2020-09-28 05:33:04 +02:00
|
|
|
#else
|
2018-05-24 22:32:00 +02:00
|
|
|
QString retStr = QTextCodec::codecForName("UTF-16LE")->toUnicode(commitBytes).trimmed();
|
2020-09-28 05:33:04 +02:00
|
|
|
#endif
|
2018-05-24 22:32:00 +02:00
|
|
|
retStr.remove(QChar('\x00'));
|
|
|
|
return retStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::convertDrawStringForLog(const QString &inputStr)
|
|
|
|
{
|
|
|
|
QString outputStr = inputStr;
|
|
|
|
return outputStr.replace("&","&u;").replace(",", "&c;");
|
|
|
|
}
|
|
|
|
|
|
|
|
QString SnapmaticPicture::convertLogStringForDraw(const QString &inputStr)
|
|
|
|
{
|
|
|
|
QString outputStr = inputStr;
|
|
|
|
return outputStr.replace("&c;",",").replace("&u;", "&");
|
|
|
|
}
|
2020-11-15 12:29:33 +01:00
|
|
|
|
|
|
|
// RAGEPHOTO
|
|
|
|
|
|
|
|
RagePhoto* SnapmaticPicture::ragePhoto()
|
|
|
|
{
|
|
|
|
return &p_ragePhoto;
|
|
|
|
}
|