1 /*---------------------------------------------------------------------------*
2 Project: RevoEX - tools - chjpedit
3 File: main.c
4
5 Copyright 2007 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 *---------------------------------------------------------------------------*/
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #define CHJUMP_HEADER_SIZE 32 // Size, excluding the data block
19 #define CHJUMP_SIZE_MAX 512 // File size upper limit, including the data block
20
21 unsigned char gameCode[5];
22 unsigned char chCode[5];
23 unsigned char attachData[CHJUMP_SIZE_MAX + 1];
24 unsigned int dataSize;
25 unsigned int dataBlockNum = 1; //
26 unsigned int addrDataBlock0 = 32; // 0x00000020
27
28 enum readMode
29 {
30 RM_DEFAULT = 0,
31 RM_GAMECODE, // -gc
32 RM_CHCODE,
33 RM_DATA // -d
34 };
35
36 enum errorCode
37 {
38 ERR_WRONG_GAMECODE = 1,
39 ERR_WRONG_CHCODE,
40 ERR_UNKNOWN_OPTION,
41 ERR_DATASIZE_OVER
42 };
43
44 /*---------------------------------------------------------------------------*
45 Name: Usage
46
47 Description: Output command usage to the console.
48 Arguments None.
49 Returns: None.
50 *---------------------------------------------------------------------------*/
Usage(void)51 static void Usage( void )
52 {
53 printf("\n");
54 printf("usage: makeChjp -gc <game code> [-d <data>]\n");
55 printf(" ex. makeChjp -gc 0001 -d \"THIS IS EXAMPLE.\"\n");
56 printf("\n");
57 printf("-gc <game code> : game code. default is 0001 (0x30303031).\n");
58 printf(" if you specify this option, \n");
59 printf(" this value will be used for generating the titleId.\n");
60 printf(" the value must be 4 characters (ex. 0001 or 0x30303031).\n");
61 /* printf("-pc <publisher (channel?) code> : publisher code.\n");
62 printf(" if you specify this option, \n");
63 printf(" this value will be used for generating the titleId.\n");*/
64 printf("-h show the message for help.\n");
65 printf("-----------------------------------------------------------\n");
66 printf("-d <data> : data postted to an application .\n");
67 printf(" * all options are ignored after -d.\n");
68 printf(" * data size must be lower than 512 byte. *\n");
69 }
70
71 /*---------------------------------------------------------------------------*
72 Name: OutputError
73
74 Description: Outputs an error to the console
75 Arguments errcode
76 Returns: None.
77 *---------------------------------------------------------------------------*/
OutputError(int errcode)78 static void OutputError(int errcode)
79 {
80 switch(errcode)
81 {
82 case ERR_WRONG_GAMECODE:
83 fprintf(stderr, "error %d\n", errcode);
84 fprintf(stderr, "wrong game code (-gc)\n");
85 break;
86 case ERR_WRONG_CHCODE:
87 fprintf(stderr, "error %d\n", errcode);
88 fprintf(stderr, "wrong code (-pc)\n");
89 break;
90 case ERR_UNKNOWN_OPTION:
91 fprintf(stderr, "error %d\n", errcode);
92 fprintf(stderr, "unknown option\n");
93 Usage();
94 break;
95 case ERR_DATASIZE_OVER:
96 fprintf(stderr, "error %d\n", errcode);
97 fprintf(stderr, "data size is over 512 byte..\n");
98 break;
99 }
100 }
101
102 /*---------------------------------------------------------------------------*
103 Name: CheckHex
104
105 Description: Checks whether a character string takes on a hexadecimal value (0-9, a-f, A-F).
106 Arguments: str Character string to check
107 Returns: 1 if the check passes; 0 if the check fails.
108 *---------------------------------------------------------------------------*/
CheckHex(const char * str)109 static int CheckHex(const char *str)
110 {
111 const char *p = str;
112
113 p += 2;
114 while(*p)
115 {
116 if( !('0' <= *p && *p <= '9') && !('a' <= *p && *p <= 'f') && !('A' <= *p && *p <= 'F') )
117 return 0;
118 p++;
119 }
120
121 return 1;
122 }
123
124 /*---------------------------------------------------------------------------*
125 Name: ConvertHexCharToChar
126
127 Description: Converts a character string that contains a hexadecimal number ("0x...") to a character string that the hexadecimal number points to.
128 If the number of hexadecimal digits to convert is short of the number of characters, align them to the right and fill the remaining with '\0'.
129
130 Arguments: src Character string that stores the hexadecimal number to convert
131 dst Stores the converted character string
132 dst_size Number of characters in dst
133 Returns: None.
134 *---------------------------------------------------------------------------*/
ConvertHexCharToChar(const unsigned char * src,unsigned char * dst,unsigned int dst_size)135 static void ConvertHexCharToChar(const unsigned char *src, unsigned char *dst, unsigned int dst_size)
136 {
137 const unsigned char *p;
138 unsigned char tmp[dst_size + 1]; // For saving temporarily during conversion; in the end, copy to dst.
139 unsigned int size;
140 int i, j;
141
142 // Tentative check
143 if( src == '\0') return;
144 size = strlen(src);
145
146 p = src;
147 p += size - 1;
148
149 // Properly initialize the end.
150 tmp[dst_size] = '\0';
151
152 for(i = dst_size -1; i >= 0; i--)
153 {
154 tmp[i] = 0x00;
155
156 for(j = 0; j < 2; j++)
157 {
158 if(*p == 'x')
159 {
160 tmp[i] += 0;
161 continue;
162 }
163
164 if('0' <= *p && *p <= '9')
165 tmp[i] += (*p - '0') << 4 * j;
166 else if('a' <= *p && *p <= 'f')
167 tmp[i] += (*p - 'a' + 10) << 4 * j;
168 else if('A' <= *p && *p <= 'F')
169 tmp[i] += (*p - 'A' + 10) << 4 * j;
170
171 p--;
172 }
173 }
174
175 strcpy(dst, tmp);
176 }
177
178 /*---------------------------------------------------------------------------*
179 Name: OutputIntForBin
180
181 Description: Output an integer value to chjump.bin.
182 Values equal to or greater than the maximum value expressible in the number of bytes specified by the input value are cut off and output.
183
184
185 Arguments: val The positive integer value to output
186 byte The number of bytes to output
187 fp File pointer (assumed to be already opened with fopen)
188 Returns: None.
189 *---------------------------------------------------------------------------*/
OutputIntForBin(unsigned int val,unsigned int byte,FILE * fp)190 static void OutputIntForBin(unsigned int val, unsigned int byte, FILE *fp)
191 {
192 int i, tmp;
193
194 for( i= byte - 1; i>=0; i--)
195 {
196 tmp = val >> i * 8;
197 fwrite(&tmp, 1, 1 ,fp);
198 val = val - (tmp << i * 8);
199 }
200 }
201
202 /*---------------------------------------------------------------------------*
203 Name: CreateChJumpFile
204
205 Description: Create chjump.bin.
206 Arguments: None.
207 Returns: None.
208 *---------------------------------------------------------------------------*/
CreateChJumpFile(void)209 static void CreateChJumpFile( void )
210 {
211 int i;
212 FILE *fp;
213
214 // Prepare and write to the file
215 fp = fopen("chjump.bin", "wb");
216
217 fputs("ChJp", fp); // Magic
218 OutputIntForBin(dataSize, 4, fp); // TotalSize
219 OutputIntForBin(dataBlockNum, 4, fp); // NumBlocks
220 OutputIntForBin(0, 4, fp); // Options
221
222 // Title ID 64 bit
223 OutputIntForBin(1, 2, fp); // (Publisher Code) (16 bit)
224 OutputIntForBin((unsigned int)atoi(chCode), 2, fp); // (Channel Code) (16 bit)
225 for(i=0; i < 4; i++) // (Game Code) (32 bit)
226 {
227 if(gameCode[i] == 0x00)
228 fputc('\0', fp);
229 else
230 fputc(gameCode[i], fp);
231 }
232
233 OutputIntForBin(addrDataBlock0, 4, fp); // Offset 0
234 OutputIntForBin(dataSize - CHJUMP_HEADER_SIZE, 4, fp); // Size 0
235
236 if(strlen(attachData) != 0) // Block 0
237 fputs(attachData, fp);
238
239 fputc('\0', fp); fputc('\0', fp); // Add '\0' twice to the end.
240
241 (void)fclose(fp);
242 }
243
244 /*---------------------------------------------------------------------------*
245 Name: main
246
247 Description:
248 Arguments: argc Total number of arguments
249 argv Argument list
250 Returns: None.
251 *---------------------------------------------------------------------------*/
main(int argc,char * argv[])252 int main(int argc, char *argv[])
253 {
254 int i, mode;
255 char *p;
256
257 mode = RM_DEFAULT;
258
259 // Initialization
260 strcpy(gameCode, "0001");
261 strcpy(chCode, "0001");
262
263 // Load options
264 for(i = 1; i < argc; i++)
265 {
266 p = argv[i];
267
268 if( mode == RM_DEFAULT )
269 {
270 if(*p == '-')
271 {
272 if(strcmp(p, "-gc") == 0)
273 {
274 mode = RM_GAMECODE;
275 }
276 else if(strcmp(p, "-pc") == 0)
277 {
278 mode = RM_CHCODE;
279 }
280 else if(strcmp(p, "-d") == 0)
281 {
282 mode = RM_DATA;
283 }
284 else if(strcmp(p, "-h") == 0)
285 {
286 Usage();
287 return 0;
288 }
289 else
290 {
291 OutputError(ERR_UNKNOWN_OPTION);
292 return ERR_UNKNOWN_OPTION;
293 }
294 }
295 else
296 {
297 OutputError(ERR_UNKNOWN_OPTION);
298 return ERR_UNKNOWN_OPTION;
299 }
300 }
301 else if( mode == RM_GAMECODE )
302 {
303 // Conditionals, check for illegal values
304 if(*p == '0' && *(p + 1) == 'x')
305 {
306 if(strlen(p) < 3 || strlen(p) > 10 || !CheckHex(p))
307 {
308 OutputError(ERR_WRONG_GAMECODE);
309 return ERR_WRONG_GAMECODE;
310 }
311 ConvertHexCharToChar(p, gameCode, 4);
312 }
313 else
314 {
315 if(strlen(p) != 4)
316 {
317 OutputError(ERR_WRONG_GAMECODE);
318 return ERR_WRONG_GAMECODE;
319 }
320
321 strcpy(gameCode, p);
322 }
323
324 mode = RM_DEFAULT;
325 }
326 else if( mode == RM_CHCODE )
327 {
328 // Check whether a value is illegal or not
329 if(*p == '0' && *(p + 1) == 'x')
330 {
331 if(strlen(p) < 3 || strlen(p) > 6 || !CheckHex(p))
332 {
333 OutputError(ERR_WRONG_CHCODE);
334 return ERR_WRONG_CHCODE;
335 }
336 // Because it is a number, cut off '0x' and then copy as is
337 strcpy(chCode, p+2);
338 }
339 else
340 {
341 OutputError(ERR_WRONG_CHCODE);
342 return ERR_WRONG_CHCODE;
343 }
344
345 mode = RM_DEFAULT;
346 }
347 else if( mode == RM_DATA)
348 {
349 // Check the size (the two '\0's at the end are also included in the count)
350 if(strlen(p) >= CHJUMP_SIZE_MAX - 1)
351 {
352 OutputError(ERR_DATASIZE_OVER);
353 return ERR_DATASIZE_OVER;
354 }
355
356 // Everything after this option is considered to be data; mode is no longer changed.
357 (void)strcat(attachData, p);
358
359 // All further arguments are ignored.
360 break;
361 }
362 }
363
364 // Detect the full data size.
365 dataSize = strlen(attachData) + CHJUMP_HEADER_SIZE + 2; // Add the header size and the two '\0's at the end.
366
367 // Create chjump.bin.
368 CreateChJumpFile();
369
370 return 0;
371 }
372
373 /*---------------------------------------------------------------------------*
374 $Log: main.c,v $
375 Revision 1.2 2007/07/30 05:46:18 nishimoto_takashi
376 Revised the portion that checks the data size.
377
378 Revision 1.1 2007/07/30 00:48:20 nishimoto_takashi
379 Created
380
381
382 $NoKeywords: $
383 *---------------------------------------------------------------------------*/
384