Skip to content

Commit e439600

Browse files
committed
Updated mcloader to support embedded cli files in gci files.
Added source for cliembed command line application. Tested and working with 18 params
1 parent 232a881 commit e439600

File tree

4 files changed

+297
-5
lines changed

4 files changed

+297
-5
lines changed

mcloader/Readme.txt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Brosexec 0.1 by suloku '15
1+
Brosexec 0.2 by suloku '15
22
**************************
33

44
This is a simple dol that will mount a memory card and scan for dol files created with dol2gci, it will list them and allow to boot them.
@@ -15,6 +15,24 @@ To install dol files to the memory card, convert them with dol2gci, then install
1515

1616
note: the name of the file on the memory card will be that of the dol file BEFORE converting it with dol2gci. After the conversion is done, renaming the gci file will have no impact on the memory card filename.
1717

18+
Command line parameters
19+
-----------------------
20+
To pass command line parameters to the launched dol file, follow the following steps:
21+
1.- Use dol2gci and convert yourfile.dol to yourfile.gci
22+
2.- Create a blank text file named yourfile.cli (same filename as the dol file)
23+
3.- With a text editor, edit the cli and add the parameters, one paramenter per newline
24+
4.- Embed yourfile.cli to yourfile.gci using cliembed.exe
25+
26+
How does this work: dol2gci needs to pad the dol files when converting to gci, since even a 1 byte file will occupy 8912 bytes (1 block) in the memory card. dol2gci pads this additional space with 0xCD. cliembed searches for this padding area in the cli file, then adds the cli file with some magic strings to the very end of this padding.
27+
McLoader just looks for this magic strings to read the cli file from there.
28+
29+
What if the dol file occupies all the blocks with no padding? This would be a very very rare situation, but if it happens cliembed will ask you if you want to create a padded gci file. If you select yes, an aditional block of padded data will be added to the gci file and the gci header will be updated, then the new padded file will be saved as yourfile-fat.gci. After that, use yourfile-fat.gci to embed the cli file to it. The downside is obvious: the file will require an aditional block in the memory card.
30+
31+
32+
Changelog:
33+
----------
34+
[+] 0.2:
35+
- Added command line argument support by loading a embeded cli file inside the gci file created with dol2gci. Use attached cliembed.exe file for this.
1836

1937
----------------------
2038

mcloader/cliembed/Readme.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CLI Embedder 0.1 by suloku 15'
2+
******************************
3+
4+
This program will embedd a cli file into a gci file created with dol2gci.
5+
6+
Usage: cliembed.exe mydol.gci
7+
or drag and drop to executable file
8+
9+
Cli file must have the same name and be in the same path as gci file:
10+
swiss.gci and swiss.cli
11+
12+
13+
In case that the cli file is too big for the gci file padding, the program will ask you if you want to create a new gci file with an aditional block. After the file is created, use the new file with cliembed and you will be able to embed your cli file.

mcloader/cliembed/main.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#define BLOCK 8192
6+
#define GCIHEAD 64
7+
#define GCICOMMENT 0x520
8+
9+
#define be16(x) ((((x)>>8)&0xFF)|(((x)<<8))&0xFF00)
10+
#define be32(x) (((x)<<24)|(((x)>>8)&0xFF00)|(((x)<<8)&0xFF0000)|((x)>>24))
11+
12+
#define CLIMAGIC "CL@MAG"
13+
14+
#define myfree(x) if(x!=NULL)free(x)
15+
16+
typedef unsigned short u16;
17+
18+
int main (int argc, char *argv[]) {
19+
FILE * pFile;
20+
long gcisize;
21+
long clisize;
22+
char * gcibuffer;
23+
char * clibuffer;
24+
size_t result;
25+
char *magic = CLIMAGIC;
26+
27+
char outpath[256];
28+
char clipath[256];
29+
30+
printf("\nCLI Embedder 0.1 by suloku 15'\n");
31+
printf("******************************\n\n");
32+
33+
if(argc != 2){
34+
printf("This program will embedd a cli file into a gci file created with dol2gci.\n\n");
35+
printf("Usage: cliembed.exe mydol.gci\n");
36+
printf(" or drag and drop to executable file\n");
37+
printf("\nCli file must have the same name and be in the same path as gci file:\n\tswiss.gci and swiss.cli");
38+
printf("\n\nPress enter to continue...");
39+
getchar();
40+
exit(-1);
41+
}
42+
43+
//Prepare
44+
strcpy(outpath, argv[1]);
45+
outpath[strlen(outpath)-4] = '\0';
46+
strcat(outpath, "-CLI.gci");
47+
48+
strcpy(clipath, argv[1]);
49+
clipath[strlen(clipath)-3] = '\0';
50+
strcat(clipath, "cli");
51+
52+
printf("Embedding %s into %s\n", clipath, argv[1]);
53+
printf("\nOutfile: %s\n\n", outpath);
54+
55+
//READ DOL
56+
pFile = fopen ( argv[1] , "rb" );
57+
if (pFile==NULL) {printf ("Can't open %s", argv[1]); printf("\n\nPress enter to continue..."); getchar(); exit (1);}
58+
// obtain file size:
59+
fseek (pFile , 0 , SEEK_END);
60+
gcisize = ftell (pFile);
61+
rewind (pFile);
62+
// allocate memory to contain the whole file:
63+
gcibuffer = (char*) malloc (sizeof(char)*gcisize);
64+
if (gcibuffer == NULL) {printf ("Memory error"); printf("\n\nPress enter to continue..."); getchar(); exit (2);}
65+
// copy the file into the buffer:
66+
result = fread (gcibuffer,1,gcisize,pFile);
67+
if (result != gcisize) {printf ("Reading error"); printf("\n\nPress enter to continue..."); getchar(); exit (3);}
68+
/* the whole file is now loaded in the memory buffer. */
69+
// terminate
70+
fclose (pFile);
71+
72+
//READ CLI
73+
pFile = fopen ( clipath , "rb" );
74+
if (pFile==NULL) {printf ("Can't open %s", clipath); printf("\n\nPress enter to continue..."); getchar(); exit (1);}
75+
76+
// obtain file size:
77+
fseek (pFile , 0 , SEEK_END);
78+
clisize = ftell (pFile);
79+
rewind (pFile);
80+
81+
// allocate memory to contain the whole file:
82+
clibuffer = (char*) malloc (sizeof(char)*clisize);
83+
if (clibuffer == NULL) {printf ("Memory error"); printf("\n\nPress enter to continue..."); getchar(); exit (2);}
84+
85+
// copy the file into the buffer:
86+
result = fread (clibuffer,1,clisize,pFile);
87+
if (result != clisize) {printf ("Reading error"); printf("\n\nPress enter to continue..."); getchar(); exit (3);}
88+
89+
/* the whole file is now loaded in the memory buffer. */
90+
91+
// terminate
92+
fclose (pFile);
93+
94+
printf ("GCI size: %d bytes (%d blocks)\n", (gcisize-GCIHEAD), !((gcisize-GCIHEAD)%BLOCK)?((gcisize-GCIHEAD)/BLOCK):((gcisize-GCIHEAD)/BLOCK)+1);
95+
printf ("Cli size: %d bytes\n", clisize);
96+
97+
long offset = 0;
98+
int i = 0;
99+
int found = 0;
100+
char padmagic = 0xCD;
101+
while(1){
102+
if (memcmp(&gcibuffer[offset], &padmagic, 1) == 0 ){
103+
//printf("Found pads at %d\n", offset);
104+
for (i=0; i<16*2;i++){
105+
if (memcmp(&gcibuffer[offset+i], &padmagic, 1) != 0){
106+
break;
107+
}
108+
}
109+
if (i==((16*2))) found = 1;
110+
}
111+
if (found) break;
112+
if (offset >= gcisize) break;
113+
offset++;
114+
}
115+
if(!found){
116+
printf("\nCan't find space (at least 32 0xCD bytes) to embed cli file!");
117+
printf("\nDo you want to add 1 block to your gci file? (y/n)");
118+
char c;
119+
120+
while (1){
121+
c=getchar();
122+
getchar();
123+
if (c=='y' || c=='Y'){
124+
break;
125+
}else if (c=='n' || c=='N'){
126+
printf("\n\nThis gci file doesn't have enough space to embed the cli file.\n\nPress enter to continue...");
127+
getchar(); exit (3);
128+
}
129+
}
130+
//User wants to fatten gci file to embed the cli file
131+
strcpy(outpath, argv[1]);
132+
outpath[strlen(outpath)-4] = '\0';
133+
strcat(outpath, "-fat.gci");
134+
printf("\n\nCreating padded gci file at %s\n", outpath);
135+
136+
//Create a pad block
137+
char* padding = (char*) malloc (sizeof(char)*BLOCK);
138+
memset (padding, 0xCD, BLOCK);
139+
//Update gci header to add one block
140+
u16 blocksize;
141+
memcpy(&blocksize,gcibuffer+0x38, 2);
142+
blocksize = be16(blocksize);
143+
blocksize = blocksize + 1;
144+
printf("New GCI blocksize: %d\n", blocksize);
145+
blocksize=be16(blocksize);
146+
memcpy(gcibuffer+0x38, &blocksize, 2);
147+
148+
//write fatted gci file
149+
pFile = fopen (outpath, "wb");
150+
if (pFile==NULL) {printf ("Can't open %s", outpath); printf("\n\nPress enter to continue..."); getchar(); exit (1);}
151+
int ret;
152+
ret = fwrite (gcibuffer , sizeof(char), gcisize, pFile);
153+
//printf ("Written = %d, expected %d\n", ret, gcisize);
154+
ret = fwrite (padding , sizeof(char), BLOCK, pFile);
155+
//printf ("Written = %d, expected %d\n", ret, BLOCK);
156+
fclose (pFile);
157+
printf("\n\n%s created! Now use that file with this program to embed the cli file. Remember that the cli file must have the same name as the gci file.\n\n Press enter to continue...", outpath);
158+
getchar();
159+
myfree(padding);
160+
myfree (gcibuffer);
161+
myfree (clibuffer);
162+
return 0;
163+
} else{
164+
printf("GCI pad starts at: %d\n", offset);
165+
printf("Padding size: %d\n", gcisize-offset);
166+
int remaining = (gcisize-offset)-clisize-strlen(magic)*2;
167+
printf("Remaining pad after embed: %d\n", remaining);
168+
169+
if( remaining <= 0){printf ("\nSorry, your CLI file can't fit in this gci file, it is %d bytes too big.", remaining*(-1)); printf("\n\nPress enter to continue..."); getchar(); exit (3);}
170+
171+
//add cli file to dol buffer
172+
173+
memcpy(gcibuffer+gcisize-clisize-strlen(magic)*2, magic, strlen(magic));
174+
memcpy(gcibuffer+gcisize-clisize-strlen(magic), clibuffer, clisize);
175+
memcpy(gcibuffer+gcisize-strlen(magic), magic, strlen(magic));
176+
177+
printf("Writing cli to gci file...\n");
178+
179+
pFile = fopen (outpath, "wb");
180+
if (pFile==NULL) {printf ("Can't open %s", outpath); printf("\n\nPress enter to continue..."); getchar(); exit (1);}
181+
fwrite (gcibuffer , sizeof(char), gcisize, pFile);
182+
fclose (pFile);
183+
}
184+
185+
myfree (gcibuffer);
186+
myfree (clibuffer);
187+
188+
printf("\nEmbedding complete! Press enter to continue...");
189+
getchar();
190+
return 0;
191+
}

mcloader/source/main.c

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <time.h>
88
#include "aram/sidestep.h"
99

10+
#define CLIMAGIC "CL@MAG"
11+
1012
/*** Memory File Buffer ***/
1113
//#define MAXFILEBUFFER (1024 * 2048) /*** 2MB Buffer ***/
1214
//u8 dolbuffer[MAXFILEBUFFER] ATTRIBUTE_ALIGN (32);
@@ -26,7 +28,6 @@ u32 first_frame = 1;
2628
GXRModeObj *rmode;
2729
void (*PSOreload)() = (void(*)())0x80001800;
2830

29-
3031
void waitA(){
3132
printf("Press A to continue\n");
3233
while (1){
@@ -41,6 +42,35 @@ void waitA(){
4142
}
4243
}
4344

45+
u8* cli_buffer;
46+
int cli_size;
47+
48+
void getclifrombuffer(u8* gcibuffer, int gcisize){
49+
//test code for retrieving CLI from gci buffer
50+
char *magic = CLIMAGIC;
51+
int offset = 0;
52+
if (memcmp (gcibuffer-strlen(magic), magic, strlen(magic))){
53+
printf ("Magic found\n");
54+
for(offset = 0; offset < gcisize; offset++){
55+
if (memcmp(&gcibuffer[offset], magic, strlen(magic)) == 0 ){
56+
printf("Found first magic at %d\n", offset);
57+
cli_size = gcisize-offset-strlen(magic)*2;
58+
printf("Cli size = %d\n", cli_size);
59+
break;
60+
}
61+
}
62+
63+
if (!(offset >= gcisize)){
64+
cli_buffer = (char *) malloc (sizeof(char)*cli_size+1); //+1 to be able to append terminating null character later
65+
memcpy (cli_buffer, gcibuffer+offset+strlen(magic), cli_size );
66+
}else{
67+
printf("No embeded cli found\n");
68+
cli_size = 0;
69+
cli_buffer = NULL;
70+
}
71+
}
72+
}
73+
4474
/*---------------------------------------------------------------------------------
4575
This function is called if a card is physically removed
4676
---------------------------------------------------------------------------------*/
@@ -127,7 +157,7 @@ int main() {
127157
tomenu=0;
128158
pressed = 0;
129159
printf("\x1b[2;0H");
130-
printf("Memory Card Loader 0.1 by Suloku\n");
160+
printf("Memory Card Loader 0.2 by Suloku\n");
131161
printf("********************************\n\n");
132162
printf("Press A or B button to select a slot.\n");
133163
while (1){
@@ -243,8 +273,48 @@ int main() {
243273
}
244274
CARD_Close(&CardFile);
245275
CARD_Unmount(slot);
246-
//boot dol
247-
DOLtoARAM(dolbuffer, 0, NULL);
276+
//boot dol
277+
//This will load cli_buffer and cli_size
278+
getclifrombuffer(dolbuffer, filesize);
279+
if (cli_buffer!=NULL){
280+
// Build a command line to pass to the DOL
281+
int argc2 = 0;
282+
char *argv2[1024];
283+
//add a terminating null character for last argument if needed
284+
if (cli_buffer[cli_size-1] != '\0'){
285+
cli_buffer[cli_size] = '\0';
286+
cli_size += 1;
287+
}
288+
289+
// CLI parse
290+
char bootpath[CARD_FILENAMELEN+10];
291+
sprintf(bootpath, "mc%d:/%s", slot, (char*)&CardList[listpos].filename);
292+
argv2[argc2] = bootpath;
293+
argc2++;
294+
// First argument is at the beginning of the file
295+
if(cli_buffer[0] != '\r' && cli_buffer[0] != '\n') {
296+
argv2[argc2] = cli_buffer;
297+
argc2++;
298+
}
299+
// Search for the others after each newline
300+
int i;
301+
for(i = 0; i < cli_size; i++) {
302+
if(cli_buffer[i] == '\r' || cli_buffer[i] == '\n') {
303+
cli_buffer[i] = '\0';
304+
}
305+
else if(cli_buffer[i - 1] == '\0') {
306+
argv2[argc2] = cli_buffer + i;
307+
argc2++;
308+
309+
if(argc2 >= 1024)
310+
break;
311+
}
312+
}
313+
DOLtoARAM(dolbuffer, argc2, argc2 == 0 ? NULL : argv2);
314+
}else{
315+
DOLtoARAM(dolbuffer, 0, NULL);
316+
}
317+
248318
//If we get here dol was invalid
249319
if(dolbuffer != NULL) free(dolbuffer);
250320
printf("Not a valid dol file.\n");

0 commit comments

Comments
 (0)