2 FUJITSU FM Towns Emulator 'eFMTowns'
4 Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
7 [FM-Towns CD-ROM : CLONECD PARSER]
11 #include "../../../fileio.h"
18 bool TOWNS_CDROM::open_ccd_file(const _TCHAR* file_path, _TCHAR* img_file_path)
20 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img"), get_file_path_without_extensiton(file_path));
22 if(!FILEIO::IsFileExisting(img_file_path)) {
23 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.gz"), get_file_path_without_extensiton(file_path));
24 if(!FILEIO::IsFileExisting(img_file_path)) {
25 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img.gz"), get_file_path_without_extensiton(file_path));
27 if(!FILEIO::IsFileExisting(img_file_path)) {
28 memset(img_file_path, 0x00, _MAX_PATH);
34 std::string line_buf_shadow;
35 std::string image_tmp_data_path;
37 _TCHAR full_path_ccd[_MAX_PATH];
38 memset(full_path_ccd, 0x00, sizeof(full_path_ccd));
39 image_tmp_data_path.clear();
41 get_long_full_path_name(file_path, full_path_ccd, sizeof(full_path_ccd));
42 // out_debug_log(_T("open_ccd_file(): file_path = %s / full_path_ccd = %s"), file_path, full_path_ccd);
43 const _TCHAR *parent_dir = get_parent_dir((const _TCHAR *)full_path_ccd);
44 std::map<std::string, int> ccd_phase;
45 std::map<std::string, int> ccd_enum;
48 ccd_phase.insert(std::make_pair("[ENTRY ", CCD_PHASE_ENTRY));
49 ccd_phase.insert(std::make_pair("[SESSION ", CCD_PHASE_SESSION));
50 ccd_phase.insert(std::make_pair("[TRACK ", CCD_PHASE_TRACK));
51 ccd_phase.insert(std::make_pair("[CLONECD] ", CCD_PHASE_CLONECD));
52 ccd_phase.insert(std::make_pair("[DISC] ", CCD_PHASE_DISC));
56 // Support AMin/ASec/AFrame and PMin/PSec/PFrame.
57 ccd_enum.insert(std::make_pair("POINT=", CCD_POINT));
58 ccd_enum.insert(std::make_pair("CONTROL=", CCD_CONTROL));
59 ccd_enum.insert(std::make_pair("PLBA=", CCD_PLBA));
60 ccd_enum.insert(std::make_pair("ALBA=", CCD_ALBA));
61 // Note: If ("INDEX 0" or "INDEX 1") has set, pregap may calculate from index0 and index1.Prefer than ALBA.
62 ccd_enum.insert(std::make_pair("INDEX 0=", CCD_INDEX_0));
63 ccd_enum.insert(std::make_pair("INDEX 1=", CCD_INDEX_1));
64 ccd_enum.insert(std::make_pair("MODE=", CCD_MODE));
67 // ToDo: Support DataTracksScrambled. OR, Will not support?
68 ccd_enum.insert(std::make_pair("TOCENTRIES=", CCD_TOC_ENTRIES));
69 ccd_enum.insert(std::make_pair("CDTEXTLENGTH=", CCD_CDTEXT_LENGTH));
72 ccd_enum.insert(std::make_pair("PREGAPMODE=", CCD_PREGAP_MODE));
73 ccd_enum.insert(std::make_pair("PREGAPSUBC=", CCD_PREGAP_SUBC));
77 int phase = CCD_PHASE_NULL;
78 int64_t cdtext_length = -1;
79 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
83 // get image file size
84 if((max_logical_block = fio_img->FileLength() / 2352) > 0) {
86 FILEIO* fio = new FILEIO();
87 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
89 for(int i = 0; i < 100; i++) {
90 memset(&(track_data_path[i][0]), 0x00, _MAX_PATH * sizeof(_TCHAR));
91 with_filename[i] = false;
93 for(int i = 0; i <= 100; i++) {
94 toc_table[i].type = MODE_MODE1_2352;
95 toc_table[i].index0 = 0;
96 toc_table[i].index1 = 0;
97 toc_table[i].pregap = 0;
98 toc_table[i].physical_size = 2352;
99 toc_table[i].logical_size = 2048;
104 bool have_filename = false;
106 int64_t phase_arg = 0;
109 int toc_entries = -1;
116 if((_c == '\0') || (_c == '\n') || (_c == EOF)) break;;
117 if(_c != '\r') line_buf.push_back((char)_c);
119 if(_c == EOF) is_eof = true;
120 int slen = (int)line_buf.length();
121 if(slen <= 0) goto _n_continue;
122 // Convert String to upper.
123 std::transform(line_buf.begin(), line_buf.end(), line_buf.begin(),
124 [](unsigned char c) -> unsigned char{ return std::toupper(c); });
125 // out_debug_log(_T("FILE_PATH=\"%s\" line=\"%s\""), file_path, line_buf.c_str());
129 if(line_buf[0] == '[') {
131 int tmp_phase = CCD_PHASE_NULL;
132 std::string token = line_buf;
133 size_t ptr1 = line_buf.find_first_of(" ");
134 size_t ptr2 = line_buf.find_first_of("]");
136 if(ptr1 != std::string::npos) {
137 size_t ptr3 = line_buf.find_last_of("]");
138 if(ptr3 != std::string::npos) {
139 token.resize(ptr1 + 1);
141 arg2 = line_buf.substr(ptr1 + 1, (ptr3 - (ptr1 + 1)));
142 } catch (std::out_of_range &e) {
147 } else if(ptr2 != std::string::npos) {
148 token.resize(ptr2 + 1);
152 tmp_phase = ccd_phase.at(token);
153 } catch (std::out_of_range &e) {
154 tmp_phase = CCD_PHASE_NULL;
156 // ToDo: exception handling for CCD_NULL
157 if(tmp_phase != CCD_PHASE_NULL) {
160 // out_debug_log(_T("open_ccd_file(): file_path = %s / full_path_ccd = %s"), file_path, full_path_ccd);
162 case CCD_PHASE_ENTRY:
163 phase_arg = string_to_numeric(arg2);
164 if((phase_arg != entry_num) && (phase_arg > 0)) {
166 entry_num = phase_arg;
167 //calc_track_index(_track);
170 case CCD_PHASE_SESSION:
171 phase_arg = string_to_numeric(arg2);
173 case CCD_PHASE_TRACK:
174 phase_arg = string_to_numeric(arg2);
175 if((phase_arg > 0) && (phase_arg <= 100)) {
176 if(_track != phase_arg) {
178 if(track_num <= _track) {
179 track_num = _track + 1;
190 int local_type = CCD_TYPE_NULL;
191 std::string token = line_buf;
192 size_t ptr1 = token.find_first_of("=");
193 std::string arg2 = "";
194 if(ptr1 != std::string::npos) { // OK
195 token.resize(ptr1 + 1);
197 local_type = ccd_enum.at(token);
198 } catch (std::out_of_range &e) {
199 local_type = CCD_TYPE_NULL;
202 arg2 = line_buf.substr(ptr1 + 1, line_buf.size());
203 } catch (std::out_of_range &e) {
208 if(local_type != CCD_TYPE_NULL) {
209 arg_val = string_to_numeric(arg2);
212 case CCD_PHASE_SESSION:
214 // ToDo: Imprement around pregap.
218 case CCD_TOC_ENTRIES:
219 toc_entries = arg_val;
221 case CCD_CDTEXT_LENGTH:
222 cdtext_length = arg_val;
226 case CCD_PHASE_ENTRY:
229 // Point -> Track num
244 if((arg_val >= 0) && (arg_val <= 100)) {
245 if(arg_val != _track) {
246 //recalc_track_index(_track);
248 if(track_num <= _track) {
249 track_num = _track + 1;
258 if((_track >= 0) && (_track <= 100)) {
261 toc_table[_track].type = MODE_AUDIO;
262 toc_table[_track].is_audio = true;
263 toc_table[_track].logical_size = 2352;
266 toc_table[_track].type = MODE_MODE1_2352;
267 toc_table[_track].is_audio = false;
268 toc_table[_track].logical_size = 2048;
270 // ToDo: another types.
275 // PLBA -> LBA POSITION
276 if((_track >= 0) && (_track <= 100)) {
277 toc_table[_track].index1 = arg_val;
282 if((_track >= 0) && (_track <= 100)) {
283 toc_table[_track].pregap = -arg_val;
288 if((_track >= 0) && (_track <= 100)) {
289 toc_table[_track].index0 = arg_val;
290 toc_table[_track].pregap = 0;
295 if((_track > 0) && (_track <= 100)) {
296 toc_table[_track].index1 = arg_val;
297 toc_table[_track].pregap = 0;
302 case CCD_PHASE_TRACK:
306 if((_track >= 0) && (_track <= 100)) {
307 toc_table[_track].index0 = arg_val;
308 toc_table[_track].pregap = 0;
313 if((_track > 0) && (_track <= 100)) {
314 toc_table[_track].index1 = arg_val;
315 toc_table[_track].pregap = 0;
320 if((_track >= 0) && (_track <= 100)) {
322 case 1: // MODE1/2352
323 toc_table[_track].type = MODE_MODE1_2352;
324 toc_table[_track].is_audio = false;
325 toc_table[_track].logical_size = 2048;
328 toc_table[_track].type = MODE_AUDIO;
329 toc_table[_track].is_audio = true;
330 toc_table[_track].logical_size = 2352;
343 toc_table[0].lba_offset = 0;
344 toc_table[0].lba_size = 0;
345 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
349 // max_logical_block = toc_table[track_num - 1].index1; // PLBA
350 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
351 toc_table[track_num].lba_offset = max_logical_block;
352 toc_table[track_num].lba_size = 0;
353 for(int i = 1; i < track_num; i++) {
354 if(toc_table[i].index0 == 0) {
355 toc_table[i].index0 = toc_table[i].index1;
357 if(toc_table[i].pregap == 0) {
358 toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
360 if(toc_table[i].pregap <= 150) {
361 toc_table[i].pregap = 150; // Default PREGAP must be 2Sec. From OoTake.(Only with PCE? Not with FM-Towns?)
363 if(toc_table[i].index0 == toc_table[i].index1) {
364 toc_table[i].index0 = toc_table[i].index1 - toc_table[i].pregap;
366 if(toc_table[i].index0 <= 0) {
367 toc_table[i].index0 = 0;
369 toc_table[i].lba_offset = 0;
370 toc_table[i].lba_size = toc_table[i + 1].index1 - toc_table[i].index0;
373 // if((track_num == 2) && (max_logical_block > 0)) {
374 // toc_table[track_num - 1].lba_size -= 1;
375 // max_logical_block--;
378 // ToDo: Will fix brakes insize of *file_ptr . 20230217 K.O
380 for(int i = 1; i < track_num; i++) {
381 // toc_table[i].index0 += toc_table[i].lba_offset;
382 // toc_table[i].index1 += toc_table[i].lba_offset;
384 out_debug_log(_T("TRACK#%d TYPE=%s PREGAP=%d INDEX0=%d INDEX1=%d LBA_SIZE=%d LBA_OFFSET=%d"),
386 i, ((toc_table[i].is_audio) ? _T("AUDIO") : _T("MODE1/2352")),
387 toc_table[i].pregap, toc_table[i].index0, toc_table[i].index1,
388 toc_table[i].lba_size, toc_table[i].lba_offset);
392 // out_debug_log(_T("open_ccd_file(): track_num = %d file_path = %s / full_path_ccd = %s"), track_num, file_path, full_path_ccd);
406 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
410 // get image file size
411 if((max_logical_block = fio_img->FileLength() / 2352) > 0) {
413 FILEIO* fio = new FILEIO();
414 if(fio->Fopen(file_path, FILEIO_READ_ASCII)) {
415 char line[1024] = {0};
418 while(fio->Fgets(line, 1024) != NULL) {
419 if(strstr(line, "[Session ") != NULL) {
421 } else if((ptr = strstr(line, "Point=0x")) != NULL) {
422 if((track = hexatoi(ptr + 8)) > 0 && track < 0xa0) {
423 if(((track + 1) > track_num) && (track <= 100)) {
424 track_num = track + 1;
427 } else if((ptr = strstr(line, "Control=0x")) != NULL) {
428 if(track > 0 && track <= 100) {
429 toc_table[track].is_audio = (hexatoi(ptr + 10) != 4);
431 } else if((ptr = strstr(line, "ALBA=-")) != NULL) {
432 if(track > 0 && track <= 100) {
433 toc_table[track].pregap = atoi(ptr + 6);
435 } else if((ptr = strstr(line, "PLBA=")) != NULL) {
436 if(track > 0 && track <= 100) {
437 toc_table[track + 1].index0 = atoi(ptr + 5);
439 } else if((ptr = strstr(line, "[TRACK ")) != NULL) {
441 if((ptr2 = strstr(ptr + 7, "]")) != NULL) {
442 uintptr_t n = (uintptr_t)ptr2;
443 uintptr_t m = (uintptr_t)ptr;
446 char numbuf[3] = {0};
447 strncpy(numbuf, ptr + 7, (size_t)n);
448 track = atoi(numbuf);
449 if(((track + 1) > track_num) && (track <= 100)) {
450 track_num = track + 1;
453 } else if((ptr = strstr(line, "INDEX 0=")) != NULL) {
454 if(track > 0 && track <= 100) {
455 toc_table[track].index0 = atoi(ptr + 8);
457 } else if((ptr = strstr(line, "INDEX 1=")) != NULL) {
458 if(track > 0 && track <= 100) {
459 toc_table[track].index1 = atoi(ptr + 8);
461 } else if((ptr = strstr(line, "MODE=")) != NULL) {
462 if(track > 0 && track <= 100) {
464 mode = atoi(ptr + 5);
467 toc_table[track].type = MODE_AUDIO;
468 toc_table[track].is_audio = true;
469 toc_table[track].logical_size = 2352;
472 toc_table[track].type = MODE_MODE1_2352;
473 toc_table[track].is_audio = false;
474 toc_table[track].logical_size = 2048;
477 toc_table[track].type = MODE_MODE2_2336;
478 toc_table[track].is_audio = false;
479 toc_table[track].logical_size = 2336;
482 toc_table[track].type = MODE_AUDIO;
483 toc_table[track].is_audio = true;
484 toc_table[track].logical_size = 2352;
490 toc_table[0].lba_offset = 0;
491 toc_table[0].lba_size = 0;
492 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
493 toc_table[0].physical_size = 0;
494 toc_table[0].logical_size = 0;
496 if(track_num > 100) track_num = 101;
497 for(int i = 1; i < track_num; i++) {
499 toc_table[i].physical_size = 2352;
501 if(toc_table[i].index0 == 0) {
502 toc_table[i].index0 = toc_table[i].index1;
504 if(toc_table[i].pregap == 0) {
505 toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
507 if(toc_table[i].pregap <= 150) toc_table[i].pregap = 150;
509 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
510 for(int i = 1; i < track_num; i++) {
511 toc_table[i].lba_offset = toc_table[i].index1;
512 toc_table[i].lba_size = toc_table[i + 1].index1 - toc_table[i].index1;
513 if(toc_table[i].lba_size > 0) toc_table[i].lba_size -= 1;
515 toc_table[track_num].lba_size = 0;
516 toc_table[track_num].physical_size = 0;
517 toc_table[track_num].logical_size = 0;