Skip to content

Commit d70caba

Browse files
committed
add GameFileTree
1 parent f863bd7 commit d70caba

File tree

7 files changed

+252
-145
lines changed

7 files changed

+252
-145
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ set(SOURCES_TESTS
4747
set(SOURCES_MC
4848
src/main.cpp
4949
src/binary.hpp
50-
src/gameTree.hpp
50+
src/GameFileTree.hpp
51+
src/GameFileTree.cpp
5152
src/staticData.hpp
5253
src/Network.hpp
5354
src/Network.cpp

src/Data.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ QVector<FileList> Data::getFileList(const int id) {
240240
query.bindValue(":id", id);
241241

242242
if (query.exec() == true) {
243-
while (query.next()) {
243+
while (query.next() == true) {
244244
list.append({
245245
query.value("path").toString(),
246246
query.value("md5sum").toString()});

src/FileManager.cpp

Lines changed: 65 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include <QtCore>
2121
#include <QByteArray>
2222
#include <QDataStream>
23-
#include "gameTree.hpp"
23+
#include "GameFileTree.hpp"
2424
#include "miniz.h"
2525
#include "miniz_zip.h"
2626

@@ -88,6 +88,7 @@ const QString FileManager::calculateMD5(
8888
bool FileManager::extractZip(
8989
const QString& zipFilename,
9090
const QString& outputFolder) {
91+
bool status = false;
9192
const QString& zipPath =
9293
QString("%1%2%3").arg(m_levelDir.absolutePath(), m_sep, zipFilename);
9394
const QString& outputPath =
@@ -103,77 +104,72 @@ bool FileManager::extractZip(
103104

104105
// Open the zip file
105106
mz_zip_archive zip;
106-
memset(&zip, 0, sizeof(zip));
107-
mz_bool result =
108-
mz_zip_reader_init_file(&zip, zipPath.toUtf8().constData(), 0);
109-
if (!result) {
110-
qWarning() << "Failed to open zip file" << zipPath;
111-
return false;
112-
}
113-
114-
// Extract each file in the zip archive
115-
mz_uint numFiles = mz_zip_reader_get_num_files(&zip);
116-
qDebug() << "Zip file contains" << numFiles << "files";
117-
118-
unsigned int gotoPercent = 50; // Percentage of total work
119-
unsigned int lastPrintedPercent = 0; // Last printed percentage
120-
121-
for (uint i = 0; i < numFiles; i++) {
122-
mz_zip_archive_file_stat file_stat;
123-
if (!mz_zip_reader_file_stat(&zip, i, &file_stat)) {
124-
qWarning() << "Failed to get file info for file" << i
125-
<< "in zip file" << zipPath;
126-
mz_zip_reader_end(&zip);
127-
return false;
128-
}
107+
(void)memset(&zip, 0, sizeof(zip));
108+
if (mz_zip_reader_init_file(
109+
&zip, zipPath.toUtf8().constData(), 0) == true) {
110+
// Extract each file in the zip archive
111+
quint64 numFiles = mz_zip_reader_get_num_files(&zip);
112+
qDebug() << "Zip file contains" << numFiles << "files";
113+
114+
quint64 gotoPercent = 50; // Percentage of total work
115+
quint64 lastPrintedPercent = 0; // Last printed percentage
116+
117+
for (quint64 i = 0; i < numFiles; i++) {
118+
mz_zip_archive_file_stat file_stat;
119+
if (!mz_zip_reader_file_stat(&zip, i, &file_stat)) {
120+
qWarning() << "Failed to get file info for file" << i
121+
<< "in zip file" << zipPath;
122+
mz_zip_reader_end(&zip);
123+
break;
124+
}
129125

130-
QString filename = QString::fromUtf8(file_stat.m_filename);
131-
if (filename.endsWith('/') == true) {
132-
continue; // Skip directories
133-
}
126+
QString filename = QString::fromUtf8(file_stat.m_filename);
127+
if (filename.endsWith('/') == true) {
128+
continue; // Skip directories
129+
}
134130

135-
QString outFile = outputPath + "/" + filename;
136-
qDebug() << "Extracting" << filename;
131+
QString outFile = QString("%1/%2").arg(outputPath, filename);
132+
qDebug() << "Extracting" << filename;
137133

138-
if (!QDir().mkpath(QFileInfo(outFile).path())) {
139-
qWarning() << "Failed to create directory for file" << outFile;
140-
mz_zip_reader_end(&zip);
141-
return false;
142-
}
143-
144-
if (!mz_zip_reader_extract_to_file(
145-
&zip,
146-
i,
147-
outFile.toUtf8().constData(),
148-
0)) {
149-
qWarning() << "Failed to extract file" << filename
150-
<< "from zip file" << zipPath;
151-
mz_zip_reader_end(&zip);
152-
return false;
153-
}
134+
if (!QDir().mkpath(QFileInfo(outFile).path())) {
135+
qWarning() << "Failed to create directory for file" << outFile;
136+
mz_zip_reader_end(&zip);
137+
break;
138+
}
154139

155-
unsigned int currentPercent = ((i + 1) * gotoPercent) / numFiles;
140+
if (!mz_zip_reader_extract_to_file(
141+
&zip,
142+
i,
143+
outFile.toUtf8().constData(),
144+
0)) {
145+
qWarning() << "Failed to extract file" << filename
146+
<< "from zip file" << zipPath;
147+
mz_zip_reader_end(&zip);
148+
break;
149+
}
156150

157-
if (currentPercent != lastPrintedPercent) {
158-
for (unsigned int j = lastPrintedPercent + 1;
159-
j <= currentPercent; j++) {
160-
emit this->fileWorkTickSignal();
161-
QCoreApplication::processEvents();
151+
quint64 currentPercent =
152+
((i + quint64(1)) * gotoPercent) / numFiles;
153+
154+
if (currentPercent != lastPrintedPercent) {
155+
for (quint64 j = lastPrintedPercent + quint64(1);
156+
j <= currentPercent; j++) {
157+
emit this->fileWorkTickSignal();
158+
QCoreApplication::processEvents();
159+
}
160+
lastPrintedPercent = currentPercent;
161+
if (currentPercent == gotoPercent) {
162+
status = true;
163+
}
162164
}
163-
lastPrintedPercent = currentPercent;
164165
}
166+
} else {
167+
qWarning() << "Failed to open zip file" << zipPath;
165168
}
166-
167-
// Ensure any remaining progress is emitted
168-
for (unsigned int j = lastPrintedPercent + 1; j <= gotoPercent; j++) {
169-
emit this->fileWorkTickSignal();
170-
QCoreApplication::processEvents();
171-
}
172-
173169
// Clean up
174170
mz_zip_reader_end(&zip);
175171
qDebug() << "Unzip complete";
176-
return true;
172+
return status;
177173
}
178174

179175
/**
@@ -219,15 +215,17 @@ bool FileManager::linkGameDir(const QString& levelDir, const QString& gameDir) {
219215
const QString gamePath = QString("%1%2")
220216
.arg(m_gameDir.absolutePath(), gameDir);
221217

222-
test(levelPath); // here we just output the directory tree for now..
218+
QDir dir(levelPath);
219+
GameFileTree test(dir);
220+
test.printTree(1);
223221

224222
if (QFile::link(levelPath, gamePath) == true) {
225223
qDebug() << "Symbolic link created successfully.";
226224
status = true;
227225
} else {
228226
QFileInfo fileInfo(gamePath);
229227
if (fileInfo.isSymLink() == true) {
230-
QFile::remove(gamePath);
228+
(void)QFile::remove(gamePath);
231229
if (QFile::link(levelPath, gamePath) == true) {
232230
qDebug() << "Symbolic link created successfully.";
233231
status = true;
@@ -261,7 +259,7 @@ bool FileManager::makeRelativeLink(
261259
} else {
262260
QFileInfo i(toPath);
263261
if (i.isSymLink() == true) {
264-
QFile::remove(toPath);
262+
(void)QFile::remove(toPath);
265263
if (QFile::link(fromPath, toPath) == true) {
266264
qDebug() << "Symbolic link created successfully.";
267265
status = true;
@@ -419,10 +417,10 @@ bool FileManager::moveFilesToDirectory(
419417
dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
420418

421419
// Move files and recursively move directories
422-
bool allMoved = std::all_of(
420+
return std::all_of(
423421
entryFileList.cbegin(),
424422
entryFileList.cend(),
425-
[&](const QString& entry) {
423+
[&](const QString& entry) -> bool {
426424
bool status = true;
427425

428426
QString entryPath = QString("%1%2%3")
@@ -435,10 +433,9 @@ bool FileManager::moveFilesToDirectory(
435433
<< entryPath << "to:" << destinationPath;
436434
status = false;
437435
}
438-
436+
// cppcheck-suppress misra-c2012-15.5
439437
return status;
440438
});
441-
return allMoved;
442439
}
443440

444441
bool FileManager::moveFilesToParentDirectory(

src/GameFileTree.cpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/* TombRaiderLinuxLauncher
2+
* Martin Bångens Copyright (C) 2024
3+
* This program is free software: you can redistribute it and/or modify
4+
* it under the terms of the GNU General Public License as published by
5+
* the Free Software Foundation, either version 3 of the License, or
6+
* (at your option) any later version.
7+
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
/* An GameFileTree object can contain
15+
* one tree of game files and can match another whole tree or branch.
16+
* It can print out the tree or a specific branch by index.
17+
* This object it used to recognise game files from TRLE's or
18+
* any distribution of the original Tomb Raider Games
19+
* a tree pattern can be matched from "root or branch"
20+
* This mean we have default tree objects to match with
21+
* like how we know if there is an exe file and ./data + ./audio
22+
* from there we can link to the correct game directory for the
23+
* launcher. We also do binary recognition for the Tomb Raider exe
24+
* and maybe other files. We compare/match and verify game files here.
25+
*/
26+
27+
#include "GameFileTree.hpp"
28+
#include <QDir>
29+
#include <QFileInfo>
30+
#include <QQueue>
31+
#include <QTextStream>
32+
33+
GameFileTree::GameFileTree(
34+
const QString &fileName, GameFileTree *parent)
35+
// cppcheck-suppress misra-c2012-12.3
36+
: m_fileName(fileName), m_parentItem(parent)
37+
{}
38+
39+
GameFileTree::~GameFileTree() {
40+
for (GameFileTree* child : m_childItems) {
41+
delete child;
42+
}
43+
}
44+
45+
46+
GameFileTree::GameFileTree(const QString& fileList) : m_parentItem(nullptr) {
47+
QStringList pathList = fileList.split("\n");
48+
addPathList(pathList);
49+
}
50+
51+
GameFileTree::GameFileTree(const QDir &dir) : m_parentItem(nullptr) {
52+
if (dir.exists() == true) {
53+
QStringList pathList;
54+
// Skapa en kö för att hantera kataloger iterativt
55+
QQueue<QString> dirQueue;
56+
dirQueue.enqueue(dir.absolutePath());
57+
58+
while (!dirQueue.isEmpty()) {
59+
QString currentDirPath = dirQueue.dequeue();
60+
QDir currentDir(currentDirPath);
61+
62+
// Hämta alla filer och mappar i den aktuella katalogen
63+
QFileInfoList fileList = currentDir.entryInfoList(
64+
QDir::Files |
65+
QDir::Dirs |
66+
QDir::NoDotAndDotDot |
67+
QDir::Hidden,
68+
QDir::Name);
69+
70+
for (const QFileInfo& fileInfo : fileList) {
71+
pathList << fileInfo.absoluteFilePath();
72+
73+
// Om objektet är en katalog, lägg till den i kön
74+
if (fileInfo.isDir() == true) {
75+
dirQueue.enqueue(fileInfo.absoluteFilePath());
76+
}
77+
}
78+
}
79+
addPathList(pathList);
80+
} else {
81+
QTextStream(stdout) << "Directory does not exist: "
82+
<< dir.absolutePath() << Qt::endl;
83+
}
84+
}
85+
86+
void GameFileTree::addPathList(const QStringList& pathList) {
87+
for (const QString& path : pathList) {
88+
QStringList components = QDir::toNativeSeparators(path).split(QDir::separator(), Qt::SkipEmptyParts);
89+
GameFileTree* current = this;
90+
91+
for (const QString& component : components) {
92+
// Check if a child node with this name already exists
93+
auto it = std::find_if(current->m_childItems.begin(), current->m_childItems.end(),
94+
[&component](GameFileTree* child) {
95+
return child->m_fileName == component;
96+
});
97+
98+
if (it == current->m_childItems.end()) {
99+
// Node doesn't exist, create it
100+
GameFileTree* newNode = new GameFileTree(component, current);
101+
current->m_childItems.append(newNode);
102+
current = newNode;
103+
} else {
104+
// Move to the existing node
105+
current = *it;
106+
}
107+
}
108+
}
109+
}
110+
111+
112+
void GameFileTree::printTree(int level) const {
113+
// Build the current node's path by traversing up to the root
114+
QString fullPath;
115+
const GameFileTree* currentNode = this;
116+
117+
while (currentNode != nullptr) {
118+
if (!currentNode->m_fileName.isEmpty()) {
119+
fullPath = currentNode->m_fileName + QDir::separator() + fullPath;
120+
}
121+
currentNode = currentNode->m_parentItem;
122+
}
123+
124+
// Print the full path for this node
125+
QTextStream(stdout) << fullPath << Qt::endl;
126+
127+
// Recursively call printTree on all child nodes
128+
for (const GameFileTree* child : m_childItems) {
129+
if (child != nullptr) {
130+
child->printTree(level + 1);
131+
}
132+
}
133+
}

src/GameFileTree.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* TombRaiderLinuxLauncher
2+
* Martin Bångens Copyright (C) 2024
3+
* This program is free software: you can redistribute it and/or modify
4+
* it under the terms of the GNU General Public License as published by
5+
* the Free Software Foundation, either version 3 of the License, or
6+
* (at your option) any later version.
7+
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#ifndef SRC_GAMEFILETREE_HPP_
15+
#define SRC_GAMEFILETREE_HPP_
16+
17+
#include <QString>
18+
#include <QVector>
19+
#include <QDir>
20+
#include <QStringList>
21+
#include <QDebug>
22+
23+
class GameFileTree {
24+
public:
25+
explicit GameFileTree(const QDir& fullPath);
26+
explicit GameFileTree(const QString& fileList);
27+
~GameFileTree();
28+
29+
void printTree(int level) const;
30+
31+
private:
32+
explicit GameFileTree(
33+
const QString &fileName, GameFileTree *parentItem);
34+
void addPathList(const QStringList& pathList);
35+
void addNode(GameFileTree* node); // maybe dont need this
36+
QVector<GameFileTree*> m_childItems;
37+
QString m_fileName;
38+
GameFileTree *m_parentItem;
39+
};
40+
41+
#endif // SRC_GAMEFILETREE_HPP_

0 commit comments

Comments
 (0)