summaryrefslogtreecommitdiff
path: root/utils/zenutils/source/shared/firmware.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/zenutils/source/shared/firmware.cpp')
-rwxr-xr-xutils/zenutils/source/shared/firmware.cpp387
1 files changed, 387 insertions, 0 deletions
diff --git a/utils/zenutils/source/shared/firmware.cpp b/utils/zenutils/source/shared/firmware.cpp
new file mode 100755
index 0000000000..7767b55d8f
--- /dev/null
+++ b/utils/zenutils/source/shared/firmware.cpp
@@ -0,0 +1,387 @@
1/* zenutils - Utilities for working with creative firmwares.
2 * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include "firmware.h"
20#include <iostream>
21#include <stdexcept>
22
23
24zen::firmware_entry::firmware_entry(bool big_endian)
25 : _big_endian(big_endian)
26{
27}
28
29zen::firmware_entry::firmware_entry(const firmware_entry& copy)
30{
31 assign(copy);
32}
33
34zen::firmware_entry& zen::firmware_entry::operator=(const firmware_entry& right)
35{
36 assign(right);
37 return *this;
38}
39
40
41bool zen::firmware_entry::read(std::istream& is)
42{
43 // Read the header.
44 is.read((char*)&_header, sizeof(firmware_header_t));
45 if (!is.good())
46 return false;
47
48 // If the firmware is big-endian, swap the header values to little-endian.
49 if (_big_endian)
50 {
51 _header.tag = shared::swap(_header.tag);
52 if (_header.tag != 'NULL')
53 {
54 _header.size = shared::swap(_header.size);
55 }
56 }
57
58 // Resize the bytes buffer to the size specified in the header.
59 _bytes.resize(_header.size);
60
61 // Read the entry contents.
62 is.read(reinterpret_cast<char*>(&_bytes[0]),
63 _header.size);
64
65 return is.good();
66}
67
68bool zen::firmware_entry::write(std::ostream& os) const
69{
70 // Form a header using the current size of the bytes buffer.
71 firmware_header_t header = {
72 _header.tag,
73 static_cast<dword>(_bytes.size())
74 };
75
76 // If the firmware is big-endian, swap the header values back into big-endian.
77 if (_big_endian)
78 {
79 if (header.tag != 'NULL')
80 {
81 header.size = shared::swap(header.size);
82 }
83 header.tag = shared::swap(header.tag);
84 }
85
86 // Write the header.
87 os.write((const char*)&header, sizeof(firmware_header_t));
88 if (!os.good())
89 return false;
90
91 // Write the entry contents.
92 os.write(reinterpret_cast<const char*>(&_bytes[0]),
93 static_cast<std::streamsize>(_bytes.size()));
94
95 return os.good();
96}
97
98
99bool zen::firmware_entry::is_big_endian() const
100{
101 return _big_endian;
102}
103
104const zen::firmware_header_t& zen::firmware_entry::get_header() const
105{
106 return _header;
107}
108zen::firmware_header_t& zen::firmware_entry::get_header()
109{
110 return _header;
111}
112
113const shared::bytes& zen::firmware_entry::get_bytes() const
114{
115 return _bytes;
116}
117shared::bytes& zen::firmware_entry::get_bytes()
118{
119 return _bytes;
120}
121
122
123std::string zen::firmware_entry::get_name() const
124{
125 char name[5];
126 *(dword*)name = shared::swap(_header.tag);
127 name[4] = '\0';
128
129 // Determine if all characters in the tag are printable.
130 bool isprintable = true;
131 for (int i = 0; i < 4; i++)
132 {
133 if (!isprint((byte)name[i]))
134 {
135 isprintable = false;
136 break;
137 }
138 }
139
140 // If they are, simply return the tag as a string.
141 if (isprintable)
142 {
143 return std::string(name);
144 }
145
146 // Otherwise, encode the tag into a hexadecimal string.
147 char buffer[11];
148 sprintf(buffer, "0x%08x", _header.tag);
149 return std::string(buffer);
150}
151
152std::string zen::firmware_entry::get_content_name() const
153{
154 std::string name = get_name();
155 if (name == "DATA")
156 {
157 name = "";
158 int nameoff = is_big_endian() ? 1 : 0;
159 for (int i = 0; i < 16; i++)
160 {
161 char c = get_bytes()[i * 2 + nameoff];
162 if (!c)
163 break;
164 name += c;
165 }
166 }
167 else if (name == "EXT0")
168 {
169 name = "";
170 int nameoff = is_big_endian() ? 1 : 0;
171 for (int i = 0; i < 12; i++)
172 {
173 char c = get_bytes()[i * 2 + nameoff];
174 if (!c)
175 break;
176 name += c;
177 }
178 }
179 return name;
180}
181
182size_t zen::firmware_entry::get_content_offset() const
183{
184 std::string name = get_name();
185 if (name == "DATA")
186 {
187 return 32;
188 }
189 else if (name == "EXT0")
190 {
191 return 24;
192 }
193 return 0;
194}
195
196size_t zen::firmware_entry::calc_size() const
197{
198 return _bytes.size() + sizeof(firmware_header_t);
199}
200
201
202void zen::firmware_entry::assign(const firmware_entry& copy)
203{
204 _big_endian = copy._big_endian;
205 _header.tag = copy._header.tag;
206 _header.size = copy._header.size;
207 _bytes.assign(copy._bytes.begin(), copy._bytes.end());
208}
209
210
211
212zen::firmware_archive::firmware_archive(bool big_endian)
213 : _big_endian(big_endian)
214{
215}
216
217zen::firmware_archive::firmware_archive(const firmware_archive& copy)
218{
219 assign(copy);
220}
221
222zen::firmware_archive& zen::firmware_archive::operator=(const firmware_archive& right)
223{
224 assign(right);
225 return *this;
226}
227
228
229bool zen::firmware_archive::read(std::istream& is)
230{
231 // Read the root entry's header.
232 firmware_header_t root;
233 is.read((char*)&root, sizeof(firmware_header_t));
234 if (!is.good())
235 return false;
236
237 if ((root.tag != 'CIFF') && (root.tag != 'FFIC'))
238 {
239 throw std::runtime_error("Invalid firmware archive format!");
240 }
241
242 _big_endian = root.tag == 'FFIC' ? true : false;
243 if (_big_endian)
244 {
245 root.tag = shared::swap(root.tag);
246 root.size = shared::swap(root.size);
247 }
248
249 // Save the current stream position.
250 std::istream::pos_type endpos = is.tellg();
251 std::istream::pos_type curpos = endpos;
252 endpos += std::istream::pos_type(root.size);
253
254 // Read untill the end of the root entry contents.
255 while (curpos < endpos)
256 {
257 firmware_entry entry(_big_endian);
258 if (!entry.read(is))
259 return false;
260
261 _children.push_back(entry);
262 curpos = is.tellg();
263 }
264
265 curpos = is.tellg();
266 is.seekg(0, std::ios::end);
267 endpos = is.tellg();
268 is.seekg(curpos);
269
270 // Read untill the end of the file.
271 while (((size_t)curpos + sizeof(firmware_header_t)) < endpos)
272 {
273 firmware_entry entry(_big_endian);
274 if (!entry.read(is))
275 return false;
276
277 _neighbours.push_back(entry);
278 curpos = is.tellg();
279 }
280
281 return true;
282}
283
284bool zen::firmware_archive::write(std::ostream& os) const
285{
286 // Read the root entry's header.
287 firmware_header_t root = {'CIFF', 0};
288
289 // Calculate the total size of all the children entries.
290 for (firmware_entries::const_iterator i = _children.begin();
291 i != _children.end(); ++i)
292 {
293 root.size += i->calc_size();
294 }
295
296 // If the firmware is big-endian, swap the header values back into big-endian.
297 if (_big_endian)
298 {
299 root.tag = shared::swap(root.tag);
300 root.size = shared::swap(root.size);
301 }
302
303 // Write the header.
304 os.write((const char*)&root, sizeof(firmware_header_t));
305 if (!os.good())
306 return false;
307
308 // Write all the child entries.
309 for (firmware_entries::const_iterator i = _children.begin();
310 i != _children.end(); ++i)
311 {
312 if (!i->write(os))
313 return false;
314 }
315
316 // Write all the neighbour entries.
317 for (firmware_entries::const_iterator i = _neighbours.begin();
318 i != _neighbours.end(); ++i)
319 {
320 if (!i->write(os))
321 return false;
322 }
323
324 return true;
325}
326
327
328bool zen::firmware_archive::is_big_endian() const
329{
330 return _big_endian;
331}
332
333const zen::firmware_entries& zen::firmware_archive::get_children() const
334{
335 return _children;
336}
337zen::firmware_entries& zen::firmware_archive::get_children()
338{
339 return _children;
340}
341
342const zen::firmware_entries& zen::firmware_archive::get_neighbours() const
343{
344 return _neighbours;
345}
346zen::firmware_entries& zen::firmware_archive::get_neighbours()
347{
348 return _neighbours;
349}
350
351bool zen::firmware_archive::is_signed() const
352{
353 for (firmware_entries::const_iterator i = _neighbours.begin();
354 i != _neighbours.end(); i++)
355 {
356 if (i->get_name() == "NULL")
357 return true;
358 }
359 return false;
360}
361
362size_t zen::firmware_archive::calc_size() const
363{
364 size_t size = sizeof(firmware_header_t);
365
366 for (firmware_entries::const_iterator i = _children.begin();
367 i != _children.end(); i++)
368 {
369 size += i->calc_size();
370 }
371
372 for (firmware_entries::const_iterator i = _neighbours.begin();
373 i != _neighbours.end(); i++)
374 {
375 size += i->calc_size();
376 }
377
378 return size;
379}
380
381
382void zen::firmware_archive::assign(const firmware_archive& copy)
383{
384 _big_endian = copy._big_endian;
385 _children.assign(copy._children.begin(), copy._children.end());
386 _neighbours.assign(copy._neighbours.begin(), copy._neighbours.end());
387}