summaryrefslogtreecommitdiffstats
path: root/xbmc/storage/cdioSupport.h
blob: b786ff2d3f9422414897de717fa48bb783e9c9b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
/*
 *  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 <map>
#include <memory>
#include <string>
#include <utility>

#include "PlatformDefs.h" // for ssize_t typedef, used by cdio

#include <cdio/cdio.h>

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<cdtext_field_t, std::string> 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<CLibcdio> 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<CLibcdio> 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<CLibcdio> m_cdio;
};

}