source: rtems/c/src/lib/libbsp/arm/nds/tools/ndstool/source/ndstool.cpp @ 9a12c7e5

4.104.11
Last change on this file since 9a12c7e5 was 9a12c7e5, checked in by Joel Sherrill <joel.sherrill@…>, on May 4, 2009 at 2:04:42 AM

2009-05-03 Joel Sherrill <joel.sherrill@…>

  • ndstool/include/banner.h, ndstool/include/header.h, ndstool/include/ndstree.h, ndstool/source/banner.cpp, ndstool/source/header.cpp, ndstool/source/ndscreate.cpp, ndstool/source/ndstool.cpp, ndstool/source/passme.cpp: Remove warnings for deprecated character conversions.
  • Property mode set to 100644
File size: 12.1 KB
Line 
1/*
2        Nintendo DS rom tool
3        by Rafael Vuijk (aka DarkFader)
4*/
5
6#include <unistd.h>
7#include "ndstool.h"
8#include "sha1.h"
9#include "ndscreate.h"
10#include "ndsextract.h"
11#include "passme.h"
12#include "hook.h"
13#include "encryption.h"
14
15/*
16 * Variables
17 */
18int verbose = 0;
19Header header;
20FILE *fNDS = 0;
21char *romlistfilename = 0;
22char *filemasks[MAX_FILEMASKS];
23int filemask_num = 0;
24char *ndsfilename = 0;
25char *arm7filename = 0;
26char *arm9filename = 0;
27char *filerootdir = 0;
28char *overlaydir = 0;
29char *arm7ovltablefilename = 0;
30char *arm9ovltablefilename = 0;
31char *bannerfilename = 0;
32char *bannertext = 0;
33//bool compatibility = false;
34char *headerfilename_or_size = 0;
35//char *uniquefilename = 0;
36char *logofilename = 0;
37char *title = 0;
38char *makercode = 0;
39char *gamecode = 0;
40char *vhdfilename = 0;
41char *sramfilename = 0;
42int latency1 = 0x1FFF;  //0x8F8;
43int latency2 = 0x3F;    //0x18;
44int romversion = 0;
45char endecrypt_option = 0;
46
47int bannertype;
48unsigned int arm9RamAddress = 0;
49unsigned int arm7RamAddress = 0;
50unsigned int arm9Entry = 0;
51unsigned int arm7Entry = 0;
52
53
54/*
55 * Title
56 */
57void Title()
58{
59        printf("Nintendo DS rom tool "VERSION" - %s\nby Rafael Vuijk, Dave Murphy, Alexei Karpenko\n",CompileDate);
60}
61
62/*
63 * Help data
64 */
65struct HelpLine
66{
67        const char *option_char;
68        const char *text;
69
70        void Print()
71        {
72                char s[1024];
73                strcpy(s, text);
74                printf("%-22s ", strtok(s, "\n"));
75                char *p = strtok(0, "\n"); if (p) printf("%-30s ", p);
76                for (int i=0; ; i++)
77                {
78                        char *p = strtok(0, "\n");
79                        if (!p) { printf("\n"); break; }
80                        if (i) printf("\n%54s", "");
81                        printf("%s", p);
82                }
83        }
84};
85
86HelpLine helplines[] =
87{
88        {"",    "Parameter\nSyntax\nComments"},
89        {"",    "---------\n------\n--------"},
90        {"?",   "Show this help:\n-?[option]\nAll or single help for an option."},
91        {"i",   "Show information:\n-i [file.nds]\nHeader information."},
92        {"v",   "  Show more info\n-v [roms_rc.dat]\nChecksums, warnings, release info"},
93        {"p",   "PassMe:\n-p [file.nds] [passme.vhd] [passme.sav]\nGenerates PassMe2 files."},
94        {"k",   "Hook ARM7 executable\n-k [file.nds]\nCurrently not tested."},
95        {"f",   "Fix header CRC\n-f [file.nds]\nYou only need this after manual editing."},
96        //{"T", "Test\n-T [file.nds]"},
97        {"s",   "En/decrypt secure area\n-s[e|E|d] [file.nds]\nEn/decrypt the secure area and\nput/remove card encryption tables and test patterns.\nOptionally add: d for decryption, e/E for encryption.\n(e: Nintendo offsets, E: others)"},
98        //{"@", "Hash file & compare:\n-@ [arm7.bin]"},         // used in buildscript
99        {"1",   "List files:\n-l [file.nds]\nGive a list of contained files."},
100        {"v",   "  Show offsets/sizes\n-v"},
101        {"cx",  "Create/Extract\n-c/-x [file.nds]"},
102        {"v",   "  Show more info\n-v[v...]\nShow filenames and more header info.\nUse multiple v's for more information."},
103        {"9",   "  ARM9 executable\n-9 file.bin"},
104        {"7",   "  ARM7 executable\n-7 file.bin"},
105        {"y9",  "  ARM9 overlay table\n-y9 file.bin"},
106        {"y7",  "  ARM7 overlay table\n-y7 file.bin"},
107        {"d",   "  Data files\n-d directory"},
108        {"y",   "  Overlay files\n-y directory"},
109        {"b",   "  Banner bitmap/text\n-b file.bmp \"text;text;text\"\nThe three lines are shown at different sizes."},
110        {"t",   "  Banner binary\n-t file.bin"},
111        {"h",   "  Header template\n-h file.bin\nUse the header from another ROM as a template."},
112        {"h",   "  Header size\n-h size\nA header size of 0x4000 is default for real cards, 0x200 for homebrew."},
113        {"n",   "  Latency\n-n [L1] [L2]\ndefault=maximum"},
114        {"o",   "  Logo bitmap/binary\n-o file.bmp/file.bin"},
115        {"g",   "  Game info\n-g gamecode [makercode] [title] [rom ver]\nSets game-specific information.\nGame code is 4 characters. Maker code is 2 characters.\nTitle can be up to 12 characters."},
116        {"r",   "  ARM9 RAM address\n-r9 address"},
117        {"r",   "  ARM7 RAM address\n-r7 address"},
118        {"e",   "  ARM9 RAM entry\n-e9 address"},
119        {"e",   "  ARM7 RAM entry\n-e7 address"},
120        {"w",   "  Wildcard filemask(s)\n-w [filemask]...\n* and ? are wildcard characters."},
121};
122
123/*
124 * Help
125 */
126void Help(char *specificoption = 0)
127{
128        Title();
129        printf("\n");
130
131        if (specificoption)
132        {
133                bool found = false;
134                for (unsigned int i=0; i<(sizeof(helplines) / sizeof(helplines[0])); i++)
135                {
136                        for (const char *o = helplines[i].option_char; *o; o++)
137                        {
138                                if (*o == *specificoption) { helplines[i].Print(); found = true; }
139                        }
140                }
141                if (!found)
142                {
143                        printf("Unknown option: %s\n\n", specificoption);
144                }
145        }
146        else
147        {
148                for (unsigned int i=0; i<(sizeof(helplines) / sizeof(helplines[0])); i++)
149                {
150                        helplines[i].Print();
151                }
152                printf("\n");
153                printf("You only need to specify the NDS filename once if you want to perform multiple actions.\n");
154                printf("Actions are performed in the specified order.\n");
155                printf("Addresses can be prefixed with '0x' to use hexadecimal format.\n");
156        }
157}
158
159
160#define REQUIRED(var)   var = ((argc > a+1) ? argv[++a] : 0)                                                            // must precede OPTIONAL
161#define OPTIONAL(var)   { /*fprintf(stderr, "'%s'\n", argv[a]);*/ char *t = ((argc > a+1) && (argv[a+1][0] != '-') ? argv[++a] : 0); if (!var) var = t; else if (t) fprintf(stderr, "%s is already specified!\n", #var); }              // final paramter requirement checks are done when performing actions
162#define OPTIONAL_INT(var)       { char *t = ((argc > a+1) && (argv[a+1][0] != '-') ? argv[++a] : 0); if (t) var = strtoul(t,0,0); }             // like OPTIONAL, but for (positive) integers
163#define MAX_ACTIONS             32
164#define ADDACTION(a)    { if (num_actions < MAX_ACTIONS) actions[num_actions++] = a; }
165
166enum {
167        ACTION_SHOWINFO,
168        ACTION_FIXHEADERCRC,
169        ACTION_ENCRYPTSECUREAREA,
170        ACTION_PASSME,
171        ACTION_LISTFILES,
172        ACTION_EXTRACT,
173        ACTION_CREATE,
174        ACTION_HASHFILE,
175        ACTION_HOOK,
176};
177
178/*
179 * main
180 */
181int main(int argc, char *argv[])
182{
183        #ifdef _NDSTOOL_P_H
184                if (sizeof(Header) != 0x200) { fprintf(stderr, "Header size %d != %d\n", sizeof(Header), 0x200); return 1; }
185        #endif
186
187        if (argc < 2) { Help(); return 0; }
188
189        int num_actions = 0;
190        int actions[MAX_ACTIONS];
191
192        /*
193         * parse parameters to actions
194         */
195
196        for (int a=1; a<argc; a++)
197        {
198                if (argv[a][0] == '-')
199                {
200                        switch (argv[a][1])
201                        {
202                                case 'i':       // show information
203                                {
204                                        ADDACTION(ACTION_SHOWINFO);
205                                        OPTIONAL(ndsfilename);
206                                        break;
207                                }
208
209                                case 'f':       // fix header CRC
210                                {
211                                        ADDACTION(ACTION_FIXHEADERCRC);
212                                        OPTIONAL(ndsfilename);
213                                        break;
214                                }
215
216                                case 's':       // en-/decrypt secure area
217                                {
218                                        ADDACTION(ACTION_ENCRYPTSECUREAREA);
219                                        endecrypt_option = argv[a][2];
220                                        OPTIONAL(ndsfilename);
221                                        break;
222                                }
223
224                                case 'p':       // PassMe
225                                {
226                                        ADDACTION(ACTION_PASSME);
227                                        OPTIONAL(ndsfilename);
228                                        OPTIONAL(vhdfilename);
229                                        OPTIONAL(sramfilename);
230                                        break;
231                                }
232
233                                case 'l':       // list files
234                                {
235                                        ADDACTION(ACTION_LISTFILES);
236                                        OPTIONAL(ndsfilename);
237                                        break;
238                                }
239
240                                case 'x':       // extract
241                                {
242                                        ADDACTION(ACTION_EXTRACT);
243                                        OPTIONAL(ndsfilename);
244                                        break;
245                                }
246
247                                case 'w':       // wildcard filemasks
248                                {
249                                        while (1)
250                                        {
251                                                char *filemask = 0;
252                                                OPTIONAL(filemask);
253                                                if (!(filemasks[filemask_num] = filemask)) break;
254                                                if (++filemask_num >= MAX_FILEMASKS) return 1;
255                                        }
256                                        break;
257                                }
258
259                                case 'c':       // create
260                                {
261                                        ADDACTION(ACTION_CREATE);
262                                        OPTIONAL(ndsfilename);
263                                        break;
264                                }
265
266                                // file root directory
267                                case 'd': REQUIRED(filerootdir); break;
268
269                                // ARM7 filename
270                                case '7': REQUIRED(arm7filename); break;
271
272                                // ARM9 filename
273                                case '9': REQUIRED(arm9filename); break;
274
275                                // hash file
276                                case '@':
277                                {
278                                        ADDACTION(ACTION_HASHFILE);
279                                        OPTIONAL(arm7filename);
280                                        break;
281                                }
282
283                                // hook ARM7 executable
284                                case 'k':
285                                {
286                                        ADDACTION(ACTION_HOOK);
287                                        OPTIONAL(ndsfilename);
288                                        break;
289                                }
290
291                                case 't':
292                                        REQUIRED(bannerfilename);
293                                        bannertype = BANNER_BINARY;
294                                        break;
295
296                                case 'b':
297                                        bannertype = BANNER_IMAGE;
298                                        REQUIRED(bannerfilename);
299                                        REQUIRED(bannertext);
300                                        break;
301
302                                case 'o':
303                                        REQUIRED(logofilename);
304                                        break;
305
306                                case 'h':       // load header or header size
307                                        REQUIRED(headerfilename_or_size);
308                                        break;
309
310                                /*case 'u':     // unique ID file
311                                        REQUIRED(uniquefilename);
312                                        break;*/
313
314                                case 'v':       // verbose
315                                        for (char *p=argv[a]; *p; p++) if (*p == 'v') verbose++;
316                                        OPTIONAL(romlistfilename);
317                                        break;
318
319                                case 'n':       // latency
320                                        //compatibility = true;
321                                        OPTIONAL_INT(latency1);
322                                        OPTIONAL_INT(latency2);
323                                        break;
324
325                                case 'r':       // RAM address
326                                        switch (argv[a][2])
327                                        {
328                                                case '7': arm7RamAddress = (argc > a) ? strtoul(argv[++a], 0, 0) : 0; break;
329                                                case '9': arm9RamAddress = (argc > a) ? strtoul(argv[++a], 0, 0) : 0; break;
330                                                default: Help(argv[a]); return 1;
331                                        }
332                                        break;
333
334                                case 'e':       // entry point
335                                        switch (argv[a][2])
336                                        {
337                                                case '7': arm7Entry = (argc > a) ? strtoul(argv[++a], 0, 0) : 0; break;
338                                                case '9': arm9Entry = (argc > a) ? strtoul(argv[++a], 0, 0) : 0; break;
339                                                default: Help(argv[a]); return 1;
340                                        }
341                                        break;
342
343                                case 'm':       // maker code
344                                        REQUIRED(makercode);
345                                        break;
346
347                                case 'g':       // game code
348                                        REQUIRED(gamecode);
349                                        OPTIONAL(makercode);
350                                        OPTIONAL(title);
351                                        OPTIONAL_INT(romversion);
352                                        break;
353
354                                case 'y':       // overlay table file / directory
355                                        switch (argv[a][2])
356                                        {
357                                                case '7': REQUIRED(arm7ovltablefilename); break;
358                                                case '9': REQUIRED(arm9ovltablefilename); break;
359                                                case 0: REQUIRED(overlaydir); break;
360                                                default: Help(argv[a]); return 1;
361                                        }
362                                        break;
363
364                                case '?':       // global or specific help
365                                {
366                                        Help(argv[a][2] ? argv[a]+2 : 0);       // 0=global help
367                                        return 0;       // do not perform any other actions
368                                }
369
370                                default:
371                                {
372                                        Help(argv[a]);
373                                        return 1;
374                                }
375                        }
376                }
377                else
378                {
379                        //Help();
380                        if (ndsfilename)
381                        {
382                                fprintf(stderr, "NDS filename is already given!\n");
383                                return 1;
384                        }
385                        ndsfilename = argv[a];
386                        break;
387                }
388        }
389
390        Title();
391
392        /*
393         * sanity checks
394         */
395
396        if (gamecode)
397        {
398                if (strlen(gamecode) != 4)
399                {
400                        fprintf(stderr, "Game code must be 4 characters!\n");
401                        return 1;
402                }
403                for (int i=0; i<4; i++) if ((gamecode[i] >= 'a') && (gamecode[i] <= 'z'))
404                {
405                        fprintf(stderr, "Warning: Gamecode contains lowercase characters.\n");
406                        break;
407                }
408                if (gamecode[0] == 'A')
409                {
410                        fprintf(stderr, "Warning: Gamecode starts with 'A', which might be used for another commercial product.\n");
411                }
412        }
413        if (makercode && (strlen(makercode) != 2))
414        {
415                fprintf(stderr, "Maker code must be 2 characters!\n");
416                return 1;
417        }
418        if (title && (strlen(title) > 12))
419        {
420                fprintf(stderr, "Title can be no more than 12 characters!\n");
421                return 1;
422        }
423
424        /*
425         * perform actions
426         */
427
428        int status = 0;
429        for (int i=0; i<num_actions; i++)
430        {
431//printf("action %d\n", actions[i]);
432                switch (actions[i])
433                {
434                        case ACTION_SHOWINFO:
435                                ShowInfo(ndsfilename);
436                                break;
437
438                        case ACTION_FIXHEADERCRC:
439                                FixHeaderCRC(ndsfilename);
440                                break;
441
442                        case ACTION_EXTRACT:
443                                if (arm9filename) Extract(arm9filename, true, 0x20, true, 0x2C, true);
444                                if (arm7filename) Extract(arm7filename, true, 0x30, true, 0x3C);
445                                if (bannerfilename) Extract(bannerfilename, true, 0x68, false, 0x840);
446                                if (headerfilename_or_size) Extract(headerfilename_or_size, false, 0x0, false, 0x200);
447                                if (logofilename) Extract(logofilename, false, 0xC0, false, 156);       // *** bin only
448                                if (arm9ovltablefilename) Extract(arm9ovltablefilename, true, 0x50, true, 0x54);
449                                if (arm7ovltablefilename) Extract(arm7ovltablefilename, true, 0x58, true, 0x5C);
450                                if (overlaydir) ExtractOverlayFiles();
451                                if (filerootdir) ExtractFiles(ndsfilename);
452                                break;
453
454                        case ACTION_CREATE:
455                                Create();
456                                break;
457
458                        case ACTION_PASSME:
459                                status = PassMe(ndsfilename, vhdfilename, sramfilename);
460                                break;
461
462                        case ACTION_LISTFILES:
463                                filerootdir = 0;
464                                /*status =*/ ExtractFiles(ndsfilename);
465                                break;
466
467                        case ACTION_HASHFILE:
468                        {
469                                char *filename = arm7filename;
470                                if (!filename) filename = ndsfilename;
471                                if (!filename) return 1;
472                                unsigned char sha1[SHA1_DIGEST_SIZE];
473                                int r = HashAndCompareWithList(filename, sha1);
474                                status = -1;
475                                if (r > 0)
476                                {
477                                        for (int i=0; i<SHA1_DIGEST_SIZE; i++) printf("%02X", sha1[i]);
478                                        printf("\n");
479                                        status = 0;
480                                }
481                                break;
482                        }
483
484                        case ACTION_HOOK:
485                        {
486                                Hook(ndsfilename, arm7filename);
487                                break;
488                        }
489
490                        case ACTION_ENCRYPTSECUREAREA:
491                        {
492                                /*status =*/ EnDecryptSecureArea(ndsfilename, endecrypt_option);
493                                break;
494                        }
495                }
496        }
497
498        return (status < 0) ? 1 : 0;
499}
Note: See TracBrowser for help on using the repository browser.