1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Dominik Riebeling 2008-10-12 19:21:58 +00:00
parent 3d30029883
commit f958717d43
23 changed files with 36 additions and 34 deletions

View file

@ -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;
}

View file

@ -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_*/

View file

@ -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("");
}

View file

@ -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

View file

@ -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;
}

View file

@ -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:
};

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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:
};

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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;
}

View file

@ -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