1 /*
2   Copyright (C) 2003-2005, 2008, 2011-2013
3   Rocky Bernstein <rocky@gnu.org>
4   Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
5 
6   This program is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /*! Track-related routines. */
20 
21 
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25 
26 #ifdef HAVE_STDBOOL_H
27 # include <stdbool.h>
28 #endif
29 
30 #include <cdio/cdio.h>
31 #include <cdio/logging.h>
32 #include "cdio_private.h"
33 
34 const char *track_format2str[6] =
35   {
36     "audio", "CD-i", "XA", "data", "PSX", "error"
37   };
38 
39 /* Variables to hold debugger-helping enumerations */
40 enum cdio_track_enums;
41 
42 /*!
43   Return the number of the first track.
44   CDIO_INVALID_TRACK is returned on error.
45 */
46 track_t
cdio_get_first_track_num(const CdIo_t * p_cdio)47 cdio_get_first_track_num(const CdIo_t *p_cdio)
48 {
49   if (NULL == p_cdio) {
50     cdio_info("Null CdIo object passed\n");
51     return CDIO_INVALID_TRACK;
52   }
53 
54 
55   if (p_cdio->op.get_first_track_num) {
56     return p_cdio->op.get_first_track_num (p_cdio->env);
57   } else {
58     return CDIO_INVALID_TRACK;
59   }
60 }
61 
62 /*!
63   Return the last track number.
64   CDIO_INVALID_TRACK is returned on error.
65 */
66 track_t
cdio_get_last_track_num(const CdIo_t * p_cdio)67 cdio_get_last_track_num (const CdIo_t *p_cdio)
68 {
69   if (NULL == p_cdio) {
70     cdio_info("Null CdIo object passed\n");
71     return CDIO_INVALID_TRACK;
72   }
73 
74   {
75     const track_t i_first_track = cdio_get_first_track_num(p_cdio);
76     if ( CDIO_INVALID_TRACK != i_first_track ) {
77       const track_t u_tracks = cdio_get_num_tracks(p_cdio);
78       if ( CDIO_INVALID_TRACK != u_tracks )
79 	return i_first_track + u_tracks - 1;
80     }
81     return CDIO_INVALID_TRACK;
82   }
83 }
84 
85 /*! Return number of channels in track: 2 or 4; -2 if not
86   implemented or -1 for error.
87   Not meaningful if track is not an audio track.
88 */
89 int
cdio_get_track_channels(const CdIo_t * p_cdio,track_t u_track)90 cdio_get_track_channels(const CdIo_t *p_cdio, track_t u_track)
91 {
92   track_t u_last_track;
93   if (NULL == p_cdio) {
94     cdio_info("Null CdIo object passed\n");
95     return -1;
96   }
97   u_last_track = cdio_get_last_track_num(p_cdio);
98   if (u_track > u_last_track) {
99      cdio_log(CDIO_LOG_WARN, "Number of tracks exceeds maximum (%d vs. %d)\n",
100               u_track, u_last_track);
101      return -1;
102   }
103   if (p_cdio->op.get_track_channels) {
104     return p_cdio->op.get_track_channels (p_cdio->env, u_track);
105   } else {
106     return -2;
107   }
108 }
109 
110 /*! Return copy protection status on a track. Is this meaningful
111   if not an audio track?
112 */
113 track_flag_t
cdio_get_track_copy_permit(const CdIo_t * p_cdio,track_t u_track)114 cdio_get_track_copy_permit(const CdIo_t *p_cdio, track_t u_track)
115 {
116   if (p_cdio->op.get_track_copy_permit) {
117     return p_cdio->op.get_track_copy_permit (p_cdio->env, u_track);
118   } else {
119     return CDIO_TRACK_FLAG_UNKNOWN;
120   }
121 }
122 
123 /*!
124   Get format of track.
125 */
126 track_format_t
cdio_get_track_format(const CdIo_t * p_cdio,track_t u_track)127 cdio_get_track_format(const CdIo_t *p_cdio, track_t u_track)
128 {
129   if (!p_cdio) return TRACK_FORMAT_ERROR;
130 
131   if (p_cdio->op.get_track_format) {
132     return p_cdio->op.get_track_format (p_cdio->env, u_track);
133   } else {
134     return TRACK_FORMAT_ERROR;
135   }
136 }
137 /*!
138   Return the Joliet level recognized for p_cdio.
139 */
140 uint8_t
cdio_get_joliet_level(const CdIo_t * p_cdio)141 cdio_get_joliet_level(const CdIo_t *p_cdio)
142 {
143   if (!p_cdio) return 0;
144   {
145     const generic_img_private_t *p_env
146       = (generic_img_private_t *) (p_cdio->env);
147     return p_env->u_joliet_level;
148   }
149 }
150 
151 /*!
152   Return the number of tracks in the current medium.
153   CDIO_INVALID_TRACK is returned on error.
154 */
155 track_t
cdio_get_num_tracks(const CdIo_t * p_cdio)156 cdio_get_num_tracks (const CdIo_t *p_cdio)
157 {
158   if (p_cdio == NULL) return CDIO_INVALID_TRACK;
159 
160   if (p_cdio->op.get_num_tracks) {
161     return p_cdio->op.get_num_tracks (p_cdio->env);
162   } else {
163     return CDIO_INVALID_TRACK;
164   }
165 }
166 
167 /*! Find the track which contans lsn.
168     CDIO_INVALID_TRACK is returned if the lsn outside of the CD or
169     if there was some error.
170 
171     If the lsn is before the pregap of the first track 0 is returned.
172     Otherwise we return the track that spans the lsn.
173 */
174 track_t
cdio_get_track(const CdIo_t * p_cdio,lsn_t lsn)175 cdio_get_track(const CdIo_t *p_cdio, lsn_t lsn)
176 {
177   if (!p_cdio) return CDIO_INVALID_TRACK;
178 
179   {
180     track_t i_low_track   = cdio_get_first_track_num(p_cdio);
181     track_t i_high_track  = cdio_get_last_track_num(p_cdio)+1;
182     track_t i_lead_track  = i_high_track;
183 
184     if (CDIO_INVALID_TRACK == i_low_track
185 	|| CDIO_INVALID_TRACK == i_high_track ) return CDIO_INVALID_TRACK;
186 
187     if (lsn < cdio_get_track_lsn(p_cdio, i_low_track))
188       return 0; /* We're in the pre-gap of first track */
189 
190     if (lsn > cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK))
191       return CDIO_INVALID_TRACK; /* We're beyond the end. */
192 
193     do {
194       const track_t i_mid = (i_low_track + i_high_track) / 2;
195       const lsn_t i_mid_lsn = cdio_get_track_lsn(p_cdio, i_mid);
196       if (lsn <= i_mid_lsn) i_high_track = i_mid - 1;
197       if (lsn >= i_mid_lsn) i_low_track  = i_mid + 1;
198     } while ( i_low_track <= i_high_track );
199 
200     if (i_low_track > i_high_track + 1) {
201 	i_high_track++;
202     }
203     if (i_high_track == i_lead_track ) {
204 	return CDIO_CDROM_LEADOUT_TRACK;
205     } else {
206 	return i_high_track;
207     }
208   }
209 }
210 
211 /*!
212   Return true if we have XA data (green, mode2 form1) or
213   XA data (green, mode2 form2). That is track begins:
214   sync - header - subheader
215   12     4      -  8
216 
217   FIXME: there's gotta be a better design for this and get_track_format?
218 */
219 bool
cdio_get_track_green(const CdIo_t * p_cdio,track_t u_track)220 cdio_get_track_green(const CdIo_t *p_cdio, track_t u_track)
221 {
222   if (p_cdio == NULL) {
223     return false;
224   }
225 
226   if (p_cdio->op.get_track_green) {
227     return p_cdio->op.get_track_green (p_cdio->env, u_track);
228   } else {
229     return false;
230   }
231 }
232 
233 /*!
234   Return the starting LBA for track number
235   track_num in cdio.  Tracks numbers start at 1.
236   The "leadout" track is specified either by
237   using track_num LEADOUT_TRACK or the total tracks+1.
238   CDIO_INVALID_LBA is returned on error.
239 */
240 lba_t
cdio_get_track_lba(const CdIo_t * p_cdio,track_t u_track)241 cdio_get_track_lba(const CdIo_t *p_cdio, track_t u_track)
242 {
243   if (NULL == p_cdio) {
244     cdio_info("Null CdIo object passed\n");
245     return CDIO_INVALID_LBA;
246   }
247 
248   if (p_cdio->op.get_track_lba) {
249     return p_cdio->op.get_track_lba (p_cdio->env, u_track);
250   } else {
251     msf_t msf;
252     if (p_cdio->op.get_track_msf)
253       if (cdio_get_track_msf(p_cdio, u_track, &msf))
254         return cdio_msf_to_lba(&msf);
255     return CDIO_INVALID_LBA;
256   }
257 }
258 
259 /*!
260   Return the starting LSN for track number
261   u_track in cdio.  Tracks numbers start at 1.
262   The "leadout" track is specified either by
263   using u_track LEADOUT_TRACK or the total tracks+1.
264   CDIO_INVALID_LSN is returned on error.
265 */
266 lsn_t
cdio_get_track_lsn(const CdIo_t * p_cdio,track_t u_track)267 cdio_get_track_lsn(const CdIo_t *p_cdio, track_t u_track)
268 {
269   /*track_t u_last_track; */
270   if (NULL == p_cdio) {
271     cdio_info("Null CdIo object passed\n");
272     return CDIO_INVALID_LSN;
273   }
274   /*
275   u_last_track = cdio_get_last_track_num(p_cdio);
276   if (u_track > u_last_track && u_track != CDIO_CDROM_LEADOUT_TRACK) {
277      cdio_log(CDIO_LOG_WARN, "Number of tracks exceeds maximum (%d vs. %d)\n",
278               u_track, u_last_track);
279      return CDIO_INVALID_LSN;
280   }
281   */
282 
283   if (p_cdio->op.get_track_lba) {
284     return cdio_lba_to_lsn(p_cdio->op.get_track_lba (p_cdio->env, u_track));
285   } else {
286     msf_t msf;
287     if (cdio_get_track_msf(p_cdio, u_track, &msf))
288       return cdio_msf_to_lsn(&msf);
289     return CDIO_INVALID_LSN;
290   }
291 }
292 
293 /*!
294   Return the International Standard Recording Code (ISRC) for track number
295   u_track in p_cdio.  Track numbers start at 1.
296 
297   Note: The caller must free the returned string with cdio_free()
298   when done with it.
299 */
300 char *
cdio_get_track_isrc(const CdIo_t * p_cdio,track_t u_track)301 cdio_get_track_isrc (const CdIo_t *p_cdio, track_t u_track)
302 {
303   track_t u_last_track;
304   if (NULL == p_cdio) {
305     cdio_info("Null CdIo object passed\n");
306     return NULL;
307   }
308 
309   u_last_track = cdio_get_last_track_num(p_cdio);
310   if (u_track > u_last_track) {
311      cdio_log(CDIO_LOG_WARN, "Number of tracks exceeds maximum (%d vs. %d)\n",
312               u_track, u_last_track);
313      return NULL;
314   }
315 
316   if (p_cdio->op.get_track_isrc) {
317     return p_cdio->op.get_track_isrc (p_cdio->env, u_track);
318   } else {
319     return NULL;
320   }
321 }
322 
323 /*!
324   Return the starting LBA for the pregap for track number
325   u_track in cdio.  Track numbers start at 1.
326   CDIO_INVALID_LBA is returned on error.
327 */
328 lba_t
cdio_get_track_pregap_lba(const CdIo_t * p_cdio,track_t u_track)329 cdio_get_track_pregap_lba(const CdIo_t *p_cdio, track_t u_track)
330 {
331   if (NULL == p_cdio) {
332     cdio_info("Null CdIo object passed\n");
333     return CDIO_INVALID_LBA;
334   }
335 
336   if (p_cdio->op.get_track_pregap_lba) {
337     return p_cdio->op.get_track_pregap_lba (p_cdio->env, u_track);
338   } else {
339     return CDIO_INVALID_LBA;
340   }
341 }
342 
343 /*!
344   Return the starting LSN for the pregap for track number
345   u_track in cdio.  Track numbers start at 1.
346   CDIO_INVALID_LSN is returned on error.
347 */
348 lsn_t
cdio_get_track_pregap_lsn(const CdIo_t * p_cdio,track_t u_track)349 cdio_get_track_pregap_lsn(const CdIo_t *p_cdio, track_t u_track)
350 {
351   return cdio_lba_to_lsn(cdio_get_track_pregap_lba(p_cdio, u_track));
352 }
353 
354 /*!
355   Return the ending LSN for track number
356   u_track in cdio.  CDIO_INVALID_LSN is returned on error.
357 */
358 lsn_t
cdio_get_track_last_lsn(const CdIo_t * p_cdio,track_t u_track)359 cdio_get_track_last_lsn(const CdIo_t *p_cdio, track_t u_track)
360 {
361   lsn_t lsn = cdio_get_track_lsn(p_cdio, u_track+1);
362 
363   if (CDIO_INVALID_LSN == lsn) return CDIO_INVALID_LSN;
364   /* Safe, we've always the leadout. */
365   return lsn - 1;
366 }
367 
368 /*!
369   Return the starting MSF (minutes/secs/frames) for track number
370   u_track in cdio.  Track numbers start at 1.
371   The "leadout" track is specified either by
372   using u_track LEADOUT_TRACK or the total tracks+1.
373   False is returned if there is no track entry.
374 */
375 bool
cdio_get_track_msf(const CdIo_t * p_cdio,track_t u_track,msf_t * msf)376 cdio_get_track_msf(const CdIo_t *p_cdio, track_t u_track, /*out*/ msf_t *msf)
377 {
378   if (!p_cdio) return false;
379 
380   if (p_cdio->op.get_track_msf) {
381     return p_cdio->op.get_track_msf (p_cdio->env, u_track, msf);
382   } else if (p_cdio->op.get_track_lba) {
383     lba_t lba = p_cdio->op.get_track_lba (p_cdio->env, u_track);
384     if (lba  == CDIO_INVALID_LBA) return false;
385     cdio_lba_to_msf(lba, msf);
386     return true;
387   } else {
388     return false;
389   }
390 }
391 
392 /*! Return copy protection status on a track. Is this meaningful
393   if not an audio track?
394 */
395 track_flag_t
cdio_get_track_preemphasis(const CdIo * p_cdio,track_t u_track)396 cdio_get_track_preemphasis(const CdIo *p_cdio, track_t u_track)
397 {
398   if (p_cdio->op.get_track_preemphasis) {
399     return p_cdio->op.get_track_preemphasis (p_cdio->env, u_track);
400   } else {
401     return CDIO_TRACK_FLAG_UNKNOWN;
402   }
403 }
404 
405 /*!
406   Return the number of sectors between this track an the next.  This
407   includes any pregap sectors before the start of the next track.
408   Tracks start at 1.
409   0 is returned if there is an error.
410 */
411 unsigned int
cdio_get_track_sec_count(const CdIo_t * p_cdio,track_t u_track)412 cdio_get_track_sec_count(const CdIo_t *p_cdio, track_t u_track)
413 {
414   const track_t u_tracks = cdio_get_num_tracks(p_cdio);
415 
416   if (u_track >=1 && u_track <= u_tracks)
417     return ( cdio_get_track_lba(p_cdio, u_track+1)
418              - cdio_get_track_lba(p_cdio, u_track) );
419   return 0;
420 }
421