2 FUJITSU FM Towns Emulator 'eFMTowns'
4 Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
7 [FM-Towns CD-ROM : CUE PARSER]
11 #include "../../../fileio.h"
27 bool TOWNS_CDROM::open_cue_file(const _TCHAR* file_path)
30 std::string line_buf_shadow;
31 std::string image_tmp_data_path;
33 _TCHAR full_path_cue[_MAX_PATH];
37 int nr_current_track = 0;
38 FILEIO* fio = new FILEIO();
39 if(fio == NULL) return false;
41 memset(full_path_cue, 0x00, sizeof(full_path_cue));
42 image_tmp_data_path.clear();
44 get_long_full_path_name(file_path, full_path_cue, sizeof(full_path_cue));
46 const _TCHAR *parent_dir = get_parent_dir((const _TCHAR *)full_path_cue);
58 std::map<std::string, int> cue_enum;
61 cue_enum.insert(std::make_pair("REM", CUE_REM));
62 cue_enum.insert(std::make_pair("FILE", CUE_FILE));
63 cue_enum.insert(std::make_pair("TRACK", CUE_TRACK));
64 cue_enum.insert(std::make_pair("INDEX", CUE_INDEX));
65 cue_enum.insert(std::make_pair("PREGAP", CUE_PREGAP));
68 if(fio->Fopen(file_path, FILEIO_READ_ASCII)) { // ToDo: Support not ASCII cue file (i.e. SJIS/UTF8).20181118 K.O
70 for(int i = 0; i < 100; i++) {
71 memset(&(track_data_path[i][0]), 0x00, _MAX_PATH * sizeof(_TCHAR));
72 with_filename[i] = false;
77 bool have_filename = false;
85 if((_c == '\0') || (_c == '\n') || (_c == EOF)) break;;
86 if(_c != '\r') line_buf.push_back((char)_c);
88 if(_c == EOF) is_eof = true;
89 slen = (int)line_buf.length();
90 if(slen <= 0) goto _n_continue;
91 // Trim head of Space or TAB
99 ptr = line_buf.find_first_not_of((const char*)" \t");
100 if(ptr == std::string::npos) {
104 line_buf_shadow = line_buf.substr(ptr);
106 _arg1_ptr = line_buf_shadow.find_first_of((const char *)" \t");
107 _arg1 = line_buf_shadow.substr(0, _arg1_ptr);
108 _arg2 = line_buf_shadow.substr(_arg1_ptr);
109 std::transform(_arg1.begin(), _arg1.end(), _arg1.begin(),
110 [](unsigned char c) -> unsigned char{ return std::toupper(c); });
112 _arg2_ptr = _arg2.find_first_not_of((const char *)" \t");
114 if(_arg2_ptr != std::string::npos) {
115 _arg2 = _arg2.substr(_arg2_ptr);
119 typeval = cue_enum.at(_arg1);
120 } catch (std::out_of_range &e) {
128 if(!(parse_cue_file_args(_arg2, parent_dir, image_tmp_data_path))) break;
129 with_filename[nr_current_track + 1] = true;
134 parse_cue_track(_arg2, nr_current_track, image_tmp_data_path);
138 parse_cue_index(_arg2, nr_current_track);
141 if((nr_current_track > 0) && (nr_current_track < 100)) {
142 _arg2_ptr_s = _arg2.find_first_of((const char *)" \t");
143 _arg2 = _arg2.substr(0, _arg2_ptr_s - 1);
145 toc_table[nr_current_track].pregap = get_frames_from_msf(_arg2.c_str());
155 max_logical_block = 0;
156 uint32_t pt_lba_ptr = 0;
158 toc_table[0].lba_offset = 0;
159 toc_table[0].lba_size = 0;
160 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
164 for(int i = 1; i < track_num; i++) {
166 if(fio_img->IsOpened()) {
170 //if(toc_table[i].pregap <= 0) {
171 // toc_table[i].pregap = 150; // Default PREGAP must be 2Sec. From OoTake.(Only with PCE? Not with FM-Towns?)
173 if((strlen(track_data_path[i - 1]) > 0) && (with_filename[i])) {
174 if(fio_img->Fopen(track_data_path[i - 1], FILEIO_READ_BINARY)) {
175 if((_n = fio_img->FileLength() / physical_block_size()) > 0) {
176 max_logical_block += _n;
182 toc_table[i].lba_size = _n;
184 toc_table[i].lba_offset = max_logical_block - _n;
185 if(!(with_filename[i + 1]) && (toc_table[i + 1].index1 > toc_table[i].index1)) {
186 toc_table[i].lba_size = toc_table[i + 1].index1 - toc_table[i].index0;
188 if(toc_table[i].index0 == 0) {
189 toc_table[i].index0 = toc_table[i].index1;
191 if(toc_table[i].pregap == 0) {
192 toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
195 if(toc_table[i].pregap <= 150) {
196 toc_table[i].pregap = 150; // Default PREGAP must be 2Sec. From OoTake.(Only with PCE? Not with FM-Towns?)
199 if((track_num == 2) && (max_logical_block > 0)) {
200 toc_table[track_num - 1].lba_size -= 1;
203 for(int i = 1; i < track_num; i++) {
204 toc_table[i].index0 += toc_table[i].lba_offset;
205 toc_table[i].index1 += toc_table[i].lba_offset;
207 out_debug_log(_T("TRACK#%02d TYPE=%s PREGAP=%d INDEX0=%d INDEX1=%d LBA_SIZE=%d LBA_OFFSET=%d PATH=%s\n"),
208 i, (toc_table[i].is_audio) ? _T("AUDIO") : _T("MODE1/2352"),
209 toc_table[i].pregap, toc_table[i].index0, toc_table[i].index1,
210 toc_table[i].lba_size, toc_table[i].lba_offset, track_data_path[i - 1]);
213 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
214 toc_table[0].physical_size = 2352;
215 toc_table[0].logical_size = 2048;
216 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
217 toc_table[track_num].lba_offset = max_logical_block;
218 toc_table[track_num].lba_size = 0;
225 if(track_num > 0) is_cue = true;
230 bool TOWNS_CDROM::parse_cue_file_args(std::string& _arg2, const _TCHAR *parent_dir, std::string& imgpath)
236 _arg2_ptr = _arg2.find_first_of((const char *)"\"") + 1;
237 if(_arg2_ptr == std::string::npos) return false;
239 _arg2 = _arg2.substr(_arg2_ptr);
240 _arg3_ptr = _arg2.find_first_of((const char *)"\"");
241 if(_arg3_ptr == std::string::npos) return false;
242 _arg2 = _arg2.substr(0, _arg3_ptr);
245 imgpath = std::string(parent_dir);
246 imgpath.append(_arg2);
248 // cdrom_debug_log(_T("**FILE %s\n"), imgpath.c_str());
253 void TOWNS_CDROM::parse_cue_track(std::string &_arg2, int& nr_current_track, std::string imgpath)
257 _arg2_ptr_s = _arg2.find_first_of((const char *)" \t");
259 std::string _arg3 = _arg2.substr(_arg2_ptr_s);
260 _arg2 = _arg2.substr(0, _arg2_ptr_s);
261 size_t _arg3_ptr = _arg3.find_first_not_of((const char *)" \t");
263 int _nr_num = atoi(_arg2.c_str());
266 if((_nr_num > 0) && (_nr_num < 100) && (_arg3_ptr != std::string::npos)) {
267 std::map<std::string, int> cue_type;
268 cue_type.insert(std::make_pair("AUDIO", MODE_AUDIO));
269 cue_type.insert(std::make_pair("MODE1/2048", MODE_MODE1_2048));
270 cue_type.insert(std::make_pair("MODE1/2352", MODE_MODE1_2352));
271 cue_type.insert(std::make_pair("MODE2/2336", MODE_MODE2_2336));
272 cue_type.insert(std::make_pair("MODE2/2352", MODE_MODE2_2352));
273 cue_type.insert(std::make_pair("CDI/2336", MODE_CDI_2336));
274 cue_type.insert(std::make_pair("CDI/2352", MODE_CDI_2352));
275 cue_type.insert(std::make_pair("CDG", MODE_CD_G));
277 nr_current_track = _nr_num;
278 _arg3 = _arg3.substr(_arg3_ptr);
280 memset(track_data_path[_nr_num - 1], 0x00, sizeof(_TCHAR) * _MAX_PATH);
281 strncpy((char *)(track_data_path[_nr_num - 1]), imgpath.c_str(), _MAX_PATH - 1);
282 // image_tmp_data_path.clear();
283 // with_filename[_nr_num - 1] = have_filename;
284 // have_filename = false;
285 _arg3_ptr_s = _arg3.find_first_of((const char *)" \t\n");
286 _arg3.substr(0, _arg3_ptr_s);
288 std::transform(_arg3.begin(), _arg3.end(), _arg3.begin(),
289 [](unsigned char c) -> unsigned char{ return std::toupper(c); });
291 toc_table[nr_current_track].is_audio = false;
292 toc_table[nr_current_track].index0 = 0;
293 toc_table[nr_current_track].index1 = 0;
294 toc_table[nr_current_track].pregap = 0;
295 toc_table[nr_current_track].physical_size = 2352;
296 toc_table[nr_current_track].logical_size = 2048;
299 track_type = cue_type.at(_arg3);
300 } catch (std::out_of_range &e) {
301 track_type = MODE_NONE;
303 toc_table[nr_current_track].type = track_type;
307 toc_table[nr_current_track].is_audio = true;
308 toc_table[nr_current_track].logical_size = 2352;
310 case MODE_MODE1_2048:
311 toc_table[nr_current_track].logical_size = 2048;
312 toc_table[nr_current_track].physical_size = 2048;
314 case MODE_MODE1_2352:
315 toc_table[nr_current_track].logical_size = 2048;
317 case MODE_MODE2_2336:
318 toc_table[nr_current_track].logical_size = 2336;
319 toc_table[nr_current_track].physical_size = 2336;
321 case MODE_MODE2_2352:
322 toc_table[nr_current_track].logical_size = 2336;
325 toc_table[nr_current_track].logical_size = 2336;
326 toc_table[nr_current_track].physical_size = 2336;
329 toc_table[nr_current_track].logical_size = 2336;
332 toc_table[nr_current_track].logical_size = 2448;
333 toc_table[nr_current_track].physical_size = 2448;
335 // ToDo: Set data size.
337 if(track_num < (_nr_num + 1)) track_num = _nr_num + 1;
339 // ToDo: 20181118 K.Ohta
340 nr_current_track = 0;
345 int TOWNS_CDROM::parse_cue_index(std::string &_arg2, int nr_current_track)
352 if((nr_current_track > 0) && (nr_current_track < 100)) {
353 _arg2_ptr_s = _arg2.find_first_of((const char *)" \t");
354 if(_arg2_ptr_s == std::string::npos) return -1;;
356 _arg3 = _arg2.substr(_arg2_ptr_s);
357 _arg2 = _arg2.substr(0, _arg2_ptr_s);
358 _arg3_ptr = _arg3.find_first_not_of((const char *)" \t");
359 if(_arg3_ptr == std::string::npos) return -1;
361 _arg3 = _arg3.substr(_arg3_ptr);
362 _arg3_ptr_s = _arg3.find_first_of((const char *)" \t");
363 _arg3.substr(0, _arg3_ptr_s);
364 index = atoi(_arg2.c_str());
368 toc_table[nr_current_track].index0 = get_frames_from_msf(_arg3.c_str());
371 toc_table[nr_current_track].index1 = get_frames_from_msf(_arg3.c_str());