OSDN Git Service

[UI][Qt][OSD][LOG] CDROM: May works with new messaging framework.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / cdrom / cdrom_cue_parser.cpp
1 /*
2         FUJITSU FM Towns Emulator 'eFMTowns'
3
4         Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2019.01.31 -
6
7         [FM-Towns CD-ROM : CUE PARSER]
8 */
9
10 #include "../cdrom.h"
11 #include "../../../fileio.h"
12
13 #include <string>
14 #include <map>
15
16 namespace FMTOWNS {
17
18 enum {
19         CUE_NONE = 0,
20         CUE_REM,
21         CUE_FILE,
22         CUE_TRACK,
23         CUE_INDEX,
24         CUE_PREGAP,
25 };
26
27 bool TOWNS_CDROM::open_cue_file(const _TCHAR* file_path)
28 {
29         std::string line_buf;
30         std::string line_buf_shadow;
31         std::string image_tmp_data_path;
32
33         _TCHAR full_path_cue[_MAX_PATH];
34         size_t ptr;
35         int line_count = 0;
36         int slen;
37         int nr_current_track = 0;
38         FILEIO* fio = new FILEIO();
39         if(fio == NULL) return false;
40
41         memset(full_path_cue, 0x00, sizeof(full_path_cue));
42         image_tmp_data_path.clear();
43
44         get_long_full_path_name(file_path, full_path_cue, sizeof(full_path_cue));
45
46         const _TCHAR *parent_dir = get_parent_dir((const _TCHAR *)full_path_cue);
47
48         size_t _arg1_ptr;
49         size_t _arg2_ptr;
50         size_t _arg2_ptr_s;
51         size_t _arg3_ptr;
52         size_t _arg3_ptr_s;
53
54         std::string _arg1;
55         std::string _arg2;
56         std::string _arg3;
57
58         std::map<std::string, int> cue_enum;
59
60         // Initialize
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));
66
67
68         if(fio->Fopen(file_path, FILEIO_READ_ASCII)) { // ToDo: Support not ASCII cue file (i.e. SJIS/UTF8).20181118 K.O
69                 line_buf.clear();
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;
73                 }
74                 int _c;
75                 bool is_eof = false;
76                 int sptr = 0;
77                 bool have_filename = false;
78 //              int _nr_num = 0;
79                 while(1) {
80                         line_buf.clear();
81                         int _np = 0;
82                         _c = EOF;
83                         do {
84                                 _c = fio->Fgetc();
85                                 if((_c == '\0') || (_c == '\n') || (_c == EOF)) break;;
86                                 if(_c != '\r') line_buf.push_back((char)_c);
87                         } while(1);
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
92                         ptr = 0;
93                         sptr = 0;
94                         // Tokenize
95                         _arg1.clear();
96                         _arg2.clear();
97                         _arg3.clear();
98
99                         ptr = line_buf.find_first_not_of((const char*)" \t");
100                         if(ptr == std::string::npos) {
101                                 goto _n_continue;
102                         }
103                         // Token1
104                         line_buf_shadow = line_buf.substr(ptr);
105
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); });
111
112                         _arg2_ptr = _arg2.find_first_not_of((const char *)" \t");
113
114                         if(_arg2_ptr != std::string::npos) {
115                                 _arg2 = _arg2.substr(_arg2_ptr);
116                         }
117                         int typeval;
118                         try {
119                                 typeval = cue_enum.at(_arg1);
120                         } catch (std::out_of_range &e) {
121                                 typeval = CUE_NONE;
122                         }
123                         switch(typeval) {
124                         case CUE_REM:
125                                 break;
126                         case CUE_FILE:
127                                 {
128                                         if(!(parse_cue_file_args(_arg2, parent_dir, image_tmp_data_path))) break;
129                                         with_filename[nr_current_track + 1] = true;
130                                 }
131                                 break;
132                         case CUE_TRACK:
133                                 {
134                                         parse_cue_track(_arg2, nr_current_track, image_tmp_data_path);
135                                 }
136                                 break;
137                         case CUE_INDEX:
138                                 parse_cue_index(_arg2, nr_current_track);
139                                 break;
140                         case CUE_PREGAP:
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);
144
145                                         toc_table[nr_current_track].pregap = get_frames_from_msf(_arg2.c_str());
146                                 }
147                                 break;
148                         }
149                 _n_continue:
150                         if(is_eof) break;
151                         line_buf.clear();
152                         continue;
153                 }
154                 // Finish
155                 max_logical_block = 0;
156                 uint32_t pt_lba_ptr = 0;
157                 if(track_num > 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;
161                         // P1: Calc
162                         int _n = 0;
163                         int vnptr = 0;
164                         for(int i = 1; i < track_num; i++) {
165
166                                 if(fio_img->IsOpened()) {
167                                         fio_img->Fclose();
168                                 }
169                                 // Even...
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?)
172                                 //}
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;
177                                                 } else {
178                                                         _n = 0;
179                                                 }
180                                                 fio_img->Fclose();
181                                         }
182                                         toc_table[i].lba_size = _n;
183                                 }
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;
187                                 }
188                                 if(toc_table[i].index0 == 0) {
189                                         toc_table[i].index0 = toc_table[i].index1;
190                                 }
191                                 if(toc_table[i].pregap == 0) {
192                                         toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
193                                 }
194                                 // Even...
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?)
197                                 }
198                         }
199                         if((track_num == 2) && (max_logical_block > 0)) {
200                                 toc_table[track_num - 1].lba_size -= 1;
201                                 max_logical_block--;
202                         }
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;
206 #if 1
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]);
211 #endif
212                         }
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;
219                 }
220                 fio->Fclose();
221         }
222         delete fio;
223
224         is_cue = false;
225         if(track_num > 0) is_cue = true;
226         // Not Cue FILE.
227         return is_cue;
228 }
229
230 bool TOWNS_CDROM::parse_cue_file_args(std::string& _arg2, const _TCHAR *parent_dir, std::string& imgpath)
231 {
232         size_t _arg2_ptr;
233         size_t _arg3_ptr;
234         std::string _arg3;
235
236         _arg2_ptr = _arg2.find_first_of((const char *)"\"") + 1;
237         if(_arg2_ptr == std::string::npos) return false;
238
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);
243
244         imgpath.clear();
245         imgpath = std::string(parent_dir);
246         imgpath.append(_arg2);
247
248 //      cdrom_debug_log(_T("**FILE %s\n"), imgpath.c_str());
249
250         return true;
251 }
252
253 void TOWNS_CDROM::parse_cue_track(std::string &_arg2, int& nr_current_track, std::string imgpath)
254 {
255         size_t _arg2_ptr_s;
256         size_t _arg2_ptr;
257         _arg2_ptr_s = _arg2.find_first_of((const char *)" \t");
258
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");
262         size_t _arg3_ptr_s;
263         int _nr_num = atoi(_arg2.c_str());
264
265         // Set image file
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));
276
277                 nr_current_track = _nr_num;
278                 _arg3 = _arg3.substr(_arg3_ptr);
279
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);
287
288                 std::transform(_arg3.begin(), _arg3.end(), _arg3.begin(),
289                                            [](unsigned char c) -> unsigned char{ return std::toupper(c); });
290
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;
297                 int track_type;
298                 try {
299                         track_type = cue_type.at(_arg3);
300                 } catch (std::out_of_range &e) {
301                         track_type = MODE_NONE;
302                 }
303                 toc_table[nr_current_track].type = track_type;
304
305                 switch(track_type) {
306                 case MODE_AUDIO:
307                         toc_table[nr_current_track].is_audio = true;
308                         toc_table[nr_current_track].logical_size = 2352;
309                         break;
310                 case MODE_MODE1_2048:
311                         toc_table[nr_current_track].logical_size = 2048;
312                         toc_table[nr_current_track].physical_size = 2048;
313                         break;
314                 case MODE_MODE1_2352:
315                         toc_table[nr_current_track].logical_size = 2048;
316                         break;
317                 case MODE_MODE2_2336:
318                         toc_table[nr_current_track].logical_size = 2336;
319                         toc_table[nr_current_track].physical_size = 2336;
320                         break;
321                 case MODE_MODE2_2352:
322                         toc_table[nr_current_track].logical_size = 2336;
323                         break;
324                 case MODE_CDI_2336:
325                         toc_table[nr_current_track].logical_size = 2336;
326                         toc_table[nr_current_track].physical_size = 2336;
327                         break;
328                 case MODE_CDI_2352:
329                         toc_table[nr_current_track].logical_size = 2336;
330                         break;
331                 case MODE_CD_G:
332                         toc_table[nr_current_track].logical_size = 2448;
333                         toc_table[nr_current_track].physical_size = 2448;
334                         break;
335                         // ToDo: Set data size.
336                 }
337                 if(track_num < (_nr_num + 1)) track_num = _nr_num + 1;
338         } else {
339                 // ToDo: 20181118 K.Ohta
340                 nr_current_track = 0;
341         }
342
343 }
344
345 int TOWNS_CDROM::parse_cue_index(std::string &_arg2, int nr_current_track)
346 {
347         int index = -1;
348         std::string _arg3;
349         size_t _arg2_ptr_s;
350         size_t _arg3_ptr_s;
351         size_t _arg3_ptr;
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;;
355
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;
360
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());
365
366                 switch(index) {
367                 case 0:
368                         toc_table[nr_current_track].index0 = get_frames_from_msf(_arg3.c_str());
369                         break;
370                 case 1:
371                         toc_table[nr_current_track].index1 = get_frames_from_msf(_arg3.c_str());
372                         break;
373                 default:
374                         index = -1;
375                         break;
376                 }
377         }
378         return index;
379 }
380
381 }