replace internal RagePhoto with libragephoto, few other changes
- remove more Qt4 compatibility stuff - replaced internal RagePhoto with libragephoto 0.2 - some minor UI changes - year 2023 updates
This commit is contained in:
		
							parent
							
								
									e463d2d22c
								
							
						
					
					
						commit
						050a281be8
					
				
					 23 changed files with 472 additions and 1302 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
[submodule "src/libragephoto"]
 | 
			
		||||
path = src/libragephoto
 | 
			
		||||
url = https://github.com/Syping/libragephoto.git
 | 
			
		||||
branch = 0.2.0
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,9 @@ endif()
 | 
			
		|||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network Svg Widgets REQUIRED)
 | 
			
		||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS LinguistTools QUIET)
 | 
			
		||||
 | 
			
		||||
set(RAGEPHOTO_STATIC ON CACHE BOOL "Build libragephoto as static library")
 | 
			
		||||
add_subdirectory(src/libragephoto)
 | 
			
		||||
 | 
			
		||||
if(WIN32)
 | 
			
		||||
    list(APPEND GTA5VIEW_LIBS
 | 
			
		||||
        dwmapi
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +74,6 @@ set(GTA5VIEW_SOURCES
 | 
			
		|||
    src/ProfileInterface.cpp
 | 
			
		||||
    src/ProfileLoader.cpp
 | 
			
		||||
    src/ProfileWidget.cpp
 | 
			
		||||
    src/RagePhoto.cpp
 | 
			
		||||
    src/SavegameCopy.cpp
 | 
			
		||||
    src/SavegameData.cpp
 | 
			
		||||
    src/SavegameDialog.cpp
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +116,6 @@ set(GTA5VIEW_HEADERS
 | 
			
		|||
    src/ProfileInterface.h
 | 
			
		||||
    src/ProfileLoader.h
 | 
			
		||||
    src/ProfileWidget.h
 | 
			
		||||
    src/RagePhoto.h
 | 
			
		||||
    src/SavegameCopy.h
 | 
			
		||||
    src/SavegameData.h
 | 
			
		||||
    src/SavegameDialog.h
 | 
			
		||||
| 
						 | 
				
			
			@ -360,8 +361,8 @@ if(Qt5Core_VERSION VERSION_GREATER_EQUAL "5.14.0")
 | 
			
		|||
endif()
 | 
			
		||||
 | 
			
		||||
target_compile_definitions(gta5view PRIVATE ${GTA5VIEW_DEFINES})
 | 
			
		||||
target_include_directories(gta5view PRIVATE ${GTA5VIEW_INCLUDEDIR})
 | 
			
		||||
target_link_libraries(gta5view PRIVATE Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Widgets ${GTA5VIEW_LIBS})
 | 
			
		||||
target_include_directories(gta5view PRIVATE ${GTA5VIEW_INCLUDEDIR} ${RAGEPHOTO_INCLUDE_DIRS})
 | 
			
		||||
target_link_libraries(gta5view PRIVATE Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Widgets ragephoto ${GTA5VIEW_LIBS})
 | 
			
		||||
 | 
			
		||||
install(TARGETS gta5view DESTINATION bin)
 | 
			
		||||
install(FILES res/de.syping.gta5view.desktop DESTINATION share/applications)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
 | 
			
		|||
 | 
			
		||||
    # Note: Install Docker Community Edition and Git before continuing
 | 
			
		||||
    docker pull sypingauto/gta5view-build:1.10-static
 | 
			
		||||
    git clone https://gitlab.com/Syping/gta5view
 | 
			
		||||
    git clone --recurse-submodules https://gitlab.com/Syping/gta5view
 | 
			
		||||
    docker run --rm -v "$PWD/gta5view:/gta5view" -it sypingauto/gta5view-build:1.10-static
 | 
			
		||||
    mingw64-qt-cmake -B /gta5view/build /gta5view
 | 
			
		||||
    cmake --build /gta5view/build
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
 | 
			
		|||
#### Build gta5view for Debian/Ubuntu
 | 
			
		||||
 | 
			
		||||
    sudo apt-get install cmake git gcc g++ libqt5svg5-dev make qtbase5-dev qttranslations5-l10n
 | 
			
		||||
    git clone https://gitlab.com/Syping/gta5view
 | 
			
		||||
    git clone --recurse-submodules https://gitlab.com/Syping/gta5view
 | 
			
		||||
    cmake -B gta5view-build gta5view
 | 
			
		||||
    cmake --build gta5view-build
 | 
			
		||||
    sudo cmake --install gta5view-build
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +31,7 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
 | 
			
		|||
#### Build gta5view for Arch/Manjaro
 | 
			
		||||
 | 
			
		||||
    sudo pacman -S cmake gcc git make qt5-base qt5-svg qt5-tools qt5-translations
 | 
			
		||||
    git clone https://gitlab.com/Syping/gta5view
 | 
			
		||||
    git clone --recurse-submodules https://gitlab.com/Syping/gta5view
 | 
			
		||||
    cmake -B gta5view-build gta5view
 | 
			
		||||
    cmake --build gta5view-build
 | 
			
		||||
    sudo cmake --install gta5view-build
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ Open Source Snapmatic and Savegame viewer/editor for GTA V
 | 
			
		|||
#### Build gta5view for Fedora/RHEL
 | 
			
		||||
 | 
			
		||||
    sudo dnf install cmake git gcc gcc-c++ make qt5-qtbase-devel qt5-qtsvg-devel qt5-qttranslations
 | 
			
		||||
    git clone https://gitlab.com/Syping/gta5view
 | 
			
		||||
    git clone --recurse-submodules https://gitlab.com/Syping/gta5view
 | 
			
		||||
    cmake -B gta5view-build gta5view
 | 
			
		||||
    cmake --build gta5view-build
 | 
			
		||||
    sudo cmake --install gta5view-build
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2021 Syping
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -29,11 +29,7 @@ AboutDialog::AboutDialog(QWidget *parent) :
 | 
			
		|||
    ui(new Ui::AboutDialog)
 | 
			
		||||
{
 | 
			
		||||
    // Set Window Flags
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Build Strings
 | 
			
		||||
    QString appVersion = QApplication::applicationVersion();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2021 Syping
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -435,11 +435,7 @@ bool AppEnv::setGameLanguage(GameVersion gameVersion, GameLanguage gameLanguage)
 | 
			
		|||
 | 
			
		||||
qreal AppEnv::screenRatio()
 | 
			
		||||
{
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
    qreal dpi = QApplication::primaryScreen()->logicalDotsPerInch();
 | 
			
		||||
#else
 | 
			
		||||
    qreal dpi = QApplication::desktop()->logicalDpiX();
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef Q_OS_MAC
 | 
			
		||||
    return (dpi / 72);
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -449,9 +445,5 @@ qreal AppEnv::screenRatio()
 | 
			
		|||
 | 
			
		||||
qreal AppEnv::screenRatioPR()
 | 
			
		||||
{
 | 
			
		||||
#if QT_VERSION >= 0x050600
 | 
			
		||||
    return QApplication::primaryScreen()->devicePixelRatio();
 | 
			
		||||
#else
 | 
			
		||||
    return 1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2017-2022 Syping
 | 
			
		||||
* Copyright (C) 2017-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -49,11 +49,7 @@ ImportDialog::ImportDialog(QString profileName, QWidget *parent) :
 | 
			
		|||
    ui(new Ui::ImportDialog)
 | 
			
		||||
{
 | 
			
		||||
    // Set Window Flags
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
    ui->cmdOK->setDefault(true);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2017-2021 Syping
 | 
			
		||||
* Copyright (C) 2017-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -39,12 +39,8 @@ JsonEditorDialog::JsonEditorDialog(SnapmaticPicture *picture, QWidget *parent) :
 | 
			
		|||
    ui(new Ui::JsonEditorDialog)
 | 
			
		||||
{
 | 
			
		||||
    // Set Window Flags
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
    setWindowFlag(Qt::WindowMinMaxButtonsHint, true);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowMinMaxButtonsHint);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
    ui->cmdClose->setDefault(true);
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +190,7 @@ bool JsonEditorDialog::saveJsonContent()
 | 
			
		|||
                QJsonDocument jsonDocument;
 | 
			
		||||
                QJsonObject jsonObject;
 | 
			
		||||
                jsonObject["Type"] = "JSONEdited";
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2017-2021 Syping
 | 
			
		||||
* Copyright (C) 2017-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -29,11 +29,7 @@ MapLocationDialog::MapLocationDialog(double x, double y, QWidget *parent) :
 | 
			
		|||
    ui(new Ui::MapLocationDialog)
 | 
			
		||||
{
 | 
			
		||||
    // Set Window Flags
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
    ui->cmdDone->setVisible(false);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,11 +56,7 @@ OptionsDialog::OptionsDialog(ProfileDatabase *profileDB, QWidget *parent) :
 | 
			
		|||
    ui(new Ui::OptionsDialog)
 | 
			
		||||
{
 | 
			
		||||
    // Set Window Flags
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Setup User Interface
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2021 Syping
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -20,11 +20,9 @@
 | 
			
		|||
#include "PictureWidget.h"
 | 
			
		||||
#include "ProfileDatabase.h"
 | 
			
		||||
#include "ui_PictureDialog.h"
 | 
			
		||||
#include "SidebarGenerator.h"
 | 
			
		||||
#include "MapLocationDialog.h"
 | 
			
		||||
#include "JsonEditorDialog.h"
 | 
			
		||||
#include "SnapmaticEditor.h"
 | 
			
		||||
#include "StandardPaths.h"
 | 
			
		||||
#include "PictureExport.h"
 | 
			
		||||
#include "ImportDialog.h"
 | 
			
		||||
#include "StringParser.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -127,21 +125,8 @@ PictureDialog::PictureDialog(bool primaryWindow, ProfileDatabase *profileDB, Cre
 | 
			
		|||
void PictureDialog::setupPictureDialog()
 | 
			
		||||
{
 | 
			
		||||
    // Set Window Flags
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
    setWindowFlag(Qt::CustomizeWindowHint, true);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint^Qt::CustomizeWindowHint);
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
    // for stupid Window Manager like GNOME
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::Dialog, false);
 | 
			
		||||
    setWindowFlag(Qt::Window, true);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::Dialog^Qt::Window);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Setup User Interface
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
| 
						 | 
				
			
			@ -234,13 +219,6 @@ void PictureDialog::closeEvent(QCloseEvent *ev)
 | 
			
		|||
void PictureDialog::addPreviousNextButtons()
 | 
			
		||||
{
 | 
			
		||||
    QToolBar *uiToolbar = new QToolBar("Picture Toolbar", this);
 | 
			
		||||
#if QT_VERSION < 0x050600
 | 
			
		||||
    qreal screenRatio = AppEnv::screenRatio();
 | 
			
		||||
    if (screenRatio != 1) {
 | 
			
		||||
        QSize iconSize = uiToolbar->iconSize();
 | 
			
		||||
        uiToolbar->setIconSize(QSize(iconSize.width() * screenRatio, iconSize.height() * screenRatio));
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    uiToolbar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
 | 
			
		||||
    uiToolbar->setObjectName("UiToolbar");
 | 
			
		||||
    uiToolbar->addAction(QIcon(AppEnv::getImagesFolder() % "/back.svgz"), "", this, SLOT(previousPictureRequestedSlot()));
 | 
			
		||||
| 
						 | 
				
			
			@ -689,14 +667,8 @@ void PictureDialog::on_labPicture_mouseDoubleClicked(Qt::MouseButton button)
 | 
			
		|||
#endif
 | 
			
		||||
        PictureWidget *pictureWidget = new PictureWidget(this); // Work!
 | 
			
		||||
        pictureWidget->setObjectName("PictureWidget");
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
        pictureWidget->setWindowFlag(Qt::FramelessWindowHint, true);
 | 
			
		||||
        pictureWidget->setWindowFlag(Qt::MaximizeUsingFullscreenGeometryHint, true);
 | 
			
		||||
#elif QT_VERSION >= 0x050600
 | 
			
		||||
        pictureWidget->setWindowFlags(pictureWidget->windowFlags()^Qt::FramelessWindowHint^Qt::MaximizeUsingFullscreenGeometryHint);
 | 
			
		||||
#else
 | 
			
		||||
        pictureWidget->setWindowFlags(pictureWidget->windowFlags()^Qt::FramelessWindowHint);
 | 
			
		||||
#endif
 | 
			
		||||
        pictureWidget->setWindowTitle(windowTitle());
 | 
			
		||||
        pictureWidget->setStyleSheet("QLabel#pictureLabel{background-color:black;}");
 | 
			
		||||
        pictureWidget->setImage(smpic->getImage(), desktopRect);
 | 
			
		||||
| 
						 | 
				
			
			@ -785,7 +757,7 @@ void PictureDialog::openPreviewMap()
 | 
			
		|||
                QJsonObject jsonObject;
 | 
			
		||||
                jsonObject["Type"] = "LocationEdited";
 | 
			
		||||
                jsonObject["ExtraFlags"] = "Viewer";
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(picture->getContentMaxLength());
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(picture->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -863,7 +835,7 @@ void PictureDialog::editSnapmaticImage()
 | 
			
		|||
                QJsonObject jsonObject;
 | 
			
		||||
                jsonObject["Type"] = "ImageEdited";
 | 
			
		||||
                jsonObject["ExtraFlags"] = "Viewer";
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2021 Syping
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,6 @@
 | 
			
		|||
 | 
			
		||||
#include "PlayerListDialog.h"
 | 
			
		||||
#include "ui_PlayerListDialog.h"
 | 
			
		||||
#include "wrapper.h"
 | 
			
		||||
#include "AppEnv.h"
 | 
			
		||||
#include <QStringBuilder>
 | 
			
		||||
#include <QFontMetrics>
 | 
			
		||||
| 
						 | 
				
			
			@ -33,11 +32,7 @@ PlayerListDialog::PlayerListDialog(QStringList players, ProfileDatabase *profile
 | 
			
		|||
    ui(new Ui::PlayerListDialog)
 | 
			
		||||
{
 | 
			
		||||
    // Set Window Flags
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    listUpdated = false;
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,14 +24,12 @@
 | 
			
		|||
#include "DatabaseThread.h"
 | 
			
		||||
#include "SavegameWidget.h"
 | 
			
		||||
#include "PictureDialog.h"
 | 
			
		||||
#include "PictureExport.h"
 | 
			
		||||
#include "StandardPaths.h"
 | 
			
		||||
#include "ProfileLoader.h"
 | 
			
		||||
#include "ExportThread.h"
 | 
			
		||||
#include "ImportDialog.h"
 | 
			
		||||
#include "UiModLabel.h"
 | 
			
		||||
#include "pcg_basic.h"
 | 
			
		||||
#include "wrapper.h"
 | 
			
		||||
#include "AppEnv.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include <QNetworkAccessManager>
 | 
			
		||||
| 
						 | 
				
			
			@ -544,7 +542,7 @@ fileDialogPreOpen: //Work?
 | 
			
		|||
    fileDialog.setViewMode(QFileDialog::Detail);
 | 
			
		||||
    fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
 | 
			
		||||
    fileDialog.setOption(QFileDialog::DontUseNativeDialog, dontUseNativeDialog);
 | 
			
		||||
    fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
    fileDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
    fileDialog.setWindowTitle(tr("Import..."));
 | 
			
		||||
    fileDialog.setLabelText(QFileDialog::Accept, tr("Import..."));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -604,7 +602,8 @@ bool ProfileInterface::importFilesProgress(QStringList selectedFiles)
 | 
			
		|||
 | 
			
		||||
    // Progress dialog
 | 
			
		||||
    QProgressDialog pbDialog(this);
 | 
			
		||||
    pbDialog.setWindowFlags(pbDialog.windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint);
 | 
			
		||||
    pbDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
    pbDialog.setWindowFlag(Qt::WindowCloseButtonHint, false);
 | 
			
		||||
    pbDialog.setWindowTitle(tr("Import..."));
 | 
			
		||||
    pbDialog.setLabelText(tr("Import file %1 of %2 files").arg(QString::number(1), QString::number(maximumId)));
 | 
			
		||||
    pbDialog.setRange(1, maximumId);
 | 
			
		||||
| 
						 | 
				
			
			@ -661,7 +660,7 @@ bool ProfileInterface::importFile(QString selectedFile, QDateTime importDateTime
 | 
			
		|||
                        QJsonDocument jsonDocument;
 | 
			
		||||
                        QJsonObject jsonObject;
 | 
			
		||||
                        jsonObject["Type"] = "ImportSuccess";
 | 
			
		||||
                        jsonObject["ImportSize"] = QString::number(picture->getContentMaxLength());
 | 
			
		||||
                        jsonObject["ImportSize"] = QString::number(picture->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                        jsonObject["ImportTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -873,7 +872,7 @@ bool ProfileInterface::importFile(QString selectedFile, QDateTime importDateTime
 | 
			
		|||
                                    QJsonObject jsonObject;
 | 
			
		||||
                                    jsonObject["Type"] = "ImportSuccess";
 | 
			
		||||
                                    jsonObject["ExtraFlag"] = "Dialog";
 | 
			
		||||
                                    jsonObject["ImportSize"] = QString::number(picture->getContentMaxLength());
 | 
			
		||||
                                    jsonObject["ImportSize"] = QString::number(picture->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                                    jsonObject["ImportTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -920,7 +919,7 @@ bool ProfileInterface::importFile(QString selectedFile, QDateTime importDateTime
 | 
			
		|||
                        QJsonDocument jsonDocument;
 | 
			
		||||
                        QJsonObject jsonObject;
 | 
			
		||||
                        jsonObject["Type"] = "ImportSuccess";
 | 
			
		||||
                        jsonObject["ImportSize"] = QString::number(picture->getContentMaxLength());
 | 
			
		||||
                        jsonObject["ImportSize"] = QString::number(picture->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                        jsonObject["ImportTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -1002,27 +1001,16 @@ bool ProfileInterface::importRemote(QUrl remoteUrl)
 | 
			
		|||
{
 | 
			
		||||
    bool retValue = false;
 | 
			
		||||
    QDialog urlPasteDialog(this);
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
    urlPasteDialog.setObjectName(QStringLiteral("UrlPasteDialog"));
 | 
			
		||||
#else
 | 
			
		||||
    urlPasteDialog.setObjectName(QString::fromUtf8("UrlPasteDialog"));
 | 
			
		||||
#endif
 | 
			
		||||
    urlPasteDialog.setWindowFlags(urlPasteDialog.windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint);
 | 
			
		||||
    urlPasteDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
    urlPasteDialog.setWindowFlag(Qt::WindowCloseButtonHint, false);
 | 
			
		||||
    urlPasteDialog.setWindowTitle(tr("Import..."));
 | 
			
		||||
    urlPasteDialog.setModal(true);
 | 
			
		||||
    QVBoxLayout urlPasteLayout(&urlPasteDialog);
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
    urlPasteLayout.setObjectName(QStringLiteral("UrlPasteLayout"));
 | 
			
		||||
#else
 | 
			
		||||
    urlPasteLayout.setObjectName(QString::fromUtf8("UrlPasteLayout"));
 | 
			
		||||
#endif
 | 
			
		||||
    urlPasteDialog.setLayout(&urlPasteLayout);
 | 
			
		||||
    UiModLabel urlPasteLabel(&urlPasteDialog);
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
    urlPasteLabel.setObjectName(QStringLiteral("UrlPasteLabel"));
 | 
			
		||||
#else
 | 
			
		||||
    urlPasteLabel.setObjectName(QString::fromUtf8("UrlPasteLabel"));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    urlPasteLabel.setText(tr("Prepare Content for Import..."));
 | 
			
		||||
    urlPasteLayout.addWidget(&urlPasteLabel);
 | 
			
		||||
| 
						 | 
				
			
			@ -1401,7 +1389,8 @@ void ProfileInterface::exportSelected()
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            QProgressDialog pbDialog(this);
 | 
			
		||||
            pbDialog.setWindowFlags(pbDialog.windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint);
 | 
			
		||||
            pbDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
            pbDialog.setWindowFlag(Qt::WindowCloseButtonHint, false);
 | 
			
		||||
            pbDialog.setWindowTitle(tr("Export selected..."));
 | 
			
		||||
            pbDialog.setLabelText(tr("Initialising export..."));
 | 
			
		||||
            pbDialog.setRange(0, exportCount);
 | 
			
		||||
| 
						 | 
				
			
			@ -2030,7 +2019,8 @@ void ProfileInterface::massTool(MassTool tool)
 | 
			
		|||
        int overallId = 0;
 | 
			
		||||
 | 
			
		||||
        QProgressDialog pbDialog(this);
 | 
			
		||||
        pbDialog.setWindowFlags(pbDialog.windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint);
 | 
			
		||||
        pbDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
        pbDialog.setWindowFlag(Qt::WindowCloseButtonHint, false);
 | 
			
		||||
        pbDialog.setWindowTitle(tr("Patch selected..."));
 | 
			
		||||
        pbDialog.setLabelText(tr("Patch file %1 of %2 files").arg(QString::number(1), QString::number(maximumId)));
 | 
			
		||||
        pbDialog.setRange(1, maximumId);
 | 
			
		||||
| 
						 | 
				
			
			@ -2123,7 +2113,8 @@ void ProfileInterface::massTool(MassTool tool)
 | 
			
		|||
        int overallId = 0;
 | 
			
		||||
 | 
			
		||||
        QProgressDialog pbDialog(this);
 | 
			
		||||
        pbDialog.setWindowFlags(pbDialog.windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint);
 | 
			
		||||
        pbDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
        pbDialog.setWindowFlag(Qt::WindowCloseButtonHint, false);
 | 
			
		||||
        pbDialog.setWindowTitle(tr("Patch selected..."));
 | 
			
		||||
        pbDialog.setLabelText(tr("Patch file %1 of %2 files").arg(QString::number(1), QString::number(maximumId)));
 | 
			
		||||
        pbDialog.setRange(1, maximumId);
 | 
			
		||||
| 
						 | 
				
			
			@ -2238,7 +2229,8 @@ preSelectionCrewID:
 | 
			
		|||
        int overallId = 0;
 | 
			
		||||
 | 
			
		||||
        QProgressDialog pbDialog(this);
 | 
			
		||||
        pbDialog.setWindowFlags(pbDialog.windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint);
 | 
			
		||||
        pbDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
        pbDialog.setWindowFlag(Qt::WindowCloseButtonHint, false);
 | 
			
		||||
        pbDialog.setWindowTitle(tr("Patch selected..."));
 | 
			
		||||
        pbDialog.setLabelText(tr("Patch file %1 of %2 files").arg(QString::number(1), QString::number(maximumId)));
 | 
			
		||||
        pbDialog.setRange(1, maximumId);
 | 
			
		||||
| 
						 | 
				
			
			@ -2333,7 +2325,8 @@ preSelectionTitle:
 | 
			
		|||
        int overallId = 0;
 | 
			
		||||
 | 
			
		||||
        QProgressDialog pbDialog(this);
 | 
			
		||||
        pbDialog.setWindowFlags(pbDialog.windowFlags()^Qt::WindowContextHelpButtonHint^Qt::WindowCloseButtonHint);
 | 
			
		||||
        pbDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
        pbDialog.setWindowFlag(Qt::WindowCloseButtonHint, false);
 | 
			
		||||
        pbDialog.setWindowTitle(tr("Patch selected..."));
 | 
			
		||||
        pbDialog.setLabelText(tr("Patch file %1 of %2 files").arg(QString::number(overallId), QString::number(maximumId)));
 | 
			
		||||
        pbDialog.setRange(1, maximumId);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,865 +0,0 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2020-2022 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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 "RagePhoto.h"
 | 
			
		||||
#include <QJsonDocument>
 | 
			
		||||
#include <QBuffer>
 | 
			
		||||
#include <QFile>
 | 
			
		||||
#if QT_VERSION < 0x060000
 | 
			
		||||
#include <QTextCodec>
 | 
			
		||||
#else
 | 
			
		||||
#include <QStringEncoder>
 | 
			
		||||
#include <QStringDecoder>
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef RAGEPHOTO_BENCHMARK
 | 
			
		||||
#include <QFileInfo>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
RagePhoto::RagePhoto()
 | 
			
		||||
{
 | 
			
		||||
    p_photoFormat = PhotoFormat::Undefined;
 | 
			
		||||
    p_isLoaded = false;
 | 
			
		||||
    p_inputMode = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RagePhoto::RagePhoto(const QByteArray &data) : p_fileData(data)
 | 
			
		||||
{
 | 
			
		||||
    p_photoFormat = PhotoFormat::Undefined;
 | 
			
		||||
    p_isLoaded = false;
 | 
			
		||||
    p_inputMode = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RagePhoto::RagePhoto(const QString &filePath) : p_filePath(filePath)
 | 
			
		||||
{
 | 
			
		||||
    p_photoFormat = PhotoFormat::Undefined;
 | 
			
		||||
    p_isLoaded = false;
 | 
			
		||||
    p_inputMode = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RagePhoto::RagePhoto(QIODevice *ioDevice) : p_ioDevice(ioDevice)
 | 
			
		||||
{
 | 
			
		||||
    p_photoFormat = PhotoFormat::Undefined;
 | 
			
		||||
    p_isLoaded = false;
 | 
			
		||||
    p_inputMode = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RagePhoto::isLoaded()
 | 
			
		||||
{
 | 
			
		||||
    return p_isLoaded;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RagePhoto::load()
 | 
			
		||||
{
 | 
			
		||||
    if (p_inputMode == -1)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (p_isLoaded)
 | 
			
		||||
        clear();
 | 
			
		||||
 | 
			
		||||
    if (p_inputMode == 1) {
 | 
			
		||||
        QFile pictureFile(p_filePath);
 | 
			
		||||
        if (pictureFile.open(QIODevice::ReadOnly)) {
 | 
			
		||||
            p_fileData = pictureFile.readAll();
 | 
			
		||||
        }
 | 
			
		||||
        pictureFile.close();
 | 
			
		||||
    }
 | 
			
		||||
    else if (p_inputMode == 2) {
 | 
			
		||||
        if (!p_ioDevice->isOpen()) {
 | 
			
		||||
            if (!p_ioDevice->open(QIODevice::ReadOnly))
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
        p_fileData = p_ioDevice->readAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QBuffer dataBuffer(&p_fileData);
 | 
			
		||||
    dataBuffer.open(QIODevice::ReadOnly);
 | 
			
		||||
 | 
			
		||||
#ifdef RAGEPHOTO_BENCHMARK
 | 
			
		||||
    auto benchmark_parse_start = std::chrono::high_resolution_clock::now();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    char uInt32Buffer[4];
 | 
			
		||||
    qint64 size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
    if (size != 4)
 | 
			
		||||
        return false;
 | 
			
		||||
    quint32 format = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
    if (format == static_cast<quint32>(PhotoFormat::GTA5)) {
 | 
			
		||||
        char photoHeader[256];
 | 
			
		||||
        size = dataBuffer.read(photoHeader, 256);
 | 
			
		||||
        if (size != 256) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        for (const QChar &photoChar : utf16LEToString(photoHeader, 256)) {
 | 
			
		||||
            if (photoChar.isNull())
 | 
			
		||||
                break;
 | 
			
		||||
            p_photoString += photoChar;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_headerSum = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_endOfFile = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_jsonOffset = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_titlOffset = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_descOffset = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char markerBuffer[4];
 | 
			
		||||
        size = dataBuffer.read(markerBuffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (strncmp(markerBuffer, "JPEG", 4) != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_photoBuffer = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        quint32 t_photoSize = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *photoData = static_cast<char*>(malloc(t_photoSize));
 | 
			
		||||
        if (!photoData)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(photoData, t_photoSize);
 | 
			
		||||
        if (size != t_photoSize) {
 | 
			
		||||
            free(photoData);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        p_photoData = QByteArray(photoData, t_photoSize);
 | 
			
		||||
        free(photoData);
 | 
			
		||||
 | 
			
		||||
        dataBuffer.seek(p_jsonOffset + 264);
 | 
			
		||||
        size = dataBuffer.read(markerBuffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (strncmp(markerBuffer, "JSON", 4) != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_jsonBuffer = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *jsonBytes = static_cast<char*>(malloc(p_jsonBuffer));
 | 
			
		||||
        if (!jsonBytes)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(jsonBytes, p_jsonBuffer);
 | 
			
		||||
        if (size != p_jsonBuffer) {
 | 
			
		||||
            free(jsonBytes);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        quint32 i;
 | 
			
		||||
        for (i = 0; i != p_jsonBuffer; i++) {
 | 
			
		||||
            if (jsonBytes[i] == '\x00')
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        p_jsonData = QByteArray(jsonBytes, i);
 | 
			
		||||
        free(jsonBytes);
 | 
			
		||||
        QJsonDocument t_jsonDocument = QJsonDocument::fromJson(p_jsonData);
 | 
			
		||||
        if (t_jsonDocument.isNull())
 | 
			
		||||
            return false;
 | 
			
		||||
        p_jsonObject = t_jsonDocument.object();
 | 
			
		||||
 | 
			
		||||
        dataBuffer.seek(p_titlOffset + 264);
 | 
			
		||||
        size = dataBuffer.read(markerBuffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (strncmp(markerBuffer, "TITL", 4) != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_titlBuffer = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *titlBytes = static_cast<char*>(malloc(p_titlBuffer));
 | 
			
		||||
        if (!titlBytes)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(titlBytes, p_titlBuffer);
 | 
			
		||||
        if (size != p_titlBuffer){
 | 
			
		||||
            free(titlBytes);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        for (i = 0; i != p_titlBuffer; i++) {
 | 
			
		||||
            if (titlBytes[i] == '\x00')
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        p_titleString = QString::fromUtf8(titlBytes, i);
 | 
			
		||||
        free(titlBytes);
 | 
			
		||||
 | 
			
		||||
        dataBuffer.seek(p_descOffset + 264);
 | 
			
		||||
        size = dataBuffer.read(markerBuffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (strncmp(markerBuffer, "DESC", 4) != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        p_descBuffer = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *descBytes = static_cast<char*>(malloc(p_descBuffer));
 | 
			
		||||
        if (!descBytes)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(descBytes, p_descBuffer);
 | 
			
		||||
        if (size != p_descBuffer) {
 | 
			
		||||
            free(descBytes);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        for (i = 0; i != p_descBuffer; i++) {
 | 
			
		||||
            if (descBytes[i] == '\x00')
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        p_descriptionString = QString::fromUtf8(descBytes, i);
 | 
			
		||||
        free(descBytes);
 | 
			
		||||
 | 
			
		||||
        dataBuffer.seek(p_endOfFile + 260);
 | 
			
		||||
        size = dataBuffer.read(markerBuffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        if (strncmp(markerBuffer, "JEND", 4) != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
#ifdef RAGEPHOTO_BENCHMARK
 | 
			
		||||
        auto benchmark_parse_end = std::chrono::high_resolution_clock::now();
 | 
			
		||||
        auto benchmark_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark_parse_end - benchmark_parse_start);
 | 
			
		||||
        if (p_inputMode == 1) {
 | 
			
		||||
            QTextStream(stdout) << QFileInfo(p_filePath).fileName() << ": " << benchmark_ns.count() << "ns" << Qt::endl;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            QTextStream(stdout) << "PGTA5" << p_jsonObject.value("uid").toInt() << ": " << benchmark_ns.count() << "ns" << Qt::endl;
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        if (p_photoFormat != PhotoFormat::G5EX)
 | 
			
		||||
            p_photoFormat = PhotoFormat::GTA5;
 | 
			
		||||
 | 
			
		||||
        p_fileData.clear();
 | 
			
		||||
        p_isLoaded = true;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (format == static_cast<quint32>(PhotoFormat::G5EX)) {
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        format = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
        if (format == static_cast<quint32>(ExportFormat::G5E3P)) {
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            quint32 compressedSize = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            char *compressedPhotoHeader = static_cast<char*>(malloc(compressedSize));
 | 
			
		||||
            if (!compressedPhotoHeader)
 | 
			
		||||
                return false;
 | 
			
		||||
            size = dataBuffer.read(compressedPhotoHeader, compressedSize);
 | 
			
		||||
            if (size != compressedSize) {
 | 
			
		||||
                free(compressedPhotoHeader);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            QByteArray t_photoHeader = QByteArray::fromRawData(compressedPhotoHeader, compressedSize);
 | 
			
		||||
            t_photoHeader = qUncompress(t_photoHeader);
 | 
			
		||||
            free(compressedPhotoHeader);
 | 
			
		||||
            if (t_photoHeader.isEmpty())
 | 
			
		||||
                return false;
 | 
			
		||||
            p_photoString = QString::fromUtf8(t_photoHeader);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_headerSum = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_photoBuffer = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            compressedSize = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            char *compressedPhoto = static_cast<char*>(malloc(compressedSize));
 | 
			
		||||
            if (!compressedPhoto)
 | 
			
		||||
                return false;
 | 
			
		||||
            size = dataBuffer.read(compressedPhoto, compressedSize);
 | 
			
		||||
            if (size != compressedSize) {
 | 
			
		||||
                free(compressedPhoto);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            QByteArray t_photoData = QByteArray::fromRawData(compressedPhoto, compressedSize);
 | 
			
		||||
            p_photoData = qUncompress(t_photoData);
 | 
			
		||||
            free(compressedPhoto);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_jsonOffset = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_jsonBuffer = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            compressedSize = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            char *compressedJson = static_cast<char*>(malloc(compressedSize));
 | 
			
		||||
            if (!compressedJson)
 | 
			
		||||
                return false;
 | 
			
		||||
            size = dataBuffer.read(compressedJson, compressedSize);
 | 
			
		||||
            if (size != compressedSize) {
 | 
			
		||||
                free(compressedJson);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            QByteArray t_jsonBytes = QByteArray::fromRawData(compressedJson, compressedSize);
 | 
			
		||||
            p_jsonData = qUncompress(t_jsonBytes);
 | 
			
		||||
            free(compressedJson);
 | 
			
		||||
            if (p_jsonData.isEmpty())
 | 
			
		||||
                return false;
 | 
			
		||||
            QJsonDocument t_jsonDocument = QJsonDocument::fromJson(p_jsonData);
 | 
			
		||||
            if (t_jsonDocument.isNull())
 | 
			
		||||
                return false;
 | 
			
		||||
            p_jsonObject = t_jsonDocument.object();
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_titlOffset = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_titlBuffer = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            compressedSize = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            char *compressedTitl = static_cast<char*>(malloc(compressedSize));
 | 
			
		||||
            if (!compressedTitl)
 | 
			
		||||
                return false;
 | 
			
		||||
            size = dataBuffer.read(compressedTitl, compressedSize);
 | 
			
		||||
            if (size != compressedSize) {
 | 
			
		||||
                free(compressedTitl);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            QByteArray t_titlBytes = QByteArray::fromRawData(compressedTitl, compressedSize);
 | 
			
		||||
            t_titlBytes = qUncompress(t_titlBytes);
 | 
			
		||||
            free(compressedTitl);
 | 
			
		||||
            p_titleString = QString::fromUtf8(t_titlBytes);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_descOffset = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_descBuffer = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            compressedSize = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
            char *compressedDesc = static_cast<char*>(malloc(compressedSize));
 | 
			
		||||
            if (!compressedDesc)
 | 
			
		||||
                return false;
 | 
			
		||||
            size = dataBuffer.read(compressedDesc, compressedSize);
 | 
			
		||||
            if (size != compressedSize) {
 | 
			
		||||
                free(compressedDesc);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            QByteArray t_descBytes = QByteArray::fromRawData(compressedDesc, compressedSize);
 | 
			
		||||
            t_descBytes = qUncompress(t_descBytes);
 | 
			
		||||
            free(compressedDesc);
 | 
			
		||||
            p_descriptionString = QString::fromUtf8(t_descBytes);
 | 
			
		||||
 | 
			
		||||
            size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
            if (size != 4)
 | 
			
		||||
                return false;
 | 
			
		||||
            p_endOfFile = charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
#ifdef RAGEPHOTO_BENCHMARK
 | 
			
		||||
            auto benchmark_parse_end = std::chrono::high_resolution_clock::now();
 | 
			
		||||
            auto benchmark_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark_parse_end - benchmark_parse_start);
 | 
			
		||||
            if (p_inputMode == 1) {
 | 
			
		||||
                QTextStream(stdout) << QFileInfo(p_filePath).fileName() << ": " << benchmark_ns.count() << "ns" << Qt::endl;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                QTextStream(stdout) << "PGTA5" << p_jsonObject.value("uid").toInt() << ": " << benchmark_ns.count() << "ns" << Qt::endl;
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            p_photoFormat = PhotoFormat::G5EX;
 | 
			
		||||
 | 
			
		||||
            p_fileData.clear();
 | 
			
		||||
            p_isLoaded = true;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else if (format == static_cast<quint32>(ExportFormat::G5E2P)) {
 | 
			
		||||
            p_photoFormat = PhotoFormat::G5EX;
 | 
			
		||||
            p_fileData = qUncompress(dataBuffer.readAll());
 | 
			
		||||
            if (p_fileData.isEmpty())
 | 
			
		||||
                return false;
 | 
			
		||||
            p_inputMode = 0;
 | 
			
		||||
            return load();
 | 
			
		||||
        }
 | 
			
		||||
        else if (format == static_cast<quint32>(ExportFormat::G5E1P)) {
 | 
			
		||||
#if QT_VERSION >= 0x050A00
 | 
			
		||||
            size = dataBuffer.skip(1);
 | 
			
		||||
            if (size != 1)
 | 
			
		||||
                return false;
 | 
			
		||||
#else
 | 
			
		||||
            if (!dataBuffer.seek(dataBuffer.pos() + 1))
 | 
			
		||||
                return false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            char length[1];
 | 
			
		||||
            size = dataBuffer.read(length, 1);
 | 
			
		||||
            if (size != 1)
 | 
			
		||||
                return false;
 | 
			
		||||
            int i_length = QByteArray::number(static_cast<int>(length[0]), 16).toInt() + 6;
 | 
			
		||||
 | 
			
		||||
#if QT_VERSION >= 0x050A00
 | 
			
		||||
            size = dataBuffer.skip(i_length);
 | 
			
		||||
            if (size != i_length)
 | 
			
		||||
                return false;
 | 
			
		||||
#else
 | 
			
		||||
            if (!dataBuffer.seek(dataBuffer.pos() + i_length))
 | 
			
		||||
                return false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            p_photoFormat = PhotoFormat::G5EX;
 | 
			
		||||
            p_fileData = qUncompress(dataBuffer.readAll());
 | 
			
		||||
            if (p_fileData.isEmpty())
 | 
			
		||||
                return false;
 | 
			
		||||
            p_inputMode = 0;
 | 
			
		||||
            return load();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::clear()
 | 
			
		||||
{
 | 
			
		||||
    p_photoFormat = PhotoFormat::Undefined;
 | 
			
		||||
    p_jsonObject = QJsonObject();
 | 
			
		||||
    p_descriptionString.clear();
 | 
			
		||||
    p_jsonData.clear();
 | 
			
		||||
    p_photoData.clear();
 | 
			
		||||
    p_photoString.clear();
 | 
			
		||||
    p_titleString.clear();
 | 
			
		||||
    p_headerSum = 0;
 | 
			
		||||
    p_isLoaded = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::setDescription(const QString &description)
 | 
			
		||||
{
 | 
			
		||||
    p_descriptionString = description;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::setFileData(const QByteArray &data)
 | 
			
		||||
{
 | 
			
		||||
    p_fileData = data;
 | 
			
		||||
    p_inputMode = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::setFilePath(const QString &filePath)
 | 
			
		||||
{
 | 
			
		||||
    p_filePath = filePath;
 | 
			
		||||
    p_inputMode = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::setIODevice(QIODevice *ioDevice)
 | 
			
		||||
{
 | 
			
		||||
    p_ioDevice = ioDevice;
 | 
			
		||||
    p_inputMode = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RagePhoto::setJsonData(const QByteArray &data)
 | 
			
		||||
{
 | 
			
		||||
    QJsonDocument t_jsonDocument = QJsonDocument::fromJson(data);
 | 
			
		||||
    if (t_jsonDocument.isNull())
 | 
			
		||||
        return false;
 | 
			
		||||
    p_jsonData = t_jsonDocument.toJson(QJsonDocument::Compact);
 | 
			
		||||
    p_jsonObject = t_jsonDocument.object();
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RagePhoto::setPhotoBuffer(quint32 size, bool moveOffsets)
 | 
			
		||||
{
 | 
			
		||||
    if (size < static_cast<quint32>(p_photoData.size()))
 | 
			
		||||
        return false;
 | 
			
		||||
    p_photoBuffer = size;
 | 
			
		||||
    if (moveOffsets) {
 | 
			
		||||
        p_jsonOffset = size + 28;
 | 
			
		||||
        p_titlOffset = p_jsonOffset + p_jsonBuffer + 8;
 | 
			
		||||
        p_descOffset = p_titlOffset + p_titlBuffer + 8;
 | 
			
		||||
        p_endOfFile = p_descOffset + p_descBuffer + 12;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RagePhoto::setPhotoData(const QByteArray &data)
 | 
			
		||||
{
 | 
			
		||||
    quint32 size = data.size();
 | 
			
		||||
    if (size > p_photoBuffer)
 | 
			
		||||
        return false;
 | 
			
		||||
    p_photoData = data;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RagePhoto::setPhotoData(const char *data, int size)
 | 
			
		||||
{
 | 
			
		||||
    if (static_cast<quint32>(size) > p_photoBuffer)
 | 
			
		||||
        return false;
 | 
			
		||||
    p_photoData = QByteArray(data, size);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::setPhotoFormat(PhotoFormat photoFormat)
 | 
			
		||||
{
 | 
			
		||||
    p_photoFormat = photoFormat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::setTitle(const QString &title)
 | 
			
		||||
{
 | 
			
		||||
    p_titleString = title;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QByteArray RagePhoto::jsonData(JsonFormat jsonFormat)
 | 
			
		||||
{
 | 
			
		||||
    if (jsonFormat == JsonFormat::Compact) {
 | 
			
		||||
        return QJsonDocument(p_jsonObject).toJson(QJsonDocument::Compact);
 | 
			
		||||
    }
 | 
			
		||||
    else if (jsonFormat == JsonFormat::Indented) {
 | 
			
		||||
        return QJsonDocument(p_jsonObject).toJson(QJsonDocument::Indented);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        return p_jsonData;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QJsonObject RagePhoto::jsonObject()
 | 
			
		||||
{
 | 
			
		||||
    return p_jsonObject;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QByteArray RagePhoto::photoData()
 | 
			
		||||
{
 | 
			
		||||
    return p_photoData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QString RagePhoto::description()
 | 
			
		||||
{
 | 
			
		||||
    return p_descriptionString;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QString RagePhoto::photoString()
 | 
			
		||||
{
 | 
			
		||||
    return p_photoString;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QString RagePhoto::title()
 | 
			
		||||
{
 | 
			
		||||
    return p_titleString;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
quint32 RagePhoto::photoBuffer()
 | 
			
		||||
{
 | 
			
		||||
    return p_photoBuffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
quint32 RagePhoto::photoSize()
 | 
			
		||||
{
 | 
			
		||||
    return p_photoData.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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::G5EX) {
 | 
			
		||||
        char uInt32Buffer[4];
 | 
			
		||||
        quint32 format = static_cast<quint32>(PhotoFormat::G5EX);
 | 
			
		||||
        uInt32ToCharLE(format, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
        format = static_cast<quint32>(ExportFormat::G5E3P);
 | 
			
		||||
        uInt32ToCharLE(format, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        QByteArray compressedData = qCompress(p_photoString.toUtf8(), 9);
 | 
			
		||||
        quint32 compressedSize = compressedData.size();
 | 
			
		||||
        uInt32ToCharLE(compressedSize, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
        ioDevice->write(compressedData);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_headerSum, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_photoBuffer, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        compressedData = qCompress(p_photoData, 9);
 | 
			
		||||
        compressedSize = compressedData.size();
 | 
			
		||||
        uInt32ToCharLE(compressedSize, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
        ioDevice->write(compressedData);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_jsonOffset, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_jsonBuffer, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        compressedData = qCompress(p_jsonData, 9);
 | 
			
		||||
        compressedSize = compressedData.size();
 | 
			
		||||
        uInt32ToCharLE(compressedSize, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
        ioDevice->write(compressedData);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_titlOffset, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_titlBuffer, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        compressedData = qCompress(p_titleString.toUtf8(), 9);
 | 
			
		||||
        compressedSize = compressedData.size();
 | 
			
		||||
        uInt32ToCharLE(compressedSize, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
        ioDevice->write(compressedData);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_descOffset, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_descBuffer, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        compressedData = qCompress(p_descriptionString.toUtf8(), 9);
 | 
			
		||||
        compressedSize = compressedData.size();
 | 
			
		||||
        uInt32ToCharLE(compressedSize, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
        ioDevice->write(compressedData);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_endOfFile, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
    }
 | 
			
		||||
    else if (photoFormat == PhotoFormat::GTA5) {
 | 
			
		||||
        char uInt32Buffer[4];
 | 
			
		||||
        quint32 format = static_cast<quint32>(PhotoFormat::GTA5);
 | 
			
		||||
        uInt32ToCharLE(format, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        QByteArray photoHeader = stringToUtf16LE(p_photoString);
 | 
			
		||||
        if (photoHeader.startsWith("\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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_headerSum, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_endOfFile, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_jsonOffset, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_titlOffset, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_descOffset, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        ioDevice->write("JPEG", 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_photoBuffer, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        quint32 t_photoSize = p_photoData.size();
 | 
			
		||||
        uInt32ToCharLE(t_photoSize, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        ioDevice->write(p_photoData);
 | 
			
		||||
        for (qint64 size = t_photoSize; size < p_photoBuffer; size++) {
 | 
			
		||||
            ioDevice->write("\x00", 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ioDevice->seek(p_jsonOffset + 264);
 | 
			
		||||
        ioDevice->write("JSON", 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_jsonBuffer, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        qint64 dataSize = p_jsonData.size();
 | 
			
		||||
        ioDevice->write(p_jsonData);
 | 
			
		||||
        for (qint64 size = dataSize; size < p_jsonBuffer; size++) {
 | 
			
		||||
            ioDevice->write("\x00", 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ioDevice->seek(p_titlOffset + 264);
 | 
			
		||||
        ioDevice->write("TITL", 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_titlBuffer, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        QByteArray data = p_titleString.toUtf8();
 | 
			
		||||
        dataSize = data.size();
 | 
			
		||||
        ioDevice->write(data);
 | 
			
		||||
        for (qint64 size = dataSize; size < p_titlBuffer; size++) {
 | 
			
		||||
            ioDevice->write("\x00", 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ioDevice->seek(p_descOffset + 264);
 | 
			
		||||
        ioDevice->write("DESC", 4);
 | 
			
		||||
 | 
			
		||||
        uInt32ToCharLE(p_descBuffer, uInt32Buffer);
 | 
			
		||||
        ioDevice->write(uInt32Buffer, 4);
 | 
			
		||||
 | 
			
		||||
        data = p_descriptionString.toUtf8();
 | 
			
		||||
        dataSize = data.size();
 | 
			
		||||
        ioDevice->write(data);
 | 
			
		||||
        for (qint64 size = dataSize; size < p_descBuffer; size++) {
 | 
			
		||||
            ioDevice->write("\x00", 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ioDevice->seek(p_endOfFile + 260);
 | 
			
		||||
        ioDevice->write("JEND", 4);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RagePhoto* RagePhoto::loadFile(const QString &filePath)
 | 
			
		||||
{
 | 
			
		||||
    RagePhoto *ragePhoto = new RagePhoto(filePath);
 | 
			
		||||
    ragePhoto->load();
 | 
			
		||||
    return ragePhoto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
quint32 RagePhoto::charToUInt32BE(char *x)
 | 
			
		||||
{
 | 
			
		||||
    return (static_cast<unsigned char>(x[0]) << 24 |
 | 
			
		||||
            static_cast<unsigned char>(x[1]) << 16 |
 | 
			
		||||
            static_cast<unsigned char>(x[2]) << 8 |
 | 
			
		||||
            static_cast<unsigned char>(x[3]));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
quint32 RagePhoto::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]));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::uInt32ToCharBE(quint32 x, char *y)
 | 
			
		||||
{
 | 
			
		||||
    y[0] = x >> 24;
 | 
			
		||||
    y[1] = x >> 16;
 | 
			
		||||
    y[2] = x >> 8;
 | 
			
		||||
    y[3] = x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RagePhoto::uInt32ToCharLE(quint32 x, char *y)
 | 
			
		||||
{
 | 
			
		||||
    y[0] = x;
 | 
			
		||||
    y[1] = x >> 8;
 | 
			
		||||
    y[2] = x >> 16;
 | 
			
		||||
    y[3] = x >> 24;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QByteArray RagePhoto::stringToUtf16LE(const QString &string)
 | 
			
		||||
{
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
    return QStringEncoder(QStringEncoder::Utf16LE)(string);
 | 
			
		||||
#else
 | 
			
		||||
    return QTextCodec::codecForName("UTF-16LE")->fromUnicode(string);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QString RagePhoto::utf16LEToString(const QByteArray &data)
 | 
			
		||||
{
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
    return QStringDecoder(QStringDecoder::Utf16LE)(data);
 | 
			
		||||
#else
 | 
			
		||||
    return QTextCodec::codecForName("UTF-16LE")->toUnicode(data);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const QString RagePhoto::utf16LEToString(const char *data, int size)
 | 
			
		||||
{
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
    return QStringDecoder(QStringDecoder::Utf16LE)(QByteArray::fromRawData(data, size));
 | 
			
		||||
#else
 | 
			
		||||
    return QTextCodec::codecForName("UTF-16LE")->toUnicode(data, size);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										110
									
								
								src/RagePhoto.h
									
										
									
									
									
								
							
							
						
						
									
										110
									
								
								src/RagePhoto.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,110 +0,0 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2020 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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/>.
 | 
			
		||||
*****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef RAGEPHOTO_H
 | 
			
		||||
#define RAGEPHOTO_H
 | 
			
		||||
 | 
			
		||||
#include <QJsonObject>
 | 
			
		||||
#include <QIODevice>
 | 
			
		||||
#include <QObject>
 | 
			
		||||
 | 
			
		||||
class RagePhoto : public QObject
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
public:
 | 
			
		||||
    enum class JsonFormat : quint8 {
 | 
			
		||||
        Original = 0,
 | 
			
		||||
        Compact = 1,
 | 
			
		||||
        Indented = 2,
 | 
			
		||||
    };
 | 
			
		||||
    enum class ExportFormat : quint32 {
 | 
			
		||||
        G5E1P = 0x454C0010U,
 | 
			
		||||
        G5E2P = 0x01000032U,
 | 
			
		||||
        G5E2S = 0x02000032U,
 | 
			
		||||
        G5E3P = 0x01000033U,
 | 
			
		||||
        G5E3S = 0x02000033U,
 | 
			
		||||
        Undefined = 0,
 | 
			
		||||
    };
 | 
			
		||||
    enum class PhotoFormat : quint32 {
 | 
			
		||||
        G5EX = 0x45354700U,
 | 
			
		||||
        GTA5 = 0x01000000U,
 | 
			
		||||
        RDR2 = 0x04000000U,
 | 
			
		||||
        Undefined = 0,
 | 
			
		||||
    };
 | 
			
		||||
    explicit RagePhoto();
 | 
			
		||||
    explicit RagePhoto(const QByteArray &data);
 | 
			
		||||
    explicit RagePhoto(const QString &filePath);
 | 
			
		||||
    explicit RagePhoto(QIODevice *ioDevice);
 | 
			
		||||
    bool isLoaded();
 | 
			
		||||
    bool load();
 | 
			
		||||
    void clear();
 | 
			
		||||
    void setDescription(const QString &description);
 | 
			
		||||
    void setFileData(const QByteArray &data);
 | 
			
		||||
    void setFilePath(const QString &filePath);
 | 
			
		||||
    void setIODevice(QIODevice *ioDevice);
 | 
			
		||||
    bool setJsonData(const QByteArray &data);
 | 
			
		||||
    bool setPhotoBuffer(quint32 size, bool moveOffsets = true);
 | 
			
		||||
    bool setPhotoData(const QByteArray &data);
 | 
			
		||||
    bool setPhotoData(const char *data, int size);
 | 
			
		||||
    void setPhotoFormat(PhotoFormat photoFormat);
 | 
			
		||||
    void setTitle(const QString &title);
 | 
			
		||||
    const QJsonObject jsonObject();
 | 
			
		||||
    const QByteArray jsonData(JsonFormat jsonFormat = JsonFormat::Original);
 | 
			
		||||
    const QByteArray photoData();
 | 
			
		||||
    const QString description();
 | 
			
		||||
    const QString photoString();
 | 
			
		||||
    const QString title();
 | 
			
		||||
    quint32 photoBuffer();
 | 
			
		||||
    quint32 photoSize();
 | 
			
		||||
    PhotoFormat photoFormat();
 | 
			
		||||
    QByteArray save(PhotoFormat photoFormat);
 | 
			
		||||
    void save(QIODevice *ioDevice, PhotoFormat photoFormat);
 | 
			
		||||
    static RagePhoto* loadFile(const QString &filePath);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    inline quint32 charToUInt32BE(char *x);
 | 
			
		||||
    inline quint32 charToUInt32LE(char *x);
 | 
			
		||||
    inline void uInt32ToCharBE(quint32 x, char *y);
 | 
			
		||||
    inline void uInt32ToCharLE(quint32 x, char *y);
 | 
			
		||||
    inline const QByteArray stringToUtf16LE(const QString &string);
 | 
			
		||||
    inline const QString utf16LEToString(const QByteArray &data);
 | 
			
		||||
    inline const QString utf16LEToString(const char *data, int size);
 | 
			
		||||
    PhotoFormat p_photoFormat;
 | 
			
		||||
    QJsonObject p_jsonObject;
 | 
			
		||||
    QByteArray p_fileData;
 | 
			
		||||
    QByteArray p_jsonData;
 | 
			
		||||
    QByteArray p_photoData;
 | 
			
		||||
    QIODevice *p_ioDevice;
 | 
			
		||||
    QString p_descriptionString;
 | 
			
		||||
    QString p_filePath;
 | 
			
		||||
    QString p_photoString;
 | 
			
		||||
    QString p_titleString;
 | 
			
		||||
    quint32 p_descBuffer;
 | 
			
		||||
    quint32 p_descOffset;
 | 
			
		||||
    quint32 p_endOfFile;
 | 
			
		||||
    quint32 p_headerSum;
 | 
			
		||||
    quint32 p_jsonBuffer;
 | 
			
		||||
    quint32 p_jsonOffset;
 | 
			
		||||
    quint32 p_photoBuffer;
 | 
			
		||||
    quint32 p_titlBuffer;
 | 
			
		||||
    quint32 p_titlOffset;
 | 
			
		||||
    bool p_isLoaded;
 | 
			
		||||
    int p_inputMode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // RAGEPHOTO_H
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,6 @@
 | 
			
		|||
*****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "SnapmaticPicture.h"
 | 
			
		||||
#include "StringParser.h"
 | 
			
		||||
#include "SavegameData.h"
 | 
			
		||||
#include <QStringBuilder>
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +77,7 @@ QString SavegameData::getSavegameDataString(const QByteArray &savegameHeader)
 | 
			
		|||
    QList<QByteArray> savegameBytesList = savegameBytes.split(char(0x01));
 | 
			
		||||
    savegameBytes = savegameBytesList.at(1);
 | 
			
		||||
    savegameBytesList.clear();
 | 
			
		||||
    return SnapmaticPicture::parseTitleString(savegameBytes, savegameBytes.length());
 | 
			
		||||
    return SnapmaticPicture::parseTitleString(savegameBytes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SavegameData::readingSavegameFromFile(const QString &fileName)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2018 Syping
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -28,11 +28,7 @@ SavegameDialog::SavegameDialog(QWidget *parent) :
 | 
			
		|||
    ui(new Ui::SavegameDialog)
 | 
			
		||||
{
 | 
			
		||||
    // Set Window Flags
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
    setWindowFlags(windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Setup User Interface
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -315,7 +315,7 @@ void SnapmaticEditor::on_cmdApply_clicked()
 | 
			
		|||
                QJsonDocument jsonDocument;
 | 
			
		||||
                QJsonObject jsonObject;
 | 
			
		||||
                jsonObject["Type"] = "PropertyEdited";
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5spv Grand Theft Auto Snapmatic Picture Viewer
 | 
			
		||||
* Copyright (C) 2016-2021 Syping
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -37,18 +37,287 @@
 | 
			
		|||
#else
 | 
			
		||||
#include <QStringDecoder>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
#include <QSaveFile>
 | 
			
		||||
#else
 | 
			
		||||
#include "StandardPaths.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// IMAGES VALUES
 | 
			
		||||
#define snapmaticResolutionW 960
 | 
			
		||||
#define snapmaticResolutionH 536
 | 
			
		||||
#define snapmaticResolution QSize(snapmaticResolutionW, snapmaticResolutionH)
 | 
			
		||||
 | 
			
		||||
// 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool gta5view_export_load(const QByteArray &fileData, RagePhoto *ragePhoto)
 | 
			
		||||
{
 | 
			
		||||
    QBuffer dataBuffer;
 | 
			
		||||
    dataBuffer.setData(fileData);
 | 
			
		||||
    if (!dataBuffer.open(QIODevice::ReadOnly))
 | 
			
		||||
        return false;
 | 
			
		||||
    dataBuffer.seek(4);
 | 
			
		||||
 | 
			
		||||
    char uInt32Buffer[4];
 | 
			
		||||
    qint64 size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
    if (size != 4)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    quint32 format = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
    if (format == G5EExportFormat::G5E3P) {
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        quint32 compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *compressedPhotoHeader = static_cast<char*>(std::malloc(compressedSize));
 | 
			
		||||
        if (!compressedPhotoHeader)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(compressedPhotoHeader, compressedSize);
 | 
			
		||||
        if (size != compressedSize) {
 | 
			
		||||
            free(compressedPhotoHeader);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        QByteArray t_photoHeader = QByteArray::fromRawData(compressedPhotoHeader, compressedSize);
 | 
			
		||||
        t_photoHeader = qUncompress(t_photoHeader);
 | 
			
		||||
        free(compressedPhotoHeader);
 | 
			
		||||
        if (t_photoHeader.isEmpty())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        quint32 t_headerSum = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
        ragePhoto->setHeader(t_photoHeader.constData(), t_headerSum);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        quint32 t_photoBuffer = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *compressedPhoto = static_cast<char*>(std::malloc(compressedSize));
 | 
			
		||||
        if (!compressedPhoto)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(compressedPhoto, compressedSize);
 | 
			
		||||
        if (size != compressedSize) {
 | 
			
		||||
            free(compressedPhoto);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        QByteArray t_photoData = QByteArray::fromRawData(compressedPhoto, compressedSize);
 | 
			
		||||
        t_photoData = qUncompress(t_photoData);
 | 
			
		||||
        free(compressedPhoto);
 | 
			
		||||
        ragePhoto->setPhoto(t_photoData.constData(), t_photoData.size(), t_photoBuffer);
 | 
			
		||||
 | 
			
		||||
        // JSON offset will be calculated later, offsets will be removed in G5E4P
 | 
			
		||||
        size = dataBuffer.skip(4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        quint32 t_jsonBuffer = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *compressedJson = static_cast<char*>(std::malloc(compressedSize));
 | 
			
		||||
        if (!compressedJson)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(compressedJson, compressedSize);
 | 
			
		||||
        if (size != compressedSize) {
 | 
			
		||||
            free(compressedJson);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        QByteArray t_jsonData = QByteArray::fromRawData(compressedJson, compressedSize);
 | 
			
		||||
        t_jsonData = qUncompress(t_jsonData);
 | 
			
		||||
        free(compressedJson);
 | 
			
		||||
        if (t_jsonData.isEmpty())
 | 
			
		||||
            return false;
 | 
			
		||||
        ragePhoto->setJson(t_jsonData.constData(), t_jsonBuffer);
 | 
			
		||||
 | 
			
		||||
        // TITL offset will be calculated later, offsets will be removed in G5E4P
 | 
			
		||||
        size = dataBuffer.skip(4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        quint32 t_titlBuffer = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *compressedTitl = static_cast<char*>(std::malloc(compressedSize));
 | 
			
		||||
        if (!compressedTitl)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(compressedTitl, compressedSize);
 | 
			
		||||
        if (size != compressedSize) {
 | 
			
		||||
            free(compressedTitl);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        QByteArray t_titlData = QByteArray::fromRawData(compressedTitl, compressedSize);
 | 
			
		||||
        t_titlData = qUncompress(t_titlData);
 | 
			
		||||
        free(compressedTitl);
 | 
			
		||||
        ragePhoto->setTitle(t_titlData.constData(), t_titlBuffer);
 | 
			
		||||
 | 
			
		||||
        // DESC offset will be calculated later, offsets will be removed in G5E4P
 | 
			
		||||
        size = dataBuffer.skip(4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        quint32 t_descBuffer = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.read(uInt32Buffer, 4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
        compressedSize = gta5view_charToUInt32LE(uInt32Buffer);
 | 
			
		||||
 | 
			
		||||
        char *compressedDesc = static_cast<char*>(std::malloc(compressedSize));
 | 
			
		||||
        if (!compressedDesc)
 | 
			
		||||
            return false;
 | 
			
		||||
        size = dataBuffer.read(compressedDesc, compressedSize);
 | 
			
		||||
        if (size != compressedSize) {
 | 
			
		||||
            free(compressedDesc);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        QByteArray t_descData = QByteArray::fromRawData(compressedDesc, compressedSize);
 | 
			
		||||
        t_descData  = qUncompress(t_descData);
 | 
			
		||||
        free(compressedDesc);
 | 
			
		||||
        ragePhoto->setDescription(t_descData.constData(), t_descBuffer);
 | 
			
		||||
 | 
			
		||||
        // EOF will be calculated later, EOF marker will be removed in G5E4P
 | 
			
		||||
        size = dataBuffer.skip(4);
 | 
			
		||||
        if (size != 4)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        // libragephoto needs to know we gave it a GTA V Snapmatic
 | 
			
		||||
        ragePhoto->setFormat(RagePhoto::GTA5);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (format == G5EExportFormat::G5E2P) {
 | 
			
		||||
        const QByteArray t_fileData = qUncompress(dataBuffer.readAll());
 | 
			
		||||
        if (t_fileData.isEmpty())
 | 
			
		||||
            return false;
 | 
			
		||||
        return ragePhoto->load(t_fileData.constData(), t_fileData.size());
 | 
			
		||||
    }
 | 
			
		||||
    else if (format == G5EExportFormat::G5E1P) {
 | 
			
		||||
        size = dataBuffer.skip(1);
 | 
			
		||||
        if (size != 1)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        char length[1];
 | 
			
		||||
        size = dataBuffer.read(length, 1);
 | 
			
		||||
        if (size != 1)
 | 
			
		||||
            return false;
 | 
			
		||||
        int i_length = QByteArray::number(static_cast<int>(length[0]), 16).toInt() + 6;
 | 
			
		||||
 | 
			
		||||
        size = dataBuffer.skip(i_length);
 | 
			
		||||
        if (size != i_length)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        const QByteArray t_fileData = qUncompress(dataBuffer.readAll());
 | 
			
		||||
        if (t_fileData.isEmpty())
 | 
			
		||||
            return false;
 | 
			
		||||
        return ragePhoto->load(t_fileData.constData(), t_fileData.size());
 | 
			
		||||
    }
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    gta5view_uInt32ToCharLE(data->photoBuffer, uInt32Buffer);
 | 
			
		||||
    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
 | 
			
		||||
SnapmaticPicture::SnapmaticPicture(const QString &fileName, QObject *parent) : QObject(parent), picFilePath(fileName)
 | 
			
		||||
{
 | 
			
		||||
    reset();
 | 
			
		||||
| 
						 | 
				
			
			@ -68,8 +337,12 @@ void SnapmaticPicture::reset()
 | 
			
		|||
    lastStep = QString();
 | 
			
		||||
    sortStr = QString();
 | 
			
		||||
 | 
			
		||||
    // INIT PIC FORMAT
 | 
			
		||||
    picFormat = 0;
 | 
			
		||||
 | 
			
		||||
    // INIT PIC BOOLS
 | 
			
		||||
    isFormatSwitch = false;
 | 
			
		||||
    isPreLoaded = false;
 | 
			
		||||
    picOk = false;
 | 
			
		||||
 | 
			
		||||
    // INIT JSON
 | 
			
		||||
| 
						 | 
				
			
			@ -77,32 +350,45 @@ void SnapmaticPicture::reset()
 | 
			
		|||
 | 
			
		||||
    // SNAPMATIC PROPERTIES
 | 
			
		||||
    localProperties = {};
 | 
			
		||||
 | 
			
		||||
    // JSON OBJECT
 | 
			
		||||
    jsonObject = QJsonObject();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SnapmaticPicture::preloadFile()
 | 
			
		||||
{
 | 
			
		||||
    QFile *picFile = new QFile(picFilePath);
 | 
			
		||||
    QFile picFile(picFilePath);
 | 
			
		||||
    picFileName = QFileInfo(picFilePath).fileName();
 | 
			
		||||
 | 
			
		||||
    isFormatSwitch = false;
 | 
			
		||||
 | 
			
		||||
    if (!picFile->open(QFile::ReadOnly)) {
 | 
			
		||||
    if (!picFile.open(QIODevice::ReadOnly)) {
 | 
			
		||||
        lastStep = "1;/1,OpenFile," % convertDrawStringForLog(picFilePath);
 | 
			
		||||
        delete picFile;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    p_ragePhoto.setIODevice(picFile);
 | 
			
		||||
    bool ok = p_ragePhoto.load();
 | 
			
		||||
    picFile->close();
 | 
			
		||||
    delete picFile;
 | 
			
		||||
    const qint64 fileMaxSize = (1024 * 1024 * 64);
 | 
			
		||||
    const QByteArray fileData = picFile.read(fileMaxSize);
 | 
			
		||||
 | 
			
		||||
    bool ok = p_ragePhoto.load(fileData.constData(), fileData.size());
 | 
			
		||||
    picFormat = p_ragePhoto.format();
 | 
			
		||||
 | 
			
		||||
    // libragephoto doesn't support modules yet
 | 
			
		||||
    if (picFormat == G5EPhotoFormat::G5EX)
 | 
			
		||||
        ok = gta5view_export_load(fileData, &p_ragePhoto);
 | 
			
		||||
 | 
			
		||||
    if (!ok)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (picFilePath.right(4) != QLatin1String(".g5e")) {
 | 
			
		||||
        if (p_ragePhoto.photoFormat() == RagePhoto::PhotoFormat::G5EX)
 | 
			
		||||
    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)
 | 
			
		||||
            isFormatSwitch = true;
 | 
			
		||||
    }
 | 
			
		||||
    isPreLoaded = true;
 | 
			
		||||
    emit preloaded();
 | 
			
		||||
    return ok;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -116,17 +402,17 @@ bool SnapmaticPicture::readingPicture(bool cacheEnabled_)
 | 
			
		|||
    cacheEnabled = cacheEnabled_;
 | 
			
		||||
 | 
			
		||||
    bool ok = true;
 | 
			
		||||
    if (!p_ragePhoto.isLoaded())
 | 
			
		||||
    if (!isPreLoaded)
 | 
			
		||||
        ok = preloadFile();
 | 
			
		||||
 | 
			
		||||
    if (!ok)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (cacheEnabled)
 | 
			
		||||
        picOk = cachePicture.loadFromData(p_ragePhoto.photoData(), "JPEG");
 | 
			
		||||
        picOk = cachePicture.loadFromData(QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize()), "JPEG");
 | 
			
		||||
    if (!cacheEnabled) {
 | 
			
		||||
        QImage tempPicture;
 | 
			
		||||
        picOk = tempPicture.loadFromData(p_ragePhoto.photoData(), "JPEG");
 | 
			
		||||
        picOk = tempPicture.loadFromData(QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize()), "JPEG");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    parseJsonContent(); // JSON parsing is own function
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +424,7 @@ bool SnapmaticPicture::readingPicture(bool cacheEnabled_)
 | 
			
		|||
 | 
			
		||||
void SnapmaticPicture::updateStrings()
 | 
			
		||||
{
 | 
			
		||||
    QString cmpPicTitl = p_ragePhoto.title();
 | 
			
		||||
    QString cmpPicTitl(p_ragePhoto.title());
 | 
			
		||||
    cmpPicTitl.replace('\"', "''");
 | 
			
		||||
    cmpPicTitl.replace(' ', '_');
 | 
			
		||||
    cmpPicTitl.replace(':', '-');
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +439,7 @@ void SnapmaticPicture::updateStrings()
 | 
			
		|||
    cmpPicTitl.remove('.');
 | 
			
		||||
    pictureStr = tr("PHOTO - %1").arg(localProperties.createdDateTime.toString("MM/dd/yy HH:mm:ss"));
 | 
			
		||||
    sortStr = localProperties.createdDateTime.toString("yyMMddHHmmss") % QString::number(localProperties.uid);
 | 
			
		||||
    QString exportStr = localProperties.createdDateTime.toString("yyyyMMdd") % "-" % QString::number(localProperties.uid);
 | 
			
		||||
    const QString exportStr = localProperties.createdDateTime.toString("yyyyMMdd") % "-" % QString::number(localProperties.uid);
 | 
			
		||||
    if (getSnapmaticFormat() == SnapmaticFormat::G5E_Format)
 | 
			
		||||
        picFileName = "PGTA5" % QString::number(localProperties.uid);
 | 
			
		||||
    picExportFileName = exportStr % "_" % cmpPicTitl;
 | 
			
		||||
| 
						 | 
				
			
			@ -165,17 +451,16 @@ bool SnapmaticPicture::readingPictureFromFile(const QString &fileName, bool cach
 | 
			
		|||
        picFilePath = fileName;
 | 
			
		||||
        return readingPicture(cacheEnabled_);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    else
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SnapmaticPicture::setImage(const QImage &picture, bool eXtendMode)
 | 
			
		||||
{
 | 
			
		||||
#ifdef GTA5SYNC_DYNAMIC_PHOTOBUFFER
 | 
			
		||||
    quint32 jpegPicStreamLength = p_ragePhoto.photoBuffer();
 | 
			
		||||
#ifdef GTA5SYNC_DYNAMIC_PHOTOBUFFER // It's not properly implemented yet, please don't define
 | 
			
		||||
    quint32 jpegPicStreamLength = p_ragePhoto.data()->photoBuffer();
 | 
			
		||||
#else
 | 
			
		||||
    quint32 jpegPicStreamLength = 524288U;
 | 
			
		||||
    quint32 jpegPicStreamLength = RagePhoto::DEFAULT_GTA5_PHOTOBUFFER;
 | 
			
		||||
#endif
 | 
			
		||||
    QByteArray picByteArray;
 | 
			
		||||
    int comLvl = 100;
 | 
			
		||||
| 
						 | 
				
			
			@ -193,19 +478,11 @@ bool SnapmaticPicture::setImage(const QImage &picture, bool eXtendMode)
 | 
			
		|||
                    comLvl--;
 | 
			
		||||
                    saveSuccess = false;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    p_ragePhoto.setPhotoBuffer(size, true);
 | 
			
		||||
                else
 | 
			
		||||
                    picByteArray = picByteArrayT;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
#ifndef GTA5SYNC_DYNAMIC_PHOTOBUFFER
 | 
			
		||||
                if (p_ragePhoto.photoBuffer() != jpegPicStreamLength)
 | 
			
		||||
                    p_ragePhoto.setPhotoData(QByteArray()); // avoid buffer set fail
 | 
			
		||||
                    p_ragePhoto.setPhotoBuffer(jpegPicStreamLength, true);
 | 
			
		||||
#endif
 | 
			
		||||
            else
 | 
			
		||||
                picByteArray = picByteArrayT;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (saveSuccess)
 | 
			
		||||
| 
						 | 
				
			
			@ -215,7 +492,18 @@ bool SnapmaticPicture::setImage(const QImage &picture, bool eXtendMode)
 | 
			
		|||
 | 
			
		||||
bool SnapmaticPicture::setPictureStream(const QByteArray &streamArray) // clean method
 | 
			
		||||
{
 | 
			
		||||
    bool success = p_ragePhoto.setPhotoData(streamArray);
 | 
			
		||||
#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);
 | 
			
		||||
    if (success) {
 | 
			
		||||
        if (cacheEnabled) {
 | 
			
		||||
            QImage replacedPicture;
 | 
			
		||||
| 
						 | 
				
			
			@ -224,26 +512,19 @@ bool SnapmaticPicture::setPictureStream(const QByteArray &streamArray) // clean
 | 
			
		|||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    else
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SnapmaticPicture::setPictureTitl(const QString &newTitle_)
 | 
			
		||||
{
 | 
			
		||||
    QString newTitle = newTitle_;
 | 
			
		||||
    if (newTitle.length() > 39) {
 | 
			
		||||
    if (newTitle.length() > 39)
 | 
			
		||||
        newTitle = newTitle.left(39);
 | 
			
		||||
    }
 | 
			
		||||
    p_ragePhoto.setTitle(newTitle);
 | 
			
		||||
    p_ragePhoto.setTitle(newTitle.toStdString().c_str());
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SnapmaticPicture::getContentMaxLength()
 | 
			
		||||
{
 | 
			
		||||
    return p_ragePhoto.photoBuffer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString SnapmaticPicture::getExportPictureFileName()
 | 
			
		||||
{
 | 
			
		||||
    return picExportFileName;
 | 
			
		||||
| 
						 | 
				
			
			@ -252,24 +533,20 @@ QString SnapmaticPicture::getExportPictureFileName()
 | 
			
		|||
QString SnapmaticPicture::getOriginalPictureFileName()
 | 
			
		||||
{
 | 
			
		||||
    QString newPicFileName = picFileName;
 | 
			
		||||
    if (picFileName.right(4) == ".bak") {
 | 
			
		||||
    if (picFileName.right(4) == ".bak")
 | 
			
		||||
        newPicFileName = QString(picFileName).remove(picFileName.length() - 4, 4);
 | 
			
		||||
    }
 | 
			
		||||
    if (picFileName.right(7) == ".hidden") {
 | 
			
		||||
    if (picFileName.right(7) == ".hidden")
 | 
			
		||||
        newPicFileName = QString(picFileName).remove(picFileName.length() - 7, 7);
 | 
			
		||||
    }
 | 
			
		||||
    return newPicFileName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString SnapmaticPicture::getOriginalPictureFilePath()
 | 
			
		||||
{
 | 
			
		||||
    QString newPicFilePath = picFilePath;
 | 
			
		||||
    if (picFilePath.right(4) == ".bak") {
 | 
			
		||||
    if (picFilePath.right(4) == ".bak")
 | 
			
		||||
        newPicFilePath = QString(picFilePath).remove(picFilePath.length() - 4, 4);
 | 
			
		||||
    }
 | 
			
		||||
    if (picFilePath.right(7) == ".hidden") {
 | 
			
		||||
    if (picFilePath.right(7) == ".hidden")
 | 
			
		||||
        newPicFilePath = QString(picFilePath).remove(picFilePath.length() - 7, 7);
 | 
			
		||||
    }
 | 
			
		||||
    return newPicFilePath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -309,13 +586,13 @@ QString SnapmaticPicture::getLastStep(bool readable)
 | 
			
		|||
        if (descStepList.length() < 1)
 | 
			
		||||
            return lastStep;
 | 
			
		||||
        int argsCount = descStepList.at(0).toInt(&intOk);
 | 
			
		||||
        if (!intOk) { return lastStep; }
 | 
			
		||||
        if (!intOk)
 | 
			
		||||
            return lastStep;
 | 
			
		||||
        if (argsCount == 1) {
 | 
			
		||||
            QString currentAction = descStepList.at(1);
 | 
			
		||||
            QString actionFile = descStepList.at(2);
 | 
			
		||||
            if (currentAction == "OpenFile") {
 | 
			
		||||
            if (currentAction == "OpenFile")
 | 
			
		||||
                return tr("open file %1").arg(actionFile);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (argsCount == 3 || argsCount == 4) {
 | 
			
		||||
            QString currentAction = descStepList.at(1);
 | 
			
		||||
| 
						 | 
				
			
			@ -325,42 +602,31 @@ QString SnapmaticPicture::getLastStep(bool readable)
 | 
			
		|||
            if (argsCount == 4) { actionError2 = descStepList.at(5); }
 | 
			
		||||
            if (currentAction == "ReadingFile") {
 | 
			
		||||
                QString readableError = actionError;
 | 
			
		||||
                if (actionError == "NOHEADER") {
 | 
			
		||||
                if (actionError == "NOHEADER")
 | 
			
		||||
                    readableError = tr("header not exists");
 | 
			
		||||
                }
 | 
			
		||||
                else if (actionError == "MALFORMEDHEADER") {
 | 
			
		||||
                else if (actionError == "MALFORMEDHEADER")
 | 
			
		||||
                    readableError = tr("header is malformed");
 | 
			
		||||
                }
 | 
			
		||||
                else if (actionError == "NOJPEG" || actionError == "NOPIC") {
 | 
			
		||||
                else if (actionError == "NOJPEG" || actionError == "NOPIC")
 | 
			
		||||
                    readableError = tr("picture not exists (%1)").arg(actionError);
 | 
			
		||||
                }
 | 
			
		||||
                else if (actionError == "NOJSON" || actionError == "CTJSON") {
 | 
			
		||||
                else if (actionError == "NOJSON" || actionError == "CTJSON")
 | 
			
		||||
                    readableError = tr("JSON not exists (%1)").arg(actionError);
 | 
			
		||||
                }
 | 
			
		||||
                else if (actionError == "NOTITL" || actionError == "CTTITL") {
 | 
			
		||||
                else if (actionError == "NOTITL" || actionError == "CTTITL")
 | 
			
		||||
                    readableError = tr("title not exists (%1)").arg(actionError);
 | 
			
		||||
                }
 | 
			
		||||
                else if (actionError == "NODESC" || actionError == "CTDESC") {
 | 
			
		||||
                else if (actionError == "NODESC" || actionError == "CTDESC")
 | 
			
		||||
                    readableError = tr("description not exists (%1)").arg(actionError);
 | 
			
		||||
                }
 | 
			
		||||
                else if (actionError == "JSONINCOMPLETE" && actionError2 == "JSONERROR") {
 | 
			
		||||
                else if (actionError == "JSONINCOMPLETE" && actionError2 == "JSONERROR")
 | 
			
		||||
                    readableError = tr("JSON is incomplete and malformed");
 | 
			
		||||
                }
 | 
			
		||||
                else if (actionError == "JSONINCOMPLETE") {
 | 
			
		||||
                else if (actionError == "JSONINCOMPLETE")
 | 
			
		||||
                    readableError = tr("JSON is incomplete");
 | 
			
		||||
                }
 | 
			
		||||
                else if (actionError == "JSONERROR") {
 | 
			
		||||
                else if (actionError == "JSONERROR")
 | 
			
		||||
                    readableError = tr("JSON is malformed");
 | 
			
		||||
                }
 | 
			
		||||
                return tr("reading file %1 because of %2", "Example for %2: JSON is malformed error").arg(actionFile, readableError);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
            else
 | 
			
		||||
                return lastStep;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
        else
 | 
			
		||||
            return lastStep;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return lastStep;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -368,18 +634,16 @@ QString SnapmaticPicture::getLastStep(bool readable)
 | 
			
		|||
 | 
			
		||||
QImage SnapmaticPicture::getImage()
 | 
			
		||||
{
 | 
			
		||||
    if (cacheEnabled) {
 | 
			
		||||
    if (cacheEnabled)
 | 
			
		||||
        return cachePicture;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        return QImage::fromData(p_ragePhoto.photoData(), "JPEG");
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        return QImage::fromData(QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize()), "JPEG");
 | 
			
		||||
    return QImage();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QByteArray SnapmaticPicture::getPictureStream()
 | 
			
		||||
{
 | 
			
		||||
    return p_ragePhoto.photoData();
 | 
			
		||||
    return QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SnapmaticPicture::isPicOk()
 | 
			
		||||
| 
						 | 
				
			
			@ -412,7 +676,7 @@ bool SnapmaticPicture::isJsonOk()
 | 
			
		|||
 | 
			
		||||
QString SnapmaticPicture::getJsonStr()
 | 
			
		||||
{
 | 
			
		||||
    return QString::fromUtf8(p_ragePhoto.jsonData());
 | 
			
		||||
    return QString::fromUtf8(p_ragePhoto.json());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SnapmaticProperties SnapmaticPicture::getSnapmaticProperties()
 | 
			
		||||
| 
						 | 
				
			
			@ -422,7 +686,6 @@ SnapmaticProperties SnapmaticPicture::getSnapmaticProperties()
 | 
			
		|||
 | 
			
		||||
void SnapmaticPicture::parseJsonContent()
 | 
			
		||||
{
 | 
			
		||||
    QJsonObject jsonObject = p_ragePhoto.jsonObject();
 | 
			
		||||
    QVariantMap jsonMap = jsonObject.toVariantMap();
 | 
			
		||||
 | 
			
		||||
    bool jsonIncomplete = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -540,28 +803,28 @@ void SnapmaticPicture::parseJsonContent()
 | 
			
		|||
 | 
			
		||||
bool SnapmaticPicture::setSnapmaticProperties(SnapmaticProperties properties)
 | 
			
		||||
{
 | 
			
		||||
    QJsonObject jsonObject = p_ragePhoto.jsonObject();
 | 
			
		||||
    QJsonObject t_jsonObject = jsonObject;
 | 
			
		||||
 | 
			
		||||
    QJsonObject locObject;
 | 
			
		||||
    locObject["x"] = properties.location.x;
 | 
			
		||||
    locObject["y"] = properties.location.y;
 | 
			
		||||
    locObject["z"] = properties.location.z;
 | 
			
		||||
 | 
			
		||||
    jsonObject["loc"] = locObject;
 | 
			
		||||
    jsonObject["uid"] = properties.uid;
 | 
			
		||||
    jsonObject["area"] = properties.location.area;
 | 
			
		||||
    jsonObject["crewid"] = properties.crewID;
 | 
			
		||||
    jsonObject["street"] = properties.streetID;
 | 
			
		||||
    jsonObject["creat"] = QJsonValue::fromVariant(properties.createdTimestamp);
 | 
			
		||||
    jsonObject["plyrs"] = QJsonValue::fromVariant(properties.playersList);
 | 
			
		||||
    jsonObject["meme"] = properties.isMeme;
 | 
			
		||||
    jsonObject["mug"] = properties.isMug;
 | 
			
		||||
    jsonObject["slf"] = properties.isSelfie;
 | 
			
		||||
    jsonObject["drctr"] = properties.isFromDirector;
 | 
			
		||||
    jsonObject["rsedtr"] = properties.isFromRSEditor;
 | 
			
		||||
    jsonObject["onislandx"] = properties.location.isCayoPerico;
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    QJsonDocument jsonDocument(jsonObject);
 | 
			
		||||
    const QJsonDocument jsonDocument(t_jsonObject);
 | 
			
		||||
    if (setJsonStr(QString::fromUtf8(jsonDocument.toJson(QJsonDocument::Compact)))) {
 | 
			
		||||
        localProperties = properties;
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -571,14 +834,16 @@ bool SnapmaticPicture::setSnapmaticProperties(SnapmaticProperties properties)
 | 
			
		|||
 | 
			
		||||
bool SnapmaticPicture::setJsonStr(const QString &newJsonStr, bool updateProperties)
 | 
			
		||||
{
 | 
			
		||||
    if (p_ragePhoto.setJsonData(newJsonStr.toUtf8())) {
 | 
			
		||||
        if (updateProperties)
 | 
			
		||||
            parseJsonContent();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    const QJsonDocument t_jsonDocument = QJsonDocument::fromJson(newJsonStr.toStdString().c_str());
 | 
			
		||||
    if (t_jsonDocument.isNull())
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    const QByteArray t_jsonData = t_jsonDocument.toJson(QJsonDocument::Compact);
 | 
			
		||||
    jsonObject = t_jsonDocument.object();
 | 
			
		||||
 | 
			
		||||
    p_ragePhoto.setJson(t_jsonData.constData());
 | 
			
		||||
    if (updateProperties)
 | 
			
		||||
        parseJsonContent();
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FILE MANAGEMENT
 | 
			
		||||
| 
						 | 
				
			
			@ -588,7 +853,7 @@ bool SnapmaticPicture::exportPicture(const QString &fileName, SnapmaticFormat fo
 | 
			
		|||
    // Keep current format when Auto_Format is used
 | 
			
		||||
    SnapmaticFormat format = format_;
 | 
			
		||||
    if (format_ == SnapmaticFormat::Auto_Format) {
 | 
			
		||||
        if (p_ragePhoto.photoFormat() == RagePhoto::PhotoFormat::G5EX) {
 | 
			
		||||
        if (p_ragePhoto.format() == G5EPhotoFormat::G5EX) {
 | 
			
		||||
            format = SnapmaticFormat::G5E_Format;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
| 
						 | 
				
			
			@ -597,68 +862,27 @@ bool SnapmaticPicture::exportPicture(const QString &fileName, SnapmaticFormat fo
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    bool saveSuccess = false;
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
    QSaveFile *picFile = new QSaveFile(fileName);
 | 
			
		||||
#else
 | 
			
		||||
    QFile *picFile = new QFile(StandardPaths::tempLocation() % "/" % QFileInfo(fileName).fileName() % ".tmp");
 | 
			
		||||
#endif
 | 
			
		||||
    if (picFile->open(QIODevice::WriteOnly)) {
 | 
			
		||||
    QSaveFile picFile(fileName);
 | 
			
		||||
    if (picFile.open(QIODevice::WriteOnly)) {
 | 
			
		||||
        if (format == SnapmaticFormat::G5E_Format) {
 | 
			
		||||
            p_ragePhoto.save(picFile, RagePhoto::PhotoFormat::G5EX);
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
            saveSuccess = picFile->commit();
 | 
			
		||||
#else
 | 
			
		||||
            saveSuccess = true;
 | 
			
		||||
            picFile->close();
 | 
			
		||||
#endif
 | 
			
		||||
            delete picFile;
 | 
			
		||||
            gta5view_export_save(&picFile, p_ragePhoto.data());
 | 
			
		||||
            saveSuccess = picFile.commit();
 | 
			
		||||
        }
 | 
			
		||||
        else if (format == SnapmaticFormat::JPEG_Format) {
 | 
			
		||||
            picFile->write(p_ragePhoto.photoData());
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
            saveSuccess = picFile->commit();
 | 
			
		||||
#else
 | 
			
		||||
            saveSuccess = true;
 | 
			
		||||
            picFile->close();
 | 
			
		||||
#endif
 | 
			
		||||
            delete picFile;
 | 
			
		||||
            picFile.write(QByteArray::fromRawData(p_ragePhoto.photoData(), p_ragePhoto.photoSize()));
 | 
			
		||||
            saveSuccess = picFile.commit();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            p_ragePhoto.save(picFile, RagePhoto::PhotoFormat::GTA5);
 | 
			
		||||
#if QT_VERSION >= 0x050000
 | 
			
		||||
            saveSuccess = picFile->commit();
 | 
			
		||||
#else
 | 
			
		||||
            saveSuccess = true;
 | 
			
		||||
            picFile->close();
 | 
			
		||||
#endif
 | 
			
		||||
            delete picFile;
 | 
			
		||||
            bool ok;
 | 
			
		||||
            const std::string photo = p_ragePhoto.save(&ok);
 | 
			
		||||
            if (ok)
 | 
			
		||||
                picFile.write(photo.data(), photo.size());
 | 
			
		||||
            saveSuccess = picFile.commit();
 | 
			
		||||
        }
 | 
			
		||||
#if QT_VERSION <= 0x050000
 | 
			
		||||
        if (saveSuccess) {
 | 
			
		||||
            bool tempBakCreated = false;
 | 
			
		||||
            if (QFile::exists(fileName)) {
 | 
			
		||||
                if (!QFile::rename(fileName, fileName % ".tmp")) {
 | 
			
		||||
                    QFile::remove(StandardPaths::tempLocation() % "/" % QFileInfo(fileName).fileName() % ".tmp");
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                tempBakCreated = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (!QFile::rename(StandardPaths::tempLocation() % "/" % QFileInfo(fileName).fileName() % ".tmp", fileName)) {
 | 
			
		||||
                QFile::remove(StandardPaths::tempLocation() % "/" % QFileInfo(fileName).fileName() % ".tmp");
 | 
			
		||||
                if (tempBakCreated)
 | 
			
		||||
                    QFile::rename(fileName % ".tmp", fileName);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if (tempBakCreated)
 | 
			
		||||
                QFile::remove(fileName % ".tmp");
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        return saveSuccess;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        delete picFile;
 | 
			
		||||
    else
 | 
			
		||||
        return saveSuccess;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SnapmaticPicture::setPicFileName(const QString &picFileName_)
 | 
			
		||||
| 
						 | 
				
			
			@ -674,19 +898,19 @@ void SnapmaticPicture::setPicFilePath(const QString &picFilePath_)
 | 
			
		|||
bool SnapmaticPicture::deletePicFile()
 | 
			
		||||
{
 | 
			
		||||
    bool success = false;
 | 
			
		||||
    if (!QFile::exists(picFilePath)) {
 | 
			
		||||
    if (!QFile::exists(picFilePath))
 | 
			
		||||
        success = true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (QFile::remove(picFilePath)) {
 | 
			
		||||
    else if (QFile::remove(picFilePath))
 | 
			
		||||
        success = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (isHidden()) {
 | 
			
		||||
        const QString picBakPath = QString(picFilePath).remove(picFilePath.length() - 7, 7) % ".bak";
 | 
			
		||||
        if (QFile::exists(picBakPath)) QFile::remove(picBakPath);
 | 
			
		||||
        if (QFile::exists(picBakPath))
 | 
			
		||||
            QFile::remove(picBakPath);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        const QString picBakPath = picFilePath % ".bak";
 | 
			
		||||
        if (QFile::exists(picBakPath)) QFile::remove(picBakPath);
 | 
			
		||||
        if (QFile::exists(picBakPath))
 | 
			
		||||
            QFile::remove(picBakPath);
 | 
			
		||||
    }
 | 
			
		||||
    return success;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -695,23 +919,21 @@ bool SnapmaticPicture::deletePicFile()
 | 
			
		|||
 | 
			
		||||
bool SnapmaticPicture::isHidden()
 | 
			
		||||
{
 | 
			
		||||
    if (picFilePath.right(7) == QLatin1String(".hidden")) {
 | 
			
		||||
    if (picFilePath.right(7) == QLatin1String(".hidden"))
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SnapmaticPicture::isVisible()
 | 
			
		||||
{
 | 
			
		||||
    if (picFilePath.right(7) == QLatin1String(".hidden")) {
 | 
			
		||||
    if (picFilePath.right(7) == QLatin1String(".hidden"))
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SnapmaticPicture::setPictureHidden()
 | 
			
		||||
{
 | 
			
		||||
    if (p_ragePhoto.photoFormat() == RagePhoto::PhotoFormat::G5EX) {
 | 
			
		||||
    if (picFormat == G5EPhotoFormat::G5EX) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (!isHidden()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -727,9 +949,8 @@ bool SnapmaticPicture::setPictureHidden()
 | 
			
		|||
 | 
			
		||||
bool SnapmaticPicture::setPictureVisible()
 | 
			
		||||
{
 | 
			
		||||
    if (p_ragePhoto.photoFormat() == RagePhoto::PhotoFormat::G5EX) {
 | 
			
		||||
    if (picFormat == G5EPhotoFormat::G5EX)
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (isHidden()) {
 | 
			
		||||
        QString newPicFilePath = QString(picFilePath).remove(picFilePath.length() - 7, 7);
 | 
			
		||||
        if (QFile::rename(picFilePath, newPicFilePath)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -752,20 +973,19 @@ QSize SnapmaticPicture::getSnapmaticResolution()
 | 
			
		|||
 | 
			
		||||
SnapmaticFormat SnapmaticPicture::getSnapmaticFormat()
 | 
			
		||||
{
 | 
			
		||||
    if (p_ragePhoto.photoFormat() == RagePhoto::PhotoFormat::G5EX) {
 | 
			
		||||
    if (picFormat == G5EPhotoFormat::G5EX)
 | 
			
		||||
        return SnapmaticFormat::G5E_Format;
 | 
			
		||||
    }
 | 
			
		||||
    return SnapmaticFormat::PGTA_Format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SnapmaticPicture::setSnapmaticFormat(SnapmaticFormat format)
 | 
			
		||||
{
 | 
			
		||||
    if (format == SnapmaticFormat::G5E_Format) {
 | 
			
		||||
        p_ragePhoto.setPhotoFormat(RagePhoto::PhotoFormat::G5EX);
 | 
			
		||||
        picFormat = G5EPhotoFormat::G5EX;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    else if (format == SnapmaticFormat::PGTA_Format) {
 | 
			
		||||
        p_ragePhoto.setPhotoFormat(RagePhoto::PhotoFormat::GTA5);
 | 
			
		||||
        picFormat = RagePhoto::PhotoFormat::GTA5;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    qDebug() << "setSnapmaticFormat: Invalid SnapmaticFormat defined, valid SnapmaticFormats are G5E_Format and PGTA_Format";
 | 
			
		||||
| 
						 | 
				
			
			@ -794,7 +1014,8 @@ bool SnapmaticPicture::verifyTitleChar(const QChar &titleChar)
 | 
			
		|||
{
 | 
			
		||||
    // VERIFY CHAR FOR BE A VALID SNAPMATIC CHARACTER
 | 
			
		||||
    if (titleChar.isLetterOrNumber() || titleChar.isPrint()) {
 | 
			
		||||
        if (titleChar == '<' || titleChar == '>' || titleChar == '\\') return false;
 | 
			
		||||
        if (titleChar == '<' || titleChar == '>' || titleChar == '\\')
 | 
			
		||||
            return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -802,9 +1023,8 @@ bool SnapmaticPicture::verifyTitleChar(const QChar &titleChar)
 | 
			
		|||
 | 
			
		||||
// STRING OPERATIONS
 | 
			
		||||
 | 
			
		||||
QString SnapmaticPicture::parseTitleString(const QByteArray &commitBytes, int maxLength)
 | 
			
		||||
QString SnapmaticPicture::parseTitleString(const QByteArray &commitBytes)
 | 
			
		||||
{
 | 
			
		||||
    Q_UNUSED(maxLength)
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
    QStringDecoder strDecoder = QStringDecoder(QStringDecoder::Utf16LE);
 | 
			
		||||
    QString retStr = strDecoder(commitBytes);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5spv Grand Theft Auto Snapmatic Picture Viewer
 | 
			
		||||
* Copyright (C) 2016-2020 Syping
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +21,7 @@
 | 
			
		|||
 | 
			
		||||
#include "RagePhoto.h"
 | 
			
		||||
#include <QStringList>
 | 
			
		||||
#include <QJsonObject>
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
#include <QObject>
 | 
			
		||||
#include <QString>
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +29,16 @@
 | 
			
		|||
#include <QFile>
 | 
			
		||||
 | 
			
		||||
enum class SnapmaticFormat : int { Auto_Format = 0, PGTA_Format = 1, JPEG_Format = 2, G5E_Format = 3 };
 | 
			
		||||
enum G5EExportFormat : uint32_t {
 | 
			
		||||
    G5E1P = 0x454C0010UL,
 | 
			
		||||
    G5E2P = 0x01000032UL,
 | 
			
		||||
    G5E2S = 0x02000032UL,
 | 
			
		||||
    G5E3P = 0x01000033UL,
 | 
			
		||||
    G5E3S = 0x02000033UL,
 | 
			
		||||
};
 | 
			
		||||
enum G5EPhotoFormat : uint32_t {
 | 
			
		||||
    G5EX = 0x45354700UL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SnapmaticProperties {
 | 
			
		||||
    struct SnapmaticLocation {
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +85,6 @@ public:
 | 
			
		|||
    QString getExportPictureFileName();
 | 
			
		||||
    QString getOriginalPictureFileName();
 | 
			
		||||
    QString getOriginalPictureFilePath();
 | 
			
		||||
    int getContentMaxLength();
 | 
			
		||||
    bool setImage(const QImage &picture, bool eXtendMode = false);
 | 
			
		||||
    bool setPictureTitl(const QString &newTitle); // Please use setPictureTitle instead
 | 
			
		||||
    bool setPictureStream(const QByteArray &streamArray);
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +140,7 @@ public:
 | 
			
		|||
    static bool verifyTitle(const QString &title);
 | 
			
		||||
 | 
			
		||||
    // STRING OPERATIONS
 | 
			
		||||
    static QString parseTitleString(const QByteArray &commitBytes, int maxLength);
 | 
			
		||||
    static QString parseTitleString(const QByteArray &commitBytes);
 | 
			
		||||
    static QString convertDrawStringForLog(const QString &inputStr);
 | 
			
		||||
    static QString convertLogStringForDraw(const QString &inputStr);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -145,14 +155,17 @@ private:
 | 
			
		|||
    QString pictureStr;
 | 
			
		||||
    QString lastStep;
 | 
			
		||||
    QString sortStr;
 | 
			
		||||
    uint32_t picFormat;
 | 
			
		||||
    bool picOk;
 | 
			
		||||
    bool cacheEnabled;
 | 
			
		||||
    bool isFormatSwitch;
 | 
			
		||||
    bool isPreLoaded;
 | 
			
		||||
 | 
			
		||||
    // JSON
 | 
			
		||||
    void parseJsonContent();
 | 
			
		||||
    bool jsonOk;
 | 
			
		||||
    SnapmaticProperties localProperties;
 | 
			
		||||
    QJsonObject jsonObject;
 | 
			
		||||
 | 
			
		||||
    // VERIFY CONTENT
 | 
			
		||||
    static bool verifyTitleChar(const QChar &titleChar);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ bool SnapmaticWidget::deletePicture()
 | 
			
		|||
                QJsonObject jsonObject;
 | 
			
		||||
                jsonObject["Type"] = "DeleteSuccess";
 | 
			
		||||
                jsonObject["ExtraFlags"] = "Snapmatic";
 | 
			
		||||
                jsonObject["DeletedSize"] = QString::number(smpic->getContentMaxLength());
 | 
			
		||||
                jsonObject["DeletedSize"] = QString::number(smpic->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                jsonObject["DeletedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -381,7 +381,7 @@ void SnapmaticWidget::editSnapmaticImage()
 | 
			
		|||
                QJsonObject jsonObject;
 | 
			
		||||
                jsonObject["Type"] = "ImageEdited";
 | 
			
		||||
                jsonObject["ExtraFlags"] = "Interface";
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->getContentMaxLength());
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			@ -439,7 +439,7 @@ void SnapmaticWidget::openMapViewer()
 | 
			
		|||
                QJsonObject jsonObject;
 | 
			
		||||
                jsonObject["Type"] = "LocationEdited";
 | 
			
		||||
                jsonObject["ExtraFlags"] = "Interface";
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(picture->getContentMaxLength());
 | 
			
		||||
                jsonObject["EditedSize"] = QString::number(smpic->ragePhoto()->photoSize());
 | 
			
		||||
#if QT_VERSION >= 0x060000
 | 
			
		||||
                jsonObject["EditedTime"] = QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
 | 
			
		||||
#else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2021 Syping
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -184,11 +184,7 @@ UserInterface::UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, D
 | 
			
		|||
    QObject::connect(donateAction, &QAction::triggered, this, [=](){
 | 
			
		||||
        QDialog *donateDialog = new QDialog(this);
 | 
			
		||||
        donateDialog->setWindowTitle(QString("%1 - %2").arg(GTA5SYNC_APPSTR, tr("Donate")));
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
        donateDialog->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
        donateDialog->setWindowFlags(donateDialog->windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
        QVBoxLayout *donateLayout = new QVBoxLayout;
 | 
			
		||||
        donateDialog->setLayout(donateLayout);
 | 
			
		||||
        QLabel *methodsLabel = new QLabel(QString("<b>%1</b>").arg(tr("Donation methods").toHtmlEscaped()), donateDialog);
 | 
			
		||||
| 
						 | 
				
			
			@ -222,11 +218,7 @@ UserInterface::UserInterface(ProfileDatabase *profileDB, CrewDatabase *crewDB, D
 | 
			
		|||
                QObject::connect(currencyButton, &QPushButton::pressed, donateDialog, [=](){
 | 
			
		||||
                    QDialog *addressDialog = new QDialog(donateDialog);
 | 
			
		||||
                    addressDialog->setWindowTitle(currencyStr);
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
                    addressDialog->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
                    addressDialog->setWindowFlags(donateDialog->windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
                    QVBoxLayout *addressLayout = new QVBoxLayout;
 | 
			
		||||
                    addressDialog->setLayout(addressLayout);
 | 
			
		||||
                    QLabel *addressLabel = new QLabel(address, addressDialog);
 | 
			
		||||
| 
						 | 
				
			
			@ -580,11 +572,7 @@ fileDialogPreOpen:
 | 
			
		|||
    fileDialog.setViewMode(QFileDialog::Detail);
 | 
			
		||||
    fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
 | 
			
		||||
    fileDialog.setOption(QFileDialog::DontUseNativeDialog, false);
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    fileDialog.setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
    fileDialog.setWindowFlags(fileDialog.windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
    fileDialog.setWindowTitle(tr("Open File..."));
 | 
			
		||||
 | 
			
		||||
    QStringList filters;
 | 
			
		||||
| 
						 | 
				
			
			@ -754,11 +742,7 @@ void UserInterface::showMessages(const QStringList messages)
 | 
			
		|||
{
 | 
			
		||||
    QDialog *messageDialog = new QDialog(this);
 | 
			
		||||
    messageDialog->setWindowTitle(tr("%1 - Messages").arg(GTA5SYNC_APPSTR));
 | 
			
		||||
#if QT_VERSION >= 0x050900
 | 
			
		||||
    messageDialog->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
 | 
			
		||||
#else
 | 
			
		||||
    messageDialog->setWindowFlags(messageDialog->windowFlags()^Qt::WindowContextHelpButtonHint);
 | 
			
		||||
#endif
 | 
			
		||||
    QVBoxLayout *messageLayout = new QVBoxLayout;
 | 
			
		||||
    messageDialog->setLayout(messageLayout);
 | 
			
		||||
    QStackedWidget *stackWidget = new QStackedWidget(messageDialog);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								src/libragephoto
									
										
									
									
									
										Submodule
									
								
							
							
						
						
									
										1
									
								
								src/libragephoto
									
										
									
									
									
										Submodule
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Subproject commit 8e732195493c4a4d5f120f290e77524645d8772e
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
/*****************************************************************************
 | 
			
		||||
* gta5view Grand Theft Auto V Profile Viewer
 | 
			
		||||
* Copyright (C) 2016-2021 Syping
 | 
			
		||||
* Copyright (C) 2016-2023 Syping
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -21,15 +21,12 @@
 | 
			
		|||
#include "ProfileDatabase.h"
 | 
			
		||||
#include "DatabaseThread.h"
 | 
			
		||||
#include "SavegameDialog.h"
 | 
			
		||||
#include "OptionsDialog.h"
 | 
			
		||||
#include "PictureDialog.h"
 | 
			
		||||
#include "UserInterface.h"
 | 
			
		||||
#include "CrewDatabase.h"
 | 
			
		||||
#include "SavegameData.h"
 | 
			
		||||
#include "UiModWidget.h"
 | 
			
		||||
#include "UiModLabel.h"
 | 
			
		||||
#include "IconLoader.h"
 | 
			
		||||
#include "AppEnv.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include <QStringBuilder>
 | 
			
		||||
#include <QSignalMapper>
 | 
			
		||||
| 
						 | 
				
			
			@ -227,7 +224,6 @@ int main(int argc, char *argv[])
 | 
			
		|||
        bool readOk = picture.readingPictureFromFile(arg1);
 | 
			
		||||
        picDialog.setWindowIcon(IconLoader::loadingAppIcon());
 | 
			
		||||
        picDialog.setSnapmaticPicture(&picture, readOk);
 | 
			
		||||
        picDialog.setWindowFlags(picDialog.windowFlags()^Qt::Dialog^Qt::Window);
 | 
			
		||||
 | 
			
		||||
        int crewID = picture.getSnapmaticProperties().crewID;
 | 
			
		||||
        if (crewID != 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +250,6 @@ int main(int argc, char *argv[])
 | 
			
		|||
        bool readOk = savegame.readingSavegameFromFile(arg1);
 | 
			
		||||
        savegameDialog.setWindowIcon(IconLoader::loadingAppIcon());
 | 
			
		||||
        savegameDialog.setSavegameData(&savegame, arg1, readOk);
 | 
			
		||||
        savegameDialog.setWindowFlags(savegameDialog.windowFlags()^Qt::Dialog^Qt::Window);
 | 
			
		||||
 | 
			
		||||
        if (!readOk)
 | 
			
		||||
            return 1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue