summaryrefslogtreecommitdiff
path: root/utils/rbutilqt/base/bootloaderinstallhex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/base/bootloaderinstallhex.cpp')
-rw-r--r--utils/rbutilqt/base/bootloaderinstallhex.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/bootloaderinstallhex.cpp b/utils/rbutilqt/base/bootloaderinstallhex.cpp
new file mode 100644
index 0000000000..b3dde0bbfa
--- /dev/null
+++ b/utils/rbutilqt/base/bootloaderinstallhex.cpp
@@ -0,0 +1,271 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2008 by Dominik Riebeling
10 *
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.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QtCore>
20#include "bootloaderinstallbase.h"
21#include "bootloaderinstallhex.h"
22#include "utils.h"
23#include "Logger.h"
24
25#include "../../tools/iriver.h"
26#include "../../tools/mkboot.h"
27
28struct md5s {
29 const char* orig;
30 const char* patched;
31};
32
33struct md5s md5sums[] = {
34#include "irivertools/h100sums.h"
35 { nullptr, nullptr },
36#include "irivertools/h120sums.h"
37 { nullptr, nullptr },
38#include "irivertools/h300sums.h"
39 { nullptr, nullptr }
40};
41
42
43BootloaderInstallHex::BootloaderInstallHex(QObject *parent)
44 : BootloaderInstallBase(parent)
45{
46}
47
48QString BootloaderInstallHex::ofHint()
49{
50 return tr("Bootloader installation requires you to provide "
51 "a firmware file of the original firmware (hex file). "
52 "You need to download this file yourself due to legal "
53 "reasons. Please refer to the "
54 "<a href='http://www.rockbox.org/manual.shtml'>manual</a> and the "
55 "<a href='http://www.rockbox.org/wiki/IriverBoot"
56 "#Download_and_extract_a_recent_ve'>IriverBoot</a> wiki page on "
57 "how to obtain this file.<br/>"
58 "Press Ok to continue and browse your computer for the firmware "
59 "file.");
60}
61
62bool BootloaderInstallHex::install(void)
63{
64 if(m_offile.isEmpty())
65 return false;
66 m_hashindex = -1;
67
68 // md5sum hex file
69 emit logItem(tr("checking MD5 hash of input file ..."), LOGINFO);
70 QByteArray filedata;
71 // read hex file into QByteArray
72 QFile file(m_offile);
73 file.open(QIODevice::ReadOnly);
74 filedata = file.readAll();
75 file.close();
76 QString hash = QCryptographicHash::hash(filedata,
77 QCryptographicHash::Md5).toHex();
78 LOG_INFO() << "hexfile hash:" << hash;
79 if(file.error() != QFile::NoError) {
80 emit logItem(tr("Could not verify original firmware file"), LOGERROR);
81 emit done(true);
82 return false;
83 }
84 // check hash and figure model from md5sum
85 int i = sizeof(md5sums) / sizeof(struct md5s);
86 m_model = 4;
87 // 3: h300, 2: h120, 1: h100, 0:invalid
88 while(i--) {
89 if(md5sums[i].orig == nullptr)
90 m_model--;
91 if(!qstrcmp(md5sums[i].orig, hash.toLatin1()))
92 break;
93 }
94 if(i < 0) {
95 emit logItem(tr("Firmware file not recognized."), LOGERROR);
96 return false;
97 }
98 else {
99 emit logItem(tr("MD5 hash ok"), LOGOK);
100 m_hashindex = i;
101 }
102
103 // check model agains download link.
104 QString match[] = {"", "h100", "h120", "h300"};
105 if(!m_blurl.path().contains(match[m_model])) {
106 emit logItem(tr("Firmware file doesn't match selected player."),
107 LOGERROR);
108 return false;
109 }
110
111 emit logItem(tr("Descrambling file"), LOGINFO);
112 m_descrambled.open();
113 int result;
114 result = iriver_decode(m_offile.toLatin1().data(),
115 m_descrambled.fileName().toLatin1().data(), FALSE, STRIP_NONE);
116 LOG_INFO() << "iriver_decode():" << result;
117
118 if(result < 0) {
119 emit logItem(tr("Error in descramble: %1").arg(scrambleError(result)), LOGERROR);
120 return false;
121 }
122
123 // download firmware from server
124 emit logItem(tr("Downloading bootloader file"), LOGINFO);
125 connect(this, &BootloaderInstallBase::downloadDone, this, &BootloaderInstallHex::installStage2);
126
127 downloadBlStart(m_blurl);
128 return true;
129}
130
131
132void BootloaderInstallHex::installStage2(void)
133{
134 emit logItem(tr("Adding bootloader to firmware file"), LOGINFO);
135 QCoreApplication::processEvents();
136
137 // local temp file
138 QTemporaryFile tempbin;
139 tempbin.open();
140 QString tempbinName = tempbin.fileName();
141 tempbin.close();
142 // get temporary files filenames -- external tools need this.
143 m_descrambled.open();
144 QString descrambledName = m_descrambled.fileName();
145 m_descrambled.close();
146 m_tempfile.open();
147 QString tempfileName = m_tempfile.fileName();
148 m_tempfile.close();
149
150 int origin = 0;
151 switch(m_model) {
152 case 3:
153 origin = 0x3f0000;
154 break;
155 case 2:
156 case 1:
157 origin = 0x1f0000;
158 break;
159 default:
160 origin = 0;
161 break;
162 }
163
164 // iriver decode already done in stage 1
165 int result;
166 if((result = mkboot_iriver(descrambledName.toLocal8Bit().constData(),
167 tempfileName.toLocal8Bit().constData(),
168 tempbinName.toLocal8Bit().constData(), origin)) < 0)
169 {
170 QString error;
171 switch(result) {
172 case -1: error = tr("could not open input file"); break;
173 case -2: error = tr("reading header failed"); break;
174 case -3: error = tr("reading firmware failed"); break;
175 case -4: error = tr("can't open bootloader file"); break;
176 case -5: error = tr("reading bootloader file failed"); break;
177 case -6: error = tr("can't open output file"); break;
178 case -7: error = tr("writing output file failed"); break;
179 }
180 emit logItem(tr("Error in patching: %1").arg(error), LOGERROR);
181
182 emit done(true);
183 return;
184 }
185 QTemporaryFile targethex;
186 targethex.open();
187 QString targethexName = targethex.fileName();
188 if((result = iriver_encode(tempbinName.toLocal8Bit().constData(),
189 targethexName.toLocal8Bit().constData(), FALSE)) < 0)
190 {
191 emit logItem(tr("Error in scramble: %1").arg(scrambleError(result)), LOGERROR);
192 targethex.close();
193
194 emit done(true);
195 return;
196 }
197
198 // finally check the md5sum of the created file
199 QByteArray filedata;
200 filedata = targethex.readAll();
201 targethex.close();
202 QString hash = QCryptographicHash::hash(filedata,
203 QCryptographicHash::Md5).toHex();
204 LOG_INFO() << "created hexfile hash:" << hash;
205
206 emit logItem(tr("Checking modified firmware file"), LOGINFO);
207 if(hash != QString(md5sums[m_hashindex].patched)) {
208 emit logItem(tr("Error: modified file checksum wrong"), LOGERROR);
209 targethex.remove();
210 emit done(true);
211 return;
212 }
213 // finally copy file to player
214 if(!Utils::resolvePathCase(m_blfile).isEmpty()) {
215 emit logItem(tr("A firmware file is already present on player"), LOGERROR);
216 emit done(true);
217 return;
218 }
219 if(targethex.copy(m_blfile)) {
220 emit logItem(tr("Success: modified firmware file created"), LOGINFO);
221 }
222 else {
223 emit logItem(tr("Copying modified firmware file failed"), LOGERROR);
224 emit done(true);
225 return;
226 }
227
228 logInstall(LogAdd);
229 emit done(false);
230
231 return;
232}
233
234
235bool BootloaderInstallHex::uninstall(void)
236{
237 emit logItem(tr("Uninstallation not possible, only installation info removed"), LOGINFO);
238 logInstall(LogRemove);
239 emit done(true);
240 return false;
241}
242
243
244BootloaderInstallBase::BootloaderType BootloaderInstallHex::installed(void)
245{
246 return BootloaderUnknown;
247}
248
249
250BootloaderInstallBase::Capabilities BootloaderInstallHex::capabilities(void)
251{
252 return (Install | NeedsOf);
253}
254
255QString BootloaderInstallHex::scrambleError(int err)
256{
257 QString error;
258 switch(err) {
259 case -1: error = tr("Can't open input file"); break;
260 case -2: error = tr("Can't open output file"); break;
261 case -3: error = tr("invalid file: header length wrong"); break;
262 case -4: error = tr("invalid file: unrecognized header"); break;
263 case -5: error = tr("invalid file: \"length\" field wrong"); break;
264 case -6: error = tr("invalid file: \"length2\" field wrong"); break;
265 case -7: error = tr("invalid file: internal checksum error"); break;
266 case -8: error = tr("invalid file: \"length3\" field wrong"); break;
267 default: error = tr("unknown"); break;
268 }
269 return error;
270}
271