diff options
Diffstat (limited to 'utils/rbutilqt/base/bootloaderinstallhex.cpp')
-rw-r--r-- | utils/rbutilqt/base/bootloaderinstallhex.cpp | 271 |
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 | |||
28 | struct md5s { | ||
29 | const char* orig; | ||
30 | const char* patched; | ||
31 | }; | ||
32 | |||
33 | struct 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 | |||
43 | BootloaderInstallHex::BootloaderInstallHex(QObject *parent) | ||
44 | : BootloaderInstallBase(parent) | ||
45 | { | ||
46 | } | ||
47 | |||
48 | QString 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 | |||
62 | bool 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 | |||
132 | void 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 | |||
235 | bool 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 | |||
244 | BootloaderInstallBase::BootloaderType BootloaderInstallHex::installed(void) | ||
245 | { | ||
246 | return BootloaderUnknown; | ||
247 | } | ||
248 | |||
249 | |||
250 | BootloaderInstallBase::Capabilities BootloaderInstallHex::capabilities(void) | ||
251 | { | ||
252 | return (Install | NeedsOf); | ||
253 | } | ||
254 | |||
255 | QString 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 | |||