OSDN Git Service

[VM][FMTOWNS][CDROM] Fix around re-calculate TOC table.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / cdrom_skelton.cpp
1 /*!
2  * @file cdrom_skelton.cpp
3  * @brief Skelton methods of new CD-ROM class for eFM-Towns.
4  * @author K.Ohta <whatisthis.sowhat _at_ gmail.com>
5  * @date 2021-03-12
6  * @copyright GPLv2
7  */
8 #include <cmath>
9 #include <stdlib.h>
10
11 #include "../../fileio.h"
12 #include "./cdrom_skelton.h"
13
14 /*!
15  * @brief constructor
16  */
17 CDROM_SKELTON::CDIMAGE_SKELTON()
18 {
19         max_blocks = 0;
20         tracks = 0;
21         type = CDROM_META::IMAGETYPE_NONE;
22         tracktype = CDROM_META::TRACKTYPE_NONE;
23         openmode = CDROM_META::OPENMODE_AUTO;
24         logical_bytes_per_block = 2048;
25         physical_bytes_per_block = 2352;
26         real_physical_bytes_per_block = 2352; //!< 2048 if MODE1/ISO.
27         allow_beyond_track = false;
28         transfer_rate_us = 1.0e6 / 150.0e3; //!< 1.0x 150s
29
30         seek_speed = 1.0;
31                 
32         now_lba = 0;
33         now_track = 0;
34         offset_in_sector = 0;
35         lba_offset_of_this_track = 0;
36         sectors_of_this_track = 0;
37         pregap_of_this_track = 150;
38         track_is_available = false;
39         bytes_position = 0;
40         __filename.erase();
41         for(int t = 0; t < 102; i++) {
42                 init_toc_table(t);
43         }
44                 
45         current_fio = NULL;
46         sheet_fio = NULL;
47 }
48 /*!
49  * @brief de-constructor
50  * @note Please implement de-allocating tracks list 
51  * in de-constructor if you need.
52  */
53 CDROM_SKELTON::~CDIMAGE_SKELTON()
54 {
55         reset_sheet_fio();
56 }
57
58 /*!
59  * @brief initialize function (blank skelton)
60  */
61 void CDROM_SKELTON::initialize()
62 {
63 }
64 /*!
65  * @brief de-initialize function (blank skelton)
66  */
67 void CDROM_SKELTON::release()
68 {
69 }
70
71 /*!
72  * @brief reset status function (blank skelton)
73  */
74 void CDROM_SKELTON::reset()
75 {
76 }
77
78 /*!
79  * @brief Convert BCD value to binary value.
80  * @param n BCD value
81  * @return Binarized value.-1 if error.
82  */
83 int CDROM_SKELTON::bcd2bin(uint8_t n, bool& __error)
84 {
85         return bcd_to_bin(n, __error);
86 }
87 /*!
88  * @brief Convert POSITIVE BINARY value to BCD.
89  * @param n Binary value.
90  * @param _error Set true if available range (0 to 99) at n.
91  * @return BCDed value.
92  */
93 uint8_t CDROM_SKELTON::bin2bcd(uint8_t n, bool& __error)
94 {
95         return bin_to_bcd(n, __error);
96 }
97
98 /*!
99  * @brief Calculate LBA position of M,S,F.
100  * @param m minutes of LBA.
101  * @param s seconds of LBA.
102  * @param f frames  of LBA.
103  * @return LBA position.-1 if error.
104  * @note m,s,f must be encoded by BCD.Not binary.
105  */
106 int64_t CDROM_SKELTON::msf_to_lba(uint8_t m, uint8_t s, uint8_t f) const
107 {
108         bool _err1, _err2, _err3;
109         int64_t mm = bcd_to_bin(m, _err1);
110         int64_t ss = bcd_to_bin(s, _err2);
111         int64_t ff = bcd_to_bin(f, _err3);
112
113         if((_err1) || (_err2) || (_err3)) return -1;
114         return ((mm * 60 * 75) + (ss * 75) + ff);
115 }
116 /*!
117  * @brief Calculate M,S,F from LBA position.
118  * @param lba LBA position. 
119  * @param m minutes of LBA.
120  * @param s seconds of LBA.
121  * @param f frames  of LBA.
122  * @return true if suceeded.
123  * @note m,s,f are encoded by BCD.Not binary.
124  */
125 bool  CDROM_SKELTON::lba_to_msf(int64_t lba, uint8_t& m, uint8_t& s, uint8_t& f) const
126 {
127         if(lba < 0) return false;
128         int64_t mm = lba / (60 * 75);
129         int64_t ss;
130         int64_t ff;
131         bool _error = false;
132                 
133 //      ss = (lba - (mm * (60 * 75))) / 75;
134 //      ff =  lba - ((mm * (60 * 75)) + ss * 75);
135         ss = (lba / 75) % 60;
136         ff = lba % 75;
137         if((mm >= 100) || (mm < 0)) return false; 
138         if((ss >= 60) || (ss < 0)) return false; 
139         if((ff >= 75) || (ff < 0)) return false; 
140         m = bin_to_bcd((uint8_t)mm, _error);
141         if(_error) return false;
142         s = bin_to_bcd((uint8_t)ss, _error);
143         if(_error) return false;
144         f = bin_to_bcd((uint8_t)ff, _error);
145         if(_error) return false;
146         return true;
147 }
148
149 /*!
150  * @brief Read TOC/Playing position of used track (BCD Format)
151  * @param trk TRACK NUM (0 to 99). If -1 get informations of track now playing.
152  * @param pointer of Destination Playing status table buffer.
153  *        MUST allocate more than sizeof(CDROM_META::cdrom_position_bcd_t).
154  * @return true if available this track.
155  */
156 bool CDROM_SKELTON::get_position_by_bcd(int trk, CDROM_META::cdrom_position_bcd_t* data)
157 {
158         if(data == nullptr) return false;
159         if(trk == -1) {
160                 if(now_track > 99) return -false;
161                 if(now_track < 1)  return false;
162                 trk = now_track;
163         }
164         if((trk < 0) || (trk > 99)) return false;
165         if(trk >= tracks) return false;
166         if(!(toc_table[trk].available)) return false;
167         CDROM_META::cdrom_position_binary_t __data;
168
169         memset(((uint8_t*)data), 0x00, sizeof(cdrom_position_bcd_t));
170         if(get_position_by_bynary(trk, &__data)) {
171                 uint8_t m, s, f;
172                 
173                 data->trk = __data.trk;
174                 data->type = __data.type;
175                 
176 //              if(!(lba_to_msf(__data.pregap, m, s, f))) {
177 //                      return false;
178 //              }
179                 data->pregap_m = m;
180                 data->pregap_s = s;
181                 data->pregap_f = f;
182                 
183 //              if(!(lba_to_msf(__data.start, m, s, f))) {
184 //                      return false;
185 //              }
186                 data->start_m = m;
187                 data->start_s = s;
188                 data->start_f = f;
189
190 //              if(!(lba_to_msf(__data.end, m, s, f))) {
191 //                      return false;
192 //              }
193                 data->end_m = m;
194                 data->end_s = s;
195                 data->end_f = f;
196                 
197 //              if(!(lba_to_msf(__data.abs_pos, m, s, f))) {
198 //                      return false;
199 //              }
200                 data->abs_m = m;
201                 data->abs_s = s;
202                 data->abs_f = f;
203
204 //              if(!(lba_to_msf(__data.rel_pos, m, s, f))) {
205 //                      return false;
206 //              }
207                 data->rel_m = m;
208                 data->rel_s = s;
209                 data->rel_f = f;
210                 return true;
211         }
212         return false;
213 }
214
215 /*!
216  * @brief Read TOC/Playing position of used track (BINARY Format)
217  * @param trk TRACK NUM (0 to 99). If -1 get informations of track now playing.
218  * @param pointer of Destination Playing status table buffer.
219  *        MUST allocate more than sizeof(CDROM_META::cdrom_position_bcd_t).
220  * @return true if available this track.
221  */
222 bool CDROM_SKELTON::get_position_by_binary(int trk, CDROM_META::cdrom_position_binary_t* data)
223 {
224         if(data == nullptr) return false;
225         if(trk == -1) {
226                 if(now_track > 99) return -false;
227                 if(now_track < 1)  return false;
228                 trk = now_track;
229         }
230         if((trk < 0) || (trk > 99)) return false;
231         if(trk >= tracks) return false;
232         if(!(toc_table[trk].available)) return false;
233         
234         memset(((uint8_t*)data), 0x00, sizeof(cdrom_position_binary_t));
235
236         int64_t _pregap = toc_table[trk].pregap;
237         
238         if(_pregap < 0) _pregap = 0; // OK?
239         data->trk = trk;
240         data->type = toc_table[trk].type;
241         data->pregap = _pregap;
242         data->start = toc_table[trk].absolute_lba;
243
244         int64_t n_size = toc_table[trk].lba_size;
245         if(n_size < 1) n_size = 1;
246
247         data->end = toc_table[trk].absolute_lba + n_size - 1;
248
249         data->abs_pos = 0;
250         data->rel_pos = 0;
251         
252         int64_t rel_lba = now_lba;
253         if(rel_lba > 0) {
254                 if(trk == now_track) {
255                         data->abs_pos = toc_table[trk].absolute_lba + rel_lba;
256                         data->rel_pos = rel_lba;
257                 }
258         }
259         return true;
260 }
261 /*!
262  * @brief Get TOC table by TRACK (RAW format).
263  * @param trk TRACK NUM (0 to 99).
264  * @param pointer of Destination TOC buffer.
265  *        MUST allocate more than sizeof(CDROM_META::cdrom_toc_table_t).
266  * @return true if success.
267  */
268 bool CDROM_SKELTON::get_toc_table(int trk, CDROM_META::cdrom_toc_table_t* data)
269 {
270         if(data == nullptr) return false;
271         if((trk < 0) || (track > 99)) return false;
272         if(trk >= tracks) return false;
273                 
274         data->available            = toc_table[trk].available;
275         data->type                 = toc_table[trk].type;
276         data->absolute_lba         = toc_table[trk].absolute_lba;
277         data->lba_offset           = toc_table[trk].lba_offset;
278         data->lba_size             = toc_table[trk].lba_size;
279         data->index0               = toc_table[trk].index0;
280         data->index1               = toc_table[trk].index1;
281         data->current_bytes_offset = toc_table[trk].current_bytes_offset;
282         data->pregap               = toc_table[trk].pregap;
283         data->physical_size        = toc_table[trk].physical_size;
284         data->real_physical_size   = toc_table[trk].real_physical_size;
285         data->logical_size         = toc_table[trk].logical_size;
286                 
287         memset(&(data->filename[0]), 0x00, sizeof(_TCHAR) * _MAX_PATH);
288         my_tcscpy_s(&(data->filename[0]), _MAX_PATH - 1, &(toc_table[trk].filename[0]));
289         return true;
290 }
291
292 /*!
293  * @brief Open virtual disc image.
294  * @param filename Filename of image (absolute path).
295  * @param req_type Opening mode.
296  * @return true if succeeded.
297  *
298  * @note Must set disc parameters list only at this function (or sub-functions).
299  * @see parse_sheet
300  * @see check_type
301  */
302 bool CDROM_SKELTON::open(_TCHAR *filename, enum CDROM_META::CDIMAGE_OPEN_MODE req_type)
303 {
304         close();
305         if(FILEIO::IsFileExisting(filename)) {
306                 bool stat = false;
307                 sheet_fio = new FILEIO();
308                 if(sheet_fio != nullptr) {
309                         if(sheet_fio->Fopen(filename, FILEIO_READ_BINARY)) {
310                                 parse_sheet();
311                         }
312                         delete sheet_fio;
313                         sheet_fio = NULL;
314                 }
315                 return stat;
316         }
317         return false;
318 }
319 /*!
320  * @brief Close virtual disc image.
321  * @return true if succeeded.
322  */
323 bool CDROM_SKELTON::close()
324 {
325         reset_sheet_fio();
326         for(uint8_t num = 0; num < 102; num++) {
327                 init_toc_table(num);
328         }
329                 
330         type = CDROM_META::IMAGETYPE_NODE;
331         tracktype = CDROM_META::TRACKTYPE_NONE;
332         logical_bytes_per_block = 2048;
333         physical_bytes_per_block = 2352;
334         real_physical_bytes_per_block = 2352;
335         track_is_available = false;
336         now_lba = 0;
337         offset_in_sector = 0;
338         bytes_position = 0;
339         lba_offset_of_this_track = 0;
340
341         sectors_of_this_track = 0;
342         pregap_of_this_track = 150;
343         __filename.erase();
344
345         return true;
346 }
347
348 /*!
349  * @brief Read image data to buffer as CD-ROM/MODE1 from current LBA position.
350  * @param buf Destination pointer of read buffer.
351  * @param buflen Size of read buffer.
352  * @param sectors Count of sectors (LBAs).
353  * @param _clear true if expect to clear buffer.
354  * @return size of reading.
355  * @note Override and inherit this to implement real method.
356  * @note Stop when reaches END of CURRENT TRACK.
357  */
358 ssize_t CDROM_SKELTON::read_mode1(uint8_t *buf, ssize_t buflen, size_t sectors, bool _clear)
359 {
360         if(buf == nullptr) return -1;
361         if(buflen <= 0) return -1;
362         if(_clear) {
363                 memset(buf, 0x00, buflen);
364         }
365         
366         if((now_track == 0) || (now_track >= 100)) return -1;
367         if(now_track >= tracks) return -1;
368                 
369         if(sectors <= 0) return -1;
370         if(current_fio == nullptr) return -1;
371         if(!(curent_fio->IsOpened())) return -1;
372         
373         int64_t logical_size = (int64_t)(sectors * logical_bytes_per_block);
374         if(logical_size >= buflen) logical_size = buflen;
375         if(logical_size <= 0) return -1;
376
377         int xptr = 0;
378         /*!
379          * @note standard reading function.
380          */
381         switch(tracktype) {
382         case TRACKTYPE_2352_ISO:
383         case TRACKTYPE_MODE1_2352:
384                 {
385                         CDROM_META::cdrom_data_mode1_t secbuf;
386                         for(int i = 0; i < sectors; i++) {
387                                 if(xptr >= logical_size) break;
388                                 if(now_lba >= sectors_of_this_track) {
389                                         // SEEK?
390                                         return xptr;
391                                 }
392                                 size_t n = current_fio->Fread((uint8_t*)(&secbuf), sizeof(secbuf), 1);
393                                 now_lba++;
394                                 if(n != sizeof(secbuf)) {
395                                         return xptr;
396                                 }
397                                 // Data OK
398                                 memcpy(&(buf[xptr]), &(secbuf.data[0]), 2048);
399                                 xptr += 2048;
400                         }
401                 }
402                 break;
403         case TRACKTYPE_MODE1_2048:
404         case TRACKTYPE_MODE1_ISO:
405                 {
406                         uint8_t secbuf[2048];
407                         for(int i = 0; i < sectors; i++) {
408                                 if(xptr >= logical_size) break;
409                                 if(now_lba >= sectors_of_this_track) {
410                                         // SEEK?
411                                         return xptr;
412                                 }
413                                 size_t n = current_fio->Fread((uint8_t*)(secbuf), sizeof(secbuf), 1);
414                                 now_lba++;
415                                 if(n != sizeof(secbuf)) {
416                                         return xptr;
417                                 }
418                                 // Data OK
419                                 memcpy(&(buf[xptr]), secbuf, 2048);
420                                 xptr += 2048;
421                         }
422                 }
423                 break;
424                 /*
425                  * If another Image type, return -1.
426                  */
427         default:
428                 return -1;
429                 break;
430         }
431         return logical_size;
432 }
433 /*!
434  * @brief Read image data to buffer as CD-ROM/MODE2 from current LBA position.
435  * @param buf Destination pointer of read buffer.
436  * @param buflen Size of read buffer.
437  * @param sectors Count of sectors (LBAs).
438  * @param _clear true if expect to clear buffer.
439  * @return size of reading.
440  * @note Override and inherit this to implement real method.
441  * @note Stop when reaches END of CURRENT TRACK.
442  */
443 ssize_t CDROM_SKELTON::read_mode2(uint8_t *buf, ssize_t buflen, size_t sectors, bool _clear)
444 {
445         if(buf == nullptr) return -1;
446         if(buflen <= 0) return -1;
447         if(_clear) {
448                 memset(buf, 0x00, buflen);
449         }
450         
451         if((now_track == 0) || (now_track >= 100)) return -1;
452         if(now_track >= tracks) return -1;
453                 
454         if(sectors <= 0) return -1;
455         if(current_fio == nullptr) return -1;
456         if(!(curent_fio->IsOpened())) return -1;
457
458         int64_t logical_size = (int64_t)(sectors * logical_bytes_per_block);
459         if(logical_size >= buflen) logical_size = buflen;
460         if(logical_size <= 0) return -1;
461
462         int xptr = 0;
463         /*!
464          * @note standard reading function.
465          */
466         switch(tracktype) {
467         case TRACKTYPE_MODE2_2352:
468         case TRACKTYPE_2352_ISO:
469                 {
470                         CDROM_META::cdrom_data_mode2_t secbuf;
471                         for(int i = 0; i < sectors; i++) {
472                                 if(xptr >= logical_size) break;
473                                 if(now_lba >= sectors_of_this_track) {
474                                         // SEEK?
475                                         return xptr;
476                                 }
477                                 size_t n = current_fio->Fread((uint8_t*)(&secbuf), sizeof(secbuf), 1);
478                                  
479                                 now_lba++;
480                                 if(n != sizeof(secbuf)) {
481                                         return xptr;
482                                 }
483                                 // Data OK
484                                 memcpy(&(buf[xptr]), &(secbuf.data[0]), 2336);
485                                 xptr += 2336;
486                         }
487                 }
488                 break;
489         case TRACKTYPE_MODE2_ISO:
490         case TRACKTYPE_MODE2_2336:
491                 {
492                         uint8_t secbuf[2336];
493                         for(int i = 0; i < sectors; i++) {
494                                 if(xptr >= logical_size) break;
495                                 if(now_lba >= sectors_of_this_track) {
496                                         // SEEK?
497                                         return xptr;
498                                 }
499                                 size_t n = current_fio->Fread((uint8_t*)(secbuf), sizeof(secbuf), 1);
500                                 now_lba++;
501                                 if(n != sizeof(secbuf)) {
502                                         return xptr;
503                                 }
504                                 // Data OK
505                                 memcpy(&(buf[xptr]), secbuf, 2336);
506                                 xptr += 2336;
507                         }
508                 }
509                 break;
510                 /*
511                  * If another Image type, return -1.
512                  */
513         default:
514                 return -1;
515                 break;
516         }
517         return logical_size;
518 }
519 /*!
520  * @brief Read image data to buffer as CD-DA from current LBA position.
521  * @param buf Destination pointer of read buffer.Must be pair16_t[(2352 / 4) * 2].
522  * @param buflen bytes of read buffer.
523  * @param sectors Count of sectors (LBAs).
524  * @param swap_byte true if swap byte order.
525  * @param _clear true if expect to clear buffer.
526  * @return read samples.
527  * @note Override and inherit this to implement real method.
528  * @note Stop when reaches END of CURRENT TRACK.
529  */
530 ssize_t CDROM_SKELTON::read_cdda(pair16_t *buf, ssize_t buflen, size_t sectors, bool swap_byte, bool _clear)
531 {
532         if(buf == nullptr) return -1;
533         if(buflen <= 0) return -1;
534         if(_clear) {
535                 memset(buf, 0x00, buflen);
536         }
537         
538         if((now_track == 0) || (now_track >= 100)) return -1;
539         if(now_track >= tracks) return -1;
540                 
541         if(sectors <= 0) return -1;
542         if(current_fio == nullptr) return -1;
543         if(!(curent_fio->IsOpened())) return -1;
544
545         int64_t physical_size = ((int64_t)sectors) * (2352 / 4);
546         buflen >>= 2;
547         if(physical_size >= buflen) physical_size = buflen;
548         if(physical_size <= 0) return -1;
549         
550         int xptr = 0;
551         int64_t xbptr = 0;
552         switch(tracktype) {
553         case TRACKTYPE_AUDIO:
554         case TRACKTYPE_MODE1_2352:
555         case TRACKTYPE_MODE2_2352:
556         case TRACKTYPE_CDI_2352:
557         case TRACKTYPE_2352_ISO:
558                 {
559                         __DECL_ALIGNED(8) uint8_t secbuf[2352];
560                         for(int i = 0; i < sectors; i++) {
561                                 if(xbptr >= physical_size) break;
562                                 if(now_lba >= sectors_of_this_track) {
563                                         // SEEK?
564                                         if(!(allow_beyond_track)) {
565                                                 return xbptr;
566                                         } else {
567                                                 if(now_track >= 99) return xbptr;
568                                                 if(!(get_track_image(now_track + 1))) {
569                                                         return xbptr;
570                                                 }
571                                                 // Refleshed.
572                                                 if(!(seek_in_track(pregap_of_this_track))) {
573                                                         return xbptr;
574                                                 }
575                                         }
576                                 }
577                                 size_t n = current_fio->Fread((uint8_t*)(secbuf), sizeof(secbuf), 1);
578                                 now_lba++;
579                                 if(n != sizeof(secbuf)) {
580                                         return xbptr;
581                                 }
582                                 // Data OK
583                                 xptr = 0;
584                                 if(swap_byte) {
585 __DECL_VECTORIZED_LOOP                                  
586                                         for(int j = 0; j < (2352 / 2); j++) {
587                                                 buf[j + (xbptr << 1)].b.h = secbuf[xptr];
588                                                 buf[j + (xbptr << 1)].b.l = secbuf[xptr + 1];
589                                                 xptr += 2;
590                                         }
591                                 } else {
592 __DECL_VECTORIZED_LOOP
593                                         for(int j = 0; j < (2352 / 2); j++) {
594                                                 buf[j + (xbptr << 1)].b.l = secbuf[xptr];
595                                                 buf[j + (xbptr << 1)].b.h = secbuf[xptr + 1];
596                                                 xptr += 2;
597                                         }
598                                 }
599                                 xbptr += (2352 / 4);
600                         }
601                 }
602                 break;
603                 /*!
604                  * @todo Implement sector size = 2048 or 2336.
605                  */
606         default:
607                 return -1;
608         }
609         return xbptr;
610 }
611         
612 /*!
613  * @brief Read raw image data to buffer from current LBA position.
614  * @param buf Destination pointer of read buffer.
615  * @param buflen Size of read buffer.
616  * @param sectors Count of sectors (LBAs).
617  * @param _clear true if expect to clear buffer.
618  * @return size of reading.
619  * @note Override and inherit this to implement real method.
620  * @note Stop when reaches END of CURRENT TRACK.
621  * @note Changing size of data by type of Virtual image.
622  */
623 ssize_t CDROM_SKELTON::read_raw(uint8_t *buf, ssize_t buflen, size_t sectors, bool _clear)
624 {
625         if(buf == nullptr) return -1;
626         if(buflen <= 0) return -1;
627         if(_clear) {
628                 memset(buf, 0x00, buflen);
629         }
630         
631         if((now_track == 0) || (now_track >= 100)) return -1;
632         if(now_track >= tracks) return -1;
633                 
634         if(sectors <= 0) return -1;
635         if(current_fio == nullptr) return -1;
636         if(!(curent_fio->IsOpened())) return -1;
637
638         int64_t physical_size = (int64_t)(sectors * physical_bytes_per_block);
639         if(physical_size >= buflen) physical_size = buflen;
640         if(physical_size <= 0) return -1;
641         int xptr = 0;
642         uint8_t secbuf[2352];
643         int ps = physical_bytes_per_block;
644         if(ps >= 2352) ps = 2352;
645         if(ps <= 0) {
646                 return -1;
647         }
648         
649
650         for(int i = 0; i < sectors; i++) {
651                 if(xptr >= physical_size) break;
652                 if(now_lba >= sectors_of_this_track) {
653                         // SEEK?
654                         if(!(allow_beyond_track)) {
655                                 return xptr;
656                         } else {
657                                 if(now_track >= 99) return xptr;
658                                 if(!(get_track_image(now_track + 1))) {
659                                         return xptr;
660                                 }
661                                 // Refleshed.
662                                 if(!(seek_in_track(pregap_of_this_track))) {
663                                         return xptr;
664                                 }
665                         }
666                 }
667                 size_t n = current_fio->Fread((uint8_t*)(secbuf), ps, 1);
668                 now_lba++;
669                 if(n != ps) {
670                         return xptr;
671                 }
672                 memcpy(&(buf[xptr]), secbuf, ps);
673                 xptr += ps;
674         }
675         return physical_size;
676 }
677
678 /*!
679  * @brief Try to seek to expected LBA.
680  * @param m minutes of LBA (absolute)
681  * @param s seconds of LBA (absolute)
682  * @param f frames  of LBA (absolute)
683  * @param in_track Set true if within track, set false if seek to another track.
684  * @return true if succeeded.
685  * @note need to implement accross another tracks.
686  */     
687 bool CDROM_SKELTON::seek(uint8_t m, uint8_t s, uint8_t f, bool& in_track)
688 {
689         int64_t lba = msf_to_lba(m, s, f);
690         return seek_absolute_lba(lba);
691 }
692 /*!
693  * @brief Try to seek to expected LBA.
694  * @param lba Position of LBA (absolute)
695  * @param in_track Set true if within track, set false if seek to another track.
696  * @return true if succeeded.
697  * @note need to implement accross another tracks.
698  */     
699 bool CDROM_SKELTON::seek_absolute_lba(int64_t lba, bool& in_track)
700 {
701         if(lba >= max_blocks) {
702                 lba = max_blocks;
703         }
704         if(lba < 0) {
705                 lba = 0;
706         }
707         uint8_t trk = 0;
708         for(int i = 0; i < tracks; i++) {
709                 if(toc_table[trk + 1].absolute_lba > lba) break;
710                 trk++;
711         }
712         if(trk >= tracks) {
713                 trk = (tracks > 0) ? (tracks - 1) : 0;
714         }
715         if((trk == 0) || (!(toc_table[trk].available))) {
716                 if(now_track != 0) {
717                         in_track = false;
718                         if(!(allow_beyond_track)) {
719                                 return false;
720                         }
721                 }
722                 get_track_image(0);
723                 return seek_in_track(0);
724         }
725         if(trk != now_track) {
726                 in_track = false;
727                 now_track = trk;
728                 if(allow_beyond_track) {
729                         if(!(get_track_image(now_trk))) {  // Seek inner.
730                                 seek_in_track(0);
731                                 return false;
732                         }
733                 } else {
734                         get_track_image(0);
735                         seek_in_track(0);
736                         return false;
737                 }
738         } else {
739                 in_track = true;
740         }
741         lba = lba - toc_table[now_track].lba_offset;
742         if(lba <= 0) {
743                 lba = 0;
744         }
745         return seek_in_track(lba);
746 }
747 /*!
748  * @brief Try to seek to expected LBA.
749  * @param lba Position of LBA (relative)
750  * @param in_track Set true if within track, set false if seek to another track.
751  * @return true if succeeded.
752  * @note need to implement accross another tracks.
753  */     
754 bool CDROM_SKELTON::seek_relative_lba(int64_t lba, bool& in_track)
755 {
756         int64_t __lba = lba + now_lba;
757         return seek_absolute_lba(__lba, in_track);
758 }
759
760
761 /*!
762  * @brief Calculate seek time to expected LBA.
763  * @param m minutes of LBA (absolute)
764  * @param s seconds of LBA (absolute)
765  * @param f frames  of LBA (absolute)
766  * @return seek time as usec.
767  * If error, return NaN. 
768  */     
769 double CDROM_SKELTON::get_seek_time(uint8_t m, uint8_t s, uint8_t f)
770 {
771         int64_t lba = msf_to_lba(m, s, f);
772         return get_seek_time_absolute_lba(lba);
773 }
774 /*!
775  * @brief Calculate seek time to expected LBA.
776  * @param lba Position of LBA (absolute)
777  * @return seek time as usec.
778  * If error, return NaN. 
779  */     
780 double CDROM_SKELTON::get_seek_time_absolute_lba(int64_t lba)
781 {
782         if(lba < 0) {
783                 return std::nan();
784         } else {
785                 int64_t step = (int64_t)(llabs(lba - now_lba));
786                 if(step > max_blocks) step = max_blocks;
787                         
788                 double _t = (get_single_seek_time_us() * ((double)step));
789                 return _t;
790         }
791 }
792 /*!
793  * @brief Calculate seek time to expected LBA.
794  * @param lba Position of LBA (relative)
795  * @return seek time as usec.
796  * If error, return NaN. 
797  */     
798 double CDROM_SKELTON::get_seek_time_relative_lba(int64_t lba)
799 {
800         int64_t lba2 = llabs(lba);
801         if(lba2 > max_blocks) lba2 = max_blocks;
802
803         double _t = (get_single_seek_time_us() * ((double)lba2));
804         return _t;
805 }
806 /*!
807  * @brief Check type of virtual disc image by filename.
808  * @param filename Filename of image (absolute path).
809  * @return Type of CD image.
810  */
811 static enum CDROM_META::CDIMAGE_TYPE CDROM_SKELTON::check_type(_TCHAR *filename)
812 {
813         if(filename == nullptr) {
814                 return CDROM_META::IMAGETYPE_NONE;
815         }
816         if(!(FILEIO::IsFileExisting(filename))) {
817                 return CDROM_META::IMAGETYPE_NONE;
818         }
819         if(check_file_extension(filename, _T(".gz"))) {
820                 if(check_file_extension(filename, _T(".iso.gz"))) {
821                         return CDROM_META::IMAGETYPE_ISO;
822                 }
823                 if(check_file_extension(filename, _T(".cue.gz"))) {
824                         return CDROM_META::IMAGETYPE_CUE;
825                 }
826                 if(check_file_extension(filename, _T(".ccd.gz"))) {
827                         return CDROM_META::IMAGETYPE_CCD;
828                 }
829         } else {
830                 if(check_file_extension(filename, _T(".iso"))) {
831                         return CDROM_META::IMAGETYPE_ISO;
832                 }
833                 if(check_file_extension(filename, _T(".cue"))) {
834                         return CDROM_META::IMAGETYPE_CUE;
835                 }
836                 if(check_file_extension(filename, _T(".ccd"))) {
837                         return CDROM_META::IMAGETYPE_CCD;
838                 }
839         }
840         return CDROM_META::IMAGETYPE_NONE; // Write Unique routines to next.
841 }
842
843 /*!
844  * @brief Get Relative LBA offset value (at head of this track) of this image.
845  * @return Relative LBA offset value (in image).
846  */
847 int64_t CDROM_SKELTON::get_lba_offset() const
848 {
849         return __get_lba_offset();
850 }
851 /*!
852  * @brief Get image type of this virtual CD.
853  * @return Image type of virtual CD.
854  */
855 enum CDROM_META::CDIMAGE_TYPE CDROM_SKELTON::get_type() const
856 {
857         return __get_type();
858 }
859 /*!
860  * @brief Get full path of this virtual image.
861  * @param var Returned full path of opened file.Erase if not opened.
862  * @return true if already opened.
863  */
864 bool CDROM_SKELTON::get_track_image_file_name(std::string& var)
865 {
866         return __get_track_image_file_name(var);
867 }
868         
869 /*!
870  * @brief Set seek speed.
871  * @param usec Basic transfer time normally 1.0 / 150.0KHz.
872  */
873 void CDROM_SKELTON::set_transfer_time_us(double usec)
874 {
875         __set_transfer_time_us(double usec);
876 }
877 /*!
878  * @brief Get transfer time per byte.
879  * @return transfer time as uSec.
880  */
881 double CDROM_SKELTON::get_transfer_time_us()
882 {
883         return __get_transfer_time_us();
884 }
885 /*!
886  * @brief Get seek multiply rate.
887  * @return Seek rate.
888  */
889 double CDROM_SKELTON::get_seek_speed()
890 {
891         return __get_seek_speed();
892 }
893 /*!
894  * @brief Get seek time per block.
895  * @return seek time as uSec.
896  */
897 double CDROM_SKELTON::get_single_seek_time_us()
898 {
899         return __get_single_seek_time_us();
900 }
901 /*!
902  * @brief Set seek speed.
903  * @param speed Transfer speed multiply rate, normally 1.0.
904  */
905 void CDROM_SKELTON::set_seek_speed(double speed)
906 {
907         __set_seek_speed(speed);
908 }
909 /*!
910  * @brief Set physical bytes per block (in emulation).
911  * @param bytes bytes per block.
912  */
913 void CDROM_SKELTON::set_physical_bytes_per_block(uint32_t bytes)
914 {
915         __set_physical_bytes_per_block(bytes);
916 }
917 /*!
918  * @brief Set physical bytes per block (in image).
919  * @param bytes bytes per block.
920  */
921 void CDROM_SKELTON::set_real_physical_bytes_per_block(uint32_t bytes)
922 {
923         __set_real_physical_bytes_per_block(bytes);
924 }
925 /*!
926  * @brief Set logical bytes per block (in emulation).
927  * @param bytes bytes per block.
928  */
929 void CDROM_SKELTON::set_logical_bytes_per_block(uint32_t bytes)
930 {
931         __set_logical_bytes_per_block(bytes);
932 }
933
934 /*!
935  * @brief Set enable/disable beyond track reading.
936  * @param val enable when setting true.
937  */
938 void CDROM_SKELTON::enable_beyond_track_reading(bool val)
939 {
940         allow_beyond_track = val;
941 }
942
943 /*!
944  * @brief Get track position now accessing.
945  * @return track value.-1 if not avaiable image.
946  */
947 int CDROM_SKELTON::get_track() const
948 {
949         return __get_track();
950 }
951 /*!
952  * @brief Get LBA position of now accessing.
953  * @return LBA position of now accessing.
954  */
955 int64_t CDROM_SKELTON::get_lba() const
956 {
957         return __get_lba();
958 }
959 /*!
960  * @brief Get number of sectors at this track.
961  * @return Number of sectors at this track.
962  */
963 int64_t CDROM_SKELTON::get_sectors_of_this_track() const
964 {
965         return __get_sectors_of_this_track();
966 }
967 /*!
968  * @brief Get current position-offset in this sector.
969  * @return Offset position.
970  */
971 int CDROM_SKELTON::get_offset_of_this_sector() const
972 {
973         return __get_offset_of_this_sector();
974 }
975 /*!
976  * @brief Whether this track is available.
977  * @return true if available.
978  */
979 bool CDROM_SKELTON::is_available() const
980 {
981         return __is_available();
982 }
983 /*!
984  * @brief Get blocks of this virtual CD.
985  * @return Blocks (sectors) of this virtual CD.
986  */
987 int64_t CDROM_SKELTON::get_blocks() const
988 {
989         return __get_blocks();
990 }
991 /*!
992  * @brief Get physical block size of this virtual CD.
993  * @return Physical block size of this virtual CD.
994  */
995 uint32_t CDROM_SKELTON::get_physical_block_size() const
996 {
997         return __get_physical_block_size();
998 }
999 /*!
1000  * @brief Get REAL (in VIRTUAL IMAGE) physical block size of this virtual CD.
1001  * @return Physical block size of this virtual CD.
1002  */
1003 uint32_t CDROM_SKELTON::get_real_physical_block_size() const
1004 {
1005         return __get_real_physical_block_size();
1006 }
1007 /*!
1008  * @brief Get logical block size of this virtual CD.
1009  * @return Logical block size of this virtual CD.
1010  */
1011 uint32_t CDROM_SKELTON::get_logical_block_size() const
1012 {
1013         return __get_logical_block_size();
1014 }
1015
1016 /*!
1017  * @brief Parse CUE/CCD sheet, check track data and construct tracks table.
1018  * @return true if succeeded.
1019  * @note Must open sheet file before using.
1020  * @note Initialize TOC table when calling.
1021  */
1022 bool CDROM_SKELTON::parse_sheet()
1023 {
1024         for(int trk = 0; trk < 102; trk++) {
1025                 init_toc_table(trk);
1026         }
1027         return true;
1028 }
1029
1030 /*!
1031  * @brief Load / Save state(TOC table part) to VM.
1032  * @param state_fio FILE IO for state loading/saving.
1033  * @param loading If true loading, false is saving.
1034  * @return true if succeeded.
1035  */
1036 bool CDROM_SKELTON::load_save_toc_table(FILEIO* state_fio, bool loading)
1037 {
1038         uint8_t ntracks = 0;
1039         if(loading) {
1040                 ntracks = state_fio->FgetUint8();
1041                 if(ntracks >= 101) return false;
1042         } else {
1043                 ntracks = tracks;
1044                 if(ntracks >= 101) return false;
1045                 state_fio->FputUint8(tracks);
1046         }
1047         uint8_t n = 0;
1048         for(int i = 1; i <= ntracks; i++) {
1049                 if(loading) {
1050                         n = state_fio->FgetUint8(); //!< Get track number
1051                         if(n != i) return false; //!< Error when wrong filename.
1052                 } else {
1053                         state_fio->FputUint8((uint8_t)i);
1054                 }
1055                 state_fio->StateValue(toc_table[i].available);
1056                 state_fio->StateValue(toc_table[i].type);
1057                 state_fio->StateValue(toc_table[i].pregap);
1058                 state_fio->StateValue(toc_table[i].absolute_lba);
1059                 state_fio->StateValue(toc_table[i].lba_offset);
1060                 state_fio->StateValue(toc_table[i].lba_size);
1061                 state_fio->StateValue(toc_table[i].index0);
1062                 state_fio->StateValue(toc_table[i].index1);
1063                 state_fio->StateValue(toc_table[i].physical_size);
1064                 state_fio->StateValue(toc_table[i].real_physical_size);
1065                 state_fio->StateValue(toc_table[i].logical_size);
1066                 state_fio->StateArray(toc_table[i].filename, _MAX_PATH, 1);
1067         }
1068         if(loading) {
1069                 tracks = ntracks;
1070                 /*
1071                  * clear TRACK 00.
1072                  */
1073                 init_toc_table(0);
1074                 if(tracks > 1) {
1075                         toc_table[0].available = true;
1076                 } else {
1077                         toc_table[0].available = false;
1078                 }
1079         }
1080         return true;
1081 }
1082         
1083 /*!
1084  * @brief Seek assigned position in track.
1085  * @param lba *Relative* LBA in this track.
1086  * @return true if success.
1087  */
1088 bool CDROM_SKELTON::seek_in_track(int64_t lba)
1089 {
1090         if(lba < 0) return false;
1091         if((now_track < 0) || (now_track >= 100)) return false;
1092                 
1093         int64_t _lba_bak = lba + lba_offset_of_this_track;
1094         if(current_fio == nullptr) return true;
1095                 
1096         int64_t lba_max = sectors_of_this_track + lba_offset_of_this_track;
1097         int64_t lba_min = lba_offset_of_this_track;
1098         if(lba_min < 0) lba_min = 0;
1099         if(lba_max < 0) lba_max = 0;
1100         lba = lba + lba_offset_of_this_track;
1101                 
1102         if(lba >= lba_max) return false;
1103         if(lba < lba_min) return false;
1104         if(pregap_of_this_track < 0) return false; // Illegal PREGAP
1105                 
1106         lba = lba - pregap_of_this_track;
1107         if(lba < 0) lba = 0;
1108                 
1109         int64_t offset = lba * get_real_physical_block_size();
1110                 
1111         if(offset >= LONG_MAX) {
1112                 bytes_position = 0;
1113                 offset_in_sector = 0;
1114                 return false;
1115         }
1116         if(current_fio->Fseek(offset, FILEIO_SEEK_SET) != 0) {
1117                 bytes_position = 0;
1118                 offset_in_sector = 0;
1119                 return false;
1120         }
1121         now_lba = _lba_bak;
1122         bytes_position = offset;
1123         offset_in_sector = 0;
1124         return true;
1125 }
1126 /*!
1127  * @brief Get image data of track.
1128  * @param track track number.
1129  * return true if success.
1130  */
1131 bool CDROM_SKELTON::get_track_image(uint8_t track)
1132 {
1133         bool result = false;
1134         if(track >= tracks) track = tracks;
1135         /*
1136          * Set default values
1137          */
1138         tracktype = CDROM_META::TRACKTYPE_NONE;
1139         logical_bytes_per_block = 2048;
1140         physical_bytes_per_block = 2352;
1141         real_physical_bytes_per_block = 2352;
1142         track_is_available = false;
1143         now_lba = 0;
1144         offset_in_sector = 0;
1145         bytes_position = 0;
1146         lba_offset_of_this_track = 0;
1147
1148         sectors_of_this_track = 0;
1149         pregap_of_this_track = 150;
1150                 
1151         __filename.erase();
1152                 
1153         if(current_fio != nullptr) {
1154                 if(current_fio->IsOpened()) {
1155                         current_fio->Fclose();
1156                 }
1157                 delete curent_fio;
1158                 current_fio = NULL;
1159         }
1160         if(track >= 100) {
1161                 return false;
1162         }
1163                 
1164         if(now_track != track) {
1165                 now_track = track;
1166         }
1167         if(!(toc_table[track].available)) {
1168                 return false;
1169         }
1170         if(strlen(toc_table[track].filename) > 0) {
1171                 current_fio = new FILEIO();
1172                 if(current_fio != nullptr) {
1173                         result = current_fio->Fopen(toc_table[track].filename, FILEIO_READ_BINARY);
1174                 }
1175                 if(result) {
1176                         __filename.assign(toc_table[track].filename, _MAX_PATH);
1177                 }
1178         }
1179         if(result) {
1180                 tracktype = toc_table[now_track].type;
1181                 logical_bytes_per_block = toc_table[now_track].logical_size;
1182                 physical_bytes_per_block = toc_table[now_track].physical_size;
1183                 real_physical_bytes_per_block = toc_table[now_track].real_physical_size;
1184                 track_is_available = toc_table[now_track].available;
1185                 now_lba = toc_table[now_track].lba_offset;
1186                 offset_in_sector = 0;
1187                 bytes_position = 0;
1188                 lba_offset_of_this_track = toc_table[now_track].lba_offset;
1189                 sectors_of_this_track = toc_table[now_track].lba_size;
1190                 pregap_of_this_track = toc_table[now_track].pregap;
1191         }
1192         return false;
1193 }
1194 /*!
1195  * @brief reset FILEIOs for sheet and image.
1196  */
1197 void CDROM_SKELTON::reset_sheet_fio()
1198 {
1199         if(current_fio != nullptr) {
1200                 if(current_fio->IsOpened()) {
1201                         current_fio->Fclose();
1202                 }
1203                 delete current_fio;
1204                 current_fio = NULL;
1205         }
1206         if(sheet_fio != nullptr) {
1207                 if(sheet_fio->IsOpened()) {
1208                         sheet_fio->Fclose();
1209                 }
1210                 delete sheet_fio;
1211                 sheet_fio = NULL;
1212         }
1213 }
1214
1215 /*!
1216  * @brief To be Upper characters from string.
1217  * @param s source string.
1218  * @return ToUpper'ed string.
1219  */
1220 static std::string CDROM_SKELTON::to_upper(std::string s)
1221 {
1222         std::string rets;
1223
1224         rets.clear();
1225         if(!(s.empty())) {
1226                 for(auto c = s.begin(); c != s.end(); ++c) {
1227                         _TCHAR n = std::toupper(*c);
1228                         rets.push_back(n);
1229                 }
1230         }
1231         return rets;
1232 }
1233 /*!
1234  * @brief Get uint value from BCD string.
1235  * @param s source string
1236  * @param errorval set true if wrong string value.
1237  * @return Value if success, 0 if not.
1238  */
1239 static uint64_t CDROM_SKELTON::get_val_from_bcdstr(std::string s, bool& errorval)
1240 {
1241         int pos = 0;
1242         uint64_t rval = 0;
1243         int pval;
1244         for(auto c = s.begin(); c != s.end() ; ++c) {
1245                 char cc = *c;
1246                 if((cc < '0') || (cc > '9')) {
1247                         break;
1248                 }
1249                 rval = rval * 10;
1250                 pval = cc - '0';
1251                 rval = rval + pval;
1252                 pos++;
1253         }
1254         if(pos < 1) {
1255                 errorval = true;
1256                 return 0;
1257         }
1258         errorval = false;
1259         return rval;
1260 }
1261
1262 /*!
1263  * @brief Get uint value from HEXADECIMAL string.
1264  * @param s source string
1265  * @param errorval set true if wrong string value.
1266  * @return Value if success, 0 if not.
1267  */
1268 static uint64_t CDROM_SKELTON::get_val_from_hexstr(std::string s, bool& errorval)
1269 {
1270         int pos = 0;
1271         uint64_t rval = 0;
1272         int pval;
1273         for(auto c = s.begin(); c != s.end() ; ++c) {
1274                 char cc = *c;
1275                 bool is_val = false;
1276                 if((cc >= '0') && (cc <= '9')) {
1277                         is_val = true;
1278                         pval = cc - '0';
1279                 } else if((cc >= 'A') && (cc <= 'F')) {
1280                         is_val = true;
1281                         pval = cc - 'A';
1282                 } else if((cc >= 'a') && (cc <= 'f')) {
1283                         is_val = true;
1284                         pval = cc - 'a';
1285                 }
1286                 if(!(is_val)) {
1287                         break;
1288                 }
1289                 rval = rval << 4;
1290                 rval = rval + pval;
1291                 pos++;
1292         }
1293         if(pos < 1) {
1294                 errorval = true;
1295                 return 0;
1296         }
1297         errorval = false;
1298         return rval;
1299 }
1300
1301 /*!
1302  * @brief Decode frame value from MSF string.
1303  * @param timestr Time string. Encoded by "xx:xx:xx". xx must be BCD value.
1304  * @param errorval true if wrong string.
1305  * @return value if success, 0 when failed.
1306  */
1307 static uint64_t CDROM_SKELTON::get_frames_from_msfstr(std::string timestr, bool &errorval)
1308 {
1309         if(timestr.size() < 8) { //xx:xx:xx
1310                 errorval = true;
1311                 return 0;
1312         }
1313         std::string s_m = timnestr.substr(0, 2);
1314         std::string _d1 = timnestr.substr(2, 1);
1315         std::string s_s = timnestr.substr(3, 2);
1316         std::string _d2 = timnestr.substr(5, 1);
1317         std::string s_f = timnestr.substr(6, 2);
1318
1319         if((_d1 != ":") || (_d2 != ":")) {
1320                 // delimiter(s) not found
1321                 errorval = true;
1322                 return 0;
1323         }
1324         bool error1, error2, error3;
1325         error1 = false;
1326         error2 = false;
1327         error3 = false;
1328         uint64_t mm = get_val_from_bcdstr(s_m, error1);
1329         uint64_t ss = get_val_from_bcdstr(s_s, error2);
1330         uint64_t ff = get_val_from_bcdstr(s_f, error3);
1331         if((error1) || (error2) || (error3)) {
1332                 errorval = true;
1333                 return 0;
1334         }
1335         if(mm > 99) {
1336                 errorval = true;
1337                 return 0;
1338         }
1339         if(ss > 59) {
1340                 errorval = true;
1341                 return 0;
1342         }
1343         if(ff > 74) {
1344                 errorval = true;
1345                 return 0;
1346         }
1347         uint64_t nt = (mm * 60 * 75) + (ss * 75) + ff;
1348         errorval = false;
1349         return nt;
1350 }
1351
1352
1353 #define STATE_VERSION 1
1354 /*!
1355  * @brief Load / Save state(main part) to VM.
1356  * @param state_fio FILE IO for state loading/saving.
1357  * @param loading If true loading, false is saving.
1358  * @return true if succeeded.
1359  */
1360 bool CDROM_SKELTON::load_save_params(FILEIO* state_fio, bool loading)
1361 {
1362         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
1363                 return false;
1364         }
1365         // device id is not exists.
1366         state_fio->StateValue(type);
1367         state_fio->StateValue(tracks);
1368         state_fio->StateValue(tracktype);
1369         state_fio->StateValue(openmode);
1370         state_fio->StateValue(logical_bytes_per_block);
1371         state_fio->StateValue(physical_bytes_per_block);
1372         state_fio->StateValue(real_physical_bytes_per_block);
1373         state_fio->StateValue(max_blocks);
1374
1375         state_fio->StateValue(transfer_time_us);
1376         state_fio->StateValue(seek_speed);
1377
1378         state_fio->StateValue(allow_beyond_track);
1379
1380         state_fio->StateValue(track_is_available);
1381         state_fio->StateValue(now_track);
1382         state_fio->StateValue(now_lba);
1383         state_fio->StateValue(bytes_position);
1384         state_fio->StateValue(offset_in_sector);
1385         state_fio->StateValue(lba_offset_of_this_track);
1386         state_fio->StateValue(sectors_of_this_track);
1387         state_fio->StateValue(pregap_of_this_track);
1388
1389         int strsize = 0;
1390         _TCHAR _l[_MAX_PATH] = {0};
1391         if(loading) {
1392                 strsize = state_fio->FgetInt32_LE();
1393                 if(strsize < 0) return false;
1394                         
1395                 __filename.clear();
1396                 state_fio->StateArray(_l, _MAX_PATH, 1);
1397                 __filename.assign(_l, _MAX_PATH - 1);
1398         } else {
1399                 strsize = __filename.length();
1400                 if(strsize < 0) strsize = 0;
1401                 state_fio->FputInt32_LE(strsize);
1402                 __filename.copy(_l, _MAX_PATH - 1);
1403                 state_fio->StateArray(_l, _MAX_PATH, 1);
1404         }
1405         return true;
1406 }
1407                         
1408 /*!
1409  * @brief Initialize TOC table..
1410  * @param num track number.
1411  */
1412 void CDROM_SKELTON::init_toc_table(uint8_t num)
1413 {
1414         if(num > 101) return;
1415                 
1416         toc_table[num].available = false;
1417         toc_table[num].type = CDROM_META::TRACKTYPE_NONE;
1418         toc_table[num].pregap = 0;
1419         toc_table[num].absolute_lba = 0;
1420         toc_table[num].lba_offset = 0;
1421         toc_table[num].lba_size = 0;
1422         toc_table[num].index0 = 0;
1423         toc_table[num].index1 = 0;
1424         toc_table[num].physical_size = 2352;
1425         toc_table[num].logical_size = 2048;
1426         toc_table[num].real_physical_size = 2352;
1427         toc_table[num].current_bytes_offset = 0;
1428         
1429         memset(toc_table[num].filename, 0x00, sizeof(_TCHAR) * _MAX_PATH);
1430 }
1431
1432 /*!
1433  * @brief Load / Save state to VM.
1434  * @param state_fio FILE IO for state loading/saving.
1435  * @param loading If true loading, false is saving.
1436  * @return true if succeeded.
1437  */
1438 bool CDROM_SKELTON::process_state(FILEIO* state_fio, bool loading)
1439 {
1440         /*!
1441          * @note Must place checking STATE_VERSION and MAGIC for unique image type..
1442          */
1443         if(!(load_save_params(state_fio, loading))) {
1444                 return false;
1445         }
1446         if(!(load_save_toc_table(state_fio, loading))) {
1447                 return false;
1448         }
1449         /*
1450          * please place state procesing for unuque values below.
1451          */
1452         return true;
1453 }