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