summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xheimdall-frontend/Source/FirmwareInfo.cpp188
-rwxr-xr-xheimdall-frontend/Source/FirmwareInfo.h16
-rwxr-xr-xheimdall-frontend/Source/Packaging.cpp496
-rwxr-xr-xheimdall-frontend/Source/Packaging.h16
-rw-r--r--heimdall-frontend/Source/mainwindow.cpp88
-rw-r--r--heimdall-frontend/Source/mainwindow.h2
-rw-r--r--heimdall-frontend/aboutform.ui2
-rw-r--r--heimdall-frontend/mainwindow.ui96
-rw-r--r--heimdall/source/BridgeManager.cpp34
-rw-r--r--heimdall/source/Interface.cpp2
-rw-r--r--heimdall/source/Interface.h5
-rw-r--r--heimdall/source/main.cpp64
-rwxr-xr-xlibpit/Source/libpit.cpp35
-rwxr-xr-xlibpit/Source/libpit.h8
14 files changed, 797 insertions, 255 deletions
diff --git a/heimdall-frontend/Source/FirmwareInfo.cpp b/heimdall-frontend/Source/FirmwareInfo.cpp
index 7d11605..39ec242 100755
--- a/heimdall-frontend/Source/FirmwareInfo.cpp
+++ b/heimdall-frontend/Source/FirmwareInfo.cpp
@@ -50,7 +50,7 @@ bool DeviceInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundManufacturer)
{
- // TODO: "found multiple device manufacturers."
+ // TODO: "Found multiple device manufacturers."
return (false);
}
@@ -62,7 +62,7 @@ bool DeviceInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundProduct)
{
- // TODO: "found multiple device product identifiers."
+ // TODO: "Found multiple device product identifiers."
return (false);
}
@@ -74,7 +74,7 @@ bool DeviceInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundName)
{
- // TODO: "found multiple device names."));
+ // TODO: "Found multiple device names."));
return (false);
}
@@ -101,6 +101,25 @@ bool DeviceInfo::ParseXml(QXmlStreamReader& xml)
return (false);
}
+void DeviceInfo::WriteXml(QXmlStreamWriter& xml) const
+{
+ xml.writeStartElement("device");
+
+ xml.writeStartElement("manufacturer");
+ xml.writeCharacters(manufacturer);
+ xml.writeEndElement();
+
+ xml.writeStartElement("product");
+ xml.writeCharacters(product);
+ xml.writeEndElement();
+
+ xml.writeStartElement("name");
+ xml.writeCharacters(name);
+ xml.writeEndElement();
+
+ xml.writeEndElement();
+}
+
PlatformInfo::PlatformInfo()
@@ -135,7 +154,7 @@ bool PlatformInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundName)
{
- // TODO: "found multiple platform names."
+ // TODO: "Found multiple platform names."
return (false);
}
@@ -147,7 +166,7 @@ bool PlatformInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundVersion)
{
- // TODO: "found multiple platform versions."
+ // TODO: "Found multiple platform versions."
return (false);
}
@@ -179,6 +198,21 @@ bool PlatformInfo::ParseXml(QXmlStreamReader& xml)
return (false);
}
+void PlatformInfo::WriteXml(QXmlStreamWriter& xml) const
+{
+ xml.writeStartElement("platform");
+
+ xml.writeStartElement("name");
+ xml.writeCharacters(name);
+ xml.writeEndElement();
+
+ xml.writeStartElement("version");
+ xml.writeCharacters(version);
+ xml.writeEndElement();
+
+ xml.writeEndElement();
+}
+
FileInfo::FileInfo()
@@ -206,7 +240,7 @@ bool FileInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundId)
{
- // TODO: "found multiple file IDs."
+ // TODO: "Found multiple file IDs."
return (false);
}
@@ -218,7 +252,7 @@ bool FileInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundFilename)
{
- // TODO: "found multiple file filenames."
+ // TODO: "Found multiple file filenames."
return (false);
}
@@ -245,11 +279,34 @@ bool FileInfo::ParseXml(QXmlStreamReader& xml)
return (false);
}
+void FileInfo::WriteXml(QXmlStreamWriter& xml) const
+{
+ xml.writeStartElement("file");
+
+ xml.writeStartElement("id");
+ xml.writeCharacters(QString::number(partitionId));
+ xml.writeEndElement();
+
+ xml.writeStartElement("filename");
+
+ int lastSlash = filename.lastIndexOf('/');
+
+ if (lastSlash < 0)
+ lastSlash = filename.lastIndexOf('\\');
+
+ xml.writeCharacters(filename.mid(lastSlash + 1));
+
+ xml.writeEndElement();
+
+ xml.writeEndElement();
+}
+
FirmwareInfo::FirmwareInfo()
{
repartition = false;
+ noReboot = false;
}
void FirmwareInfo::Clear(void)
@@ -267,13 +324,15 @@ void FirmwareInfo::Clear(void)
pitFilename.clear();
repartition = false;
+ noReboot = false;
+
fileInfos.clear();
}
bool FirmwareInfo::IsCleared(void) const
{
return (name.isEmpty() && version.isEmpty() && platformInfo.IsCleared() && developers.isEmpty() && url.isEmpty() && url.isEmpty() && donateUrl.isEmpty()
- && deviceInfos.isEmpty() && pitFilename.isEmpty() && !repartition && fileInfos.isEmpty());
+ && deviceInfos.isEmpty() && pitFilename.isEmpty() && !repartition && !noReboot && fileInfos.isEmpty());
}
bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
@@ -289,6 +348,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
bool foundDevices = false;
bool foundPit = false;
bool foundRepartition = false;
+ bool foundNoReboot = false;
bool foundFiles = false;
if (!xml.readNextStartElement())
@@ -337,7 +397,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundName)
{
- // TODO: "found multiple firmware names."
+ // TODO: "Found multiple firmware names."
return (false);
}
@@ -348,7 +408,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundVersion)
{
- // TODO: "found multiple firmware versions."
+ // TODO: "Found multiple firmware versions."
return (false);
}
@@ -359,7 +419,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundPlatform)
{
- // TODO: "found multiple firmware platforms."
+ // TODO: "Found multiple firmware platforms."
return (false);
}
@@ -372,7 +432,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundDevelopers)
{
- // TODO: "found multiple sets of firmware developers."
+ // TODO: "Found multiple sets of firmware developers."
return (false);
}
@@ -406,7 +466,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundUrl)
{
- // TODO: "found multiple firmware URLs."
+ // TODO: "Found multiple firmware URLs."
return (false);
}
@@ -418,7 +478,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundDonateUrl)
{
- // TODO: "found multiple firmware donate URLs."
+ // TODO: "Found multiple firmware donate URLs."
return (false);
}
@@ -430,7 +490,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundDevices)
{
- // TODO: "found multiple sets of firmware devices."
+ // TODO: "Found multiple sets of firmware devices."
return (false);
}
@@ -471,7 +531,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundPit)
{
- // TODO: "found multiple firmware PIT files."
+ // TODO: "Found multiple firmware PIT files."
return (false);
}
@@ -483,7 +543,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (foundRepartition)
{
- // TODO: "found multiple firmware repartition values."
+ // TODO: "Found multiple firmware repartition values."
return (false);
}
@@ -491,11 +551,23 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
repartition = (xml.readElementText().toInt() != 0);
}
+ else if (xml.name() == "noreboot")
+ {
+ if (foundNoReboot)
+ {
+ // TODO: "Found multiple firmware noreboot values."
+ return (false);
+ }
+
+ foundNoReboot = true;
+
+ noReboot = (xml.readElementText().toInt() != 0);
+ }
else if (xml.name() == "files")
{
if (foundFiles)
{
- // TODO: "found multiple sets of firmware files."
+ // TODO: "Found multiple sets of firmware files."
return (false);
}
@@ -542,7 +614,7 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
{
if (xml.name() == "firmware")
{
- if (!(foundName && foundVersion && foundPlatform && foundDevelopers && foundDevices && foundPit && foundRepartition && foundFiles))
+ if (!(foundName && foundVersion && foundPlatform && foundDevelopers && foundDevices && foundPit && foundRepartition && foundNoReboot && foundFiles))
return (false);
else
break;
@@ -569,3 +641,81 @@ bool FirmwareInfo::ParseXml(QXmlStreamReader& xml)
return (true);
}
+
+void FirmwareInfo::WriteXml(QXmlStreamWriter& xml) const
+{
+ xml.writeStartDocument();
+ xml.writeStartElement("firmware");
+ xml.writeAttribute("version", QString::number(FirmwareInfo::kVersion));
+
+ xml.writeStartElement("name");
+ xml.writeCharacters(name);
+ xml.writeEndElement();
+
+ xml.writeStartElement("version");
+ xml.writeCharacters(version);
+ xml.writeEndElement();
+
+ platformInfo.WriteXml(xml);
+
+ xml.writeStartElement("developers");
+
+ for (int i = 0; i < developers.length(); i++)
+ {
+ xml.writeStartElement("name");
+ xml.writeCharacters(developers[i]);
+ xml.writeEndElement();
+ }
+
+ xml.writeEndElement();
+
+ if (!url.isEmpty())
+ {
+ xml.writeStartElement("url");
+ xml.writeCharacters(url);
+ xml.writeEndElement();
+ }
+
+ if (!donateUrl.isEmpty())
+ {
+ xml.writeStartElement("donateurl");
+ xml.writeCharacters(donateUrl);
+ xml.writeEndElement();
+ }
+
+ xml.writeStartElement("devices");
+
+ for (int i = 0; i < deviceInfos.length(); i++)
+ deviceInfos[i].WriteXml(xml);
+
+ xml.writeEndElement();
+
+ xml.writeStartElement("pit");
+
+ int lastSlash = pitFilename.lastIndexOf('/');
+
+ if (lastSlash < 0)
+ lastSlash = pitFilename.lastIndexOf('\\');
+
+ xml.writeCharacters(pitFilename.mid(lastSlash + 1));
+
+ xml.writeEndElement();
+
+ xml.writeStartElement("repartition");
+ xml.writeCharacters((repartition) ? "1" : "0");
+ xml.writeEndElement();
+
+ xml.writeStartElement("noreboot");
+ xml.writeCharacters((noReboot) ? "1" : "0");
+ xml.writeEndElement();
+
+ xml.writeStartElement("files");
+
+ for (int i = 0; i < fileInfos.length(); i++)
+ fileInfos[i].WriteXml(xml);
+
+ xml.writeEndElement();
+
+ xml.writeEndElement();
+ xml.writeEndDocument();
+}
diff --git a/heimdall-frontend/Source/FirmwareInfo.h b/heimdall-frontend/Source/FirmwareInfo.h
index a72dab1..3fd6341 100755
--- a/heimdall-frontend/Source/FirmwareInfo.h
+++ b/heimdall-frontend/Source/FirmwareInfo.h
@@ -42,6 +42,7 @@ namespace HeimdallFrontend
DeviceInfo(const QString& manufacturer, const QString& product, const QString& name);
bool ParseXml(QXmlStreamReader& xml);
+ void WriteXml(QXmlStreamWriter& xml) const;
const QString& GetManufacturer(void) const
{
@@ -89,6 +90,7 @@ namespace HeimdallFrontend
bool IsCleared(void) const;
bool ParseXml(QXmlStreamReader& xml);
+ void WriteXml(QXmlStreamWriter& xml) const;
const QString& GetName(void) const
{
@@ -124,6 +126,7 @@ namespace HeimdallFrontend
FileInfo(unsigned int partitionId, const QString& filename);
bool ParseXml(QXmlStreamReader& xml);
+ void WriteXml(QXmlStreamWriter& xml) const;
unsigned int GetPartitionId(void) const
{
@@ -170,6 +173,8 @@ namespace HeimdallFrontend
QString pitFilename;
bool repartition;
+ bool noReboot;
+
QList<FileInfo> fileInfos;
public:
@@ -180,6 +185,7 @@ namespace HeimdallFrontend
bool IsCleared(void) const;
bool ParseXml(QXmlStreamReader& xml);
+ void WriteXml(QXmlStreamWriter& xml) const;
const QString& GetName(void) const
{
@@ -271,6 +277,16 @@ namespace HeimdallFrontend
this->repartition = repartition;
}
+ bool GetNoReboot(void) const
+ {
+ return (noReboot);
+ }
+
+ void SetNoReboot(bool noReboot)
+ {
+ this->noReboot = noReboot;
+ }
+
const QList<FileInfo>& GetFileInfos(void) const
{
return (fileInfos);
diff --git a/heimdall-frontend/Source/Packaging.cpp b/heimdall-frontend/Source/Packaging.cpp
index cbd03a4..1034539 100755
--- a/heimdall-frontend/Source/Packaging.cpp
+++ b/heimdall-frontend/Source/Packaging.cpp
@@ -18,6 +18,10 @@
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>
@@ -27,6 +31,7 @@
// Qt
#include <QDateTime>
#include <QDir>
+#include <QProgressDialog>
// Heimdall Frontend
#include "Packaging.h"
@@ -35,20 +40,44 @@ using namespace HeimdallFrontend;
const char *Packaging::ustarMagic = "ustar";
-bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *outputPackageData)
+bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData)
{
TarHeader tarHeader;
- tarFile.reset();
+ if (!tarFile.open())
+ {
+ // TODO: "Error opening temporary TAR archive."
+ 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)
+ {
+ // TODO: "Package's TAR archive is malformed."
+ tarFile.close();
+ progressDialog.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;
@@ -73,7 +102,20 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *outputPackageDa
}
else
{
- // TODO: Check checksum
+ 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;
@@ -87,6 +129,7 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *outputPackageDa
if (!parsed)
{
// TODO: Error message?
+ tarFile.close();
return (false);
}
@@ -95,14 +138,15 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *outputPackageDa
// We're working with a file.
QString filename = QString::fromUtf8(tarHeader.fields.name);
- // This is slightly pointless as we don't support directories...
- if (ustarFormat)
- filename.prepend(tarHeader.fields.prefix);
-
QTemporaryFile *outputFile = new QTemporaryFile("XXXXXX-" + filename);
- outputFile->open();
+ packageData->GetFiles().append(outputFile);
- outputPackageData->GetFiles().append(outputFile);
+ if (!outputFile->open())
+ {
+ // TODO: "Failed to open output file \"%s\""
+ tarFile.close();
+ return (false);
+ }
qulonglong dataRemaining = fileSize;
char readBuffer[TarHeader::kBlockReadCount * TarHeader::kBlockLength];
@@ -116,18 +160,41 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *outputPackageDa
qint64 dataRead = tarFile.read(readBuffer, fileDataToRead + (TarHeader::kBlockLength - fileDataToRead % TarHeader::kBlockLength) % TarHeader::kBlockLength);
if (dataRead < fileDataToRead || dataRead % TarHeader::kBlockLength != 0)
+ {
+ // TODO: "Unexpected error 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
{
- // We don't support links/directories.
+ // TODO: "Heimdall packages shouldn't contain links or directories."
+ tarFile.close();
return (false);
}
}
@@ -135,195 +202,320 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *outputPackageDa
previousEmpty = empty;
}
+ progressDialog.close();
+ tarFile.close();
+
return (true);
}
-bool Packaging::CreateTar(const PackageData& packageData, QTemporaryFile *outputTarFile)
+bool Packaging::WriteTarEntry(const QString& filename, QTemporaryFile *tarFile, bool firmwareXml)
{
- const QList<FileInfo>& fileInfos = packageData.GetFirmwareInfo().GetFileInfos();
+ TarHeader tarHeader;
+ memset(tarHeader.buffer, 0, TarHeader::kBlockLength);
+
+ QFile file(filename);
- if (!outputTarFile->open())
+ if (!file.open(QFile::ReadOnly))
{
// TODO: "Failed to open \"%s\""
return (false);
}
- bool failure = false;
-
- TarHeader tarHeader;
-
- for (int i = 0; i < fileInfos.length(); i++)
+ if (file.size() > TarHeader::kMaxFileSize)
{
- memset(tarHeader.buffer, 0, TarHeader::kBlockLength);
+ // TODO: "File is too large to packaged"
+ return (false);
+ }
- QFile file(fileInfos[i].GetFilename());
+ QFileInfo qtFileInfo(file);
+ QByteArray utfFilename;
- if (!file.open(QFile::ReadOnly))
- {
- // TODO: "Failed to open \"%s\""
- failure = true;
- break;
- }
+ if (firmwareXml)
+ {
+ utfFilename = QString("firmware.xml").toUtf8();
+ }
+ else
+ {
+ utfFilename = qtFileInfo.fileName().toUtf8();
- if (file.size() > TarHeader::kMaxFileSize)
+ if (utfFilename.length() > 100)
{
- // TODO: "File is too large to packaged"
- failure = true;
- break;
+ // TODO: "Filename is too long"
+ return (false);
}
+ }
- QFileInfo qtFileInfo(file);
- strcpy(tarHeader.fields.name, qtFileInfo.fileName().toUtf8().constData());
+ 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, "%o", mode);
-
- sprintf(tarHeader.fields.userId, "%o", qtFileInfo.ownerId());
- sprintf(tarHeader.fields.groupId, "%o", qtFileInfo.groupId());
-
- // Note: We don't support base-256 encoding. Support could be added in future.
- sprintf(tarHeader.fields.size, "%o", file.size());
-
- sprintf(tarHeader.fields.modifiedTime, "%o", qtFileInfo.lastModified().toMSecsSinceEpoch());
+ 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, "%011o", file.size());
+ sprintf(tarHeader.fields.modifiedTime, "%011o", qtFileInfo.lastModified().toMSecsSinceEpoch() / 1000);
- // Regular File
- tarHeader.fields.typeFlag = '0';
+ // Regular File
+ tarHeader.fields.typeFlag = '0';
- // Calculate checksum
- int checksum = 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]);
- for (int i = 0; i < TarHeader::kTarHeaderLength; i++)
- checksum += tarHeader.buffer[i];
+ sprintf(tarHeader.fields.checksum, "%07o", checksum);
- sprintf(tarHeader.fields.checksum, "%o", checksum);
+ // Write the header to the TAR file.
+ tarFile->write(tarHeader.buffer, TarHeader::kBlockLength);
- // Write the header to the TAR file.
- outputTarFile->write(tarHeader.buffer, TarHeader::kBlockLength);
+ char buffer[TarHeader::kBlockWriteCount * TarHeader::kBlockLength];
+ qint64 offset = 0;
- char buffer[TarHeader::kBlockWriteCount * TarHeader::kBlockLength];
+ while (offset < file.size())
+ {
+ qint64 dataRead = file.read(buffer, TarHeader::kBlockWriteCount * TarHeader::kBlockLength);
+
+ if (tarFile->write(buffer, dataRead) != dataRead)
+ {
+ // TODO: "Failed to write data to the temporary TAR file."
+ return (false);
+ }
- for (qint64 i = 0; i < file.size(); i++)
+ if (dataRead % TarHeader::kBlockLength != 0)
{
- qint64 dataRead = file.read(buffer, TarHeader::kBlockWriteCount * TarHeader::kBlockLength);
+ int remainingBlockLength = TarHeader::kBlockLength - dataRead % TarHeader::kBlockLength;
+ memset(buffer, 0, remainingBlockLength);
- if (outputTarFile->write(buffer, dataRead) != dataRead)
+ if (tarFile->write(buffer, remainingBlockLength) != remainingBlockLength)
{
// TODO: "Failed to write data to the temporary TAR file."
- failure = true;
- break;
+ return (false);
}
+ }
- if (dataRead % TarHeader::kBlockLength != 0)
- {
- int remainingBlockLength = TarHeader::kBlockLength - dataRead % TarHeader::kBlockLength;
- memset(buffer, 0, remainingBlockLength);
+ offset += dataRead;
+ }
- if (outputTarFile->write(buffer, remainingBlockLength) != remainingBlockLength)
- {
- // TODO: "Failed to write data to the temporary TAR file."
- failure = true;
- break;
- }
- }
+ 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())
+ {
+ // TODO: "Failed to create temporary file "%s"
+ return (false);
+ }
+
+ firmwareInfo.WriteXml(QXmlStreamWriter(&firmwareXmlFile));
+
+ firmwareXmlFile.close();
+
+ if (!tarFile->open())
+ {
+ // TODO: "Failed to open \"%s\""
+ return (false);
+ }
+
+ for (int i = 0; i < fileInfos.length(); i++)
+ {
+ if (!WriteTarEntry(fileInfos[i].GetFilename(), tarFile))
+ {
+ tarFile->resize(0);
+ tarFile->close();
+
+ progressDialog.close();
- i += dataRead;
+ return (false);
}
- if (failure)
- break;
+ progressDialog.setValue(i);
+
+ if (progressDialog.wasCanceled())
+ {
+ tarFile->resize(0);
+ tarFile->close();
+
+ progressDialog.close();
+
+ return (false);
+ }
}
- if (failure)
+ if (!WriteTarEntry(firmwareInfo.GetPitFilename(), tarFile))
{
- outputTarFile->resize(0);
- outputTarFile->close();
+ 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, true))
+ {
+ 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.
- memset(tarHeader.buffer, 0, TarHeader::kBlockLength);
- outputTarFile->write(tarHeader.buffer, TarHeader::kBlockLength);
- outputTarFile->write(tarHeader.buffer, TarHeader::kBlockLength);
+ char emptyEntry[TarHeader::kBlockLength];
+ memset(emptyEntry, 0, TarHeader::kBlockLength);
+
+ tarFile->write(emptyEntry, TarHeader::kBlockLength);
+ tarFile->write(emptyEntry, TarHeader::kBlockLength);
- outputTarFile->close();
+ tarFile->close();
return (true);
}
-bool Packaging::ExtractPackage(const QString& packagePath, PackageData *outputPackageData)
+bool Packaging::ExtractPackage(const QString& packagePath, PackageData *packageData)
{
FILE *compressedPackageFile = fopen(packagePath.toStdString().c_str(), "rb");
+
+ if (fopen == NULL)
+ {
+ // TODO: "Failed to open package \"%s\"."
+ 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())
{
+ // TODO: "Error opening temporary TAR archive."
gzclose(packageFile);
return (false);
}
- char buffer[32768];
-
+ 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, 32768);
+ bytesRead = gzread(packageFile, buffer, kExtractBufferLength);
if (bytesRead == -1)
{
+ // TODO: "Error decompressing archive."
gzclose(packageFile);
+ progressDialog.close();
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, outputPackageData))
+ if (!ExtractTar(outputTar, packageData))
return (false);
// Find and read firmware.xml
- for (int i = 0; i < outputPackageData->GetFiles().length(); i++)
+ for (int i = 0; i < packageData->GetFiles().length(); i++)
{
- QTemporaryFile *file = outputPackageData->GetFiles()[i];
+ QTemporaryFile *file = packageData->GetFiles()[i];
if (file->fileTemplate() == "XXXXXX-firmware.xml")
{
- if (!outputPackageData->ReadFirmwareInfo(file))
+ if (!packageData->ReadFirmwareInfo(file))
{
- outputPackageData->Clear();
+ packageData->Clear();
return (false);
}
@@ -334,12 +526,82 @@ bool Packaging::ExtractPackage(const QString& packagePath, PackageData *outputPa
return (false);
}
-bool Packaging::BuildPackage(const QString& packagePath, const PackageData& packageData)
+bool Packaging::BuildPackage(const QString& packagePath, const FirmwareInfo& firmwareInfo)
{
- QTemporaryFile temporaryFile("XXXXXX.tar");
+ FILE *compressedPackageFile = fopen(packagePath.toStdString().c_str(), "wb");
- if (!CreateTar(packageData, &temporaryFile))
+ if (fopen == NULL)
+ {
+ // TODO: "Failed to open package "%s"
return (false);
+ }
+
+ QTemporaryFile tar("XXXXXX.tar");
+
+ if (!CreateTar(firmwareInfo, &tar))
+ return (false);
+
+ if (!tar.open())
+ {
+ // TODO: "Failed to open temporary file "%s"
+ 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)
+ {
+ // TODO: "Error reading temporary TAR file."
+ gzclose(packageFile);
+ remove(packagePath.toStdString().c_str());
+
+ progressDialog.close();
+
+ return (false);
+ }
+
+ if (gzwrite(packageFile, buffer, bytesRead) != bytesRead)
+ {
+ // TODO: "Error compressing package."
+ gzclose(packageFile);
+ remove(packagePath.toStdString().c_str());
+
+ progressDialog.close();
+
+ 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);
}
diff --git a/heimdall-frontend/Source/Packaging.h b/heimdall-frontend/Source/Packaging.h
index c341f0f..97637de 100755
--- a/heimdall-frontend/Source/Packaging.h
+++ b/heimdall-frontend/Source/Packaging.h
@@ -93,17 +93,25 @@ namespace HeimdallFrontend
class Packaging
{
private:
+
+ enum
+ {
+ kExtractBufferLength = 262144,
+ kCompressBufferLength = 262144
+ };
// TODO: Add support for sparse files to both methods.
- static bool ExtractTar(QTemporaryFile& tarFile, PackageData *outputPackageData);
- static bool CreateTar(const PackageData& packageData, QTemporaryFile *outputTarFile); // Uses original TAR format.
+ static bool ExtractTar(QTemporaryFile& tarFile, PackageData *packageData);
+
+ static bool WriteTarEntry(const QString& filename, QTemporaryFile *tarFile, bool firmwareXml = false);
+ static bool CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarFile); // Uses original TAR format.
public:
static const char *ustarMagic;
- static bool ExtractPackage(const QString& packagePath, PackageData *outputPackageData);
- static bool BuildPackage(const QString& packagePath, const PackageData& packageData);
+ static bool ExtractPackage(const QString& packagePath, PackageData *packageData);
+ static bool BuildPackage(const QString& packagePath, const FirmwareInfo& firmwareInfo);
};
}
diff --git a/heimdall-frontend/Source/mainwindow.cpp b/heimdall-frontend/Source/mainwindow.cpp
index 8043599..b44c3de 100644
--- a/heimdall-frontend/Source/mainwindow.cpp
+++ b/heimdall-frontend/Source/mainwindow.cpp
@@ -91,6 +91,7 @@ void MainWindow::UpdatePackageUserInterface(void)
developerDonateButton->setEnabled(false);
repartitionRadioButton->setChecked(false);
+ noRebootRadioButton->setChecked(false);
loadFirmwareButton->setEnabled(false);
}
@@ -126,7 +127,7 @@ void MainWindow::UpdatePackageUserInterface(void)
for (int i = 0; i < loadedPackageData.GetFirmwareInfo().GetDeviceInfos().length(); i++)
{
const DeviceInfo& deviceInfo = loadedPackageData.GetFirmwareInfo().GetDeviceInfos()[i];
- supportedDevicesListWidget->addItem(deviceInfo.GetManufacturer() + " " + deviceInfo.GetName() + " (" + deviceInfo.GetProduct() + ")");
+ supportedDevicesListWidget->addItem(deviceInfo.GetManufacturer() + " " + deviceInfo.GetName() + ": " + deviceInfo.GetProduct());
}
for (int i = 0; i < loadedPackageData.GetFirmwareInfo().GetFileInfos().length(); i++)
@@ -136,6 +137,7 @@ void MainWindow::UpdatePackageUserInterface(void)
}
repartitionRadioButton->setChecked(loadedPackageData.GetFirmwareInfo().GetRepartition());
+ noRebootRadioButton->setChecked(loadedPackageData.GetFirmwareInfo().GetNoReboot());
loadFirmwareButton->setEnabled(true);
}
@@ -143,7 +145,7 @@ void MainWindow::UpdatePackageUserInterface(void)
bool MainWindow::IsArchive(QString path)
{
- // Not a real check but hopefully it gets the message across, don't flash archives!
+ // Not a real check but hopefully it gets the message across, don't directly flash archives!
return (path.endsWith(".tar", Qt::CaseInsensitive) || path.endsWith(".gz", Qt::CaseInsensitive) || path.endsWith(".zip", Qt::CaseInsensitive)
|| path.endsWith(".bz2", Qt::CaseInsensitive) || path.endsWith(".7z", Qt::CaseInsensitive) || path.endsWith(".rar", Qt::CaseInsensitive));
}
@@ -266,7 +268,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
QObject::connect(partitionFileBrowseButton, SIGNAL(clicked()), this, SLOT(SelectPartitionFile()));
QObject::connect(pitBrowseButton, SIGNAL(clicked()), this, SLOT(SelectPit()));
+
QObject::connect(repartitionCheckBox, SIGNAL(stateChanged(int)), this, SLOT(SetRepartition(int)));
+ QObject::connect(noRebootCheckBox, SIGNAL(stateChanged(int)), this, SLOT(SetNoReboot(int)));
QObject::connect(startFlashButton, SIGNAL(clicked()), this, SLOT(StartFlash()));
@@ -394,6 +398,7 @@ void MainWindow::LoadFirmwarePackage(void)
UpdateUnusedPartitionIds();
workingPackageData.GetFirmwareInfo().SetRepartition(loadedPackageData.GetFirmwareInfo().GetRepartition());
+ workingPackageData.GetFirmwareInfo().SetNoReboot(loadedPackageData.GetFirmwareInfo().GetNoReboot());
loadedPackageData.Clear();
UpdatePackageUserInterface();
@@ -431,6 +436,9 @@ void MainWindow::LoadFirmwarePackage(void)
repartitionCheckBox->setEnabled(true);
repartitionCheckBox->setChecked(workingPackageData.GetFirmwareInfo().GetRepartition());
+ noRebootCheckBox->setEnabled(true);
+ noRebootCheckBox->setChecked(workingPackageData.GetFirmwareInfo().GetNoReboot());
+
partitionsListWidget->setEnabled(true);
addPartitionButton->setEnabled(true);
removePartitionButton->setEnabled(true && partitionsListWidget->currentRow() >= 0);
@@ -466,7 +474,7 @@ void MainWindow::SelectPartitionFile(void)
{
QString path = PromptFileSelection();
- if (path != "")
+ if (path != "" && !IsArchive(path))
{
workingPackageData.GetFirmwareInfo().GetFileInfos()[partitionsListWidget->currentRow()].SetFilename(path);
partitionFileLineEdit->setText(path);
@@ -608,6 +616,7 @@ void MainWindow::SelectPit(void)
pitLineEdit->setText(workingPackageData.GetFirmwareInfo().GetPitFilename());
repartitionCheckBox->setEnabled(validPit);
+ noRebootCheckBox->setEnabled(validPit);
partitionsListWidget->setEnabled(validPit);
addPartitionButton->setEnabled(validPit);
@@ -620,24 +629,41 @@ void MainWindow::SetRepartition(int enabled)
{
workingPackageData.GetFirmwareInfo().SetRepartition(enabled);
}
+void MainWindow::SetNoReboot(int enabled)
+{
+ workingPackageData.GetFirmwareInfo().SetNoReboot(enabled);
+}
void MainWindow::StartFlash(void)
{
+ outputPlainTextEdit->clear();
+
heimdallRunning = true;
heimdallFailed = false;
+
+ const FirmwareInfo& firmwareInfo = workingPackageData.GetFirmwareInfo();
+ const QList<FileInfo>& fileInfos = firmwareInfo.GetFileInfos();
QStringList arguments;
arguments.append("flash");
- if (repartitionCheckBox->isChecked())
- {
+ if (firmwareInfo.GetRepartition())
arguments.append("--repartition");
- arguments.append("--pit");
- arguments.append(pitLineEdit->text());
+ arguments.append("--pit");
+ arguments.append(firmwareInfo.GetPitFilename());
+
+ for (int i = 0; i < fileInfos.length(); i++)
+ {
+ QString flag;
+ flag.sprintf("--%u", fileInfos[i].GetPartitionId());
+
+ arguments.append(flag);
+ arguments.append(fileInfos[i].GetFilename());
}
- // TODO: Loop through partitions and append them.
+ if (firmwareInfo.GetNoReboot())
+ arguments.append("--no-reboot");
flashProgressBar->setEnabled(true);
UpdateStartButton();
@@ -785,10 +811,10 @@ void MainWindow::SelectDevice(int row)
void MainWindow::AddDevice(void)
{
- workingPackageData.GetFirmwareInfo().GetDeviceInfos().append(DeviceInfo(deviceManufacturerLineEdit->text(), deviceNameLineEdit->text(),
- deviceProductCodeLineEdit->text()));
+ workingPackageData.GetFirmwareInfo().GetDeviceInfos().append(DeviceInfo(deviceManufacturerLineEdit->text(), deviceProductCodeLineEdit->text(),
+ deviceNameLineEdit->text()));
- createDevicesListWidget->addItem(deviceManufacturerLineEdit->text() + " " + deviceNameLineEdit->text() + " (" + deviceProductCodeLineEdit->text() + ")");
+ createDevicesListWidget->addItem(deviceManufacturerLineEdit->text() + " " + deviceNameLineEdit->text() + ": " + deviceProductCodeLineEdit->text());
deviceManufacturerLineEdit->clear();
deviceNameLineEdit->clear();
deviceProductCodeLineEdit->clear();
@@ -825,12 +851,12 @@ void MainWindow::BuildPackage(void)
packagePath.append(".tar.gz");
}
- Packaging::BuildPackage(packagePath, workingPackageData);
+ Packaging::BuildPackage(packagePath, workingPackageData.GetFirmwareInfo());
}
void MainWindow::HandleHeimdallStdout(void)
{
- QString output = process.read(1024);
+ QString output = process.readAll();
// We often receive multiple lots of output from Heimdall at one time. So we use regular expressions
// to ensure we don't miss out on any important information.
@@ -845,35 +871,10 @@ void MainWindow::HandleHeimdallStdout(void)
flashProgressBar->setValue(percentString.mid(1, percentString.length() - 2).toInt());
}
- /*// Handle other information
-
- int endOfLastLine = output.length() - 1;
- for (; endOfLastLine > -1; endOfLastLine--)
- {
- if (output[endOfLastLine] != '\n')
- break;
- }
-
- if (endOfLastLine < 0)
- return; // Output was blank or just a bunch of new line characters.
-
- int startOfLastLine = endOfLastLine - 1;
- for (; startOfLastLine > -1; startOfLastLine--)
- {
- if (output[startOfLastLine] == '\n')
- break;
- }
-
- startOfLastLine++;
-
- // Just look at the last line of the output
- output = output.mid(startOfLastLine, endOfLastLine - startOfLastLine + 1); // Work with the last line only
-
- percentExp.setPattern("[0-9]+%");
-
- // If the last line wasn't a uploading message or a percentage transferred then display it.
- if (output.lastIndexOf(uploadingExp) < 0 && output.lastIndexOf(percentExp) < 0)
- flashLabel->setText(output);*/
+ output.remove(QChar('\b'));
+ output.replace(QChar('%'), QString("%\n"));
+ outputPlainTextEdit->insertPlainText(output);
+ outputPlainTextEdit->ensureCursorVisible();
}
void MainWindow::HandleHeimdallReturned(int exitCode, QProcess::ExitStatus exitStatus)
@@ -894,6 +895,9 @@ void MainWindow::HandleHeimdallReturned(int exitCode, QProcess::ExitStatus exitS
{
QString error = process.readAllStandardError();
+ outputPlainTextEdit->insertPlainText(error);
+ outputPlainTextEdit->ensureCursorVisible();
+
int firstNewLineChar = error.indexOf('\n');
if (firstNewLineChar == 0)
diff --git a/heimdall-frontend/Source/mainwindow.h b/heimdall-frontend/Source/mainwindow.h
index 7525d67..6e16596 100644
--- a/heimdall-frontend/Source/mainwindow.h
+++ b/heimdall-frontend/Source/mainwindow.h
@@ -99,7 +99,9 @@ namespace HeimdallFrontend
void RemovePartition(void);
void SelectPit(void);
+
void SetRepartition(int enabled);
+ void SetNoReboot(int enabled);
void StartFlash(void);
diff --git a/heimdall-frontend/aboutform.ui b/heimdall-frontend/aboutform.ui
index 39e87cc..764e751 100644
--- a/heimdall-frontend/aboutform.ui
+++ b/heimdall-frontend/aboutform.ui
@@ -167,7 +167,7 @@ THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRES
</property>
<property name="text">
<string>Heimdall Frontend
-Version 1.3.0
+Version 1.3 (beta)
Copyright © 2010 Benjamin Dobell, Glass Echidna</string>
</property>
<property name="textFormat">
diff --git a/heimdall-frontend/mainwindow.ui b/heimdall-frontend/mainwindow.ui
index 6165b8d..020c761 100644
--- a/heimdall-frontend/mainwindow.ui
+++ b/heimdall-frontend/mainwindow.ui
@@ -108,9 +108,9 @@
<property name="geometry">
<rect>
<x>510</x>
- <y>20</y>
+ <y>10</y>
<width>251</width>
- <height>341</height>
+ <height>331</height>
</rect>
</property>
<property name="title">
@@ -122,7 +122,7 @@
<x>10</x>
<y>20</y>
<width>231</width>
- <height>311</height>
+ <height>301</height>
</rect>
</property>
</widget>
@@ -186,7 +186,7 @@
<property name="geometry">
<rect>
<x>520</x>
- <y>370</y>
+ <y>350</y>
<width>241</width>
<height>21</height>
</rect>
@@ -375,6 +375,22 @@
</property>
</widget>
</widget>
+ <widget class="QRadioButton" name="noRebootRadioButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>520</x>
+ <y>380</y>
+ <width>241</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>No Reboot Recommended</string>
+ </property>
+ </widget>
</widget>
<widget class="QWidget" name="flashTab">
<attribute name="title">
@@ -410,7 +426,7 @@
</widget>
<widget class="QPlainTextEdit" name="outputPlainTextEdit">
<property name="enabled">
- <bool>false</bool>
+ <bool>true</bool>
</property>
<property name="geometry">
<rect>
@@ -420,6 +436,15 @@
<height>91</height>
</rect>
</property>
+ <property name="undoRedoEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="plainText">
+ <string notr="true"/>
+ </property>
</widget>
<widget class="QLabel" name="flashLabel">
<property name="geometry">
@@ -478,7 +503,7 @@
<x>10</x>
<y>20</y>
<width>381</width>
- <height>91</height>
+ <height>51</height>
</rect>
</property>
<property name="title">
@@ -491,7 +516,7 @@
<property name="geometry">
<rect>
<x>10</x>
- <y>50</y>
+ <y>20</y>
<width>281</width>
<height>21</height>
</rect>
@@ -507,7 +532,7 @@
<property name="geometry">
<rect>
<x>300</x>
- <y>50</y>
+ <y>20</y>
<width>71</width>
<height>23</height>
</rect>
@@ -516,22 +541,6 @@
<string>Browse</string>
</property>
</widget>
- <widget class="QCheckBox" name="repartitionCheckBox">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>20</y>
- <width>91</width>
- <height>17</height>
- </rect>
- </property>
- <property name="text">
- <string>Repartition</string>
- </property>
- </widget>
</widget>
<widget class="QPushButton" name="removePartitionButton">
<property name="enabled">
@@ -540,7 +549,7 @@
<property name="geometry">
<rect>
<x>670</x>
- <y>230</y>
+ <y>240</y>
<width>71</width>
<height>23</height>
</rect>
@@ -669,7 +678,7 @@
<property name="geometry">
<rect>
<x>400</x>
- <y>230</y>
+ <y>240</y>
<width>71</width>
<height>23</height>
</rect>
@@ -687,9 +696,41 @@
<x>400</x>
<y>20</y>
<width>341</width>
- <height>201</height>
+ <height>211</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="noRebootCheckBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>150</x>
+ <y>80</y>
+ <width>121</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>No Reboot</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="repartitionCheckBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>80</y>
+ <width>121</width>
+ <height>21</height>
</rect>
</property>
+ <property name="text">
+ <string>Repartition</string>
+ </property>
</widget>
</widget>
</widget>
@@ -1221,7 +1262,6 @@
<tabstop>includedFilesListWidget</tabstop>
<tabstop>repartitionRadioButton</tabstop>
<tabstop>loadFirmwareButton</tabstop>
- <tabstop>repartitionCheckBox</tabstop>
<tabstop>pitLineEdit</tabstop>
<tabstop>pitBrowseButton</tabstop>
<tabstop>partitionNameComboBox</tabstop>
diff --git a/heimdall/source/BridgeManager.cpp b/heimdall/source/BridgeManager.cpp
index 204d87f..ef5faa6 100644
--- a/heimdall/source/BridgeManager.cpp
+++ b/heimdall/source/BridgeManager.cpp
@@ -116,7 +116,7 @@ bool BridgeManager::DetectDevice(void)
int result = libusb_init(&libusbContext);
if (result != LIBUSB_SUCCESS)
{
- Interface::PrintError("Failed to initialise libusb. Error: %i\n", result);
+ Interface::PrintError("Failed to initialise libusb. Error: %d\n", result);
return (false);
}
@@ -153,7 +153,7 @@ bool BridgeManager::Initialise(void)
int result = libusb_init(&libusbContext);
if (result != LIBUSB_SUCCESS)
{
- Interface::PrintError("Failed to initialise libusb. Error: %i\n", result);
+ Interface::PrintError("Failed to initialise libusb. Error: %d\n", result);
return (false);
}
@@ -191,7 +191,7 @@ bool BridgeManager::Initialise(void)
result = libusb_open(heimdallDevice, &deviceHandle);
if (result != LIBUSB_SUCCESS)
{
- Interface::PrintError("Failed to access device. Error: %i\n", result);
+ Interface::PrintError("Failed to access device. Error: %d\n", result);
return (false);
}
@@ -528,7 +528,7 @@ bool BridgeManager::SendPacket(OutboundPacket *packet, int timeout) const
int retryDelay = (communicationDelay > 250) ? communicationDelay : 250;
if (verbose)
- Interface::PrintError("Error %i whilst sending packet. ", result);
+ Interface::PrintError("Error %d whilst sending packet. ", result);
// Retry
for (int i = 0; i < 5; i++)
@@ -546,7 +546,7 @@ bool BridgeManager::SendPacket(OutboundPacket *packet, int timeout) const
break;
if (verbose)
- Interface::PrintError("Error %i whilst sending packet. ", result);
+ Interface::PrintError("Error %d whilst sending packet. ", result);
}
if (verbose)
@@ -574,7 +574,7 @@ bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout) const
int retryDelay = (communicationDelay > 250) ? communicationDelay : 250;
if (verbose)
- Interface::PrintError("Error %i whilst receiving packet. ", result);
+ Interface::PrintError("Error %d whilst receiving packet. ", result);
// Retry
for (int i = 0; i < 5; i++)
@@ -592,7 +592,7 @@ bool BridgeManager::ReceivePacket(InboundPacket *packet, int timeout) const
break;
if (verbose)
- Interface::PrintError("Error %i whilst receiving packet. ", result);
+ Interface::PrintError("Error %d whilst receiving packet. ", result);
if (i >= 3)
{
@@ -750,7 +750,7 @@ int BridgeManager::ReceivePitFile(unsigned char **pitBuffer) const
if (!success)
{
- Interface::PrintError("Failed to request PIT file part #%i!\n", i);
+ Interface::PrintError("Failed to request PIT file part #%d!\n", i);
delete [] buffer;
return (0);
}
@@ -760,7 +760,7 @@ int BridgeManager::ReceivePitFile(unsigned char **pitBuffer) const
if (!success)
{
- Interface::PrintError("Failed to receive PIT file part #%i!\n", i);
+ Interface::PrintError("Failed to receive PIT file part #%d!\n", i);
delete receiveFilePartPacket;
delete [] buffer;
return (0);
@@ -906,7 +906,7 @@ bool BridgeManager::SendFile(FILE *file, int destination, int fileIdentifier) co
if (verbose)
{
const unsigned char *data = sendFilePartResponse->GetData();
- Interface::Print("File Part #%i... Response: %X %X %X %X %X %X %X %X \n", filePartIndex,
+ Interface::Print("File Part #%d... Response: %X %X %X %X %X %X %X %X \n", filePartIndex,
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
}
@@ -939,7 +939,7 @@ bool BridgeManager::SendFile(FILE *file, int destination, int fileIdentifier) co
if (verbose)
{
const unsigned char *data = sendFilePartResponse->GetData();
- Interface::Print("File Part #%i... Response: %X %X %X %X %X %X %X %X \n", filePartIndex,
+ Interface::Print("File Part #%d... Response: %X %X %X %X %X %X %X %X \n", filePartIndex,
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
}
@@ -947,7 +947,7 @@ bool BridgeManager::SendFile(FILE *file, int destination, int fileIdentifier) co
if (receivedPartIndex != filePartIndex)
{
- Interface::PrintError("\nERROR: Expected file part index: %i Received: %i\n",
+ Interface::PrintError("\nERROR: Expected file part index: %d Received: %d\n",
filePartIndex, receivedPartIndex);
return (false);
}
@@ -962,7 +962,7 @@ bool BridgeManager::SendFile(FILE *file, int destination, int fileIdentifier) co
if (receivedPartIndex != filePartIndex)
{
- Interface::PrintError("\nERROR: Expected file part index: %i Received: %i\n",
+ Interface::PrintError("\nERROR: Expected file part index: %d Received: %d\n",
filePartIndex, receivedPartIndex);
return (false);
}
@@ -978,9 +978,9 @@ bool BridgeManager::SendFile(FILE *file, int destination, int fileIdentifier) co
if (currentPercent != previousPercent)
{
if (previousPercent < 10)
- Interface::Print("\b\b%i%%", currentPercent);
+ Interface::Print("\b\b%d%%", currentPercent);
else
- Interface::Print("\b\b\b%i%%", currentPercent);
+ Interface::Print("\b\b\b%d%%", currentPercent);
}
}
@@ -1076,7 +1076,7 @@ bool BridgeManager::ReceiveDump(int chipType, int chipId, FILE *file) const
if (!success)
{
- Interface::PrintError("Failed to request dump part #%i!\n", i);
+ Interface::PrintError("Failed to request dump part #%d!\n", i);
delete [] buffer;
return (false);
}
@@ -1086,7 +1086,7 @@ bool BridgeManager::ReceiveDump(int chipType, int chipId, FILE *file) const
if (!success)
{
- Interface::PrintError("Failed to receive dump part #%i!\n", i);
+ Interface::PrintError("Failed to receive dump part #%d!\n", i);
continue;
delete receiveFilePartPacket;
delete [] buffer;
diff --git a/heimdall/source/Interface.cpp b/heimdall/source/Interface.cpp
index 5f0942d..35105bb 100644
--- a/heimdall/source/Interface.cpp
+++ b/heimdall/source/Interface.cpp
@@ -31,7 +31,7 @@ using namespace std;
using namespace libpit;
using namespace Heimdall;
-const char *Interface::version = "v1.3.0";
+const char *Interface::version = "v1.3 (beta)";
const char *Interface::usage = "Usage: heimdall <action> <arguments> [--verbose] [--no-reboot] [--delay <ms>]\n\
\n\
diff --git a/heimdall/source/Interface.h b/heimdall/source/Interface.h
index c6bdef3..7b1741d 100644
--- a/heimdall/source/Interface.h
+++ b/heimdall/source/Interface.h
@@ -249,6 +249,11 @@ namespace Heimdall
static void PrintReleaseInfo(void);
static void PrintPit(const PitData *pitData);
+
+ static string& GetPitArgument(void)
+ {
+ return (flashValueArguments[kFlashValueArgPit]);
+ }
};
}
diff --git a/heimdall/source/main.cpp b/heimdall/source/main.cpp
index 64cc553..f24b64a 100644
--- a/heimdall/source/main.cpp
+++ b/heimdall/source/main.cpp
@@ -348,7 +348,7 @@ bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFile
// 131072 for Galaxy S II, 0 for other devices.
if (deviceInfoResult != 0 && deviceInfoResult != 131072)
{
- Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%i\n", deviceInfoResult);
+ Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", deviceInfoResult);
return (false);
}
@@ -360,7 +360,7 @@ bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFile
// TODO: Work out what this value is... it has been either 180 or 0 for Galaxy S phones, 3 on the Galaxy Tab, 190 for SHW-M110S.
if (deviceInfoResult != 180 && deviceInfoResult != 0 && deviceInfoResult != 3 && deviceInfoResult != 190)
{
- Interface::PrintError("Unexpected device info response!\nExpected: 180, 0 or 3\nReceived:%i\n", deviceInfoResult);
+ Interface::PrintError("Unexpected device info response!\nExpected: 180, 0 or 3\nReceived:%d\n", deviceInfoResult);
return (false);
}
@@ -369,9 +369,12 @@ bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFile
int totalBytes = 0;
for (map<string, FILE *>::const_iterator it = argumentFileMap.begin(); it != argumentFileMap.end(); it++)
{
- fseek(it->second, 0, SEEK_END);
- totalBytes += ftell(it->second);
- rewind(it->second);
+ if (repartition || it->first != Interface::GetPitArgument())
+ {
+ fseek(it->second, 0, SEEK_END);
+ totalBytes += ftell(it->second);
+ rewind(it->second);
+ }
}
DeviceInfoPacket *deviceInfoPacket = new DeviceInfoPacket(DeviceInfoPacket::kTotalBytes, totalBytes);
@@ -397,27 +400,22 @@ bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFile
if (deviceInfoResult != 0)
{
- Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%i\n", deviceInfoResult);
+ Interface::PrintError("Unexpected device info response!\nExpected: 0\nReceived:%d\n", deviceInfoResult);
return (false);
}
// -----------------------------------------------------
PitData *pitData;
- FILE *localPitFile = nullptr;
+ PitData *localPitData = nullptr;
- if (repartition)
- {
- // If we're repartitioning then we need to unpack the information from the specified PIT file.
- map<string, FILE *>::iterator it = argumentFileMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]);
+ FILE *localPitFile = nullptr;
- // This shouldn't ever happen due to early checks, but we'll check again just in case...
- if (it == argumentFileMap.end())
- {
- Interface::PrintError("Attempt was made to repartition without specifying a PIT file!\n");
- return (false);
- }
+ // If a PIT file was passed as an argument then we must unpack it.
+ map<string, FILE *>::iterator it = argumentFileMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]);
+ if (it != argumentFileMap.end())
+ {
localPitFile = it->second;
// Load the local pit file into memory.
@@ -432,11 +430,17 @@ bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFile
int dataRead = fread(pitFileBuffer, 1, localPitFileSize, localPitFile);
rewind(localPitFile);
- pitData = new PitData();
- pitData->Unpack(pitFileBuffer);
+ localPitData = new PitData();
+ localPitData->Unpack(pitFileBuffer);
delete [] pitFileBuffer;
}
+
+ if (repartition)
+ {
+ // Use the local PIT file data.
+ pitData = localPitData;
+ }
else
{
// If we're not repartitioning then we need to retrieve the device's PIT file and unpack it.
@@ -447,6 +451,21 @@ bool attemptFlash(BridgeManager *bridgeManager, map<string, FILE *> argumentFile
pitData->Unpack(pitFileBuffer);
delete [] pitFileBuffer;
+
+ if (localPitData != nullptr)
+ {
+ // The user has specified a PIT without repartitioning, we should verify the local and device PIT data match!
+ bool pitsMatch = pitData->Matches(localPitData);
+ delete localPitData;
+
+ if (!pitsMatch)
+ {
+ Interface::PrintError("Local and device PIT files don't match and repartition wasn't specified!\n");
+
+ delete pitData;
+ return (false);
+ }
+ }
}
map<unsigned int, PartitionNameFilePair> partitionFileMap;
@@ -521,13 +540,6 @@ int main(int argc, char **argv)
return (0);
}
- if (argumentMap.find(Interface::actions[Interface::kActionFlash].valueArguments[Interface::kFlashValueArgPit]) != argumentMap.end()
- && argumentMap.find(Interface::actions[Interface::kActionFlash].valuelessArguments[Interface::kFlashValuelessArgRepartition]) == argumentMap.end())
- {
- Interface::Print("A PIT file should only be used when repartitioning.\n");
- return (0);
- }
-
break;
case Interface::kActionDump:
diff --git a/libpit/Source/libpit.cpp b/libpit/Source/libpit.cpp
index 030a80b..1eb3e76 100755
--- a/libpit/Source/libpit.cpp
+++ b/libpit/Source/libpit.cpp
@@ -43,6 +43,21 @@ PitEntry::~PitEntry()
{
}
+bool PitEntry::Matches(const PitEntry *otherPitEntry) const
+{
+ if (unused == otherPitEntry->unused && partitionType == otherPitEntry->partitionType && partitionIdentifier == otherPitEntry->partitionIdentifier
+ && partitionFlags == otherPitEntry->partitionFlags && unknown1 == otherPitEntry->unknown1 && partitionBlockSize == otherPitEntry->partitionBlockSize
+ && partitionBlockCount == otherPitEntry->partitionBlockCount && unknown2 == otherPitEntry->unknown2 && unknown3 == otherPitEntry->unknown3
+ && strcmp(partitionName, otherPitEntry->partitionName) == 0 && strcmp(filename, otherPitEntry->filename) == 0)
+ {
+ return (true);
+ }
+ else
+ {
+ return (false);
+ }
+}
+
PitData::PitData()
@@ -179,6 +194,26 @@ void PitData::Pack(unsigned char *data) const
}
}
+bool PitData::Matches(const PitData *otherPitData) const
+{
+ if (entryCount == otherPitData->entryCount && unknown1 == otherPitData->unknown1 && unknown2 == otherPitData->unknown2
+ && unknown3 == otherPitData->unknown3 && unknown4 == otherPitData->unknown4 && unknown5 == otherPitData->unknown5
+ && unknown6 == otherPitData->unknown6 && unknown7 == otherPitData->unknown7 && unknown8 == otherPitData->unknown8)
+ {
+ for (unsigned int i = 0; i < entryCount; i++)
+ {
+ if (!entries[i]->Matches(otherPitData->entries[i]))
+ return (false);
+ }
+
+ return (true);
+ }
+ else
+ {
+ return (false);
+ }
+}
+
void PitData::Clear(void)
{
entryCount = 0;
diff --git a/libpit/Source/libpit.h b/libpit/Source/libpit.h
index 636f1e1..fa4a534 100755
--- a/libpit/Source/libpit.h
+++ b/libpit/Source/libpit.h
@@ -21,6 +21,10 @@
#ifndef LIBPIT_H
#define LIBPIT_H
+#ifdef WIN32
+#pragma warning(disable : 4996)
+#endif
+
// C Standard Library
#include <string.h>
#include <vector>
@@ -74,6 +78,8 @@ namespace libpit
PitEntry();
~PitEntry();
+ bool Matches(const PitEntry *otherPitEntry) const;
+
bool GetUnused(void) const
{
return unused;
@@ -285,6 +291,8 @@ namespace libpit
bool Unpack(const unsigned char *data);
void Pack(unsigned char *data) const;
+ bool Matches(const PitData *otherPitData) const;
+
void Clear(void);
PitEntry *GetEntry(unsigned int index);