tachtig: Handle animated icons.
[svpe-tools.git] / tachtig.c
blob11664f68dd16c30d2619f042e9a57ccbd49a60a9
1 // Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
2 // Licensed under the terms of the GNU GPL, version 2
3 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdio.h>
12 #include "tools.h"
14 #define ERROR(s) do { fprintf(stderr, s "\n"); exit(1); } while (0)
16 static u8 sd_key[16];
17 static u8 sd_iv[16];
18 static u8 md5_blanker[16];
20 static FILE *fp;
21 static u32 n_files;
22 static u32 files_size;
23 static u32 total_size;
25 static void output_image(u8 *data, u32 w, u32 h, const char *name)
27 FILE *fp;
28 u32 x, y;
30 fp = fopen(name, "wb");
31 if (!fp)
32 fatal("open %s", name);
34 fprintf(fp, "P6 %d %d 255\n", w, h);
36 for (y = 0; y < h; y++)
37 for (x = 0; x < w; x++) {
38 u8 pix[3];
39 u16 raw;
40 u32 x0, x1, y0, y1, off;
42 x0 = x & 3;
43 x1 = x >> 2;
44 y0 = y & 3;
45 y1 = y >> 2;
46 off = x0 + 4 * y0 + 16 * x1 + 4 * w * y1;
48 raw = be16(data + 2*off);
50 // RGB5A3
51 if (raw & 0x8000) {
52 pix[0] = (raw >> 7) & 0xf8;
53 pix[1] = (raw >> 2) & 0xf8;
54 pix[2] = (raw << 3) & 0xf8;
55 } else {
56 pix[0] = (raw >> 4) & 0xf0;
57 pix[1] = raw & 0xf0;
58 pix[2] = (raw << 4) & 0xf0;
61 if (fwrite(pix, 3, 1, fp) != 1)
62 fatal("write %s", name);
65 fclose(fp);
68 static void do_file_header(void)
70 u8 header[0xf0c0];
71 u8 md5_file[16];
72 u8 md5_calc[16];
73 u32 header_size;
74 char name[256];
75 FILE *out;
76 u32 i;
78 if (fread(header, sizeof header, 1, fp) != 1)
79 fatal("read file header");
81 aes_cbc_dec(sd_key, sd_iv, header, sizeof header, header);
83 memcpy(md5_file, header + 0x0e, 16);
84 memcpy(header + 0x0e, md5_blanker, 16);
85 md5(header, sizeof header, md5_calc);
87 if (memcmp(md5_file, md5_calc, 0x10))
88 ERROR("MD5 mismatch");
90 header_size = be32(header + 8);
91 if (header_size != 0x72a0 && header_size != 0xf0a0)
92 ERROR("unknown file header size");
94 out = fopen("###title###", "wb");
95 if (!out)
96 fatal("open ###title###");
97 if (fwrite(header + 0x40, 0x80, 1, out) != 1)
98 fatal("write ###title###");
99 fclose(out);
101 output_image(header + 0xc0, 192, 64, "###banner###.ppm");
102 if (header_size == 0x72a0)
103 output_image(header + 0x60c0, 48, 48, "###icon###.ppm");
104 else
105 for (i = 0; i < 8; i++) {
106 snprintf(name, sizeof name, "###icon%d###.ppm", i);
107 output_image(header + 0x60c0 + 0x1200*i, 48, 48, name);
111 static void do_backup_header(void)
113 u8 header[0x80];
115 if (fread(header, sizeof header, 1, fp) != 1)
116 fatal("read backup header");
118 if (be32(header + 4) != 0x426b0001)
119 ERROR("no Bk header");
120 if (be32(header) != 0x70)
121 ERROR("wrong Bk header size");
123 fprintf(stderr, "NG id: %08x\n", be32(header + 8));
125 n_files = be32(header + 0x0c);
126 files_size = be32(header + 0x10);
127 total_size = be32(header + 0x1c);
129 fprintf(stderr, "%d files\n", n_files);
132 static mode_t perm_to_mode(u8 perm)
134 mode_t mode;
135 u32 i;
137 mode = 0;
138 for (i = 0; i < 3; i++) {
139 mode <<= 3;
140 if (perm & 0x20)
141 mode |= 2;
142 if (perm & 0x10)
143 mode |= 4;
144 perm <<= 2;
147 return mode;
150 static void do_file(void)
152 u8 header[0x80];
153 u32 size;
154 u32 rounded_size;
155 u8 perm, attr, type;
156 char *name;
157 u8 *data;
158 FILE *out;
159 mode_t mode;
161 if (fread(header, sizeof header, 1, fp) != 1)
162 fatal("read file header");
164 if (be32(header) != 0x03adf17e)
165 ERROR("bad file header");
167 size = be32(header + 4);
168 perm = header[8];
169 attr = header[9];
170 type = header[10];
171 name = header + 11;
173 fprintf(stderr, "file: size=%08x perm=%02x attr=%02x type=%02x name=%s\n", size, perm, attr, type, name);
175 mode = perm_to_mode(perm);
177 switch (type) {
178 case 1:
179 rounded_size = (size + 63) & ~63;
180 data = malloc(rounded_size);
181 if (!data)
182 fatal("malloc");
183 if (fread(data, rounded_size, 1, fp) != 1)
184 fatal("read file data for %s", name);
186 aes_cbc_dec(sd_key, header + 0x50, data, rounded_size, data);
188 out = fopen(name, "wb");
189 if (!out)
190 fatal("open %s", name);
191 if (fwrite(data, size, 1, out) != 1)
192 fatal("write %s", name);
193 fclose(out);
195 free(data);
196 break;
198 case 2:
199 if (mkdir(name, 0777))
200 fatal("mkdir %s", name);
201 mode |= 0111;
202 break;
204 default:
205 ERROR("unhandled file type");
208 if (chmod(name, mode))
209 fatal("chmod %s", name);
212 static void do_sig(void)
214 u8 sig[0x40];
215 u8 ng_cert[0x180];
216 u8 ap_cert[0x180];
217 u8 hash[0x14];
218 u8 *data;
219 u32 data_size;
220 int ok;
222 if (fread(sig, sizeof sig, 1, fp) != 1)
223 fatal("read signature");
224 if (fread(ng_cert, sizeof ng_cert, 1, fp) != 1)
225 fatal("read NG cert");
226 if (fread(ap_cert, sizeof ap_cert, 1, fp) != 1)
227 fatal("read AP cert");
229 data_size = total_size - 0x340;
231 data = malloc(data_size);
232 if (!data)
233 fatal("malloc");
234 fseek(fp, 0xf0c0, SEEK_SET);
235 if (fread(data, data_size, 1, fp) != 1)
236 fatal("read data for sig check");
237 sha(data, data_size, hash);
238 sha(hash, 20, hash);
239 free(data);
241 ok = check_ec(ng_cert, ap_cert, sig, hash);
242 printf("ok: %d\n", ok);
245 int main(int argc, char **argv)
247 u32 i;
249 if (argc != 3) {
250 fprintf(stderr, "Usage: %s <data.bin> <destdir>\n", argv[0]);
251 return 1;
254 get_key("sd-key", sd_key, 16);
255 get_key("sd-iv", sd_iv, 16);
256 get_key("md5-blanker", md5_blanker, 16);
258 fp = fopen(argv[1], "rb");
259 if (!fp)
260 fatal("open %s", argv[1]);
262 if (mkdir(argv[2], 0777))
263 fatal("mkdir %s", argv[2]);
264 if (chdir(argv[2]))
265 fatal("chdir %s", argv[2]);
267 do_file_header();
268 do_backup_header();
270 for (i = 0; i < n_files; i++)
271 do_file();
273 if (chdir(".."))
274 fatal("chdir ..");
276 do_sig();
278 fclose(fp);
280 return 0;