/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #pragma once // CCdInfo - Information about media type of an inserted cd // CCdIoSupport - Wrapper class for libcdio with the interface of CIoSupport // and detecting the filesystem on the Disc. // // by Bobbin007 in 2003 // CD-Text support by Mog - Oct 2004 #include "threads/CriticalSection.h" #include #include #include #include #include "PlatformDefs.h" // for ssize_t typedef, used by cdio #include namespace MEDIA_DETECT { #define STRONG "__________________________________\n" //#define NORMAL "" #define FS_NO_DATA 0 /* audio only */ #define FS_HIGH_SIERRA 1 #define FS_ISO_9660 2 #define FS_INTERACTIVE 3 #define FS_HFS 4 #define FS_UFS 5 #define FS_EXT2 6 #define FS_ISO_HFS 7 /* both hfs & isofs filesystem */ #define FS_ISO_9660_INTERACTIVE 8 /* both CD-RTOS and isofs filesystem */ #define FS_3DO 9 #define FS_UDF 11 #define FS_ISO_UDF 12 #define FS_UNKNOWN 15 #define FS_MASK 15 #define XA 16 #define MULTISESSION 32 #define PHOTO_CD 64 #define HIDDEN_TRACK 128 #define CDTV 256 #define BOOTABLE 512 #define VIDEOCDI 1024 #define ROCKRIDGE 2048 #define JOLIET 4096 #define CVD 8192 /* Choiji Video CD */ #define IS_ISOFS 0 #define IS_CD_I 1 #define IS_CDTV 2 #define IS_CD_RTOS 3 #define IS_HS 4 #define IS_BRIDGE 5 #define IS_XA 6 #define IS_PHOTO_CD 7 #define IS_EXT2 8 #define IS_UFS 9 #define IS_BOOTABLE 10 #define IS_VIDEO_CD 11 /* Video CD */ #define IS_CVD 12 /* Chinese Video CD - slightly incompatible with SVCD */ #define IS_UDF 14 typedef struct signature { unsigned int buf_num; unsigned int offset; const char *sig_str; const char *description; } signature_t; typedef std::map xbmc_cdtext_t; typedef struct TRACKINFO { int nfsInfo; // Information of the Tracks Filesystem int nJolietLevel; // Jouliet Level int ms_offset; // Multisession Offset int isofs_size; // Size of the ISO9660 Filesystem int nFrames; // Can be used for cddb query int nMins; // minutes playtime part of Track int nSecs; // seconds playtime part of Track xbmc_cdtext_t cdtext; // CD-Text for this track } trackinfo; /*! \brief Helper enum class for the MMC tray state */ enum class CdioTrayStatus { /* The MMC tray state is reported closed */ CLOSED, /* The MMC tray state is reported open */ OPEN, /* The MMC tray status operation is not supported */ UNKNOWN, /* Generic driver error */ DRIVER_ERROR }; class CCdInfo { public: CCdInfo() { m_bHasCDDBInfo = true; m_nLength = m_nFirstTrack = m_nNumTrack = m_nNumAudio = m_nFirstAudio = m_nNumData = m_nFirstData = 0; } trackinfo GetTrackInformation( int nTrack ) { return m_ti[nTrack -1]; } xbmc_cdtext_t GetDiscCDTextInformation() { return m_cdtext; } bool HasDataTracks() { return (m_nNumData > 0); } bool HasAudioTracks() { return (m_nNumAudio > 0); } int GetFirstTrack() { return m_nFirstTrack; } int GetTrackCount() { return m_nNumTrack; } int GetFirstAudioTrack() { return m_nFirstAudio; } int GetFirstDataTrack() { return m_nFirstData; } int GetDataTrackCount() { return m_nNumData; } int GetAudioTrackCount() { return m_nNumAudio; } uint32_t GetCddbDiscId() { return m_ulCddbDiscId; } int GetDiscLength() { return m_nLength; } std::string GetDiscLabel(){ return m_strDiscLabel; } // CD-ROM with ISO 9660 filesystem bool IsIso9660( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_ISO_9660); } // CD-ROM with joliet extension bool IsJoliet( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & JOLIET) ? false : true; } // Joliet extension level int GetJolietLevel( int nTrack ) { return m_ti[nTrack - 1].nJolietLevel; } // ISO filesystem size int GetIsoSize( int nTrack ) { return m_ti[nTrack - 1].isofs_size; } // CD-ROM with rockridge extensions bool IsRockridge( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & ROCKRIDGE) ? false : true; } // CD-ROM with CD-RTOS and ISO 9660 filesystem bool IsIso9660Interactive( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_ISO_9660_INTERACTIVE); } // CD-ROM with High Sierra filesystem bool IsHighSierra( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_HIGH_SIERRA); } // CD-Interactive, with audiotracks > 0 CD-Interactive/Ready bool IsCDInteractive( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_INTERACTIVE); } // CD-ROM with Macintosh HFS bool IsHFS( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_HFS); } // CD-ROM with both Macintosh HFS and ISO 9660 filesystem bool IsISOHFS( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_ISO_HFS); } // CD-ROM with both UDF and ISO 9660 filesystem bool IsISOUDF( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_ISO_UDF); } // CD-ROM with Unix UFS bool IsUFS( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_UFS); } // CD-ROM with Linux second extended filesystem bool IsEXT2( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_EXT2); } // CD-ROM with Panasonic 3DO filesystem bool Is3DO( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_3DO); } // Mixed Mode CD-ROM bool IsMixedMode( int nTrack ) { return (m_nFirstData == 1 && m_nNumAudio > 0); } // CD-ROM with XA sectors bool IsXA( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & XA) ? false : true; } // Multisession CD-ROM bool IsMultiSession( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & MULTISESSION) ? false : true; } // Gets multisession offset int GetMultisessionOffset( int nTrack ) { return m_ti[nTrack - 1].ms_offset; } // Hidden Track on Audio CD bool IsHiddenTrack( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & HIDDEN_TRACK) ? false : true; } // Photo CD, with audiotracks > 0 Portfolio Photo CD bool IsPhotoCd( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & PHOTO_CD) ? false : true; } // CD-ROM with Commodore CDTV bool IsCdTv( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & CDTV) ? false : true; } // CD-Plus/Extra bool IsCDExtra( int nTrack ) { return (m_nFirstData > 1); } // Bootable CD bool IsBootable( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & BOOTABLE) ? false : true; } // Video CD bool IsVideoCd( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & VIDEOCDI && m_nNumAudio == 0); } // Chaoji Video CD bool IsChaojiVideoCD( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & CVD) ? false : true; } // Audio Track bool IsAudio( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_NO_DATA); } // UDF filesystem bool IsUDF( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_UDF); } // Has the cd a filesystem that is readable by the xbox bool IsValidFs() { return (IsISOHFS(1) || IsIso9660(1) || IsIso9660Interactive(1) || IsISOUDF(1) || IsUDF(1) || IsAudio(1)); } void SetFirstTrack( int nTrack ) { m_nFirstTrack = nTrack; } void SetTrackCount( int nCount ) { m_nNumTrack = nCount; } void SetFirstAudioTrack( int nTrack ) { m_nFirstAudio = nTrack; } void SetFirstDataTrack( int nTrack ) { m_nFirstData = nTrack; } void SetDataTrackCount( int nCount ) { m_nNumData = nCount; } void SetAudioTrackCount( int nCount ) { m_nNumAudio = nCount; } void SetTrackInformation(int nTrack, trackinfo nInfo) { if (nTrack > 0 && nTrack <= 99) m_ti[nTrack - 1] = std::move(nInfo); } void SetDiscCDTextInformation(xbmc_cdtext_t cdtext) { m_cdtext = std::move(cdtext); } void SetCddbDiscId( uint32_t ulCddbDiscId ) { m_ulCddbDiscId = ulCddbDiscId; } void SetDiscLength( int nLength ) { m_nLength = nLength; } bool HasCDDBInfo() { return m_bHasCDDBInfo; } void SetNoCDDBInfo() { m_bHasCDDBInfo = false; } void SetDiscLabel(const std::string& strDiscLabel){ m_strDiscLabel = strDiscLabel; } private: int m_nFirstData; /* # of first data track */ int m_nNumData; /* # of data tracks */ int m_nFirstAudio; /* # of first audio track */ int m_nNumAudio; /* # of audio tracks */ int m_nNumTrack; int m_nFirstTrack; trackinfo m_ti[100]; uint32_t m_ulCddbDiscId; int m_nLength; // Disclength can be used for cddb query, also see trackinfo.nFrames bool m_bHasCDDBInfo; std::string m_strDiscLabel; xbmc_cdtext_t m_cdtext; // CD-Text for this disc }; class CLibcdio : public CCriticalSection { private: CLibcdio(); public: virtual ~CLibcdio(); static void ReleaseInstance(); static std::shared_ptr GetInstance(); // libcdio is not thread safe so these are wrappers to libcdio routines CdIo_t* cdio_open(const char *psz_source, driver_id_t driver_id); CdIo_t* cdio_open_win32(const char *psz_source); void cdio_destroy(CdIo_t *p_cdio); discmode_t cdio_get_discmode(CdIo_t *p_cdio); CdioTrayStatus mmc_get_tray_status(const CdIo_t* p_cdio); driver_return_code_t cdio_eject_media(CdIo_t** p_cdio); track_t cdio_get_last_track_num(const CdIo_t *p_cdio); lsn_t cdio_get_track_lsn(const CdIo_t *p_cdio, track_t i_track); lsn_t cdio_get_track_last_lsn(const CdIo_t *p_cdio, track_t i_track); driver_return_code_t cdio_read_audio_sectors(const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn, uint32_t i_blocks); driver_return_code_t cdio_close_tray(const char* psz_source, driver_id_t* driver_id); const char* cdio_driver_errmsg(driver_return_code_t drc); char* GetDeviceFileName(); private: char* s_defaultDevice; CCriticalSection m_critSection; static std::shared_ptr m_pInstance; }; class CCdIoSupport { public: CCdIoSupport(); virtual ~CCdIoSupport(); bool EjectTray(); bool CloseTray(); HANDLE OpenCDROM(); HANDLE OpenIMAGE( std::string& strFilename ); int ReadSector(HANDLE hDevice, DWORD dwSector, char* lpczBuffer); int ReadSectorMode2(HANDLE hDevice, DWORD dwSector, char* lpczBuffer); int ReadSectorCDDA(HANDLE hDevice, DWORD dwSector, char* lpczBuffer); void CloseCDROM(HANDLE hDevice); void PrintAnalysis(int fs, int num_audio); CCdInfo* GetCdInfo(char* cDeviceFileName=NULL); void GetCdTextInfo(xbmc_cdtext_t &xcdt, int trackNum); protected: int ReadBlock(int superblock, uint32_t offset, uint8_t bufnum, track_t track_num); bool IsIt(int num); int IsHFS(void); int Is3DO(void); int IsJoliet(void); int IsUDF(void); int GetSize(void); int GetJolietLevel( void ); int GuessFilesystem(int start_session, track_t track_num); uint32_t CddbDiscId(); int CddbDecDigitSum(int n); unsigned int MsfSeconds(msf_t *msf); private: char buffer[7][CDIO_CD_FRAMESIZE_RAW]; /* for CD-Data */ static signature_t sigs[17]; int i = 0, j = 0; /* index */ int m_nStartTrack; /* first sector of track */ int m_nIsofsSize; /* size of session */ int m_nJolietLevel; int m_nMsOffset; /* multisession offset found by track-walking */ int m_nDataStart; /* start of data area */ int m_nFs; int m_nUDFVerMinor; int m_nUDFVerMajor; CdIo* cdio; track_t m_nNumTracks = CDIO_INVALID_TRACK; track_t m_nFirstTrackNum = CDIO_INVALID_TRACK; std::string m_strDiscLabel; int m_nFirstData; /* # of first data track */ int m_nNumData; /* # of data tracks */ int m_nFirstAudio; /* # of first audio track */ int m_nNumAudio; /* # of audio tracks */ std::shared_ptr m_cdio; }; }