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>
11 #include "../../fileio.h"
12 #include "./cdrom_skelton.h"
17 CDROM_SKELTON::CDIMAGE_SKELTON()
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
35 lba_offset_of_this_track = 0;
36 sectors_of_this_track = 0;
37 pregap_of_this_track = 150;
38 track_is_available = false;
41 for(int t = 0; t < 102; i++) {
49 * @brief de-constructor
50 * @note Please implement de-allocating tracks list
51 * in de-constructor if you need.
53 CDROM_SKELTON::~CDIMAGE_SKELTON()
59 * @brief initialize function (blank skelton)
61 void CDROM_SKELTON::initialize()
65 * @brief de-initialize function (blank skelton)
67 void CDROM_SKELTON::release()
72 * @brief reset status function (blank skelton)
74 void CDROM_SKELTON::reset()
79 * @brief Convert BCD value to binary value.
81 * @return Binarized value.-1 if error.
83 int CDROM_SKELTON::bcd2bin(uint8_t n, bool& __error)
85 return bcd_to_bin(n, __error);
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.
93 uint8_t CDROM_SKELTON::bin2bcd(uint8_t n, bool& __error)
95 return bin_to_bcd(n, __error);
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.
106 int64_t CDROM_SKELTON::msf_to_lba(uint8_t m, uint8_t s, uint8_t f) const
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);
113 if((_err1) || (_err2) || (_err3)) return -1;
114 return ((mm * 60 * 75) + (ss * 75) + ff);
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.
125 bool CDROM_SKELTON::lba_to_msf(int64_t lba, uint8_t& m, uint8_t& s, uint8_t& f) const
127 if(lba < 0) return false;
128 int64_t mm = lba / (60 * 75);
133 // ss = (lba - (mm * (60 * 75))) / 75;
134 // ff = lba - ((mm * (60 * 75)) + ss * 75);
135 ss = (lba / 75) % 60;
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;
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.
156 bool CDROM_SKELTON::get_position_by_bcd(int trk, CDROM_META::cdrom_position_bcd_t* data)
158 if(data == nullptr) return false;
160 if(now_track > 99) return -false;
161 if(now_track < 1) return false;
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;
169 memset(((uint8_t*)data), 0x00, sizeof(cdrom_position_bcd_t));
170 if(get_position_by_bynary(trk, &__data)) {
173 data->trk = __data.trk;
174 data->type = __data.type;
176 // if(!(lba_to_msf(__data.pregap, m, s, f))) {
183 // if(!(lba_to_msf(__data.start, m, s, f))) {
190 // if(!(lba_to_msf(__data.end, m, s, f))) {
197 // if(!(lba_to_msf(__data.abs_pos, m, s, f))) {
204 // if(!(lba_to_msf(__data.rel_pos, m, s, f))) {
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.
222 bool CDROM_SKELTON::get_position_by_binary(int trk, CDROM_META::cdrom_position_binary_t* data)
224 if(data == nullptr) return false;
226 if(now_track > 99) return -false;
227 if(now_track < 1) return false;
230 if((trk < 0) || (trk > 99)) return false;
231 if(trk >= tracks) return false;
232 if(!(toc_table[trk].available)) return false;
234 memset(((uint8_t*)data), 0x00, sizeof(cdrom_position_binary_t));
236 int64_t _pregap = toc_table[trk].pregap;
238 if(_pregap < 0) _pregap = 0; // OK?
240 data->type = toc_table[trk].type;
241 data->pregap = _pregap;
242 data->start = toc_table[trk].absolute_lba;
244 int64_t n_size = toc_table[trk].lba_size;
245 if(n_size < 1) n_size = 1;
247 data->end = toc_table[trk].absolute_lba + n_size - 1;
252 int64_t rel_lba = now_lba;
254 if(trk == now_track) {
255 data->abs_pos = toc_table[trk].absolute_lba + rel_lba;
256 data->rel_pos = rel_lba;
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.
268 bool CDROM_SKELTON::get_toc_table(int trk, CDROM_META::cdrom_toc_table_t* data)
270 if(data == nullptr) return false;
271 if((trk < 0) || (track > 99)) return false;
272 if(trk >= tracks) return false;
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;
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]));
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.
298 * @note Must set disc parameters list only at this function (or sub-functions).
302 bool CDROM_SKELTON::open(_TCHAR *filename, enum CDROM_META::CDIMAGE_OPEN_MODE req_type)
305 if(FILEIO::IsFileExisting(filename)) {
307 sheet_fio = new FILEIO();
308 if(sheet_fio != nullptr) {
309 if(sheet_fio->Fopen(filename, FILEIO_READ_BINARY)) {
320 * @brief Close virtual disc image.
321 * @return true if succeeded.
323 bool CDROM_SKELTON::close()
326 for(uint8_t num = 0; num < 102; num++) {
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;
337 offset_in_sector = 0;
339 lba_offset_of_this_track = 0;
341 sectors_of_this_track = 0;
342 pregap_of_this_track = 150;
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.
358 ssize_t CDROM_SKELTON::read_mode1(uint8_t *buf, ssize_t buflen, size_t sectors, bool _clear)
360 if(buf == nullptr) return -1;
361 if(buflen <= 0) return -1;
363 memset(buf, 0x00, buflen);
366 if((now_track == 0) || (now_track >= 100)) return -1;
367 if(now_track >= tracks) return -1;
369 if(sectors <= 0) return -1;
370 if(current_fio == nullptr) return -1;
371 if(!(curent_fio->IsOpened())) return -1;
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;
379 * @note standard reading function.
382 case TRACKTYPE_2352_ISO:
383 case TRACKTYPE_MODE1_2352:
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) {
392 size_t n = current_fio->Fread((uint8_t*)(&secbuf), sizeof(secbuf), 1);
394 if(n != sizeof(secbuf)) {
398 memcpy(&(buf[xptr]), &(secbuf.data[0]), 2048);
403 case TRACKTYPE_MODE1_2048:
404 case TRACKTYPE_MODE1_ISO:
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) {
413 size_t n = current_fio->Fread((uint8_t*)(secbuf), sizeof(secbuf), 1);
415 if(n != sizeof(secbuf)) {
419 memcpy(&(buf[xptr]), secbuf, 2048);
425 * If another Image type, return -1.
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.
443 ssize_t CDROM_SKELTON::read_mode2(uint8_t *buf, ssize_t buflen, size_t sectors, bool _clear)
445 if(buf == nullptr) return -1;
446 if(buflen <= 0) return -1;
448 memset(buf, 0x00, buflen);
451 if((now_track == 0) || (now_track >= 100)) return -1;
452 if(now_track >= tracks) return -1;
454 if(sectors <= 0) return -1;
455 if(current_fio == nullptr) return -1;
456 if(!(curent_fio->IsOpened())) return -1;
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;
464 * @note standard reading function.
467 case TRACKTYPE_MODE2_2352:
468 case TRACKTYPE_2352_ISO:
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) {
477 size_t n = current_fio->Fread((uint8_t*)(&secbuf), sizeof(secbuf), 1);
480 if(n != sizeof(secbuf)) {
484 memcpy(&(buf[xptr]), &(secbuf.data[0]), 2336);
489 case TRACKTYPE_MODE2_ISO:
490 case TRACKTYPE_MODE2_2336:
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) {
499 size_t n = current_fio->Fread((uint8_t*)(secbuf), sizeof(secbuf), 1);
501 if(n != sizeof(secbuf)) {
505 memcpy(&(buf[xptr]), secbuf, 2336);
511 * If another Image type, return -1.
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.
530 ssize_t CDROM_SKELTON::read_cdda(pair16_t *buf, ssize_t buflen, size_t sectors, bool swap_byte, bool _clear)
532 if(buf == nullptr) return -1;
533 if(buflen <= 0) return -1;
535 memset(buf, 0x00, buflen);
538 if((now_track == 0) || (now_track >= 100)) return -1;
539 if(now_track >= tracks) return -1;
541 if(sectors <= 0) return -1;
542 if(current_fio == nullptr) return -1;
543 if(!(curent_fio->IsOpened())) return -1;
545 int64_t physical_size = ((int64_t)sectors) * (2352 / 4);
547 if(physical_size >= buflen) physical_size = buflen;
548 if(physical_size <= 0) return -1;
553 case TRACKTYPE_AUDIO:
554 case TRACKTYPE_MODE1_2352:
555 case TRACKTYPE_MODE2_2352:
556 case TRACKTYPE_CDI_2352:
557 case TRACKTYPE_2352_ISO:
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) {
564 if(!(allow_beyond_track)) {
567 if(now_track >= 99) return xbptr;
568 if(!(get_track_image(now_track + 1))) {
572 if(!(seek_in_track(pregap_of_this_track))) {
577 size_t n = current_fio->Fread((uint8_t*)(secbuf), sizeof(secbuf), 1);
579 if(n != sizeof(secbuf)) {
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];
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];
604 * @todo Implement sector size = 2048 or 2336.
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.
623 ssize_t CDROM_SKELTON::read_raw(uint8_t *buf, ssize_t buflen, size_t sectors, bool _clear)
625 if(buf == nullptr) return -1;
626 if(buflen <= 0) return -1;
628 memset(buf, 0x00, buflen);
631 if((now_track == 0) || (now_track >= 100)) return -1;
632 if(now_track >= tracks) return -1;
634 if(sectors <= 0) return -1;
635 if(current_fio == nullptr) return -1;
636 if(!(curent_fio->IsOpened())) return -1;
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;
642 uint8_t secbuf[2352];
643 int ps = physical_bytes_per_block;
644 if(ps >= 2352) ps = 2352;
650 for(int i = 0; i < sectors; i++) {
651 if(xptr >= physical_size) break;
652 if(now_lba >= sectors_of_this_track) {
654 if(!(allow_beyond_track)) {
657 if(now_track >= 99) return xptr;
658 if(!(get_track_image(now_track + 1))) {
662 if(!(seek_in_track(pregap_of_this_track))) {
667 size_t n = current_fio->Fread((uint8_t*)(secbuf), ps, 1);
672 memcpy(&(buf[xptr]), secbuf, ps);
675 return physical_size;
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.
687 bool CDROM_SKELTON::seek(uint8_t m, uint8_t s, uint8_t f, bool& in_track)
689 int64_t lba = msf_to_lba(m, s, f);
690 return seek_absolute_lba(lba);
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.
699 bool CDROM_SKELTON::seek_absolute_lba(int64_t lba, bool& in_track)
701 if(lba >= max_blocks) {
708 for(int i = 0; i < tracks; i++) {
709 if(toc_table[trk + 1].absolute_lba > lba) break;
713 trk = (tracks > 0) ? (tracks - 1) : 0;
715 if((trk == 0) || (!(toc_table[trk].available))) {
718 if(!(allow_beyond_track)) {
723 return seek_in_track(0);
725 if(trk != now_track) {
728 if(allow_beyond_track) {
729 if(!(get_track_image(now_trk))) { // Seek inner.
741 lba = lba - toc_table[now_track].lba_offset;
745 return seek_in_track(lba);
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.
754 bool CDROM_SKELTON::seek_relative_lba(int64_t lba, bool& in_track)
756 int64_t __lba = lba + now_lba;
757 return seek_absolute_lba(__lba, in_track);
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.
769 double CDROM_SKELTON::get_seek_time(uint8_t m, uint8_t s, uint8_t f)
771 int64_t lba = msf_to_lba(m, s, f);
772 return get_seek_time_absolute_lba(lba);
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.
780 double CDROM_SKELTON::get_seek_time_absolute_lba(int64_t lba)
785 int64_t step = (int64_t)(llabs(lba - now_lba));
786 if(step > max_blocks) step = max_blocks;
788 double _t = (get_single_seek_time_us() * ((double)step));
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.
798 double CDROM_SKELTON::get_seek_time_relative_lba(int64_t lba)
800 int64_t lba2 = llabs(lba);
801 if(lba2 > max_blocks) lba2 = max_blocks;
803 double _t = (get_single_seek_time_us() * ((double)lba2));
807 * @brief Check type of virtual disc image by filename.
808 * @param filename Filename of image (absolute path).
809 * @return Type of CD image.
811 static enum CDROM_META::CDIMAGE_TYPE CDROM_SKELTON::check_type(_TCHAR *filename)
813 if(filename == nullptr) {
814 return CDROM_META::IMAGETYPE_NONE;
816 if(!(FILEIO::IsFileExisting(filename))) {
817 return CDROM_META::IMAGETYPE_NONE;
819 if(check_file_extension(filename, _T(".gz"))) {
820 if(check_file_extension(filename, _T(".iso.gz"))) {
821 return CDROM_META::IMAGETYPE_ISO;
823 if(check_file_extension(filename, _T(".cue.gz"))) {
824 return CDROM_META::IMAGETYPE_CUE;
826 if(check_file_extension(filename, _T(".ccd.gz"))) {
827 return CDROM_META::IMAGETYPE_CCD;
830 if(check_file_extension(filename, _T(".iso"))) {
831 return CDROM_META::IMAGETYPE_ISO;
833 if(check_file_extension(filename, _T(".cue"))) {
834 return CDROM_META::IMAGETYPE_CUE;
836 if(check_file_extension(filename, _T(".ccd"))) {
837 return CDROM_META::IMAGETYPE_CCD;
840 return CDROM_META::IMAGETYPE_NONE; // Write Unique routines to next.
844 * @brief Get Relative LBA offset value (at head of this track) of this image.
845 * @return Relative LBA offset value (in image).
847 int64_t CDROM_SKELTON::get_lba_offset() const
849 return __get_lba_offset();
852 * @brief Get image type of this virtual CD.
853 * @return Image type of virtual CD.
855 enum CDROM_META::CDIMAGE_TYPE CDROM_SKELTON::get_type() const
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.
864 bool CDROM_SKELTON::get_track_image_file_name(std::string& var)
866 return __get_track_image_file_name(var);
870 * @brief Set seek speed.
871 * @param usec Basic transfer time normally 1.0 / 150.0KHz.
873 void CDROM_SKELTON::set_transfer_time_us(double usec)
875 __set_transfer_time_us(double usec);
878 * @brief Get transfer time per byte.
879 * @return transfer time as uSec.
881 double CDROM_SKELTON::get_transfer_time_us()
883 return __get_transfer_time_us();
886 * @brief Get seek multiply rate.
889 double CDROM_SKELTON::get_seek_speed()
891 return __get_seek_speed();
894 * @brief Get seek time per block.
895 * @return seek time as uSec.
897 double CDROM_SKELTON::get_single_seek_time_us()
899 return __get_single_seek_time_us();
902 * @brief Set seek speed.
903 * @param speed Transfer speed multiply rate, normally 1.0.
905 void CDROM_SKELTON::set_seek_speed(double speed)
907 __set_seek_speed(speed);
910 * @brief Set physical bytes per block (in emulation).
911 * @param bytes bytes per block.
913 void CDROM_SKELTON::set_physical_bytes_per_block(uint32_t bytes)
915 __set_physical_bytes_per_block(bytes);
918 * @brief Set physical bytes per block (in image).
919 * @param bytes bytes per block.
921 void CDROM_SKELTON::set_real_physical_bytes_per_block(uint32_t bytes)
923 __set_real_physical_bytes_per_block(bytes);
926 * @brief Set logical bytes per block (in emulation).
927 * @param bytes bytes per block.
929 void CDROM_SKELTON::set_logical_bytes_per_block(uint32_t bytes)
931 __set_logical_bytes_per_block(bytes);
935 * @brief Set enable/disable beyond track reading.
936 * @param val enable when setting true.
938 void CDROM_SKELTON::enable_beyond_track_reading(bool val)
940 allow_beyond_track = val;
944 * @brief Get track position now accessing.
945 * @return track value.-1 if not avaiable image.
947 int CDROM_SKELTON::get_track() const
949 return __get_track();
952 * @brief Get LBA position of now accessing.
953 * @return LBA position of now accessing.
955 int64_t CDROM_SKELTON::get_lba() const
960 * @brief Get number of sectors at this track.
961 * @return Number of sectors at this track.
963 int64_t CDROM_SKELTON::get_sectors_of_this_track() const
965 return __get_sectors_of_this_track();
968 * @brief Get current position-offset in this sector.
969 * @return Offset position.
971 int CDROM_SKELTON::get_offset_of_this_sector() const
973 return __get_offset_of_this_sector();
976 * @brief Whether this track is available.
977 * @return true if available.
979 bool CDROM_SKELTON::is_available() const
981 return __is_available();
984 * @brief Get blocks of this virtual CD.
985 * @return Blocks (sectors) of this virtual CD.
987 int64_t CDROM_SKELTON::get_blocks() const
989 return __get_blocks();
992 * @brief Get physical block size of this virtual CD.
993 * @return Physical block size of this virtual CD.
995 uint32_t CDROM_SKELTON::get_physical_block_size() const
997 return __get_physical_block_size();
1000 * @brief Get REAL (in VIRTUAL IMAGE) physical block size of this virtual CD.
1001 * @return Physical block size of this virtual CD.
1003 uint32_t CDROM_SKELTON::get_real_physical_block_size() const
1005 return __get_real_physical_block_size();
1008 * @brief Get logical block size of this virtual CD.
1009 * @return Logical block size of this virtual CD.
1011 uint32_t CDROM_SKELTON::get_logical_block_size() const
1013 return __get_logical_block_size();
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.
1022 bool CDROM_SKELTON::parse_sheet()
1024 for(int trk = 0; trk < 102; trk++) {
1025 init_toc_table(trk);
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.
1036 bool CDROM_SKELTON::load_save_toc_table(FILEIO* state_fio, bool loading)
1038 uint8_t ntracks = 0;
1040 ntracks = state_fio->FgetUint8();
1041 if(ntracks >= 101) return false;
1044 if(ntracks >= 101) return false;
1045 state_fio->FputUint8(tracks);
1048 for(int i = 1; i <= ntracks; i++) {
1050 n = state_fio->FgetUint8(); //!< Get track number
1051 if(n != i) return false; //!< Error when wrong filename.
1053 state_fio->FputUint8((uint8_t)i);
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);
1075 toc_table[0].available = true;
1077 toc_table[0].available = false;
1084 * @brief Seek assigned position in track.
1085 * @param lba *Relative* LBA in this track.
1086 * @return true if success.
1088 bool CDROM_SKELTON::seek_in_track(int64_t lba)
1090 if(lba < 0) return false;
1091 if((now_track < 0) || (now_track >= 100)) return false;
1093 int64_t _lba_bak = lba + lba_offset_of_this_track;
1094 if(current_fio == nullptr) return true;
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;
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
1106 lba = lba - pregap_of_this_track;
1107 if(lba < 0) lba = 0;
1109 int64_t offset = lba * get_real_physical_block_size();
1111 if(offset >= LONG_MAX) {
1113 offset_in_sector = 0;
1116 if(current_fio->Fseek(offset, FILEIO_SEEK_SET) != 0) {
1118 offset_in_sector = 0;
1122 bytes_position = offset;
1123 offset_in_sector = 0;
1127 * @brief Get image data of track.
1128 * @param track track number.
1129 * return true if success.
1131 bool CDROM_SKELTON::get_track_image(uint8_t track)
1133 bool result = false;
1134 if(track >= tracks) track = tracks;
1136 * Set default values
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;
1144 offset_in_sector = 0;
1146 lba_offset_of_this_track = 0;
1148 sectors_of_this_track = 0;
1149 pregap_of_this_track = 150;
1153 if(current_fio != nullptr) {
1154 if(current_fio->IsOpened()) {
1155 current_fio->Fclose();
1164 if(now_track != track) {
1167 if(!(toc_table[track].available)) {
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);
1176 __filename.assign(toc_table[track].filename, _MAX_PATH);
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;
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;
1195 * @brief reset FILEIOs for sheet and image.
1197 void CDROM_SKELTON::reset_sheet_fio()
1199 if(current_fio != nullptr) {
1200 if(current_fio->IsOpened()) {
1201 current_fio->Fclose();
1206 if(sheet_fio != nullptr) {
1207 if(sheet_fio->IsOpened()) {
1208 sheet_fio->Fclose();
1216 * @brief To be Upper characters from string.
1217 * @param s source string.
1218 * @return ToUpper'ed string.
1220 static std::string CDROM_SKELTON::to_upper(std::string s)
1226 for(auto c = s.begin(); c != s.end(); ++c) {
1227 _TCHAR n = std::toupper(*c);
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.
1239 static uint64_t CDROM_SKELTON::get_val_from_bcdstr(std::string s, bool& errorval)
1244 for(auto c = s.begin(); c != s.end() ; ++c) {
1246 if((cc < '0') || (cc > '9')) {
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.
1268 static uint64_t CDROM_SKELTON::get_val_from_hexstr(std::string s, bool& errorval)
1273 for(auto c = s.begin(); c != s.end() ; ++c) {
1275 bool is_val = false;
1276 if((cc >= '0') && (cc <= '9')) {
1279 } else if((cc >= 'A') && (cc <= 'F')) {
1282 } else if((cc >= 'a') && (cc <= 'f')) {
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.
1307 static uint64_t CDROM_SKELTON::get_frames_from_msfstr(std::string timestr, bool &errorval)
1309 if(timestr.size() < 8) { //xx:xx:xx
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);
1319 if((_d1 != ":") || (_d2 != ":")) {
1320 // delimiter(s) not found
1324 bool error1, error2, error3;
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)) {
1347 uint64_t nt = (mm * 60 * 75) + (ss * 75) + ff;
1353 #define STATE_VERSION 1
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.
1360 bool CDROM_SKELTON::load_save_params(FILEIO* state_fio, bool loading)
1362 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
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);
1375 state_fio->StateValue(transfer_time_us);
1376 state_fio->StateValue(seek_speed);
1378 state_fio->StateValue(allow_beyond_track);
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);
1390 _TCHAR _l[_MAX_PATH] = {0};
1392 strsize = state_fio->FgetInt32_LE();
1393 if(strsize < 0) return false;
1396 state_fio->StateArray(_l, _MAX_PATH, 1);
1397 __filename.assign(_l, _MAX_PATH - 1);
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);
1409 * @brief Initialize TOC table..
1410 * @param num track number.
1412 void CDROM_SKELTON::init_toc_table(uint8_t num)
1414 if(num > 101) return;
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;
1429 memset(toc_table[num].filename, 0x00, sizeof(_TCHAR) * _MAX_PATH);
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.
1438 bool CDROM_SKELTON::process_state(FILEIO* state_fio, bool loading)
1441 * @note Must place checking STATE_VERSION and MAGIC for unique image type..
1443 if(!(load_save_params(state_fio, loading))) {
1446 if(!(load_save_toc_table(state_fio, loading))) {
1450 * please place state procesing for unuque values below.