@@ -32,9 +32,11 @@ static void storeU32(uint32_t value, uint8_t* buffer) {
32
32
buffer[3 ] = (value >> 24 ) & 0xff ;
33
33
}
34
34
35
- // make sure to call this with a sector that's memset to 0
36
- static void getSector (uint8_t data[2048 ], uint32_t lba, uint32_t exeSize, uint32_t exeOffset = 19 ) {
35
+ // make sure to call this with a sector that's memset to 0, as it relies on zeros being
36
+ // in the right place.
37
+ static void getSectorMinimal (uint8_t data[2048 ], uint32_t lba, uint32_t exeSize, uint32_t exeOffset = 19 ) {
37
38
switch (lba) {
39
+ // Minimal PVD
38
40
case 16 :
39
41
data[0 ] = 1 ;
40
42
data[1 ] = ' C' ;
@@ -46,11 +48,13 @@ static void getSector(uint8_t data[2048], uint32_t lba, uint32_t exeSize, uint32
46
48
storeU32 (17 , data + 140 );
47
49
storeU32 (18 , data + 158 );
48
50
break ;
51
+ // Minimal path table
49
52
case 17 :
50
53
data[0 ] = 1 ;
51
54
data[2 ] = 18 ;
52
55
data[6 ] = 1 ;
53
56
break ;
57
+ // Minimal root directory
54
58
case 18 :
55
59
data[0 ] = 42 ;
56
60
storeU32 (exeOffset, data + 2 );
@@ -69,16 +73,20 @@ static void getSector(uint8_t data[2048], uint32_t lba, uint32_t exeSize, uint32
69
73
}
70
74
}
71
75
72
- // make sure to call this with a sector that's memset to 0, as it relies on zeros being
73
- // in the right place.
74
- static void makeHeader (uint8_t sector[2352 ], uint32_t lba) {
75
- PCSX::IEC60908b::MSF time (lba + 150 );
76
+ // Call this once on a sector that's been memset to 0,
77
+ // in order to set all of the immutable data.
78
+ static void makeHeaderOnce (uint8_t sector[2352 ]) {
76
79
memset (sector + 1 , 0xff , 10 );
77
- time .toBCD (sector + 12 );
78
80
sector[15 ] = 2 ;
79
81
sector[18 ] = sector[22 ] = 8 ;
80
82
}
81
83
84
+ // This function sets the LBA in the header of the sector.
85
+ static void makeHeader (uint8_t sector[2352 ], uint32_t lba) {
86
+ PCSX::IEC60908b::MSF time (lba + 150 );
87
+ time .toBCD (sector + 12 );
88
+ }
89
+
82
90
int main (int argc, char ** argv) {
83
91
CommandLine::args args (argc, argv);
84
92
@@ -96,12 +104,14 @@ exe2iso by Nicolas "Pixel" Noble
96
104
const bool pad = args.get <bool >(" pad" ).value_or (false );
97
105
const bool regen = args.get <bool >(" regen" ).value_or (false );
98
106
const auto license = args.get <std::string>(" license" );
107
+ const auto data = args.get <std::string>(" data" );
99
108
if (asksForHelp || !oneInput || !hasOutput) {
100
109
fmt::print (R"(
101
110
Usage: {} input.ps-exe [-offset value] [-pad] [-regen] [-license file] -o output.bin
102
111
input.ps-exe mandatory: specify the input ps-exe file.
103
112
-o output.bin mandatory: name of the output file.
104
113
-offset value optional: move the exe data by value sectors.
114
+ -data filename optional: insert this file into the iso after the exe.
105
115
-pad optional: pads the iso with 150 blank sectors.
106
116
-regen optional: generates proper ECC/EDC.
107
117
-license file optional: use this license file.
@@ -114,17 +124,29 @@ Usage: {} input.ps-exe [-offset value] [-pad] [-regen] [-license file] -o output
114
124
auto & input = inputs[0 ];
115
125
PCSX::IO<PCSX::File> file (new PCSX::PosixFile (input));
116
126
if (file->failed ()) {
117
- fmt::print (" Unable to open file: {}\n " , input);
127
+ fmt::print (" Error opening input file {}\n " , input);
118
128
return -1 ;
119
129
}
120
130
PCSX::IO<PCSX::File> licenseFile (new PCSX::FailedFile);
131
+ PCSX::IO<PCSX::File> dataFile (new PCSX::FailedFile);
121
132
PCSX::IO<PCSX::File> out (new PCSX::PosixFile (output.value (), PCSX::FileOps::TRUNCATE));
122
133
if (out->failed ()) {
123
134
fmt::print (" Error opening output file {}\n " , output.value ());
124
135
return -1 ;
125
136
}
126
137
if (license.has_value ()) {
127
138
licenseFile.setFile (new PCSX::PosixFile (license.value ()));
139
+ if (licenseFile->failed ()) {
140
+ fmt::print (" Error opening license file {}\n " , license.value ());
141
+ return -1 ;
142
+ }
143
+ }
144
+ if (data.has_value ()) {
145
+ dataFile.setFile (new PCSX::PosixFile (data.value ()));
146
+ if (dataFile->failed ()) {
147
+ fmt::print (" Error opening data file {}\n " , data.value ());
148
+ return -1 ;
149
+ }
128
150
}
129
151
130
152
uint32_t exeSize = file->size ();
@@ -134,77 +156,80 @@ Usage: {} input.ps-exe [-offset value] [-pad] [-regen] [-license file] -o output
134
156
uint32_t exeOffset = 19 + offset;
135
157
136
158
uint8_t sector[2352 ];
159
+ memset (sector, 0 , sizeof (sector));
160
+ makeHeaderOnce (sector);
137
161
bool wroteLicense = false ;
162
+ unsigned LBA = 0 ;
163
+ auto writeSector = [&]() {
164
+ makeHeader (sector, LBA++);
165
+ if (regen) compute_edcecc (sector);
166
+ out->write (sector, sizeof (sector));
167
+ };
138
168
// Sectors 0-15 are the license. We can keep it to zeroes and it'll work most everywhere.
139
169
if (licenseFile && !licenseFile->failed ()) {
140
170
uint8_t licenseData[2352 * 16 ];
141
171
memset (licenseData, 0 , sizeof (licenseData));
142
172
licenseFile->read (licenseData, sizeof (licenseData));
143
- if (licenseData[0x2492 ] == ' L' ) {
173
+ if ((licenseFile-> size () == 2336 * 16 ) && ( licenseData[0x2492 ] == ' L' ) ) {
144
174
// official license file from the sdk, in 2336 bytes per sector.
145
175
for (unsigned i = 0 ; i < 16 ; i++) {
146
- memset (sector, 0 , sizeof (sector));
147
176
memcpy (sector + 16 , licenseData + 2336 * i, 2336 );
148
- makeHeader (sector, i);
149
- if (regen) compute_edcecc (sector);
150
- out->write (sector, sizeof (sector));
177
+ writeSector ();
151
178
}
152
179
wroteLicense = true ;
153
180
} else if (licenseData[0x24e2 ] == ' L' ) {
154
181
// looks like an iso file itself
155
182
for (unsigned i = 0 ; i < 16 ; i++) {
156
183
memcpy (sector, licenseData + 2352 * i, 2352 );
157
- makeHeader (sector, i);
158
- if (regen) compute_edcecc (sector);
159
- out->write (sector, sizeof (sector));
184
+ makeHeaderOnce (sector);
185
+ writeSector ();
160
186
}
161
187
wroteLicense = true ;
162
188
} else {
163
189
fmt::print (" Unrecognized LICENSE file format {}\n " , output.value ());
164
190
}
165
191
}
166
192
if (!wroteLicense) {
193
+ memset (sector, 0 , sizeof (sector));
167
194
for (unsigned i = 0 ; i < 16 ; i++) {
168
- memset (sector, 0 , sizeof (sector));
169
- makeHeader (sector, i);
170
- if (regen) compute_edcecc (sector);
171
- out->write (sector, sizeof (sector));
195
+ writeSector ();
172
196
}
173
197
}
174
198
// The actual structure of the iso. We're only generating 3 sectors,
175
199
// from 16 to 18, as it's the only things necessary for the PS1 bios.
176
- for (unsigned i = 16 ; i < 19 ; i++) {
200
+ for (unsigned i = 0 ; i < 3 ; i++) {
177
201
memset (sector, 0 , sizeof (sector));
178
- makeHeader (sector, i );
202
+ makeHeaderOnce (sector);
179
203
// This function will fill the sector with the right data, as
180
204
// necessary for the PS1 bios.
181
- getSector (sector + 24 , i, exeSize, exeOffset);
182
- if (regen) compute_edcecc (sector);
183
- out->write (sector, sizeof (sector));
205
+ getSectorMinimal (sector + 24 , LBA, exeSize, exeOffset);
206
+ writeSector ();
184
207
}
185
208
// Potential padding before the start of the exe.
186
- for (unsigned i = 19 ; i < exeOffset; i++) {
187
- memset (sector, 0 , sizeof (sector));
188
- makeHeader (sector, i);
189
- if (regen) compute_edcecc (sector);
190
- out->write (sector, sizeof (sector));
209
+ memset (sector, 0 , sizeof (sector));
210
+ makeHeaderOnce (sector);
211
+ for (unsigned i = 0 ; i < offset; i++) {
212
+ writeSector ();
191
213
}
192
- unsigned LBA = exeOffset;
193
214
// The actual exe.
194
215
for (unsigned i = 0 ; i < exeSize; i += 2048 ) {
195
- memset (sector, 0 , sizeof (sector));
196
- makeHeader (sector, LBA++);
197
216
file->read (sector + 24 , 2048 );
198
- if (regen) compute_edcecc (sector);
199
- out->write (sector, sizeof (sector));
217
+ writeSector ();
218
+ }
219
+ if (dataFile && !dataFile->failed ()) {
220
+ // The additional data file.
221
+ unsigned sectors = (dataFile->size () + 2047 ) / 2048 ;
222
+ for (unsigned i = 0 ; i < sectors; i++) {
223
+ dataFile->read (sector + 24 , 2048 );
224
+ writeSector ();
225
+ }
200
226
}
227
+ memset (sector, 0 , sizeof (sector));
228
+ makeHeaderOnce (sector);
201
229
if (pad) {
202
230
// 150 sectors padding.
203
231
for (unsigned i = 0 ; i < 150 ; i++) {
204
- memset (sector, 0 , sizeof (sector));
205
- makeHeader (sector, LBA++);
206
- if (regen) compute_edcecc (sector);
207
- out->write (sector, sizeof (sector));
232
+ writeSector ();
208
233
}
209
234
}
210
235
fmt::print (" Done." );
0 commit comments