summaryrefslogtreecommitdiff
path: root/rbutil/rbutilqt/base
diff options
context:
space:
mode:
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include "autodetection.h"
22
23#if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
24#include <stdio.h>
25#include <usb.h>
26#endif
27#if defined(Q_OS_LINUX)
28#include <mntent.h>
29#endif
30#if defined(Q_OS_MACX)
31#include <sys/param.h>
32#include <sys/ucred.h>
33#include <sys/mount.h>
34#endif
35#if defined(Q_OS_WIN32)
36#if defined(UNICODE)
37#define _UNICODE
38#endif
39#include <stdio.h>
40#include <tchar.h>
41#include <windows.h>
42#include <setupapi.h>
43#include <winioctl.h>
44#endif
45#include "detect.h"
46#include "utils.h"
47
48Autodetection::Autodetection(QObject* parent): QObject(parent)
49{
50
51}
52
53bool Autodetection::detect()
54{
55 m_device = "";
56 m_mountpoint = "";
57 m_errdev = "";
58
59 detectUsb();
60
61 // Try detection via rockbox.info / rbutil.log
62 QStringList mountpoints = getMountpoints();
63
64 for(int i=0; i< mountpoints.size();i++)
65 {
66 // do the file checking
67 QDir dir(mountpoints.at(i));
68 qDebug() << "paths to check for player specific files:" << mountpoints;
69 if(dir.exists())
70 {
71 // check logfile first.
72 if(QFile(mountpoints.at(i) + "/.rockbox/rbutil.log").exists()) {
73 QSettings log(mountpoints.at(i) + "/.rockbox/rbutil.log",
74 QSettings::IniFormat, this);
75 if(!log.value("platform").toString().isEmpty()) {
76 if(m_device.isEmpty())
77 m_device = log.value("platform").toString();
78 m_mountpoint = mountpoints.at(i);
79 qDebug() << "rbutil.log detected:" << m_device << m_mountpoint;
80 return true;
81 }
82 }
83
84 // check rockbox-info.txt afterwards.
85 QFile file(mountpoints.at(i) + "/.rockbox/rockbox-info.txt");
86 if(file.exists())
87 {
88 file.open(QIODevice::ReadOnly | QIODevice::Text);
89 QString line = file.readLine();
90 if(line.startsWith("Target: "))
91 {
92 line.remove("Target: ");
93 if(m_device.isEmpty())
94 m_device = line.trimmed(); // trim whitespaces
95 m_mountpoint = mountpoints.at(i);
96 qDebug() << "rockbox-info.txt detected:" << m_device << m_mountpoint;
97 return true;
98 }
99 }
100 // check for some specific files in root folder
101 QDir root(mountpoints.at(i));
102 QStringList rootentries = root.entryList(QDir::Files);
103 if(rootentries.contains("archos.mod", Qt::CaseInsensitive))
104 {
105 // archos.mod in root folder -> Archos Player
106 m_device = "player";
107 m_mountpoint = mountpoints.at(i);
108 return true;
109 }
110 if(rootentries.contains("ONDIOST.BIN", Qt::CaseInsensitive))
111 {
112 // ONDIOST.BIN in root -> Ondio FM
113 m_device = "ondiofm";
114 m_mountpoint = mountpoints.at(i);
115 return true;
116 }
117 if(rootentries.contains("ONDIOSP.BIN", Qt::CaseInsensitive))
118 {
119 // ONDIOSP.BIN in root -> Ondio SP
120 m_device = "ondiosp";
121 m_mountpoint = mountpoints.at(i);
122 return true;
123 }
124 if(rootentries.contains("ajbrec.ajz", Qt::CaseInsensitive))
125 {
126 qDebug() << "ajbrec.ajz found. Trying detectAjbrec()";
127 if(detectAjbrec(mountpoints.at(i))) {
128 m_mountpoint = mountpoints.at(i);
129 qDebug() << m_device;
130 return true;
131 }
132 }
133 // detection based on player specific folders
134 QStringList rootfolders = root.entryList(QDir::Dirs
135 | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
136 if(rootfolders.contains("GBSYSTEM", Qt::CaseInsensitive))
137 {
138 // GBSYSTEM folder -> Gigabeat
139 m_device = "gigabeatf";
140 m_mountpoint = mountpoints.at(i);
141 return true;
142 }
143#if defined(Q_OS_WIN32)
144 // on windows, try to detect the drive letter of an Ipod
145 if(rootfolders.contains("iPod_Control", Qt::CaseInsensitive))
146 {
147 // iPod_Control folder -> Ipod found
148 // detecting of the Ipod type is done below using ipodpatcher
149 m_mountpoint = mountpoints.at(i);
150 }
151#endif
152 }
153
154 }
155
156 int n;
157 // try ipodpatcher
158 // initialize sector buffer. Needed.
159 ipod_sectorbuf = NULL;
160 ipod_alloc_buffer(&ipod_sectorbuf, BUFFER_SIZE);
161 struct ipod_t ipod;
162 n = ipod_scan(&ipod);
163 if(n == 1) {
164 qDebug() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname;
165 m_device = ipod.targetname;
166 m_mountpoint = resolveMountPoint(ipod.diskname);
167 return true;
168 }
169 else {
170 qDebug() << "ipodpatcher: no Ipod found." << n;
171 }
172 free(ipod_sectorbuf);
173 ipod_sectorbuf = NULL;
174
175 // try sansapatcher
176 // initialize sector buffer. Needed.
177 sansa_sectorbuf = NULL;
178 sansa_alloc_buffer(&sansa_sectorbuf, BUFFER_SIZE);
179 struct sansa_t sansa;
180 n = sansa_scan(&sansa);
181 if(n == 1) {
182 qDebug() << "Sansa found:" << sansa.targetname << "at" << sansa.diskname;
183 m_device = QString("sansa%1").arg(sansa.targetname);
184 m_mountpoint = resolveMountPoint(sansa.diskname);
185 return true;
186 }
187 else {
188 qDebug() << "sansapatcher: no Sansa found." << n;
189 }
190 free(sansa_sectorbuf);
191 sansa_sectorbuf = NULL;
192
193 if(m_mountpoint.isEmpty() && m_device.isEmpty() && m_errdev.isEmpty() && m_incompat.isEmpty())
194 return false;
195 return true;
196}
197
198
199QStringList Autodetection::getMountpoints()
200{
201 QStringList tempList;
202#if defined(Q_OS_WIN32)
203 QFileInfoList list = QDir::drives();
204 for(int i=0; i<list.size();i++)
205 {
206 tempList << list.at(i).absolutePath();
207 }
208
209#elif defined(Q_OS_MACX)
210 int num;
211 struct statfs *mntinf;
212
213 num = getmntinfo(&mntinf, MNT_WAIT);
214 while(num--) {
215 tempList << QString(mntinf->f_mntonname);
216 mntinf++;
217 }
218#elif defined(Q_OS_LINUX)
219
220 FILE *mn = setmntent("/etc/mtab", "r");
221 if(!mn)
222 return QStringList("");
223
224 struct mntent *ent;
225 while((ent = getmntent(mn)))
226 tempList << QString(ent->mnt_dir);
227 endmntent(mn);
228
229#else
230#error Unknown Plattform
231#endif
232 return tempList;
233}
234
235QString Autodetection::resolveMountPoint(QString device)
236{
237 qDebug() << "Autodetection::resolveMountPoint(QString)" << device;
238
239#if defined(Q_OS_LINUX)
240 FILE *mn = setmntent("/etc/mtab", "r");
241 if(!mn)
242 return QString("");
243
244 struct mntent *ent;
245 while((ent = getmntent(mn))) {
246 if(QString(ent->mnt_fsname).startsWith(device)
247 && QString(ent->mnt_type).contains("vfat", Qt::CaseInsensitive)) {
248 endmntent(mn);
249 return QString(ent->mnt_dir);
250 }
251 }
252 endmntent(mn);
253
254#endif
255
256#if defined(Q_OS_MACX)
257 int num;
258 struct statfs *mntinf;
259
260 num = getmntinfo(&mntinf, MNT_WAIT);
261 while(num--) {
262 if(QString(mntinf->f_mntfromname).startsWith(device)
263 && QString(mntinf->f_fstypename).contains("vfat", Qt::CaseInsensitive))
264 return QString(mntinf->f_mntonname);
265 mntinf++;
266 }
267#endif
268
269#if defined(Q_OS_WIN32)
270 QString result;
271 unsigned int driveno = device.replace(QRegExp("^.*([0-9]+)"), "\\1").toInt();
272
273 for(int letter = 'A'; letter <= 'Z'; letter++) {
274 DWORD written;
275 HANDLE h;
276 TCHAR uncpath[MAX_PATH];
277 UCHAR buffer[0x400];
278 PVOLUME_DISK_EXTENTS extents = (PVOLUME_DISK_EXTENTS)buffer;
279
280 _stprintf(uncpath, _TEXT("\\\\.\\%c:"), letter);
281 h = CreateFile(uncpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
282 NULL, OPEN_EXISTING, 0, NULL);
283 if(h == INVALID_HANDLE_VALUE) {
284 //qDebug() << "error getting extents for" << uncpath;
285 continue;
286 }
287 // get the extents
288 if(DeviceIoControl(h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
289 NULL, 0, extents, sizeof(buffer), &written, NULL)) {
290 for(unsigned int a = 0; a < extents->NumberOfDiskExtents; a++) {
291 qDebug() << "Disk:" << extents->Extents[a].DiskNumber;
292 if(extents->Extents[a].DiskNumber == driveno) {
293 result = letter;
294 qDebug("drive found for volume %i: %c", driveno, letter);
295 break;
296 }
297 }
298
299 }
300
301 }
302 if(!result.isEmpty())
303 return result + ":/";
304#endif
305 return QString("");
306}
307
308
309/** @brief detect devices based on usb pid / vid.
310 * @return true upon success, false otherwise.
311 */
312bool Autodetection::detectUsb()
313{
314 // usbids holds the mapping in the form
315 // ((VID<<16)|(PID)), targetname
316 // the ini file needs to hold the IDs as hex values.
317 QMap<int, QString> usbids = settings->usbIdMap();
318 QMap<int, QString> usberror = settings->usbIdErrorMap();
319 QMap<int, QString> usbincompat = settings->usbIdIncompatMap();
320
321 // usb pid detection
322 QList<uint32_t> attached;
323 attached = Detect::listUsbIds();
324
325 int i = attached.size();
326 while(i--) {
327 if(usbids.contains(attached.at(i))) {
328 m_device = usbids.value(attached.at(i));
329 qDebug() << "[USB] detected supported player" << m_device;
330 return true;
331 }
332 if(usberror.contains(attached.at(i))) {
333 m_errdev = usberror.value(attached.at(i));
334 qDebug() << "[USB] detected problem with player" << m_errdev;
335 return true;
336 }
337 if(usbincompat.contains(attached.at(i))) {
338 m_incompat = usbincompat.value(attached.at(i));
339 qDebug() << "[USB] detected incompatible player" << m_incompat;
340 return true;
341 }
342 }
343 return false;
344}
345
346
347bool Autodetection::detectAjbrec(QString root)
348{
349 QFile f(root + "/ajbrec.ajz");
350 char header[24];
351 f.open(QIODevice::ReadOnly);
352 if(!f.read(header, 24)) return false;
353
354 // check the header of the file.
355 // recorder v1 had a 6 bytes sized header
356 // recorder v2, FM, Ondio SP and FM have a 24 bytes header.
357
358 // recorder v1 has the binary length in the first 4 bytes, so check
359 // for them first.
360 int len = (header[0]<<24) | (header[1]<<16) | (header[2]<<8) | header[3];
361 qDebug() << "possible bin length:" << len;
362 qDebug() << "file len:" << f.size();
363 if((f.size() - 6) == len)
364 m_device = "recorder";
365
366 // size didn't match, now we need to assume we have a headerlength of 24.
367 switch(header[11]) {
368 case 2:
369 m_device = "recorderv2";
370 break;
371
372 case 4:
373 m_device = "fmrecorder";
374 break;
375
376 case 8:
377 m_device = "ondiofm";
378 break;
379
380 case 16:
381 m_device = "ondiosp";
382 break;
383
384 default:
385 break;
386 }
387 f.close();
388
389 if(m_device.isEmpty()) return false;
390 return true;
391}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22
23#ifndef AUTODETECTION_H_
24#define AUTODETECTION_H_
25
26#include <QtCore>
27#include "rbsettings.h"
28
29#include "../ipodpatcher/ipodpatcher.h"
30#include "../sansapatcher/sansapatcher.h"
31
32class Autodetection :public QObject
33{
34 Q_OBJECT
35
36public:
37 Autodetection(QObject* parent=0);
38
39 void setSettings(RbSettings* sett) {settings = sett;}
40
41 bool detect();
42
43 QString getDevice() {return m_device;}
44 QString getMountPoint() {return m_mountpoint;}
45 QString errdev(void) { return m_errdev; }
46 QString incompatdev(void) { return m_incompat; }
47
48private:
49 QStringList getMountpoints(void);
50 QString resolveMountPoint(QString);
51 bool detectUsb(void);
52 bool detectAjbrec(QString);
53
54 QString m_device;
55 QString m_mountpoint;
56 QString m_errdev;
57 QString m_incompat;
58 QList<int> m_usbconid;
59 RbSettings* settings;
60};
61
62
63#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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20
21#include <QtCore>
22
23#include "bootloaderinstallbase.h"
24#include "utils.h"
25
26BootloaderInstallBase::BootloaderType BootloaderInstallBase::installed(void)
27{
28 return BootloaderUnknown;
29}
30
31
32BootloaderInstallBase::Capabilities BootloaderInstallBase::capabilities(void)
33{
34 return 0;
35}
36
37
38void BootloaderInstallBase::downloadBlStart(QUrl source)
39{
40 m_http.setFile(&m_tempfile);
41 m_http.setCache(true);
42 connect(&m_http, SIGNAL(done(bool)), this, SLOT(downloadBlFinish(bool)));
43 // connect the http read signal to our logProgess *signal*
44 // to immediately emit it without any helper function.
45 connect(&m_http, SIGNAL(dataReadProgress(int, int)),
46 this, SIGNAL(logProgress(int, int)));
47 m_http.getFile(source);
48}
49
50
51void BootloaderInstallBase::downloadReqFinished(int id, bool error)
52{
53 qDebug() << __FILE__ << "::" << __func__ << id << error;
54 qDebug() << "error:" << m_http.errorString();
55
56 downloadBlFinish(error);
57}
58
59
60void BootloaderInstallBase::downloadBlFinish(bool error)
61{
62 qDebug() << __FILE__ << "::" << __func__ << ": error =" << error;
63
64 // update progress bar
65 emit logProgress(100, 100);
66
67 if(m_http.httpResponse() != 200) {
68 emit logItem(tr("Download error: received HTTP error %1.")
69 .arg(m_http.errorString()), LOGERROR);
70 emit done(true);
71 return;
72 }
73 if(error) {
74 emit logItem(tr("Download error: %1")
75 .arg(m_http.error()), LOGERROR);
76 emit done(true);
77 return;
78 }
79 else if(m_http.isCached())
80 emit logItem(tr("Download finished (cache used)."), LOGOK);
81 else
82 emit logItem(tr("Download finished."), LOGOK);
83
84 m_blversion = m_http.timestamp();
85 emit downloadDone();
86}
87
88void BootloaderInstallBase::installBlfile(void)
89{
90 qDebug() << __FILE__ << __func__;
91}
92
93
94//! @brief backup OF file.
95//! @param to folder to write backup file to. Folder will get created.
96//! @return true on success, false on error.
97
98bool BootloaderInstallBase::backup(QString to)
99{
100 qDebug() << __func__;
101 QDir targetDir(".");
102 emit logItem(tr("Creating backup of original firmware file."), LOGINFO);
103 if(!targetDir.mkpath(to)) {
104 emit logItem(tr("Creating backup folder failed"), LOGERROR);
105 return false;
106 }
107 QString tofile = to + "/" + QFileInfo(m_blfile).fileName();
108 qDebug() << "trying to backup" << m_blfile << "to" << tofile;
109 if(!QFile::copy(resolvePathCase(m_blfile), tofile)) {
110 emit logItem(tr("Creating backup copy failed."), LOGERROR);
111 return false;
112 }
113 emit logItem(tr("Backup created."), LOGOK);
114 return true;
115}
116
117
118//! @brief log installation to logfile.
119//! @param mode action to perform. 0: add to log, 1: remove from log.
120//! @return 0 on success
121int BootloaderInstallBase::logInstall(LogMode mode)
122{
123 int result = 0;
124 QString section = m_blurl.path().section('/', -1);
125 QSettings s(m_logfile, QSettings::IniFormat, this);
126 emit logItem(tr("Creating installation log"), LOGINFO);
127
128 if(mode == LogAdd) {
129 s.setValue("Bootloader/" + section, m_blversion.toString(Qt::ISODate));
130 qDebug() << m_blversion.toString(Qt::ISODate);
131 }
132 else {
133 s.remove("Bootloader/" + section);
134 }
135 s.sync();
136
137 return result;
138}
139
140
141//! @brief Return post install hints string.
142//! @param model model string
143//! @return hints.
144QString BootloaderInstallBase::postinstallHints(QString model)
145{
146 bool hint = false;
147 QString msg = tr("Bootloader installation is almost complete. "
148 "Installation <b>requires</b> you to perform the "
149 "following steps manually:");
150
151 msg += tr("<ol>");
152 msg += tr("<li>Safely remove your player.</li>");
153 if(model == "h100" || model == "h120" || model == "h300") {
154 hint = true;
155 msg += tr("<li>Reboot your player into the original firmware.</li>"
156 "<li>Perform a firmware upgrade using the update functionality "
157 "of the original firmware. Please refer to your player's manual "
158 "on details.</li>"
159 "<li>After the firmware has been updated reboot your player.</li>");
160 }
161 if(model == "iaudiox5" || model == "iaudiom5"
162 || model == "iaudiox5v" || model == "iaudiom3") {
163 hint = true;
164 msg += tr("<li>Turn the player off</li>"
165 "<li>Insert the charger</li>");
166 }
167 if(model == "gigabeatf") {
168 hint = true;
169 msg += tr("<li>Unplug USB and power adaptors</li>"
170 "<li>Hold <i>Power</i> to turn the player off</li>"
171 "<li>Toggle the battery switch on the player</li>"
172 "<li>Hold <i>Power</i> to boot into Rockbox</li>");
173 }
174
175 msg += "</ol>";
176 msg += tr("<p><b>Note:</b> You can safely install other parts first, but "
177 "the above steps are <b>required</b> to finish the installation!</p>");
178
179 if(hint)
180 return msg;
181 else
182 return QString("");
183}
184
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef BOOTLOADERINSTALLBASE_H
21#define BOOTLOADERINSTALLBASE_H
22
23#include <QtCore>
24#include "progressloggerinterface.h"
25#include "httpget.h"
26
27
28class BootloaderInstallBase : public QObject
29{
30 Q_OBJECT
31
32 public:
33 enum Capability
34 { Install = 0x01, Uninstall = 0x02, Backup = 0x04,
35 IsFile = 0x08, IsRaw = 0x10, NeedsFlashing = 0x20,
36 CanCheckInstalled = 0x40, CanCheckVersion = 0x80 };
37 Q_DECLARE_FLAGS(Capabilities, Capability)
38
39 enum BootloaderType
40 { BootloaderNone, BootloaderRockbox, BootloaderOther, BootloaderUnknown };
41
42 BootloaderInstallBase(QObject *parent = 0) : QObject(parent)
43 { }
44
45 virtual bool install(void)
46 { return false; }
47 virtual bool uninstall(void)
48 { return false; }
49 virtual BootloaderType installed(void);
50 virtual Capabilities capabilities(void);
51 bool backup(QString to);
52
53 void setBlFile(QString f)
54 { m_blfile = f; }
55 void setBlUrl(QUrl u)
56 { m_blurl = u; }
57 void setLogfile(QString f)
58 { m_logfile = f; }
59
60 static QString postinstallHints(QString model);
61
62 protected slots:
63 void downloadReqFinished(int id, bool error);
64 void downloadBlFinish(bool error);
65 void installBlfile(void);
66 protected:
67 enum LogMode
68 { LogAdd, LogRemove };
69
70 void downloadBlStart(QUrl source);
71 int logInstall(LogMode mode);
72
73 HttpGet m_http; //! http download object
74 QString m_blfile; //! bootloader filename on player
75 QString m_logfile; //! file for installation log
76 QUrl m_blurl; //! bootloader download URL
77 QTemporaryFile m_tempfile; //! temporary file for download
78 QDateTime m_blversion; //! download timestamp used for version information
79
80 signals:
81 void downloadDone(void); //! internal signal sent when download finished.
82 void done(bool);
83 void logItem(QString, int); //! set logger item
84 void logProgress(int, int); //! set progress bar.
85};
86
87Q_DECLARE_OPERATORS_FOR_FLAGS(BootloaderInstallBase::Capabilities)
88
89#endif
90
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include <QtDebug>
22#include <QtDebug>
23#include "bootloaderinstallfile.h"
24#include "utils.h"
25
26
27BootloaderInstallFile::BootloaderInstallFile(QObject *parent)
28 : BootloaderInstallBase(parent)
29{
30}
31
32
33bool BootloaderInstallFile::install(void)
34{
35 emit logItem(tr("Downloading bootloader"), LOGINFO);
36 qDebug() << __func__;
37 downloadBlStart(m_blurl);
38 connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
39 return true;
40}
41
42void BootloaderInstallFile::installStage2(void)
43{
44 emit logItem(tr("Installing Rockbox bootloader"), LOGINFO);
45
46 // if an old bootloader is present (Gigabeat) move it out of the way.
47 QString fwfile(resolvePathCase(m_blfile));
48 if(!fwfile.isEmpty()) {
49 QString moved = resolvePathCase(m_blfile) + ".ORIG";
50 qDebug() << "renaming" << fwfile << "->" << moved;
51 QFile::rename(fwfile, moved);
52 }
53
54 // if no old file found resolve path without basename
55 QFileInfo fi(m_blfile);
56 QString absPath = resolvePathCase(fi.absolutePath());
57
58 // if it's not possible to locate the base path try to create it
59 if(absPath.isEmpty()) {
60 QStringList pathElements = m_blfile.split("/");
61 // remove filename from list and save last path element
62 pathElements.removeLast();
63 QString lastElement = pathElements.last();
64 // remove last path element for base
65 pathElements.removeLast();
66 QString basePath = pathElements.join("/");
67
68 // check for base and bail out if not found. Otherwise create folder.
69 absPath = resolvePathCase(basePath);
70 QDir d(absPath);
71 d.mkpath(lastElement);
72 absPath = resolvePathCase(fi.absolutePath());
73
74 if(absPath.isEmpty()) {
75 emit logItem(tr("Error accessing output folder"), LOGERROR);
76 emit done(true);
77 return;
78 }
79 }
80 fwfile = absPath + "/" + fi.fileName();
81
82 // place (new) bootloader
83 m_tempfile.open();
84 qDebug() << "renaming" << m_tempfile.fileName() << "->" << fwfile;
85 m_tempfile.close();
86 m_tempfile.rename(fwfile);
87
88 emit logItem(tr("Bootloader successful installed"), LOGOK);
89 logInstall(LogAdd);
90
91 emit done(false);
92}
93
94
95bool BootloaderInstallFile::uninstall(void)
96{
97 qDebug() << __func__;
98 emit logItem(tr("Removing Rockbox bootloader"), LOGINFO);
99 // check if a .ORIG file is present, and allow moving it back.
100 QString origbl = resolvePathCase(m_blfile + ".ORIG");
101 if(origbl.isEmpty()) {
102 emit logItem(tr("No original firmware file found."), LOGERROR);
103 emit done(true);
104 return false;
105 }
106 QString fwfile = resolvePathCase(m_blfile);
107 if(!QFile::remove(fwfile)) {
108 emit logItem(tr("Can't remove Rockbox bootloader file."), LOGERROR);
109 emit done(true);
110 return false;
111 }
112 if(!QFile::rename(origbl, fwfile)) {
113 emit logItem(tr("Can't restore bootloader file."), LOGERROR);
114 emit done(true);
115 return false;
116 }
117 emit logItem(tr("Original bootloader restored successfully."), LOGOK);
118 logInstall(LogRemove);
119 emit done(false);
120
121 return true;
122}
123
124
125//! @brief check if bootloader is installed.
126//! @return BootloaderRockbox, BootloaderOther or BootloaderUnknown.
127BootloaderInstallBase::BootloaderType BootloaderInstallFile::installed(void)
128{
129 qDebug("%s()", __func__);
130 if(!resolvePathCase(m_blfile).isEmpty()
131 && !resolvePathCase(m_blfile + ".ORIG").isEmpty())
132 return BootloaderRockbox;
133 else if(!resolvePathCase(m_blfile).isEmpty())
134 return BootloaderOther;
135 else
136 return BootloaderUnknown;
137}
138
139
140BootloaderInstallBase::Capabilities BootloaderInstallFile::capabilities(void)
141{
142 qDebug() << __func__;
143 return Install | IsFile | CanCheckInstalled | Backup;
144}
145
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include "progressloggerinterface.h"
22#include "bootloaderinstallbase.h"
23
24//! install a bootloader by putting a single file on the player.
25// This installation method is used by Iaudio (firmware is flashed
26// automatically) and Gigabeat (Firmware is a file, OF needs to get
27// renamed).
28class BootloaderInstallFile : public BootloaderInstallBase
29{
30 Q_OBJECT
31
32 public:
33 BootloaderInstallFile(QObject *parent = 0);
34 bool install(void);
35 bool uninstall(void);
36 BootloaderInstallBase::BootloaderType installed(void);
37 Capabilities capabilities(void);
38
39 private slots:
40 void installStage2(void);
41
42 private:
43};
44
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include "bootloaderinstallbase.h"
22#include "bootloaderinstallhex.h"
23
24#include "../../tools/iriver.h"
25#include "../../tools/mkboot.h"
26
27struct md5s {
28 const char* orig;
29 const char* patched;
30};
31
32struct md5s md5sums[] = {
33#include "irivertools/h100sums.h"
34 { 0, 0 },
35#include "irivertools/h120sums.h"
36 { 0, 0 },
37#include "irivertools/h300sums.h"
38 { 0, 0 }
39};
40
41
42BootloaderInstallHex::BootloaderInstallHex(QObject *parent)
43 : BootloaderInstallBase(parent)
44{
45}
46
47
48bool BootloaderInstallHex::install(void)
49{
50 if(m_hex.isEmpty())
51 return false;
52 m_hashindex = -1;
53
54 // md5sum hex file
55 emit logItem(tr("checking MD5 hash of input file ..."), LOGINFO);
56 QByteArray filedata;
57 // read hex file into QByteArray
58 QFile file(m_hex);
59 file.open(QIODevice::ReadOnly);
60 filedata = file.readAll();
61 file.close();
62 QString hash = QCryptographicHash::hash(filedata,
63 QCryptographicHash::Md5).toHex();
64 qDebug() << "hexfile hash:" << hash;
65 if(file.error() != QFile::NoError) {
66 emit logItem(tr("Could not verify original firmware file"), LOGERROR);
67 emit done(true);
68 return false;
69 }
70 // check hash and figure model from md5sum
71 int i = sizeof(md5sums) / sizeof(struct md5s);
72 m_model = 4;
73 // 3: h300, 2: h120, 1: h100, 0:invalid
74 while(i--) {
75 if(md5sums[i].orig == 0)
76 m_model--;
77 if(!qstrcmp(md5sums[i].orig, hash.toAscii()))
78 break;
79 }
80 if(i < 0) {
81 emit logItem(tr("Firmware file not recognized."), LOGERROR);
82 return false;
83 }
84 else {
85 emit logItem(tr("MD5 hash ok"), LOGOK);
86 m_hashindex = i;
87 }
88
89 // check model agains download link.
90 QString match[] = {"", "h100", "h120", "h300"};
91 if(!m_blurl.path().contains(match[m_model])) {
92 emit logItem(tr("Firmware file doesn't match selected player."),
93 LOGERROR);
94 return false;
95 }
96
97 emit logItem(tr("Descrambling file"), LOGINFO);
98 m_descrambled.open();
99 int result;
100 result = iriver_decode(m_hex.toAscii().data(),
101 m_descrambled.fileName().toAscii().data(), FALSE, STRIP_NONE);
102 qDebug() << "iriver_decode" << result;
103
104 if(result < 0) {
105 emit logItem(tr("Error in descramble: %1").arg(scrambleError(result)), LOGERROR);
106 return false;
107 }
108
109 // download firmware from server
110 emit logItem(tr("Downloading bootloader file"), LOGINFO);
111 connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
112
113 downloadBlStart(m_blurl);
114 return true;
115}
116
117
118void BootloaderInstallHex::installStage2(void)
119{
120 emit logItem(tr("Adding bootloader to firmware file"), LOGINFO);
121
122 // local temp file
123 QTemporaryFile tempbin;
124 tempbin.open();
125 QString tempbinName = tempbin.fileName();
126 tempbin.close();
127 // get temporary files filenames -- external tools need this.
128 m_descrambled.open();
129 QString descrambledName = m_descrambled.fileName();
130 m_descrambled.close();
131 m_tempfile.open();
132 QString tempfileName = m_tempfile.fileName();
133 m_tempfile.close();
134
135 int origin = 0;
136 switch(m_model) {
137 case 3:
138 origin = 0x3f0000;
139 break;
140 case 2:
141 case 1:
142 origin = 0x1f0000;
143 break;
144 default:
145 origin = 0;
146 break;
147 }
148
149 // iriver decode already done in stage 1
150 int result;
151 if((result = mkboot(descrambledName.toLocal8Bit().constData(),
152 tempfileName.toLocal8Bit().constData(),
153 tempbinName.toLocal8Bit().constData(), origin)) < 0)
154 {
155 QString error;
156 switch(result) {
157 case -1: error = tr("could not open input file"); break;
158 case -2: error = tr("reading header failed"); break;
159 case -3: error = tr("reading firmware failed"); break;
160 case -4: error = tr("can't open bootloader file"); break;
161 case -5: error = tr("reading bootloader file failed"); break;
162 case -6: error = tr("can't open output file"); break;
163 case -7: error = tr("writing output file failed"); break;
164 }
165 emit logItem(tr("Error in patching: %1").arg(error), LOGERROR);
166
167 emit done(true);
168 return;
169 }
170 QTemporaryFile targethex;
171 targethex.open();
172 QString targethexName = targethex.fileName();
173 if((result = iriver_encode(tempbinName.toLocal8Bit().constData(),
174 targethexName.toLocal8Bit().constData(), FALSE)) < 0)
175 {
176 emit logItem(tr("Error in scramble: %1").arg(scrambleError(result)), LOGERROR);
177 targethex.close();
178
179 emit done(true);
180 return;
181 }
182
183 // finally check the md5sum of the created file
184 QByteArray filedata;
185 filedata = targethex.readAll();
186 targethex.close();
187 QString hash = QCryptographicHash::hash(filedata,
188 QCryptographicHash::Md5).toHex();
189 qDebug() << "created hexfile hash:" << hash;
190
191 emit logItem(tr("Checking modified firmware file"), LOGINFO);
192 if(hash != QString(md5sums[m_hashindex].patched)) {
193 emit logItem(tr("Error: modified file checksum wrong"), LOGERROR);
194 targethex.remove();
195 emit done(true);
196 return;
197 }
198 // finally copy file to player
199 targethex.copy(m_blfile);
200
201 emit logItem(tr("Success: modified firmware file created"), LOGINFO);
202 logInstall(LogAdd);
203 emit done(false);
204
205 return;
206}
207
208
209bool BootloaderInstallHex::uninstall(void)
210{
211 emit logItem("Uninstallation not possible, only installation info removed", LOGINFO);
212 logInstall(LogRemove);
213 return false;
214}
215
216
217BootloaderInstallBase::BootloaderType BootloaderInstallHex::installed(void)
218{
219 return BootloaderUnknown;
220}
221
222
223BootloaderInstallBase::Capabilities BootloaderInstallHex::capabilities(void)
224{
225 return (Install | NeedsFlashing);
226}
227
228QString BootloaderInstallHex::scrambleError(int err)
229{
230 QString error;
231 switch(err) {
232 case -1: error = tr("Can't open input file"); break;
233 case -2: error = tr("Can't open output file"); break;
234 case -3: error = tr("invalid file: header length wrong"); break;
235 case -4: error = tr("invalid file: unrecognized header"); break;
236 case -5: error = tr("invalid file: \"length\" field wrong"); break;
237 case -6: error = tr("invalid file: \"length2\" field wrong"); break;
238 case -7: error = tr("invalid file: internal checksum error"); break;
239 case -8: error = tr("invalid file: \"length3\" field wrong"); break;
240 default: error = tr("unknown"); break;
241 }
242 return error;
243}
244
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef BOOTLOADERINSTALLHEX_H
21#define BOOTLOADERINSTALLHEX_H
22
23#include <QtCore>
24#include "bootloaderinstallbase.h"
25
26
27// bootloader installation derivate based on fwpatcher
28// This will patch a given hex file using (de)scramble / mkboot
29// and put it on the player.
30class BootloaderInstallHex : public BootloaderInstallBase
31{
32 Q_OBJECT
33
34 public:
35 BootloaderInstallHex(QObject *parent = 0);
36 bool install(void);
37 bool uninstall(void);
38 BootloaderInstallBase::BootloaderType installed(void);
39 Capabilities capabilities(void);
40
41 void setHexfile(QString h)
42 { m_hex = h; }
43
44 private:
45 QString m_hex;
46 int m_hashindex;
47 int m_model;
48 QTemporaryFile m_descrambled;
49 QString scrambleError(int);
50
51 private slots:
52 void installStage2(void);
53};
54
55
56#endif
57
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include "bootloaderinstallbase.h"
22#include "bootloaderinstallipod.h"
23
24#include "../ipodpatcher/ipodpatcher.h"
25
26
27BootloaderInstallIpod::BootloaderInstallIpod(QObject *parent)
28 : BootloaderInstallBase(parent)
29{
30 (void)parent;
31 // initialize sector buffer. ipod_sectorbuf is defined in ipodpatcher.
32 ipod_sectorbuf = NULL;
33 ipod_alloc_buffer(&ipod_sectorbuf, BUFFER_SIZE);
34}
35
36
37BootloaderInstallIpod::~BootloaderInstallIpod()
38{
39 free(ipod_sectorbuf);
40}
41
42
43bool BootloaderInstallIpod::install(void)
44{
45 if(ipod_sectorbuf == NULL) {
46 emit logItem(tr("Error: can't allocate buffer memory!"), LOGERROR);
47 emit done(true);
48 return false;
49 }
50
51 struct ipod_t ipod;
52
53 int n = ipod_scan(&ipod);
54 if(n == -1) {
55 emit logItem(tr("No Ipod detected\n"
56 "Permission for disc access denied!"),
57 LOGERROR);
58 emit done(true);
59 return false;
60 }
61 if(n == 0) {
62 emit logItem(tr("No Ipod detected!"), LOGERROR);
63 emit done(true);
64 return false;
65 }
66
67 if(ipod.macpod) {
68 emit logItem(tr("Warning: This is a MacPod, Rockbox only runs on WinPods.\n"
69 "See http://www.rockbox.org/wiki/IpodConversionToFAT32"), LOGERROR);
70 emit done(true);
71 return false;
72 }
73 emit logItem(tr("Downloading bootloader file"), LOGINFO);
74
75 downloadBlStart(m_blurl);
76 connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
77 return true;
78}
79
80
81void BootloaderInstallIpod::installStage2(void)
82{
83 struct ipod_t ipod;
84
85 if(!ipodInitialize(&ipod)) {
86 emit done(true);
87 return;
88 }
89
90 read_directory(&ipod);
91
92 if(ipod.nimages <= 0) {
93 emit logItem(tr("Failed to read firmware directory"), LOGERROR);
94 emit done(true);
95 return;
96 }
97 if(getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) {
98 emit logItem(tr("Unknown version number in firmware (%1)").arg(
99 ipod.ipod_directory[0].vers), LOGERROR);
100 emit done(true);
101 return;
102 }
103
104 if(ipod.macpod) {
105 emit logItem(tr("Warning: This is a MacPod. Rockbox only runs on WinPods.\n"
106 "See http://www.rockbox.org/wiki/IpodConversionToFAT32"), LOGERROR);
107 emit done(true);
108 return;
109 }
110
111 if(ipod_reopen_rw(&ipod) < 0) {
112 emit logItem(tr("Could not open Ipod in R/W mode"), LOGERROR);
113 emit done(true);
114 return;
115 }
116
117 m_tempfile.open();
118 QString blfile = m_tempfile.fileName();
119 m_tempfile.close();
120 if(add_bootloader(&ipod, blfile.toLatin1().data(), FILETYPE_DOT_IPOD) == 0) {
121 emit logItem(tr("Successfull added bootloader"), LOGOK);
122 logInstall(LogAdd);
123 emit done(false);
124 ipod_close(&ipod);
125 return;
126 }
127 else {
128 emit logItem(tr("Failed to add bootloader"), LOGERROR);
129 ipod_close(&ipod);
130 emit done(true);
131 return;
132 }
133 qDebug() << "version installed:" << m_blversion.toString(Qt::ISODate);
134}
135
136
137bool BootloaderInstallIpod::uninstall(void)
138{
139 struct ipod_t ipod;
140
141 if(!ipodInitialize(&ipod)) {
142 emit done(true);
143 return false;
144 }
145
146 read_directory(&ipod);
147
148 if (ipod.nimages <= 0) {
149 emit logItem(tr("Failed to read firmware directory"),LOGERROR);
150 emit done(true);
151 return false;
152 }
153 if (getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) {
154 emit logItem(tr("Unknown version number in firmware (%1)").arg(
155 ipod.ipod_directory[0].vers), LOGERROR);
156 emit done(true);
157 return false;
158 }
159
160 if (ipod_reopen_rw(&ipod) < 0) {
161 emit logItem(tr("Could not open Ipod in RW mode"), LOGERROR);
162 emit done(true);
163 return false;
164 }
165
166 if (ipod.ipod_directory[0].entryOffset == 0) {
167 emit logItem(tr("No bootloader detected."), LOGERROR);
168 emit done(true);
169 return false;
170 }
171
172 if (delete_bootloader(&ipod)==0) {
173 emit logItem(tr("Successfully removed Bootloader"), LOGOK);
174 logInstall(LogRemove);
175 emit done(false);
176 ipod_close(&ipod);
177 return true;
178 }
179 else {
180 emit logItem(tr("Removing the bootloader failed."), LOGERROR);
181 emit done(true);
182 ipod_close(&ipod);
183 return false;
184 }
185}
186
187
188BootloaderInstallBase::BootloaderType BootloaderInstallIpod::installed(void)
189{
190 struct ipod_t ipod;
191 BootloaderInstallBase::BootloaderType result = BootloaderRockbox;
192
193 if(!ipodInitialize(&ipod)) {
194 qDebug() << "BootloaderInstallIpod::installed(): BootloaderUnknown";
195 result = BootloaderUnknown;
196 }
197
198 if (ipod.ipod_directory[0].entryOffset == 0) {
199 qDebug() << "BootloaderInstallIpod::installed(): BootloaderOther";
200 result = BootloaderOther;
201 }
202 qDebug() << "BootloaderInstallIpod::installed(): BootloaderRockbox";
203 ipod_close(&ipod);
204
205 return result;
206}
207
208
209BootloaderInstallBase::Capabilities BootloaderInstallIpod::capabilities(void)
210{
211 return (Install | Uninstall | IsRaw);
212}
213
214
215bool BootloaderInstallIpod::ipodInitialize(struct ipod_t *ipod)
216{
217 ipod_scan(ipod);
218 if(ipod_open(ipod, 0) < 0) {
219 emit logItem(tr("Could not open Ipod"), LOGERROR);
220 return false;
221 }
222
223 if(read_partinfo(ipod, 0) < 0) {
224 emit logItem(tr("Could not read partition table"), LOGERROR);
225 return false;
226 }
227
228 if(ipod->pinfo[0].start == 0) {
229 emit logItem(tr("No firmware partition on disk"), LOGERROR);
230
231 return false;
232 }
233 return true;
234}
235
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef BOOTLOADERINSTALLIPOD_H
21#define BOOTLOADERINSTALLIPOD_H
22
23#include <QtCore>
24#include "bootloaderinstallbase.h"
25#include "../ipodpatcher/ipodpatcher.h"
26
27// installer class derivate for Ipod installation
28// based on ipodpatcher.
29class BootloaderInstallIpod : public BootloaderInstallBase
30{
31 Q_OBJECT
32
33 public:
34 BootloaderInstallIpod(QObject *parent = 0);
35 ~BootloaderInstallIpod();
36 bool install(void);
37 bool uninstall(void);
38 BootloaderInstallBase::BootloaderType installed(void);
39 Capabilities capabilities(void);
40
41 private slots:
42 void installStage2(void);
43
44 private:
45 bool ipodInitialize(struct ipod_t *);
46};
47
48
49#endif
50
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include <QtDebug>
22#include <QtDebug>
23#include "bootloaderinstallmi4.h"
24#include "utils.h"
25
26BootloaderInstallMi4::BootloaderInstallMi4(QObject *parent)
27 : BootloaderInstallBase(parent)
28{
29}
30
31
32bool BootloaderInstallMi4::install(void)
33{
34 emit logItem(tr("Downloading bootloader"), LOGINFO);
35 qDebug() << __func__;
36 downloadBlStart(m_blurl);
37 connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
38 return true;
39}
40
41void BootloaderInstallMi4::installStage2(void)
42{
43 emit logItem(tr("Installing Rockbox bootloader"), LOGINFO);
44
45 // move old bootloader out of the way
46 QString fwfile(resolvePathCase(m_blfile));
47 QFile oldbl(fwfile);
48 QString moved = QFileInfo(resolvePathCase(m_blfile)).absolutePath()
49 + "/OF.mi4";
50 qDebug() << "renaming" << fwfile << "->" << moved;
51 oldbl.rename(moved);
52
53 // place new bootloader
54 m_tempfile.open();
55 qDebug() << "renaming" << m_tempfile.fileName() << "->" << fwfile;
56 m_tempfile.close();
57 m_tempfile.rename(fwfile);
58
59 emit logItem(tr("Bootloader successful installed"), LOGOK);
60 logInstall(LogAdd);
61
62 emit done(true);
63}
64
65
66bool BootloaderInstallMi4::uninstall(void)
67{
68 qDebug() << __func__;
69
70 // check if it's actually a Rockbox bootloader
71 emit logItem(tr("Checking for Rockbox bootloader"), LOGINFO);
72 if(installed() != BootloaderRockbox) {
73 emit logItem(tr("No Rockbox bootloader found"), LOGERROR);
74 return false;
75 }
76
77 // check if OF file present
78 emit logItem(tr("Checking for original firmware file"), LOGINFO);
79 QString original = QFileInfo(resolvePathCase(m_blfile)).absolutePath()
80 + "/OF.mi4";
81
82 if(resolvePathCase(original).isEmpty()) {
83 emit logItem(tr("Error finding original firmware file"), LOGERROR);
84 return false;
85 }
86
87 // finally remove RB bootloader
88 QString resolved = resolvePathCase(m_blfile);
89 QFile blfile(resolved);
90 blfile.remove();
91
92 QFile oldbl(resolvePathCase(original));
93 oldbl.rename(m_blfile);
94 emit logItem(tr("Rockbox bootloader successful removed"), LOGINFO);
95 logInstall(LogRemove);
96 emit done(false);
97
98 return true;
99}
100
101
102//! check if a bootloader is installed and return its state.
103BootloaderInstallBase::BootloaderType BootloaderInstallMi4::installed(void)
104{
105 // for MI4 files we can check if we actually have a RB bootloader
106 // installed.
107 // RB bootloader has "RBBL" at 0x1f8 in the mi4 file.
108
109 // make sure to resolve case to prevent case issues
110 QString resolved;
111 resolved = resolvePathCase(m_blfile);
112 if(resolved.isEmpty()) {
113 qDebug("%s: BootloaderNone", __func__);
114 return BootloaderNone;
115 }
116
117 QFile f(resolved);
118 f.open(QIODevice::ReadOnly);
119 f.seek(0x1f8);
120 char magic[4];
121 f.read(magic, 4);
122 f.close();
123
124 if(!memcmp(magic, "RBBL", 4)) {
125 qDebug("%s: BootloaderRockbox", __func__);
126 return BootloaderRockbox;
127 }
128 else {
129 qDebug("%s: BootloaderOther", __func__);
130 return BootloaderOther;
131 }
132}
133
134
135BootloaderInstallBase::Capabilities BootloaderInstallMi4::capabilities(void)
136{
137 qDebug() << __func__;
138 return Install | Uninstall | Backup | IsFile | CanCheckInstalled | CanCheckVersion;
139}
140
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include "progressloggerinterface.h"
22#include "bootloaderinstallbase.h"
23
24
25// mi4 bootloader file based installation.
26// Puts the bootloader file to the correct location and
27// renames the OF to OF.mi4.
28class BootloaderInstallMi4 : public BootloaderInstallBase
29{
30 Q_OBJECT
31
32 public:
33 BootloaderInstallMi4(QObject *parent = 0);
34 bool install(void);
35 bool uninstall(void);
36 BootloaderInstallBase::BootloaderType installed(void);
37 Capabilities capabilities(void);
38
39 private slots:
40 void installStage2(void);
41
42 private:
43};
44
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include "bootloaderinstallbase.h"
22#include "bootloaderinstallsansa.h"
23
24#include "../sansapatcher/sansapatcher.h"
25
26BootloaderInstallSansa::BootloaderInstallSansa(QObject *parent)
27 : BootloaderInstallBase(parent)
28{
29 (void)parent;
30 // initialize sector buffer. sansa_sectorbuf is instantiated by
31 // sansapatcher.
32 sansa_sectorbuf = NULL;
33 sansa_alloc_buffer(&sansa_sectorbuf, BUFFER_SIZE);
34}
35
36
37BootloaderInstallSansa::~BootloaderInstallSansa()
38{
39 free(sansa_sectorbuf);
40}
41
42
43/** Start bootloader installation.
44 */
45bool BootloaderInstallSansa::install(void)
46{
47 if(sansa_sectorbuf == NULL) {
48 emit logItem(tr("Error: can't allocate buffer memory!"), LOGERROR);
49 return false;
50 emit done(true);
51 }
52
53 emit logItem(tr("Searching for Sansa"), LOGINFO);
54
55 struct sansa_t sansa;
56
57 int n = sansa_scan(&sansa);
58 if(n == -1) {
59 emit logItem(tr("Permission for disc access denied!\n"
60 "This is required to install the bootloader"),
61 LOGERROR);
62 emit done(true);
63 return false;
64 }
65 if(n == 0) {
66 emit logItem(tr("No Sansa detected!"), LOGERROR);
67 emit done(true);
68 return false;
69 }
70 emit logItem(tr("Downloading bootloader file"), LOGINFO);
71
72 downloadBlStart(m_blurl);
73 connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
74 return true;
75}
76
77
78/** Finish bootloader installation.
79 */
80void BootloaderInstallSansa::installStage2(void)
81{
82 struct sansa_t sansa;
83 sansa_scan(&sansa);
84
85 if(sansa_open(&sansa, 0) < 0) {
86 emit logItem(tr("could not open Sansa"), LOGERROR);
87 emit done(true);
88 return;
89 }
90
91 if(sansa_read_partinfo(&sansa, 0) < 0)
92 {
93 emit logItem(tr("could not read partitiontable"), LOGERROR);
94 emit done(true);
95 return;
96 }
97
98 int i = is_sansa(&sansa);
99 if(i < 0) {
100
101 emit logItem(tr("Disk is not a Sansa (Error: %1), aborting.").arg(i), LOGERROR);
102 emit done(true);
103 return;
104 }
105
106 if(sansa.hasoldbootloader) {
107 emit logItem(tr("OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n"
108 "You must reinstall the original Sansa firmware before running\n"
109 "sansapatcher for the first time.\n"
110 "See http://www.rockbox.org/wiki/SansaE200Install\n"),
111 LOGERROR);
112 emit done(true);
113 return;
114 }
115
116 if(sansa_reopen_rw(&sansa) < 0) {
117 emit logItem(tr("Could not open Sansa in R/W mode"), LOGERROR);
118 emit done(true);
119 return;
120 }
121
122 m_tempfile.open();
123 QString blfile = m_tempfile.fileName();
124 m_tempfile.close();
125 if(sansa_add_bootloader(&sansa, blfile.toLatin1().data(),
126 FILETYPE_MI4) == 0) {
127 emit logItem(tr("Successfully installed bootloader"), LOGOK);
128 logInstall(LogAdd);
129 emit done(false);
130 sansa_close(&sansa);
131 return;
132 }
133 else {
134 emit logItem(tr("Failed to install bootloader"), LOGERROR);
135 sansa_close(&sansa);
136 emit done(true);
137 return;
138 }
139
140}
141
142
143/** Uninstall the bootloader.
144 */
145bool BootloaderInstallSansa::uninstall(void)
146{
147 struct sansa_t sansa;
148
149 if(sansa_scan(&sansa) != 1) {
150 emit logItem(tr("Can't find Sansa"), LOGERROR);
151 emit done(true);
152 return false;
153 }
154
155 if (sansa_open(&sansa, 0) < 0) {
156 emit logItem(tr("Could not open Sansa"), LOGERROR);
157 emit done(true);
158 return false;
159 }
160
161 if (sansa_read_partinfo(&sansa,0) < 0) {
162 emit logItem(tr("Could not read partition table"), LOGERROR);
163 emit done(true);
164 return false;
165 }
166
167 int i = is_sansa(&sansa);
168 if(i < 0) {
169 emit logItem(tr("Disk is not a Sansa (Error %1), aborting.").arg(i), LOGERROR);
170 emit done(true);
171 return false;
172 }
173
174 if (sansa.hasoldbootloader) {
175 emit logItem(tr("OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n"
176 "You must reinstall the original Sansa firmware before running\n"
177 "sansapatcher for the first time.\n"
178 "See http://www.rockbox.org/wiki/SansaE200Install\n"),
179 LOGERROR);
180 emit done(true);
181 return false;
182 }
183
184 if (sansa_reopen_rw(&sansa) < 0) {
185 emit logItem(tr("Could not open Sansa in R/W mode"), LOGERROR);
186 emit done(true);
187 return false;
188 }
189
190 if (sansa_delete_bootloader(&sansa)==0) {
191 emit logItem(tr("Successfully removed bootloader"), LOGOK);
192 logInstall(LogRemove);
193 emit done(false);
194 sansa_close(&sansa);
195 return true;
196 }
197 else {
198 emit logItem(tr("Removing bootloader failed."),LOGERROR);
199 emit done(true);
200 sansa_close(&sansa);
201 return false;
202 }
203
204 return false;
205}
206
207
208/** Check if bootloader is already installed
209 */
210BootloaderInstallBase::BootloaderType BootloaderInstallSansa::installed(void)
211{
212 struct sansa_t sansa;
213 int num;
214
215 if(sansa_scan(&sansa) != 1) {
216 return BootloaderUnknown;
217 }
218 if (sansa_open(&sansa, 0) < 0) {
219 return BootloaderUnknown;
220 }
221 if (sansa_read_partinfo(&sansa,0) < 0) {
222 return BootloaderUnknown;
223 }
224 if(is_sansa(&sansa) < 0) {
225 return BootloaderUnknown;
226 }
227 if((num = sansa_list_images(&sansa)) == 2) {
228 return BootloaderRockbox;
229 }
230 else if(num == 1) {
231 return BootloaderOther;
232 }
233 return BootloaderUnknown;
234
235}
236
237
238/** Get capabilities of subclass installer.
239 */
240BootloaderInstallBase::Capabilities BootloaderInstallSansa::capabilities(void)
241{
242 return (Install | Uninstall | IsRaw | CanCheckInstalled);
243}
244
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#ifndef BOOTLOADERINSTALLSANSA_H
21#define BOOTLOADERINSTALLSANSA_H
22
23#include <QtCore>
24#include "bootloaderinstallbase.h"
25
26
27// bootloader installation class for devices handled by sansapatcher.
28class BootloaderInstallSansa : public BootloaderInstallBase
29{
30 Q_OBJECT
31
32 public:
33 BootloaderInstallSansa(QObject *parent = 0);
34 ~BootloaderInstallSansa();
35 bool install(void);
36 bool uninstall(void);
37 BootloaderInstallBase::BootloaderType installed(void);
38 Capabilities capabilities(void);
39
40 private:
41
42 private slots:
43 void installStage2(void);
44};
45
46
47#endif
48
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include <QtNetwork>
22#include <QtDebug>
23
24#include "httpget.h"
25
26QDir HttpGet::m_globalCache; //< global cach path value for new objects
27QUrl HttpGet::m_globalProxy; //< global proxy value for new objects
28bool HttpGet::m_globalDumbCache = false; //< globally set cache "dumb" mode
29QString HttpGet::m_globalUserAgent; //< globally set user agent for requests
30
31HttpGet::HttpGet(QObject *parent)
32 : QObject(parent)
33{
34 outputToBuffer = true;
35 m_cached = false;
36 m_dumbCache = m_globalDumbCache;
37 getRequest = -1;
38 headRequest = -1;
39 // if a request is cancelled before a reponse is available return some
40 // hint about this in the http response instead of nonsense.
41 m_response = -1;
42
43 // default to global proxy / cache if not empty.
44 // proxy is automatically enabled, disable it by setting an empty proxy
45 // cache is enabled to be in line, can get disabled with setCache(bool)
46 if(!m_globalProxy.isEmpty())
47 setProxy(m_globalProxy);
48 m_usecache = false;
49 m_cachedir = m_globalCache;
50
51 m_serverTimestamp = QDateTime();
52
53 connect(&http, SIGNAL(done(bool)), this, SLOT(httpDone(bool)));
54 connect(&http, SIGNAL(dataReadProgress(int, int)), this, SIGNAL(dataReadProgress(int, int)));
55 connect(&http, SIGNAL(requestFinished(int, bool)), this, SLOT(httpFinished(int, bool)));
56 connect(&http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)), this, SLOT(httpResponseHeader(const QHttpResponseHeader&)));
57 connect(&http, SIGNAL(stateChanged(int)), this, SLOT(httpState(int)));
58 connect(&http, SIGNAL(requestStarted(int)), this, SLOT(httpStarted(int)));
59
60 connect(&http, SIGNAL(readyRead(const QHttpResponseHeader&)), this, SLOT(httpResponseHeader(const QHttpResponseHeader&)));
61
62}
63
64
65//! @brief set cache path
66// @param d new directory to use as cache path
67void HttpGet::setCache(QDir d)
68{
69 m_cachedir = d;
70 bool result;
71 result = initializeCache(d);
72 qDebug() << "[HTTP]"<< __func__ << "(QDir)" << d.absolutePath() << result;
73 m_usecache = result;
74}
75
76
77/** @brief enable / disable cache useage
78 * @param c set cache usage
79 */
80void HttpGet::setCache(bool c)
81{
82 qDebug() << "[HTTP]" << __func__ << "(bool) =" << c;
83 m_usecache = c;
84 // make sure cache is initialized
85 if(c)
86 m_usecache = initializeCache(m_cachedir);
87}
88
89
90bool HttpGet::initializeCache(const QDir& d)
91{
92 bool result;
93 QString p = d.absolutePath() + "/rbutil-cache";
94 if(QFileInfo(d.absolutePath()).isDir())
95 {
96 if(!QFileInfo(p).isDir())
97 result = d.mkdir("rbutil-cache");
98 else
99 result = true;
100 }
101 else
102 result = false;
103
104 return result;
105
106}
107
108
109/** @brief read all downloaded data into a buffer
110 * @return data
111 */
112QByteArray HttpGet::readAll()
113{
114 return dataBuffer;
115}
116
117
118/** @brief get http error
119 * @return http error
120 */
121QHttp::Error HttpGet::error()
122{
123 return http.error();
124}
125
126
127void HttpGet::setProxy(const QUrl &proxy)
128{
129 qDebug() << "[HTTP]" << __func__ << "(QUrl)" << proxy.toString();
130 m_proxy = proxy;
131 http.setProxy(m_proxy.host(), m_proxy.port(), m_proxy.userName(), m_proxy.password());
132}
133
134
135void HttpGet::setProxy(bool enable)
136{
137 qDebug() << "[HTTP]" << __func__ << "(bool)" << enable;
138 if(enable)
139 http.setProxy(m_proxy.host(), m_proxy.port(), m_proxy.userName(), m_proxy.password());
140 else
141 http.setProxy("", 0);
142}
143
144
145void HttpGet::setFile(QFile *file)
146{
147 outputFile = file;
148 outputToBuffer = false;
149 qDebug() << "[HTTP]" << __func__ << "(QFile*)" << outputFile->fileName();
150}
151
152
153void HttpGet::abort()
154{
155 http.abort();
156 if(!outputToBuffer)
157 outputFile->close();
158}
159
160
161bool HttpGet::getFile(const QUrl &url)
162{
163 if (!url.isValid()) {
164 qDebug() << "[HTTP] Error: Invalid URL" << endl;
165 return false;
166 }
167
168 if (url.scheme() != "http") {
169 qDebug() << "[HTTP] Error: URL must start with 'http:'" << endl;
170 return false;
171 }
172
173 if (url.path().isEmpty()) {
174 qDebug() << "[HTTP] Error: URL has no path" << endl;
175 return false;
176 }
177 m_serverTimestamp = QDateTime();
178 // if no output file was set write to buffer
179 if(!outputToBuffer) {
180 if (!outputFile->open(QIODevice::ReadWrite)) {
181 qDebug() << "[HTTP] Error: Cannot open " << qPrintable(outputFile->fileName())
182 << " for writing: " << qPrintable(outputFile->errorString())
183 << endl;
184 return false;
185 }
186 }
187 qDebug() << "[HTTP] downloading" << url.toEncoded();
188 // create request
189 http.setHost(url.host(), url.port(80));
190 // construct query (if any)
191 QList<QPair<QString, QString> > qitems = url.queryItems();
192 if(url.hasQuery()) {
193 m_query = "?";
194 for(int i = 0; i < qitems.size(); i++)
195 m_query += QUrl::toPercentEncoding(qitems.at(i).first, "/") + "="
196 + QUrl::toPercentEncoding(qitems.at(i).second, "/") + "&";
197 }
198
199 // create hash used for caching
200 m_hash = QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Md5).toHex();
201 m_path = QString(QUrl::toPercentEncoding(url.path(), "/"));
202
203 // construct request header
204 m_header.setValue("Host", url.host());
205 m_header.setValue("User-Agent", m_globalUserAgent);
206 m_header.setValue("Connection", "Keep-Alive");
207
208 if(m_dumbCache || !m_usecache) {
209 getFileFinish();
210 }
211 else {
212 // schedule HTTP header request
213 connect(this, SIGNAL(headerFinished()), this, SLOT(getFileFinish()));
214 m_header.setRequest("HEAD", m_path + m_query);
215 headRequest = http.request(m_header);
216 }
217
218 return true;
219}
220
221
222void HttpGet::getFileFinish()
223{
224 m_cachefile = m_cachedir.absolutePath() + "/rbutil-cache/" + m_hash;
225 if(m_usecache) {
226 // check if the file is present in cache
227 qDebug() << "[HTTP] cache ENABLED";
228 QFileInfo cachefile = QFileInfo(m_cachefile);
229 if(cachefile.isReadable()
230 && cachefile.size() > 0
231 && cachefile.lastModified() > m_serverTimestamp) {
232
233 qDebug() << "[HTTP] cached file found:" << m_cachefile;
234
235 getRequest = -1;
236 QFile c(m_cachefile);
237 if(!outputToBuffer) {
238 qDebug() << "[HTTP] copying cache file to output" << outputFile->fileName();
239 c.open(QIODevice::ReadOnly);
240 outputFile->open(QIODevice::ReadWrite);
241 outputFile->write(c.readAll());
242 outputFile->close();
243 c.close();
244 }
245 else {
246 qDebug() << "[HTTP] reading cache file into buffer";
247 c.open(QIODevice::ReadOnly);
248 dataBuffer = c.readAll();
249 c.close();
250 }
251 m_response = 200; // fake "200 OK" HTTP response
252 m_cached = true;
253 httpDone(false); // we're done now. Fake http "done" signal.
254 return;
255 }
256 else {
257 if(cachefile.isReadable())
258 qDebug() << "[HTTP] file in cache timestamp:" << cachefile.lastModified();
259 else
260 qDebug() << "[HTTP] file not in cache.";
261 qDebug() << "[HTTP] server file timestamp:" << m_serverTimestamp;
262 qDebug() << "[HTTP] downloading file to" << m_cachefile;
263 // unlink old cache file
264 if(cachefile.isReadable())
265 QFile(m_cachefile).remove();
266 }
267
268 }
269 else {
270 qDebug() << "[HTTP] cache DISABLED";
271 }
272 // schedule GET request
273 m_header.setRequest("GET", m_path + m_query);
274 if(outputToBuffer) {
275 qDebug() << "[HTTP] downloading to buffer.";
276 getRequest = http.request(m_header);
277 }
278 else {
279 qDebug() << "[HTTP] downloading to file:"
280 << qPrintable(outputFile->fileName());
281 getRequest = http.request(m_header, 0, outputFile);
282 }
283 qDebug() << "[HTTP] GET request scheduled, id:" << getRequest;
284
285 return;
286}
287
288
289void HttpGet::httpDone(bool error)
290{
291 if (error) {
292 qDebug() << "[HTTP] Error: " << qPrintable(http.errorString()) << httpResponse();
293 }
294 if(!outputToBuffer)
295 outputFile->close();
296
297 if(m_usecache && !m_cached && !error) {
298 qDebug() << "[HTTP] creating cache file" << m_cachefile;
299 QFile c(m_cachefile);
300 c.open(QIODevice::ReadWrite);
301 if(!outputToBuffer) {
302 outputFile->open(QIODevice::ReadOnly | QIODevice::Truncate);
303 c.write(outputFile->readAll());
304 outputFile->close();
305 }
306 else
307 c.write(dataBuffer);
308
309 c.close();
310 }
311 // if cached file found and cache enabled ignore http errors
312 if(m_usecache && m_cached && !http.hasPendingRequests()) {
313 error = false;
314 }
315 // take care of concurring requests. If there is still one running,
316 // don't emit done(). That request will call this slot again.
317 if(http.currentId() == 0 && !http.hasPendingRequests())
318 emit done(error);
319}
320
321
322void HttpGet::httpFinished(int id, bool error)
323{
324 qDebug() << "[HTTP]" << __func__ << "(int, bool) =" << id << error;
325 if(id == getRequest) {
326 dataBuffer = http.readAll();
327
328 emit requestFinished(id, error);
329 }
330 qDebug() << "[HTTP] hasPendingRequests =" << http.hasPendingRequests();
331
332
333 if(id == headRequest) {
334 QHttpResponseHeader h = http.lastResponse();
335
336 QString date = h.value("Last-Modified").simplified();
337 if(date.isEmpty()) {
338 m_serverTimestamp = QDateTime(); // no value = invalid
339 emit headerFinished();
340 return;
341 }
342 // to successfully parse the date strip weekday and timezone
343 date.remove(0, date.indexOf(" ") + 1);
344 if(date.endsWith("GMT"))
345 date.truncate(date.indexOf(" GMT"));
346 // distinguish input formats (see RFC1945)
347 // RFC 850
348 if(date.contains("-"))
349 m_serverTimestamp = QDateTime::fromString(date, "dd-MMM-yy hh:mm:ss");
350 // asctime format
351 else if(date.at(0).isLetter())
352 m_serverTimestamp = QDateTime::fromString(date, "MMM d hh:mm:ss yyyy");
353 // RFC 822
354 else
355 m_serverTimestamp = QDateTime::fromString(date, "dd MMM yyyy hh:mm:ss");
356 qDebug() << "[HTTP] Header Request Date:" << date << ", parsed:" << m_serverTimestamp;
357 emit headerFinished();
358 return;
359 }
360 if(id == getRequest)
361 emit requestFinished(id, error);
362}
363
364void HttpGet::httpStarted(int id)
365{
366 qDebug() << "[HTTP]" << __func__ << "(int) =" << id;
367 qDebug() << "headRequest" << headRequest << "getRequest" << getRequest;
368}
369
370
371QString HttpGet::errorString()
372{
373 return http.errorString();
374}
375
376
377void HttpGet::httpResponseHeader(const QHttpResponseHeader &resp)
378{
379 // if there is a network error abort all scheduled requests for
380 // this download
381 m_response = resp.statusCode();
382 if(m_response != 200) {
383 qDebug() << "[HTTP] response error =" << m_response << resp.reasonPhrase();
384 http.abort();
385 }
386 // 301 -- moved permanently
387 // 302 -- found
388 // 303 -- see other
389 // 307 -- moved temporarily
390 // in all cases, header: location has the correct address so we can follow.
391 if(m_response == 301 || m_response == 302 || m_response == 303 || m_response == 307) {
392 // start new request with new url
393 qDebug() << "[HTTP] response =" << m_response << "- following";
394 getFile(resp.value("location") + m_query);
395 }
396}
397
398
399int HttpGet::httpResponse()
400{
401 return m_response;
402}
403
404
405void HttpGet::httpState(int state)
406{
407 QString s[] = {"Unconnected", "HostLookup", "Connecting", "Sending",
408 "Reading", "Connected", "Closing"};
409 if(state <= 6)
410 qDebug() << "[HTTP]" << __func__ << "() = " << s[state];
411 else qDebug() << "[HTTP]" << __func__ << "() = " << state;
412}
413
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 by Dominik Riebeling
10 * $Id$
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22
23#ifndef HTTPGET_H
24#define HTTPGET_H
25
26#include <QtCore>
27#include <QtNetwork>
28
29class QUrl;
30
31class HttpGet : public QObject
32{
33 Q_OBJECT
34
35 public:
36 HttpGet(QObject *parent = 0);
37
38 bool getFile(const QUrl &url);
39 void setProxy(const QUrl &url);
40 void setProxy(bool);
41 QHttp::Error error(void);
42 QString errorString(void);
43 void setFile(QFile*);
44 void setCache(QDir);
45 void setCache(bool);
46 int httpResponse(void);
47 QByteArray readAll(void);
48 bool isCached()
49 { return m_cached; }
50 QDateTime timestamp(void)
51 { return m_serverTimestamp; }
52 void setDumbCache(bool b) //< disable checking of http header timestamp for caching
53 { m_dumbCache = b; }
54 static void setGlobalCache(const QDir d) //< set global cache path
55 { m_globalCache = d; }
56 static void setGlobalProxy(const QUrl p) //< set global proxy value
57 { m_globalProxy = p; }
58 static void setGlobalDumbCache(bool b) //< set "dumb" (ignore server status) caching mode
59 { m_globalDumbCache = b; }
60 static void setGlobalUserAgent(QString u) //< set global user agent string
61 { m_globalUserAgent = u; }
62
63 public slots:
64 void abort(void);
65
66 signals:
67 void done(bool);
68 void dataReadProgress(int, int);
69 void requestFinished(int, bool);
70 void headerFinished(void);
71
72 private slots:
73 void httpDone(bool error);
74 void httpFinished(int, bool);
75 void httpResponseHeader(const QHttpResponseHeader&);
76 void httpState(int);
77 void httpStarted(int);
78 void getFileFinish(void);
79
80 private:
81 bool initializeCache(const QDir&);
82 QHttp http; //< download object
83 QFile *outputFile;
84 int m_response; //< http response
85 int getRequest; //! get file http request id
86 int headRequest; //! get http header request id
87 QByteArray dataBuffer;
88 bool outputToBuffer;
89 bool m_usecache;
90 QDir m_cachedir;
91 QString m_cachefile; // cached filename
92 bool m_cached;
93 QUrl m_proxy;
94 QDateTime m_serverTimestamp; //< timestamp of file on server
95 QString m_query; //< constructed query to pass http getter
96 QString m_path; //< constructed path to pass http getter
97 QString m_hash; //< caching hash
98 bool m_dumbCache; //< true if caching should ignore the server header
99 QHttpRequestHeader m_header;
100
101 static QDir m_globalCache; //< global cache path value
102 static QUrl m_globalProxy; //< global proxy value
103 static bool m_globalDumbCache; //< cache "dumb" mode global setting
104 static QString m_globalUserAgent; //< global user agent string
105};
106
107#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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "rbunzip.h"
21#include <QtCore>
22
23
24UnZip::ErrorCode RbUnZip::extractArchive(const QString& dest)
25{
26 QStringList files = this->fileList();
27 UnZip::ErrorCode error = Ok;
28 m_abortunzip = false;
29
30 int total = files.size();
31 for(int i = 0; i < total; i++) {
32 qDebug() << __func__ << files.at(i);
33 error = this->extractFile(files.at(i), dest, UnZip::ExtractPaths);
34 emit unzipProgress(i + 1, total);
35 QCoreApplication::processEvents(); // update UI
36 if(m_abortunzip)
37 error = SkipAll;
38 if(error != Ok)
39 break;
40 }
41 return error;
42}
43
44void RbUnZip::abortUnzip(void)
45{
46 m_abortunzip = true;
47}
48
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 * $Id$
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef RBUNZIP_H
23#define RBUNZIP_H
24
25#include <QtCore>
26#include "zip/unzip.h"
27#include "zip/zip.h"
28
29class RbUnZip : public QObject, public UnZip
30{
31 Q_OBJECT
32 public:
33 UnZip::ErrorCode extractArchive(const QString&);
34
35 signals:
36 void unzipProgress(int, int);
37
38 public slots:
39 void abortUnzip(void);
40
41 private:
42 bool m_abortunzip;
43};
44
45#endif
46
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Wenger
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "rbzip.h"
21#include <QtCore>
22
23
24Zip::ErrorCode RbZip::createZip(QString zip,QString dir)
25{
26 Zip::ErrorCode error = Ok;
27 m_curEntry = 1;
28 m_numEntrys=0;
29
30 QCoreApplication::processEvents();
31
32 // get number of entrys in dir
33 QDirIterator it(dir, QDirIterator::Subdirectories);
34 while (it.hasNext())
35 {
36 it.next();
37 m_numEntrys++;
38 QCoreApplication::processEvents();
39 }
40
41
42 //! create zip
43 error = Zip::createArchive(zip);
44 if(error != Ok)
45 return error;
46
47 //! add the content
48 error = Zip::addDirectory(dir);
49 if(error != Ok)
50 return error;
51
52 //! close zip
53 error = Zip::closeArchive();
54
55 return error;
56}
57
58void RbZip::progress()
59{
60 m_curEntry++;
61 emit zipProgress(m_curEntry,m_numEntrys);
62 QCoreApplication::processEvents(); // update UI
63}
64
65
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Wenger
10 * $Id$
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef RBZIP_H
23#define RBZIP_H
24
25#include <QtCore>
26#include "zip/zip.h"
27
28class RbZip : public QObject, public Zip
29{
30 Q_OBJECT
31 public:
32 Zip::ErrorCode createZip(QString zip,QString dir);
33
34 virtual void progress();
35
36 signals:
37 void zipProgress(int, int);
38
39 private:
40 int m_curEntry;
41 int m_numEntrys;
42};
43
44#endif
45
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "utils.h"
21#ifdef UNICODE
22#define _UNICODE
23#endif
24
25#include <QtCore>
26#include <QDebug>
27#include <cstdlib>
28#include <stdio.h>
29
30#if defined(Q_OS_WIN32)
31#include <windows.h>
32#include <tchar.h>
33#include <winioctl.h>
34#endif
35
36// recursive function to delete a dir with files
37bool recRmdir( const QString &dirName )
38{
39 QString dirN = dirName;
40 QDir dir(dirN);
41 // make list of entries in directory
42 QStringList list = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
43 QFileInfo fileInfo;
44 QString curItem, lstAt;
45 for(int i = 0; i < list.size(); i++){ // loop through all items of list
46 QString name = list.at(i);
47 curItem = dirN + "/" + name;
48 fileInfo.setFile(curItem);
49 if(fileInfo.isDir()) // is directory
50 recRmdir(curItem); // call recRmdir() recursively for deleting subdirectory
51 else // is file
52 QFile::remove(curItem); // ok, delete file
53 }
54 dir.cdUp();
55 return dir.rmdir(dirN); // delete empty dir and return if (now empty) dir-removing was successfull
56}
57
58
59//! @brief resolves the given path, ignoring case.
60//! @param path absolute path to resolve.
61//! @return returns exact casing of path, empty string if path not found.
62QString resolvePathCase(QString path)
63{
64 QStringList elems;
65 QString realpath;
66
67 elems = path.split("/", QString::SkipEmptyParts);
68 int start;
69#if defined(Q_OS_WIN32)
70 // on windows we must make sure to start with the first entry (i.e. the
71 // drive letter) instead of a single / to make resolving work.
72 start = 1;
73 realpath = elems.at(0) + "/";
74#else
75 start = 0;
76 realpath = "/";
77#endif
78
79 for(int i = start; i < elems.size(); i++) {
80 QStringList direlems
81 = QDir(realpath).entryList(QDir::AllEntries|QDir::Hidden|QDir::System);
82 if(direlems.contains(elems.at(i), Qt::CaseInsensitive)) {
83 // need to filter using QRegExp as QStringList::filter(QString)
84 // matches any substring
85 QString expr = QString("^" + elems.at(i) + "$");
86 QRegExp rx = QRegExp(expr, Qt::CaseInsensitive);
87 QStringList a = direlems.filter(rx);
88
89 if(a.size() != 1)
90 return QString("");
91 if(!realpath.endsWith("/"))
92 realpath += "/";
93 realpath += a.at(0);
94 }
95 else
96 return QString("");
97 }
98 qDebug() << __func__ << path << "->" << realpath;
99 return realpath;
100}
101
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22
23#ifndef UTILS_H
24#define UTILS_H
25
26#include <QString>
27#include <QUrl>
28
29bool recRmdir( const QString &dirName );
30QString resolvePathCase(QString path);
31
32#endif
33