aboutsummaryrefslogtreecommitdiffstats
path: root/heimdall-frontend/Source/Packaging.cpp
diff options
context:
space:
mode:
authorBenjamin Dobell <benjamin.dobell+git@glassechidna.com.au>2015-02-19 03:13:56 +1100
committerBenjamin Dobell <benjamin.dobell+git@glassechidna.com.au>2015-02-19 04:13:33 +1100
commitb22ae7b89f7993f632e10e18c116f293f314575f (patch)
tree03161ccff78d3c9353e860e5cd9b74b84d07810b /heimdall-frontend/Source/Packaging.cpp
parent39b48f2357b0b783815be88031b738376fa228e0 (diff)
downloadexternal_heimdall-b22ae7b89f7993f632e10e18c116f293f314575f.zip
external_heimdall-b22ae7b89f7993f632e10e18c116f293f314575f.tar.gz
external_heimdall-b22ae7b89f7993f632e10e18c116f293f314575f.tar.bz2
Removed autotools and VS files, and standardised source dir naming
Diffstat (limited to 'heimdall-frontend/Source/Packaging.cpp')
-rw-r--r--heimdall-frontend/Source/Packaging.cpp934
1 files changed, 0 insertions, 934 deletions
diff --git a/heimdall-frontend/Source/Packaging.cpp b/heimdall-frontend/Source/Packaging.cpp
deleted file mode 100644
index 7a27b3c..0000000
--- a/heimdall-frontend/Source/Packaging.cpp
+++ /dev/null
@@ -1,934 +0,0 @@
-/* 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.*/
-
-#ifdef WIN32
-#pragma warning(disable : 4996)
-#endif
-
-// C/C++ Standard Library
-#include <stdio.h>
-
-// zlib
-#include "zlib.h"
-
-// Qt
-#include <QDateTime>
-#include <QDir>
-#include <QProgressDialog>
-
-// Heimdall Frontend
-#include "Alerts.h"
-#include "Packaging.h"
-
-using namespace HeimdallFrontend;
-
-const qint64 Packaging::kMaxFileSize = 8589934592ll;
-const char *Packaging::ustarMagic = "ustar";
-
-bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
-{
- TarHeader tarHeader;
-
- if (!tarFile.open())
- {
- Alerts::DisplayError(QString("Error opening temporary TAR archive:\n%1").arg(tarFile.fileName()));
- return (false);
- }
-
- bool previousEmpty = false;
-
- QProgressDialog progressDialog("Extracting files...", "Cancel", 0, tarFile.size());
- progressDialog.setWindowModality(Qt::ApplicationModal);
- progressDialog.setWindowTitle("Heimdall Frontend");
-
- while (!tarFile.atEnd())
- {
- qint64 dataRead = tarFile.read(tarHeader.buffer, TarHeader::kBlockLength);
-
- if (dataRead != TarHeader::kBlockLength)
- {
- progressDialog.close();
- Alerts::DisplayError("Package's TAR archive is malformed.");
-
- tarFile.close();
-
- return (false);
- }
-
- progressDialog.setValue(tarFile.pos());
-
- if (progressDialog.wasCanceled())
- {
- tarFile.close();
- progressDialog.close();
-
- return (false);
- }
-
- //bool ustarFormat = strcmp(tarHeader.fields.magic, ustarMagic) == 0;
- bool empty = true;
-
- for (int i = 0; i < TarHeader::kBlockLength; i++)
- {
- if (tarHeader.buffer[i] != 0)
- {
- empty = false;
- break;
- }
- }
-
- if (empty)
- {
- if (previousEmpty)
- {
- // Two empty blocks in a row means we've reached the end of the archive.
- break;
- }
- }
- 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.
- char fileSizeString[13];
- memcpy(fileSizeString, tarHeader.fields.size, 12);
- fileSizeString[12] = '\0';
-
- qulonglong fileSize = QString(fileSizeString).toULongLong(&parsed, 8);
-
- if (!parsed)
- {
- progressDialog.close();
- Alerts::DisplayError("Tar header contained an invalid file size.");
-
- tarFile.close();
-
- return (false);
- }
-
- if (fileSize > 0 && tarHeader.fields.typeFlag == '0')
- {
- // We're working with a file.
- QString filename = QString::fromUtf8(tarHeader.fields.name);
-
- QTemporaryFile *outputFile = new QTemporaryFile("XXXXXX-" + filename);
- packageData->GetFiles().append(outputFile);
-
- if (!outputFile->open())
- {
- progressDialog.close();
- Alerts::DisplayError(QString("Failed to open output file: \n%1").arg(outputFile->fileName()));
-
- tarFile.close();
-
- return (false);
- }
-
- qulonglong dataRemaining = fileSize;
- char readBuffer[TarHeader::kBlockReadCount * TarHeader::kBlockLength];
-
- // Copy the file contents from tarFile to outputFile
- while (dataRemaining > 0)
- {
- qint64 fileDataToRead = (dataRemaining < TarHeader::kBlockReadCount * TarHeader::kBlockLength)
- ? dataRemaining : TarHeader::kBlockReadCount * TarHeader::kBlockLength;
-
- qint64 dataRead = tarFile.read(readBuffer, fileDataToRead + (TarHeader::kBlockLength - fileDataToRead % TarHeader::kBlockLength) % TarHeader::kBlockLength);
-
- if (dataRead < fileDataToRead || dataRead % TarHeader::kBlockLength != 0)
- {
- progressDialog.close();
- Alerts::DisplayError("Unexpected read error whilst extracting package files.");
-
- tarFile.close();
- outputFile->close();
-
- remove(outputFile->fileName().toStdString().c_str());
-
- return (false);
- }
-
- outputFile->write(readBuffer, fileDataToRead);
-
- dataRemaining -= fileDataToRead;
-
- progressDialog.setValue(tarFile.pos());
-
- if (progressDialog.wasCanceled())
- {
- tarFile.close();
- outputFile->close();
-
- remove(outputFile->fileName().toStdString().c_str());
-
- progressDialog.close();
-
- return (false);
- }
- }
-
- outputFile->close();
- }
- else
- {
- progressDialog.close();
- Alerts::DisplayError("Heimdall packages shouldn't contain links or directories.");
-
- tarFile.close();
-
- return (false);
- }
- }
-
- previousEmpty = empty;
- }
-
- progressDialog.close();
- tarFile.close();
-
- return (true);
-}
-
-bool Packaging::WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile, const QString& entryFilename)
-{
- TarHeader tarHeader;
- memset(tarHeader.buffer, 0, TarHeader::kBlockLength);
-
- QFile file(filePath);
-
- if (!file.open(QFile::ReadOnly))
- {
- Alerts::DisplayError(QString("Failed to open file: \n%1").arg(file.fileName()));
- return (false);
- }
-
- if (file.size() > Packaging::kMaxFileSize)
- {
- Alerts::DisplayError(QString("File is too large to be packaged:\n%1").arg(file.fileName()));
- return (false);
- }
-
- QFileInfo qtFileInfo(file);
- QByteArray utfFilename;
-
- utfFilename = entryFilename.toUtf8();
-
- if (utfFilename.length() > 100)
- {
- Alerts::DisplayError(QString("File name is too long:\n%1").arg(qtFileInfo.fileName()));
- return (false);
- }
-
- strcpy(tarHeader.fields.name, utfFilename.constData());
-
- unsigned int mode = 0;
-
- QFile::Permissions permissions = file.permissions();
-
- // Other
- if (permissions.testFlag(QFile::ExeOther))
- mode |= TarHeader::kModeOtherExecute;
- if (permissions.testFlag(QFile::WriteOther))
- mode |= TarHeader::kModeOtherWrite;
- if (permissions.testFlag(QFile::ReadOther))
- mode |= TarHeader::kModeOtherRead;
-
- // Group
- if (permissions.testFlag(QFile::ExeGroup))
- mode |= TarHeader::kModeGroupExecute;
- if (permissions.testFlag(QFile::WriteGroup))
- mode |= TarHeader::kModeGroupWrite;
- if (permissions.testFlag(QFile::ReadGroup))
- mode |= TarHeader::kModeGroupRead;
-
- // Owner
- if (permissions.testFlag(QFile::ExeOwner))
- mode |= TarHeader::kModeOwnerExecute;
- if (permissions.testFlag(QFile::WriteOwner))
- mode |= TarHeader::kModeOwnerWrite;
- if (permissions.testFlag(QFile::ReadOwner))
- mode |= TarHeader::kModeOwnerRead;
-
- sprintf(tarHeader.fields.mode, "%07o", mode);
-
- // Owner id
- uint id = qtFileInfo.ownerId();
-
- if (id < 2097151)
- sprintf(tarHeader.fields.userId, "%07o", id);
- else
- sprintf(tarHeader.fields.userId, "%07o", 0);
-
- // Group id
- id = qtFileInfo.groupId();
-
- if (id < 2097151)
- sprintf(tarHeader.fields.groupId, "%07o", id);
- else
- sprintf(tarHeader.fields.groupId, "%07o", 0);
-
- // Note: We don't support base-256 encoding. Support could be added later.
- sprintf(tarHeader.fields.size, "%011llo", file.size());
- sprintf(tarHeader.fields.modifiedTime, "%u", qtFileInfo.lastModified().toTime_t());
-
- // Regular File
- tarHeader.fields.typeFlag = '0';
-
- // Calculate checksum
- int checksum = 0;
- memset(tarHeader.fields.checksum, ' ', 8);
-
- for (int i = 0; i < TarHeader::kTarHeaderLength; i++)
- checksum += static_cast<unsigned char>(tarHeader.buffer[i]);
-
- sprintf(tarHeader.fields.checksum, "%07o", checksum);
-
- // Write the header to the TAR file.
- tarFile->write(tarHeader.buffer, TarHeader::kBlockLength);
-
- char buffer[TarHeader::kBlockWriteCount * TarHeader::kBlockLength];
- qint64 offset = 0;
-
- while (offset < file.size())
- {
- qint64 dataRead = file.read(buffer, TarHeader::kBlockWriteCount * TarHeader::kBlockLength);
-
- if (tarFile->write(buffer, dataRead) != dataRead)
- {
- Alerts::DisplayError("Failed to write data to the temporary TAR file.");
- return (false);
- }
-
- if (dataRead % TarHeader::kBlockLength != 0)
- {
- int remainingBlockLength = TarHeader::kBlockLength - dataRead % TarHeader::kBlockLength;
- memset(buffer, 0, remainingBlockLength);
-
- if (tarFile->write(buffer, remainingBlockLength) != remainingBlockLength)
- {
- Alerts::DisplayError("Failed to write data to the temporary TAR file.");
- return (false);
- }
- }
-
- offset += dataRead;
- }
-
- return (true);
-}
-
-bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarFile)
-{
- const QList<FileInfo>& fileInfos = firmwareInfo.GetFileInfos();
-
- QProgressDialog progressDialog("Packaging files...", "Cancel", 0, fileInfos.length() + 2);
- progressDialog.setWindowModality(Qt::ApplicationModal);
- progressDialog.setWindowTitle("Heimdall Frontend");
-
- QTemporaryFile firmwareXmlFile("XXXXXX-firmware.xml");
-
- if (!firmwareXmlFile.open())
- {
- progressDialog.close();
- Alerts::DisplayError(QString("Failed to create temporary file: \n%1").arg(firmwareXmlFile.fileName()));
-
- return (false);
- }
-
- QXmlStreamWriter xml(&firmwareXmlFile);
- firmwareInfo.WriteXml(xml);
- firmwareXmlFile.close();
-
- if (!tarFile->open())
- {
- progressDialog.close();
- Alerts::DisplayError(QString("Failed to open file: \n%1").arg(tarFile->fileName()));
-
- return (false);
- }
-
- for (int i = 0; i < fileInfos.length(); i++)
- {
- // If the file was already compressed we don't compress it again.
- bool skip = false;
-
- for (int j = 0; j < i; j++)
- {
- if (fileInfos[i].GetFilename() == fileInfos[j].GetFilename())
- {
- skip = true;
- break;
- }
- }
-
- if (skip)
- {
- progressDialog.setValue(i);
- continue;
- }
-
- QString filename = ClashlessFilename(fileInfos, i);
-
- if (filename == "firmware.xml")
- {
- Alerts::DisplayError("You cannot name your partition files \"firmware.xml\".\nIt is a reserved name.");
- return (false);
- }
-
- if (!WriteTarEntry(fileInfos[i].GetFilename(), tarFile, filename))
- {
- tarFile->resize(0);
- tarFile->close();
-
- progressDialog.close();
-
- return (false);
- }
-
- progressDialog.setValue(i);
-
- if (progressDialog.wasCanceled())
- {
- tarFile->resize(0);
- tarFile->close();
-
- progressDialog.close();
-
- return (false);
- }
- }
-
- int lastSlash = firmwareInfo.GetPitFilename().lastIndexOf('/');
-
- if (lastSlash < 0)
- lastSlash = firmwareInfo.GetPitFilename().lastIndexOf('\\');
-
- QString pitFilename = ClashlessFilename(fileInfos, firmwareInfo.GetPitFilename().mid(lastSlash + 1));
-
- if (pitFilename == "firmware.xml")
- {
- Alerts::DisplayError("You cannot name your PIT file \"firmware.xml\".\nIt is a reserved name.");
- return (false);
- }
-
- if (!WriteTarEntry(firmwareInfo.GetPitFilename(), tarFile, pitFilename))
- {
- tarFile->resize(0);
- tarFile->close();
-
- return (false);
- }
-
- progressDialog.setValue(progressDialog.value() + 1);
-
- if (progressDialog.wasCanceled())
- {
- tarFile->resize(0);
- tarFile->close();
-
- progressDialog.close();
-
- return (false);
- }
-
- if (!WriteTarEntry(firmwareXmlFile.fileName(), tarFile, "firmware.xml"))
- {
- tarFile->resize(0);
- tarFile->close();
-
- return (false);
- }
-
- progressDialog.setValue(progressDialog.value() + 1);
- progressDialog.close();
-
- // Write two empty blocks to signify the end of the archive.
- char emptyEntry[TarHeader::kBlockLength];
- memset(emptyEntry, 0, TarHeader::kBlockLength);
-
- tarFile->write(emptyEntry, TarHeader::kBlockLength);
- tarFile->write(emptyEntry, TarHeader::kBlockLength);
-
- tarFile->close();
-
- return (true);
-}
-
-bool Packaging::ExtractPackage(const QString& packagePath, PackageData *packageData)
-{
- FILE *compressedPackageFile = fopen(packagePath.toStdString().c_str(), "rb");
-
- if (!compressedPackageFile)
- {
- Alerts::DisplayError(QString("Failed to open package:\n%1").arg(packagePath));
- return (false);
- }
-
- fseek(compressedPackageFile, 0, SEEK_END);
- quint64 compressedFileSize = ftell(compressedPackageFile);
- rewind(compressedPackageFile);
-
- gzFile packageFile = gzdopen(fileno(compressedPackageFile), "rb");
-
- QTemporaryFile outputTar("XXXXXX.tar");
-
- if (!outputTar.open())
- {
- 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++)
- {
- QTemporaryFile *file = packageData->GetFiles()[i];
-
- if (file->fileTemplate() == "XXXXXX-firmware.xml")
- {
- if (!packageData->ReadFirmwareInfo(file))
- {
- packageData->Clear();
- return (false);
- }
-
- return (true);
- }
- }
-
- Alerts::DisplayError("firmware.xml is missing from the package.");
- return (false);
-}
-
-bool Packaging::BuildPackage(const QString& packagePath, const FirmwareInfo& firmwareInfo)
-{
- FILE *compressedPackageFile = fopen(packagePath.toStdString().c_str(), "wb");
-
- if (!compressedPackageFile)
- {
- Alerts::DisplayError(QString("Failed to create package:\n%1").arg(packagePath));
- return (false);
- }
-
- QTemporaryFile tar("XXXXXX.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());
- progressDialog.setWindowModality(Qt::ApplicationModal);
- progressDialog.setWindowTitle("Heimdall Frontend");
-
- do
- {
- bytesRead = tar.read(buffer, kCompressBufferLength);
-
- if (bytesRead == -1)
- {
- progressDialog.close();
- Alerts::DisplayError("Error reading temporary TAR file.");
-
- gzclose(packageFile);
- remove(packagePath.toStdString().c_str());
-
- return (false);
- }
-
- if (gzwrite(packageFile, buffer, bytesRead) != bytesRead)
- {
- progressDialog.close();
- Alerts::DisplayError("Error compressing package.");
-
- gzclose(packageFile);
- remove(packagePath.toStdString().c_str());
-
- return (false);
- }
-
- totalBytesRead += bytesRead;
- progressDialog.setValue(totalBytesRead);
-
- 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
-
- return (true);
-}
-
-QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, int fileInfoIndex)
-{
- int lastSlash = fileInfos[fileInfoIndex].GetFilename().lastIndexOf('/');
-
- if (lastSlash < 0)
- lastSlash = fileInfos[fileInfoIndex].GetFilename().lastIndexOf('\\');
-
- QString filename = fileInfos[fileInfoIndex].GetFilename().mid(lastSlash + 1);
- unsigned int renameIndex = 0;
-
- // Check for name clashes
- for (int i = 0; i < fileInfoIndex; i++)
- {
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
-
- if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
-
- QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
-
- // If the filenames are the same, but the files themselves aren't the same (i.e. not the same path), then rename.
- if (filename == otherFilename && fileInfos[i].GetFilename() != fileInfos[fileInfoIndex].GetFilename())
- renameIndex++;
- }
-
- if (renameIndex > 0)
- {
- int lastPeriodIndex = filename.lastIndexOf(QChar('.'));
- QString shortFilename;
- QString fileType;
-
- if (lastPeriodIndex >= 0)
- {
- shortFilename = filename.left(lastPeriodIndex);
- fileType = filename.mid(lastPeriodIndex);
- }
- else
- {
- shortFilename = filename;
- }
-
- unsigned int renameIndexOffset = 0;
- 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++)
- {
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
-
- if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
-
- QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
-
- if (otherFilename.length() > filename.length() + 1)
- {
- QString trimmedOtherFilename = otherFilename.left(shortFilename.length());
-
- if (shortFilename == trimmedOtherFilename)
- {
- lastPeriodIndex = otherFilename.lastIndexOf(QChar('.'));
- QString shortOtherFilename;
-
- if (lastPeriodIndex >= 0)
- shortOtherFilename = otherFilename.left(lastPeriodIndex);
- else
- shortOtherFilename = otherFilename;
-
- QRegExp renameExp("-[0-9]+");
-
- if (renameExp.lastIndexIn(shortOtherFilename) == shortFilename.length())
- {
- unsigned int trailingInteger = shortOtherFilename.mid(shortFilename.length() + 1).toUInt(&validIndexOffset);
-
- if (!validIndexOffset)
- break;
-
- if (trailingInteger > renameIndexOffset)
- renameIndexOffset = trailingInteger;
- }
- }
- }
- }
-
- if (validIndexOffset)
- {
- // Ensure renaming won't involve integer overflow!
- if (renameIndex > static_cast<unsigned int>(-1) - renameIndexOffset)
- validIndexOffset = false;
- }
-
- if (validIndexOffset)
- {
- shortFilename.append(QChar('-'));
- shortFilename.append(QString::number(renameIndexOffset + renameIndex));
-
- return (shortFilename + fileType);
- }
- else
- {
- // Fallback behaviour... an absolutely terrible brute force implementation!
- QString filename;
- QString renamePrefix;
-
- for (;;)
- {
- renamePrefix.append(QChar('+'));
-
- for (unsigned int i = 0; i < static_cast<unsigned int>(-1); i++)
- {
- filename = shortFilename + renamePrefix + QString::number(i) + fileType;
-
- bool valid = true;
-
- for (int i = 0; i < fileInfos.length(); i++)
- {
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
-
- if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
-
- if (filename == fileInfos[i].GetFilename().mid(lastSlash + 1))
- {
- valid = false;
- break;
- }
- }
-
- if (valid)
- return (filename);
- }
- }
- }
- }
- else
- {
- return (filename);
- }
-}
-
-QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, const QString& filename)
-{
- unsigned int renameIndex = 0;
-
- // Check for name clashes
- for (int i = 0; i < fileInfos.length(); i++)
- {
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
-
- if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
-
- QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
-
- if (filename == otherFilename)
- renameIndex++;
- }
-
- if (renameIndex > 0)
- {
- int lastPeriodIndex = filename.lastIndexOf(QChar('.'));
- QString shortFilename;
- QString fileType;
-
- if (lastPeriodIndex >= 0)
- {
- shortFilename = filename.left(lastPeriodIndex);
- fileType = filename.mid(lastPeriodIndex);
- }
- else
- {
- shortFilename = filename;
- }
-
- unsigned int renameIndexOffset = 0;
- 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++)
- {
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
-
- if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
-
- QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1);
-
- if (otherFilename.length() > filename.length() + 1)
- {
- QString trimmedOtherFilename = otherFilename.left(filename.length());
-
- if (filename == trimmedOtherFilename)
- {
- lastPeriodIndex = otherFilename.lastIndexOf(QChar('.'));
- QString shortOtherFilename;
-
- if (lastPeriodIndex >= 0)
- shortOtherFilename = otherFilename.left(lastPeriodIndex);
- else
- shortOtherFilename = otherFilename;
-
- QRegExp renameExp("-[0-9]+");
-
- if (renameExp.lastIndexIn(shortOtherFilename) == shortFilename.length())
- {
- unsigned int trailingInteger = shortOtherFilename.mid(shortFilename.length() + 1).toUInt(&validIndexOffset);
-
- if (!validIndexOffset)
- break;
-
- if (trailingInteger > renameIndexOffset)
- renameIndexOffset = trailingInteger;
- }
- }
- }
- }
-
- if (validIndexOffset)
- {
- // Ensure renaming won't involve integer overflow!
- if (renameIndex > static_cast<unsigned int>(-1) - renameIndexOffset)
- validIndexOffset = false;
- }
-
- if (validIndexOffset)
- {
- shortFilename.append(QChar('-'));
- shortFilename.append(QString::number(renameIndexOffset + renameIndex));
-
- return (shortFilename + fileType);
- }
- else
- {
- // Fallback behaviour, brute-force/semi-random.
- bool valid;
- QString filename;
-
- do
- {
- valid = true;
-
- filename = shortFilename + "-";
- for (int i = 0; i < 8; i++)
- filename.append(QChar(qrand() % ('Z' - 'A' + 1) + 'A'));
-
- for (int i = 0; i < fileInfos.length(); i++)
- {
- int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/');
-
- if (lastSlash < 0)
- lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\');
-
- if (filename == fileInfos[i].GetFilename().mid(lastSlash + 1))
- {
- valid = false;
- break;
- }
- }
- } while (!valid);
-
- return (filename);
- }
- }
- else
- {
- return (filename);
- }
-}