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