Fix rbutil building with gcc 4.3 on linux (FS#8757 by Dennis Schridde).
[Rockbox.git] / tools / scramble.c
blobb49bde10a2685c4cc72c7e65bc8c6eaad8b8b589
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <string.h>
24 #include "iriver.h"
25 #include "gigabeat.h"
26 #include "gigabeats.h"
27 #include "mi4.h"
28 #include "telechips.h"
29 #include "iaudio_bl_flash.h"
31 int iaudio_encode(char *iname, char *oname, char *idstring);
32 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
34 enum
36 ARCHOS_PLAYER, /* and V1 recorder */
37 ARCHOS_V2RECORDER,
38 ARCHOS_FMRECORDER,
39 ARCHOS_ONDIO_SP,
40 ARCHOS_ONDIO_FM
43 int size_limit[] =
45 0x32000, /* ARCHOS_PLAYER */
46 0x64000, /* ARCHOS_V2RECORDER */
47 0x64000, /* ARCHOS_FMRECORDER */
48 0x64000, /* ARCHOS_ONDIO_SP */
49 0x64000 /* ARCHOS_ONDIO_FM */
52 void short2le(unsigned short val, unsigned char* addr)
54 addr[0] = val & 0xFF;
55 addr[1] = (val >> 8) & 0xff;
58 unsigned int le2int(unsigned char* buf)
60 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
62 return res;
65 void int2le(unsigned int val, unsigned char* addr)
67 addr[0] = val & 0xFF;
68 addr[1] = (val >> 8) & 0xff;
69 addr[2] = (val >> 16) & 0xff;
70 addr[3] = (val >> 24) & 0xff;
73 void int2be(unsigned int val, unsigned char* addr)
75 addr[0] = (val >> 24) & 0xff;
76 addr[1] = (val >> 16) & 0xff;
77 addr[2] = (val >> 8) & 0xff;
78 addr[3] = val & 0xFF;
81 void short2be(unsigned short val, unsigned char* addr)
83 addr[0] = (val >> 8) & 0xff;
84 addr[1] = val & 0xFF;
87 void usage(void)
89 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
90 printf("options:\n"
91 "\t-fm Archos FM recorder format\n"
92 "\t-v2 Archos V2 recorder format\n"
93 "\t-ofm Archos Ondio FM recorder format\n"
94 "\t-osp Archos Ondio SP format\n"
95 "\t-neo SSI Neo format\n"
96 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
97 "\t-iriver iRiver format\n"
98 "\t-iaudiox5 iAudio X5 format\n"
99 "\t-iaudiox5v iAudio X5V format\n"
100 "\t-iaudiom5 iAudio M5 format\n"
101 "\t-iaudiom3 iAudio M3 format\n"
102 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
103 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
104 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
105 "\t-zvm Zen Vision:M FRESCUE structure format\n"
106 "\t-gigabeat Toshiba Gigabeat F/X format\n"
107 "\t-gigabeats Toshiba Gigabeat S format\n"
108 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
109 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
110 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
111 "\t All mi4 options take two optional arguments:\n"
112 "\t -model=XXXX where XXXX is the model id string\n"
113 "\t -type=XXXX where XXXX is a string indicating the \n"
114 "\t type of binary, eg. RBOS, RBBL\n"
115 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
116 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
117 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
118 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
119 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2)\n"
120 "\nNo option results in Archos standard player/recorder format.\n");
122 exit(1);
125 int main (int argc, char** argv)
127 unsigned long length,i,slen;
128 unsigned char *inbuf,*outbuf;
129 unsigned short crc=0;
130 unsigned long chksum=0; /* 32 bit checksum */
131 unsigned char header[24];
132 char *iname = argv[1];
133 char *oname = argv[2];
134 char *xorstring;
135 int headerlen = 6;
136 FILE* file;
137 int version;
138 unsigned long modelnum;
139 char modelname[5];
140 int model_id;
141 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
143 model_id = ARCHOS_PLAYER;
145 if (argc < 3) {
146 usage();
149 if(!strcmp(argv[1], "-fm")) {
150 headerlen = 24;
151 iname = argv[2];
152 oname = argv[3];
153 version = 4;
154 model_id = ARCHOS_FMRECORDER;
157 else if(!strcmp(argv[1], "-v2")) {
158 headerlen = 24;
159 iname = argv[2];
160 oname = argv[3];
161 version = 2;
162 model_id = ARCHOS_V2RECORDER;
165 else if(!strcmp(argv[1], "-ofm")) {
166 headerlen = 24;
167 iname = argv[2];
168 oname = argv[3];
169 version = 8;
170 model_id = ARCHOS_ONDIO_FM;
173 else if(!strcmp(argv[1], "-osp")) {
174 headerlen = 24;
175 iname = argv[2];
176 oname = argv[3];
177 version = 16;
178 model_id = ARCHOS_ONDIO_SP;
181 else if(!strcmp(argv[1], "-neo")) {
182 headerlen = 17;
183 iname = argv[2];
184 oname = argv[3];
185 method = none;
187 else if(!strncmp(argv[1], "-mm=", 4)) {
188 headerlen = 16;
189 iname = argv[2];
190 oname = argv[3];
191 method = xor;
192 version = argv[1][4];
193 if (argc > 4)
194 xorstring = argv[4];
195 else {
196 printf("Multimedia needs an xor string\n");
197 return -1;
200 else if(!strncmp(argv[1], "-tcc=", 4)) {
201 headerlen = 0;
202 iname = argv[2];
203 oname = argv[3];
205 if(!strcmp(&argv[1][5], "sum"))
206 method = tcc_sum;
207 else if(!strcmp(&argv[1][5], "crc"))
208 method = tcc_crc;
209 else {
210 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
211 return 2;
214 else if(!strncmp(argv[1], "-add=", 5)) {
215 iname = argv[2];
216 oname = argv[3];
217 method = add;
219 if(!strcmp(&argv[1][5], "h120"))
220 modelnum = 0;
221 else if(!strcmp(&argv[1][5], "h140"))
222 modelnum = 0; /* the same as the h120 */
223 else if(!strcmp(&argv[1][5], "h100"))
224 modelnum = 1;
225 else if(!strcmp(&argv[1][5], "h300"))
226 modelnum = 2;
227 else if(!strcmp(&argv[1][5], "ipco"))
228 modelnum = 3;
229 else if(!strcmp(&argv[1][5], "nano"))
230 modelnum = 4;
231 else if(!strcmp(&argv[1][5], "ipvd"))
232 modelnum = 5;
233 else if(!strcmp(&argv[1][5], "fp7x"))
234 modelnum = 6;
235 else if(!strcmp(&argv[1][5], "ip3g"))
236 modelnum = 7;
237 else if(!strcmp(&argv[1][5], "ip4g"))
238 modelnum = 8;
239 else if(!strcmp(&argv[1][5], "mini"))
240 modelnum = 9;
241 else if(!strcmp(&argv[1][5], "iax5"))
242 modelnum = 10;
243 else if(!strcmp(&argv[1][5], "mn2g"))
244 modelnum = 11;
245 else if(!strcmp(&argv[1][5], "h10"))
246 modelnum = 13;
247 else if(!strcmp(&argv[1][5], "h10_5gb"))
248 modelnum = 14;
249 else if(!strcmp(&argv[1][5], "tpj2"))
250 modelnum = 15;
251 else if(!strcmp(&argv[1][5], "e200"))
252 modelnum = 16;
253 else if(!strcmp(&argv[1][5], "iam5"))
254 modelnum = 17;
255 else if(!strcmp(&argv[1][5], "giga"))
256 modelnum = 18;
257 else if(!strcmp(&argv[1][5], "1g2g"))
258 modelnum = 19;
259 else if(!strcmp(&argv[1][5], "c200"))
260 modelnum = 20;
261 else if(!strcmp(&argv[1][5], "gigs"))
262 modelnum = 21;
263 else if(!strcmp(&argv[1][5], "m500"))
264 modelnum = 22;
265 else if(!strcmp(&argv[1][5], "m100"))
266 modelnum = 23;
267 else if(!strcmp(&argv[1][5], "d2"))
268 modelnum = 24;
269 else if(!strcmp(&argv[1][5], "iam3"))
270 modelnum = 25;
271 else {
272 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
273 return 2;
275 /* we store a 4-letter model name too, for humans */
276 strcpy(modelname, &argv[1][5]);
277 chksum = modelnum; /* start checksum calcs with this */
280 else if(!strcmp(argv[1], "-iriver")) {
281 /* iRiver code dealt with in the iriver.c code */
282 iname = argv[2];
283 oname = argv[3];
284 iriver_encode(iname, oname, FALSE);
285 return 0;
287 else if(!strcmp(argv[1], "-gigabeat")) {
288 /* iRiver code dealt with in the iriver.c code */
289 iname = argv[2];
290 oname = argv[3];
291 gigabeat_code(iname, oname);
292 return 0;
294 else if(!strcmp(argv[1], "-gigabeats")) {
295 iname = argv[2];
296 oname = argv[3];
297 gigabeat_s_code(iname, oname);
298 return 0;
300 else if(!strcmp(argv[1], "-iaudiox5")) {
301 iname = argv[2];
302 oname = argv[3];
303 return iaudio_encode(iname, oname, "COWON_X5_FW");
305 else if(!strcmp(argv[1], "-iaudiox5v")) {
306 iname = argv[2];
307 oname = argv[3];
308 return iaudio_encode(iname, oname, "COWON_X5V_FW");
310 else if(!strcmp(argv[1], "-iaudiom5")) {
311 iname = argv[2];
312 oname = argv[3];
313 return iaudio_encode(iname, oname, "COWON_M5_FW");
315 else if(!strcmp(argv[1], "-iaudiom3")) {
316 iname = argv[2];
317 oname = argv[3];
318 return iaudio_encode(iname, oname, "COWON_M3_FW");
320 else if(!strcmp(argv[1], "-ipod3g")) {
321 iname = argv[2];
322 oname = argv[3];
323 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
325 else if(!strcmp(argv[1], "-ipod4g")) {
326 iname = argv[2];
327 oname = argv[3];
328 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
330 else if(!strcmp(argv[1], "-ipod5g")) {
331 iname = argv[2];
332 oname = argv[3];
333 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
335 else if(!strcmp(argv[1], "-zvm")) {
336 iname = argv[2];
337 oname = argv[3];
338 return zvm_encode(iname, oname);
340 else if(!strncmp(argv[1], "-mi4", 4)) {
341 int mi4magic;
342 int version;
343 char model[4] = "";
344 char type[4] = "";
346 if(!strcmp(&argv[1][4], "v2")) {
347 mi4magic = MI4_MAGIC_DEFAULT;
348 version = 0x00010201;
350 else if(!strcmp(&argv[1][4], "v3")) {
351 mi4magic = MI4_MAGIC_DEFAULT;
352 version = 0x00010301;
354 else if(!strcmp(&argv[1][4], "r")) {
355 mi4magic = MI4_MAGIC_R;
356 version = 0x00010301;
358 else {
359 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
360 return -1;
363 iname = argv[2];
364 oname = argv[3];
366 if(!strncmp(argv[2], "-model=", 7)) {
367 iname = argv[3];
368 oname = argv[4];
369 strncpy(model, &argv[2][7], 4);
371 if(!strncmp(argv[3], "-type=", 6)) {
372 iname = argv[4];
373 oname = argv[5];
374 strncpy(type, &argv[3][6], 4);
378 return mi4_encode(iname, oname, version, mi4magic, model, type);
381 /* open file */
382 file = fopen(iname,"rb");
383 if (!file) {
384 perror(iname);
385 return -1;
387 fseek(file,0,SEEK_END);
388 length = ftell(file);
389 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
391 if ((method == scramble) &&
392 ((length + headerlen) >= size_limit[model_id])) {
393 printf("error: firmware image is %d bytes while max size is %d!\n",
394 length + headerlen,
395 size_limit[model_id]);
396 fclose(file);
397 return -1;
400 fseek(file,0,SEEK_SET);
401 inbuf = malloc(length);
402 if (method == xor)
403 outbuf = malloc(length*2);
404 else if(method == add)
405 outbuf = malloc(length + 8);
406 else
407 outbuf = malloc(length);
408 if ( !inbuf || !outbuf ) {
409 printf("out of memory!\n");
410 return -1;
412 if(length> 4) {
413 /* zero-fill the last 4 bytes to make sure there's no rubbish there
414 when we write the size-aligned file later */
415 memset(outbuf+length-4, 0, 4);
418 /* read file */
419 i=fread(inbuf,1,length,file);
420 if ( !i ) {
421 perror(iname);
422 return -1;
424 fclose(file);
426 switch (method)
428 case add:
429 for (i = 0; i < length; i++) {
430 /* add 8 unsigned bits but keep a 32 bit sum */
431 chksum += inbuf[i];
433 break;
434 case scramble:
435 slen = length/4;
436 for (i = 0; i < length; i++) {
437 unsigned long addr = (i >> 2) + ((i % 4) * slen);
438 unsigned char data = inbuf[i];
439 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
440 outbuf[addr] = data;
442 break;
444 case xor:
445 /* "compress" */
446 slen = 0;
447 for (i=0; i<length; i++) {
448 if (!(i&7))
449 outbuf[slen++] = 0xff; /* all data is uncompressed */
450 outbuf[slen++] = inbuf[i];
452 break;
455 if((method == none) || (method == scramble) || (method == xor)) {
456 /* calculate checksum */
457 for (i=0;i<length;i++)
458 crc += inbuf[i];
461 memset(header, 0, sizeof header);
462 switch (method)
464 case add:
466 int2be(chksum, header); /* checksum, big-endian */
467 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
468 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
469 headerlen = 8;
471 break;
473 case tcc_sum:
474 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
475 telechips_encode_sum(outbuf, length);
476 break;
478 case tcc_crc:
479 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
480 telechips_encode_crc(outbuf, length);
481 break;
483 case scramble:
484 if (headerlen == 6) {
485 int2be(length, header);
486 header[4] = (crc >> 8) & 0xff;
487 header[5] = crc & 0xff;
489 else {
490 header[0] =
491 header[1] =
492 header[2] =
493 header[3] = 0xff; /* ??? */
495 header[6] = (crc >> 8) & 0xff;
496 header[7] = crc & 0xff;
498 header[11] = version;
500 header[15] = headerlen; /* really? */
502 int2be(length, &header[20]);
504 break;
506 case xor:
508 int xorlen = strlen(xorstring);
510 /* xor data */
511 for (i=0; i<slen; i++)
512 outbuf[i] ^= xorstring[i & (xorlen-1)];
514 /* calculate checksum */
515 for (i=0; i<slen; i++)
516 crc += outbuf[i];
518 header[0] = header[2] = 'Z';
519 header[1] = header[3] = version;
520 int2le(length, &header[4]);
521 int2le(slen, &header[8]);
522 int2le(crc, &header[12]);
523 length = slen;
524 break;
527 #define MY_FIRMWARE_TYPE "Rockbox"
528 #define MY_HEADER_VERSION 1
529 default:
530 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
531 header[9]='\0'; /*shouldn't have to, but to be SURE */
532 header[10]=MY_HEADER_VERSION&0xFF;
533 header[11]=(crc>>8)&0xFF;
534 header[12]=crc&0xFF;
535 int2be(sizeof(header), &header[12]);
536 break;
539 /* write file */
540 file = fopen(oname,"wb");
541 if ( !file ) {
542 perror(oname);
543 return -1;
545 if (headerlen > 0) {
546 if ( !fwrite(header,headerlen,1,file) ) {
547 perror(oname);
548 return -1;
551 if ( !fwrite(outbuf,length,1,file) ) {
552 perror(oname);
553 return -1;
555 fclose(file);
557 free(inbuf);
558 free(outbuf);
560 return 0;
563 int iaudio_encode(char *iname, char *oname, char *idstring)
565 size_t len;
566 int length;
567 FILE *file;
568 unsigned char *outbuf;
569 int i;
570 unsigned char sum = 0;
572 file = fopen(iname, "rb");
573 if (!file) {
574 perror(iname);
575 return -1;
577 fseek(file,0,SEEK_END);
578 length = ftell(file);
580 fseek(file,0,SEEK_SET);
581 outbuf = malloc(length+0x1030);
583 if ( !outbuf ) {
584 printf("out of memory!\n");
585 return -1;
588 len = fread(outbuf+0x1030, 1, length, file);
589 if(len < length) {
590 perror(iname);
591 return -2;
594 memset(outbuf, 0, 0x1030);
595 strcpy((char *)outbuf, idstring);
596 memcpy(outbuf+0x20, iaudio_bl_flash,
597 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
598 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
599 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
600 outbuf[0x19] = 2;
602 for(i = 0; i < length;i++)
603 sum += outbuf[0x1030 + i];
605 int2be(length, &outbuf[0x1024]);
606 outbuf[0x102b] = sum;
608 fclose(file);
610 file = fopen(oname, "wb");
611 if (!file) {
612 perror(oname);
613 return -3;
616 len = fwrite(outbuf, 1, length+0x1030, file);
617 if(len < length) {
618 perror(oname);
619 return -4;
622 fclose(file);
626 /* Create an ipod firmware partition image
628 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
630 This function doesn't yet handle the Broadcom resource image for the 5g,
631 so the resulting images won't be usable.
633 This has also only been tested on an ipod Photo
636 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
638 static const char *apple_stop_sign = "{{~~ /-----\\ "\
639 "{{~~ / \\ "\
640 "{{~~| | "\
641 "{{~~| S T O P | "\
642 "{{~~| | "\
643 "{{~~ \\ / "\
644 "{{~~ \\-----/ "\
645 "Copyright(C) 200"\
646 "1 Apple Computer"\
647 ", Inc.----------"\
648 "----------------"\
649 "----------------"\
650 "----------------"\
651 "----------------"\
652 "----------------"\
653 "---------------";
654 size_t len;
655 int length;
656 int rsrclength;
657 int rsrcoffset;
658 FILE *file;
659 unsigned int sum = 0;
660 unsigned int rsrcsum = 0;
661 unsigned char *outbuf;
662 int bufsize;
663 int i;
665 file = fopen(iname, "rb");
666 if (!file) {
667 perror(iname);
668 return -1;
670 fseek(file,0,SEEK_END);
671 length = ftell(file);
673 fseek(file,0,SEEK_SET);
675 bufsize=(length+0x4600);
676 if (fake_rsrc) {
677 bufsize = (bufsize + 0x400) & ~0x200;
680 outbuf = malloc(bufsize);
682 if ( !outbuf ) {
683 printf("out of memory!\n");
684 return -1;
687 len = fread(outbuf+0x4600, 1, length, file);
688 if(len < length) {
689 perror(iname);
690 return -2;
692 fclose(file);
694 /* Calculate checksum for later use in header */
695 for(i = 0x4600; i < 0x4600+length;i++)
696 sum += outbuf[i];
698 /* Clear the header area to zero */
699 memset(outbuf, 0, 0x4600);
701 /* APPLE STOP SIGN */
702 strcpy((char *)outbuf, apple_stop_sign);
704 /* VOLUME HEADER */
705 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
706 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
707 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
708 short2le(fw_ver, &outbuf[0x10a]);
710 /* Firmware Directory - "osos" entry */
711 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
712 int2le(0, &outbuf[0x4208]); /* id */
713 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
714 int2le(length, &outbuf[0x4210]); /* Length of firmware */
715 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
716 int2le(0, &outbuf[0x4218]); /* Entry Offset */
717 int2le(sum, &outbuf[0x421c]); /* Checksum */
718 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
719 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
721 /* "rsrc" entry (if applicable) */
722 if (fake_rsrc) {
723 rsrcoffset=(length+0x4600+0x200) & ~0x200;
724 rsrclength=0x200;
725 rsrcsum=0;
727 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
728 int2le(0, &outbuf[0x4230]); /* id */
729 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
730 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
731 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
732 int2le(0, &outbuf[0x4240]); /* Entry Offset */
733 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
734 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
735 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
738 file = fopen(oname, "wb");
739 if (!file) {
740 perror(oname);
741 return -3;
744 len = fwrite(outbuf, 1, length+0x4600, file);
745 if(len < length) {
746 perror(oname);
747 return -4;
750 fclose(file);
752 return 0;
756 /* Create an Zen Vision:M FRESCUE structure file
759 int zvm_encode(char *iname, char *oname)
761 size_t len;
762 int length;
763 FILE *file;
764 unsigned int sum = 0;
765 unsigned char *outbuf;
766 int i;
768 file = fopen(iname, "rb");
769 if (!file) {
770 perror(iname);
771 return -1;
773 fseek(file,0,SEEK_END);
774 length = ftell(file);
776 fseek(file,0,SEEK_SET);
778 outbuf = malloc(length+0x18+0x10);
780 if ( !outbuf ) {
781 printf("out of memory!\n");
782 return -1;
785 len = fread(outbuf+0x18, 1, length, file);
786 if(len < length) {
787 perror(iname);
788 return -2;
790 fclose(file);
792 /* Calculate checksum for later use in header */
793 for(i=0; i<length; i+= 4)
794 sum += le2int(&outbuf[0x18+i]) + (le2int(&outbuf[0x18+i])>>16);
796 /* Clear the header area to zero */
797 memset(outbuf, 0, 0x18);
799 /* Header (EDOC) */
800 memcpy((char*)outbuf, "EDOC", 4);
801 /* Total Size */
802 int2le(length+0x20, &outbuf[0x4]);
803 /* 4 bytes of zero */
805 /* Address = 0x900000 */
806 int2le(0x900000, &outbuf[0xC]);
807 /* Size */
808 int2le(length, &outbuf[0x10]);
809 /* Checksum */
810 int2le(sum, &outbuf[0x14]);
811 outbuf[0x16] = 0;
812 outbuf[0x17] = 0;
813 /* Data starts here... */
815 /* Second block starts here ... */
816 /* Address = 0x0 */
817 /* Size */
818 int2le(0x4, &outbuf[0x18+length+0x4]);
819 /* Checksum */
820 outbuf[0x18+length+0x8] = 0xB7;
821 outbuf[0x18+length+0x9] = 0xD5;
822 /* Data: LDR PC, =0x900000 */
823 outbuf[0x18+length+0xC] = 0x18;
824 outbuf[0x18+length+0xD] = 0xF0;
825 outbuf[0x18+length+0xE] = 0x9F;
826 outbuf[0x18+length+0xF] = 0xE5;
829 file = fopen(oname, "wb");
830 if (!file) {
831 perror(oname);
832 return -3;
835 len = fwrite(outbuf, 1, length+0x28, file);
836 if(len < length+0x18) {
837 perror(oname);
838 return -4;
841 free(outbuf);
843 fclose(file);
845 return 0;