Check for existing firmware file on H100 / H300.
[maemo-rb.git] / rbutil / rbutilqt / base / bootloaderinstallhex.cpp
blob3fdfba6c8adc733fa215da900fde4bfc3a13d39a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2008 by Dominik Riebeling
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
17 ****************************************************************************/
19 #include <QtCore>
20 #include "bootloaderinstallbase.h"
21 #include "bootloaderinstallhex.h"
22 #include "utils.h"
24 #include "../../tools/iriver.h"
25 #include "../../tools/mkboot.h"
27 struct md5s {
28 const char* orig;
29 const char* patched;
32 struct 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 }
42 BootloaderInstallHex::BootloaderInstallHex(QObject *parent)
43 : BootloaderInstallBase(parent)
47 QString BootloaderInstallHex::ofHint()
49 return tr("Bootloader installation requires you to provide "
50 "a firmware file of the original firmware (hex file). "
51 "You need to download this file yourself due to legal "
52 "reasons. Please refer to the "
53 "<a href='http://www.rockbox.org/manual.shtml'>manual</a> and the "
54 "<a href='http://www.rockbox.org/wiki/IriverBoot"
55 "#Download_and_extract_a_recent_ve'>IriverBoot</a> wiki page on "
56 "how to obtain this file.<br/>"
57 "Press Ok to continue and browse your computer for the firmware "
58 "file.");
61 bool BootloaderInstallHex::install(void)
63 if(m_offile.isEmpty())
64 return false;
65 m_hashindex = -1;
67 // md5sum hex file
68 emit logItem(tr("checking MD5 hash of input file ..."), LOGINFO);
69 QByteArray filedata;
70 // read hex file into QByteArray
71 QFile file(m_offile);
72 file.open(QIODevice::ReadOnly);
73 filedata = file.readAll();
74 file.close();
75 QString hash = QCryptographicHash::hash(filedata,
76 QCryptographicHash::Md5).toHex();
77 qDebug() << "[BootloaderInstallHex] hexfile hash:" << hash;
78 if(file.error() != QFile::NoError) {
79 emit logItem(tr("Could not verify original firmware file"), LOGERROR);
80 emit done(true);
81 return false;
83 // check hash and figure model from md5sum
84 int i = sizeof(md5sums) / sizeof(struct md5s);
85 m_model = 4;
86 // 3: h300, 2: h120, 1: h100, 0:invalid
87 while(i--) {
88 if(md5sums[i].orig == 0)
89 m_model--;
90 if(!qstrcmp(md5sums[i].orig, hash.toAscii()))
91 break;
93 if(i < 0) {
94 emit logItem(tr("Firmware file not recognized."), LOGERROR);
95 return false;
97 else {
98 emit logItem(tr("MD5 hash ok"), LOGOK);
99 m_hashindex = i;
102 // check model agains download link.
103 QString match[] = {"", "h100", "h120", "h300"};
104 if(!m_blurl.path().contains(match[m_model])) {
105 emit logItem(tr("Firmware file doesn't match selected player."),
106 LOGERROR);
107 return false;
110 emit logItem(tr("Descrambling file"), LOGINFO);
111 m_descrambled.open();
112 int result;
113 result = iriver_decode(m_offile.toAscii().data(),
114 m_descrambled.fileName().toAscii().data(), FALSE, STRIP_NONE);
115 qDebug() << "[BootloaderInstallHex] iriver_decode" << result;
117 if(result < 0) {
118 emit logItem(tr("Error in descramble: %1").arg(scrambleError(result)), LOGERROR);
119 return false;
122 // download firmware from server
123 emit logItem(tr("Downloading bootloader file"), LOGINFO);
124 connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
126 downloadBlStart(m_blurl);
127 return true;
131 void BootloaderInstallHex::installStage2(void)
133 emit logItem(tr("Adding bootloader to firmware file"), LOGINFO);
134 QCoreApplication::processEvents();
136 // local temp file
137 QTemporaryFile tempbin;
138 tempbin.open();
139 QString tempbinName = tempbin.fileName();
140 tempbin.close();
141 // get temporary files filenames -- external tools need this.
142 m_descrambled.open();
143 QString descrambledName = m_descrambled.fileName();
144 m_descrambled.close();
145 m_tempfile.open();
146 QString tempfileName = m_tempfile.fileName();
147 m_tempfile.close();
149 int origin = 0;
150 switch(m_model) {
151 case 3:
152 origin = 0x3f0000;
153 break;
154 case 2:
155 case 1:
156 origin = 0x1f0000;
157 break;
158 default:
159 origin = 0;
160 break;
163 // iriver decode already done in stage 1
164 int result;
165 if((result = mkboot_iriver(descrambledName.toLocal8Bit().constData(),
166 tempfileName.toLocal8Bit().constData(),
167 tempbinName.toLocal8Bit().constData(), origin)) < 0)
169 QString error;
170 switch(result) {
171 case -1: error = tr("could not open input file"); break;
172 case -2: error = tr("reading header failed"); break;
173 case -3: error = tr("reading firmware failed"); break;
174 case -4: error = tr("can't open bootloader file"); break;
175 case -5: error = tr("reading bootloader file failed"); break;
176 case -6: error = tr("can't open output file"); break;
177 case -7: error = tr("writing output file failed"); break;
179 emit logItem(tr("Error in patching: %1").arg(error), LOGERROR);
181 emit done(true);
182 return;
184 QTemporaryFile targethex;
185 targethex.open();
186 QString targethexName = targethex.fileName();
187 if((result = iriver_encode(tempbinName.toLocal8Bit().constData(),
188 targethexName.toLocal8Bit().constData(), FALSE)) < 0)
190 emit logItem(tr("Error in scramble: %1").arg(scrambleError(result)), LOGERROR);
191 targethex.close();
193 emit done(true);
194 return;
197 // finally check the md5sum of the created file
198 QByteArray filedata;
199 filedata = targethex.readAll();
200 targethex.close();
201 QString hash = QCryptographicHash::hash(filedata,
202 QCryptographicHash::Md5).toHex();
203 qDebug() << "[BootloaderInstallHex] created hexfile hash:" << hash;
205 emit logItem(tr("Checking modified firmware file"), LOGINFO);
206 if(hash != QString(md5sums[m_hashindex].patched)) {
207 emit logItem(tr("Error: modified file checksum wrong"), LOGERROR);
208 targethex.remove();
209 emit done(true);
210 return;
212 // finally copy file to player
213 if(!Utils::resolvePathCase(m_blfile).isEmpty()) {
214 emit logItem(tr("A firmware file is already present on player"), LOGERROR);
215 emit done(true);
216 return;
218 if(targethex.copy(m_blfile)) {
219 emit logItem(tr("Success: modified firmware file created"), LOGINFO);
221 else {
222 emit logItem(tr("Copying modified firmware file failed"), LOGERROR);
223 emit done(true);
224 return;
227 logInstall(LogAdd);
228 emit done(false);
230 return;
234 bool BootloaderInstallHex::uninstall(void)
236 emit logItem(tr("Uninstallation not possible, only installation info removed"), LOGINFO);
237 logInstall(LogRemove);
238 return false;
242 BootloaderInstallBase::BootloaderType BootloaderInstallHex::installed(void)
244 return BootloaderUnknown;
248 BootloaderInstallBase::Capabilities BootloaderInstallHex::capabilities(void)
250 return (Install | NeedsOf);
253 QString BootloaderInstallHex::scrambleError(int err)
255 QString error;
256 switch(err) {
257 case -1: error = tr("Can't open input file"); break;
258 case -2: error = tr("Can't open output file"); break;
259 case -3: error = tr("invalid file: header length wrong"); break;
260 case -4: error = tr("invalid file: unrecognized header"); break;
261 case -5: error = tr("invalid file: \"length\" field wrong"); break;
262 case -6: error = tr("invalid file: \"length2\" field wrong"); break;
263 case -7: error = tr("invalid file: internal checksum error"); break;
264 case -8: error = tr("invalid file: \"length3\" field wrong"); break;
265 default: error = tr("unknown"); break;
267 return error;