Blame lib/driver/track.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2003-2005, 2008, 2011-2013
Packit dd8086
  Rocky Bernstein <rocky@gnu.org>
Packit dd8086
  Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086
/*! Track-related routines. */
Packit dd8086

Packit dd8086
Packit dd8086
#ifdef HAVE_CONFIG_H
Packit dd8086
# include "config.h"
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STDBOOL_H
Packit dd8086
# include <stdbool.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <cdio/cdio.h>
Packit dd8086
#include <cdio/logging.h>
Packit dd8086
#include "cdio_private.h"
Packit dd8086
Packit dd8086
const char *track_format2str[6] =
Packit dd8086
  {
Packit dd8086
    "audio", "CD-i", "XA", "data", "PSX", "error"
Packit dd8086
  };
Packit dd8086
Packit dd8086
/* Variables to hold debugger-helping enumerations */
Packit dd8086
enum cdio_track_enums;
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the number of the first track.
Packit dd8086
  CDIO_INVALID_TRACK is returned on error.
Packit dd8086
*/
Packit dd8086
track_t
Packit dd8086
cdio_get_first_track_num(const CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  if (NULL == p_cdio) {
Packit dd8086
    cdio_info("Null CdIo object passed\n");
Packit dd8086
    return CDIO_INVALID_TRACK;
Packit dd8086
  }
Packit dd8086
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_first_track_num) {
Packit dd8086
    return p_cdio->op.get_first_track_num (p_cdio->env);
Packit dd8086
  } else {
Packit dd8086
    return CDIO_INVALID_TRACK;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the last track number.
Packit dd8086
  CDIO_INVALID_TRACK is returned on error.
Packit dd8086
*/
Packit dd8086
track_t
Packit dd8086
cdio_get_last_track_num (const CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  if (NULL == p_cdio) {
Packit dd8086
    cdio_info("Null CdIo object passed\n");
Packit dd8086
    return CDIO_INVALID_TRACK;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  {
Packit dd8086
    const track_t i_first_track = cdio_get_first_track_num(p_cdio);
Packit dd8086
    if ( CDIO_INVALID_TRACK != i_first_track ) {
Packit dd8086
      const track_t u_tracks = cdio_get_num_tracks(p_cdio);
Packit dd8086
      if ( CDIO_INVALID_TRACK != u_tracks )
Packit dd8086
	return i_first_track + u_tracks - 1;
Packit dd8086
    }
Packit dd8086
    return CDIO_INVALID_TRACK;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Return number of channels in track: 2 or 4; -2 if not
Packit dd8086
  implemented or -1 for error.
Packit dd8086
  Not meaningful if track is not an audio track.
Packit dd8086
*/
Packit dd8086
int
Packit dd8086
cdio_get_track_channels(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  track_t u_last_track;
Packit dd8086
  if (NULL == p_cdio) {
Packit dd8086
    cdio_info("Null CdIo object passed\n");
Packit dd8086
    return -1;
Packit dd8086
  }
Packit dd8086
  u_last_track = cdio_get_last_track_num(p_cdio);
Packit dd8086
  if (u_track > u_last_track) {
Packit dd8086
     cdio_log(CDIO_LOG_WARN, "Number of tracks exceeds maximum (%d vs. %d)\n",
Packit dd8086
              u_track, u_last_track);
Packit dd8086
     return -1;
Packit dd8086
  }
Packit dd8086
  if (p_cdio->op.get_track_channels) {
Packit dd8086
    return p_cdio->op.get_track_channels (p_cdio->env, u_track);
Packit dd8086
  } else {
Packit dd8086
    return -2;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Return copy protection status on a track. Is this meaningful
Packit dd8086
  if not an audio track?
Packit dd8086
*/
Packit dd8086
track_flag_t
Packit dd8086
cdio_get_track_copy_permit(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  if (p_cdio->op.get_track_copy_permit) {
Packit dd8086
    return p_cdio->op.get_track_copy_permit (p_cdio->env, u_track);
Packit dd8086
  } else {
Packit dd8086
    return CDIO_TRACK_FLAG_UNKNOWN;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Get format of track.
Packit dd8086
*/
Packit dd8086
track_format_t
Packit dd8086
cdio_get_track_format(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  if (!p_cdio) return TRACK_FORMAT_ERROR;
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_track_format) {
Packit dd8086
    return p_cdio->op.get_track_format (p_cdio->env, u_track);
Packit dd8086
  } else {
Packit dd8086
    return TRACK_FORMAT_ERROR;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
/*!
Packit dd8086
  Return the Joliet level recognized for p_cdio.
Packit dd8086
*/
Packit dd8086
uint8_t
Packit dd8086
cdio_get_joliet_level(const CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  if (!p_cdio) return 0;
Packit dd8086
  {
Packit dd8086
    const generic_img_private_t *p_env
Packit dd8086
      = (generic_img_private_t *) (p_cdio->env);
Packit dd8086
    return p_env->u_joliet_level;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the number of tracks in the current medium.
Packit dd8086
  CDIO_INVALID_TRACK is returned on error.
Packit dd8086
*/
Packit dd8086
track_t
Packit dd8086
cdio_get_num_tracks (const CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
  if (p_cdio == NULL) return CDIO_INVALID_TRACK;
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_num_tracks) {
Packit dd8086
    return p_cdio->op.get_num_tracks (p_cdio->env);
Packit dd8086
  } else {
Packit dd8086
    return CDIO_INVALID_TRACK;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Find the track which contans lsn.
Packit dd8086
    CDIO_INVALID_TRACK is returned if the lsn outside of the CD or
Packit dd8086
    if there was some error.
Packit dd8086
Packit dd8086
    If the lsn is before the pregap of the first track 0 is returned.
Packit dd8086
    Otherwise we return the track that spans the lsn.
Packit dd8086
*/
Packit dd8086
track_t
Packit dd8086
cdio_get_track(const CdIo_t *p_cdio, lsn_t lsn)
Packit dd8086
{
Packit dd8086
  if (!p_cdio) return CDIO_INVALID_TRACK;
Packit dd8086
Packit dd8086
  {
Packit dd8086
    track_t i_low_track   = cdio_get_first_track_num(p_cdio);
Packit dd8086
    track_t i_high_track  = cdio_get_last_track_num(p_cdio)+1;
Packit dd8086
    track_t i_lead_track  = i_high_track;
Packit dd8086
Packit dd8086
    if (CDIO_INVALID_TRACK == i_low_track
Packit dd8086
	|| CDIO_INVALID_TRACK == i_high_track ) return CDIO_INVALID_TRACK;
Packit dd8086
Packit dd8086
    if (lsn < cdio_get_track_lsn(p_cdio, i_low_track))
Packit dd8086
      return 0; /* We're in the pre-gap of first track */
Packit dd8086
Packit dd8086
    if (lsn > cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK))
Packit dd8086
      return CDIO_INVALID_TRACK; /* We're beyond the end. */
Packit dd8086
Packit dd8086
    do {
Packit dd8086
      const track_t i_mid = (i_low_track + i_high_track) / 2;
Packit dd8086
      const lsn_t i_mid_lsn = cdio_get_track_lsn(p_cdio, i_mid);
Packit dd8086
      if (lsn <= i_mid_lsn) i_high_track = i_mid - 1;
Packit dd8086
      if (lsn >= i_mid_lsn) i_low_track  = i_mid + 1;
Packit dd8086
    } while ( i_low_track <= i_high_track );
Packit dd8086
Packit dd8086
    if (i_low_track > i_high_track + 1) {
Packit dd8086
	i_high_track++;
Packit dd8086
    }
Packit dd8086
    if (i_high_track == i_lead_track ) {
Packit dd8086
	return CDIO_CDROM_LEADOUT_TRACK;
Packit dd8086
    } else {
Packit dd8086
	return i_high_track;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return true if we have XA data (green, mode2 form1) or
Packit dd8086
  XA data (green, mode2 form2). That is track begins:
Packit dd8086
  sync - header - subheader
Packit dd8086
  12     4      -  8
Packit dd8086
Packit dd8086
  FIXME: there's gotta be a better design for this and get_track_format?
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
cdio_get_track_green(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  if (p_cdio == NULL) {
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_track_green) {
Packit dd8086
    return p_cdio->op.get_track_green (p_cdio->env, u_track);
Packit dd8086
  } else {
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the starting LBA for track number
Packit dd8086
  track_num in cdio.  Tracks numbers start at 1.
Packit dd8086
  The "leadout" track is specified either by
Packit dd8086
  using track_num LEADOUT_TRACK or the total tracks+1.
Packit dd8086
  CDIO_INVALID_LBA is returned on error.
Packit dd8086
*/
Packit dd8086
lba_t
Packit dd8086
cdio_get_track_lba(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  if (NULL == p_cdio) {
Packit dd8086
    cdio_info("Null CdIo object passed\n");
Packit dd8086
    return CDIO_INVALID_LBA;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_track_lba) {
Packit dd8086
    return p_cdio->op.get_track_lba (p_cdio->env, u_track);
Packit dd8086
  } else {
Packit dd8086
    msf_t msf;
Packit dd8086
    if (p_cdio->op.get_track_msf)
Packit dd8086
      if (cdio_get_track_msf(p_cdio, u_track, &msf))
Packit dd8086
        return cdio_msf_to_lba(&msf;;
Packit dd8086
    return CDIO_INVALID_LBA;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the starting LSN for track number
Packit dd8086
  u_track in cdio.  Tracks numbers start at 1.
Packit dd8086
  The "leadout" track is specified either by
Packit dd8086
  using u_track LEADOUT_TRACK or the total tracks+1.
Packit dd8086
  CDIO_INVALID_LSN is returned on error.
Packit dd8086
*/
Packit dd8086
lsn_t
Packit dd8086
cdio_get_track_lsn(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  /*track_t u_last_track; */
Packit dd8086
  if (NULL == p_cdio) {
Packit dd8086
    cdio_info("Null CdIo object passed\n");
Packit dd8086
    return CDIO_INVALID_LSN;
Packit dd8086
  }
Packit dd8086
  /*
Packit dd8086
  u_last_track = cdio_get_last_track_num(p_cdio);
Packit dd8086
  if (u_track > u_last_track && u_track != CDIO_CDROM_LEADOUT_TRACK) {
Packit dd8086
     cdio_log(CDIO_LOG_WARN, "Number of tracks exceeds maximum (%d vs. %d)\n",
Packit dd8086
              u_track, u_last_track);
Packit dd8086
     return CDIO_INVALID_LSN;
Packit dd8086
  }
Packit dd8086
  */
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_track_lba) {
Packit dd8086
    return cdio_lba_to_lsn(p_cdio->op.get_track_lba (p_cdio->env, u_track));
Packit dd8086
  } else {
Packit dd8086
    msf_t msf;
Packit dd8086
    if (cdio_get_track_msf(p_cdio, u_track, &msf))
Packit dd8086
      return cdio_msf_to_lsn(&msf;;
Packit dd8086
    return CDIO_INVALID_LSN;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the International Standard Recording Code (ISRC) for track number
Packit dd8086
  u_track in p_cdio.  Track numbers start at 1.
Packit dd8086
Packit dd8086
  Note: The caller must free the returned string with cdio_free()
Packit dd8086
  when done with it.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
cdio_get_track_isrc (const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  track_t u_last_track;
Packit dd8086
  if (NULL == p_cdio) {
Packit dd8086
    cdio_info("Null CdIo object passed\n");
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  u_last_track = cdio_get_last_track_num(p_cdio);
Packit dd8086
  if (u_track > u_last_track) {
Packit dd8086
     cdio_log(CDIO_LOG_WARN, "Number of tracks exceeds maximum (%d vs. %d)\n",
Packit dd8086
              u_track, u_last_track);
Packit dd8086
     return NULL;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_track_isrc) {
Packit dd8086
    return p_cdio->op.get_track_isrc (p_cdio->env, u_track);
Packit dd8086
  } else {
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the starting LBA for the pregap for track number
Packit dd8086
  u_track in cdio.  Track numbers start at 1.
Packit dd8086
  CDIO_INVALID_LBA is returned on error.
Packit dd8086
*/
Packit dd8086
lba_t
Packit dd8086
cdio_get_track_pregap_lba(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  if (NULL == p_cdio) {
Packit dd8086
    cdio_info("Null CdIo object passed\n");
Packit dd8086
    return CDIO_INVALID_LBA;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_track_pregap_lba) {
Packit dd8086
    return p_cdio->op.get_track_pregap_lba (p_cdio->env, u_track);
Packit dd8086
  } else {
Packit dd8086
    return CDIO_INVALID_LBA;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the starting LSN for the pregap for track number
Packit dd8086
  u_track in cdio.  Track numbers start at 1.
Packit dd8086
  CDIO_INVALID_LSN is returned on error.
Packit dd8086
*/
Packit dd8086
lsn_t
Packit dd8086
cdio_get_track_pregap_lsn(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  return cdio_lba_to_lsn(cdio_get_track_pregap_lba(p_cdio, u_track));
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the ending LSN for track number
Packit dd8086
  u_track in cdio.  CDIO_INVALID_LSN is returned on error.
Packit dd8086
*/
Packit dd8086
lsn_t
Packit dd8086
cdio_get_track_last_lsn(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  lsn_t lsn = cdio_get_track_lsn(p_cdio, u_track+1);
Packit dd8086
Packit dd8086
  if (CDIO_INVALID_LSN == lsn) return CDIO_INVALID_LSN;
Packit dd8086
  /* Safe, we've always the leadout. */
Packit dd8086
  return lsn - 1;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the starting MSF (minutes/secs/frames) for track number
Packit dd8086
  u_track in cdio.  Track numbers start at 1.
Packit dd8086
  The "leadout" track is specified either by
Packit dd8086
  using u_track LEADOUT_TRACK or the total tracks+1.
Packit dd8086
  False is returned if there is no track entry.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
cdio_get_track_msf(const CdIo_t *p_cdio, track_t u_track, /*out*/ msf_t *msf)
Packit dd8086
{
Packit dd8086
  if (!p_cdio) return false;
Packit dd8086
Packit dd8086
  if (p_cdio->op.get_track_msf) {
Packit dd8086
    return p_cdio->op.get_track_msf (p_cdio->env, u_track, msf);
Packit dd8086
  } else if (p_cdio->op.get_track_lba) {
Packit dd8086
    lba_t lba = p_cdio->op.get_track_lba (p_cdio->env, u_track);
Packit dd8086
    if (lba  == CDIO_INVALID_LBA) return false;
Packit dd8086
    cdio_lba_to_msf(lba, msf);
Packit dd8086
    return true;
Packit dd8086
  } else {
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Return copy protection status on a track. Is this meaningful
Packit dd8086
  if not an audio track?
Packit dd8086
*/
Packit dd8086
track_flag_t
Packit dd8086
cdio_get_track_preemphasis(const CdIo *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  if (p_cdio->op.get_track_preemphasis) {
Packit dd8086
    return p_cdio->op.get_track_preemphasis (p_cdio->env, u_track);
Packit dd8086
  } else {
Packit dd8086
    return CDIO_TRACK_FLAG_UNKNOWN;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the number of sectors between this track an the next.  This
Packit dd8086
  includes any pregap sectors before the start of the next track.
Packit dd8086
  Tracks start at 1.
Packit dd8086
  0 is returned if there is an error.
Packit dd8086
*/
Packit dd8086
unsigned int
Packit dd8086
cdio_get_track_sec_count(const CdIo_t *p_cdio, track_t u_track)
Packit dd8086
{
Packit dd8086
  const track_t u_tracks = cdio_get_num_tracks(p_cdio);
Packit dd8086
Packit dd8086
  if (u_track >=1 && u_track <= u_tracks)
Packit dd8086
    return ( cdio_get_track_lba(p_cdio, u_track+1)
Packit dd8086
             - cdio_get_track_lba(p_cdio, u_track) );
Packit dd8086
  return 0;
Packit dd8086
}