summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2015-03-23 21:30:06 +0100
committerGerrit Rockbox <gerrit@rockbox.org>2015-03-29 14:08:28 +0200
commitb130b507349952cbab2a371628891de78cc8dda2 (patch)
treec2cc360f4fc8b14f704e93f89783ad7c31c2e67a
parent32154bfc0be5fa57ddc5f70c51c4162f4dceb0e8 (diff)
downloadrockbox-b130b507349952cbab2a371628891de78cc8dda2.tar.gz
rockbox-b130b507349952cbab2a371628891de78cc8dda2.zip
Add jz4760 tool
This tool can pack/unpack a jz4760 archive (like the one used for the fiio x1/x3/x5), and can descramble/scramble (it's the same operation) a firmware file (the sys.bin file in the archive). I did my best to keep the compatibility with the leaked Fiio/Ingenic tool which has the same name. I wrote the tools from scratch, but here are some remarks: - the format used is a slightly modified IHFS used in the older JZ4640 series, I used the information on the wiki about the IHFS format - the CRC computation done was already reversed engineered by someone on the forums but I realised this later - There are a few unknown fields in the headers, see comments in the source code - The firmware scrambling was discovered by pure guess, I realised there were some repetitve sequences, some I guessed it was a rotative XOR and ran some analysis to find the most probable sequence Change-Id: Ib83735b3db8475be5de9c94231714e88668a0340
-rw-r--r--utils/jz4760_tools/Makefile21
-rw-r--r--utils/jz4760_tools/packtools.cpp563
2 files changed, 584 insertions, 0 deletions
diff --git a/utils/jz4760_tools/Makefile b/utils/jz4760_tools/Makefile
new file mode 100644
index 0000000000..847539e38c
--- /dev/null
+++ b/utils/jz4760_tools/Makefile
@@ -0,0 +1,21 @@
1DEFINES=
2CC?=gcc
3CXX?=g++
4LD?=g++
5CFLAGS=-g -std=c99 -Wall $(DEFINES) -Ilib
6CXXFLAGS=-g -Wall $(DEFINES)
7LDFLAGS=
8SRC=$(wildcard *.c)
9SRCXX=$(wildcard *.cpp)
10EXEC=$(SRC:.c=) $(SRCXX:.cpp=)
11
12all: $(EXEC)
13
14%: %.c
15 $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
16
17%: %.cpp
18 $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS)
19
20clean:
21 rm -fr $(EXEC)
diff --git a/utils/jz4760_tools/packtools.cpp b/utils/jz4760_tools/packtools.cpp
new file mode 100644
index 0000000000..6bd5ec0330
--- /dev/null
+++ b/utils/jz4760_tools/packtools.cpp
@@ -0,0 +1,563 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2015 by Amaury Pouly
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#include <cstdio>
23#include <cstring>
24#include <cstdlib>
25#include <stdint.h>
26#include <fstream>
27#include <sys/stat.h>
28#include <getopt.h>
29#include <sys/types.h>
30#include <dirent.h>
31#include <unistd.h>
32#include <vector>
33#include <string>
34#include <algorithm>
35#include <ctime>
36#include <sstream>
37
38struct jz4760_fw_hdr_t
39{
40 uint32_t magic;
41 uint32_t fs_size; // unsure, always 0x7f00000
42 uint32_t hdr_size; // header size in sectors, always 4
43 uint32_t pad;
44 char datetime[12]; // format: yyyymmddhhmm
45 uint32_t nr_files;
46 uint32_t unk; // always 2, seems related to CRC, maybe CRC mode
47 uint32_t pad2[3];
48 uint8_t machine[8];
49 uint8_t pad3[452];
50 uint32_t eoh; // end of header
51} __attribute__((packed));
52
53const uint32_t JZ4760_FW_MAGIC = 0x49484653; // 'IHFS'
54const uint32_t JZ4760_FW_EOH = 0x55aa55aa; // end of header
55
56struct jz4760_fw_file_t
57{
58 char name[56];
59 uint32_t offset; // absolute offset in sectors
60 uint32_t size; // in bytes
61} __attribute__((packed));
62
63const uint32_t jz4760_crc_key[256] =
64{
65 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
66 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
67 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
68 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
69 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
70 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
71 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
72 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
73 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
74 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
75 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
76 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
77 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
78 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
79 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
80 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
81 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
82 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
83 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
84 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
85 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
86 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
87 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
88 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
89 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
90 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
91 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
92 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
93 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
94 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
95 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
96 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
97};
98
99const unsigned JZ4760_XOR_KEY_SIZE = 344;
100uint8_t jz4760_xor_key[JZ4760_XOR_KEY_SIZE] =
101{
102 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
103 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
104 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
105 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83,
106 0x89, 0x8b, 0x95, 0x97, 0x9d, 0xa3, 0xa7, 0xad,
107 0xb3, 0xb5, 0xbf, 0xc1, 0xc5, 0xc7, 0xd3, 0xdf,
108 0xe3, 0xe5, 0xe9, 0xef, 0xf1, 0xfb, 0x01, 0x07,
109 0x0d, 0x0f, 0x15, 0x19, 0x1b, 0x25, 0x33, 0x37,
110 0x39, 0x3d, 0x4b, 0x51, 0x5b, 0x5d, 0x61, 0x67,
111 0x6f, 0x75, 0x7b, 0x7f, 0x85, 0x8d, 0x91, 0x99,
112 0xa3, 0xa5, 0xaf, 0xb1, 0xb7, 0xbb, 0xc1, 0xc9,
113 0xcd, 0xcf, 0xd3, 0xdf, 0xe7, 0xeb, 0xf3, 0xf7,
114 0xfd, 0x09, 0x0b, 0x1d, 0x23, 0x2d, 0x33, 0x39,
115 0x3b, 0x41, 0x4b, 0x51, 0x57, 0x59, 0x5f, 0x65,
116 0x69, 0x6b, 0x77, 0x81, 0x83, 0x87, 0x8d, 0x93,
117 0x95, 0xa1, 0xa5, 0xab, 0xb3, 0xbd, 0xc5, 0xcf,
118 0xd7, 0xdd, 0xe3, 0xe7, 0xef, 0xf5, 0xf9, 0x01,
119 0x05, 0x13, 0x1d, 0x29, 0x2b, 0x35, 0x37, 0x3b,
120 0x3d, 0x47, 0x55, 0x59, 0x5b, 0x5f, 0x6d, 0x71,
121 0x73, 0x77, 0x8b, 0x8f, 0x97, 0xa1, 0xa9, 0xad,
122 0xb3, 0xb9, 0xc7, 0xcb, 0xd1, 0xd7, 0xdf, 0xe5,
123 0xf1, 0xf5, 0xfb, 0xfd, 0x02, 0x03, 0x05, 0x07,
124 0x0b, 0x0d, 0x11, 0x13, 0x17, 0x1d, 0x1f, 0x25,
125 0x29, 0x2b, 0x2f, 0x35, 0x3b, 0x3d, 0x43, 0x47,
126 0x49, 0x4f, 0x53, 0x59, 0x61, 0x65, 0x67, 0x6b,
127 0x6d, 0x71, 0x7f, 0x83, 0x89, 0x8b, 0x95, 0x97,
128 0x9d, 0xa3, 0xa7, 0xad, 0xb3, 0xb5, 0xbf, 0xc1,
129 0xc5, 0xc7, 0xd3, 0xdf, 0xe3, 0xe5, 0xe9, 0xef,
130 0xf1, 0xfb, 0x01, 0x07, 0x0d, 0x0f, 0x15, 0x19,
131 0x1b, 0x25, 0x33, 0x37, 0x39, 0x3d, 0x4b, 0x51,
132 0x5b, 0x5d, 0x61, 0x67, 0x6f, 0x75, 0x7b, 0x7f,
133 0x85, 0x8d, 0x91, 0x99, 0xa3, 0xa5, 0xaf, 0xb1,
134 0xb7, 0xbb, 0xc1, 0xc9, 0xcd, 0xcf, 0xd3, 0xdf,
135 0xe7, 0xeb, 0xf3, 0xf7, 0xfd, 0x09, 0x0b, 0x1d,
136 0x23, 0x2d, 0x33, 0x39, 0x3b, 0x41, 0x4b, 0x51,
137 0x57, 0x59, 0x5f, 0x65, 0x69, 0x6b, 0x77, 0x81,
138 0x83, 0x87, 0x8d, 0x93, 0x95, 0xa1, 0xa5, 0xab,
139 0xb3, 0xbd, 0xc5, 0xcf, 0xd7, 0xdd, 0xe3, 0xe7,
140 0xef, 0xf5, 0xf9, 0x01, 0x05, 0x13, 0x1d, 0x29,
141 0x2b, 0x35, 0x37, 0x3b, 0x3d, 0x47, 0x55, 0x59,
142 0x5b, 0x5f, 0x6d, 0x71, 0x73, 0x77, 0x8b, 0x8f,
143 0x97, 0xa1, 0xa9, 0xad, 0xb3, 0xb9, 0xc7, 0xcb,
144 0xd1, 0xd7, 0xdf, 0xe5, 0xf1, 0xf5, 0xfb, 0xfd,
145};
146
147bool g_verbose = false;
148
149uint8_t *read_file(const std::string& path, size_t& size)
150{
151 std::ifstream fin(path.c_str(), std::ios::binary);
152 if(!fin)
153 {
154 printf("Error: cannot open '%s'\n", path.c_str());
155 return 0;
156 }
157 fin.seekg(0, std::ios::end);
158 size = fin.tellg();
159 fin.seekg(0, std::ios::beg);
160 uint8_t *buf = new uint8_t[size];
161 fin.read((char *)buf, size);
162 return buf;
163}
164
165bool write_file(const std::string& path, uint8_t *buf, size_t size)
166{
167 std::ofstream fout(path.c_str(), std::ios::binary);
168 if(!fout)
169 {
170 printf("Error: cannot open '%s'\n", path.c_str());
171 return false;
172 }
173 fout.write((char *)buf, size);
174 fout.close();
175 return true;
176}
177
178bool create_dir(const std::string& dir)
179{
180 mkdir(dir.c_str(), 0755);
181 return true;
182}
183
184// the firmware uses '\' as separator
185bool create_file(std::string path, uint8_t *buf, size_t size)
186{
187 size_t pos = -1;
188 while((pos = path.find_first_of("/\\", pos + 1)) != std::string::npos)
189 {
190 path[pos] = '/';
191 create_dir(path.substr(0, pos));
192 }
193 return write_file(path, buf, size);
194}
195
196bool list_files(const std::string& prefix, const std::string& path,
197 std::vector< std::string >& list)
198{
199 DIR *dir = opendir((prefix + "/" + path).c_str());
200 if(!dir)
201 {
202 printf("Error: cannot open directory '%s'\n", path.c_str());
203 goto Lerr;
204 }
205 struct dirent *entry;
206 while((entry = readdir(dir)))
207 {
208 std::string p = entry->d_name;
209 if(p == "." || p == "..")
210 continue;
211 std::string subname = prefix + "/" + path + "/" + entry->d_name;
212 struct stat st;
213 if(lstat(subname.c_str(), &st) != 0)
214 {
215 printf("Error: cannot stat '%s'\n", subname.c_str());
216 goto Lerr;
217 }
218 if(!path.empty())
219 p = path + "/" + p;
220 if(st.st_mode & S_IFREG)
221 list.push_back(p);
222 if(st.st_mode & S_IFDIR)
223 {
224 if(!list_files(prefix, p, list))
225 goto Lerr;
226 }
227 }
228 closedir(dir);
229 return true;
230Lerr:
231 closedir(dir);
232 return false;
233}
234
235std::vector< std::string > list_files(const std::string& path, bool& ok)
236{
237 std::vector< std::string > list;
238 ok = list_files(path, "", list);
239 return list;
240}
241
242uint32_t jz4760_crc(uint32_t crc, uint8_t *buf, size_t size)
243{
244 while(size--)
245 crc = jz4760_crc_key[*buf++ ^ ((crc & 0xff00) >> 8)] ^ (crc << 8);
246 return crc;
247}
248
249int unpack(int argc, char **argv)
250{
251 std::string input_file;
252 std::string output_dir;
253 while(1)
254 {
255 int c = getopt(argc, argv, "i:o:v");
256 if(c == -1)
257 break;
258 switch(c)
259 {
260 case 'v':
261 g_verbose = true;
262 break;
263 case 'i':
264 input_file = optarg;
265 break;
266 case 'o':
267 output_dir = optarg;
268 break;
269 default:
270 abort();
271 }
272 }
273 if(optind != argc)
274 return printf("Error: extra arguments on command line\n");
275 if(input_file.empty())
276 return printf("Error: you need to specify the input file\n");
277 if(output_dir.empty())
278 printf("Warning: you did not specify an output directory, this will be a dry run\n");
279 size_t fw_size;
280 uint8_t *fw_buf = read_file(input_file, fw_size);
281 if(!fw_buf)
282 return 1;
283 /* firmware has N blocks of 512 plus a 4 byte checksum at the end
284 * each file must have at least 4 sectors for the header and 256 for the entries
285 * for a total of 260 */
286 if(fw_size < 512 * 260)
287 return printf("Error: firmware is too small\n");
288 if((fw_size - 4) % 512)
289 return printf("Error: firmware has bad size\n");
290 struct jz4760_fw_hdr_t *fw_hdr = (struct jz4760_fw_hdr_t *)fw_buf;
291 if(fw_hdr->magic != JZ4760_FW_MAGIC)
292 return printf("Error: firmware has wrong magic value\n");
293 if(fw_hdr->eoh != JZ4760_FW_EOH)
294 return printf("Error: firmware has wrong end of header value\n");
295 if(g_verbose)
296 {
297 printf("Header:\n");
298 printf(" Magic: %#x\n", fw_hdr->magic);
299 printf(" FS Size: %#x\n", fw_hdr->fs_size);
300 printf(" Header Size: %d\n", fw_hdr->hdr_size);
301 printf(" Date: %c%c/%c%c/%c%c%c%c\n", fw_hdr->datetime[6],
302 fw_hdr->datetime[7], fw_hdr->datetime[4], fw_hdr->datetime[5],
303 fw_hdr->datetime[0], fw_hdr->datetime[1], fw_hdr->datetime[2],
304 fw_hdr->datetime[3]);
305 printf(" Time: %c%c:%c%c\n", fw_hdr->datetime[8],
306 fw_hdr->datetime[9], fw_hdr->datetime[10], fw_hdr->datetime[11]);
307 printf(" Files: %u\n", fw_hdr->nr_files);
308 printf(" Unknown: %x\n", fw_hdr->unk);
309 printf(" Machine: %.8s\n", fw_hdr->machine);
310 }
311 uint32_t crc = *reinterpret_cast< uint32_t* >(fw_buf + fw_size - 4);
312 if(crc != jz4760_crc(0, fw_buf, fw_size - 4))
313 return printf("Error: CRC does not match\n");
314 // check number of files
315 if(fw_hdr->nr_files > 2048)
316 return printf("Error: too many files\n");
317 struct jz4760_fw_file_t *fw_file = (struct jz4760_fw_file_t *)(fw_buf + 4 * 512);
318 for(unsigned i = 0; i < fw_hdr->nr_files; i++)
319 {
320 if(g_verbose)
321 {
322 printf("File #%d:\n", i);
323 printf(" Name: %s\n", fw_file[i].name);
324 printf(" Offset: %#x\n", fw_file[i].offset);
325 printf(" Size: %u\n", fw_file[i].size);
326 }
327 if(output_dir.empty())
328 continue;
329 create_file(output_dir + "/" + std::string(fw_file[i].name, sizeof(fw_file[i].name)),
330 fw_buf + 512 * fw_file[i].offset, fw_file[i].size);
331 }
332 return 0;
333}
334
335bool parse_time(const std::string& time, std::tm& tm)
336{
337 std::istringstream iss(time);
338 iss >> tm.tm_mday;
339 if(iss.get() != '/')
340 goto Lwarn;
341 iss >> tm.tm_mon;
342 if(iss.get() != '/')
343 goto Lwarn;
344 iss >> tm.tm_year;
345 iss >> tm.tm_hour;
346 if(iss.get() != ':')
347 goto Lwarn;
348 iss >> tm.tm_min;
349 return true;
350Lwarn:
351 printf("Error: wrong time format\n");
352 return false;
353}
354
355bool istrcmp(const std::string& a, const std::string& b)
356{
357 return strcasecmp(a.c_str(), b.c_str()) < 0;
358}
359
360int pack(int argc, char **argv)
361{
362 std::string input_dir;
363 std::string output_file;
364 std::string machine;
365 std::string datetime;
366 while(1)
367 {
368 int c = getopt(argc, argv, "i:o:m:vt:");
369 if(c == -1)
370 break;
371 switch(c)
372 {
373 case 'v':
374 g_verbose = true;
375 break;
376 case 'i':
377 input_dir = optarg;
378 break;
379 case 'o':
380 output_file = optarg;
381 break;
382 case 'm':
383 machine = optarg;
384 break;
385 case 't':
386 datetime = optarg;
387 break;
388 default:
389 abort();
390 }
391 }
392 if(optind != argc)
393 return printf("Error: extra arguments on command line\n");
394 if(input_dir.empty())
395 return printf("Error: you need to specify the input file\n");
396 if(machine.empty())
397 printf("Warning: you did not specify the machine flags, the produce file may be invalid\n");
398 if(output_file.empty())
399 return printf("Error: you must specify an output file\n");
400 bool ok = true;
401 std::vector< std::string > list = list_files(input_dir, ok);
402 if(!ok)
403 return printf("Error: there were some errors while listing files\n");
404 /* NOTE: keep compatibility with original packtools which sorts files,
405 * I doubt the sorted order is really necessary but not costly anyway */
406 std::sort(list.begin(), list.end(), istrcmp);
407 if(g_verbose)
408 {
409 for(size_t i = 0; i < list.size(); i++)
410 printf("%s\n", list[i].c_str());
411 }
412 if(list.size() > 2048)
413 return printf("Error: cannot make an archive with more than 2048 files\n");
414 struct jz4760_fw_hdr_t hdr;
415 memset(&hdr, 0, sizeof(hdr));
416 hdr.magic = JZ4760_FW_MAGIC;
417 hdr.fs_size = 0x7f00000;
418 hdr.hdr_size = 4;
419 std::time_t time = std::time(0);
420 std::tm *tm = localtime(&time);
421 if(!datetime.empty())
422 if(!parse_time(datetime, *tm))
423 return 1;
424 char str[13];
425 snprintf(str, sizeof(str), "%04d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon,
426 tm->tm_mday, tm->tm_hour, tm->tm_min);
427 memcpy(hdr.datetime, str, sizeof(hdr.datetime));
428 hdr.unk = 2;
429 hdr.nr_files = list.size();
430 memcpy(hdr.machine, machine.c_str(), sizeof(hdr.machine));
431 hdr.eoh = JZ4760_FW_EOH;
432 uint32_t crc = jz4760_crc(0, (uint8_t *)&hdr, sizeof(hdr));
433
434 std::ofstream fout(output_file.c_str(), std::ios::binary);
435 fout.write((char *)&hdr, sizeof(hdr));
436 // three empty sectors
437 uint8_t zero_sector[512];
438 memset(zero_sector, 0, sizeof(zero_sector));
439 crc = jz4760_crc(crc, zero_sector, sizeof(zero_sector));
440 fout.write((char *)zero_sector, sizeof(zero_sector));
441 crc = jz4760_crc(crc, zero_sector, sizeof(zero_sector));
442 fout.write((char *)zero_sector, sizeof(zero_sector));
443 crc = jz4760_crc(crc, zero_sector, sizeof(zero_sector));
444 fout.write((char *)zero_sector, sizeof(zero_sector));
445 // write file headers
446 size_t tot_size = 260; // 4 for headers, 256 for file headers
447 for(size_t i = 0; i < list.size(); i++)
448 {
449 jz4760_fw_file_t file;
450 memset(&file, 0, sizeof(file));
451 std::string name = list[i];
452 for(size_t j = 0; j < name.size(); j++)
453 if(name[j] == '/')
454 name[j] = '\\';
455 if(name.size() > sizeof(file.name))
456 return printf("Error: filename '%s' is too long\n", name.c_str());
457 memcpy(file.name, name.c_str(), name.size());
458 struct stat st;
459 if(lstat((input_dir + "/" + list[i]).c_str(), &st))
460 return printf("Error: cannot stat file '%s'\n", list[i].c_str());
461 file.size = st.st_size;
462 file.offset = tot_size;
463 tot_size += (file.size + 511) / 512;
464 crc = jz4760_crc(crc, (uint8_t *)&file, sizeof(file));
465 fout.write((char *)&file, sizeof(file));
466 }
467 // finish writing the 256 sectors
468 for(size_t i = list.size(); i < 2048; i++)
469 {
470 crc = jz4760_crc(crc, zero_sector, sizeof(jz4760_fw_file_t));
471 fout.write((char *)zero_sector, sizeof(jz4760_fw_file_t));
472 }
473 // write the files
474 for(size_t i = 0; i < list.size(); i++)
475 {
476 size_t sz;
477 uint8_t *data = read_file(input_dir + "/" + list[i], sz);
478 if(!data)
479 return printf("Error: cannot read file '%s'\n", list[i].c_str());
480 crc = jz4760_crc(crc, data, sz);
481 fout.write((char *)data, sz);
482 delete data;
483 if(sz % 512)
484 {
485 crc = jz4760_crc(crc, zero_sector, 512 - (sz % 512));
486 fout.write((char *)zero_sector, 512 - (sz % 512));
487 }
488 }
489 // write the crc
490 fout.write((char *)&crc, sizeof(crc));
491 fout.close();
492 return 0;
493}
494
495int descramble(int argc, char **argv)
496{
497 std::string input_file;
498 std::string output_file;
499 while(1)
500 {
501 int c = getopt(argc, argv, "i:o:");
502 if(c == -1)
503 break;
504 switch(c)
505 {
506 case 'i':
507 input_file = optarg;
508 break;
509 case 'o':
510 output_file = optarg;
511 break;
512 default:
513 abort();
514 }
515 }
516 if(optind != argc)
517 return printf("Error: extra arguments on command line\n");
518 if(input_file.empty() || output_file.empty())
519 return printf("Error: you need to specify the input and output files\n");
520 size_t fw_size;
521 uint8_t *fw_buf = read_file(input_file, fw_size);
522 if(!fw_buf)
523 return 1;
524 for(size_t i = 0; i < fw_size; i++)
525 fw_buf[i] ^= jz4760_xor_key[i % JZ4760_XOR_KEY_SIZE];
526 if(!write_file(output_file, fw_buf, fw_size))
527 return 1;
528 return 0;
529}
530
531void usage()
532{
533 printf("usage: [--pack|--unpack|--descramble] <options>\n");
534 printf(" unpack options:\n");
535 printf(" -i <file> Input file\n");
536 printf(" -o <dir> Output directory\n");
537 printf(" -v Verbose output\n");
538 printf(" pack options:\n");
539 printf(" -i <dir> Input directory\n");
540 printf(" -o <file> Output file\n");
541 printf(" -m <mach> Machine flags\n");
542 printf(" -v Verbose output\n");
543 printf(" -t <time> Override date/time (dd/mm/yy hh:mm)\n");
544 printf(" descramble options:\n");
545 printf(" -i <file> Input file\n");
546 printf(" -o <file> Output file\n");
547 exit(1);
548}
549
550int main(int argc, char **argv)
551{
552 if(argc <= 1)
553 usage();
554 if(strcmp(argv[1], "--unpack") == 0)
555 return unpack(argc - 1, argv + 1);
556 if(strcmp(argv[1], "--pack") == 0)
557 return pack(argc - 1, argv + 1);
558 if(strcmp(argv[1], "--descramble") == 0)
559 return descramble(argc - 1, argv + 1);
560 usage();
561 return 1;
562}
563