summaryrefslogtreecommitdiffstats
path: root/rbutil/rbutilqt/base
diff options
context:
space:
mode:
authorDominik Riebeling <Dominik.Riebeling@gmail.com>2008-10-12 19:21:58 +0000
committerDominik Riebeling <Dominik.Riebeling@gmail.com>2008-10-12 19:21:58 +0000
commitf958717d43420655519ae079ef0d35aa912411b2 (patch)
treedf0dbb774dc3619e2b53c944c6928724092dc171 /rbutil/rbutilqt/base
parent3d30029883e7e2a862bceede967d95d0bfbd93bb (diff)
downloadrockbox-f958717d43420655519ae079ef0d35aa912411b2.tar.gz
rockbox-f958717d43420655519ae079ef0d35aa912411b2.tar.bz2
rockbox-f958717d43420655519ae079ef0d35aa912411b2.zip
Separate basic functionality from GUI parts by moving it into a separate folder. Some files still need to get cleaned up prior moving them too.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18788 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'rbutil/rbutilqt/base')
-rw-r--r--rbutil/rbutilqt/base/autodetection.cpp391
-rw-r--r--rbutil/rbutilqt/base/autodetection.h63
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallbase.cpp184
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallbase.h90
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallfile.cpp145
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallfile.h44
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallhex.cpp244
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallhex.h57
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallipod.cpp235
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallipod.h50
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallmi4.cpp140
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallmi4.h44
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallsansa.cpp244
-rw-r--r--rbutil/rbutilqt/base/bootloaderinstallsansa.h48
-rw-r--r--rbutil/rbutilqt/base/httpget.cpp413
-rw-r--r--rbutil/rbutilqt/base/httpget.h107
-rw-r--r--rbutil/rbutilqt/base/rbunzip.cpp48
-rw-r--r--rbutil/rbutilqt/base/rbunzip.h46
-rw-r--r--rbutil/rbutilqt/base/rbzip.cpp65
-rw-r--r--rbutil/rbutilqt/base/rbzip.h45
-rw-r--r--rbutil/rbutilqt/base/utils.cpp101
-rw-r--r--rbutil/rbutilqt/base/utils.h33
22 files changed, 2837 insertions, 0 deletions
diff --git a/rbutil/rbutilqt/base/autodetection.cpp b/rbutil/rbutilqt/base/autodetection.cpp
new file mode 100644
index 0000000000..67e95b998d
--- /dev/null
+++ b/rbutil/rbutilqt/base/autodetection.cpp
@@ -0,0 +1,391 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2007 by Dominik Wenger
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include "autodetection.h"
+
+#if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
+#include <stdio.h>
+#include <usb.h>
+#endif
+#if defined(Q_OS_LINUX)
+#include <mntent.h>
+#endif
+#if defined(Q_OS_MACX)
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#endif
+#if defined(Q_OS_WIN32)
+#if defined(UNICODE)
+#define _UNICODE
+#endif
+#include <stdio.h>
+#include <tchar.h>
+#include <windows.h>
+#include <setupapi.h>
+#include <winioctl.h>
+#endif
+#include "detect.h"
+#include "utils.h"
+
+Autodetection::Autodetection(QObject* parent): QObject(parent)
+{
+
+}
+
+bool Autodetection::detect()
+{
+ m_device = "";
+ m_mountpoint = "";
+ m_errdev = "";
+
+ detectUsb();
+
+ // Try detection via rockbox.info / rbutil.log
+ QStringList mountpoints = getMountpoints();
+
+ for(int i=0; i< mountpoints.size();i++)
+ {
+ // do the file checking
+ QDir dir(mountpoints.at(i));
+ qDebug() << "paths to check for player specific files:" << mountpoints;
+ if(dir.exists())
+ {
+ // check logfile first.
+ if(QFile(mountpoints.at(i) + "/.rockbox/rbutil.log").exists()) {
+ QSettings log(mountpoints.at(i) + "/.rockbox/rbutil.log",
+ QSettings::IniFormat, this);
+ if(!log.value("platform").toString().isEmpty()) {
+ if(m_device.isEmpty())
+ m_device = log.value("platform").toString();
+ m_mountpoint = mountpoints.at(i);
+ qDebug() << "rbutil.log detected:" << m_device << m_mountpoint;
+ return true;
+ }
+ }
+
+ // check rockbox-info.txt afterwards.
+ QFile file(mountpoints.at(i) + "/.rockbox/rockbox-info.txt");
+ if(file.exists())
+ {
+ file.open(QIODevice::ReadOnly | QIODevice::Text);
+ QString line = file.readLine();
+ if(line.startsWith("Target: "))
+ {
+ line.remove("Target: ");
+ if(m_device.isEmpty())
+ m_device = line.trimmed(); // trim whitespaces
+ m_mountpoint = mountpoints.at(i);
+ qDebug() << "rockbox-info.txt detected:" << m_device << m_mountpoint;
+ return true;
+ }
+ }
+ // check for some specific files in root folder
+ QDir root(mountpoints.at(i));
+ QStringList rootentries = root.entryList(QDir::Files);
+ if(rootentries.contains("archos.mod", Qt::CaseInsensitive))
+ {
+ // archos.mod in root folder -> Archos Player
+ m_device = "player";
+ m_mountpoint = mountpoints.at(i);
+ return true;
+ }
+ if(rootentries.contains("ONDIOST.BIN", Qt::CaseInsensitive))
+ {
+ // ONDIOST.BIN in root -> Ondio FM
+ m_device = "ondiofm";
+ m_mountpoint = mountpoints.at(i);
+ return true;
+ }
+ if(rootentries.contains("ONDIOSP.BIN", Qt::CaseInsensitive))
+ {
+ // ONDIOSP.BIN in root -> Ondio SP
+ m_device = "ondiosp";
+ m_mountpoint = mountpoints.at(i);
+ return true;
+ }
+ if(rootentries.contains("ajbrec.ajz", Qt::CaseInsensitive))
+ {
+ qDebug() << "ajbrec.ajz found. Trying detectAjbrec()";
+ if(detectAjbrec(mountpoints.at(i))) {
+ m_mountpoint = mountpoints.at(i);
+ qDebug() << m_device;
+ return true;
+ }
+ }
+ // detection based on player specific folders
+ QStringList rootfolders = root.entryList(QDir::Dirs
+ | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
+ if(rootfolders.contains("GBSYSTEM", Qt::CaseInsensitive))
+ {
+ // GBSYSTEM folder -> Gigabeat
+ m_device = "gigabeatf";
+ m_mountpoint = mountpoints.at(i);
+ return true;
+ }
+#if defined(Q_OS_WIN32)
+ // on windows, try to detect the drive letter of an Ipod
+ if(rootfolders.contains("iPod_Control", Qt::CaseInsensitive))
+ {
+ // iPod_Control folder -> Ipod found
+ // detecting of the Ipod type is done below using ipodpatcher
+ m_mountpoint = mountpoints.at(i);
+ }
+#endif
+ }
+
+ }
+
+ int n;
+ // try ipodpatcher
+ // initialize sector buffer. Needed.
+ ipod_sectorbuf = NULL;
+ ipod_alloc_buffer(&ipod_sectorbuf, BUFFER_SIZE);
+ struct ipod_t ipod;
+ n = ipod_scan(&ipod);
+ if(n == 1) {
+ qDebug() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname;
+ m_device = ipod.targetname;
+ m_mountpoint = resolveMountPoint(ipod.diskname);
+ return true;
+ }
+ else {
+ qDebug() << "ipodpatcher: no Ipod found." << n;
+ }
+ free(ipod_sectorbuf);
+ ipod_sectorbuf = NULL;
+
+ // try sansapatcher
+ // initialize sector buffer. Needed.
+ sansa_sectorbuf = NULL;
+ sansa_alloc_buffer(&sansa_sectorbuf, BUFFER_SIZE);
+ struct sansa_t sansa;
+ n = sansa_scan(&sansa);
+ if(n == 1) {
+ qDebug() << "Sansa found:" << sansa.targetname << "at" << sansa.diskname;
+ m_device = QString("sansa%1").arg(sansa.targetname);
+ m_mountpoint = resolveMountPoint(sansa.diskname);
+ return true;
+ }
+ else {
+ qDebug() << "sansapatcher: no Sansa found." << n;
+ }
+ free(sansa_sectorbuf);
+ sansa_sectorbuf = NULL;
+
+ if(m_mountpoint.isEmpty() && m_device.isEmpty() && m_errdev.isEmpty() && m_incompat.isEmpty())
+ return false;
+ return true;
+}
+
+
+QStringList Autodetection::getMountpoints()
+{
+ QStringList tempList;
+#if defined(Q_OS_WIN32)
+ QFileInfoList list = QDir::drives();
+ for(int i=0; i<list.size();i++)
+ {
+ tempList << list.at(i).absolutePath();
+ }
+
+#elif defined(Q_OS_MACX)
+ int num;
+ struct statfs *mntinf;
+
+ num = getmntinfo(&mntinf, MNT_WAIT);
+ while(num--) {
+ tempList << QString(mntinf->f_mntonname);
+ mntinf++;
+ }
+#elif defined(Q_OS_LINUX)
+
+ FILE *mn = setmntent("/etc/mtab", "r");
+ if(!mn)
+ return QStringList("");
+
+ struct mntent *ent;
+ while((ent = getmntent(mn)))
+ tempList << QString(ent->mnt_dir);
+ endmntent(mn);
+
+#else
+#error Unknown Plattform
+#endif
+ return tempList;
+}
+
+QString Autodetection::resolveMountPoint(QString device)
+{
+ qDebug() << "Autodetection::resolveMountPoint(QString)" << device;
+
+#if defined(Q_OS_LINUX)
+ FILE *mn = setmntent("/etc/mtab", "r");
+ if(!mn)
+ return QString("");
+
+ struct mntent *ent;
+ while((ent = getmntent(mn))) {
+ if(QString(ent->mnt_fsname).startsWith(device)
+ && QString(ent->mnt_type).contains("vfat", Qt::CaseInsensitive)) {
+ endmntent(mn);
+ return QString(ent->mnt_dir);
+ }
+ }
+ endmntent(mn);
+
+#endif
+
+#if defined(Q_OS_MACX)
+ int num;
+ struct statfs *mntinf;
+
+ num = getmntinfo(&mntinf, MNT_WAIT);
+ while(num--) {
+ if(QString(mntinf->f_mntfromname).startsWith(device)
+ && QString(mntinf->f_fstypename).contains("vfat", Qt::CaseInsensitive))
+ return QString(mntinf->f_mntonname);
+ mntinf++;
+ }
+#endif
+
+#if defined(Q_OS_WIN32)
+ QString result;
+ unsigned int driveno = device.replace(QRegExp("^.*([0-9]+)"), "\\1").toInt();
+
+ for(int letter = 'A'; letter <= 'Z'; letter++) {
+ DWORD written;
+ HANDLE h;
+ TCHAR uncpath[MAX_PATH];
+ UCHAR buffer[0x400];
+ PVOLUME_DISK_EXTENTS extents = (PVOLUME_DISK_EXTENTS)buffer;
+
+ _stprintf(uncpath, _TEXT("\\\\.\\%c:"), letter);
+ h = CreateFile(uncpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if(h == INVALID_HANDLE_VALUE) {
+ //qDebug() << "error getting extents for" << uncpath;
+ continue;
+ }
+ // get the extents
+ if(DeviceIoControl(h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+ NULL, 0, extents, sizeof(buffer), &written, NULL)) {
+ for(unsigned int a = 0; a < extents->NumberOfDiskExtents; a++) {
+ qDebug() << "Disk:" << extents->Extents[a].DiskNumber;
+ if(extents->Extents[a].DiskNumber == driveno) {
+ result = letter;
+ qDebug("drive found for volume %i: %c", driveno, letter);
+ break;
+ }
+ }
+
+ }
+
+ }
+ if(!result.isEmpty())
+ return result + ":/";
+#endif
+ return QString("");
+}
+
+
+/** @brief detect devices based on usb pid / vid.
+ * @return true upon success, false otherwise.
+ */
+bool Autodetection::detectUsb()
+{
+ // usbids holds the mapping in the form
+ // ((VID<<16)|(PID)), targetname
+ // the ini file needs to hold the IDs as hex values.
+ QMap<int, QString> usbids = settings->usbIdMap();
+ QMap<int, QString> usberror = settings->usbIdErrorMap();
+ QMap<int, QString> usbincompat = settings->usbIdIncompatMap();
+
+ // usb pid detection
+ QList<uint32_t> attached;
+ attached = Detect::listUsbIds();
+
+ int i = attached.size();
+ while(i--) {
+ if(usbids.contains(attached.at(i))) {
+ m_device = usbids.value(attached.at(i));
+ qDebug() << "[USB] detected supported player" << m_device;
+ return true;
+ }
+ if(usberror.contains(attached.at(i))) {
+ m_errdev = usberror.value(attached.at(i));
+ qDebug() << "[USB] detected problem with player" << m_errdev;
+ return true;
+ }
+ if(usbincompat.contains(attached.at(i))) {
+ m_incompat = usbincompat.value(attached.at(i));
+ qDebug() << "[USB] detected incompatible player" << m_incompat;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool Autodetection::detectAjbrec(QString root)
+{
+ QFile f(root + "/ajbrec.ajz");
+ char header[24];
+ f.open(QIODevice::ReadOnly);
+ if(!f.read(header, 24)) return false;
+
+ // check the header of the file.
+ // recorder v1 had a 6 bytes sized header
+ // recorder v2, FM, Ondio SP and FM have a 24 bytes header.
+
+ // recorder v1 has the binary length in the first 4 bytes, so check
+ // for them first.
+ int len = (header[0]<<24) | (header[1]<<16) | (header[2]<<8) | header[3];
+ qDebug() << "possible bin length:" << len;
+ qDebug() << "file len:" << f.size();
+ if((f.size() - 6) == len)
+ m_device = "recorder";
+
+ // size didn't match, now we need to assume we have a headerlength of 24.
+ switch(header[11]) {
+ case 2:
+ m_device = "recorderv2";
+ break;
+
+ case 4:
+ m_device = "fmrecorder";
+ break;
+
+ case 8:
+ m_device = "ondiofm";
+ break;
+
+ case 16:
+ m_device = "ondiosp";
+ break;
+
+ default:
+ break;
+ }
+ f.close();
+
+ if(m_device.isEmpty()) return false;
+ return true;
+}
diff --git a/rbutil/rbutilqt/base/autodetection.h b/rbutil/rbutilqt/base/autodetection.h
new file mode 100644
index 0000000000..1fbe47f9a7
--- /dev/null
+++ b/rbutil/rbutilqt/base/autodetection.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2007 by Dominik Wenger
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#ifndef AUTODETECTION_H_
+#define AUTODETECTION_H_
+
+#include <QtCore>
+#include "rbsettings.h"
+
+#include "../ipodpatcher/ipodpatcher.h"
+#include "../sansapatcher/sansapatcher.h"
+
+class Autodetection :public QObject
+{
+ Q_OBJECT
+
+public:
+ Autodetection(QObject* parent=0);
+
+ void setSettings(RbSettings* sett) {settings = sett;}
+
+ bool detect();
+
+ QString getDevice() {return m_device;}
+ QString getMountPoint() {return m_mountpoint;}
+ QString errdev(void) { return m_errdev; }
+ QString incompatdev(void) { return m_incompat; }
+
+private:
+ QStringList getMountpoints(void);
+ QString resolveMountPoint(QString);
+ bool detectUsb(void);
+ bool detectAjbrec(QString);
+
+ QString m_device;
+ QString m_mountpoint;
+ QString m_errdev;
+ QString m_incompat;
+ QList<int> m_usbconid;
+ RbSettings* settings;
+};
+
+
+#endif /*AUTODETECTION_H_*/
diff --git a/rbutil/rbutilqt/base/bootloaderinstallbase.cpp b/rbutil/rbutilqt/base/bootloaderinstallbase.cpp
new file mode 100644
index 0000000000..d0abffa44d
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallbase.cpp
@@ -0,0 +1,184 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#include <QtCore>
+
+#include "bootloaderinstallbase.h"
+#include "utils.h"
+
+BootloaderInstallBase::BootloaderType BootloaderInstallBase::installed(void)
+{
+ return BootloaderUnknown;
+}
+
+
+BootloaderInstallBase::Capabilities BootloaderInstallBase::capabilities(void)
+{
+ return 0;
+}
+
+
+void BootloaderInstallBase::downloadBlStart(QUrl source)
+{
+ m_http.setFile(&m_tempfile);
+ m_http.setCache(true);
+ connect(&m_http, SIGNAL(done(bool)), this, SLOT(downloadBlFinish(bool)));
+ // connect the http read signal to our logProgess *signal*
+ // to immediately emit it without any helper function.
+ connect(&m_http, SIGNAL(dataReadProgress(int, int)),
+ this, SIGNAL(logProgress(int, int)));
+ m_http.getFile(source);
+}
+
+
+void BootloaderInstallBase::downloadReqFinished(int id, bool error)
+{
+ qDebug() << __FILE__ << "::" << __func__ << id << error;
+ qDebug() << "error:" << m_http.errorString();
+
+ downloadBlFinish(error);
+}
+
+
+void BootloaderInstallBase::downloadBlFinish(bool error)
+{
+ qDebug() << __FILE__ << "::" << __func__ << ": error =" << error;
+
+ // update progress bar
+ emit logProgress(100, 100);
+
+ if(m_http.httpResponse() != 200) {
+ emit logItem(tr("Download error: received HTTP error %1.")
+ .arg(m_http.errorString()), LOGERROR);
+ emit done(true);
+ return;
+ }
+ if(error) {
+ emit logItem(tr("Download error: %1")
+ .arg(m_http.error()), LOGERROR);
+ emit done(true);
+ return;
+ }
+ else if(m_http.isCached())
+ emit logItem(tr("Download finished (cache used)."), LOGOK);
+ else
+ emit logItem(tr("Download finished."), LOGOK);
+
+ m_blversion = m_http.timestamp();
+ emit downloadDone();
+}
+
+void BootloaderInstallBase::installBlfile(void)
+{
+ qDebug() << __FILE__ << __func__;
+}
+
+
+//! @brief backup OF file.
+//! @param to folder to write backup file to. Folder will get created.
+//! @return true on success, false on error.
+
+bool BootloaderInstallBase::backup(QString to)
+{
+ qDebug() << __func__;
+ QDir targetDir(".");
+ emit logItem(tr("Creating backup of original firmware file."), LOGINFO);
+ if(!targetDir.mkpath(to)) {
+ emit logItem(tr("Creating backup folder failed"), LOGERROR);
+ return false;
+ }
+ QString tofile = to + "/" + QFileInfo(m_blfile).fileName();
+ qDebug() << "trying to backup" << m_blfile << "to" << tofile;
+ if(!QFile::copy(resolvePathCase(m_blfile), tofile)) {
+ emit logItem(tr("Creating backup copy failed."), LOGERROR);
+ return false;
+ }
+ emit logItem(tr("Backup created."), LOGOK);
+ return true;
+}
+
+
+//! @brief log installation to logfile.
+//! @param mode action to perform. 0: add to log, 1: remove from log.
+//! @return 0 on success
+int BootloaderInstallBase::logInstall(LogMode mode)
+{
+ int result = 0;
+ QString section = m_blurl.path().section('/', -1);
+ QSettings s(m_logfile, QSettings::IniFormat, this);
+ emit logItem(tr("Creating installation log"), LOGINFO);
+
+ if(mode == LogAdd) {
+ s.setValue("Bootloader/" + section, m_blversion.toString(Qt::ISODate));
+ qDebug() << m_blversion.toString(Qt::ISODate);
+ }
+ else {
+ s.remove("Bootloader/" + section);
+ }
+ s.sync();
+
+ return result;
+}
+
+
+//! @brief Return post install hints string.
+//! @param model model string
+//! @return hints.
+QString BootloaderInstallBase::postinstallHints(QString model)
+{
+ bool hint = false;
+ QString msg = tr("Bootloader installation is almost complete. "
+ "Installation <b>requires</b> you to perform the "
+ "following steps manually:");
+
+ msg += tr("<ol>");
+ msg += tr("<li>Safely remove your player.</li>");
+ if(model == "h100" || model == "h120" || model == "h300") {
+ hint = true;
+ msg += tr("<li>Reboot your player into the original firmware.</li>"
+ "<li>Perform a firmware upgrade using the update functionality "
+ "of the original firmware. Please refer to your player's manual "
+ "on details.</li>"
+ "<li>After the firmware has been updated reboot your player.</li>");
+ }
+ if(model == "iaudiox5" || model == "iaudiom5"
+ || model == "iaudiox5v" || model == "iaudiom3") {
+ hint = true;
+ msg += tr("<li>Turn the player off</li>"
+ "<li>Insert the charger</li>");
+ }
+ if(model == "gigabeatf") {
+ hint = true;
+ msg += tr("<li>Unplug USB and power adaptors</li>"
+ "<li>Hold <i>Power</i> to turn the player off</li>"
+ "<li>Toggle the battery switch on the player</li>"
+ "<li>Hold <i>Power</i> to boot into Rockbox</li>");
+ }
+
+ msg += "</ol>";
+ msg += tr("<p><b>Note:</b> You can safely install other parts first, but "
+ "the above steps are <b>required</b> to finish the installation!</p>");
+
+ if(hint)
+ return msg;
+ else
+ return QString("");
+}
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallbase.h b/rbutil/rbutilqt/base/bootloaderinstallbase.h
new file mode 100644
index 0000000000..0916935208
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallbase.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef BOOTLOADERINSTALLBASE_H
+#define BOOTLOADERINSTALLBASE_H
+
+#include <QtCore>
+#include "progressloggerinterface.h"
+#include "httpget.h"
+
+
+class BootloaderInstallBase : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum Capability
+ { Install = 0x01, Uninstall = 0x02, Backup = 0x04,
+ IsFile = 0x08, IsRaw = 0x10, NeedsFlashing = 0x20,
+ CanCheckInstalled = 0x40, CanCheckVersion = 0x80 };
+ Q_DECLARE_FLAGS(Capabilities, Capability)
+
+ enum BootloaderType
+ { BootloaderNone, BootloaderRockbox, BootloaderOther, BootloaderUnknown };
+
+ BootloaderInstallBase(QObject *parent = 0) : QObject(parent)
+ { }
+
+ virtual bool install(void)
+ { return false; }
+ virtual bool uninstall(void)
+ { return false; }
+ virtual BootloaderType installed(void);
+ virtual Capabilities capabilities(void);
+ bool backup(QString to);
+
+ void setBlFile(QString f)
+ { m_blfile = f; }
+ void setBlUrl(QUrl u)
+ { m_blurl = u; }
+ void setLogfile(QString f)
+ { m_logfile = f; }
+
+ static QString postinstallHints(QString model);
+
+ protected slots:
+ void downloadReqFinished(int id, bool error);
+ void downloadBlFinish(bool error);
+ void installBlfile(void);
+ protected:
+ enum LogMode
+ { LogAdd, LogRemove };
+
+ void downloadBlStart(QUrl source);
+ int logInstall(LogMode mode);
+
+ HttpGet m_http; //! http download object
+ QString m_blfile; //! bootloader filename on player
+ QString m_logfile; //! file for installation log
+ QUrl m_blurl; //! bootloader download URL
+ QTemporaryFile m_tempfile; //! temporary file for download
+ QDateTime m_blversion; //! download timestamp used for version information
+
+ signals:
+ void downloadDone(void); //! internal signal sent when download finished.
+ void done(bool);
+ void logItem(QString, int); //! set logger item
+ void logProgress(int, int); //! set progress bar.
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(BootloaderInstallBase::Capabilities)
+
+#endif
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallfile.cpp b/rbutil/rbutilqt/base/bootloaderinstallfile.cpp
new file mode 100644
index 0000000000..daa1ad8af7
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallfile.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include <QtDebug>
+#include <QtDebug>
+#include "bootloaderinstallfile.h"
+#include "utils.h"
+
+
+BootloaderInstallFile::BootloaderInstallFile(QObject *parent)
+ : BootloaderInstallBase(parent)
+{
+}
+
+
+bool BootloaderInstallFile::install(void)
+{
+ emit logItem(tr("Downloading bootloader"), LOGINFO);
+ qDebug() << __func__;
+ downloadBlStart(m_blurl);
+ connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
+ return true;
+}
+
+void BootloaderInstallFile::installStage2(void)
+{
+ emit logItem(tr("Installing Rockbox bootloader"), LOGINFO);
+
+ // if an old bootloader is present (Gigabeat) move it out of the way.
+ QString fwfile(resolvePathCase(m_blfile));
+ if(!fwfile.isEmpty()) {
+ QString moved = resolvePathCase(m_blfile) + ".ORIG";
+ qDebug() << "renaming" << fwfile << "->" << moved;
+ QFile::rename(fwfile, moved);
+ }
+
+ // if no old file found resolve path without basename
+ QFileInfo fi(m_blfile);
+ QString absPath = resolvePathCase(fi.absolutePath());
+
+ // if it's not possible to locate the base path try to create it
+ if(absPath.isEmpty()) {
+ QStringList pathElements = m_blfile.split("/");
+ // remove filename from list and save last path element
+ pathElements.removeLast();
+ QString lastElement = pathElements.last();
+ // remove last path element for base
+ pathElements.removeLast();
+ QString basePath = pathElements.join("/");
+
+ // check for base and bail out if not found. Otherwise create folder.
+ absPath = resolvePathCase(basePath);
+ QDir d(absPath);
+ d.mkpath(lastElement);
+ absPath = resolvePathCase(fi.absolutePath());
+
+ if(absPath.isEmpty()) {
+ emit logItem(tr("Error accessing output folder"), LOGERROR);
+ emit done(true);
+ return;
+ }
+ }
+ fwfile = absPath + "/" + fi.fileName();
+
+ // place (new) bootloader
+ m_tempfile.open();
+ qDebug() << "renaming" << m_tempfile.fileName() << "->" << fwfile;
+ m_tempfile.close();
+ m_tempfile.rename(fwfile);
+
+ emit logItem(tr("Bootloader successful installed"), LOGOK);
+ logInstall(LogAdd);
+
+ emit done(false);
+}
+
+
+bool BootloaderInstallFile::uninstall(void)
+{
+ qDebug() << __func__;
+ emit logItem(tr("Removing Rockbox bootloader"), LOGINFO);
+ // check if a .ORIG file is present, and allow moving it back.
+ QString origbl = resolvePathCase(m_blfile + ".ORIG");
+ if(origbl.isEmpty()) {
+ emit logItem(tr("No original firmware file found."), LOGERROR);
+ emit done(true);
+ return false;
+ }
+ QString fwfile = resolvePathCase(m_blfile);
+ if(!QFile::remove(fwfile)) {
+ emit logItem(tr("Can't remove Rockbox bootloader file."), LOGERROR);
+ emit done(true);
+ return false;
+ }
+ if(!QFile::rename(origbl, fwfile)) {
+ emit logItem(tr("Can't restore bootloader file."), LOGERROR);
+ emit done(true);
+ return false;
+ }
+ emit logItem(tr("Original bootloader restored successfully."), LOGOK);
+ logInstall(LogRemove);
+ emit done(false);
+
+ return true;
+}
+
+
+//! @brief check if bootloader is installed.
+//! @return BootloaderRockbox, BootloaderOther or BootloaderUnknown.
+BootloaderInstallBase::BootloaderType BootloaderInstallFile::installed(void)
+{
+ qDebug("%s()", __func__);
+ if(!resolvePathCase(m_blfile).isEmpty()
+ && !resolvePathCase(m_blfile + ".ORIG").isEmpty())
+ return BootloaderRockbox;
+ else if(!resolvePathCase(m_blfile).isEmpty())
+ return BootloaderOther;
+ else
+ return BootloaderUnknown;
+}
+
+
+BootloaderInstallBase::Capabilities BootloaderInstallFile::capabilities(void)
+{
+ qDebug() << __func__;
+ return Install | IsFile | CanCheckInstalled | Backup;
+}
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallfile.h b/rbutil/rbutilqt/base/bootloaderinstallfile.h
new file mode 100644
index 0000000000..075f047ed2
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallfile.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include "progressloggerinterface.h"
+#include "bootloaderinstallbase.h"
+
+//! install a bootloader by putting a single file on the player.
+// This installation method is used by Iaudio (firmware is flashed
+// automatically) and Gigabeat (Firmware is a file, OF needs to get
+// renamed).
+class BootloaderInstallFile : public BootloaderInstallBase
+{
+ Q_OBJECT
+
+ public:
+ BootloaderInstallFile(QObject *parent = 0);
+ bool install(void);
+ bool uninstall(void);
+ BootloaderInstallBase::BootloaderType installed(void);
+ Capabilities capabilities(void);
+
+ private slots:
+ void installStage2(void);
+
+ private:
+};
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallhex.cpp b/rbutil/rbutilqt/base/bootloaderinstallhex.cpp
new file mode 100644
index 0000000000..aa42beb994
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallhex.cpp
@@ -0,0 +1,244 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include "bootloaderinstallbase.h"
+#include "bootloaderinstallhex.h"
+
+#include "../../tools/iriver.h"
+#include "../../tools/mkboot.h"
+
+struct md5s {
+ const char* orig;
+ const char* patched;
+};
+
+struct md5s md5sums[] = {
+#include "irivertools/h100sums.h"
+ { 0, 0 },
+#include "irivertools/h120sums.h"
+ { 0, 0 },
+#include "irivertools/h300sums.h"
+ { 0, 0 }
+};
+
+
+BootloaderInstallHex::BootloaderInstallHex(QObject *parent)
+ : BootloaderInstallBase(parent)
+{
+}
+
+
+bool BootloaderInstallHex::install(void)
+{
+ if(m_hex.isEmpty())
+ return false;
+ m_hashindex = -1;
+
+ // md5sum hex file
+ emit logItem(tr("checking MD5 hash of input file ..."), LOGINFO);
+ QByteArray filedata;
+ // read hex file into QByteArray
+ QFile file(m_hex);
+ file.open(QIODevice::ReadOnly);
+ filedata = file.readAll();
+ file.close();
+ QString hash = QCryptographicHash::hash(filedata,
+ QCryptographicHash::Md5).toHex();
+ qDebug() << "hexfile hash:" << hash;
+ if(file.error() != QFile::NoError) {
+ emit logItem(tr("Could not verify original firmware file"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+ // check hash and figure model from md5sum
+ int i = sizeof(md5sums) / sizeof(struct md5s);
+ m_model = 4;
+ // 3: h300, 2: h120, 1: h100, 0:invalid
+ while(i--) {
+ if(md5sums[i].orig == 0)
+ m_model--;
+ if(!qstrcmp(md5sums[i].orig, hash.toAscii()))
+ break;
+ }
+ if(i < 0) {
+ emit logItem(tr("Firmware file not recognized."), LOGERROR);
+ return false;
+ }
+ else {
+ emit logItem(tr("MD5 hash ok"), LOGOK);
+ m_hashindex = i;
+ }
+
+ // check model agains download link.
+ QString match[] = {"", "h100", "h120", "h300"};
+ if(!m_blurl.path().contains(match[m_model])) {
+ emit logItem(tr("Firmware file doesn't match selected player."),
+ LOGERROR);
+ return false;
+ }
+
+ emit logItem(tr("Descrambling file"), LOGINFO);
+ m_descrambled.open();
+ int result;
+ result = iriver_decode(m_hex.toAscii().data(),
+ m_descrambled.fileName().toAscii().data(), FALSE, STRIP_NONE);
+ qDebug() << "iriver_decode" << result;
+
+ if(result < 0) {
+ emit logItem(tr("Error in descramble: %1").arg(scrambleError(result)), LOGERROR);
+ return false;
+ }
+
+ // download firmware from server
+ emit logItem(tr("Downloading bootloader file"), LOGINFO);
+ connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
+
+ downloadBlStart(m_blurl);
+ return true;
+}
+
+
+void BootloaderInstallHex::installStage2(void)
+{
+ emit logItem(tr("Adding bootloader to firmware file"), LOGINFO);
+
+ // local temp file
+ QTemporaryFile tempbin;
+ tempbin.open();
+ QString tempbinName = tempbin.fileName();
+ tempbin.close();
+ // get temporary files filenames -- external tools need this.
+ m_descrambled.open();
+ QString descrambledName = m_descrambled.fileName();
+ m_descrambled.close();
+ m_tempfile.open();
+ QString tempfileName = m_tempfile.fileName();
+ m_tempfile.close();
+
+ int origin = 0;
+ switch(m_model) {
+ case 3:
+ origin = 0x3f0000;
+ break;
+ case 2:
+ case 1:
+ origin = 0x1f0000;
+ break;
+ default:
+ origin = 0;
+ break;
+ }
+
+ // iriver decode already done in stage 1
+ int result;
+ if((result = mkboot(descrambledName.toLocal8Bit().constData(),
+ tempfileName.toLocal8Bit().constData(),
+ tempbinName.toLocal8Bit().constData(), origin)) < 0)
+ {
+ QString error;
+ switch(result) {
+ case -1: error = tr("could not open input file"); break;
+ case -2: error = tr("reading header failed"); break;
+ case -3: error = tr("reading firmware failed"); break;
+ case -4: error = tr("can't open bootloader file"); break;
+ case -5: error = tr("reading bootloader file failed"); break;
+ case -6: error = tr("can't open output file"); break;
+ case -7: error = tr("writing output file failed"); break;
+ }
+ emit logItem(tr("Error in patching: %1").arg(error), LOGERROR);
+
+ emit done(true);
+ return;
+ }
+ QTemporaryFile targethex;
+ targethex.open();
+ QString targethexName = targethex.fileName();
+ if((result = iriver_encode(tempbinName.toLocal8Bit().constData(),
+ targethexName.toLocal8Bit().constData(), FALSE)) < 0)
+ {
+ emit logItem(tr("Error in scramble: %1").arg(scrambleError(result)), LOGERROR);
+ targethex.close();
+
+ emit done(true);
+ return;
+ }
+
+ // finally check the md5sum of the created file
+ QByteArray filedata;
+ filedata = targethex.readAll();
+ targethex.close();
+ QString hash = QCryptographicHash::hash(filedata,
+ QCryptographicHash::Md5).toHex();
+ qDebug() << "created hexfile hash:" << hash;
+
+ emit logItem(tr("Checking modified firmware file"), LOGINFO);
+ if(hash != QString(md5sums[m_hashindex].patched)) {
+ emit logItem(tr("Error: modified file checksum wrong"), LOGERROR);
+ targethex.remove();
+ emit done(true);
+ return;
+ }
+ // finally copy file to player
+ targethex.copy(m_blfile);
+
+ emit logItem(tr("Success: modified firmware file created"), LOGINFO);
+ logInstall(LogAdd);
+ emit done(false);
+
+ return;
+}
+
+
+bool BootloaderInstallHex::uninstall(void)
+{
+ emit logItem("Uninstallation not possible, only installation info removed", LOGINFO);
+ logInstall(LogRemove);
+ return false;
+}
+
+
+BootloaderInstallBase::BootloaderType BootloaderInstallHex::installed(void)
+{
+ return BootloaderUnknown;
+}
+
+
+BootloaderInstallBase::Capabilities BootloaderInstallHex::capabilities(void)
+{
+ return (Install | NeedsFlashing);
+}
+
+QString BootloaderInstallHex::scrambleError(int err)
+{
+ QString error;
+ switch(err) {
+ case -1: error = tr("Can't open input file"); break;
+ case -2: error = tr("Can't open output file"); break;
+ case -3: error = tr("invalid file: header length wrong"); break;
+ case -4: error = tr("invalid file: unrecognized header"); break;
+ case -5: error = tr("invalid file: \"length\" field wrong"); break;
+ case -6: error = tr("invalid file: \"length2\" field wrong"); break;
+ case -7: error = tr("invalid file: internal checksum error"); break;
+ case -8: error = tr("invalid file: \"length3\" field wrong"); break;
+ default: error = tr("unknown"); break;
+ }
+ return error;
+}
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallhex.h b/rbutil/rbutilqt/base/bootloaderinstallhex.h
new file mode 100644
index 0000000000..04b657a193
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallhex.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef BOOTLOADERINSTALLHEX_H
+#define BOOTLOADERINSTALLHEX_H
+
+#include <QtCore>
+#include "bootloaderinstallbase.h"
+
+
+// bootloader installation derivate based on fwpatcher
+// This will patch a given hex file using (de)scramble / mkboot
+// and put it on the player.
+class BootloaderInstallHex : public BootloaderInstallBase
+{
+ Q_OBJECT
+
+ public:
+ BootloaderInstallHex(QObject *parent = 0);
+ bool install(void);
+ bool uninstall(void);
+ BootloaderInstallBase::BootloaderType installed(void);
+ Capabilities capabilities(void);
+
+ void setHexfile(QString h)
+ { m_hex = h; }
+
+ private:
+ QString m_hex;
+ int m_hashindex;
+ int m_model;
+ QTemporaryFile m_descrambled;
+ QString scrambleError(int);
+
+ private slots:
+ void installStage2(void);
+};
+
+
+#endif
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallipod.cpp b/rbutil/rbutilqt/base/bootloaderinstallipod.cpp
new file mode 100644
index 0000000000..e47c96b239
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallipod.cpp
@@ -0,0 +1,235 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include "bootloaderinstallbase.h"
+#include "bootloaderinstallipod.h"
+
+#include "../ipodpatcher/ipodpatcher.h"
+
+
+BootloaderInstallIpod::BootloaderInstallIpod(QObject *parent)
+ : BootloaderInstallBase(parent)
+{
+ (void)parent;
+ // initialize sector buffer. ipod_sectorbuf is defined in ipodpatcher.
+ ipod_sectorbuf = NULL;
+ ipod_alloc_buffer(&ipod_sectorbuf, BUFFER_SIZE);
+}
+
+
+BootloaderInstallIpod::~BootloaderInstallIpod()
+{
+ free(ipod_sectorbuf);
+}
+
+
+bool BootloaderInstallIpod::install(void)
+{
+ if(ipod_sectorbuf == NULL) {
+ emit logItem(tr("Error: can't allocate buffer memory!"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ struct ipod_t ipod;
+
+ int n = ipod_scan(&ipod);
+ if(n == -1) {
+ emit logItem(tr("No Ipod detected\n"
+ "Permission for disc access denied!"),
+ LOGERROR);
+ emit done(true);
+ return false;
+ }
+ if(n == 0) {
+ emit logItem(tr("No Ipod detected!"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if(ipod.macpod) {
+ emit logItem(tr("Warning: This is a MacPod, Rockbox only runs on WinPods.\n"
+ "See http://www.rockbox.org/wiki/IpodConversionToFAT32"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+ emit logItem(tr("Downloading bootloader file"), LOGINFO);
+
+ downloadBlStart(m_blurl);
+ connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
+ return true;
+}
+
+
+void BootloaderInstallIpod::installStage2(void)
+{
+ struct ipod_t ipod;
+
+ if(!ipodInitialize(&ipod)) {
+ emit done(true);
+ return;
+ }
+
+ read_directory(&ipod);
+
+ if(ipod.nimages <= 0) {
+ emit logItem(tr("Failed to read firmware directory"), LOGERROR);
+ emit done(true);
+ return;
+ }
+ if(getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) {
+ emit logItem(tr("Unknown version number in firmware (%1)").arg(
+ ipod.ipod_directory[0].vers), LOGERROR);
+ emit done(true);
+ return;
+ }
+
+ if(ipod.macpod) {
+ emit logItem(tr("Warning: This is a MacPod. Rockbox only runs on WinPods.\n"
+ "See http://www.rockbox.org/wiki/IpodConversionToFAT32"), LOGERROR);
+ emit done(true);
+ return;
+ }
+
+ if(ipod_reopen_rw(&ipod) < 0) {
+ emit logItem(tr("Could not open Ipod in R/W mode"), LOGERROR);
+ emit done(true);
+ return;
+ }
+
+ m_tempfile.open();
+ QString blfile = m_tempfile.fileName();
+ m_tempfile.close();
+ if(add_bootloader(&ipod, blfile.toLatin1().data(), FILETYPE_DOT_IPOD) == 0) {
+ emit logItem(tr("Successfull added bootloader"), LOGOK);
+ logInstall(LogAdd);
+ emit done(false);
+ ipod_close(&ipod);
+ return;
+ }
+ else {
+ emit logItem(tr("Failed to add bootloader"), LOGERROR);
+ ipod_close(&ipod);
+ emit done(true);
+ return;
+ }
+ qDebug() << "version installed:" << m_blversion.toString(Qt::ISODate);
+}
+
+
+bool BootloaderInstallIpod::uninstall(void)
+{
+ struct ipod_t ipod;
+
+ if(!ipodInitialize(&ipod)) {
+ emit done(true);
+ return false;
+ }
+
+ read_directory(&ipod);
+
+ if (ipod.nimages <= 0) {
+ emit logItem(tr("Failed to read firmware directory"),LOGERROR);
+ emit done(true);
+ return false;
+ }
+ if (getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) {
+ emit logItem(tr("Unknown version number in firmware (%1)").arg(
+ ipod.ipod_directory[0].vers), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if (ipod_reopen_rw(&ipod) < 0) {
+ emit logItem(tr("Could not open Ipod in RW mode"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if (ipod.ipod_directory[0].entryOffset == 0) {
+ emit logItem(tr("No bootloader detected."), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if (delete_bootloader(&ipod)==0) {
+ emit logItem(tr("Successfully removed Bootloader"), LOGOK);
+ logInstall(LogRemove);
+ emit done(false);
+ ipod_close(&ipod);
+ return true;
+ }
+ else {
+ emit logItem(tr("Removing the bootloader failed."), LOGERROR);
+ emit done(true);
+ ipod_close(&ipod);
+ return false;
+ }
+}
+
+
+BootloaderInstallBase::BootloaderType BootloaderInstallIpod::installed(void)
+{
+ struct ipod_t ipod;
+ BootloaderInstallBase::BootloaderType result = BootloaderRockbox;
+
+ if(!ipodInitialize(&ipod)) {
+ qDebug() << "BootloaderInstallIpod::installed(): BootloaderUnknown";
+ result = BootloaderUnknown;
+ }
+
+ if (ipod.ipod_directory[0].entryOffset == 0) {
+ qDebug() << "BootloaderInstallIpod::installed(): BootloaderOther";
+ result = BootloaderOther;
+ }
+ qDebug() << "BootloaderInstallIpod::installed(): BootloaderRockbox";
+ ipod_close(&ipod);
+
+ return result;
+}
+
+
+BootloaderInstallBase::Capabilities BootloaderInstallIpod::capabilities(void)
+{
+ return (Install | Uninstall | IsRaw);
+}
+
+
+bool BootloaderInstallIpod::ipodInitialize(struct ipod_t *ipod)
+{
+ ipod_scan(ipod);
+ if(ipod_open(ipod, 0) < 0) {
+ emit logItem(tr("Could not open Ipod"), LOGERROR);
+ return false;
+ }
+
+ if(read_partinfo(ipod, 0) < 0) {
+ emit logItem(tr("Could not read partition table"), LOGERROR);
+ return false;
+ }
+
+ if(ipod->pinfo[0].start == 0) {
+ emit logItem(tr("No firmware partition on disk"), LOGERROR);
+
+ return false;
+ }
+ return true;
+}
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallipod.h b/rbutil/rbutilqt/base/bootloaderinstallipod.h
new file mode 100644
index 0000000000..5867b754f1
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallipod.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef BOOTLOADERINSTALLIPOD_H
+#define BOOTLOADERINSTALLIPOD_H
+
+#include <QtCore>
+#include "bootloaderinstallbase.h"
+#include "../ipodpatcher/ipodpatcher.h"
+
+// installer class derivate for Ipod installation
+// based on ipodpatcher.
+class BootloaderInstallIpod : public BootloaderInstallBase
+{
+ Q_OBJECT
+
+ public:
+ BootloaderInstallIpod(QObject *parent = 0);
+ ~BootloaderInstallIpod();
+ bool install(void);
+ bool uninstall(void);
+ BootloaderInstallBase::BootloaderType installed(void);
+ Capabilities capabilities(void);
+
+ private slots:
+ void installStage2(void);
+
+ private:
+ bool ipodInitialize(struct ipod_t *);
+};
+
+
+#endif
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallmi4.cpp b/rbutil/rbutilqt/base/bootloaderinstallmi4.cpp
new file mode 100644
index 0000000000..fa0ebb2f02
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallmi4.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include <QtDebug>
+#include <QtDebug>
+#include "bootloaderinstallmi4.h"
+#include "utils.h"
+
+BootloaderInstallMi4::BootloaderInstallMi4(QObject *parent)
+ : BootloaderInstallBase(parent)
+{
+}
+
+
+bool BootloaderInstallMi4::install(void)
+{
+ emit logItem(tr("Downloading bootloader"), LOGINFO);
+ qDebug() << __func__;
+ downloadBlStart(m_blurl);
+ connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
+ return true;
+}
+
+void BootloaderInstallMi4::installStage2(void)
+{
+ emit logItem(tr("Installing Rockbox bootloader"), LOGINFO);
+
+ // move old bootloader out of the way
+ QString fwfile(resolvePathCase(m_blfile));
+ QFile oldbl(fwfile);
+ QString moved = QFileInfo(resolvePathCase(m_blfile)).absolutePath()
+ + "/OF.mi4";
+ qDebug() << "renaming" << fwfile << "->" << moved;
+ oldbl.rename(moved);
+
+ // place new bootloader
+ m_tempfile.open();
+ qDebug() << "renaming" << m_tempfile.fileName() << "->" << fwfile;
+ m_tempfile.close();
+ m_tempfile.rename(fwfile);
+
+ emit logItem(tr("Bootloader successful installed"), LOGOK);
+ logInstall(LogAdd);
+
+ emit done(true);
+}
+
+
+bool BootloaderInstallMi4::uninstall(void)
+{
+ qDebug() << __func__;
+
+ // check if it's actually a Rockbox bootloader
+ emit logItem(tr("Checking for Rockbox bootloader"), LOGINFO);
+ if(installed() != BootloaderRockbox) {
+ emit logItem(tr("No Rockbox bootloader found"), LOGERROR);
+ return false;
+ }
+
+ // check if OF file present
+ emit logItem(tr("Checking for original firmware file"), LOGINFO);
+ QString original = QFileInfo(resolvePathCase(m_blfile)).absolutePath()
+ + "/OF.mi4";
+
+ if(resolvePathCase(original).isEmpty()) {
+ emit logItem(tr("Error finding original firmware file"), LOGERROR);
+ return false;
+ }
+
+ // finally remove RB bootloader
+ QString resolved = resolvePathCase(m_blfile);
+ QFile blfile(resolved);
+ blfile.remove();
+
+ QFile oldbl(resolvePathCase(original));
+ oldbl.rename(m_blfile);
+ emit logItem(tr("Rockbox bootloader successful removed"), LOGINFO);
+ logInstall(LogRemove);
+ emit done(false);
+
+ return true;
+}
+
+
+//! check if a bootloader is installed and return its state.
+BootloaderInstallBase::BootloaderType BootloaderInstallMi4::installed(void)
+{
+ // for MI4 files we can check if we actually have a RB bootloader
+ // installed.
+ // RB bootloader has "RBBL" at 0x1f8 in the mi4 file.
+
+ // make sure to resolve case to prevent case issues
+ QString resolved;
+ resolved = resolvePathCase(m_blfile);
+ if(resolved.isEmpty()) {
+ qDebug("%s: BootloaderNone", __func__);
+ return BootloaderNone;
+ }
+
+ QFile f(resolved);
+ f.open(QIODevice::ReadOnly);
+ f.seek(0x1f8);
+ char magic[4];
+ f.read(magic, 4);
+ f.close();
+
+ if(!memcmp(magic, "RBBL", 4)) {
+ qDebug("%s: BootloaderRockbox", __func__);
+ return BootloaderRockbox;
+ }
+ else {
+ qDebug("%s: BootloaderOther", __func__);
+ return BootloaderOther;
+ }
+}
+
+
+BootloaderInstallBase::Capabilities BootloaderInstallMi4::capabilities(void)
+{
+ qDebug() << __func__;
+ return Install | Uninstall | Backup | IsFile | CanCheckInstalled | CanCheckVersion;
+}
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallmi4.h b/rbutil/rbutilqt/base/bootloaderinstallmi4.h
new file mode 100644
index 0000000000..c746b0c87f
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallmi4.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include "progressloggerinterface.h"
+#include "bootloaderinstallbase.h"
+
+
+// mi4 bootloader file based installation.
+// Puts the bootloader file to the correct location and
+// renames the OF to OF.mi4.
+class BootloaderInstallMi4 : public BootloaderInstallBase
+{
+ Q_OBJECT
+
+ public:
+ BootloaderInstallMi4(QObject *parent = 0);
+ bool install(void);
+ bool uninstall(void);
+ BootloaderInstallBase::BootloaderType installed(void);
+ Capabilities capabilities(void);
+
+ private slots:
+ void installStage2(void);
+
+ private:
+};
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallsansa.cpp b/rbutil/rbutilqt/base/bootloaderinstallsansa.cpp
new file mode 100644
index 0000000000..9294cdd497
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallsansa.cpp
@@ -0,0 +1,244 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include "bootloaderinstallbase.h"
+#include "bootloaderinstallsansa.h"
+
+#include "../sansapatcher/sansapatcher.h"
+
+BootloaderInstallSansa::BootloaderInstallSansa(QObject *parent)
+ : BootloaderInstallBase(parent)
+{
+ (void)parent;
+ // initialize sector buffer. sansa_sectorbuf is instantiated by
+ // sansapatcher.
+ sansa_sectorbuf = NULL;
+ sansa_alloc_buffer(&sansa_sectorbuf, BUFFER_SIZE);
+}
+
+
+BootloaderInstallSansa::~BootloaderInstallSansa()
+{
+ free(sansa_sectorbuf);
+}
+
+
+/** Start bootloader installation.
+ */
+bool BootloaderInstallSansa::install(void)
+{
+ if(sansa_sectorbuf == NULL) {
+ emit logItem(tr("Error: can't allocate buffer memory!"), LOGERROR);
+ return false;
+ emit done(true);
+ }
+
+ emit logItem(tr("Searching for Sansa"), LOGINFO);
+
+ struct sansa_t sansa;
+
+ int n = sansa_scan(&sansa);
+ if(n == -1) {
+ emit logItem(tr("Permission for disc access denied!\n"
+ "This is required to install the bootloader"),
+ LOGERROR);
+ emit done(true);
+ return false;
+ }
+ if(n == 0) {
+ emit logItem(tr("No Sansa detected!"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+ emit logItem(tr("Downloading bootloader file"), LOGINFO);
+
+ downloadBlStart(m_blurl);
+ connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
+ return true;
+}
+
+
+/** Finish bootloader installation.
+ */
+void BootloaderInstallSansa::installStage2(void)
+{
+ struct sansa_t sansa;
+ sansa_scan(&sansa);
+
+ if(sansa_open(&sansa, 0) < 0) {
+ emit logItem(tr("could not open Sansa"), LOGERROR);
+ emit done(true);
+ return;
+ }
+
+ if(sansa_read_partinfo(&sansa, 0) < 0)
+ {
+ emit logItem(tr("could not read partitiontable"), LOGERROR);
+ emit done(true);
+ return;
+ }
+
+ int i = is_sansa(&sansa);
+ if(i < 0) {
+
+ emit logItem(tr("Disk is not a Sansa (Error: %1), aborting.").arg(i), LOGERROR);
+ emit done(true);
+ return;
+ }
+
+ if(sansa.hasoldbootloader) {
+ emit logItem(tr("OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n"
+ "You must reinstall the original Sansa firmware before running\n"
+ "sansapatcher for the first time.\n"
+ "See http://www.rockbox.org/wiki/SansaE200Install\n"),
+ LOGERROR);
+ emit done(true);
+ return;
+ }
+
+ if(sansa_reopen_rw(&sansa) < 0) {
+ emit logItem(tr("Could not open Sansa in R/W mode"), LOGERROR);
+ emit done(true);
+ return;
+ }
+
+ m_tempfile.open();
+ QString blfile = m_tempfile.fileName();
+ m_tempfile.close();
+ if(sansa_add_bootloader(&sansa, blfile.toLatin1().data(),
+ FILETYPE_MI4) == 0) {
+ emit logItem(tr("Successfully installed bootloader"), LOGOK);
+ logInstall(LogAdd);
+ emit done(false);
+ sansa_close(&sansa);
+ return;
+ }
+ else {
+ emit logItem(tr("Failed to install bootloader"), LOGERROR);
+ sansa_close(&sansa);
+ emit done(true);
+ return;
+ }
+
+}
+
+
+/** Uninstall the bootloader.
+ */
+bool BootloaderInstallSansa::uninstall(void)
+{
+ struct sansa_t sansa;
+
+ if(sansa_scan(&sansa) != 1) {
+ emit logItem(tr("Can't find Sansa"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if (sansa_open(&sansa, 0) < 0) {
+ emit logItem(tr("Could not open Sansa"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if (sansa_read_partinfo(&sansa,0) < 0) {
+ emit logItem(tr("Could not read partition table"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ int i = is_sansa(&sansa);
+ if(i < 0) {
+ emit logItem(tr("Disk is not a Sansa (Error %1), aborting.").arg(i), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if (sansa.hasoldbootloader) {
+ emit logItem(tr("OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n"
+ "You must reinstall the original Sansa firmware before running\n"
+ "sansapatcher for the first time.\n"
+ "See http://www.rockbox.org/wiki/SansaE200Install\n"),
+ LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if (sansa_reopen_rw(&sansa) < 0) {
+ emit logItem(tr("Could not open Sansa in R/W mode"), LOGERROR);
+ emit done(true);
+ return false;
+ }
+
+ if (sansa_delete_bootloader(&sansa)==0) {
+ emit logItem(tr("Successfully removed bootloader"), LOGOK);
+ logInstall(LogRemove);
+ emit done(false);
+ sansa_close(&sansa);
+ return true;
+ }
+ else {
+ emit logItem(tr("Removing bootloader failed."),LOGERROR);
+ emit done(true);
+ sansa_close(&sansa);
+ return false;
+ }
+
+ return false;
+}
+
+
+/** Check if bootloader is already installed
+ */
+BootloaderInstallBase::BootloaderType BootloaderInstallSansa::installed(void)
+{
+ struct sansa_t sansa;
+ int num;
+
+ if(sansa_scan(&sansa) != 1) {
+ return BootloaderUnknown;
+ }
+ if (sansa_open(&sansa, 0) < 0) {
+ return BootloaderUnknown;
+ }
+ if (sansa_read_partinfo(&sansa,0) < 0) {
+ return BootloaderUnknown;
+ }
+ if(is_sansa(&sansa) < 0) {
+ return BootloaderUnknown;
+ }
+ if((num = sansa_list_images(&sansa)) == 2) {
+ return BootloaderRockbox;
+ }
+ else if(num == 1) {
+ return BootloaderOther;
+ }
+ return BootloaderUnknown;
+
+}
+
+
+/** Get capabilities of subclass installer.
+ */
+BootloaderInstallBase::Capabilities BootloaderInstallSansa::capabilities(void)
+{
+ return (Install | Uninstall | IsRaw | CanCheckInstalled);
+}
+
diff --git a/rbutil/rbutilqt/base/bootloaderinstallsansa.h b/rbutil/rbutilqt/base/bootloaderinstallsansa.h
new file mode 100644
index 0000000000..a3911057a0
--- /dev/null
+++ b/rbutil/rbutilqt/base/bootloaderinstallsansa.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef BOOTLOADERINSTALLSANSA_H
+#define BOOTLOADERINSTALLSANSA_H
+
+#include <QtCore>
+#include "bootloaderinstallbase.h"
+
+
+// bootloader installation class for devices handled by sansapatcher.
+class BootloaderInstallSansa : public BootloaderInstallBase
+{
+ Q_OBJECT
+
+ public:
+ BootloaderInstallSansa(QObject *parent = 0);
+ ~BootloaderInstallSansa();
+ bool install(void);
+ bool uninstall(void);
+ BootloaderInstallBase::BootloaderType installed(void);
+ Capabilities capabilities(void);
+
+ private:
+
+ private slots:
+ void installStage2(void);
+};
+
+
+#endif
+
diff --git a/rbutil/rbutilqt/base/httpget.cpp b/rbutil/rbutilqt/base/httpget.cpp
new file mode 100644
index 0000000000..129545d158
--- /dev/null
+++ b/rbutil/rbutilqt/base/httpget.cpp
@@ -0,0 +1,413 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2007 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include <QtNetwork>
+#include <QtDebug>
+
+#include "httpget.h"
+
+QDir HttpGet::m_globalCache; //< global cach path value for new objects
+QUrl HttpGet::m_globalProxy; //< global proxy value for new objects
+bool HttpGet::m_globalDumbCache = false; //< globally set cache "dumb" mode
+QString HttpGet::m_globalUserAgent; //< globally set user agent for requests
+
+HttpGet::HttpGet(QObject *parent)
+ : QObject(parent)
+{
+ outputToBuffer = true;
+ m_cached = false;
+ m_dumbCache = m_globalDumbCache;
+ getRequest = -1;
+ headRequest = -1;
+ // if a request is cancelled before a reponse is available return some
+ // hint about this in the http response instead of nonsense.
+ m_response = -1;
+
+ // default to global proxy / cache if not empty.
+ // proxy is automatically enabled, disable it by setting an empty proxy
+ // cache is enabled to be in line, can get disabled with setCache(bool)
+ if(!m_globalProxy.isEmpty())
+ setProxy(m_globalProxy);
+ m_usecache = false;
+ m_cachedir = m_globalCache;
+
+ m_serverTimestamp = QDateTime();
+
+ connect(&http, SIGNAL(done(bool)), this, SLOT(httpDone(bool)));
+ connect(&http, SIGNAL(dataReadProgress(int, int)), this, SIGNAL(dataReadProgress(int, int)));
+ connect(&http, SIGNAL(requestFinished(int, bool)), this, SLOT(httpFinished(int, bool)));
+ connect(&http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)), this, SLOT(httpResponseHeader(const QHttpResponseHeader&)));
+ connect(&http, SIGNAL(stateChanged(int)), this, SLOT(httpState(int)));
+ connect(&http, SIGNAL(requestStarted(int)), this, SLOT(httpStarted(int)));
+
+ connect(&http, SIGNAL(readyRead(const QHttpResponseHeader&)), this, SLOT(httpResponseHeader(const QHttpResponseHeader&)));
+
+}
+
+
+//! @brief set cache path
+// @param d new directory to use as cache path
+void HttpGet::setCache(QDir d)
+{
+ m_cachedir = d;
+ bool result;
+ result = initializeCache(d);
+ qDebug() << "[HTTP]"<< __func__ << "(QDir)" << d.absolutePath() << result;
+ m_usecache = result;
+}
+
+
+/** @brief enable / disable cache useage
+ * @param c set cache usage
+ */
+void HttpGet::setCache(bool c)
+{
+ qDebug() << "[HTTP]" << __func__ << "(bool) =" << c;
+ m_usecache = c;
+ // make sure cache is initialized
+ if(c)
+ m_usecache = initializeCache(m_cachedir);
+}
+
+
+bool HttpGet::initializeCache(const QDir& d)
+{
+ bool result;
+ QString p = d.absolutePath() + "/rbutil-cache";
+ if(QFileInfo(d.absolutePath()).isDir())
+ {
+ if(!QFileInfo(p).isDir())
+ result = d.mkdir("rbutil-cache");
+ else
+ result = true;
+ }
+ else
+ result = false;
+
+ return result;
+
+}
+
+
+/** @brief read all downloaded data into a buffer
+ * @return data
+ */
+QByteArray HttpGet::readAll()
+{
+ return dataBuffer;
+}
+
+
+/** @brief get http error
+ * @return http error
+ */
+QHttp::Error HttpGet::error()
+{
+ return http.error();
+}
+
+
+void HttpGet::setProxy(const QUrl &proxy)
+{
+ qDebug() << "[HTTP]" << __func__ << "(QUrl)" << proxy.toString();
+ m_proxy = proxy;
+ http.setProxy(m_proxy.host(), m_proxy.port(), m_proxy.userName(), m_proxy.password());
+}
+
+
+void HttpGet::setProxy(bool enable)
+{
+ qDebug() << "[HTTP]" << __func__ << "(bool)" << enable;
+ if(enable)
+ http.setProxy(m_proxy.host(), m_proxy.port(), m_proxy.userName(), m_proxy.password());
+ else
+ http.setProxy("", 0);
+}
+
+
+void HttpGet::setFile(QFile *file)
+{
+ outputFile = file;
+ outputToBuffer = false;
+ qDebug() << "[HTTP]" << __func__ << "(QFile*)" << outputFile->fileName();
+}
+
+
+void HttpGet::abort()
+{
+ http.abort();
+ if(!outputToBuffer)
+ outputFile->close();
+}
+
+
+bool HttpGet::getFile(const QUrl &url)
+{
+ if (!url.isValid()) {
+ qDebug() << "[HTTP] Error: Invalid URL" << endl;
+ return false;
+ }
+
+ if (url.scheme() != "http") {
+ qDebug() << "[HTTP] Error: URL must start with 'http:'" << endl;
+ return false;
+ }
+
+ if (url.path().isEmpty()) {
+ qDebug() << "[HTTP] Error: URL has no path" << endl;
+ return false;
+ }
+ m_serverTimestamp = QDateTime();
+ // if no output file was set write to buffer
+ if(!outputToBuffer) {
+ if (!outputFile->open(QIODevice::ReadWrite)) {
+ qDebug() << "[HTTP] Error: Cannot open " << qPrintable(outputFile->fileName())
+ << " for writing: " << qPrintable(outputFile->errorString())
+ << endl;
+ return false;
+ }
+ }
+ qDebug() << "[HTTP] downloading" << url.toEncoded();
+ // create request
+ http.setHost(url.host(), url.port(80));
+ // construct query (if any)
+ QList<QPair<QString, QString> > qitems = url.queryItems();
+ if(url.hasQuery()) {
+ m_query = "?";
+ for(int i = 0; i < qitems.size(); i++)
+ m_query += QUrl::toPercentEncoding(qitems.at(i).first, "/") + "="
+ + QUrl::toPercentEncoding(qitems.at(i).second, "/") + "&";
+ }
+
+ // create hash used for caching
+ m_hash = QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Md5).toHex();
+ m_path = QString(QUrl::toPercentEncoding(url.path(), "/"));
+
+ // construct request header
+ m_header.setValue("Host", url.host());
+ m_header.setValue("User-Agent", m_globalUserAgent);
+ m_header.setValue("Connection", "Keep-Alive");
+
+ if(m_dumbCache || !m_usecache) {
+ getFileFinish();
+ }
+ else {
+ // schedule HTTP header request
+ connect(this, SIGNAL(headerFinished()), this, SLOT(getFileFinish()));
+ m_header.setRequest("HEAD", m_path + m_query);
+ headRequest = http.request(m_header);
+ }
+
+ return true;
+}
+
+
+void HttpGet::getFileFinish()
+{
+ m_cachefile = m_cachedir.absolutePath() + "/rbutil-cache/" + m_hash;
+ if(m_usecache) {
+ // check if the file is present in cache
+ qDebug() << "[HTTP] cache ENABLED";
+ QFileInfo cachefile = QFileInfo(m_cachefile);
+ if(cachefile.isReadable()
+ && cachefile.size() > 0
+ && cachefile.lastModified() > m_serverTimestamp) {
+
+ qDebug() << "[HTTP] cached file found:" << m_cachefile;
+
+ getRequest = -1;
+ QFile c(m_cachefile);
+ if(!outputToBuffer) {
+ qDebug() << "[HTTP] copying cache file to output" << outputFile->fileName();
+ c.open(QIODevice::ReadOnly);
+ outputFile->open(QIODevice::ReadWrite);
+ outputFile->write(c.readAll());
+ outputFile->close();
+ c.close();
+ }
+ else {
+ qDebug() << "[HTTP] reading cache file into buffer";
+ c.open(QIODevice::ReadOnly);
+ dataBuffer = c.readAll();
+ c.close();
+ }
+ m_response = 200; // fake "200 OK" HTTP response
+ m_cached = true;
+ httpDone(false); // we're done now. Fake http "done" signal.
+ return;
+ }
+ else {
+ if(cachefile.isReadable())
+ qDebug() << "[HTTP] file in cache timestamp:" << cachefile.lastModified();
+ else
+ qDebug() << "[HTTP] file not in cache.";
+ qDebug() << "[HTTP] server file timestamp:" << m_serverTimestamp;
+ qDebug() << "[HTTP] downloading file to" << m_cachefile;
+ // unlink old cache file
+ if(cachefile.isReadable())
+ QFile(m_cachefile).remove();
+ }
+
+ }
+ else {
+ qDebug() << "[HTTP] cache DISABLED";
+ }
+ // schedule GET request
+ m_header.setRequest("GET", m_path + m_query);
+ if(outputToBuffer) {
+ qDebug() << "[HTTP] downloading to buffer.";
+ getRequest = http.request(m_header);
+ }
+ else {
+ qDebug() << "[HTTP] downloading to file:"
+ << qPrintable(outputFile->fileName());
+ getRequest = http.request(m_header, 0, outputFile);
+ }
+ qDebug() << "[HTTP] GET request scheduled, id:" << getRequest;
+
+ return;
+}
+
+
+void HttpGet::httpDone(bool error)
+{
+ if (error) {
+ qDebug() << "[HTTP] Error: " << qPrintable(http.errorString()) << httpResponse();
+ }
+ if(!outputToBuffer)
+ outputFile->close();
+
+ if(m_usecache && !m_cached && !error) {
+ qDebug() << "[HTTP] creating cache file" << m_cachefile;
+ QFile c(m_cachefile);
+ c.open(QIODevice::ReadWrite);
+ if(!outputToBuffer) {
+ outputFile->open(QIODevice::ReadOnly | QIODevice::Truncate);
+ c.write(outputFile->readAll());
+ outputFile->close();
+ }
+ else
+ c.write(dataBuffer);
+
+ c.close();
+ }
+ // if cached file found and cache enabled ignore http errors
+ if(m_usecache && m_cached && !http.hasPendingRequests()) {
+ error = false;
+ }
+ // take care of concurring requests. If there is still one running,
+ // don't emit done(). That request will call this slot again.
+ if(http.currentId() == 0 && !http.hasPendingRequests())
+ emit done(error);
+}
+
+
+void HttpGet::httpFinished(int id, bool error)
+{
+ qDebug() << "[HTTP]" << __func__ << "(int, bool) =" << id << error;
+ if(id == getRequest) {
+ dataBuffer = http.readAll();
+
+ emit requestFinished(id, error);
+ }
+ qDebug() << "[HTTP] hasPendingRequests =" << http.hasPendingRequests();
+
+
+ if(id == headRequest) {
+ QHttpResponseHeader h = http.lastResponse();
+
+ QString date = h.value("Last-Modified").simplified();
+ if(date.isEmpty()) {
+ m_serverTimestamp = QDateTime(); // no value = invalid
+ emit headerFinished();
+ return;
+ }
+ // to successfully parse the date strip weekday and timezone
+ date.remove(0, date.indexOf(" ") + 1);
+ if(date.endsWith("GMT"))
+ date.truncate(date.indexOf(" GMT"));
+ // distinguish input formats (see RFC1945)
+ // RFC 850
+ if(date.contains("-"))
+ m_serverTimestamp = QDateTime::fromString(date, "dd-MMM-yy hh:mm:ss");
+ // asctime format
+ else if(date.at(0).isLetter())
+ m_serverTimestamp = QDateTime::fromString(date, "MMM d hh:mm:ss yyyy");
+ // RFC 822
+ else
+ m_serverTimestamp = QDateTime::fromString(date, "dd MMM yyyy hh:mm:ss");
+ qDebug() << "[HTTP] Header Request Date:" << date << ", parsed:" << m_serverTimestamp;
+ emit headerFinished();
+ return;
+ }
+ if(id == getRequest)
+ emit requestFinished(id, error);
+}
+
+void HttpGet::httpStarted(int id)
+{
+ qDebug() << "[HTTP]" << __func__ << "(int) =" << id;
+ qDebug() << "headRequest" << headRequest << "getRequest" << getRequest;
+}
+
+
+QString HttpGet::errorString()
+{
+ return http.errorString();
+}
+
+
+void HttpGet::httpResponseHeader(const QHttpResponseHeader &resp)
+{
+ // if there is a network error abort all scheduled requests for
+ // this download
+ m_response = resp.statusCode();
+ if(m_response != 200) {
+ qDebug() << "[HTTP] response error =" << m_response << resp.reasonPhrase();
+ http.abort();
+ }
+ // 301 -- moved permanently
+ // 302 -- found
+ // 303 -- see other
+ // 307 -- moved temporarily
+ // in all cases, header: location has the correct address so we can follow.
+ if(m_response == 301 || m_response == 302 || m_response == 303 || m_response == 307) {
+ // start new request with new url
+ qDebug() << "[HTTP] response =" << m_response << "- following";
+ getFile(resp.value("location") + m_query);
+ }
+}
+
+
+int HttpGet::httpResponse()
+{
+ return m_response;
+}
+
+
+void HttpGet::httpState(int state)
+{
+ QString s[] = {"Unconnected", "HostLookup", "Connecting", "Sending",
+ "Reading", "Connected", "Closing"};
+ if(state <= 6)
+ qDebug() << "[HTTP]" << __func__ << "() = " << s[state];
+ else qDebug() << "[HTTP]" << __func__ << "() = " << state;
+}
+
diff --git a/rbutil/rbutilqt/base/httpget.h b/rbutil/rbutilqt/base/httpget.h
new file mode 100644
index 0000000000..ba4cbc821e
--- /dev/null
+++ b/rbutil/rbutilqt/base/httpget.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2007 by Dominik Riebeling
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#ifndef HTTPGET_H
+#define HTTPGET_H
+
+#include <QtCore>
+#include <QtNetwork>
+
+class QUrl;
+
+class HttpGet : public QObject
+{
+ Q_OBJECT
+
+ public:
+ HttpGet(QObject *parent = 0);
+
+ bool getFile(const QUrl &url);
+ void setProxy(const QUrl &url);
+ void setProxy(bool);
+ QHttp::Error error(void);
+ QString errorString(void);
+ void setFile(QFile*);
+ void setCache(QDir);
+ void setCache(bool);
+ int httpResponse(void);
+ QByteArray readAll(void);
+ bool isCached()
+ { return m_cached; }
+ QDateTime timestamp(void)
+ { return m_serverTimestamp; }
+ void setDumbCache(bool b) //< disable checking of http header timestamp for caching
+ { m_dumbCache = b; }
+ static void setGlobalCache(const QDir d) //< set global cache path
+ { m_globalCache = d; }
+ static void setGlobalProxy(const QUrl p) //< set global proxy value
+ { m_globalProxy = p; }
+ static void setGlobalDumbCache(bool b) //< set "dumb" (ignore server status) caching mode
+ { m_globalDumbCache = b; }
+ static void setGlobalUserAgent(QString u) //< set global user agent string
+ { m_globalUserAgent = u; }
+
+ public slots:
+ void abort(void);
+
+ signals:
+ void done(bool);
+ void dataReadProgress(int, int);
+ void requestFinished(int, bool);
+ void headerFinished(void);
+
+ private slots:
+ void httpDone(bool error);
+ void httpFinished(int, bool);
+ void httpResponseHeader(const QHttpResponseHeader&);
+ void httpState(int);
+ void httpStarted(int);
+ void getFileFinish(void);
+
+ private:
+ bool initializeCache(const QDir&);
+ QHttp http; //< download object
+ QFile *outputFile;
+ int m_response; //< http response
+ int getRequest; //! get file http request id
+ int headRequest; //! get http header request id
+ QByteArray dataBuffer;
+ bool outputToBuffer;
+ bool m_usecache;
+ QDir m_cachedir;
+ QString m_cachefile; // cached filename
+ bool m_cached;
+ QUrl m_proxy;
+ QDateTime m_serverTimestamp; //< timestamp of file on server
+ QString m_query; //< constructed query to pass http getter
+ QString m_path; //< constructed path to pass http getter
+ QString m_hash; //< caching hash
+ bool m_dumbCache; //< true if caching should ignore the server header
+ QHttpRequestHeader m_header;
+
+ static QDir m_globalCache; //< global cache path value
+ static QUrl m_globalProxy; //< global proxy value
+ static bool m_globalDumbCache; //< cache "dumb" mode global setting
+ static QString m_globalUserAgent; //< global user agent string
+};
+
+#endif
diff --git a/rbutil/rbutilqt/base/rbunzip.cpp b/rbutil/rbutilqt/base/rbunzip.cpp
new file mode 100644
index 0000000000..49d12156ea
--- /dev/null
+++ b/rbutil/rbutilqt/base/rbunzip.cpp
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "rbunzip.h"
+#include <QtCore>
+
+
+UnZip::ErrorCode RbUnZip::extractArchive(const QString& dest)
+{
+ QStringList files = this->fileList();
+ UnZip::ErrorCode error = Ok;
+ m_abortunzip = false;
+
+ int total = files.size();
+ for(int i = 0; i < total; i++) {
+ qDebug() << __func__ << files.at(i);
+ error = this->extractFile(files.at(i), dest, UnZip::ExtractPaths);
+ emit unzipProgress(i + 1, total);
+ QCoreApplication::processEvents(); // update UI
+ if(m_abortunzip)
+ error = SkipAll;
+ if(error != Ok)
+ break;
+ }
+ return error;
+}
+
+void RbUnZip::abortUnzip(void)
+{
+ m_abortunzip = true;
+}
+
diff --git a/rbutil/rbutilqt/base/rbunzip.h b/rbutil/rbutilqt/base/rbunzip.h
new file mode 100644
index 0000000000..133437a4e2
--- /dev/null
+++ b/rbutil/rbutilqt/base/rbunzip.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Riebeling
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef RBUNZIP_H
+#define RBUNZIP_H
+
+#include <QtCore>
+#include "zip/unzip.h"
+#include "zip/zip.h"
+
+class RbUnZip : public QObject, public UnZip
+{
+ Q_OBJECT
+ public:
+ UnZip::ErrorCode extractArchive(const QString&);
+
+ signals:
+ void unzipProgress(int, int);
+
+ public slots:
+ void abortUnzip(void);
+
+ private:
+ bool m_abortunzip;
+};
+
+#endif
+
diff --git a/rbutil/rbutilqt/base/rbzip.cpp b/rbutil/rbutilqt/base/rbzip.cpp
new file mode 100644
index 0000000000..b5cfb22416
--- /dev/null
+++ b/rbutil/rbutilqt/base/rbzip.cpp
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Wenger
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "rbzip.h"
+#include <QtCore>
+
+
+Zip::ErrorCode RbZip::createZip(QString zip,QString dir)
+{
+ Zip::ErrorCode error = Ok;
+ m_curEntry = 1;
+ m_numEntrys=0;
+
+ QCoreApplication::processEvents();
+
+ // get number of entrys in dir
+ QDirIterator it(dir, QDirIterator::Subdirectories);
+ while (it.hasNext())
+ {
+ it.next();
+ m_numEntrys++;
+ QCoreApplication::processEvents();
+ }
+
+
+ //! create zip
+ error = Zip::createArchive(zip);
+ if(error != Ok)
+ return error;
+
+ //! add the content
+ error = Zip::addDirectory(dir);
+ if(error != Ok)
+ return error;
+
+ //! close zip
+ error = Zip::closeArchive();
+
+ return error;
+}
+
+void RbZip::progress()
+{
+ m_curEntry++;
+ emit zipProgress(m_curEntry,m_numEntrys);
+ QCoreApplication::processEvents(); // update UI
+}
+
+
diff --git a/rbutil/rbutilqt/base/rbzip.h b/rbutil/rbutilqt/base/rbzip.h
new file mode 100644
index 0000000000..d7cf05f3de
--- /dev/null
+++ b/rbutil/rbutilqt/base/rbzip.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2008 by Dominik Wenger
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef RBZIP_H
+#define RBZIP_H
+
+#include <QtCore>
+#include "zip/zip.h"
+
+class RbZip : public QObject, public Zip
+{
+ Q_OBJECT
+ public:
+ Zip::ErrorCode createZip(QString zip,QString dir);
+
+ virtual void progress();
+
+ signals:
+ void zipProgress(int, int);
+
+ private:
+ int m_curEntry;
+ int m_numEntrys;
+};
+
+#endif
+
diff --git a/rbutil/rbutilqt/base/utils.cpp b/rbutil/rbutilqt/base/utils.cpp
new file mode 100644
index 0000000000..a6a80c6eef
--- /dev/null
+++ b/rbutil/rbutilqt/base/utils.cpp
@@ -0,0 +1,101 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2007 by Dominik Wenger
+ * $Id$
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "utils.h"
+#ifdef UNICODE
+#define _UNICODE
+#endif
+
+#include <QtCore>
+#include <QDebug>
+#include <cstdlib>
+#include <stdio.h>
+
+#if defined(Q_OS_WIN32)
+#include <windows.h>
+#include <tchar.h>
+#include <winioctl.h>
+#endif
+
+// recursive function to delete a dir with files
+bool recRmdir( const QString &dirName )
+{
+ QString dirN = dirName;
+ QDir dir(dirN);
+ // make list of entries in directory
+ QStringList list = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
+ QFileInfo fileInfo;
+ QString curItem, lstAt;
+ for(int i = 0; i < list.size(); i++){ // loop through all items of list
+ QString name = list.at(i);
+ curItem = dirN + "/" + name;
+ fileInfo.setFile(curItem);
+ if(fileInfo.isDir()) // is directory
+ recRmdir(curItem); // call recRmdir() recursively for deleting subdirectory
+ else // is file
+ QFile::remove(curItem); // ok, delete file
+ }
+ dir.cdUp();
+ return dir.rmdir(dirN); // delete empty dir and return if (now empty) dir-removing was successfull
+}
+
+
+//! @brief resolves the given path, ignoring case.
+//! @param path absolute path to resolve.
+//! @return returns exact casing of path, empty string if path not found.
+QString resolvePathCase(QString path)
+{
+ QStringList elems;
+ QString realpath;
+
+ elems = path.split("/", QString::SkipEmptyParts);
+ int start;
+#if defined(Q_OS_WIN32)
+ // on windows we must make sure to start with the first entry (i.e. the
+ // drive letter) instead of a single / to make resolving work.
+ start = 1;
+ realpath = elems.at(0) + "/";
+#else
+ start = 0;
+ realpath = "/";
+#endif
+
+ for(int i = start; i < elems.size(); i++) {
+ QStringList direlems
+ = QDir(realpath).entryList(QDir::AllEntries|QDir::Hidden|QDir::System);
+ if(direlems.contains(elems.at(i), Qt::CaseInsensitive)) {
+ // need to filter using QRegExp as QStringList::filter(QString)
+ // matches any substring
+ QString expr = QString("^" + elems.at(i) + "$");
+ QRegExp rx = QRegExp(expr, Qt::CaseInsensitive);
+ QStringList a = direlems.filter(rx);
+
+ if(a.size() != 1)
+ return QString("");
+ if(!realpath.endsWith("/"))
+ realpath += "/";
+ realpath += a.at(0);
+ }
+ else
+ return QString("");
+ }
+ qDebug() << __func__ << path << "->" << realpath;
+ return realpath;
+}
+
diff --git a/rbutil/rbutilqt/base/utils.h b/rbutil/rbutilqt/base/utils.h
new file mode 100644
index 0000000000..19cdca92c9
--- /dev/null
+++ b/rbutil/rbutilqt/base/utils.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2007 by Dominik Wenger
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <QString>
+#include <QUrl>
+
+bool recRmdir( const QString &dirName );
+QString resolvePathCase(QString path);
+
+#endif
+