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.
11 // CCdInfo - Information about media type of an inserted cd
12 // CCdIoSupport - Wrapper class for libcdio with the interface of CIoSupport
13 // and detecting the filesystem on the Disc.
15 // by Bobbin007 in 2003
16 // CD-Text support by Mog - Oct 2004
18 #include "threads/CriticalSection.h"
25 #include "PlatformDefs.h" // for ssize_t typedef, used by cdio
27 #include <cdio/cdio.h>
29 namespace MEDIA_DETECT
32 #define STRONG "__________________________________\n"
35 #define FS_NO_DATA 0 /* audio only */
36 #define FS_HIGH_SIERRA 1
38 #define FS_INTERACTIVE 3
42 #define FS_ISO_HFS 7 /* both hfs & isofs filesystem */
43 #define FS_ISO_9660_INTERACTIVE 8 /* both CD-RTOS and isofs filesystem */
51 #define MULTISESSION 32
53 #define HIDDEN_TRACK 128
57 #define ROCKRIDGE 2048
59 #define CVD 8192 /* Choiji Video CD */
71 #define IS_BOOTABLE 10
72 #define IS_VIDEO_CD 11 /* Video CD */
73 #define IS_CVD 12 /* Chinese Video CD - slightly incompatible with SVCD */
76 typedef struct signature
81 const char *description
;
85 typedef std::map
<cdtext_field_t
, std::string
> xbmc_cdtext_t
;
87 typedef struct TRACKINFO
89 int nfsInfo
; // Information of the Tracks Filesystem
90 int nJolietLevel
; // Jouliet Level
91 int ms_offset
; // Multisession Offset
92 int isofs_size
; // Size of the ISO9660 Filesystem
93 int nFrames
; // Can be used for cddb query
94 int nMins
; // minutes playtime part of Track
95 int nSecs
; // seconds playtime part of Track
96 xbmc_cdtext_t cdtext
; // CD-Text for this track
100 /*! \brief Helper enum class for the MMC tray state
102 enum class CdioTrayStatus
104 /* The MMC tray state is reported closed */
106 /* The MMC tray state is reported open */
108 /* The MMC tray status operation is not supported */
110 /* Generic driver error */
119 m_bHasCDDBInfo
= true;
120 m_nLength
= m_nFirstTrack
= m_nNumTrack
= m_nNumAudio
= m_nFirstAudio
= m_nNumData
= m_nFirstData
= 0;
123 trackinfo
GetTrackInformation( int nTrack
) { return m_ti
[nTrack
-1]; }
124 const xbmc_cdtext_t
& GetDiscCDTextInformation() const { return m_cdtext
; }
126 bool HasDataTracks() { return (m_nNumData
> 0); }
127 bool HasAudioTracks() { return (m_nNumAudio
> 0); }
128 int GetFirstTrack() { return m_nFirstTrack
; }
129 int GetTrackCount() { return m_nNumTrack
; }
130 int GetFirstAudioTrack() { return m_nFirstAudio
; }
131 int GetFirstDataTrack() { return m_nFirstData
; }
132 int GetDataTrackCount() { return m_nNumData
; }
133 int GetAudioTrackCount() { return m_nNumAudio
; }
134 uint32_t GetCddbDiscId() { return m_ulCddbDiscId
; }
135 int GetDiscLength() { return m_nLength
; }
136 const std::string
& GetDiscLabel() const { return m_strDiscLabel
; }
138 // CD-ROM with ISO 9660 filesystem
139 bool IsIso9660( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_ISO_9660
); }
140 // CD-ROM with joliet extension
141 bool IsJoliet( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& JOLIET
) ? false : true; }
142 // Joliet extension level
143 int GetJolietLevel( int nTrack
) { return m_ti
[nTrack
- 1].nJolietLevel
; }
144 // ISO filesystem size
145 int GetIsoSize( int nTrack
) { return m_ti
[nTrack
- 1].isofs_size
; }
146 // CD-ROM with rockridge extensions
147 bool IsRockridge( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& ROCKRIDGE
) ? false : true; }
149 // CD-ROM with CD-RTOS and ISO 9660 filesystem
150 bool IsIso9660Interactive( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_ISO_9660_INTERACTIVE
); }
152 // CD-ROM with High Sierra filesystem
153 bool IsHighSierra( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_HIGH_SIERRA
); }
155 // CD-Interactive, with audiotracks > 0 CD-Interactive/Ready
156 bool IsCDInteractive( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_INTERACTIVE
); }
158 // CD-ROM with Macintosh HFS
159 bool IsHFS( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_HFS
); }
161 // CD-ROM with both Macintosh HFS and ISO 9660 filesystem
162 bool IsISOHFS( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_ISO_HFS
); }
164 // CD-ROM with both UDF and ISO 9660 filesystem
165 bool IsISOUDF( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_ISO_UDF
); }
167 // CD-ROM with Unix UFS
168 bool IsUFS( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_UFS
); }
170 // CD-ROM with Linux second extended filesystem
171 bool IsEXT2( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_EXT2
); }
173 // CD-ROM with Panasonic 3DO filesystem
174 bool Is3DO( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_3DO
); }
177 bool IsMixedMode( int nTrack
) { return (m_nFirstData
== 1 && m_nNumAudio
> 0); }
179 // CD-ROM with XA sectors
180 bool IsXA( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& XA
) ? false : true; }
182 // Multisession CD-ROM
183 bool IsMultiSession( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& MULTISESSION
) ? false : true; }
184 // Gets multisession offset
185 int GetMultisessionOffset( int nTrack
) { return m_ti
[nTrack
- 1].ms_offset
; }
187 // Hidden Track on Audio CD
188 bool IsHiddenTrack( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& HIDDEN_TRACK
) ? false : true; }
190 // Photo CD, with audiotracks > 0 Portfolio Photo CD
191 bool IsPhotoCd( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& PHOTO_CD
) ? false : true; }
193 // CD-ROM with Commodore CDTV
194 bool IsCdTv( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& CDTV
) ? false : true; }
197 bool IsCDExtra( int nTrack
) { return (m_nFirstData
> 1); }
200 bool IsBootable( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& BOOTABLE
) ? false : true; }
203 bool IsVideoCd( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& VIDEOCDI
&& m_nNumAudio
== 0); }
206 bool IsChaojiVideoCD( int nTrack
) { return (m_ti
[nTrack
- 1].nfsInfo
& CVD
) ? false : true; }
209 bool IsAudio( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_NO_DATA
); }
212 bool IsUDF( int nTrack
) { return ((m_ti
[nTrack
- 1].nfsInfo
& FS_MASK
) == FS_UDF
); }
214 // Has the cd a filesystem that is readable by the xbox
215 bool IsValidFs() { return (IsISOHFS(1) || IsIso9660(1) || IsIso9660Interactive(1) || IsISOUDF(1) || IsUDF(1) || IsAudio(1)); }
217 void SetFirstTrack( int nTrack
) { m_nFirstTrack
= nTrack
; }
218 void SetTrackCount( int nCount
) { m_nNumTrack
= nCount
; }
219 void SetFirstAudioTrack( int nTrack
) { m_nFirstAudio
= nTrack
; }
220 void SetFirstDataTrack( int nTrack
) { m_nFirstData
= nTrack
; }
221 void SetDataTrackCount( int nCount
) { m_nNumData
= nCount
; }
222 void SetAudioTrackCount( int nCount
) { m_nNumAudio
= nCount
; }
223 void SetTrackInformation(int nTrack
, trackinfo nInfo
)
225 if (nTrack
> 0 && nTrack
<= 99)
226 m_ti
[nTrack
- 1] = std::move(nInfo
);
228 void SetDiscCDTextInformation(xbmc_cdtext_t cdtext
) { m_cdtext
= std::move(cdtext
); }
230 void SetCddbDiscId( uint32_t ulCddbDiscId
) { m_ulCddbDiscId
= ulCddbDiscId
; }
231 void SetDiscLength( int nLength
) { m_nLength
= nLength
; }
232 bool HasCDDBInfo() { return m_bHasCDDBInfo
; }
233 void SetNoCDDBInfo() { m_bHasCDDBInfo
= false; }
235 void SetDiscLabel(const std::string
& strDiscLabel
){ m_strDiscLabel
= strDiscLabel
; }
238 int m_nFirstData
; /* # of first data track */
239 int m_nNumData
; /* # of data tracks */
240 int m_nFirstAudio
; /* # of first audio track */
241 int m_nNumAudio
; /* # of audio tracks */
245 uint32_t m_ulCddbDiscId
;
246 int m_nLength
; // Disclength can be used for cddb query, also see trackinfo.nFrames
248 std::string m_strDiscLabel
;
249 xbmc_cdtext_t m_cdtext
; // CD-Text for this disc
252 class CLibcdio
: public CCriticalSection
259 static void ReleaseInstance();
260 static std::shared_ptr
<CLibcdio
> GetInstance();
262 // libcdio is not thread safe so these are wrappers to libcdio routines
263 CdIo_t
* cdio_open(const char *psz_source
, driver_id_t driver_id
);
264 CdIo_t
* cdio_open_win32(const char *psz_source
);
265 void cdio_destroy(CdIo_t
*p_cdio
);
266 discmode_t
cdio_get_discmode(CdIo_t
*p_cdio
);
267 CdioTrayStatus
mmc_get_tray_status(const CdIo_t
* p_cdio
);
268 driver_return_code_t
cdio_eject_media(CdIo_t
** p_cdio
);
269 track_t
cdio_get_last_track_num(const CdIo_t
*p_cdio
);
270 lsn_t
cdio_get_track_lsn(const CdIo_t
*p_cdio
, track_t i_track
);
271 lsn_t
cdio_get_track_last_lsn(const CdIo_t
*p_cdio
, track_t i_track
);
272 driver_return_code_t
cdio_read_audio_sectors(const CdIo_t
*p_cdio
, void *p_buf
, lsn_t i_lsn
, uint32_t i_blocks
);
273 driver_return_code_t
cdio_close_tray(const char* psz_source
, driver_id_t
* driver_id
);
274 const char* cdio_driver_errmsg(driver_return_code_t drc
);
276 char* GetDeviceFileName();
279 char* s_defaultDevice
;
280 CCriticalSection m_critSection
;
281 static std::shared_ptr
<CLibcdio
> m_pInstance
;
288 virtual ~CCdIoSupport();
294 HANDLE
OpenIMAGE( std::string
& strFilename
);
295 int ReadSector(HANDLE hDevice
, DWORD dwSector
, char* lpczBuffer
);
296 int ReadSectorMode2(HANDLE hDevice
, DWORD dwSector
, char* lpczBuffer
);
297 int ReadSectorCDDA(HANDLE hDevice
, DWORD dwSector
, char* lpczBuffer
);
298 void CloseCDROM(HANDLE hDevice
);
300 void PrintAnalysis(int fs
, int num_audio
);
302 CCdInfo
* GetCdInfo(char* cDeviceFileName
=NULL
);
303 void GetCdTextInfo(xbmc_cdtext_t
&xcdt
, int trackNum
);
306 int ReadBlock(int superblock
, uint32_t offset
, uint8_t bufnum
, track_t track_num
);
313 int GetJolietLevel( void );
314 int GuessFilesystem(int start_session
, track_t track_num
);
316 uint32_t CddbDiscId();
317 int CddbDecDigitSum(int n
);
318 unsigned int MsfSeconds(msf_t
*msf
);
321 char buffer
[7][CDIO_CD_FRAMESIZE_RAW
]; /* for CD-Data */
322 static signature_t sigs
[17];
323 int i
= 0, j
= 0; /* index */
324 int m_nStartTrack
; /* first sector of track */
325 int m_nIsofsSize
; /* size of session */
327 int m_nMsOffset
; /* multisession offset found by track-walking */
328 int m_nDataStart
; /* start of data area */
334 track_t m_nNumTracks
= CDIO_INVALID_TRACK
;
335 track_t m_nFirstTrackNum
= CDIO_INVALID_TRACK
;
337 std::string m_strDiscLabel
;
339 int m_nFirstData
; /* # of first data track */
340 int m_nNumData
; /* # of data tracks */
341 int m_nFirstAudio
; /* # of first audio track */
342 int m_nNumAudio
; /* # of audio tracks */
344 std::shared_ptr
<CLibcdio
> m_cdio
;