summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--CMakeLists.txt2
-rw-r--r--heimdall-frontend/CMakeLists.txt8
-rw-r--r--heimdall-frontend/source/FirmwareInfo.cpp10
-rw-r--r--heimdall-frontend/source/GZipFile.cpp51
-rw-r--r--heimdall-frontend/source/GZipFile.h81
-rw-r--r--heimdall-frontend/source/PackageData.cpp33
-rw-r--r--heimdall-frontend/source/PackageData.h27
-rw-r--r--heimdall-frontend/source/Packaging.cpp318
-rw-r--r--heimdall-frontend/source/Packaging.h16
-rw-r--r--heimdall-frontend/source/aboutform.cpp6
-rw-r--r--heimdall-frontend/source/mainwindow.cpp104
-rw-r--r--heimdall-frontend/source/mainwindow.h2
-rw-r--r--heimdall-frontend/source/qml/DropFiles.qml27
-rw-r--r--heimdall-frontend/source/qml/FileUtils.js44
-rw-r--r--heimdall-frontend/source/qml/qml.qrc5
16 files changed, 445 insertions, 292 deletions
diff --git a/.gitignore b/.gitignore
index de1c512..cc506df 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.DS_Store
._*
.idea/
-/build/
+/*build/
+CMakeLists.txt.user
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 258fcb2..4fb8acf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,5 @@
cmake_minimum_required(VERSION 2.8.11)
-set(Qt5Quick_DIR "/usr/local/Cellar/qt5/5.4.0/lib/cmake/Qt5Quick" CACHE FILEPATH "Qt5Quick path" FORCE)
-
set(CMAKE_MODULE_PATH
${CMAKE_SOURCE_DIR}/cmake
${CMAKE_MODULE_PATH})
diff --git a/heimdall-frontend/CMakeLists.txt b/heimdall-frontend/CMakeLists.txt
index ceaffd0..da572cb 100644
--- a/heimdall-frontend/CMakeLists.txt
+++ b/heimdall-frontend/CMakeLists.txt
@@ -29,17 +29,19 @@ set(HEIMDALL_FRONTEND_SOURCE_FILES
source/aboutform.cpp
source/Alerts.cpp
source/FirmwareInfo.cpp
+ source/GZipFile.cpp
source/main.cpp
source/mainwindow.cpp
source/PackageData.cpp
source/Packaging.cpp)
set(HEIMDALL_FRONTEND_QML_FILES
+ source/qml/DropFiles.qml
+ source/qml/DropFilesForm.qml
+ source/qml/FileUtils.js
source/qml/main.qml
source/qml/Root.qml
- source/qml/RootForm.qml
- source/qml/DropFiles.qml
- source/qml/DropFilesForm.qml)
+ source/qml/RootForm.qml)
qt5_wrap_ui(HEIMDALL_FRONTEND_FORMS
mainwindow.ui
diff --git a/heimdall-frontend/source/FirmwareInfo.cpp b/heimdall-frontend/source/FirmwareInfo.cpp
index c01d636..7a1043c 100644
--- a/heimdall-frontend/source/FirmwareInfo.cpp
+++ b/heimdall-frontend/source/FirmwareInfo.cpp
@@ -720,10 +720,10 @@ void FirmwareInfo::WriteXml(QXmlStreamWriter& xml) const
xml.writeStartElement("developers");
- for (int i = 0; i < developers.length(); i++)
+ for (const QString& developer : developers)
{
xml.writeStartElement("name");
- xml.writeCharacters(developers[i]);
+ xml.writeCharacters(developer);
xml.writeEndElement();
}
@@ -745,8 +745,10 @@ void FirmwareInfo::WriteXml(QXmlStreamWriter& xml) const
xml.writeStartElement("devices");
- for (int i = 0; i < deviceInfos.length(); i++)
- deviceInfos[i].WriteXml(xml);
+ for (const DeviceInfo& deviceInfo : deviceInfos)
+ {
+ deviceInfo.WriteXml(xml);
+ }
xml.writeEndElement();
diff --git a/heimdall-frontend/source/GZipFile.cpp b/heimdall-frontend/source/GZipFile.cpp
new file mode 100644
index 0000000..af75f39
--- /dev/null
+++ b/heimdall-frontend/source/GZipFile.cpp
@@ -0,0 +1,51 @@
+#import "GZipFile.h"
+
+using namespace HeimdallFrontend;
+
+GZipFile::GZipFile(const QString& path) :
+ file(path),
+ gzFile(nullptr)
+{
+}
+
+GZipFile::~GZipFile()
+{
+ Close();
+
+ if (temporary)
+ {
+ file.remove();
+ }
+}
+
+bool GZipFile::Open(Mode mode)
+{
+ if (!file.isOpen() && !file.open(mode == GZipFile::ReadOnly ? QFile::ReadOnly : QFile::WriteOnly))
+ {
+ return (false);
+ }
+
+ gzFile = gzdopen(file.handle(), mode == GZipFile::ReadOnly ? "rb" : "wb");
+ return (gzFile != nullptr);
+}
+
+void GZipFile::Close()
+{
+ file.close();
+ gzclose(gzFile);
+}
+
+int GZipFile::Read(void *buffer, int length)
+{
+ return (length >= 0 && !file.isWritable() ? gzread(gzFile, buffer, length) : -1);
+}
+
+bool GZipFile::Write(void *buffer, int length)
+{
+ return (length >= 0 && gzwrite(gzFile, buffer, length) == length);
+}
+
+qint64 GZipFile::Offset() const
+{
+ return gzoffset(gzFile);
+}
diff --git a/heimdall-frontend/source/GZipFile.h b/heimdall-frontend/source/GZipFile.h
new file mode 100644
index 0000000..c4e225c
--- /dev/null
+++ b/heimdall-frontend/source/GZipFile.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 2010-2014 Benjamin Dobell, Glass Echidna
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+#ifndef GZIPFILE_H
+#define GZIPFILE_H
+
+// Qt
+#include <QFile>
+#include <qglobal.h>
+
+// zlib
+#include "zlib.h"
+
+namespace HeimdallFrontend
+{
+ class GZipFile
+ {
+ public:
+
+ enum Mode
+ {
+ ReadOnly = 0,
+ WriteOnly
+ };
+
+ private:
+
+ QFile file;
+ gzFile gzFile;
+
+ bool temporary;
+
+ public:
+
+ GZipFile(const QString& path);
+ ~GZipFile();
+
+ bool Open(Mode mode);
+ void Close();
+
+ int Read(void *buffer, int length);
+ bool Write(void *buffer, int length);
+
+ qint64 Offset() const;
+
+ bool IsTemporary() const
+ {
+ return temporary;
+ }
+
+ // Delete the file when we go out of scope?
+ void SetTemporary(bool temporary)
+ {
+ this->temporary = temporary;
+ }
+
+ qint64 Size() const
+ {
+ return file.size();
+ }
+ };
+}
+
+#endif
diff --git a/heimdall-frontend/source/PackageData.cpp b/heimdall-frontend/source/PackageData.cpp
index c3689b3..23ef720 100644
--- a/heimdall-frontend/source/PackageData.cpp
+++ b/heimdall-frontend/source/PackageData.cpp
@@ -30,37 +30,40 @@ PackageData::PackageData()
PackageData::~PackageData()
{
- for (int i = 0; i < files.length(); i++)
- delete files[i];
+ Clear(true);
}
-void PackageData::Clear(void)
+void PackageData::Clear(bool deletePackageDirectory)
{
- firmwareInfo.Clear();
-
- for (int i = 0; i < files.length(); i++)
- delete files[i];
+ if (deletePackageDirectory)
+ {
+ packageDirectory.removeRecursively();
+ }
- files.clear();
+ packageDirectory.setPath(QString());
+ firmwareInfo.Clear();
+ filePaths.clear();
}
-bool PackageData::ReadFirmwareInfo(QFile *file)
+bool PackageData::ReadFirmwareInfo(const QString& path)
{
- if (!file->open(QFile::ReadOnly))
+ QFile file(path);
+
+ if (!file.open(QFile::ReadOnly))
{
- Alerts::DisplayError(QString("Failed to open file: \1%s").arg(file->fileName()));
+ Alerts::DisplayError(QString("Failed to open file: %1").arg(path));
return (false);
}
- QXmlStreamReader xml(file);
+ QXmlStreamReader xml(&file);
bool success = firmwareInfo.ParseXml(xml);
- file->close();
-
return (success);
}
bool PackageData::IsCleared(void) const
{
- return (firmwareInfo.IsCleared() && files.isEmpty());
+ return (packageDirectory.path().length() == 0
+ && firmwareInfo.IsCleared()
+ && filePaths.isEmpty());
}
diff --git a/heimdall-frontend/source/PackageData.h b/heimdall-frontend/source/PackageData.h
index 84f081c..28be679 100644
--- a/heimdall-frontend/source/PackageData.h
+++ b/heimdall-frontend/source/PackageData.h
@@ -22,7 +22,7 @@
#define PACKAGEDATA_H
// Qt
-#include <QTemporaryFile>
+#include <QDir>
// Heimdall Frontend
#include "FirmwareInfo.h"
@@ -34,15 +34,16 @@ namespace HeimdallFrontend
private:
FirmwareInfo firmwareInfo;
- QList<QTemporaryFile *> files;
+ QList<QString> filePaths;
+ QDir packageDirectory;
public:
PackageData();
~PackageData();
- void Clear(void);
- bool ReadFirmwareInfo(QFile *file);
+ void Clear(bool deletePackageDirectory = true);
+ bool ReadFirmwareInfo(const QString& path);
bool IsCleared(void) const;
@@ -56,20 +57,24 @@ namespace HeimdallFrontend
return (firmwareInfo);
}
- const QList<QTemporaryFile *>& GetFiles(void) const
+ const QList<QString>& GetFilePaths(void) const
{
- return (files);
+ return (filePaths);
}
- QList<QTemporaryFile *>& GetFiles(void)
+ QList<QString>& GetFilePaths(void)
{
- return (files);
+ return (filePaths);
}
- // Simply clears the files list, it does delete/close any files.
- void RemoveAllFiles(void)
+ void SetPackagePath(const QString& path)
{
- files.clear();
+ packageDirectory.setPath(path);
+ }
+
+ QString GetPackagePath() const
+ {
+ return packageDirectory.path();
}
};
}
diff --git a/heimdall-frontend/source/Packaging.cpp b/heimdall-frontend/source/Packaging.cpp
index 7a27b3c..7e0e1c0 100644
--- a/heimdall-frontend/source/Packaging.cpp
+++ b/heimdall-frontend/source/Packaging.cpp
@@ -30,31 +30,85 @@
// Qt
#include <QDateTime>
-#include <QDir>
#include <QProgressDialog>
+#include <QTemporaryDir>
+#include <QTemporaryFile>
// Heimdall Frontend
#include "Alerts.h"
#include "Packaging.h"
+#include "GZipFile.h"
using namespace HeimdallFrontend;
-const qint64 Packaging::kMaxFileSize = 8589934592ll;
+const qint64 Packaging::kMaxFileSize = 4294967295ll;
const char *Packaging::ustarMagic = "ustar";
-bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
+bool Packaging::DecompressGZippedFile(const QString &path, const QString &outputPath)
+{
+ GZipFile gzipFile(path);
+
+ if (!gzipFile.Open(GZipFile::ReadOnly))
+ {
+ Alerts::DisplayError(QString("Failed to open file:\n%1").arg(path));
+ return (false);
+ }
+
+ qint64 compressedFileSize = gzipFile.Size();
+
+ QFile outputFile(outputPath);
+
+ if (!outputFile.open(QIODevice::WriteOnly))
+ {
+ Alerts::DisplayError(QString("Failed to open decompression output file:\n%1").arg(outputFile.fileName()));
+ return (false);
+ }
+
+ QProgressDialog progressDialog("Decompressing...", "Cancel", 0, 1000);
+ progressDialog.setWindowModality(Qt::ApplicationModal);
+ progressDialog.setWindowTitle("Heimdall Frontend");
+
+ char buffer[kExtractBufferLength];
+ int bytesRead;
+
+ do
+ {
+ bytesRead = gzipFile.Read(buffer, kExtractBufferLength);
+
+ if (bytesRead == -1)
+ {
+ progressDialog.close();
+ Alerts::DisplayError("Error decompressing archive.");
+ return (false);
+ }
+
+ outputFile.write(buffer, bytesRead);
+ progressDialog.setValue((1000ll * gzipFile.Offset()) / compressedFileSize);
+
+ if (progressDialog.wasCanceled())
+ {
+ return (false);
+ }
+ } while (bytesRead > 0);
+
+ progressDialog.close();
+ return (true);
+}
+
+bool Packaging::ExtractTar(QFile& tarFile, const QDir& outputDirectory, QList<QString>& outputFilePaths)
{
TarHeader tarHeader;
- if (!tarFile.open())
+ if (!tarFile.open(QFile::ReadOnly))
{
- Alerts::DisplayError(QString("Error opening temporary TAR archive:\n%1").arg(tarFile.fileName()));
+ Alerts::DisplayError(QString("Error opening archive:\n%1").arg(tarFile.fileName()));
return (false);
}
bool previousEmpty = false;
- QProgressDialog progressDialog("Extracting files...", "Cancel", 0, tarFile.size());
+ qint64 tarFileSize = tarFile.size();
+ QProgressDialog progressDialog("Extracting archive...", "Cancel", 0, 1000);
progressDialog.setWindowModality(Qt::ApplicationModal);
progressDialog.setWindowTitle("Heimdall Frontend");
@@ -82,7 +136,6 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
return (false);
}
- //bool ustarFormat = strcmp(tarHeader.fields.magic, ustarMagic) == 0;
bool empty = true;
for (int i = 0; i < TarHeader::kBlockLength; i++)
@@ -104,21 +157,6 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
}
else
{
- int checksum = 0;
-
- for (char *bufferIndex = tarHeader.buffer; bufferIndex < tarHeader.fields.checksum; bufferIndex++)
- checksum += static_cast<unsigned char>(*bufferIndex);
-
- checksum += 8 * ' ';
- checksum += static_cast<unsigned char>(tarHeader.fields.typeFlag);
-
- // Both the TAR and USTAR formats have terrible documentation, it's not clear if the following code is required.
- /*if (ustarFormat)
- {
- for (char *bufferIndex = tarHeader.fields.linkName; bufferIndex < tarHeader.fields.prefix + 155; bufferIndex++)
- checksum += static_cast<unsigned char>(*bufferIndex);
- }*/
-
bool parsed = false;
// The size field is not always null terminated, so we must create a copy and null terminate it for parsing.
@@ -143,19 +181,21 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
// We're working with a file.
QString filename = QString::fromUtf8(tarHeader.fields.name);
- QTemporaryFile *outputFile = new QTemporaryFile("XXXXXX-" + filename);
- packageData->GetFiles().append(outputFile);
+ QString filePath = outputDirectory.path() + "/" + filename;
+ QFile outputFile(filePath);
- if (!outputFile->open())
+ if (!outputFile.open(QFile::WriteOnly))
{
progressDialog.close();
- Alerts::DisplayError(QString("Failed to open output file: \n%1").arg(outputFile->fileName()));
+ Alerts::DisplayError(QString("Failed to open output file: \n%1").arg(outputFile.fileName()));
tarFile.close();
return (false);
}
+ outputFilePaths.append(filePath);
+
qulonglong dataRemaining = fileSize;
char readBuffer[TarHeader::kBlockReadCount * TarHeader::kBlockLength];
@@ -173,25 +213,23 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
Alerts::DisplayError("Unexpected read error whilst extracting package files.");
tarFile.close();
- outputFile->close();
-
- remove(outputFile->fileName().toStdString().c_str());
+ outputFile.close();
+ outputFile.remove();
return (false);
}
- outputFile->write(readBuffer, fileDataToRead);
+ outputFile.write(readBuffer, fileDataToRead);
dataRemaining -= fileDataToRead;
- progressDialog.setValue(tarFile.pos());
+ progressDialog.setValue((1000ll * tarFile.pos()) / tarFileSize);
if (progressDialog.wasCanceled())
{
tarFile.close();
- outputFile->close();
-
- remove(outputFile->fileName().toStdString().c_str());
+ outputFile.close();
+ outputFile.remove();
progressDialog.close();
@@ -199,7 +237,7 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
}
}
- outputFile->close();
+ outputFile.close();
}
else
{
@@ -221,7 +259,7 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
return (true);
}
-bool Packaging::WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile, const QString& entryFilename)
+bool Packaging::WriteTarEntry(const QString& entryFilename, const QString& filePath, QFile& outputTarFile)
{
TarHeader tarHeader;
memset(tarHeader.buffer, 0, TarHeader::kBlockLength);
@@ -316,7 +354,7 @@ bool Packaging::WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile,
sprintf(tarHeader.fields.checksum, "%07o", checksum);
// Write the header to the TAR file.
- tarFile->write(tarHeader.buffer, TarHeader::kBlockLength);
+ outputTarFile.write(tarHeader.buffer, TarHeader::kBlockLength);
char buffer[TarHeader::kBlockWriteCount * TarHeader::kBlockLength];
qint64 offset = 0;
@@ -325,7 +363,7 @@ bool Packaging::WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile,
{
qint64 dataRead = file.read(buffer, TarHeader::kBlockWriteCount * TarHeader::kBlockLength);
- if (tarFile->write(buffer, dataRead) != dataRead)
+ if (outputTarFile.write(buffer, dataRead) != dataRead)
{
Alerts::DisplayError("Failed to write data to the temporary TAR file.");
return (false);
@@ -336,7 +374,7 @@ bool Packaging::WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile,
int remainingBlockLength = TarHeader::kBlockLength - dataRead % TarHeader::kBlockLength;
memset(buffer, 0, remainingBlockLength);
- if (tarFile->write(buffer, remainingBlockLength) != remainingBlockLength)
+ if (outputTarFile.write(buffer, remainingBlockLength) != remainingBlockLength)
{
Alerts::DisplayError("Failed to write data to the temporary TAR file.");
return (false);
@@ -349,7 +387,7 @@ bool Packaging::WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile,
return (true);
}
-bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarFile)
+bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QFile& outputTarFile)
{
const QList<FileInfo>& fileInfos = firmwareInfo.GetFileInfos();
@@ -371,10 +409,10 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF
firmwareInfo.WriteXml(xml);
firmwareXmlFile.close();
- if (!tarFile->open())
+ if (!outputTarFile.open(QFile::WriteOnly))
{
progressDialog.close();
- Alerts::DisplayError(QString("Failed to open file: \n%1").arg(tarFile->fileName()));
+ Alerts::DisplayError(QString("Failed to open file: \n%1").arg(outputTarFile.fileName()));
return (false);
}
@@ -407,10 +445,10 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF
return (false);
}
- if (!WriteTarEntry(fileInfos[i].GetFilename(), tarFile, filename))
+ if (!WriteTarEntry(filename, fileInfos[i].GetFilename(), outputTarFile))
{
- tarFile->resize(0);
- tarFile->close();
+ outputTarFile.resize(0);
+ outputTarFile.close();
progressDialog.close();
@@ -421,8 +459,8 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF
if (progressDialog.wasCanceled())
{
- tarFile->resize(0);
- tarFile->close();
+ outputTarFile.resize(0);
+ outputTarFile.close();
progressDialog.close();
@@ -443,10 +481,10 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF
return (false);
}
- if (!WriteTarEntry(firmwareInfo.GetPitFilename(), tarFile, pitFilename))
+ if (!WriteTarEntry(pitFilename, firmwareInfo.GetPitFilename(), outputTarFile))
{
- tarFile->resize(0);
- tarFile->close();
+ outputTarFile.resize(0);
+ outputTarFile.close();
return (false);
}
@@ -455,18 +493,18 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF
if (progressDialog.wasCanceled())
{
- tarFile->resize(0);
- tarFile->close();
+ outputTarFile.resize(0);
+ outputTarFile.close();
progressDialog.close();
return (false);
}
- if (!WriteTarEntry(firmwareXmlFile.fileName(), tarFile, "firmware.xml"))
+ if (!WriteTarEntry("firmware.xml", firmwareXmlFile.fileName(), outputTarFile))
{
- tarFile->resize(0);
- tarFile->close();
+ outputTarFile.resize(0);
+ outputTarFile.close();
return (false);
}
@@ -478,97 +516,51 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF
char emptyEntry[TarHeader::kBlockLength];
memset(emptyEntry, 0, TarHeader::kBlockLength);
- tarFile->write(emptyEntry, TarHeader::kBlockLength);
- tarFile->write(emptyEntry, TarHeader::kBlockLength);
+ outputTarFile.write(emptyEntry, TarHeader::kBlockLength);
+ outputTarFile.write(emptyEntry, TarHeader::kBlockLength);
- tarFile->close();
+ outputTarFile.close();
return (true);
}
-bool Packaging::ExtractPackage(const QString& packagePath, PackageData *packageData)
+bool Packaging::ExtractPackage(const QString& packagePath, PackageData& packageData)
{
- FILE *compressedPackageFile = fopen(packagePath.toStdString().c_str(), "rb");
+ QTemporaryDir outputDirectory;
- if (!compressedPackageFile)
+ if (!outputDirectory.isValid())
{
- Alerts::DisplayError(QString("Failed to open package:\n%1").arg(packagePath));
+ Alerts::DisplayError("Failed to create package output directory.");
return (false);
}
- fseek(compressedPackageFile, 0, SEEK_END);
- quint64 compressedFileSize = ftell(compressedPackageFile);
- rewind(compressedPackageFile);
-
- gzFile packageFile = gzdopen(fileno(compressedPackageFile), "rb");
+ QTemporaryFile tarFile;
+ tarFile.open();
+ tarFile.close();
- QTemporaryFile outputTar("XXXXXX.tar");
+ QList<QString> decompressedFilePaths;
- if (!outputTar.open())
+ if (!DecompressGZippedFile(packagePath, tarFile.fileName())
+ || !ExtractTar(tarFile, QDir(outputDirectory.path()), decompressedFilePaths))
{
- Alerts::DisplayError("Failed to open temporary TAR archive.");
- gzclose(packageFile);
-
return (false);
}
- char buffer[kExtractBufferLength];
- int bytesRead;
- quint64 totalBytesRead = 0;
-
- QProgressDialog progressDialog("Decompressing package...", "Cancel", 0, compressedFileSize);
- progressDialog.setWindowModality(Qt::ApplicationModal);
- progressDialog.setWindowTitle("Heimdall Frontend");
-
- do
- {
- bytesRead = gzread(packageFile, buffer, kExtractBufferLength);
-
- if (bytesRead == -1)
- {
- progressDialog.close();
- Alerts::DisplayError("Error decompressing archive.");
-
- gzclose(packageFile);
-
- return (false);
- }
-
- outputTar.write(buffer, bytesRead);
-
- totalBytesRead += bytesRead;
- progressDialog.setValue(totalBytesRead);
-
- if (progressDialog.wasCanceled())
- {
- gzclose(packageFile);
- progressDialog.close();
-
- return (false);
- }
- } while (bytesRead > 0);
-
- progressDialog.close();
-
- outputTar.close();
- gzclose(packageFile); // Closes packageFile and compressedPackageFile
-
- if (!ExtractTar(outputTar, packageData))
- return (false);
-
// Find and read firmware.xml
- for (int i = 0; i < packageData->GetFiles().length(); i++)
+ for (const QString& path : decompressedFilePaths)
{
- QTemporaryFile *file = packageData->GetFiles()[i];
-
- if (file->fileTemplate() == "XXXXXX-firmware.xml")
+ if (path.endsWith("firmware.xml"))
{
- if (!packageData->ReadFirmwareInfo(file))
+ if (!packageData.ReadFirmwareInfo(path))
{
- packageData->Clear();
+ packageData.Clear();
return (false);
}
+ outputDirectory.setAutoRemove(false);
+
+ packageData.GetFilePaths().append(decompressedFilePaths);
+ packageData.SetPackagePath(outputDirectory.path());
return (true);
}
}
@@ -579,44 +571,39 @@ bool Packaging::ExtractPackage(const QString& packagePath, PackageData *packageD
bool Packaging::BuildPackage(const QString& packagePath, const FirmwareInfo& firmwareInfo)
{
- FILE *compressedPackageFile = fopen(packagePath.toStdString().c_str(), "wb");
+ GZipFile packageFile(packagePath);
- if (!compressedPackageFile)
+ if (!packageFile.Open(GZipFile::WriteOnly))
{
Alerts::DisplayError(QString("Failed to create package:\n%1").arg(packagePath));
return (false);
}
+ packageFile.SetTemporary(true);
+
QTemporaryFile tar("XXXXXX.tar");
- if (!CreateTar(firmwareInfo, &tar))
+ if (!CreateTar(firmwareInfo, tar))
{
- fclose(compressedPackageFile);
- remove(packagePath.toStdString().c_str());
-
return (false);
}
if (!tar.open())
{
Alerts::DisplayError(QString("Failed to open temporary file: \n%1").arg(tar.fileName()));
-
- fclose(compressedPackageFile);
- remove(packagePath.toStdString().c_str());
-
return (false);
}
-
- gzFile packageFile = gzdopen(fileno(compressedPackageFile), "wb");
char buffer[kCompressBufferLength];
qint64 totalBytesRead = 0;
- int bytesRead;
- QProgressDialog progressDialog("Compressing package...", "Cancel", 0, tar.size());
+ quint64 tarSize = tar.size();
+ QProgressDialog progressDialog("Compressing package...", "Cancel", 0, 1000);
progressDialog.setWindowModality(Qt::ApplicationModal);
progressDialog.setWindowTitle("Heimdall Frontend");
+ int bytesRead;
+
do
{
bytesRead = tar.read(buffer, kCompressBufferLength);
@@ -625,42 +612,29 @@ bool Packaging::BuildPackage(const QString& packagePath, const FirmwareInfo& fir
{
progressDialog.close();
Alerts::DisplayError("Error reading temporary TAR file.");
-
- gzclose(packageFile);
- remove(packagePath.toStdString().c_str());
-
return (false);
}
- if (gzwrite(packageFile, buffer, bytesRead) != bytesRead)
+ if (!packageFile.Write(buffer, bytesRead))
{
progressDialog.close();
Alerts::DisplayError("Error compressing package.");
-
- gzclose(packageFile);
- remove(packagePath.toStdString().c_str());
-
return (false);
}
totalBytesRead += bytesRead;
- progressDialog.setValue(totalBytesRead);
+ progressDialog.setValue((1000ll * totalBytesRead) / tarSize);
if (progressDialog.wasCanceled())
{
- gzclose(packageFile);
- remove(packagePath.toStdString().c_str());
-
progressDialog.close();
-
return (false);
}
} while (bytesRead > 0);
progressDialog.close();
- gzclose(packageFile); // Closes packageFile and compressedPackageFile
-
+ packageFile.SetTemporary(false);
return (true);
}
@@ -709,14 +683,14 @@ QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, int fileI
bool validIndexOffset = true;
// Before we append a rename index we must ensure it doesn't produce further collisions.
- for (int i = 0; i < fileInfos.length(); i++)
+ for (const FileInfo& fileInfo : fileInfos)
{
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
+ int lastSlash = fileInfo.GetFilename().lastIndexOf('/');
if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
+ lastSlash = fileInfo.GetFilename().lastIndexOf('\\');
- QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
+ QString otherFilename = fileInfo.GetFilename().mid(lastSlash + 1);
if (otherFilename.length() > filename.length() + 1)
{
@@ -778,14 +752,14 @@ QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, int fileI
bool valid = true;
- for (int i = 0; i < fileInfos.length(); i++)
+ for (const FileInfo& fileInfo : fileInfos)
{
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
+ int lastSlash = fileInfo.GetFilename().lastIndexOf('/');
if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
+ lastSlash = fileInfo.GetFilename().lastIndexOf('\\');
- if (filename == fileInfos[i].GetFilename().mid(lastSlash + 1))
+ if (filename == fileInfo.GetFilename().mid(lastSlash + 1))
{
valid = false;
break;
@@ -809,14 +783,14 @@ QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, const QSt
unsigned int renameIndex = 0;
// Check for name clashes
- for (int i = 0; i < fileInfos.length(); i++)
+ for (const FileInfo& fileInfo : fileInfos)
{
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
+ int lastSlash = fileInfo.GetFilename().lastIndexOf('/');
if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
+ lastSlash = fileInfo.GetFilename().lastIndexOf('\\');
- QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
+ QString otherFilename = fileInfo.GetFilename().mid(lastSlash + 1);
if (filename == otherFilename)
renameIndex++;
@@ -842,14 +816,14 @@ QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, const QSt
bool validIndexOffset = true;
// Before we append a rename index we must ensure it doesn't produce further collisions.
- for (int i = 0; i < fileInfos.length(); i++)
+ for (const FileInfo& fileInfo : fileInfos)
{
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
+ int lastSlash = fileInfo.GetFilename().lastIndexOf('/');
if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
+ lastSlash = fileInfo.GetFilename().lastIndexOf('\\');
- QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
+ QString otherFilename = fileInfo.GetFilename().mid(lastSlash + 1);
if (otherFilename.length() > filename.length() + 1)
{
@@ -909,14 +883,14 @@ QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, const QSt
for (int i = 0; i < 8; i++)
filename.append(QChar(qrand() % ('Z' - 'A' + 1) + 'A'));
- for (int i = 0; i < fileInfos.length(); i++)
+ for (const FileInfo& fileInfo : fileInfos)
{
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
+ int lastSlash = fileInfo.GetFilename().lastIndexOf('/');
if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
+ lastSlash = fileInfo.GetFilename().lastIndexOf('\\');
- if (filename == fileInfos[i].GetFilename().mid(lastSlash + 1))
+ if (filename == fileInfo.GetFilename().mid(lastSlash + 1))
{
valid = false;
break;
diff --git a/heimdall-frontend/source/Packaging.h b/heimdall-frontend/source/Packaging.h
index 8ba83f7..80b6d81 100644
--- a/heimdall-frontend/source/Packaging.h
+++ b/heimdall-frontend/source/Packaging.h
@@ -22,9 +22,7 @@
#define PACKAGING_H
// Qt
-#include <QList>
-#include <QString>
-#include <QTemporaryFile>
+#include <QDir>
// Heimdall Frontend
#include "PackageData.h"
@@ -99,18 +97,20 @@ namespace HeimdallFrontend
kExtractBufferLength = 262144,
kCompressBufferLength = 262144
};
-
+
+ static bool DecompressGZippedFile(const QString &path, const QString &outputPath);
+
// TODO: Add support for sparse files to both methods?
- static bool ExtractTar(QTemporaryFile& tarFile, PackageData *packageData);
+ static bool ExtractTar(QFile& tarFile, const QDir& outputDirectory, QList<QString>& outputFilePaths);
- static bool WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile, const QString& entryFilename);
- static bool CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarFile); // Uses original TAR format.
+ static bool WriteTarEntry(const QString& entryFilename, const QString& filePath, QFile& outputTarFile);
+ static bool CreateTar(const FirmwareInfo& firmwareInfo, QFile& outputTarFile); // Uses original TAR format.
public:
static const char *ustarMagic;
- static bool ExtractPackage(const QString& packagePath, PackageData *packageData);
+ static bool ExtractPackage(const QString& packagePath, PackageData& packageData);
static bool BuildPackage(const QString& packagePath, const FirmwareInfo& firmwareInfo);
static QString ClashlessFilename(const QList<FileInfo>& fileInfos, int fileInfoIndex);
diff --git a/heimdall-frontend/source/aboutform.cpp b/heimdall-frontend/source/aboutform.cpp
index 93e56fb..4be8a1b 100644
--- a/heimdall-frontend/source/aboutform.cpp
+++ b/heimdall-frontend/source/aboutform.cpp
@@ -60,11 +60,11 @@ void AboutForm::RetrieveHeimdallVersion(void)
QStringList paths;
// Ensure /usr/bin is in PATH
- for (int i = 0; i < environment.length(); i++)
+ for (const QString& var : environment)
{
- if (environment[i].left(5) == "PATH=")
+ if (var.left(5) == "PATH=")
{
- paths = environment[i].mid(5).split(':');
+ paths = var.mid(5).split(':');
paths.prepend("/usr/bin");
break;
}
diff --git a/heimdall-frontend/source/mainwindow.cpp b/heimdall-frontend/source/mainwindow.cpp
index e110d69..ab83105 100644
--- a/heimdall-frontend/source/mainwindow.cpp
+++ b/heimdall-frontend/source/mainwindow.cpp
@@ -53,11 +53,11 @@ void MainWindow::StartHeimdall(const QStringList& arguments)
QStringList paths;
// Ensure /usr/local/bin and /usr/bin are in PATH.
- for (int i = 0; i < environment.length(); i++)
+ for (const QString& var : environment)
{
- if (environment[i].left(5) == "PATH=")
+ if (var.left(5) == "PATH=")
{
- paths = environment[i].mid(5).split(':');
+ paths = var.mid(5).split(':');
if (!paths.contains("/usr/local/bin"))
paths.prepend("/usr/local/bin");
@@ -114,21 +114,20 @@ void MainWindow::UpdateUnusedPartitionIds(void)
}
// Remove any used partition IDs from unusedPartitionIds
- QList<FileInfo>& fileList = workingPackageData.GetFirmwareInfo().GetFileInfos();
-
- for (int i = 0; i < fileList.length(); i++)
- unusedPartitionIds.removeOne(fileList[i].GetPartitionId());
+ for (const FileInfo& fileInfo : workingPackageData.GetFirmwareInfo().GetFileInfos())
+ unusedPartitionIds.removeOne(fileInfo.GetPartitionId());
}
-bool MainWindow::ReadPit(QFile *file)
+bool MainWindow::ReadPit(const QString& path)
{
- if(!file->open(QIODevice::ReadOnly))
+ QFile pitFile(path);
+
+ if (!pitFile.open(QIODevice::ReadOnly))
return (false);
- unsigned char *buffer = new unsigned char[file->size()];
+ unsigned char *buffer = new unsigned char[pitFile.size()];
- file->read(reinterpret_cast<char *>(buffer), file->size());
- file->close();
+ pitFile.read(reinterpret_cast<char *>(buffer), pitFile.size());
bool success = currentPitData.Unpack(buffer);
delete buffer;
@@ -176,15 +175,13 @@ void MainWindow::UpdatePackageUserInterface(void)
platformLineEdit->setText(loadedPackageData.GetFirmwareInfo().GetPlatformInfo().GetName() + " ("
+ loadedPackageData.GetFirmwareInfo().GetPlatformInfo().GetVersion() + ")");
- for (int i = 0; i < loadedPackageData.GetFirmwareInfo().GetDeviceInfos().length(); i++)
+ for (const DeviceInfo& deviceInfo : loadedPackageData.GetFirmwareInfo().GetDeviceInfos())
{
- const DeviceInfo& deviceInfo = loadedPackageData.GetFirmwareInfo().GetDeviceInfos()[i];
supportedDevicesListWidget->addItem(deviceInfo.GetManufacturer() + " " + deviceInfo.GetName() + ": " + deviceInfo.GetProduct());
}
- for (int i = 0; i < loadedPackageData.GetFirmwareInfo().GetFileInfos().length(); i++)
+ for (const FileInfo& fileInfo : loadedPackageData.GetFirmwareInfo().GetFileInfos())
{
- const FileInfo& fileInfo = loadedPackageData.GetFirmwareInfo().GetFileInfos()[i];
includedFilesListWidget->addItem(fileInfo.GetFilename());
}
@@ -247,9 +244,9 @@ void MainWindow::UpdateFlashInterfaceAvailability(void)
bool allPartitionsValid = true;
QList<FileInfo>& fileList = workingPackageData.GetFirmwareInfo().GetFileInfos();
- for (int i = 0; i < fileList.length(); i++)
+ for (const FileInfo& fileInfo : fileList)
{
- if (fileList[i].GetFilename().isEmpty())
+ if (fileInfo.GetFilename().isEmpty())
{
allPartitionsValid = false;
break;
@@ -374,8 +371,8 @@ void MainWindow::UpdatePartitionNamesInterface(void)
{
const FileInfo& partitionInfo = workingPackageData.GetFirmwareInfo().GetFileInfos()[partitionsListWidget->currentRow()];
- for (int i = 0; i < unusedPartitionIds.length(); i++)
- partitionNameComboBox->addItem(currentPitData.FindEntry(unusedPartitionIds[i])->GetPartitionName());
+ for (unsigned int id : unusedPartitionIds)
+ partitionNameComboBox->addItem(currentPitData.FindEntry(id)->GetPartitionName());
partitionNameComboBox->addItem(currentPitData.FindEntry(partitionInfo.GetPartitionId())->GetPartitionName());
partitionNameComboBox->setCurrentIndex(unusedPartitionIds.length());
@@ -510,7 +507,7 @@ void MainWindow::SelectFirmwarePackage(void)
if (firmwarePackageLineEdit->text() != "")
{
- if (Packaging::ExtractPackage(firmwarePackageLineEdit->text(), &loadedPackageData))
+ if (Packaging::ExtractPackage(firmwarePackageLineEdit->text(), loadedPackageData))
UpdatePackageUserInterface();
else
loadedPackageData.Clear();
@@ -533,21 +530,17 @@ void MainWindow::LoadFirmwarePackage(void)
{
workingPackageData.Clear();
currentPitData.Clear();
-
- workingPackageData.GetFiles().append(loadedPackageData.GetFiles());
- loadedPackageData.RemoveAllFiles();
- const QList<FileInfo> packageFileInfos = loadedPackageData.GetFirmwareInfo().GetFileInfos();
-
- for (int i = 0; i < packageFileInfos.length(); i++)
+ // Loaded packages FileInfo store filenames, but the working package FileInfo need absolute paths
+ for (const FileInfo& packageFileInfo : loadedPackageData.GetFirmwareInfo().GetFileInfos())
{
bool fileFound = false;
- for (int j = 0; j < workingPackageData.GetFiles().length(); j++)
+ for (const QString& packageFilePath : loadedPackageData.GetFilePaths())
{
- if (workingPackageData.GetFiles()[j]->fileTemplate() == ("XXXXXX-" + packageFileInfos[i].GetFilename()))
+ if (packageFilePath.endsWith(packageFileInfo.GetFilename()))
{
- FileInfo partitionInfo(packageFileInfos[i].GetPartitionId(), QDir::current().absoluteFilePath(workingPackageData.GetFiles()[j]->fileName()));
+ FileInfo partitionInfo(packageFileInfo.GetPartitionId(), packageFilePath);
workingPackageData.GetFirmwareInfo().GetFileInfos().append(partitionInfo);
fileFound = true;
@@ -556,27 +549,28 @@ void MainWindow::LoadFirmwarePackage(void)
}
if (!fileFound)
- Alerts::DisplayWarning(QString("%1 is missing from the package.").arg(packageFileInfos[i].GetFilename()));
+ Alerts::DisplayWarning(QString("%1 is missing from the package.").arg(packageFileInfo.GetFilename()));
}
+ workingPackageData.GetFilePaths().append(loadedPackageData.GetFilePaths());
+ workingPackageData.SetPackagePath(loadedPackageData.GetPackagePath());
+
+ QString pitFilename = loadedPackageData.GetFirmwareInfo().GetPitFilename();
+
// Find the PIT file and read it
- for (int i = 0; i < workingPackageData.GetFiles().length(); i++)
+ for (const QString& filePath : workingPackageData.GetFilePaths())
{
- QTemporaryFile *file = workingPackageData.GetFiles()[i];
-
- if (file->fileTemplate() == ("XXXXXX-" + loadedPackageData.GetFirmwareInfo().GetPitFilename()))
+ if (filePath.endsWith(pitFilename))
{
- workingPackageData.GetFirmwareInfo().SetPitFilename(QDir::current().absoluteFilePath(file->fileName()));
+ workingPackageData.GetFirmwareInfo().SetPitFilename(filePath);
- if (!ReadPit(file))
+ if (!ReadPit(filePath))
{
Alerts::DisplayError("Failed to read PIT file.");
-
- loadedPackageData.Clear();
UpdatePackageUserInterface();
+ UpdateUnusedPartitionIds();
workingPackageData.Clear();
- UpdateUnusedPartitionIds();
return;
}
@@ -584,21 +578,20 @@ void MainWindow::LoadFirmwarePackage(void)
}
}
- UpdateUnusedPartitionIds();
workingPackageData.GetFirmwareInfo().SetRepartition(loadedPackageData.GetFirmwareInfo().GetRepartition());
workingPackageData.GetFirmwareInfo().SetNoReboot(loadedPackageData.GetFirmwareInfo().GetNoReboot());
- loadedPackageData.Clear();
+ loadedPackageData.Clear(false);
+
+ UpdateUnusedPartitionIds();
UpdatePackageUserInterface();
- firmwarePackageLineEdit->clear();
+ firmwarePackageLineEdit->clear();
partitionsListWidget->clear();
// Populate partitionsListWidget with partition names (from the PIT file)
- for (int i = 0; i < workingPackageData.GetFirmwareInfo().GetFileInfos().length(); i++)
+ for (const FileInfo& partitionInfo : workingPackageData.GetFirmwareInfo().GetFileInfos())
{
- const FileInfo& partitionInfo = workingPackageData.GetFirmwareInfo().GetFileInfos()[i];
-
const PitEntry *pitEntry = currentPitData.FindEntry(partitionInfo.GetPartitionId());
if (pitEntry)
@@ -609,11 +602,12 @@ void MainWindow::LoadFirmwarePackage(void)
{
Alerts::DisplayError("Firmware package includes invalid partition IDs.");
- loadedPackageData.GetFirmwareInfo().Clear();
+ workingPackageData.Clear();
currentPitData.Clear();
- UpdateUnusedPartitionIds();
+ UpdateUnusedPartitionIds();
partitionsListWidget->clear();
+
return;
}
}
@@ -803,9 +797,7 @@ void MainWindow::SelectPit(void)
currentPitData.Clear();
- QFile pitFile(path);
-
- if (ReadPit(&pitFile))
+ if (ReadPit(path))
{
workingPackageData.GetFirmwareInfo().SetPitFilename(path);
@@ -839,9 +831,7 @@ void MainWindow::SelectPit(void)
if (!workingPackageData.GetFirmwareInfo().GetPitFilename().isEmpty())
{
- QFile originalPitFile(workingPackageData.GetFirmwareInfo().GetPitFilename());
-
- if (ReadPit(&originalPitFile))
+ if (ReadPit(workingPackageData.GetFirmwareInfo().GetPitFilename()))
{
validPit = true;
}
@@ -919,13 +909,13 @@ void MainWindow::StartFlash(void)
arguments.append("--pit");
arguments.append(firmwareInfo.GetPitFilename());
- for (int i = 0; i < fileInfos.length(); i++)
+ for (const FileInfo& fileInfo : fileInfos)
{
QString flag;
- flag.sprintf("--%u", fileInfos[i].GetPartitionId());
+ flag.sprintf("--%u", fileInfo.GetPartitionId());
arguments.append(flag);
- arguments.append(fileInfos[i].GetFilename());
+ arguments.append(fileInfo.GetFilename());
}
if (firmwareInfo.GetNoReboot())
diff --git a/heimdall-frontend/source/mainwindow.h b/heimdall-frontend/source/mainwindow.h
index d0b8703..685d342 100644
--- a/heimdall-frontend/source/mainwindow.h
+++ b/heimdall-frontend/source/mainwindow.h
@@ -109,7 +109,7 @@ namespace HeimdallFrontend
void StartHeimdall(const QStringList& arguments);
void UpdateUnusedPartitionIds(void);
- bool ReadPit(QFile *file);
+ bool ReadPit(const QString& path);
void UpdatePackageUserInterface(void);
diff --git a/heimdall-frontend/source/qml/DropFiles.qml b/heimdall-frontend/source/qml/DropFiles.qml
index ddcc90b..9187b4f 100644
--- a/heimdall-frontend/source/qml/DropFiles.qml
+++ b/heimdall-frontend/source/qml/DropFiles.qml
@@ -2,12 +2,11 @@ import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
+import "FileUtils.js" as FileUtils
DropFilesForm {
id: background
-
property var fileUrls: []
-
signal nextPressed(var files)
ListModel {
@@ -30,15 +29,17 @@ DropFilesForm {
var count = urls.length;
if (count > 0) {
for (var i = 0; i < count; i++) {
- var url = urls[i].toString();
- var filename = url.slice(url.lastIndexOf('/') + 1, url.length);
+ if (FileUtils.isFile(urls[i])) {
+ var filename = FileUtils.filenameFromUrl(urls[i]);
- fileModel.append({
- icon: "drop_zone.svg",
- text: filename
- });
+ fileModel.append({ icon: "drop_zone.svg", text: filename });
- fileUrls.push(urls[i]);
+ if (FileUtils.isArchive(filename)) {
+ fileUrls.push(FileUtils.extractArchive(urls[i]));
+ } else {
+ fileUrls.push(urls[i]);
+ }
+ }
}
setFileGridVisible(true);
@@ -90,12 +91,12 @@ DropFilesForm {
}
FileDialog {
- id: browseDialog
+ id: browseDialog
title: "Select firmware file(s)"
selectMultiple: true
selectFolder: false
- onAccepted: {
+ onAccepted: {
addFiles(browseDialog.fileUrls);
- }
- }
+ }
+ }
}
diff --git a/heimdall-frontend/source/qml/FileUtils.js b/heimdall-frontend/source/qml/FileUtils.js
new file mode 100644
index 0000000..3735a37
--- /dev/null
+++ b/heimdall-frontend/source/qml/FileUtils.js
@@ -0,0 +1,44 @@
+function clipFileExtension(filename) {
+ var periodIndex = filename.lastIndexOf('.');
+
+ if (periodIndex > 0) {
+ return filename.slice(0, periodIndex - 1);
+ } else if (periodIndex === 0) {
+ return "";
+ }
+
+ return filename;
+}
+
+function filenameFromUrl(url) {
+ var urlString = url.toString();
+ return urlString.slice(urlString.lastIndexOf('/') + 1);
+}
+
+function fileExtension(url) {
+ var filename = filenameFromUrl(url);
+ var periodIndex = filename.lastIndexOf('.');
+
+ if (periodIndex >= 0) {
+ return filename.slice(periodIndex + 1);
+ }
+
+ return "";
+}
+
+// TODO: Real implemention - call out to C++ and validate with QFileInfo etc.
+function isFile(url) {
+ var filename = filenameFromUrl(url);
+ return filename.length > 0;
+}
+
+function isArchive(url) {
+ var filename = filenameFromUrl(url);
+ var extension = fileExtension(filename);
+ return (extension === 'tar' || extension === 'zip')
+ || (extension === 'gz' && fileExtension(clipFileExtension(filename)) === 'tar');
+}
+
+function extractArchive(url) {
+
+}
diff --git a/heimdall-frontend/source/qml/qml.qrc b/heimdall-frontend/source/qml/qml.qrc
index 25799fc..641c200 100644
--- a/heimdall-frontend/source/qml/qml.qrc
+++ b/heimdall-frontend/source/qml/qml.qrc
@@ -1,9 +1,10 @@
<RCC>
<qresource prefix="/">
+ <file>DropFiles.qml</file>
+ <file>DropFilesForm.qml</file>
+ <file>FileUtils.js</file>
<file>main.qml</file>
<file>Root.qml</file>
<file>RootForm.qml</file>
- <file>DropFiles.qml</file>
- <file>DropFilesForm.qml</file>
</qresource>
</RCC> \ No newline at end of file