2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "cdioSupport.h"
11 #include "platform/Environment.h"
12 #include "utils/log.h"
16 #include <cdio/cd_types.h>
17 #include <cdio/cdio.h>
18 #include <cdio/logging.h>
20 #include <cdio/util.h>
24 /* Helper constexpr to hide the 0 return code for tray closed. */
25 constexpr int CDIO_TRAY_STATUS_CLOSED
= 0;
26 /* Helper constexpr to hide the 1 return code for tray open */
27 constexpr int CDIO_TRAY_STATUS_OPEN
= 1;
28 /* Helper constexpr to hide the -2 driver code for unsupported tray status get operation */
29 constexpr int CDIO_TRAY_STATUS_OP_UNSUPPORTED
= -2;
32 using namespace MEDIA_DETECT
;
34 std::shared_ptr
<CLibcdio
> CLibcdio::m_pInstance
;
36 /* Some interesting sector numbers stored in the above buffer. */
37 #define ISO_SUPERBLOCK_SECTOR 16 /* buffer[0] */
38 #define UFS_SUPERBLOCK_SECTOR 4 /* buffer[2] */
39 #define BOOT_SECTOR 17 /* buffer[3] */
40 #define VCD_INFO_SECTOR 150 /* buffer[4] */
41 #define UDF_ANCHOR_SECTOR 256 /* buffer[5] */
44 signature_t
CCdIoSupport::sigs
[] = {
45 /*buffer[x] off look for description */
46 {0, 1, "CD001\0", "ISO 9660\0"},
47 {0, 1, "CD-I", "CD-I"},
48 {0, 8, "CDTV", "CDTV"},
49 {0, 8, "CD-RTOS", "CD-RTOS"},
50 {0, 9, "CDROM", "HIGH SIERRA"},
51 {0, 16, "CD-BRIDGE", "BRIDGE"},
52 {0, 1024, "CD-XA001", "XA"},
53 {1, 64, "PPPPHHHHOOOOTTTTOOOO____CCCCDDDD", "PHOTO CD"},
54 {1, 0x438, "\x53\xef", "EXT2 FS"},
55 {2, 1372, "\x54\x19\x01\x0", "UFS"},
56 {3, 7, "EL TORITO", "BOOTABLE"},
57 {4, 0, "VIDEO_CD", "VIDEO CD"},
58 {4, 0, "SUPERVCD", "Chaoji VCD"},
59 {0, 1, "BEA01", "UDF"},
65 cdio_log_handler (cdio_log_level_t level
, const char message
[])
71 CLog::Log(LOGDEBUG
, "**ERROR: {}", message
);
74 CLog::Log(LOGDEBUG
, "--DEBUG: {}", message
);
77 CLog::Log(LOGDEBUG
, "++ WARN: {}", message
);
80 CLog::Log(LOGDEBUG
, " INFO: {}", message
);
83 CLog::Log(LOGDEBUG
, "!ASSERT: {}", message
);
86 //cdio_assert_not_reached ();
92 //////////////////////////////////////////////////////////////////////
93 // Construction/Destruction
94 //////////////////////////////////////////////////////////////////////
95 CLibcdio::CLibcdio(): s_defaultDevice(NULL
)
97 cdio_log_set_handler( cdio_log_handler
);
100 CLibcdio::~CLibcdio()
102 free(s_defaultDevice
);
103 s_defaultDevice
= NULL
;
106 void CLibcdio::ReleaseInstance()
111 std::shared_ptr
<CLibcdio
> CLibcdio::GetInstance()
115 m_pInstance
= std::shared_ptr
<CLibcdio
>(new CLibcdio());
120 CdIo_t
* CLibcdio::cdio_open(const char *psz_source
, driver_id_t driver_id
)
122 std::unique_lock
<CCriticalSection
> lock(*this);
124 return( ::cdio_open(psz_source
, driver_id
) );
127 CdIo_t
* CLibcdio::cdio_open_win32(const char *psz_source
)
129 std::unique_lock
<CCriticalSection
> lock(*this);
131 return( ::cdio_open_win32(psz_source
) );
134 void CLibcdio::cdio_destroy(CdIo_t
*p_cdio
)
136 std::unique_lock
<CCriticalSection
> lock(*this);
138 ::cdio_destroy(p_cdio
);
141 discmode_t
CLibcdio::cdio_get_discmode(CdIo_t
*p_cdio
)
143 std::unique_lock
<CCriticalSection
> lock(*this);
145 return( ::cdio_get_discmode(p_cdio
) );
148 CdioTrayStatus
CLibcdio::mmc_get_tray_status(const CdIo_t
* p_cdio
)
150 std::unique_lock
<CCriticalSection
> lock(*this);
152 int status
= ::mmc_get_tray_status(p_cdio
);
155 case CDIO_TRAY_STATUS_CLOSED
:
156 return CdioTrayStatus::CLOSED
;
157 case CDIO_TRAY_STATUS_OPEN
:
158 return CdioTrayStatus::OPEN
;
159 case CDIO_TRAY_STATUS_OP_UNSUPPORTED
:
160 return CdioTrayStatus::UNKNOWN
;
164 return CdioTrayStatus::DRIVER_ERROR
;
167 driver_return_code_t
CLibcdio::cdio_eject_media(CdIo_t
** p_cdio
)
169 std::unique_lock
<CCriticalSection
> lock(*this);
171 return( ::cdio_eject_media(p_cdio
) );
174 track_t
CLibcdio::cdio_get_last_track_num(const CdIo_t
*p_cdio
)
176 std::unique_lock
<CCriticalSection
> lock(*this);
178 return( ::cdio_get_last_track_num(p_cdio
) );
181 lsn_t
CLibcdio::cdio_get_track_lsn(const CdIo_t
*p_cdio
, track_t i_track
)
183 std::unique_lock
<CCriticalSection
> lock(*this);
185 return( ::cdio_get_track_lsn(p_cdio
, i_track
) );
188 lsn_t
CLibcdio::cdio_get_track_last_lsn(const CdIo_t
*p_cdio
, track_t i_track
)
190 std::unique_lock
<CCriticalSection
> lock(*this);
192 return( ::cdio_get_track_last_lsn(p_cdio
, i_track
) );
195 driver_return_code_t
CLibcdio::cdio_read_audio_sectors(
196 const CdIo_t
*p_cdio
, void *p_buf
, lsn_t i_lsn
, uint32_t i_blocks
)
198 std::unique_lock
<CCriticalSection
> lock(*this);
200 return( ::cdio_read_audio_sectors(p_cdio
, p_buf
, i_lsn
, i_blocks
) );
203 driver_return_code_t
CLibcdio::cdio_close_tray(const char* psz_source
, driver_id_t
* driver_id
)
205 std::unique_lock
<CCriticalSection
> lock(*this);
206 return (::cdio_close_tray(psz_source
, driver_id
));
209 const char* CLibcdio::cdio_driver_errmsg(driver_return_code_t drc
)
211 return (::cdio_driver_errmsg(drc
));
214 char* CLibcdio::GetDeviceFileName()
216 std::unique_lock
<CCriticalSection
> lock(*this);
218 // If We don't have a DVD device initially present (Darwin or a USB DVD drive),
219 // We have to keep checking in case one appears.
220 if (s_defaultDevice
&& strlen(s_defaultDevice
) == 0)
222 free(s_defaultDevice
);
223 s_defaultDevice
= NULL
;
226 if (s_defaultDevice
== NULL
)
228 std::string strEnvDvd
= CEnvironment::getenv("KODI_DVD_DEVICE");
229 if (!strEnvDvd
.empty())
230 s_defaultDevice
= strdup(strEnvDvd
.c_str());
233 CdIo_t
*p_cdio
= ::cdio_open(NULL
, DRIVER_UNKNOWN
);
236 s_defaultDevice
= strdup(::cdio_get_arg(p_cdio
, "source"));
237 ::cdio_destroy(p_cdio
);
240 s_defaultDevice
= strdup("");
243 return s_defaultDevice
;
247 //////////////////////////////////////////////////////////////////////
248 // Construction/Destruction
249 //////////////////////////////////////////////////////////////////////
250 CCdIoSupport::CCdIoSupport() : cdio(nullptr), m_cdio(CLibcdio::GetInstance())
252 m_nFirstData
= -1; /* # of first data track */
253 m_nNumData
= 0; /* # of data tracks */
254 m_nFirstAudio
= -1; /* # of first audio track */
255 m_nNumAudio
= 0; /* # of audio tracks */
256 m_nIsofsSize
= 0; /* size of session */
266 CCdIoSupport::~CCdIoSupport() = default;
268 bool CCdIoSupport::EjectTray()
273 bool CCdIoSupport::CloseTray()
278 HANDLE
CCdIoSupport::OpenCDROM()
280 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
282 char* source_name
= m_cdio
->GetDeviceFileName();
283 CdIo
* cdio
= ::cdio_open(source_name
, DRIVER_UNKNOWN
);
285 return reinterpret_cast<HANDLE
>(cdio
);
288 HANDLE
CCdIoSupport::OpenIMAGE( std::string
& strFilename
)
290 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
292 CdIo
* cdio
= ::cdio_open(strFilename
.c_str(), DRIVER_UNKNOWN
);
294 return reinterpret_cast<HANDLE
>(cdio
);
297 int CCdIoSupport::ReadSector(HANDLE hDevice
, DWORD dwSector
, char* lpczBuffer
)
299 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
301 CdIo
* cdio
= (CdIo
*) hDevice
;
305 if ( ::cdio_read_mode1_sector( cdio
, lpczBuffer
, dwSector
, false ) == 0 )
311 int CCdIoSupport::ReadSectorMode2(HANDLE hDevice
, DWORD dwSector
, char* lpczBuffer
)
313 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
315 CdIo
* cdio
= (CdIo
*) hDevice
;
319 if ( ::cdio_read_mode2_sector( cdio
, lpczBuffer
, dwSector
, false ) == 0 )
325 int CCdIoSupport::ReadSectorCDDA(HANDLE hDevice
, DWORD dwSector
, char* lpczBuffer
)
327 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
329 CdIo
* cdio
= (CdIo
*) hDevice
;
333 if ( ::cdio_read_audio_sector( cdio
, lpczBuffer
, dwSector
) == 0 )
339 void CCdIoSupport::CloseCDROM(HANDLE hDevice
)
341 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
343 CdIo
* cdio
= (CdIo
*) hDevice
;
348 ::cdio_destroy( cdio
);
351 void CCdIoSupport::PrintAnalysis(int fs
, int num_audio
)
353 switch (fs
& FS_MASK
)
356 CLog::Log(LOGINFO
, "CD-ROM with UDF filesystem");
359 CLog::Log(LOGINFO
, "CD-ROM with audio tracks");
362 CLog::Log(LOGINFO
, "CD-ROM with ISO 9660 filesystem");
365 CLog::Log(LOGINFO
, " with joliet extension level {}", m_nJolietLevel
);
369 CLog::Log(LOGINFO
, " and rockridge extensions");
372 case FS_ISO_9660_INTERACTIVE
:
373 CLog::Log(LOGINFO
, "CD-ROM with CD-RTOS and ISO 9660 filesystem");
376 CLog::Log(LOGINFO
, "CD-ROM with High Sierra filesystem");
379 CLog::Log(LOGINFO
, "CD-Interactive{}", num_audio
> 0 ? "/Ready" : "");
382 CLog::Log(LOGINFO
, "CD-ROM with Macintosh HFS");
385 CLog::Log(LOGINFO
, "CD-ROM with both Macintosh HFS and ISO 9660 filesystem");
388 CLog::Log(LOGINFO
, "CD-ROM with both UDF and ISO 9660 filesystem");
391 CLog::Log(LOGINFO
, "CD-ROM with Unix UFS");
394 CLog::Log(LOGINFO
, "CD-ROM with Linux second extended filesystem");
397 CLog::Log(LOGINFO
, "CD-ROM with Panasonic 3DO filesystem");
400 CLog::Log(LOGINFO
, "CD-ROM with unknown filesystem");
404 switch (fs
& FS_MASK
)
407 case FS_ISO_9660_INTERACTIVE
:
410 CLog::Log(LOGINFO
, "ISO 9660: {} blocks, label {}", m_nIsofsSize
, m_strDiscLabel
);
414 switch (fs
& FS_MASK
)
418 CLog::Log(LOGINFO
, "UDF: version {:x}.{:02x}", m_nUDFVerMajor
, m_nUDFVerMinor
);
422 if (m_nFirstData
== 1 && num_audio
> 0)
424 CLog::Log(LOGINFO
, "mixed mode CD ");
428 CLog::Log(LOGINFO
, "XA sectors ");
430 if (fs
& MULTISESSION
)
432 CLog::Log(LOGINFO
, "Multisession, offset = {} ", m_nMsOffset
);
434 if (fs
& HIDDEN_TRACK
)
436 CLog::Log(LOGINFO
, "Hidden Track ");
440 CLog::Log(LOGINFO
, "{}Photo CD ", num_audio
> 0 ? " Portfolio " : "");
444 CLog::Log(LOGINFO
, "Commodore CDTV ");
446 if (m_nFirstData
> 1)
448 CLog::Log(LOGINFO
, "CD-Plus/Extra ");
452 CLog::Log(LOGINFO
, "bootable CD ");
454 if (fs
& VIDEOCDI
&& num_audio
== 0)
456 CLog::Log(LOGINFO
, "Video CD ");
457 #if defined(HAVE_VCDINFO) && defined(DEBUG)
468 CLog::Log(LOGINFO
, "Chaoji Video CD");
472 int CCdIoSupport::ReadBlock(int superblock
, uint32_t offset
, uint8_t bufnum
, track_t track_num
)
474 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
476 unsigned int track_sec_count
= ::cdio_get_track_sec_count(cdio
, track_num
);
477 memset(buffer
[bufnum
], 0, CDIO_CD_FRAMESIZE
);
479 if ( track_sec_count
< static_cast<unsigned int>(superblock
))
481 ::cdio_debug("reading block %u skipped track %d has only %u sectors\n",
482 superblock
, track_num
, track_sec_count
);
486 ::cdio_debug("about to read sector %lu\n",
487 (long unsigned int) offset
+ superblock
);
489 if (::cdio_get_track_green(cdio
, track_num
))
491 if (0 < ::cdio_read_mode2_sector(cdio
, buffer
[bufnum
],
492 offset
+ superblock
, false))
497 if (0 < ::cdio_read_mode1_sector(cdio
, buffer
[bufnum
],
498 offset
+ superblock
, false))
505 bool CCdIoSupport::IsIt(int num
)
507 signature_t
*sigp
= &sigs
[num
];
508 int len
= strlen(sigp
->sig_str
);
510 //! @todo check that num < largest sig.
511 return 0 == memcmp(&buffer
[sigp
->buf_num
][sigp
->offset
], sigp
->sig_str
, len
);
514 int CCdIoSupport::IsHFS(void)
516 return (0 == memcmp(&buffer
[1][512], "PM", 2)) ||
517 (0 == memcmp(&buffer
[1][512], "TS", 2)) ||
518 (0 == memcmp(&buffer
[1][1024], "BD", 2));
521 int CCdIoSupport::Is3DO(void)
523 return (0 == memcmp(&buffer
[1][0], "\x01\x5a\x5a\x5a\x5a\x5a\x01", 7)) &&
524 (0 == memcmp(&buffer
[1][40], "CD-ROM", 6));
527 int CCdIoSupport::IsJoliet(void)
529 return 2 == buffer
[3][0] && buffer
[3][88] == 0x25 && buffer
[3][89] == 0x2f;
532 int CCdIoSupport::IsUDF(void)
534 return 2 == ((uint16_t)buffer
[5][0] | ((uint16_t)buffer
[5][1] << 8));
537 /* ISO 9660 volume space in M2F1_SECTOR_SIZE byte units */
538 int CCdIoSupport::GetSize(void)
540 return ((buffer
[0][80] & 0xff) |
541 ((buffer
[0][81] & 0xff) << 8) |
542 ((buffer
[0][82] & 0xff) << 16) |
543 ((buffer
[0][83] & 0xff) << 24));
546 int CCdIoSupport::GetJolietLevel( void )
548 switch (buffer
[3][90])
560 #define is_it_dbg(sig) /*\
561 if (is_it(sig)) printf("%s, ", sigs[sig].description)*/
563 int CCdIoSupport::GuessFilesystem(int start_session
, track_t track_num
)
565 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
567 int ret
= FS_UNKNOWN
;
568 cdio_iso_analysis_t anal
;
572 memset(&anal
, 0, sizeof(anal
));
573 discmode_t mode
= ::cdio_get_discmode(cdio
);
574 if (::cdio_is_discmode_dvd(mode
))
577 m_nIsofsSize
= ::cdio_get_disc_last_lsn(cdio
);
578 m_nJolietLevel
= ::cdio_get_joliet_level(cdio
);
583 fs
= ::cdio_guess_cd_type(cdio
, start_session
, track_num
, &anal
);
585 switch(CDIO_FSTYPE(fs
))
591 case CDIO_FS_HIGH_SIERRA
:
592 ret
= FS_HIGH_SIERRA
;
595 case CDIO_FS_ISO_9660
:
599 case CDIO_FS_INTERACTIVE
:
600 ret
= FS_ISO_9660_INTERACTIVE
;
620 case CDIO_FS_ISO_UDF
:
631 m_nUDFVerMinor
= anal
.UDFVerMinor
;
632 m_nUDFVerMajor
= anal
.UDFVerMajor
;
635 m_strDiscLabel
= anal
.iso_label
;
636 m_nIsofsSize
= anal
.isofs_size
;
637 m_nJolietLevel
= anal
.joliet_level
;
642 void CCdIoSupport::GetCdTextInfo(xbmc_cdtext_t
&xcdt
, int trackNum
)
644 // cdtext disabled for windows as some setup doesn't like mmc commands
645 // and stall for over a minute in cdio_get_cdtext 83
646 #if !defined(TARGET_WINDOWS)
647 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
649 // Get the CD-Text , if any
650 #if defined(LIBCDIO_VERSION_NUM) && (LIBCDIO_VERSION_NUM >= 84)
651 cdtext_t
*pcdtext
= static_cast<cdtext_t
*>( cdio_get_cdtext(cdio
) );
653 //! @todo - remove after Ubuntu 16.04 (Xenial) is EOL
654 cdtext_t
*pcdtext
= (cdtext_t
*)::cdio_get_cdtext(cdio
, trackNum
);
660 #if defined(LIBCDIO_VERSION_NUM) && (LIBCDIO_VERSION_NUM >= 84)
661 for (int i
=0; i
< MAX_CDTEXT_FIELDS
; i
++)
662 if (cdtext_get_const(pcdtext
, (cdtext_field_t
)i
, trackNum
))
663 xcdt
[(cdtext_field_t
)i
] = cdtext_field2str((cdtext_field_t
)i
);
665 //! @todo - remove after Ubuntu 16.04 (Xenial) is EOL
666 // Same ids used in libcdio and for our structure + the ids are consecutive make this copy loop safe.
667 for (int i
= 0; i
< MAX_CDTEXT_FIELDS
; i
++)
668 if (pcdtext
->field
[i
])
669 xcdt
[(cdtext_field_t
)i
] = pcdtext
->field
[(cdtext_field_t
)i
];
671 #endif // TARGET_WINDOWS
674 CCdInfo
* CCdIoSupport::GetCdInfo(char* cDeviceFileName
)
676 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
679 if(cDeviceFileName
== NULL
)
680 source_name
= m_cdio
->GetDeviceFileName();
682 source_name
= cDeviceFileName
;
684 cdio
= ::cdio_open(source_name
, DRIVER_UNKNOWN
);
687 CLog::Log(LOGERROR
, "{}: Error in automatically selecting driver with input", __FUNCTION__
);
691 bool bIsCDRom
= true;
693 m_nFirstTrackNum
= ::cdio_get_first_track_num(cdio
);
694 if (m_nFirstTrackNum
== CDIO_INVALID_TRACK
)
696 #if !defined(TARGET_DARWIN)
697 ::cdio_destroy(cdio
);
700 m_nFirstTrackNum
= 1;
705 m_nNumTracks
= ::cdio_get_num_tracks(cdio
);
706 if (m_nNumTracks
== CDIO_INVALID_TRACK
)
708 #if !defined(TARGET_DARWIN)
709 ::cdio_destroy(cdio
);
717 CCdInfo
* info
= new CCdInfo
;
718 info
->SetFirstTrack( m_nFirstTrackNum
);
719 info
->SetTrackCount( m_nNumTracks
);
721 for (i
= m_nFirstTrackNum
; i
<= CDIO_CDROM_LEADOUT_TRACK
; i
++)
724 if (bIsCDRom
&& !::cdio_get_track_msf(cdio
, i
, &msf
))
727 ti
.nfsInfo
= FS_UNKNOWN
;
734 info
->SetTrackInformation( i
, ti
);
735 CLog::Log(LOGDEBUG
, "cdio_track_msf for track {} failed, I give up.", i
);
737 ::cdio_destroy(cdio
);
742 if (bIsCDRom
&& TRACK_FORMAT_AUDIO
== ::cdio_get_track_format(cdio
, i
))
745 ti
.nfsInfo
= FS_NO_DATA
;
747 int temp1
= ::cdio_get_track_lba(cdio
, i
) - CDIO_PREGAP_SECTORS
;
748 int temp2
= ::cdio_get_track_lba(cdio
, i
+ 1) - CDIO_PREGAP_SECTORS
;
749 // The length is the address of the second track minus the address of the first track
750 temp2
-= temp1
; // temp2 now has length of track1 in frames
751 ti
.nMins
= temp2
/ (60 * 75); // calculate the number of minutes
752 temp2
%= 60 * 75; // calculate the left-over frames
753 ti
.nSecs
= temp2
/ 75; // calculate the number of seconds
754 if ( -1 == m_nFirstAudio
)
757 // Make sure that we have the Disc related info available
761 GetCdTextInfo(xcdt
, 0);
762 info
->SetDiscCDTextInformation( xcdt
);
765 // Get this tracks info
766 GetCdTextInfo(ti
.cdtext
, i
);
771 if ( -1 == m_nFirstData
)
774 ti
.nfsInfo
= FS_NO_DATA
;
778 ti
.nFrames
= ::cdio_get_track_lba(cdio
, i
);
782 info
->SetTrackInformation( i
, ti
);
783 /* skip to leadout? */
784 if (i
== m_nNumTracks
)
785 i
= CDIO_CDROM_LEADOUT_TRACK
;
788 info
->SetCddbDiscId( CddbDiscId() );
789 info
->SetDiscLength( ::cdio_get_track_lba(cdio
, CDIO_CDROM_LEADOUT_TRACK
) / CDIO_CD_FRAMES_PER_SEC
);
791 info
->SetAudioTrackCount( m_nNumAudio
);
792 info
->SetDataTrackCount( m_nNumData
);
793 info
->SetFirstAudioTrack( m_nFirstAudio
);
794 info
->SetFirstDataTrack( m_nFirstData
);
796 CLog::Log(LOGINFO
, "CD Analysis Report");
797 CLog::Log(LOGINFO
, STRONG
);
799 /* Try to find out what sort of CD we have */
802 /* no data track, may be a "real" audio CD or hidden track CD */
805 ::cdio_get_track_msf(cdio
, 1, &msf
);
806 m_nStartTrack
= ::cdio_msf_to_lsn(&msf
);
808 /* CD-I/Ready says start_track <= 30*75 then CDDA */
809 if (m_nStartTrack
> 100 /* 100 is just a guess */)
811 m_nFs
= GuessFilesystem(0, 1);
812 if ((m_nFs
& FS_MASK
) != FS_UNKNOWN
)
813 m_nFs
|= HIDDEN_TRACK
;
816 m_nFs
&= ~FS_MASK
; /* del filesystem info */
817 CLog::Log(LOGDEBUG
, "Oops: {} unused sectors at start, but hidden track check failed.",
821 PrintAnalysis(m_nFs
, m_nNumAudio
);
825 /* We have data track(s) */
826 for (j
= 2, i
= m_nFirstData
; i
<= m_nNumTracks
; i
++)
829 track_format_t track_format
= ::cdio_get_track_format(cdio
, i
);
831 ::cdio_get_track_msf(cdio
, i
, &msf
);
833 switch ( track_format
)
835 case TRACK_FORMAT_AUDIO
:
838 ti
.nfsInfo
= FS_NO_DATA
;
843 ti
.nFrames
= ::cdio_get_track_lba(cdio
, i
);
846 info
->SetTrackInformation( i
+ 1, ti
);
848 case TRACK_FORMAT_ERROR
:
850 case TRACK_FORMAT_CDI
:
851 case TRACK_FORMAT_XA
:
852 case TRACK_FORMAT_DATA
:
853 case TRACK_FORMAT_PSX
:
857 m_nStartTrack
= (i
== 1) ? 0 : ::cdio_msf_to_lsn(&msf
);
859 /* Save the start of the data area */
860 if (i
== m_nFirstData
)
861 m_nDataStart
= m_nStartTrack
;
863 /* Skip tracks which belong to the current walked session */
864 if (m_nStartTrack
< m_nDataStart
+ m_nIsofsSize
)
867 m_nFs
= GuessFilesystem(m_nStartTrack
, i
);
870 ti
.ms_offset
= m_nMsOffset
;
871 ti
.isofs_size
= m_nIsofsSize
;
872 ti
.nJolietLevel
= m_nJolietLevel
;
873 ti
.nFrames
= ::cdio_get_track_lba(cdio
, i
);
876 info
->SetDiscLabel(m_strDiscLabel
);
881 /* Track is beyond last session -> new session found */
882 m_nMsOffset
= m_nStartTrack
;
885 "Session #{} starts at track {:2}, LSN: {:6},"
886 " ISO 9660 blocks: {:6}",
887 j
++, i
, m_nStartTrack
, m_nIsofsSize
);
889 CLog::Log(LOGINFO
, "ISO 9660: {} blocks, label {}", m_nIsofsSize
, m_strDiscLabel
);
890 m_nFs
|= MULTISESSION
;
895 PrintAnalysis(m_nFs
, m_nNumAudio
);
898 info
->SetTrackInformation( i
, ti
);
902 ::cdio_destroy( cdio
);
907 // Returns the sum of the decimal digits in a number. Eg. 1955 = 20
908 int CCdIoSupport::CddbDecDigitSum(int n
)
921 // Return the number of seconds (discarding frame portion) of an MSF
922 unsigned int CCdIoSupport::MsfSeconds(msf_t
*msf
)
924 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
926 return ::cdio_from_bcd8(msf
->m
)*60 + ::cdio_from_bcd8(msf
->s
);
930 // Compute the CDDB disk ID for an Audio disk.
931 // This is a funny checksum consisting of the concatenation of 3 things:
932 // The sum of the decimal digits of sizes of all tracks,
933 // The total length of the disk, and
934 // The number of tracks.
936 uint32_t CCdIoSupport::CddbDiscId()
938 std::unique_lock
<CCriticalSection
> lock(*m_cdio
);
944 for (i
= 1; i
<= m_nNumTracks
; i
++)
946 ::cdio_get_track_msf(cdio
, i
, &msf
);
947 n
+= CddbDecDigitSum(MsfSeconds(&msf
));
950 ::cdio_get_track_msf(cdio
, 1, &start_msf
);
951 ::cdio_get_track_msf(cdio
, CDIO_CDROM_LEADOUT_TRACK
, &msf
);
953 t
= MsfSeconds(&msf
) - MsfSeconds(&start_msf
);
955 return ((n
% 0xff) << 24 | t
<< 8 | m_nNumTracks
);