1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
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.
14 //
15 // by Bobbin007 in 2003
16 //  CD-Text support by Mog - Oct 2004
17 
18 #include "threads/CriticalSection.h"
19 
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 
25 #include "PlatformDefs.h" // for ssize_t typedef, used by cdio
26 
27 #include <cdio/cdio.h>
28 
29 namespace MEDIA_DETECT
30 {
31 
32 #define STRONG "__________________________________\n"
33 //#define NORMAL ""
34 
35 #define FS_NO_DATA              0  /* audio only */
36 #define FS_HIGH_SIERRA          1
37 #define FS_ISO_9660             2
38 #define FS_INTERACTIVE          3
39 #define FS_HFS                  4
40 #define FS_UFS                  5
41 #define FS_EXT2                 6
42 #define FS_ISO_HFS              7  /* both hfs & isofs filesystem */
43 #define FS_ISO_9660_INTERACTIVE 8  /* both CD-RTOS and isofs filesystem */
44 #define FS_3DO                  9
45 #define FS_UDF                 11
46 #define FS_ISO_UDF             12
47 #define FS_UNKNOWN             15
48 #define FS_MASK                15
49 
50 #define XA                     16
51 #define MULTISESSION           32
52 #define PHOTO_CD               64
53 #define HIDDEN_TRACK          128
54 #define CDTV                  256
55 #define BOOTABLE              512
56 #define VIDEOCDI             1024
57 #define ROCKRIDGE            2048
58 #define JOLIET               4096
59 #define CVD                  8192 /* Choiji Video CD */
60 
61 #define IS_ISOFS      0
62 #define IS_CD_I       1
63 #define IS_CDTV       2
64 #define IS_CD_RTOS    3
65 #define IS_HS         4
66 #define IS_BRIDGE     5
67 #define IS_XA         6
68 #define IS_PHOTO_CD   7
69 #define IS_EXT2       8
70 #define IS_UFS        9
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 */
74 #define IS_UDF       14
75 
76 typedef struct signature
77 {
78   unsigned int buf_num;
79   unsigned int offset;
80   const char *sig_str;
81   const char *description;
82 }
83 signature_t;
84 
85 typedef std::map<cdtext_field_t, std::string> xbmc_cdtext_t;
86 
87 typedef struct TRACKINFO
88 {
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
97 }
98 trackinfo;
99 
100 
101 class CCdInfo
102 {
103 public:
CCdInfo()104   CCdInfo()
105   {
106     m_bHasCDDBInfo = true;
107     m_nLength = m_nFirstTrack = m_nNumTrack = m_nNumAudio = m_nFirstAudio = m_nNumData = m_nFirstData = 0;
108   }
109 
GetTrackInformation(int nTrack)110   trackinfo GetTrackInformation( int nTrack ) { return m_ti[nTrack -1]; }
GetDiscCDTextInformation()111   xbmc_cdtext_t GetDiscCDTextInformation() { return m_cdtext; }
112 
HasDataTracks()113   bool HasDataTracks() { return (m_nNumData > 0); }
HasAudioTracks()114   bool HasAudioTracks() { return (m_nNumAudio > 0); }
GetFirstTrack()115   int GetFirstTrack() { return m_nFirstTrack; }
GetTrackCount()116   int GetTrackCount() { return m_nNumTrack; }
GetFirstAudioTrack()117   int GetFirstAudioTrack() { return m_nFirstAudio; }
GetFirstDataTrack()118   int GetFirstDataTrack() { return m_nFirstData; }
GetDataTrackCount()119   int GetDataTrackCount() { return m_nNumData; }
GetAudioTrackCount()120   int GetAudioTrackCount() { return m_nNumAudio; }
GetCddbDiscId()121   uint32_t GetCddbDiscId() { return m_ulCddbDiscId; }
GetDiscLength()122   int GetDiscLength() { return m_nLength; }
GetDiscLabel()123   std::string GetDiscLabel(){ return m_strDiscLabel; }
124 
125   // CD-ROM with ISO 9660 filesystem
IsIso9660(int nTrack)126   bool IsIso9660( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_ISO_9660); }
127   // CD-ROM with joliet extension
IsJoliet(int nTrack)128   bool IsJoliet( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & JOLIET) ? false : true; }
129   // Joliet extension level
GetJolietLevel(int nTrack)130   int GetJolietLevel( int nTrack ) { return m_ti[nTrack - 1].nJolietLevel; }
131   // ISO filesystem size
GetIsoSize(int nTrack)132   int GetIsoSize( int nTrack ) { return m_ti[nTrack - 1].isofs_size; }
133   // CD-ROM with rockridge extensions
IsRockridge(int nTrack)134   bool IsRockridge( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & ROCKRIDGE) ? false : true; }
135 
136   // CD-ROM with CD-RTOS and ISO 9660 filesystem
IsIso9660Interactive(int nTrack)137   bool IsIso9660Interactive( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_ISO_9660_INTERACTIVE); }
138 
139   // CD-ROM with High Sierra filesystem
IsHighSierra(int nTrack)140   bool IsHighSierra( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_HIGH_SIERRA); }
141 
142   // CD-Interactive, with audiotracks > 0 CD-Interactive/Ready
IsCDInteractive(int nTrack)143   bool IsCDInteractive( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_INTERACTIVE); }
144 
145   // CD-ROM with Macintosh HFS
IsHFS(int nTrack)146   bool IsHFS( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_HFS); }
147 
148   // CD-ROM with both Macintosh HFS and ISO 9660 filesystem
IsISOHFS(int nTrack)149   bool IsISOHFS( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_ISO_HFS); }
150 
151   // CD-ROM with both UDF and ISO 9660 filesystem
IsISOUDF(int nTrack)152   bool IsISOUDF( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_ISO_UDF); }
153 
154   // CD-ROM with Unix UFS
IsUFS(int nTrack)155   bool IsUFS( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_UFS); }
156 
157   // CD-ROM with Linux second extended filesystem
IsEXT2(int nTrack)158   bool IsEXT2( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_EXT2); }
159 
160   // CD-ROM with Panasonic 3DO filesystem
Is3DO(int nTrack)161   bool Is3DO( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_3DO); }
162 
163   // Mixed Mode CD-ROM
IsMixedMode(int nTrack)164   bool IsMixedMode( int nTrack ) { return (m_nFirstData == 1 && m_nNumAudio > 0); }
165 
166   // CD-ROM with XA sectors
IsXA(int nTrack)167   bool IsXA( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & XA) ? false : true; }
168 
169   // Multisession CD-ROM
IsMultiSession(int nTrack)170   bool IsMultiSession( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & MULTISESSION) ? false : true; }
171   // Gets multisession offset
GetMultisessionOffset(int nTrack)172   int GetMultisessionOffset( int nTrack ) { return m_ti[nTrack - 1].ms_offset; }
173 
174   // Hidden Track on Audio CD
IsHiddenTrack(int nTrack)175   bool IsHiddenTrack( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & HIDDEN_TRACK) ? false : true; }
176 
177   // Photo CD, with audiotracks > 0 Portfolio Photo CD
IsPhotoCd(int nTrack)178   bool IsPhotoCd( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & PHOTO_CD) ? false : true; }
179 
180   // CD-ROM with Commodore CDTV
IsCdTv(int nTrack)181   bool IsCdTv( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & CDTV) ? false : true; }
182 
183   // CD-Plus/Extra
IsCDExtra(int nTrack)184   bool IsCDExtra( int nTrack ) { return (m_nFirstData > 1); }
185 
186   // Bootable CD
IsBootable(int nTrack)187   bool IsBootable( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & BOOTABLE) ? false : true; }
188 
189   // Video CD
IsVideoCd(int nTrack)190   bool IsVideoCd( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & VIDEOCDI && m_nNumAudio == 0); }
191 
192   // Chaoji Video CD
IsChaojiVideoCD(int nTrack)193   bool IsChaojiVideoCD( int nTrack ) { return (m_ti[nTrack - 1].nfsInfo & CVD) ? false : true; }
194 
195   // Audio Track
IsAudio(int nTrack)196   bool IsAudio( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_NO_DATA); }
197 
198   // UDF filesystem
IsUDF(int nTrack)199   bool IsUDF( int nTrack ) { return ((m_ti[nTrack - 1].nfsInfo & FS_MASK) == FS_UDF); }
200 
201   // Has the cd a filesystem that is readable by the xbox
IsValidFs()202   bool IsValidFs() { return (IsISOHFS(1) || IsIso9660(1) || IsIso9660Interactive(1) || IsISOUDF(1) || IsUDF(1) || IsAudio(1)); }
203 
SetFirstTrack(int nTrack)204   void SetFirstTrack( int nTrack ) { m_nFirstTrack = nTrack; }
SetTrackCount(int nCount)205   void SetTrackCount( int nCount ) { m_nNumTrack = nCount; }
SetFirstAudioTrack(int nTrack)206   void SetFirstAudioTrack( int nTrack ) { m_nFirstAudio = nTrack; }
SetFirstDataTrack(int nTrack)207   void SetFirstDataTrack( int nTrack ) { m_nFirstData = nTrack; }
SetDataTrackCount(int nCount)208   void SetDataTrackCount( int nCount ) { m_nNumData = nCount; }
SetAudioTrackCount(int nCount)209   void SetAudioTrackCount( int nCount ) { m_nNumAudio = nCount; }
SetTrackInformation(int nTrack,trackinfo nInfo)210   void SetTrackInformation(int nTrack, trackinfo nInfo)
211   {
212     if (nTrack > 0 && nTrack <= 99)
213       m_ti[nTrack - 1] = std::move(nInfo);
214   }
SetDiscCDTextInformation(xbmc_cdtext_t cdtext)215   void SetDiscCDTextInformation(xbmc_cdtext_t cdtext) { m_cdtext = std::move(cdtext); }
216 
SetCddbDiscId(uint32_t ulCddbDiscId)217   void SetCddbDiscId( uint32_t ulCddbDiscId ) { m_ulCddbDiscId = ulCddbDiscId; }
SetDiscLength(int nLength)218   void SetDiscLength( int nLength ) { m_nLength = nLength; }
HasCDDBInfo()219   bool HasCDDBInfo() { return m_bHasCDDBInfo; }
SetNoCDDBInfo()220   void SetNoCDDBInfo() { m_bHasCDDBInfo = false; }
221 
SetDiscLabel(const std::string & strDiscLabel)222   void SetDiscLabel(const std::string& strDiscLabel){ m_strDiscLabel = strDiscLabel; }
223 
224 private:
225   int m_nFirstData;        /* # of first data track */
226   int m_nNumData;          /* # of data tracks */
227   int m_nFirstAudio;       /* # of first audio track */
228   int m_nNumAudio;         /* # of audio tracks */
229   int m_nNumTrack;
230   int m_nFirstTrack;
231   trackinfo m_ti[100];
232   uint32_t m_ulCddbDiscId;
233   int m_nLength;           // Disclength can be used for cddb query, also see trackinfo.nFrames
234   bool m_bHasCDDBInfo;
235   std::string m_strDiscLabel;
236   xbmc_cdtext_t m_cdtext;  //  CD-Text for this disc
237 };
238 
239 class CLibcdio : public CCriticalSection
240 {
241 private:
242   CLibcdio();
243 public:
244   virtual ~CLibcdio();
245 
246   static void ReleaseInstance();
247   static std::shared_ptr<CLibcdio> GetInstance();
248 
249   // libcdio is not thread safe so these are wrappers to libcdio routines
250   CdIo_t* cdio_open(const char *psz_source, driver_id_t driver_id);
251   CdIo_t* cdio_open_win32(const char *psz_source);
252   void cdio_destroy(CdIo_t *p_cdio);
253   discmode_t cdio_get_discmode(CdIo_t *p_cdio);
254   int mmc_get_tray_status(const CdIo_t *p_cdio);
255   int cdio_eject_media(CdIo_t **p_cdio);
256   track_t cdio_get_last_track_num(const CdIo_t *p_cdio);
257   lsn_t cdio_get_track_lsn(const CdIo_t *p_cdio, track_t i_track);
258   lsn_t cdio_get_track_last_lsn(const CdIo_t *p_cdio, track_t i_track);
259   driver_return_code_t cdio_read_audio_sectors(const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn, uint32_t i_blocks);
260 
261   char* GetDeviceFileName();
262 
263 private:
264   char* s_defaultDevice;
265   CCriticalSection m_critSection;
266   static std::shared_ptr<CLibcdio> m_pInstance;
267 };
268 
269 class CCdIoSupport
270 {
271 public:
272   CCdIoSupport();
273   virtual ~CCdIoSupport();
274 
275   bool EjectTray();
276   bool CloseTray();
277 
278   HANDLE OpenCDROM();
279   HANDLE OpenIMAGE( std::string& strFilename );
280   int ReadSector(HANDLE hDevice, DWORD dwSector, char* lpczBuffer);
281   int ReadSectorMode2(HANDLE hDevice, DWORD dwSector, char* lpczBuffer);
282   int ReadSectorCDDA(HANDLE hDevice, DWORD dwSector, char* lpczBuffer);
283   void CloseCDROM(HANDLE hDevice);
284 
285   void PrintAnalysis(int fs, int num_audio);
286 
287   CCdInfo* GetCdInfo(char* cDeviceFileName=NULL);
288   void GetCdTextInfo(xbmc_cdtext_t &xcdt, int trackNum);
289 
290 protected:
291   int ReadBlock(int superblock, uint32_t offset, uint8_t bufnum, track_t track_num);
292   bool IsIt(int num);
293   int IsHFS(void);
294   int Is3DO(void);
295   int IsJoliet(void);
296   int IsUDF(void);
297   int GetSize(void);
298   int GetJolietLevel( void );
299   int GuessFilesystem(int start_session, track_t track_num);
300 
301   uint32_t CddbDiscId();
302   int CddbDecDigitSum(int n);
303   unsigned int MsfSeconds(msf_t *msf);
304 
305 private:
306   char buffer[7][CDIO_CD_FRAMESIZE_RAW];  /* for CD-Data */
307   static signature_t sigs[17];
308   int i = 0, j = 0;                               /* index */
309   int m_nStartTrack;                      /* first sector of track */
310   int m_nIsofsSize;                       /* size of session */
311   int m_nJolietLevel;
312   int m_nMsOffset;                        /* multisession offset found by track-walking */
313   int m_nDataStart;                       /* start of data area */
314   int m_nFs;
315   int m_nUDFVerMinor;
316   int m_nUDFVerMajor;
317 
318   CdIo* cdio;
319   track_t m_nNumTracks = CDIO_INVALID_TRACK;
320   track_t m_nFirstTrackNum = CDIO_INVALID_TRACK;
321 
322   std::string m_strDiscLabel;
323 
324   int m_nFirstData;        /* # of first data track */
325   int m_nNumData;          /* # of data tracks */
326   int m_nFirstAudio;       /* # of first audio track */
327   int m_nNumAudio;         /* # of audio tracks */
328 
329   std::shared_ptr<CLibcdio> m_cdio;
330 };
331 
332 }
333