Add simple (non-mode2) read/seek.
_cdio_generic.c: place to save common driver routines add cdio_get_track_sec_count.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
AC_REVISION([$Id: configure.ac,v 1.1 2003/03/24 19:01:09 rocky Exp $])dnl
|
||||
AC_REVISION([$Id: configure.ac,v 1.2 2003/03/29 17:32:00 rocky Exp $])dnl
|
||||
AC_INIT(lib/cdio.c)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AM_INIT_AUTOMAKE(libcdio, 0.1)
|
||||
@@ -118,7 +118,8 @@ LIBS="$LIBS -lm"
|
||||
CFLAGS="$CFLAGS $WARN_CFLAGS"
|
||||
|
||||
AM_CONDITIONAL(CYGWIN, test "x$CYGWIN" = "xyes")
|
||||
AM_CONDITIONAL(BUILD_CDINFO_LINUX, test "x$enable_cli_fe" = "xyes")
|
||||
AM_CONDITIONAL(BUILD_CDINFO_LINUX, test "x$enable_cdinfo_linux" = "xyes")
|
||||
AM_CONDITIONAL(BUILD_CDIOTEST, test "x$enable_cdiotest" = "xyes")
|
||||
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# $Id: Makefile.am,v 1.2 2003/03/24 23:59:22 rocky Exp $
|
||||
# $Id: Makefile.am,v 1.3 2003/03/29 17:32:00 rocky Exp $
|
||||
#
|
||||
# Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
#
|
||||
@@ -29,6 +29,7 @@ libcdio_sources = \
|
||||
_cdio_bincue.c \
|
||||
_cdio_bsdi.c \
|
||||
_cdio_freebsd.c \
|
||||
_cdio_generic.c \
|
||||
_cdio_linux.c \
|
||||
_cdio_nrg.c \
|
||||
_cdio_stdio.c \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: _cdio_bincue.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: _cdio_bincue.c,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
|
||||
@@ -28,7 +28,7 @@
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_bincue.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: _cdio_bincue.c,v 1.2 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
@@ -51,7 +51,10 @@ typedef struct {
|
||||
int blocksize;
|
||||
int track_num; /* Probably is index+1 */
|
||||
msf_t start_msf;
|
||||
lba_t start_lba;
|
||||
int start_index;
|
||||
int sec_count; /* Number of sectors in this track. Does not
|
||||
include pregap */
|
||||
int num_indices;
|
||||
int flags; /* "DCP", "4CH", "PRE" */
|
||||
track_format_t track_format;
|
||||
@@ -61,16 +64,16 @@ typedef struct {
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *source_name;
|
||||
bool init;
|
||||
bool sector_2336_flag;
|
||||
|
||||
CdioDataSource *bin_src;
|
||||
char *source_name;
|
||||
CdioDataSource *data_source;
|
||||
char *cue_name;
|
||||
track_info_t tocent[100]; /* entry info for each track */
|
||||
track_t total_tracks; /* number of tracks in image */
|
||||
track_t first_track_num; /* track number of first track */
|
||||
bool have_cue;
|
||||
bool init;
|
||||
} _img_private_t;
|
||||
|
||||
static bool _cdio_image_read_cue (_img_private_t *_obj);
|
||||
@@ -82,36 +85,12 @@ static uint32_t _cdio_stat_size (void *user_data);
|
||||
static bool
|
||||
_cdio_init (_img_private_t *_obj)
|
||||
{
|
||||
lsn_t lead_lsn;
|
||||
|
||||
if (_obj->init)
|
||||
return false;
|
||||
|
||||
/* Read in CUE sheet. */
|
||||
if ((_obj->cue_name != NULL)) {
|
||||
_obj->have_cue == _cdio_image_read_cue(_obj);
|
||||
}
|
||||
|
||||
if (!_obj->have_cue ) {
|
||||
/* Time to fake things...
|
||||
Make one big track, track 0 and 1 are the same.
|
||||
We are guessing stuff atarts a msf 00:04:00 - 2 for the 150
|
||||
sector pregap and 2 for the cue information.
|
||||
*/
|
||||
int blocksize = _obj->sector_2336_flag
|
||||
? M2RAW_SECTOR_SIZE : CD_RAW_SECTOR_SIZE;
|
||||
_obj->total_tracks = 2;
|
||||
_obj->first_track_num = 1;
|
||||
_obj->tocent[0].start_msf.m = to_bcd8(0);
|
||||
_obj->tocent[0].start_msf.s = to_bcd8(4);
|
||||
_obj->tocent[0].start_msf.f = to_bcd8(0);
|
||||
_obj->tocent[0].blocksize = blocksize;
|
||||
_obj->tocent[0].track_format= TRACK_FORMAT_XA;
|
||||
_obj->tocent[0].track_green = true;
|
||||
|
||||
_obj->tocent[1] = _obj->tocent[0];
|
||||
}
|
||||
|
||||
|
||||
if (!(_obj->bin_src = cdio_stdio_new (_obj->source_name))) {
|
||||
if (!(_obj->data_source = cdio_stdio_new (_obj->source_name))) {
|
||||
cdio_error ("init failed");
|
||||
return false;
|
||||
}
|
||||
@@ -121,12 +100,113 @@ _cdio_init (_img_private_t *_obj)
|
||||
*/
|
||||
_obj->init = true;
|
||||
|
||||
/* Fake out leadout track. */
|
||||
cdio_lsn_to_msf ( _cdio_stat_size( (_img_private_t *) _obj),
|
||||
&_obj->tocent[_obj->total_tracks].start_msf);
|
||||
lead_lsn = _cdio_stat_size( (_img_private_t *) _obj);
|
||||
|
||||
/* Read in CUE sheet. */
|
||||
if ((_obj->cue_name != NULL)) {
|
||||
_obj->have_cue == _cdio_image_read_cue(_obj);
|
||||
}
|
||||
|
||||
if (!_obj->have_cue ) {
|
||||
/* Time to fake things...
|
||||
Make one big track, track 0 and 1 are the same.
|
||||
We are guessing stuff starts at msf 00:04:00 - 2 for the 150
|
||||
sector pregap and 2 for the cue information.
|
||||
*/
|
||||
track_info_t *this_track=&(_obj->tocent[0]);
|
||||
int blocksize = _obj->sector_2336_flag
|
||||
? M2RAW_SECTOR_SIZE : CD_RAW_SECTOR_SIZE;
|
||||
|
||||
_obj->total_tracks = 2;
|
||||
_obj->first_track_num = 1;
|
||||
this_track->start_msf.m = to_bcd8(0);
|
||||
this_track->start_msf.s = to_bcd8(4);
|
||||
this_track->start_msf.f = to_bcd8(0);
|
||||
this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf);
|
||||
this_track->blocksize = blocksize;
|
||||
this_track->track_format= TRACK_FORMAT_XA;
|
||||
this_track->track_green = true;
|
||||
|
||||
|
||||
_obj->tocent[1] = _obj->tocent[0];
|
||||
}
|
||||
|
||||
/* Fake out leadout track and sector count for last track*/
|
||||
cdio_lsn_to_msf (lead_lsn, &_obj->tocent[_obj->total_tracks].start_msf);
|
||||
_obj->tocent[_obj->total_tracks].start_lba = cdio_lsn_to_lba(lead_lsn);
|
||||
_obj->tocent[_obj->total_tracks-1].sec_count =
|
||||
cdio_lsn_to_lba(lead_lsn - _obj->tocent[_obj->total_tracks-1].start_lba);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Would be libc's seek() but we have to adjust for the extra track header
|
||||
information in each sector.
|
||||
*/
|
||||
static off_t
|
||||
_cdio_lseek (void *user_data, off_t offset, int whence)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
/* real_offset is the real byte offset inside the disk image
|
||||
The number below was determined empirically. I'm guessing
|
||||
the 1st 24 bytes of a bin file are used for something.
|
||||
*/
|
||||
off_t real_offset=24;
|
||||
|
||||
unsigned int i;
|
||||
unsigned int user_datasize;
|
||||
|
||||
for (i=0; i<_obj->total_tracks; i++) {
|
||||
track_info_t *this_track=&(_obj->tocent[i]);
|
||||
switch (this_track->track_format) {
|
||||
case TRACK_FORMAT_AUDIO:
|
||||
user_datasize=CDDA_SECTOR_SIZE;
|
||||
break;
|
||||
case TRACK_FORMAT_CDI:
|
||||
user_datasize=FORM1_DATA_SIZE;
|
||||
break;
|
||||
case TRACK_FORMAT_XA:
|
||||
user_datasize=FORM1_DATA_SIZE;
|
||||
break;
|
||||
default:
|
||||
cdio_warn ("track %d has unknown format %d",
|
||||
i+1, this_track->track_format);
|
||||
}
|
||||
|
||||
if ( (this_track->sec_count*user_datasize) >= offset) {
|
||||
int blocks = offset / user_datasize;
|
||||
int rem = offset % user_datasize;
|
||||
int block_offset = blocks * CD_RAW_SECTOR_SIZE;
|
||||
real_offset += block_offset + rem;
|
||||
break;
|
||||
}
|
||||
real_offset += this_track->sec_count*CD_RAW_SECTOR_SIZE;
|
||||
offset -= this_track->sec_count*user_datasize;
|
||||
}
|
||||
|
||||
if (i==_obj->total_tracks) {
|
||||
cdio_warn ("seeking outside range of disk image");
|
||||
return -1;
|
||||
} else
|
||||
return cdio_stream_seek(_obj->data_source, real_offset, whence);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
FIXME:
|
||||
At present we assume a read doesn't cross sector or track
|
||||
boundaries.
|
||||
*/
|
||||
static ssize_t
|
||||
_cdio_read (void *user_data, void *buf, size_t size)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
return cdio_stream_read(_obj->data_source, buf, size, 1);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -142,7 +222,7 @@ _cdio_stat_size (void *user_data)
|
||||
|
||||
_cdio_init (_obj);
|
||||
|
||||
size = cdio_stream_stat (_obj->bin_src);
|
||||
size = cdio_stream_stat (_obj->data_source);
|
||||
|
||||
if (size % blocksize)
|
||||
{
|
||||
@@ -194,48 +274,79 @@ _cdio_image_read_cue (_img_private_t *_obj)
|
||||
*/
|
||||
/* printf("Found file name %s\n", s); */
|
||||
} else if (2==sscanf(p, "TRACK %d MODE2/%d", &track_num, &blocksize)) {
|
||||
_obj->tocent[_obj->total_tracks].blocksize = blocksize;
|
||||
_obj->tocent[_obj->total_tracks].track_num = track_num;
|
||||
_obj->tocent[_obj->total_tracks].num_indices = 0;
|
||||
_obj->tocent[_obj->total_tracks].track_format= TRACK_FORMAT_XA;
|
||||
_obj->tocent[_obj->total_tracks].track_green = true;
|
||||
track_info_t *this_track=&(_obj->tocent[_obj->total_tracks]);
|
||||
this_track->blocksize = blocksize;
|
||||
this_track->track_num = track_num;
|
||||
this_track->num_indices = 0;
|
||||
this_track->track_format= TRACK_FORMAT_XA;
|
||||
this_track->track_green = true;
|
||||
_obj->total_tracks++;
|
||||
seen_first_index_for_track=false;
|
||||
/*printf("Added track %d with blocksize %d\n", track_num, blocksize);*/
|
||||
|
||||
} else if (2==sscanf(p, "TRACK %d MODE1/%d", &track_num, &blocksize)) {
|
||||
_obj->tocent[_obj->total_tracks].blocksize = blocksize;
|
||||
_obj->tocent[_obj->total_tracks].track_num = track_num;
|
||||
_obj->tocent[_obj->total_tracks].num_indices = 0;
|
||||
_obj->tocent[_obj->total_tracks].track_format= TRACK_FORMAT_CDI;
|
||||
_obj->tocent[_obj->total_tracks].track_green = false;
|
||||
track_info_t *this_track=&(_obj->tocent[_obj->total_tracks]);
|
||||
this_track->blocksize = blocksize;
|
||||
this_track->track_num = track_num;
|
||||
this_track->num_indices = 0;
|
||||
this_track->track_format= TRACK_FORMAT_CDI;
|
||||
this_track->track_green = false;
|
||||
_obj->total_tracks++;
|
||||
seen_first_index_for_track=false;
|
||||
/*printf("Added track %d with blocksize %d\n", track_num, blocksize);*/
|
||||
|
||||
} else if (1==sscanf(p, "TRACK %d AUDIO", &track_num)) {
|
||||
_obj->tocent[_obj->total_tracks].blocksize = blocksize;
|
||||
_obj->tocent[_obj->total_tracks].track_num = track_num;
|
||||
_obj->tocent[_obj->total_tracks].num_indices = 0;
|
||||
_obj->tocent[_obj->total_tracks].track_format= TRACK_FORMAT_AUDIO;
|
||||
_obj->tocent[_obj->total_tracks].track_green = false;
|
||||
track_info_t *this_track=&(_obj->tocent[_obj->total_tracks]);
|
||||
this_track->blocksize = CDDA_SECTOR_SIZE;
|
||||
this_track->track_num = track_num;
|
||||
this_track->num_indices = 0;
|
||||
this_track->track_format= TRACK_FORMAT_AUDIO;
|
||||
this_track->track_green = false;
|
||||
_obj->total_tracks++;
|
||||
seen_first_index_for_track=false;
|
||||
|
||||
} else if (4==sscanf(p, "INDEX %d %d:%d:%d",
|
||||
&start_index, &min, &sec, &frame)) {
|
||||
track_info_t *this_track=&(_obj->tocent[_obj->total_tracks-1]);
|
||||
/* FIXME! all of this is a big hack.
|
||||
If start_index == 0, then this is the "last_cue" information.
|
||||
The +2 below seconds is to adjust for the 150 pregap.
|
||||
*/
|
||||
if (!seen_first_index_for_track && start_index != 0) {
|
||||
_obj->tocent[_obj->total_tracks-1].start_index = start_index;
|
||||
_obj->tocent[_obj->total_tracks-1].start_msf.m = to_bcd8 (min);
|
||||
_obj->tocent[_obj->total_tracks-1].start_msf.s = to_bcd8 (sec)+2;
|
||||
_obj->tocent[_obj->total_tracks-1].start_msf.f = to_bcd8 (frame);
|
||||
if (start_index != 0) {
|
||||
if (!seen_first_index_for_track) {
|
||||
this_track->start_index = start_index;
|
||||
this_track->start_msf.m = to_bcd8 (min);
|
||||
this_track->start_msf.s = to_bcd8 (sec)+2;
|
||||
this_track->start_msf.f = to_bcd8 (frame);
|
||||
this_track->start_lba = cdio_msf_to_lba(&this_track->start_msf);
|
||||
seen_first_index_for_track=true;
|
||||
}
|
||||
_obj->tocent[_obj->total_tracks-1].num_indices++;
|
||||
|
||||
if (_obj->total_tracks > 1) {
|
||||
/* Figure out number of sectors for previous track */
|
||||
track_info_t *prev_track=&(_obj->tocent[_obj->total_tracks-2]);
|
||||
if ( this_track->start_lba < prev_track->start_lba ) {
|
||||
cdio_warn ("track %d at LBA %d starts before track %d at LBA %d",
|
||||
_obj->total_tracks, this_track->start_lba,
|
||||
_obj->total_tracks-1, prev_track->start_lba);
|
||||
prev_track->sec_count = 0;
|
||||
} else if ( this_track->start_lba >= prev_track->start_lba
|
||||
+ CDIO_PREGAP_SECTORS ) {
|
||||
prev_track->sec_count = this_track->start_lba -
|
||||
prev_track->start_lba - CDIO_PREGAP_SECTORS ;
|
||||
} else {
|
||||
cdio_warn ("%d fewer than pregap (%d) sectors in track %d",
|
||||
this_track->start_lba - prev_track->start_lba,
|
||||
CDIO_PREGAP_SECTORS,
|
||||
_obj->total_tracks-1);
|
||||
/* Include pregap portion in sec_count. Maybe the pregap
|
||||
was omitted. */
|
||||
prev_track->sec_count = this_track->start_lba -
|
||||
prev_track->start_lba;
|
||||
}
|
||||
}
|
||||
this_track->num_indices++;
|
||||
}
|
||||
}
|
||||
}
|
||||
_obj->have_cue = _obj->total_tracks != 0;
|
||||
@@ -254,8 +365,8 @@ _cdio_free (void *user_data)
|
||||
|
||||
free (_obj->source_name);
|
||||
|
||||
if (_obj->bin_src)
|
||||
cdio_stream_destroy (_obj->bin_src);
|
||||
if (_obj->data_source)
|
||||
cdio_stream_destroy (_obj->data_source);
|
||||
|
||||
free (_obj);
|
||||
}
|
||||
@@ -271,16 +382,16 @@ _read_mode2_sector (void *user_data, void *data, uint32_t lsn,
|
||||
|
||||
_cdio_init (_obj);
|
||||
|
||||
cdio_stream_seek (_obj->bin_src, lsn * blocksize);
|
||||
cdio_stream_seek (_obj->data_source, lsn * blocksize, SEEK_SET);
|
||||
|
||||
cdio_stream_read (_obj->bin_src,
|
||||
cdio_stream_read (_obj->data_source,
|
||||
_obj->sector_2336_flag ? (buf + 12 + 4) : buf,
|
||||
blocksize, 1);
|
||||
|
||||
if (mode2_form2)
|
||||
memcpy (data, buf + 12 + 4, M2RAW_SECTOR_SIZE);
|
||||
else
|
||||
memcpy (data, buf + 12 + 4 + 8, M2F1_SECTOR_SIZE);
|
||||
memcpy (data, buf + 12 + 4 + 8, FORM1_DATA_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -310,7 +421,7 @@ _read_mode2_sectors (void *user_data, void *data, uint32_t lsn,
|
||||
return retval;
|
||||
|
||||
memcpy (((char *)data) + (M2F1_SECTOR_SIZE * i), buf + 8,
|
||||
M2F1_SECTOR_SIZE);
|
||||
FORM1_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -459,11 +570,33 @@ _cdio_get_track_green(void *user_data, track_t track_num)
|
||||
return _obj->tocent[track_num-1].track_green;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for track number
|
||||
track_num in obj. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
1 is returned on error.
|
||||
*/
|
||||
static lba_t
|
||||
_cdio_get_track_lba(void *user_data, track_t track_num)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
_cdio_init (_obj);
|
||||
|
||||
if (track_num == CDIO_LEADOUT_TRACK) track_num = _obj->total_tracks+1;
|
||||
|
||||
if (track_num <= _obj->total_tracks+1 && track_num != 0) {
|
||||
return _obj->tocent[track_num-1].start_lba;
|
||||
} else
|
||||
return CDIO_INVALID_LBA;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for the track number
|
||||
track_num in obj. Tracks numbers start at 1.
|
||||
Since there are no tracks, unless the track number is is 1 we return
|
||||
falure. If the track number is 1, we return 00:00:00.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
|
||||
*/
|
||||
static bool
|
||||
_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
|
||||
@@ -497,7 +630,7 @@ cdio_open_bincue (const char *source_name)
|
||||
.get_num_tracks = _cdio_get_num_tracks,
|
||||
.get_track_format = _cdio_get_track_format,
|
||||
.get_track_green = _cdio_get_track_green,
|
||||
.get_track_lba = NULL, /* This could be implemented if need be. */
|
||||
.get_track_lba = _cdio_get_track_lba,
|
||||
.get_track_msf = _cdio_get_track_msf,
|
||||
.read_mode2_sector = _read_mode2_sector,
|
||||
.read_mode2_sectors = _read_mode2_sectors,
|
||||
@@ -535,8 +668,10 @@ cdio_open_cue (const char *cue_name)
|
||||
.get_num_tracks = _cdio_get_num_tracks,
|
||||
.get_track_format = _cdio_get_track_format,
|
||||
.get_track_green = _cdio_get_track_green,
|
||||
.get_track_lba = NULL, /* This could be implemented if need be. */
|
||||
.get_track_lba = _cdio_get_track_lba,
|
||||
.get_track_msf = _cdio_get_track_msf,
|
||||
.lseek = _cdio_lseek,
|
||||
.read = _cdio_read,
|
||||
.read_mode2_sector = _read_mode2_sector,
|
||||
.read_mode2_sectors = _read_mode2_sectors,
|
||||
.set_arg = _cdio_set_arg,
|
||||
|
||||
614
lib/_cdio_bsdi.c
614
lib/_cdio_bsdi.c
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
$Id: _cdio_bsdi.c,v 1.2 2003/03/24 23:59:22 rocky Exp $
|
||||
$Id: _cdio_bsdi.c,v 1.3 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -18,85 +18,74 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* This file contains Linux-specific code and implements low-level
|
||||
control of the CD drive.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_bsdi.c,v 1.3 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
#include "cdio_assert.h"
|
||||
#include "cdio_private.h"
|
||||
#include "util.h"
|
||||
#include "sector.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef HAVE_BSDI_CDROM
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_bsdi.c,v 1.2 2003/03/24 23:59:22 rocky Exp $";
|
||||
|
||||
#if HAVE_BSDI_CDROM
|
||||
|
||||
#include </sys/dev/scsi/scsi.h>
|
||||
#include </sys/dev/scsi/scsi_ioctl.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* reader */
|
||||
#include <dvd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#define DEFAULT_CDIO_DEVICE "/dev/sr0"
|
||||
|
||||
#define TOTAL_TRACKS (_obj->tochdr.cdth_trk1)
|
||||
#define FIRST_TRACK_NUM (_obj->tochdr.cdth_trk0)
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
|
||||
int ioctls_debugged; /* for debugging */
|
||||
|
||||
enum {
|
||||
_AM_NONE,
|
||||
_AM_READ_CD,
|
||||
_AM_READ_10
|
||||
_AM_IOCTL,
|
||||
} access_mode;
|
||||
|
||||
char *source_name;
|
||||
|
||||
bool init;
|
||||
|
||||
/* Track information */
|
||||
bool toc_init; /* if true, info below is valid. */
|
||||
struct cdrom_tochdr tochdr;
|
||||
struct cdrom_tocentry tocent[100]; /* entry info for each track */
|
||||
|
||||
} _img_private_t;
|
||||
|
||||
static int
|
||||
_scsi_cmd (int fd, struct scsi_user_cdb *sucp, const char *tag)
|
||||
{
|
||||
u_char *cp;
|
||||
|
||||
if (ioctl (fd, SCSIRAWCDB, sucp))
|
||||
{
|
||||
vcd_error ("%s: ioctl (SCSIRAWCDB): %s", tag, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
if (sucp->suc_sus.sus_status)
|
||||
{
|
||||
cp = sucp->suc_sus.sus_sense;
|
||||
vcd_info("%s: cmd: %x sus_status %d ", tag, sucp->suc_cdb[0],
|
||||
sucp->suc_sus.sus_status);
|
||||
vcd_info(" sense: %x %x %x %x %x %x %x %x", cp[0], cp[1], cp[2],
|
||||
cp[3], cp[4], cp[5], cp[6], cp[7]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize CD device.
|
||||
*/
|
||||
static bool
|
||||
_cdio_init (_img_private_t *_obj)
|
||||
{
|
||||
if (_obj->init)
|
||||
return;
|
||||
if (_obj->init) {
|
||||
cdio_error ("init called more than once");
|
||||
return false;
|
||||
}
|
||||
|
||||
_obj->fd = open (_obj->source_name, O_RDONLY, 0);
|
||||
_obj->access_mode = _AM_READ_CD;
|
||||
|
||||
if (_obj->fd < 0)
|
||||
{
|
||||
@@ -109,7 +98,6 @@ _cdio_init (_img_private_t *_obj)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Release and free resources associated with cd.
|
||||
*/
|
||||
@@ -118,240 +106,128 @@ _cdio_free (void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (NULL == _obj) return;
|
||||
free (_obj->source_name);
|
||||
|
||||
if (_obj->fd)
|
||||
if (_obj->fd >= 0)
|
||||
close (_obj->fd);
|
||||
|
||||
free (_obj);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads a single mode2 sector from cd device into data starting
|
||||
from lsn. Returns 0 if no error.
|
||||
*/
|
||||
static int
|
||||
_set_bsize (int fd, unsigned int bsize)
|
||||
_read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
bool mode2_form2)
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t reserved1;
|
||||
uint8_t medium;
|
||||
uint8_t reserved2;
|
||||
uint8_t block_desc_length;
|
||||
uint8_t density;
|
||||
uint8_t number_of_blocks_hi;
|
||||
uint8_t number_of_blocks_med;
|
||||
uint8_t number_of_blocks_lo;
|
||||
uint8_t reserved3;
|
||||
uint8_t block_length_hi;
|
||||
uint8_t block_length_med;
|
||||
uint8_t block_length_lo;
|
||||
} mh;
|
||||
char buf[M2RAW_SECTOR_SIZE] = { 0, };
|
||||
struct cdrom_msf *msf = (struct cdrom_msf *) &buf;
|
||||
msf_t _msf;
|
||||
|
||||
struct scsi_user_cdb suc;
|
||||
|
||||
memset (&mh, 0, sizeof (mh));
|
||||
memset (&suc, 0, sizeof (struct scsi_user_cdb));
|
||||
|
||||
suc.suc_cdb[0] = 0x15;
|
||||
suc.suc_cdb[1] = 1 << 4;
|
||||
suc.suc_cdb[4] = 12;
|
||||
suc.suc_cdblen = 6;;
|
||||
|
||||
suc.suc_data = (u_char *)&mh;
|
||||
suc.suc_datalen = sizeof (mh);
|
||||
|
||||
suc.suc_timeout = 500;
|
||||
suc.suc_flags = SUC_WRITE;
|
||||
|
||||
mh.block_desc_length = 0x08;
|
||||
mh.block_length_hi = (bsize >> 16) & 0xff;
|
||||
mh.block_length_med = (bsize >> 8) & 0xff;
|
||||
mh.block_length_lo = (bsize >> 0) & 0xff;
|
||||
|
||||
return _scsi_cmd (fd, &suc, "_set_bsize");
|
||||
}
|
||||
|
||||
static int
|
||||
_read_mode2 (int fd, void *buf, uint32_t lba, unsigned nblocks,
|
||||
bool _workaround)
|
||||
{
|
||||
struct scsi_user_cdb suc;
|
||||
int retval = 0;
|
||||
|
||||
memset (&suc, 0, sizeof (struct scsi_user_cdb));
|
||||
|
||||
suc.suc_cdb[0] = (_workaround
|
||||
? 0x28 /* CMD_READ_10 */
|
||||
: 0xbe /* CMD_READ_CD */);
|
||||
|
||||
if (!_workaround)
|
||||
suc.suc_cdb[1] = 0; /* sector size mode2 */
|
||||
|
||||
suc.suc_cdb[2] = (lba >> 24) & 0xff;
|
||||
suc.suc_cdb[3] = (lba >> 16) & 0xff;
|
||||
suc.suc_cdb[4] = (lba >> 8) & 0xff;
|
||||
suc.suc_cdb[5] = (lba >> 0) & 0xff;
|
||||
|
||||
suc.suc_cdb[6] = (nblocks >> 16) & 0xff;
|
||||
suc.suc_cdb[7] = (nblocks >> 8) & 0xff;
|
||||
suc.suc_cdb[8] = (nblocks >> 0) & 0xff;
|
||||
|
||||
if (!_workaround)
|
||||
suc.suc_cdb[9] = 0x58; /* 2336 mode2 mixed form */
|
||||
|
||||
suc.suc_cdblen = _workaround ? 10 : 12;
|
||||
|
||||
suc.suc_data = buf;
|
||||
suc.suc_datalen = 2336 * nblocks;
|
||||
|
||||
suc.suc_timeout = 500;
|
||||
suc.suc_flags = SUC_READ;
|
||||
|
||||
if (_workaround)
|
||||
{
|
||||
if ((retval = _set_bsize (fd, 2336)))
|
||||
goto out;
|
||||
|
||||
if ((retval = _scsi_cmd(fd, &suc, "_read_mode2_workaround")))
|
||||
{
|
||||
_set_bsize (fd, 2048);
|
||||
goto out;
|
||||
}
|
||||
retval = _set_bsize (fd, 2048);
|
||||
}
|
||||
else
|
||||
retval = _scsi_cmd(fd, &suc, "_read_mode2");
|
||||
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_read_mode2_sector (void *user_data, void *data, uint32_t lsn, bool form2)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
_cdio_init (_obj);
|
||||
cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
|
||||
msf->cdmsf_min0 = from_bcd8(_msf.m);
|
||||
msf->cdmsf_sec0 = from_bcd8(_msf.s);
|
||||
msf->cdmsf_frame0 = from_bcd8(_msf.f);
|
||||
|
||||
if (_obj->ioctls_debugged == 75)
|
||||
cdio_debug ("only displaying every 75th ioctl from now on");
|
||||
|
||||
if (_obj->ioctls_debugged == 30 * 75)
|
||||
cdio_debug ("only displaying every 30*75th ioctl from now on");
|
||||
|
||||
if (_obj->ioctls_debugged < 75
|
||||
|| (_obj->ioctls_debugged < (30 * 75)
|
||||
&& _obj->ioctls_debugged % 75 == 0)
|
||||
|| _obj->ioctls_debugged % (30 * 75) == 0)
|
||||
cdio_debug ("reading %2.2d:%2.2d:%2.2d",
|
||||
msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0);
|
||||
|
||||
_obj->ioctls_debugged++;
|
||||
|
||||
if (form2)
|
||||
{
|
||||
retry:
|
||||
switch (_obj->access_mode)
|
||||
{
|
||||
case _AM_NONE:
|
||||
vcd_error ("no way to read mode2");
|
||||
cdio_error ("no way to read mode2");
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case _AM_READ_CD:
|
||||
case _AM_READ_10:
|
||||
if (_read_mode2 (_obj->fd, data, lsn, 1,
|
||||
(_obj->access_mode == _AM_READ_10)))
|
||||
case _AM_IOCTL:
|
||||
if (ioctl (_obj->fd, CDROMREADMODE2, &buf) == -1)
|
||||
{
|
||||
if (_obj->access_mode == _AM_READ_CD)
|
||||
{
|
||||
vcd_info ("READ_CD failed; switching to READ_10 mode...");
|
||||
_obj->access_mode = _AM_READ_10;
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
{
|
||||
vcd_info ("READ_10 failed; no way to read mode2 left.");
|
||||
_obj->access_mode = _AM_NONE;
|
||||
goto retry;
|
||||
}
|
||||
perror ("ioctl()");
|
||||
return 1;
|
||||
/* exit (EXIT_FAILURE); */
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (mode2_form2)
|
||||
memcpy (data, buf, M2RAW_SECTOR_SIZE);
|
||||
else
|
||||
{
|
||||
char buf[M2RAW_SIZE] = { 0, };
|
||||
int retval;
|
||||
|
||||
if ((retval = _read_mode2_sector (_obj, buf, lsn, true)))
|
||||
return retval;
|
||||
|
||||
memcpy (data, buf + 8, M2F1_SECTOR_SIZE);
|
||||
}
|
||||
memcpy (((char *)data), buf + 8, FORM1_DATA_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u_char scsi_cdblen[8] = {6, 10, 10, 12, 12, 12, 10, 10};
|
||||
/*!
|
||||
Reads nblocks of mode2 sectors from cd device into data starting
|
||||
from lsn.
|
||||
Returns 0 if no error.
|
||||
*/
|
||||
static int
|
||||
_read_mode2_sectors (void *user_data, void *data, lsn_t lsn,
|
||||
bool mode2_form2, unsigned nblocks)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
int i;
|
||||
int retval;
|
||||
|
||||
for (i = 0; i < nblocks; i++) {
|
||||
if (mode2_form2) {
|
||||
if ( (retval = _read_mode2_sector (_obj,
|
||||
((char *)data) + (M2RAW_SECTOR_SIZE * i),
|
||||
lsn + i, true)) )
|
||||
return retval;
|
||||
} else {
|
||||
char buf[M2RAW_SECTOR_SIZE] = { 0, };
|
||||
if ( (retval = _read_mode2_sector (_obj, buf, lsn + i, true)) )
|
||||
return retval;
|
||||
|
||||
memcpy (((char *)data) + (FORM1_DATA_SIZE * i), buf + 8,
|
||||
FORM1_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the size of the CD in logical block address (LBA) units.
|
||||
*/
|
||||
static uint32_t
|
||||
_cdio_stat_size (void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
struct scsi_user_cdb suc;
|
||||
uint8_t buf[12] = { 0, };
|
||||
|
||||
uint32_t retval;
|
||||
|
||||
_cdio_init(_obj);
|
||||
|
||||
memset (&suc, 0, sizeof (struct scsi_user_cdb));
|
||||
|
||||
suc.suc_cdb[0] = 0x43; /* CMD_READ_TOC_PMA_ATIP */
|
||||
suc.suc_cdb[1] = 0; /* lba; msf: 0x2 */
|
||||
suc.suc_cdb[6] = 0xaa; /* CDROM_LEADOUT */
|
||||
suc.suc_cdb[8] = 12; /* ? */
|
||||
suc.suc_cdblen = 10;
|
||||
|
||||
suc.suc_data = buf;
|
||||
suc.suc_datalen = sizeof (buf);
|
||||
|
||||
suc.suc_timeout = 500;
|
||||
suc.suc_flags = SUC_READ;
|
||||
|
||||
if (_scsi_cmd(_obj->fd, &suc, "_cdio_stat_size"))
|
||||
return 0;
|
||||
struct cdrom_tocentry tocent;
|
||||
uint32_t size;
|
||||
|
||||
tocent.cdte_track = CDROM_LEADOUT;
|
||||
tocent.cdte_format = CDROM_LBA;
|
||||
if (ioctl (_obj->fd, CDROMREADTOCENTRY, &tocent) == -1)
|
||||
{
|
||||
int i;
|
||||
|
||||
retval = 0;
|
||||
for (i = 8; i < 12; i++)
|
||||
{
|
||||
retval <<= 8;
|
||||
retval += buf[i];
|
||||
}
|
||||
perror ("ioctl(CDROMREADTOCENTRY)");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
size = tocent.cdte_addr.lba;
|
||||
|
||||
/*!
|
||||
Return the value associated with the key "arg".
|
||||
*/
|
||||
static const char *
|
||||
_cdio_get_arg (void *user_data, const char key[])
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!strcmp (key, "source")) {
|
||||
return _obj->source_name;
|
||||
} else if (!strcmp (key, "access-mode")) {
|
||||
switch (_obj->access_mode) {
|
||||
case _AM_READ_CD:
|
||||
return "READ_CD";
|
||||
case _AM_READ_10:
|
||||
return "READ_10";
|
||||
case _AM_NONE:
|
||||
return "no access method";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return a string containing the default VCD device if none is specified.
|
||||
*/
|
||||
static char *
|
||||
_cdio_get_default_device()
|
||||
{
|
||||
return strdup(DEFAULT_CDIO_DEVICE);
|
||||
return size;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -373,10 +249,8 @@ _cdio_set_arg (void *user_data, const char key[], const char value[])
|
||||
}
|
||||
else if (!strcmp (key, "access-mode"))
|
||||
{
|
||||
if (!strcmp(value, "READ_CD"))
|
||||
_obj->access_mode = _AM_READ_CD;
|
||||
else if (!strcmp(value, "READ_10"))
|
||||
_obj->access_mode = _AM_READ_10;
|
||||
if (!strcmp(value, "IOCTL"))
|
||||
_obj->access_mode = _AM_IOCTL;
|
||||
else
|
||||
cdio_error ("unknown access type: %s. ignored.", value);
|
||||
}
|
||||
@@ -386,13 +260,254 @@ _cdio_set_arg (void *user_data, const char key[], const char value[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Read and cache the CD's Track Table of Contents and track info.
|
||||
Return false if successful or true if an error.
|
||||
*/
|
||||
static bool
|
||||
_cdio_read_toc (_img_private_t *_obj)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* read TOC header */
|
||||
if ( ioctl(_obj->fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) {
|
||||
cdio_error("%s: %s\n",
|
||||
"error in ioctl CDROMREADTOCHDR", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* read individual tracks */
|
||||
for (i= FIRST_TRACK_NUM; i<=TOTAL_TRACKS; i++) {
|
||||
_obj->tocent[i-1].cdte_track = i;
|
||||
_obj->tocent[i-1].cdte_format = CDROM_MSF;
|
||||
if ( ioctl(_obj->fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) {
|
||||
cdio_error("%s %d: %s\n",
|
||||
"error in ioctl CDROMREADTOCENTRY for track",
|
||||
i, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
/****
|
||||
struct cdrom_msf0 *msf= &_obj->tocent[i-1].cdte_addr.msf;
|
||||
|
||||
fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
|
||||
i, msf->minute, msf->second, msf->frame);
|
||||
****/
|
||||
|
||||
}
|
||||
|
||||
/* read the lead-out track */
|
||||
_obj->tocent[TOTAL_TRACKS].cdte_track = CDROM_LEADOUT;
|
||||
_obj->tocent[TOTAL_TRACKS].cdte_format = CDROM_MSF;
|
||||
|
||||
if (ioctl(_obj->fd, CDROMREADTOCENTRY,
|
||||
&_obj->tocent[TOTAL_TRACKS]) == -1 ) {
|
||||
cdio_error("%s: %s\n",
|
||||
"error in ioctl CDROMREADTOCENTRY for lead-out",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
struct cdrom_msf0 *msf= &_obj->tocent[TOTAL_TRACKS].cdte_addr.msf;
|
||||
|
||||
fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
|
||||
i, msf->minute, msf->second, msf->frame);
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Eject media in CD drive. If successful, as a side effect we
|
||||
also free obj.
|
||||
*/
|
||||
static int
|
||||
_cdio_eject_media (void *user_data) {
|
||||
|
||||
_img_private_t *_obj = user_data;
|
||||
int ret=2;
|
||||
int status;
|
||||
int fd;
|
||||
|
||||
if ((fd = open (_obj->source_name, O_RDONLY|O_NONBLOCK)) > -1) {
|
||||
if((status = ioctl(fd, CDROM_DRIVE_STATUS, (void *) CDSL_CURRENT)) > 0) {
|
||||
switch(status) {
|
||||
case CDS_TRAY_OPEN:
|
||||
if((ret = ioctl(fd, CDROMCLOSETRAY, 0)) != 0) {
|
||||
cdio_error ("ioctl CDROMCLOSETRAY failed: %s\n", strerror(errno));
|
||||
}
|
||||
break;
|
||||
case CDS_DISC_OK:
|
||||
if((ret = ioctl(fd, CDROMEJECT, 0)) != 0) {
|
||||
cdio_error("ioctl CDROMEJECT failed: %s\n", strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
ret=0;
|
||||
} else {
|
||||
cdio_error ("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno));
|
||||
ret=1;
|
||||
}
|
||||
close(fd);
|
||||
_cdio_free((void *) _obj);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the value associated with the key "arg".
|
||||
*/
|
||||
static const char *
|
||||
_cdio_get_arg (void *user_data, const char key[])
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!strcmp (key, "source")) {
|
||||
return _obj->source_name;
|
||||
} else if (!strcmp (key, "access-mode")) {
|
||||
switch (_obj->access_mode) {
|
||||
case _AM_IOCTL:
|
||||
return "ioctl";
|
||||
case _AM_NONE:
|
||||
return "no access method";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return a string containing the default VCD device if none is specified.
|
||||
*/
|
||||
static char *
|
||||
_cdio_get_default_device()
|
||||
{
|
||||
return strdup(DEFAULT_CDIO_DEVICE);
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the number of of the first track.
|
||||
CDIO_INVALID_TRACK is returned on error.
|
||||
*/
|
||||
static track_t
|
||||
_cdio_get_first_track_num(void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
|
||||
|
||||
return FIRST_TRACK_NUM;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the number of tracks in the current medium.
|
||||
CDIO_INVALID_TRACK is returned on error.
|
||||
*/
|
||||
static track_t
|
||||
_cdio_get_num_tracks(void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
|
||||
|
||||
return TOTAL_TRACKS;
|
||||
}
|
||||
|
||||
/*!
|
||||
Get format of track.
|
||||
*/
|
||||
static track_format_t
|
||||
_cdio_get_track_format(void *user_data, track_t track_num)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
|
||||
|
||||
if (track_num > TOTAL_TRACKS || track_num == 0)
|
||||
return TRACK_FORMAT_ERROR;
|
||||
|
||||
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
|
||||
in linux/cdrom.c.
|
||||
*/
|
||||
if (_obj->tocent[track_num-1].cdte_ctrl & CDROM_DATA_TRACK) {
|
||||
if (_obj->tocent[track_num-1].cdte_format == 0x10)
|
||||
return TRACK_FORMAT_CDI;
|
||||
else if (_obj->tocent[track_num-1].cdte_format == 0x20)
|
||||
return TRACK_FORMAT_XA;
|
||||
else
|
||||
return TRACK_FORMAT_DATA;
|
||||
} else
|
||||
return TRACK_FORMAT_AUDIO;
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Return true if we have XA data (green, mode2 form1) or
|
||||
XA data (green, mode2 form2). That is track begins:
|
||||
sync - header - subheader
|
||||
12 4 - 8
|
||||
|
||||
FIXME: there's gotta be a better design for this and get_track_format?
|
||||
*/
|
||||
static bool
|
||||
_cdio_get_track_green(void *user_data, track_t track_num)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
|
||||
|
||||
if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1;
|
||||
|
||||
if (track_num > TOTAL_TRACKS+1 || track_num == 0)
|
||||
return false;
|
||||
|
||||
/* FIXME: Dunno if this is the right way, but it's what
|
||||
I was using in cdinfo for a while.
|
||||
*/
|
||||
return ((_obj->tocent[track_num-1].cdte_ctrl & 2) != 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for track number
|
||||
track_num in obj. Track numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
False is returned if there is no track entry.
|
||||
*/
|
||||
static bool
|
||||
_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (NULL == msf) return false;
|
||||
|
||||
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
|
||||
|
||||
if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1;
|
||||
|
||||
if (track_num > TOTAL_TRACKS+1 || track_num == 0) {
|
||||
return false;
|
||||
} else {
|
||||
struct cdrom_msf0 *msf0= &_obj->tocent[track_num-1].cdte_addr.msf;
|
||||
msf->m = to_bcd8(msf0->minute);
|
||||
msf->s = to_bcd8(msf0->second);
|
||||
msf->f = to_bcd8(msf0->frame);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_BSDI_CDROM */
|
||||
|
||||
/*!
|
||||
Initialization routine. This is the only thing that doesn't
|
||||
get called via a function pointer. In fact *we* are the
|
||||
ones to set that up.
|
||||
*/
|
||||
CdIo *
|
||||
cdio_open_bsdi (const char *source_name)
|
||||
{
|
||||
|
||||
#ifdef HAVE_BSDI_CDROM
|
||||
CdIo *ret;
|
||||
_img_private_t *_data;
|
||||
|
||||
cdio_funcs _funcs = {
|
||||
@@ -400,13 +515,20 @@ cdio_open_bsdi (const char *source_name)
|
||||
.free = _cdio_free,
|
||||
.get_arg = _cdio_get_arg,
|
||||
.get_default_device = _cdio_get_default_device,
|
||||
.get_first_track_num= _cdio_get_first_track_num,
|
||||
.get_num_tracks = _cdio_get_num_tracks,
|
||||
.get_track_format = _cdio_get_track_format,
|
||||
.get_track_green = _cdio_get_track_green,
|
||||
.get_track_lba = NULL, /* This could be implemented if need be. */
|
||||
.get_track_msf = _cdio_get_track_msf,
|
||||
.read_mode2_sector = _read_mode2_sector,
|
||||
.read_mode2_sectors = _read_mode2_sectors,
|
||||
.set_arg = _cdio_set_arg,
|
||||
.stat_size = _cdio_stat_size
|
||||
};
|
||||
|
||||
_data = _cdio_malloc (sizeof (_img_private_t));
|
||||
_data->access_mode = _AM_READ_CD;
|
||||
_data->access_mode = _AM_IOCTL;
|
||||
_data->init = false;
|
||||
_data->fd = -1;
|
||||
|
||||
@@ -426,8 +548,8 @@ cdio_open_bsdi (const char *source_name)
|
||||
#else
|
||||
return NULL;
|
||||
#endif /* HAVE_BSDI_CDROM */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
cdio_have_bsdi (void)
|
||||
|
||||
443
lib/_cdio_bsdi_old.c
Normal file
443
lib/_cdio_bsdi_old.c
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
$Id: _cdio_bsdi_old.c,v 1.1 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "cdio_assert.h"
|
||||
#include "cdio_private.h"
|
||||
#include "util.h"
|
||||
#include "sector.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_bsdi_old.c,v 1.1 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
#if HAVE_BSDI_CDROM
|
||||
|
||||
#include </sys/dev/scsi/scsi.h>
|
||||
#include </sys/dev/scsi/scsi_ioctl.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DEFAULT_CDIO_DEVICE "/dev/rsr0c"
|
||||
|
||||
/* reader */
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
|
||||
enum {
|
||||
_AM_NONE,
|
||||
_AM_READ_CD,
|
||||
_AM_READ_10
|
||||
} access_mode;
|
||||
|
||||
char *source_name;
|
||||
|
||||
bool init;
|
||||
} _img_private_t;
|
||||
|
||||
static int
|
||||
_scsi_cmd (int fd, struct scsi_user_cdb *sucp, const char *tag)
|
||||
{
|
||||
u_char *cp;
|
||||
|
||||
if (ioctl (fd, SCSIRAWCDB, sucp))
|
||||
{
|
||||
vcd_error ("%s: ioctl (SCSIRAWCDB): %s", tag, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
if (sucp->suc_sus.sus_status)
|
||||
{
|
||||
cp = sucp->suc_sus.sus_sense;
|
||||
vcd_info("%s: cmd: %x sus_status %d ", tag, sucp->suc_cdb[0],
|
||||
sucp->suc_sus.sus_status);
|
||||
vcd_info(" sense: %x %x %x %x %x %x %x %x", cp[0], cp[1], cp[2],
|
||||
cp[3], cp[4], cp[5], cp[6], cp[7]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize CD device.
|
||||
*/
|
||||
static bool
|
||||
_cdio_init (_img_private_t *_obj)
|
||||
{
|
||||
if (_obj->init)
|
||||
return;
|
||||
|
||||
_obj->fd = open (_obj->source_name, O_RDONLY, 0);
|
||||
_obj->access_mode = _AM_READ_CD;
|
||||
|
||||
if (_obj->fd < 0)
|
||||
{
|
||||
cdio_error ("open (%s): %s", _obj->source_name, strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
_obj->init = true;
|
||||
_obj->toc_init = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Release and free resources associated with cd.
|
||||
*/
|
||||
static void
|
||||
_cdio_free (void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
free (_obj->source_name);
|
||||
|
||||
if (_obj->fd)
|
||||
close (_obj->fd);
|
||||
|
||||
free (_obj);
|
||||
}
|
||||
|
||||
static int
|
||||
_set_bsize (int fd, unsigned int bsize)
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t reserved1;
|
||||
uint8_t medium;
|
||||
uint8_t reserved2;
|
||||
uint8_t block_desc_length;
|
||||
uint8_t density;
|
||||
uint8_t number_of_blocks_hi;
|
||||
uint8_t number_of_blocks_med;
|
||||
uint8_t number_of_blocks_lo;
|
||||
uint8_t reserved3;
|
||||
uint8_t block_length_hi;
|
||||
uint8_t block_length_med;
|
||||
uint8_t block_length_lo;
|
||||
} mh;
|
||||
|
||||
struct scsi_user_cdb suc;
|
||||
|
||||
memset (&mh, 0, sizeof (mh));
|
||||
memset (&suc, 0, sizeof (struct scsi_user_cdb));
|
||||
|
||||
suc.suc_cdb[0] = 0x15;
|
||||
suc.suc_cdb[1] = 1 << 4;
|
||||
suc.suc_cdb[4] = 12;
|
||||
suc.suc_cdblen = 6;;
|
||||
|
||||
suc.suc_data = (u_char *)&mh;
|
||||
suc.suc_datalen = sizeof (mh);
|
||||
|
||||
suc.suc_timeout = 500;
|
||||
suc.suc_flags = SUC_WRITE;
|
||||
|
||||
mh.block_desc_length = 0x08;
|
||||
mh.block_length_hi = (bsize >> 16) & 0xff;
|
||||
mh.block_length_med = (bsize >> 8) & 0xff;
|
||||
mh.block_length_lo = (bsize >> 0) & 0xff;
|
||||
|
||||
return _scsi_cmd (fd, &suc, "_set_bsize");
|
||||
}
|
||||
|
||||
static int
|
||||
_read_mode2 (int fd, void *buf, uint32_t lba, unsigned nblocks,
|
||||
bool _workaround)
|
||||
{
|
||||
struct scsi_user_cdb suc;
|
||||
int retval = 0;
|
||||
|
||||
memset (&suc, 0, sizeof (struct scsi_user_cdb));
|
||||
|
||||
suc.suc_cdb[0] = (_workaround
|
||||
? 0x28 /* CMD_READ_10 */
|
||||
: 0xbe /* CMD_READ_CD */);
|
||||
|
||||
if (!_workaround)
|
||||
suc.suc_cdb[1] = 0; /* sector size mode2 */
|
||||
|
||||
suc.suc_cdb[2] = (lba >> 24) & 0xff;
|
||||
suc.suc_cdb[3] = (lba >> 16) & 0xff;
|
||||
suc.suc_cdb[4] = (lba >> 8) & 0xff;
|
||||
suc.suc_cdb[5] = (lba >> 0) & 0xff;
|
||||
|
||||
suc.suc_cdb[6] = (nblocks >> 16) & 0xff;
|
||||
suc.suc_cdb[7] = (nblocks >> 8) & 0xff;
|
||||
suc.suc_cdb[8] = (nblocks >> 0) & 0xff;
|
||||
|
||||
if (!_workaround)
|
||||
suc.suc_cdb[9] = 0x58; /* 2336 mode2 mixed form */
|
||||
|
||||
suc.suc_cdblen = _workaround ? 10 : 12;
|
||||
|
||||
suc.suc_data = buf;
|
||||
suc.suc_datalen = 2336 * nblocks;
|
||||
|
||||
suc.suc_timeout = 500;
|
||||
suc.suc_flags = SUC_READ;
|
||||
|
||||
if (_workaround)
|
||||
{
|
||||
if ((retval = _set_bsize (fd, 2336)))
|
||||
goto out;
|
||||
|
||||
if ((retval = _scsi_cmd(fd, &suc, "_read_mode2_workaround")))
|
||||
{
|
||||
_set_bsize (fd, 2048);
|
||||
goto out;
|
||||
}
|
||||
retval = _set_bsize (fd, 2048);
|
||||
}
|
||||
else
|
||||
retval = _scsi_cmd(fd, &suc, "_read_mode2");
|
||||
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_read_mode2_sector (void *user_data, void *data, uint32_t lsn, bool form2)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
_cdio_init (_obj);
|
||||
|
||||
if (form2)
|
||||
{
|
||||
retry:
|
||||
switch (_obj->access_mode)
|
||||
{
|
||||
case _AM_NONE:
|
||||
vcd_error ("no way to read mode2");
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case _AM_READ_CD:
|
||||
case _AM_READ_10:
|
||||
if (_read_mode2 (_obj->fd, data, lsn, 1,
|
||||
(_obj->access_mode == _AM_READ_10)))
|
||||
{
|
||||
if (_obj->access_mode == _AM_READ_CD)
|
||||
{
|
||||
vcd_info ("READ_CD failed; switching to READ_10 mode...");
|
||||
_obj->access_mode = _AM_READ_10;
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
{
|
||||
vcd_info ("READ_10 failed; no way to read mode2 left.");
|
||||
_obj->access_mode = _AM_NONE;
|
||||
goto retry;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[M2RAW_SIZE] = { 0, };
|
||||
int retval;
|
||||
|
||||
if ((retval = _read_mode2_sector (_obj, buf, lsn, true)))
|
||||
return retval;
|
||||
|
||||
memcpy (data, buf + 8, M2F1_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u_char scsi_cdblen[8] = {6, 10, 10, 12, 12, 12, 10, 10};
|
||||
|
||||
static uint32_t
|
||||
_cdio_stat_size (void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
struct scsi_user_cdb suc;
|
||||
uint8_t buf[12] = { 0, };
|
||||
|
||||
uint32_t retval;
|
||||
|
||||
_cdio_init(_obj);
|
||||
|
||||
memset (&suc, 0, sizeof (struct scsi_user_cdb));
|
||||
|
||||
suc.suc_cdb[0] = 0x43; /* CMD_READ_TOC_PMA_ATIP */
|
||||
suc.suc_cdb[1] = 0; /* lba; msf: 0x2 */
|
||||
suc.suc_cdb[6] = 0xaa; /* CDROM_LEADOUT */
|
||||
suc.suc_cdb[8] = 12; /* ? */
|
||||
suc.suc_cdblen = 10;
|
||||
|
||||
suc.suc_data = buf;
|
||||
suc.suc_datalen = sizeof (buf);
|
||||
|
||||
suc.suc_timeout = 500;
|
||||
suc.suc_flags = SUC_READ;
|
||||
|
||||
if (_scsi_cmd(_obj->fd, &suc, "_cdio_stat_size"))
|
||||
return 0;
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
retval = 0;
|
||||
for (i = 8; i < 12; i++)
|
||||
{
|
||||
retval <<= 8;
|
||||
retval += buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the value associated with the key "arg".
|
||||
*/
|
||||
static const char *
|
||||
_cdio_get_arg (void *user_data, const char key[])
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!strcmp (key, "source")) {
|
||||
return _obj->source_name;
|
||||
} else if (!strcmp (key, "access-mode")) {
|
||||
switch (_obj->access_mode) {
|
||||
case _AM_READ_CD:
|
||||
return "READ_CD";
|
||||
case _AM_READ_10:
|
||||
return "READ_10";
|
||||
case _AM_NONE:
|
||||
return "no access method";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return a string containing the default VCD device if none is specified.
|
||||
*/
|
||||
static char *
|
||||
_cdio_get_default_device()
|
||||
{
|
||||
return strdup(DEFAULT_CDIO_DEVICE);
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the key "arg" to "value" in source device.
|
||||
*/
|
||||
static int
|
||||
_cdio_set_arg (void *user_data, const char key[], const char value[])
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!strcmp (key, "source"))
|
||||
{
|
||||
if (!value)
|
||||
return -2;
|
||||
|
||||
free (_obj->source_name);
|
||||
|
||||
_obj->source_name = strdup (value);
|
||||
}
|
||||
else if (!strcmp (key, "access-mode"))
|
||||
{
|
||||
if (!strcmp(value, "READ_CD"))
|
||||
_obj->access_mode = _AM_READ_CD;
|
||||
else if (!strcmp(value, "READ_10"))
|
||||
_obj->access_mode = _AM_READ_10;
|
||||
else
|
||||
cdio_error ("unknown access type: %s. ignored.", value);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_BSDI_CDROM */
|
||||
|
||||
CdIo *
|
||||
cdio_open_bsdi (const char *source_name)
|
||||
{
|
||||
|
||||
#ifdef HAVE_BSDI_CDROM
|
||||
_img_private_t *_data;
|
||||
|
||||
cdio_funcs _funcs = {
|
||||
.eject_media = _cdio_eject_media,
|
||||
.free = _cdio_free,
|
||||
.get_arg = _cdio_get_arg,
|
||||
.get_default_device = _cdio_get_default_device,
|
||||
.read_mode2_sector = _read_mode2_sector,
|
||||
.set_arg = _cdio_set_arg,
|
||||
.stat_size = _cdio_stat_size
|
||||
};
|
||||
|
||||
_data = _cdio_malloc (sizeof (_img_private_t));
|
||||
_data->access_mode = _AM_READ_CD;
|
||||
_data->init = false;
|
||||
_data->fd = -1;
|
||||
|
||||
_cdio_set_arg(_data, "source", (NULL == source_name)
|
||||
? DEFAULT_CDIO_DEVICE: source_name);
|
||||
|
||||
ret = cdio_new (_data, &_funcs);
|
||||
if (ret == NULL) return NULL;
|
||||
|
||||
if (_cdio_init(_data))
|
||||
return ret;
|
||||
else {
|
||||
_cdio_free (_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
return NULL;
|
||||
#endif /* HAVE_BSDI_CDROM */
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
cdio_have_bsdi (void)
|
||||
{
|
||||
#ifdef HAVE_BSDI_CDROM
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif /* HAVE_BSDI_CDROM */
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: _cdio_freebsd.c,v 1.1 2003/03/25 00:00:36 rocky Exp $
|
||||
$Id: _cdio_freebsd.c,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_freebsd.c,v 1.1 2003/03/25 00:00:36 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: _cdio_freebsd.c,v 1.2 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
#include "cdio_assert.h"
|
||||
#include "cdio_private.h"
|
||||
@@ -209,7 +209,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
if (mode2_form2)
|
||||
memcpy (data, buf, M2RAW_SECTOR_SIZE);
|
||||
else
|
||||
memcpy (((char *)data), buf + 8, M2F1_SECTOR_SIZE);
|
||||
memcpy (((char *)data), buf + 8, FORM1_DATA_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
110
lib/_cdio_generic.c
Normal file
110
lib/_cdio_generic.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
$Id: _cdio_generic.c,v 1.1 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* This file contains Linux-specific code and implements low-level
|
||||
control of the CD drive.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.1 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
#include "cdio_assert.h"
|
||||
#include "cdio_private.h"
|
||||
#include "sector.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <linux/cdrom.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/*!
|
||||
Release and free resources associated with cd.
|
||||
*/
|
||||
void
|
||||
cdio_generic_free (void *user_data)
|
||||
{
|
||||
generic_img_private_t *_obj = user_data;
|
||||
|
||||
if (NULL == _obj) return;
|
||||
free (_obj->source_name);
|
||||
|
||||
if (_obj->fd >= 0)
|
||||
close (_obj->fd);
|
||||
|
||||
free (_obj);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Is in fact libc's read().
|
||||
*/
|
||||
off_t
|
||||
cdio_generic_lseek (void *user_data, off_t offset, int whence)
|
||||
{
|
||||
generic_img_private_t *_obj = user_data;
|
||||
return lseek(_obj->fd, offset, whence);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Is in fact libc's read().
|
||||
*/
|
||||
ssize_t
|
||||
cdio_generic_read (void *user_data, void *buf, size_t size)
|
||||
{
|
||||
generic_img_private_t *_obj = user_data;
|
||||
return read(_obj->fd, buf, size);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdio_generic_read_mode2_sectors (CdIo *obj, void *buf, lsn_t lsn,
|
||||
bool mode2raw, unsigned num_sectors)
|
||||
{
|
||||
char *_buf = buf;
|
||||
const int blocksize = mode2raw ? M2RAW_SECTOR_SIZE : M2F1_SECTOR_SIZE;
|
||||
int n, rc;
|
||||
|
||||
cdio_assert (obj != NULL);
|
||||
cdio_assert (buf != NULL);
|
||||
cdio_assert (obj->op.read_mode2_sector != NULL);
|
||||
|
||||
for (n = 0; n < num_sectors; n++)
|
||||
if ((rc = cdio_read_mode2_sector (obj, &_buf[n * blocksize],
|
||||
lsn + n, mode2raw)))
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: _cdio_linux.c,v 1.2 2003/03/24 23:59:22 rocky Exp $
|
||||
$Id: _cdio_linux.c,v 1.3 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
|
||||
@@ -27,7 +27,7 @@
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.2 2003/03/24 23:59:22 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.3 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
#include "cdio_assert.h"
|
||||
#include "cdio_private.h"
|
||||
@@ -65,9 +65,9 @@ static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.2 2003/03/24 23:59:22 rocky
|
||||
#define FIRST_TRACK_NUM (_obj->tochdr.cdth_trk0)
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
|
||||
int ioctls_debugged; /* for debugging */
|
||||
/* Things common to all drivers like this.
|
||||
This must be first. */
|
||||
generic_img_private_t gen;
|
||||
|
||||
enum {
|
||||
_AM_NONE,
|
||||
@@ -76,9 +76,7 @@ typedef struct {
|
||||
_AM_READ_10
|
||||
} access_mode;
|
||||
|
||||
char *source_name;
|
||||
|
||||
bool init;
|
||||
int ioctls_debugged; /* for debugging */
|
||||
|
||||
/* Track information */
|
||||
bool toc_init; /* if true, info below is valid. */
|
||||
@@ -93,41 +91,24 @@ typedef struct {
|
||||
static bool
|
||||
_cdio_init (_img_private_t *_obj)
|
||||
{
|
||||
if (_obj->init) {
|
||||
if (_obj->gen.init) {
|
||||
cdio_error ("init called more than once");
|
||||
return false;
|
||||
}
|
||||
|
||||
_obj->fd = open (_obj->source_name, O_RDONLY, 0);
|
||||
_obj->gen.fd = open (_obj->gen.source_name, O_RDONLY, 0);
|
||||
|
||||
if (_obj->fd < 0)
|
||||
if (_obj->gen.fd < 0)
|
||||
{
|
||||
cdio_error ("open (%s): %s", _obj->source_name, strerror (errno));
|
||||
cdio_error ("open (%s): %s", _obj->gen.source_name, strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
_obj->init = true;
|
||||
_obj->gen.init = true;
|
||||
_obj->toc_init = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Release and free resources associated with cd.
|
||||
*/
|
||||
static void
|
||||
_cdio_free (void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (NULL == _obj) return;
|
||||
free (_obj->source_name);
|
||||
|
||||
if (_obj->fd >= 0)
|
||||
close (_obj->fd);
|
||||
|
||||
free (_obj);
|
||||
}
|
||||
|
||||
static int
|
||||
_set_bsize (int fd, unsigned int bsize)
|
||||
{
|
||||
@@ -254,7 +235,7 @@ _read_mode2 (int fd, void *buf, lba_t lba, unsigned nblocks,
|
||||
from lsn. Returns 0 if no error.
|
||||
*/
|
||||
static int
|
||||
_read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
_cdio_read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
bool mode2_form2)
|
||||
{
|
||||
char buf[M2RAW_SECTOR_SIZE] = { 0, };
|
||||
@@ -292,7 +273,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
break;
|
||||
|
||||
case _AM_IOCTL:
|
||||
if (ioctl (_obj->fd, CDROMREADMODE2, &buf) == -1)
|
||||
if (ioctl (_obj->gen.fd, CDROMREADMODE2, &buf) == -1)
|
||||
{
|
||||
perror ("ioctl()");
|
||||
return 1;
|
||||
@@ -302,7 +283,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
|
||||
case _AM_READ_CD:
|
||||
case _AM_READ_10:
|
||||
if (_read_mode2 (_obj->fd, buf, lsn, 1,
|
||||
if (_read_mode2 (_obj->gen.fd, buf, lsn, 1,
|
||||
(_obj->access_mode == _AM_READ_10)))
|
||||
{
|
||||
perror ("ioctl()");
|
||||
@@ -326,7 +307,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
if (mode2_form2)
|
||||
memcpy (data, buf, M2RAW_SECTOR_SIZE);
|
||||
else
|
||||
memcpy (((char *)data), buf + 8, M2F1_SECTOR_SIZE);
|
||||
memcpy (((char *)data), buf + 8, FORM1_DATA_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -337,7 +318,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
Returns 0 if no error.
|
||||
*/
|
||||
static int
|
||||
_read_mode2_sectors (void *user_data, void *data, lsn_t lsn,
|
||||
_cdio_read_mode2_sectors (void *user_data, void *data, lsn_t lsn,
|
||||
bool mode2_form2, unsigned nblocks)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
@@ -346,17 +327,18 @@ _read_mode2_sectors (void *user_data, void *data, lsn_t lsn,
|
||||
|
||||
for (i = 0; i < nblocks; i++) {
|
||||
if (mode2_form2) {
|
||||
if ( (retval = _read_mode2_sector (_obj,
|
||||
((char *)data) + (M2RAW_SECTOR_SIZE * i),
|
||||
if ( (retval = _cdio_read_mode2_sector (_obj,
|
||||
((char *)data)
|
||||
+ (M2RAW_SECTOR_SIZE * i),
|
||||
lsn + i, true)) )
|
||||
return retval;
|
||||
} else {
|
||||
char buf[M2RAW_SECTOR_SIZE] = { 0, };
|
||||
if ( (retval = _read_mode2_sector (_obj, buf, lsn + i, true)) )
|
||||
if ( (retval = _cdio_read_mode2_sector (_obj, buf, lsn + i, true)) )
|
||||
return retval;
|
||||
|
||||
memcpy (((char *)data) + (M2F1_SECTOR_SIZE * i), buf + 8,
|
||||
M2F1_SECTOR_SIZE);
|
||||
memcpy (((char *)data) + (FORM1_DATA_SIZE * i), buf + 8,
|
||||
FORM1_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -375,7 +357,7 @@ _cdio_stat_size (void *user_data)
|
||||
|
||||
tocent.cdte_track = CDROM_LEADOUT;
|
||||
tocent.cdte_format = CDROM_LBA;
|
||||
if (ioctl (_obj->fd, CDROMREADTOCENTRY, &tocent) == -1)
|
||||
if (ioctl (_obj->gen.fd, CDROMREADTOCENTRY, &tocent) == -1)
|
||||
{
|
||||
perror ("ioctl(CDROMREADTOCENTRY)");
|
||||
exit (EXIT_FAILURE);
|
||||
@@ -399,9 +381,9 @@ _cdio_set_arg (void *user_data, const char key[], const char value[])
|
||||
if (!value)
|
||||
return -2;
|
||||
|
||||
free (_obj->source_name);
|
||||
free (_obj->gen.source_name);
|
||||
|
||||
_obj->source_name = strdup (value);
|
||||
_obj->gen.source_name = strdup (value);
|
||||
}
|
||||
else if (!strcmp (key, "access-mode"))
|
||||
{
|
||||
@@ -430,7 +412,7 @@ _cdio_read_toc (_img_private_t *_obj)
|
||||
int i;
|
||||
|
||||
/* read TOC header */
|
||||
if ( ioctl(_obj->fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) {
|
||||
if ( ioctl(_obj->gen.fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) {
|
||||
cdio_error("%s: %s\n",
|
||||
"error in ioctl CDROMREADTOCHDR", strerror(errno));
|
||||
return false;
|
||||
@@ -440,7 +422,7 @@ _cdio_read_toc (_img_private_t *_obj)
|
||||
for (i= FIRST_TRACK_NUM; i<=TOTAL_TRACKS; i++) {
|
||||
_obj->tocent[i-1].cdte_track = i;
|
||||
_obj->tocent[i-1].cdte_format = CDROM_MSF;
|
||||
if ( ioctl(_obj->fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) {
|
||||
if ( ioctl(_obj->gen.fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) {
|
||||
cdio_error("%s %d: %s\n",
|
||||
"error in ioctl CDROMREADTOCENTRY for track",
|
||||
i, strerror(errno));
|
||||
@@ -459,7 +441,7 @@ _cdio_read_toc (_img_private_t *_obj)
|
||||
_obj->tocent[TOTAL_TRACKS].cdte_track = CDROM_LEADOUT;
|
||||
_obj->tocent[TOTAL_TRACKS].cdte_format = CDROM_MSF;
|
||||
|
||||
if (ioctl(_obj->fd, CDROMREADTOCENTRY,
|
||||
if (ioctl(_obj->gen.fd, CDROMREADTOCENTRY,
|
||||
&_obj->tocent[TOTAL_TRACKS]) == -1 ) {
|
||||
cdio_error("%s: %s\n",
|
||||
"error in ioctl CDROMREADTOCENTRY for lead-out",
|
||||
@@ -489,7 +471,7 @@ _cdio_eject_media (void *user_data) {
|
||||
int status;
|
||||
int fd;
|
||||
|
||||
if ((fd = open (_obj->source_name, O_RDONLY|O_NONBLOCK)) > -1) {
|
||||
if ((fd = open (_obj->gen.source_name, O_RDONLY|O_NONBLOCK)) > -1) {
|
||||
if((status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)) > 0) {
|
||||
switch(status) {
|
||||
case CDS_TRAY_OPEN:
|
||||
@@ -509,7 +491,7 @@ _cdio_eject_media (void *user_data) {
|
||||
ret=1;
|
||||
}
|
||||
close(fd);
|
||||
_cdio_free((void *) _obj);
|
||||
cdio_generic_free((void *) _obj);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
@@ -523,7 +505,7 @@ _cdio_get_arg (void *user_data, const char key[])
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!strcmp (key, "source")) {
|
||||
return _obj->source_name;
|
||||
return _obj->gen.source_name;
|
||||
} else if (!strcmp (key, "access-mode")) {
|
||||
switch (_obj->access_mode) {
|
||||
case _AM_IOCTL:
|
||||
@@ -676,7 +658,7 @@ cdio_open_linux (const char *source_name)
|
||||
|
||||
cdio_funcs _funcs = {
|
||||
.eject_media = _cdio_eject_media,
|
||||
.free = _cdio_free,
|
||||
.free = cdio_generic_free,
|
||||
.get_arg = _cdio_get_arg,
|
||||
.get_default_device = _cdio_get_default_device,
|
||||
.get_first_track_num= _cdio_get_first_track_num,
|
||||
@@ -685,16 +667,18 @@ cdio_open_linux (const char *source_name)
|
||||
.get_track_green = _cdio_get_track_green,
|
||||
.get_track_lba = NULL, /* This could be implemented if need be. */
|
||||
.get_track_msf = _cdio_get_track_msf,
|
||||
.read_mode2_sector = _read_mode2_sector,
|
||||
.read_mode2_sectors = _read_mode2_sectors,
|
||||
.lseek = cdio_generic_lseek,
|
||||
.read = cdio_generic_read,
|
||||
.read_mode2_sector = _cdio_read_mode2_sector,
|
||||
.read_mode2_sectors = _cdio_read_mode2_sectors,
|
||||
.set_arg = _cdio_set_arg,
|
||||
.stat_size = _cdio_stat_size
|
||||
};
|
||||
|
||||
_data = _cdio_malloc (sizeof (_img_private_t));
|
||||
_data->access_mode = _AM_READ_CD;
|
||||
_data->init = false;
|
||||
_data->fd = -1;
|
||||
_data->gen.init = false;
|
||||
_data->gen.fd = -1;
|
||||
|
||||
_cdio_set_arg(_data, "source", (NULL == source_name)
|
||||
? DEFAULT_CDIO_DEVICE: source_name);
|
||||
@@ -705,7 +689,7 @@ cdio_open_linux (const char *source_name)
|
||||
if (_cdio_init(_data))
|
||||
return ret;
|
||||
else {
|
||||
_cdio_free (_data);
|
||||
cdio_generic_free (_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
125
lib/_cdio_nrg.c
125
lib/_cdio_nrg.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: _cdio_nrg.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: _cdio_nrg.c,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2001,2003 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include "util.h"
|
||||
#include "_cdio_stdio.h"
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_nrg.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: _cdio_nrg.c,v 1.2 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
/* structures used */
|
||||
|
||||
@@ -102,7 +102,7 @@ typedef struct {
|
||||
int track_num; /* Probably is index+1 */
|
||||
msf_t start_msf;
|
||||
int start_index;
|
||||
int secsize; /* Number of sectors in track. Does not
|
||||
int sec_count; /* Number of sectors in track. Does not
|
||||
include pregap before next entry. */
|
||||
int flags; /* "DCP", "4CH", "PRE" */
|
||||
track_format_t track_format;
|
||||
@@ -114,7 +114,7 @@ typedef struct {
|
||||
Possibly redundant with above track_info_t */
|
||||
typedef struct {
|
||||
uint32_t start_lsn;
|
||||
uint32_t secsize; /* Number of sectors in track. Does not
|
||||
uint32_t sec_count; /* Number of sectors in track. Does not
|
||||
include pregap before next entry. */
|
||||
uint64_t img_offset; /* Bytes offset from beginning of disk image file.*/
|
||||
} _mapping_t;
|
||||
@@ -122,7 +122,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
bool sector_2336_flag;
|
||||
CdioDataSource *nrg_src;
|
||||
CdioDataSource *data_source;
|
||||
char *source_name;
|
||||
track_info_t tocent[100]; /* entry info for each track */
|
||||
track_t total_tracks; /* number of tracks in image */
|
||||
@@ -145,8 +145,8 @@ _cdio_free (void *user_data)
|
||||
|
||||
free(_obj->source_name);
|
||||
|
||||
if (_obj->nrg_src)
|
||||
cdio_stream_destroy (_obj->nrg_src);
|
||||
if (_obj->data_source)
|
||||
cdio_stream_destroy (_obj->data_source);
|
||||
|
||||
_cdio_list_free (_obj->mapping, true);
|
||||
|
||||
@@ -157,7 +157,7 @@ _cdio_free (void *user_data)
|
||||
simulate ioctl(CDROMREADTOCENTRY).
|
||||
*/
|
||||
static void
|
||||
_register_mapping (_img_private_t *_obj, lsn_t start_lsn, uint32_t secsize,
|
||||
_register_mapping (_img_private_t *_obj, lsn_t start_lsn, uint32_t sec_count,
|
||||
uint64_t img_offset, uint32_t blocksize)
|
||||
{
|
||||
const int track_num=_obj->total_tracks;
|
||||
@@ -168,10 +168,10 @@ _register_mapping (_img_private_t *_obj, lsn_t start_lsn, uint32_t secsize,
|
||||
|
||||
_cdio_list_append (_obj->mapping, _map);
|
||||
_map->start_lsn = start_lsn;
|
||||
_map->secsize = secsize;
|
||||
_map->sec_count = sec_count;
|
||||
_map->img_offset = img_offset;
|
||||
|
||||
_obj->size = MAX (_obj->size, (start_lsn + secsize));
|
||||
_obj->size = MAX (_obj->size, (start_lsn + sec_count));
|
||||
|
||||
/* Update _obj->tocent[track_num] and track_num These structures are
|
||||
in a sense redundant witht the obj->mapping list. Perhaps one
|
||||
@@ -183,8 +183,7 @@ _register_mapping (_img_private_t *_obj, lsn_t start_lsn, uint32_t secsize,
|
||||
|
||||
_obj->tocent[track_num].track_num = track_num+1;
|
||||
_obj->tocent[track_num].blocksize = blocksize;
|
||||
_obj->tocent[track_num].secsize = secsize;
|
||||
_obj->tocent[track_num].secsize = secsize;
|
||||
_obj->tocent[track_num].sec_count = sec_count;
|
||||
|
||||
_obj->total_tracks++;
|
||||
|
||||
@@ -195,7 +194,7 @@ _register_mapping (_img_private_t *_obj, lsn_t start_lsn, uint32_t secsize,
|
||||
_obj->tocent[track_num].track_green = true;
|
||||
|
||||
|
||||
/* cdio_debug ("map: %d +%d -> %ld", start_lsn, secsize, img_offset); */
|
||||
/* cdio_debug ("map: %d +%d -> %ld", start_lsn, sec_count, img_offset); */
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +212,7 @@ _cdio_parse_nero_footer (_img_private_t *_obj)
|
||||
if (_obj->size)
|
||||
return 0;
|
||||
|
||||
size = cdio_stream_stat (_obj->nrg_src);
|
||||
size = cdio_stream_stat (_obj->data_source);
|
||||
|
||||
{
|
||||
PRAGMA_BEGIN_PACKED
|
||||
@@ -232,8 +231,8 @@ PRAGMA_END_PACKED
|
||||
|
||||
cdio_assert (sizeof (buf) == 12);
|
||||
|
||||
cdio_stream_seek (_obj->nrg_src, size - sizeof (buf));
|
||||
cdio_stream_read (_obj->nrg_src, (void *) &buf, sizeof (buf), 1);
|
||||
cdio_stream_seek (_obj->data_source, size - sizeof (buf), SEEK_SET);
|
||||
cdio_stream_read (_obj->data_source, (void *) &buf, sizeof (buf), 1);
|
||||
|
||||
if (buf.v50.ID == UINT32_TO_BE (0x4e45524f)) /* "NERO" */
|
||||
{
|
||||
@@ -258,8 +257,8 @@ PRAGMA_END_PACKED
|
||||
|
||||
footer_buf = _cdio_malloc (size - footer_start);
|
||||
|
||||
cdio_stream_seek (_obj->nrg_src, footer_start);
|
||||
cdio_stream_read (_obj->nrg_src, footer_buf, size - footer_start, 1);
|
||||
cdio_stream_seek (_obj->data_source, footer_start, SEEK_SET);
|
||||
cdio_stream_read (_obj->data_source, footer_buf, size - footer_start, 1);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -487,7 +486,7 @@ _cdio_init (_img_private_t *_obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(_obj->nrg_src = cdio_stdio_new (_obj->source_name))) {
|
||||
if (!(_obj->data_source = cdio_stdio_new (_obj->source_name))) {
|
||||
cdio_error ("init failed");
|
||||
return false;
|
||||
}
|
||||
@@ -498,6 +497,76 @@ _cdio_init (_img_private_t *_obj)
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Would be libc's seek() but we have to adjust for the extra track header
|
||||
information in each sector.
|
||||
*/
|
||||
static off_t
|
||||
_cdio_lseek (void *user_data, off_t offset, int whence)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
/* real_offset is the real byte offset inside the disk image
|
||||
The number below was determined empirically. I'm guessing
|
||||
the 1st 24 bytes of a bin file are used for something.
|
||||
*/
|
||||
off_t real_offset=8;
|
||||
|
||||
unsigned int i;
|
||||
unsigned int user_datasize;
|
||||
|
||||
for (i=0; i<_obj->total_tracks; i++) {
|
||||
track_info_t *this_track=&(_obj->tocent[i]);
|
||||
switch (this_track->track_format) {
|
||||
case TRACK_FORMAT_AUDIO:
|
||||
user_datasize=CDDA_SECTOR_SIZE;
|
||||
break;
|
||||
case TRACK_FORMAT_CDI:
|
||||
user_datasize=FORM1_DATA_SIZE;
|
||||
break;
|
||||
case TRACK_FORMAT_XA:
|
||||
user_datasize=FORM1_DATA_SIZE;
|
||||
break;
|
||||
default:
|
||||
cdio_warn ("track %d has unknown format %d",
|
||||
i+1, this_track->track_format);
|
||||
}
|
||||
|
||||
if ( (this_track->sec_count*user_datasize) >= offset) {
|
||||
int blocks = offset / user_datasize;
|
||||
int rem = offset % user_datasize;
|
||||
int block_offset = blocks * (M2RAW_SECTOR_SIZE);
|
||||
real_offset += block_offset + rem;
|
||||
break;
|
||||
}
|
||||
real_offset += this_track->sec_count*(M2RAW_SECTOR_SIZE);
|
||||
|
||||
offset -= this_track->sec_count*user_datasize;
|
||||
}
|
||||
|
||||
if (i==_obj->total_tracks) {
|
||||
cdio_warn ("seeking outside range of disk image");
|
||||
return -1;
|
||||
} else
|
||||
return cdio_stream_seek(_obj->data_source, real_offset, whence);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
FIXME:
|
||||
At present we assume a read doesn't cross sector or track
|
||||
boundaries.
|
||||
*/
|
||||
static ssize_t
|
||||
_cdio_read (void *user_data, void *buf, size_t size)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
return cdio_stream_read(_obj->data_source, buf, size, 1);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
_cdio_stat_size (void *user_data)
|
||||
{
|
||||
@@ -524,7 +593,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn, bool form2)
|
||||
{
|
||||
_mapping_t *_map = _cdio_list_node_data (node);
|
||||
|
||||
if (IN (lsn, _map->start_lsn, (_map->start_lsn + _map->secsize - 1)))
|
||||
if (IN (lsn, _map->start_lsn, (_map->start_lsn + _map->sec_count - 1)))
|
||||
{
|
||||
long img_offset = _map->img_offset;
|
||||
int blocksize = _obj->sector_2336_flag
|
||||
@@ -532,8 +601,8 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn, bool form2)
|
||||
|
||||
img_offset += (lsn - _map->start_lsn) * blocksize;
|
||||
|
||||
cdio_stream_seek (_obj->nrg_src, img_offset);
|
||||
cdio_stream_read (_obj->nrg_src,
|
||||
cdio_stream_seek (_obj->data_source, img_offset, SEEK_SET);
|
||||
cdio_stream_read (_obj->data_source,
|
||||
_obj->sector_2336_flag ? (buf + 12 + 4) : buf,
|
||||
blocksize, 1);
|
||||
|
||||
@@ -547,7 +616,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn, bool form2)
|
||||
if (form2)
|
||||
memcpy (data, buf + 12 + 4, M2RAW_SECTOR_SIZE);
|
||||
else
|
||||
memcpy (data, buf + 12 + 4 + 8, M2F1_SECTOR_SIZE);
|
||||
memcpy (data, buf + 12 + 4 + 8, FORM1_DATA_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -576,8 +645,8 @@ _read_mode2_sectors (void *user_data, void *data, uint32_t lsn,
|
||||
if ( (retval = _read_mode2_sector (_obj, buf, lsn + i, true)) )
|
||||
return retval;
|
||||
|
||||
memcpy (((char *)data) + (M2F1_SECTOR_SIZE * i), buf + 8,
|
||||
M2F1_SECTOR_SIZE);
|
||||
memcpy (((char *)data) + (FORM1_DATA_SIZE * i), buf + 8,
|
||||
FORM1_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -700,6 +769,8 @@ _cdio_get_track_green(void *user_data, track_t track_num)
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for the track number
|
||||
track_num in obj. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
*/
|
||||
static bool
|
||||
_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
|
||||
@@ -732,8 +803,10 @@ cdio_open_nrg (const char *source_name)
|
||||
.get_num_tracks = _cdio_get_num_tracks,
|
||||
.get_track_format = _cdio_get_track_format,
|
||||
.get_track_green = _cdio_get_track_green,
|
||||
.get_track_lba = NULL, /* This could be implemented if need be. */
|
||||
.get_track_lba = NULL, /* Will use generic routine via msf */
|
||||
.get_track_msf = _cdio_get_track_msf,
|
||||
.lseek = _cdio_lseek,
|
||||
.read = _cdio_read,
|
||||
.read_mode2_sector = _read_mode2_sector,
|
||||
.read_mode2_sectors = _read_mode2_sectors,
|
||||
.set_arg = _cdio_set_arg,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: _cdio_stdio.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: _cdio_stdio.c,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "_cdio_stream.h"
|
||||
#include "_cdio_stdio.h"
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.2 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
#define CDIO_STDIO_BUFSIZE (128*1024)
|
||||
|
||||
@@ -91,11 +91,11 @@ _stdio_free(void *user_data)
|
||||
}
|
||||
|
||||
static long
|
||||
_stdio_seek(void *user_data, long offset)
|
||||
_stdio_seek(void *user_data, long offset, int whence)
|
||||
{
|
||||
_UserData *const ud = user_data;
|
||||
|
||||
if (fseek (ud->fd, offset, SEEK_SET))
|
||||
if (fseek (ud->fd, offset, whence))
|
||||
cdio_error ("fseek (): %s", strerror (errno));
|
||||
|
||||
return offset;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: _cdio_stream.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: _cdio_stream.c,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "util.h"
|
||||
#include "_cdio_stream.h"
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.2 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
/*
|
||||
* DataSource implementations
|
||||
@@ -66,7 +66,7 @@ _cdio_stream_open_if_necessary(CdioDataSource *obj)
|
||||
}
|
||||
|
||||
long
|
||||
cdio_stream_seek(CdioDataSource* obj, long offset)
|
||||
cdio_stream_seek(CdioDataSource* obj, long offset, int whence)
|
||||
{
|
||||
cdio_assert (obj != NULL);
|
||||
|
||||
@@ -77,7 +77,7 @@ cdio_stream_seek(CdioDataSource* obj, long offset)
|
||||
cdio_warn("had to reposition DataSource from %ld to %ld!", obj->position, offset);
|
||||
#endif
|
||||
obj->position = offset;
|
||||
return obj->op.seek(obj->user_data, offset);
|
||||
return obj->op.seek(obj->user_data, offset, whence);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: _cdio_stream.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: _cdio_stream.h,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
@@ -35,7 +35,7 @@ typedef int(*cdio_data_open_t)(void *user_data);
|
||||
|
||||
typedef long(*cdio_data_read_t)(void *user_data, void *buf, long count);
|
||||
|
||||
typedef long(*cdio_data_seek_t)(void *user_data, long offset);
|
||||
typedef long(*cdio_data_seek_t)(void *user_data, long offset, int whence);
|
||||
|
||||
typedef long(*cdio_data_stat_t)(void *user_data);
|
||||
|
||||
@@ -64,7 +64,7 @@ long
|
||||
cdio_stream_read(CdioDataSource* obj, void *ptr, long size, long nmemb);
|
||||
|
||||
long
|
||||
cdio_stream_seek(CdioDataSource* obj, long offset);
|
||||
cdio_stream_seek(CdioDataSource* obj, long offset, int whence);
|
||||
|
||||
long
|
||||
cdio_stream_stat(CdioDataSource* obj);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: _cdio_sunos.c,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: _cdio_sunos.c,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#ifdef HAVE_SOLARIS_CDROM
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_sunos.c,v 1.1 2003/03/24 19:01:09 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: _cdio_sunos.c,v 1.2 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -62,9 +62,9 @@ static const char _rcsid[] = "$Id: _cdio_sunos.c,v 1.1 2003/03/24 19:01:09 rocky
|
||||
/* reader */
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
|
||||
int ioctls_debugged; /* for debugging */
|
||||
/* Things common to all drivers like this.
|
||||
This must be first. */
|
||||
generic_img_private_t gen;
|
||||
|
||||
enum {
|
||||
_AM_NONE,
|
||||
@@ -76,9 +76,8 @@ typedef struct {
|
||||
#endif
|
||||
} access_mode;
|
||||
|
||||
char *source_name;
|
||||
|
||||
bool init;
|
||||
int ioctls_debugged; /* for debugging */
|
||||
|
||||
/* Track information */
|
||||
bool toc_init; /* if true, info below is valid. */
|
||||
@@ -96,9 +95,9 @@ _cdio_init (_img_private_t *_obj)
|
||||
|
||||
struct dk_cinfo cinfo;
|
||||
|
||||
_obj->fd = open (_obj->source_name, O_RDONLY, 0);
|
||||
_obj->gen.fd = open (_obj->source_name, O_RDONLY, 0);
|
||||
|
||||
if (_obj->fd < 0)
|
||||
if (_obj->gen.fd < 0)
|
||||
{
|
||||
cdio_error ("open (%s): %s", _obj->source_name, strerror (errno));
|
||||
return false;
|
||||
@@ -109,7 +108,7 @@ _cdio_init (_img_private_t *_obj)
|
||||
* Try to send MMC3 SCSI commands via the uscsi interface on
|
||||
* ATAPI devices.
|
||||
*/
|
||||
if ( ioctl(_obj->fd, DKIOCINFO, &cinfo) == 0
|
||||
if ( ioctl(_obj->gen.fd, DKIOCINFO, &cinfo) == 0
|
||||
&& ((strcmp(cinfo.dki_cname, "ide") == 0)
|
||||
|| (strncmp(cinfo.dki_cname, "pci", 3) == 0)) ) {
|
||||
_obj->access_mode = _AM_SUN_CTRL_ATAPI;
|
||||
@@ -117,30 +116,12 @@ _cdio_init (_img_private_t *_obj)
|
||||
_obj->access_mode = _AM_SUN_CTRL_SCSI;
|
||||
}
|
||||
|
||||
_obj->init = true;
|
||||
_obj->gen.init = true;
|
||||
_obj->toc_init = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Release and free resources associated with cd.
|
||||
*/
|
||||
static void
|
||||
_cdio_free (void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (NULL == _obj) return;
|
||||
free (_obj->source_name);
|
||||
|
||||
if (_obj->fd >= 0)
|
||||
close (_obj->fd);
|
||||
|
||||
free (_obj);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads a single mode2 sector from cd device into data starting from lsn.
|
||||
Returns 0 if no error.
|
||||
@@ -183,7 +164,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
break;
|
||||
|
||||
case _AM_SUN_CTRL_SCSI:
|
||||
if (ioctl (_obj->fd, CDROMREADMODE2, &buf) == -1) {
|
||||
if (ioctl (_obj->gen.fd, CDROMREADMODE2, &buf) == -1) {
|
||||
perror ("ioctl(..,CDROMREADMODE2,..)");
|
||||
return 1;
|
||||
/* exit (EXIT_FAILURE); */
|
||||
@@ -236,7 +217,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
sc.uscsi_buflen = M2RAW_SECTOR_SIZE;
|
||||
sc.uscsi_flags = USCSI_ISOLATE | USCSI_READ;
|
||||
sc.uscsi_timeout = 20;
|
||||
if (ioctl(_obj->fd, USCSICMD, &sc)) {
|
||||
if (ioctl(_obj->gen.fd, USCSICMD, &sc)) {
|
||||
perror("USCSICMD: READ CD");
|
||||
return 1;
|
||||
}
|
||||
@@ -252,7 +233,7 @@ _read_mode2_sector (void *user_data, void *data, lsn_t lsn,
|
||||
if (mode2_form2)
|
||||
memcpy (data, buf, M2RAW_SECTOR_SIZE);
|
||||
else
|
||||
memcpy (((char *)data), buf + 8, M2F1_SECTOR_SIZE);
|
||||
memcpy (((char *)data), buf + 8, FORM1_DATA_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -281,8 +262,8 @@ _read_mode2_sectors (void *user_data, void *data, uint32_t lsn,
|
||||
if ( (retval = _read_mode2_sector (_obj, buf, lsn + i, true)) )
|
||||
return retval;
|
||||
|
||||
memcpy (((char *)data) + (M2F1_SECTOR_SIZE * i), buf + 8,
|
||||
M2F1_SECTOR_SIZE);
|
||||
memcpy (((char *)data) + (FORM1_DATA_SIZE * i), buf + 8,
|
||||
FORM1_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -301,7 +282,7 @@ _cdio_stat_size (void *user_data)
|
||||
|
||||
tocent.cdte_track = CDROM_LEADOUT;
|
||||
tocent.cdte_format = CDROM_LBA;
|
||||
if (ioctl (_obj->fd, CDROMREADTOCENTRY, &tocent) == -1)
|
||||
if (ioctl (_obj->gen.fd, CDROMREADTOCENTRY, &tocent) == -1)
|
||||
{
|
||||
perror ("ioctl(CDROMREADTOCENTRY)");
|
||||
exit (EXIT_FAILURE);
|
||||
@@ -354,7 +335,7 @@ _cdio_read_toc (_img_private_t *_obj)
|
||||
int i;
|
||||
|
||||
/* read TOC header */
|
||||
if ( ioctl(_obj->fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) {
|
||||
if ( ioctl(_obj->gen.fd, CDROMREADTOCHDR, &_obj->tochdr) == -1 ) {
|
||||
cdio_error("%s: %s\n",
|
||||
"error in ioctl CDROMREADTOCHDR", strerror(errno));
|
||||
return false;
|
||||
@@ -364,7 +345,7 @@ _cdio_read_toc (_img_private_t *_obj)
|
||||
for (i=_obj->tochdr.cdth_trk0; i<=_obj->tochdr.cdth_trk1; i++) {
|
||||
_obj->tocent[i-1].cdte_track = i;
|
||||
_obj->tocent[i-1].cdte_format = CDROM_MSF;
|
||||
if ( ioctl(_obj->fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) {
|
||||
if ( ioctl(_obj->gen.fd, CDROMREADTOCENTRY, &_obj->tocent[i-1]) == -1 ) {
|
||||
cdio_error("%s %d: %s\n",
|
||||
"error in ioctl CDROMREADTOCENTRY for track",
|
||||
i, strerror(errno));
|
||||
@@ -376,7 +357,7 @@ _cdio_read_toc (_img_private_t *_obj)
|
||||
_obj->tocent[_obj->tochdr.cdth_trk1].cdte_track = CDROM_LEADOUT;
|
||||
_obj->tocent[_obj->tochdr.cdth_trk1].cdte_format = CDROM_MSF;
|
||||
|
||||
if (ioctl(_obj->fd, CDROMREADTOCENTRY,
|
||||
if (ioctl(_obj->gen.fd, CDROMREADTOCENTRY,
|
||||
&_obj->tocent[_obj->tochdr.cdth_trk1]) == -1 ) {
|
||||
cdio_error("%s: %s\n",
|
||||
"error in ioctl CDROMREADTOCENTRY for lead-out",
|
||||
@@ -397,13 +378,13 @@ _cdio_eject_media (void *user_data) {
|
||||
_img_private_t *_obj = user_data;
|
||||
int ret;
|
||||
|
||||
if (_obj->fd > -1) {
|
||||
if ((ret = ioctl(_obj->fd, CDROMEJECT)) != 0) {
|
||||
_cdio_free((void *) _obj);
|
||||
if (_obj->gen.fd > -1) {
|
||||
if ((ret = ioctl(_obj->gen.fd, CDROMEJECT)) != 0) {
|
||||
cdio_generic_free((void *) _obj);
|
||||
cdio_error ("CDROMEJECT failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
} else {
|
||||
_cdio_free((void *) _obj);
|
||||
cdio_generic_free((void *) _obj);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -515,7 +496,7 @@ _cdio_get_track_format(void *user_data, track_t track_num)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!_obj->init) _cdio_init(_obj);
|
||||
if (!_obj->gen.init) _cdio_init(_obj);
|
||||
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
|
||||
|
||||
if (track_num > TOTAL_TRACKS || track_num == 0)
|
||||
@@ -549,7 +530,7 @@ _cdio_get_track_green(void *user_data, track_t track_num)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!_obj->init) _cdio_init(_obj);
|
||||
if (!_obj->gen.init) _cdio_init(_obj);
|
||||
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
|
||||
|
||||
if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1;
|
||||
@@ -568,7 +549,7 @@ _cdio_get_track_green(void *user_data, track_t track_num)
|
||||
track_num in obj. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
NULL is returned if there is no entry.
|
||||
False is returned if there is no entry.
|
||||
*/
|
||||
static bool
|
||||
_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
|
||||
@@ -577,7 +558,7 @@ _cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf)
|
||||
|
||||
if (NULL == msf) return false;
|
||||
|
||||
if (!_obj->init) _cdio_init(_obj);
|
||||
if (!_obj->gen.init) _cdio_init(_obj);
|
||||
if (!_obj->toc_init) _cdio_read_toc (_obj) ;
|
||||
|
||||
if (track_num == CDIO_LEADOUT_TRACK) track_num = TOTAL_TRACKS+1;
|
||||
@@ -610,14 +591,17 @@ cdio_open_solaris (const char *source_name)
|
||||
|
||||
cdio_funcs _funcs = {
|
||||
.eject_media = _cdio_eject_media,
|
||||
.free = _cdio_free,
|
||||
.free = cdio_generic_free,
|
||||
.get_arg = _cdio_get_arg,
|
||||
.get_default_device = _cdio_get_default_device,
|
||||
.get_first_track_num= _cdio_get_first_track_num,
|
||||
.get_num_tracks = _cdio_get_num_tracks,
|
||||
.get_track_format = _cdio_get_track_format,
|
||||
.get_track_green = _cdio_get_track_green,
|
||||
.get_track_lba = NULL, /* This could be implemented if need be. */
|
||||
.get_track_msf = _cdio_get_track_msf,
|
||||
.lseek = cdio_generic_lseek,
|
||||
.read = cdio_generic_read,
|
||||
.read_mode2_sector = _read_mode2_sector,
|
||||
.read_mode2_sectors = _read_mode2_sectors,
|
||||
.stat_size = _cdio_stat_size,
|
||||
@@ -636,7 +620,7 @@ cdio_open_solaris (const char *source_name)
|
||||
if (_cdio_init(_data))
|
||||
return ret;
|
||||
else {
|
||||
_cdio_free (_data);
|
||||
cdio_generic_free (_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
102
lib/cdio.c
102
lib/cdio.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: cdio.c,v 1.2 2003/03/24 23:59:22 rocky Exp $
|
||||
$Id: cdio.c,v 1.3 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "logging.h"
|
||||
#include "cdio_private.h"
|
||||
|
||||
static const char _rcsid[] = "$Id: cdio.c,v 1.2 2003/03/24 23:59:22 rocky Exp $";
|
||||
static const char _rcsid[] = "$Id: cdio.c,v 1.3 2003/03/29 17:32:00 rocky Exp $";
|
||||
|
||||
|
||||
const char *track_format2str[5] =
|
||||
@@ -41,11 +41,6 @@ const char *track_format2str[5] =
|
||||
|
||||
CdIo_driver_t CdIo_driver[MAX_DRIVER] = { {0} };
|
||||
|
||||
struct _CdIo {
|
||||
void *user_data;
|
||||
cdio_funcs op;
|
||||
};
|
||||
|
||||
/* The last valid entry of Cdio_driver. -1 means uninitialzed. -2
|
||||
means some sort of error.
|
||||
*/
|
||||
@@ -189,7 +184,7 @@ cdio_get_first_track_num (const CdIo *obj)
|
||||
track_t
|
||||
cdio_get_num_tracks (const CdIo *obj)
|
||||
{
|
||||
cdio_assert (obj != NULL);
|
||||
if (obj == NULL) return CDIO_INVALID_TRACK;
|
||||
|
||||
if (obj->op.get_num_tracks) {
|
||||
return obj->op.get_num_tracks (obj->user_data);
|
||||
@@ -233,6 +228,28 @@ cdio_get_track_green(const CdIo *obj, track_t track_num)
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting LBA for track number
|
||||
track_num in obj. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
CDIO_INVALID_LBA is returned on error.
|
||||
*/
|
||||
lba_t
|
||||
cdio_get_track_lba(const CdIo *obj, track_t track_num)
|
||||
{
|
||||
if (obj == NULL) return CDIO_INVALID_LBA;
|
||||
|
||||
if (obj->op.get_track_lba) {
|
||||
return obj->op.get_track_lba (obj->user_data, track_num);
|
||||
} else {
|
||||
msf_t msf;
|
||||
if (cdio_get_track_msf(obj, track_num, &msf))
|
||||
return cdio_msf_to_lba(&msf);
|
||||
return CDIO_INVALID_LBA;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for track number
|
||||
track_num in obj. Track numbers start at 1.
|
||||
@@ -241,7 +258,7 @@ cdio_get_track_green(const CdIo *obj, track_t track_num)
|
||||
False is returned if there is no track entry.
|
||||
*/
|
||||
bool
|
||||
cdio_get_track_msf(const CdIo *obj, track_t track_num, msf_t *msf)
|
||||
cdio_get_track_msf(const CdIo *obj, track_t track_num, /*out*/ msf_t *msf)
|
||||
{
|
||||
cdio_assert (obj != NULL);
|
||||
|
||||
@@ -252,6 +269,23 @@ cdio_get_track_msf(const CdIo *obj, track_t track_num, msf_t *msf)
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the number of sectors between this track an the next. This
|
||||
includes any pregap sectors before the start of the next track.
|
||||
Tracks start at 1.
|
||||
0 is returned if there is an error.
|
||||
*/
|
||||
unsigned int
|
||||
cdio_get_track_sec_count(const CdIo *obj, track_t track_num)
|
||||
{
|
||||
track_t num_tracks = cdio_get_num_tracks(obj);
|
||||
|
||||
if (track_num >=1 && track_num <= num_tracks)
|
||||
return ( cdio_get_track_lba(obj, track_num+1)
|
||||
- cdio_get_track_lba(obj, track_num) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
cdio_have_driver(driver_id_t driver_id)
|
||||
{
|
||||
@@ -300,6 +334,9 @@ cdio_new (void *user_data, const cdio_funcs *funcs)
|
||||
return new_obj;
|
||||
}
|
||||
|
||||
/*!
|
||||
Free any resources associated with obj.
|
||||
*/
|
||||
void
|
||||
cdio_destroy (CdIo *obj)
|
||||
{
|
||||
@@ -309,31 +346,46 @@ cdio_destroy (CdIo *obj)
|
||||
free (obj);
|
||||
}
|
||||
|
||||
/*!
|
||||
lseek - reposition read/write file offset
|
||||
Returns (off_t) -1 on error.
|
||||
Similar to (if not the same as) libc's lseek()
|
||||
*/
|
||||
off_t
|
||||
cdio_lseek (CdIo *obj, off_t offset, int whence)
|
||||
{
|
||||
if (obj == NULL) return -1;
|
||||
|
||||
if (obj->op.lseek)
|
||||
return obj->op.lseek (obj->user_data, offset, whence);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Similar to (if not the same as) libc's read()
|
||||
*/
|
||||
ssize_t
|
||||
cdio_read (CdIo *obj, void *buf, size_t size)
|
||||
{
|
||||
if (obj == NULL) return -1;
|
||||
|
||||
if (obj->op.read)
|
||||
return obj->op.read (obj->user_data, buf, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
cdio_read_mode2_sectors (CdIo *obj, void *buf, lsn_t lsn, bool mode2raw,
|
||||
unsigned num_sectors)
|
||||
{
|
||||
char *_buf = buf;
|
||||
const int blocksize = mode2raw ? M2RAW_SECTOR_SIZE : M2F1_SECTOR_SIZE;
|
||||
int n, rc;
|
||||
|
||||
cdio_assert (obj != NULL);
|
||||
cdio_assert (buf != NULL);
|
||||
cdio_assert (obj->op.read_mode2_sector != NULL
|
||||
|| obj->op.read_mode2_sectors != NULL);
|
||||
cdio_assert (obj->op.read_mode2_sectors != NULL);
|
||||
|
||||
if (obj->op.read_mode2_sectors)
|
||||
return obj->op.read_mode2_sectors (obj->user_data, buf, lsn,
|
||||
mode2raw, num_sectors);
|
||||
|
||||
/* fallback */
|
||||
if (obj->op.read_mode2_sector != NULL)
|
||||
for (n = 0; n < num_sectors; n++)
|
||||
if ((rc = cdio_read_mode2_sector (obj, &_buf[n * blocksize],
|
||||
lsn + n, mode2raw)))
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
46
lib/cdio.h
46
lib/cdio.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: cdio.h,v 1.2 2003/03/24 23:59:22 rocky Exp $
|
||||
$Id: cdio.h,v 1.3 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
@@ -25,6 +25,13 @@
|
||||
#ifndef __CDIO_H__
|
||||
#define __CDIO_H__
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "cdio_types.h"
|
||||
#include "sector.h"
|
||||
|
||||
@@ -79,6 +86,9 @@ extern "C" {
|
||||
*/
|
||||
int cdio_eject_media (const CdIo *obj);
|
||||
|
||||
/*!
|
||||
Free any resources associated with obj.
|
||||
*/
|
||||
void cdio_destroy (CdIo *obj);
|
||||
|
||||
/*!
|
||||
@@ -117,6 +127,15 @@ extern "C" {
|
||||
*/
|
||||
bool cdio_get_track_green(const CdIo *obj, track_t track_num);
|
||||
|
||||
/*!
|
||||
Return the starting LBA for track number
|
||||
track_num in obj. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
CDIO_INVALID_LBA is returned on error.
|
||||
*/
|
||||
lba_t cdio_get_track_lba(const CdIo *obj, track_t track_num);
|
||||
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for track number
|
||||
track_num in obj. Track numbers start at 1.
|
||||
@@ -124,7 +143,30 @@ extern "C" {
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
False is returned if there is no track entry.
|
||||
*/
|
||||
bool cdio_get_track_msf(const CdIo *obj, track_t track_num, msf_t *msf);
|
||||
bool cdio_get_track_msf(const CdIo *obj, track_t track_num,
|
||||
/*out*/ msf_t *msf);
|
||||
|
||||
/*!
|
||||
Return the number of sectors between this track an the next. This
|
||||
includes any pregap sectors before the start of the next track.
|
||||
Tracks start at 1.
|
||||
0 is returned if there is an error.
|
||||
*/
|
||||
unsigned int cdio_get_track_sec_count(const CdIo *obj, track_t track_num);
|
||||
|
||||
/*!
|
||||
lseek - reposition read/write file offset
|
||||
Returns (off_t) -1 on error.
|
||||
Similar to (if not the same as) libc's lseek()
|
||||
*/
|
||||
off_t cdio_lseek(CdIo *obj, off_t offset, int whence);
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Similar to (if not the same as) libc's read()
|
||||
*/
|
||||
ssize_t cdio_read(CdIo *obj, void *buf, size_t size);
|
||||
|
||||
/*!
|
||||
Reads a single mode2 sector from cd device into data starting
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: cdio_private.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: cdio_private.h,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
#ifndef __CDIO_PRIVATE_H__
|
||||
#define __CDIO_PRIVATE_H__
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <cdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -66,13 +73,13 @@ extern "C" {
|
||||
track_t (*get_num_tracks) (void *user_data);
|
||||
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for track number
|
||||
Return the starting LBA for track number
|
||||
track_num in obj. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
1 is returned on error.
|
||||
CDIO_INVALID_LBA is returned on error.
|
||||
*/
|
||||
uint32_t (*get_track_lba) (void *user_data, track_t track_num);
|
||||
lba_t (*get_track_lba) (void *user_data, track_t track_num);
|
||||
|
||||
/*!
|
||||
Get format of track.
|
||||
@@ -94,12 +101,26 @@ extern "C" {
|
||||
track_num in obj. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using track_num LEADOUT_TRACK or the total tracks+1.
|
||||
1 is returned on error.
|
||||
False is returned on error.
|
||||
*/
|
||||
bool (*get_track_msf) (void *user_data, track_t track_num, msf_t *msf);
|
||||
|
||||
/*!
|
||||
Reads a single mode2 sector from cd device into data starting
|
||||
lseek - reposition read/write file offset
|
||||
Returns (off_t) -1 on error.
|
||||
Similar to libc's lseek()
|
||||
*/
|
||||
off_t (*lseek) (void *user_data, off_t offset, int whence);
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Similar to libc's read()
|
||||
*/
|
||||
ssize_t (*read) (void *user_data, void *buf, size_t size);
|
||||
|
||||
/*!
|
||||
Reads a single mode2 sector from cd device into buf starting
|
||||
from lsn. Returns 0 if no error.
|
||||
*/
|
||||
int (*read_mode2_sector) (void *user_data, void *buf, lsn_t lsn,
|
||||
@@ -125,6 +146,14 @@ extern "C" {
|
||||
|
||||
} cdio_funcs;
|
||||
|
||||
|
||||
/* Things that just about all private device structures have. */
|
||||
typedef struct {
|
||||
char *source_name; /* Name used in open. */
|
||||
bool init; /* True if structure has been initialized */
|
||||
int fd; /* File descriptor of device */
|
||||
} generic_img_private_t;
|
||||
|
||||
CdIo * cdio_new (void *user_data, const cdio_funcs *funcs);
|
||||
|
||||
/* The below structure describes a specific CD Input driver */
|
||||
@@ -151,6 +180,39 @@ extern "C" {
|
||||
on a particular host. */
|
||||
extern CdIo_driver_t CdIo_all_drivers[MAX_DRIVER+1];
|
||||
|
||||
/*!
|
||||
Release and free resources associated with cd.
|
||||
*/
|
||||
void cdio_generic_free (void *user_data);
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Is in fact libc's read().
|
||||
*/
|
||||
off_t cdio_generic_lseek (void *user_data, off_t offset, int whence);
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Is in fact libc's read().
|
||||
*/
|
||||
ssize_t cdio_generic_read (void *user_data, void *buf, size_t size);
|
||||
|
||||
/*!
|
||||
Reads nblocks of mode2 sectors from cd device into data starting
|
||||
from lsn.
|
||||
Returns 0 if no error.
|
||||
*/
|
||||
int cdio_generic_read_mode2_sectors (CdIo *obj, void *buf, lsn_t lsn,
|
||||
bool mode2raw, unsigned num_sectors);
|
||||
|
||||
struct _CdIo {
|
||||
void *user_data;
|
||||
cdio_funcs op;
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: cdio_types.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: cdio_types.h,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2002,2003 Rocky Bernstein <rocky@panix.com>
|
||||
@@ -201,6 +201,11 @@ typedef uint8_t track_t;
|
||||
*/
|
||||
#define CDIO_INVALID_TRACK 0xFF
|
||||
|
||||
/*!
|
||||
Constant for invalid LBA
|
||||
*/
|
||||
#define CDIO_INVALID_LBA 0xFFFFFFFF
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: sector.h,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
$Id: sector.h,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
@@ -44,7 +44,7 @@
|
||||
* format sector type user data size (bytes)
|
||||
* -----------------------------------------------------------------------------
|
||||
* 1 (Red Book) CD-DA 2352 (CDDA_SECTOR_SIZE)
|
||||
* 2 (Yellow Book) Mode1 Form1 2048 (M2F1_SECTOR_SIZE)
|
||||
* 2 (Yellow Book) Mode1 Form1 2048 (M1F1_SECTOR_SIZE)
|
||||
* 3 (Yellow Book) Mode1 Form2 2336 (M2RAW_SECTOR_SIZE)
|
||||
* 4 (Green Book) Mode2 Form1 2048 (M2F1_SECTOR_SIZE)
|
||||
* 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes)
|
||||
@@ -71,7 +71,9 @@
|
||||
|
||||
#define CD_RAW_SECTOR_SIZE 2352
|
||||
#define CDDA_SECTOR_SIZE CD_RAW_SECTOR_SIZE
|
||||
#define M1F1_SECTOR_SIZE 2048
|
||||
#define M2F1_SECTOR_SIZE 2048
|
||||
#define FORM1_DATA_SIZE 2048 /* Mode 1 or Mode 2 user data */
|
||||
#define M2F2_SECTOR_SIZE 2324
|
||||
#define M2SUB_SECTOR_SIZE 2332
|
||||
#define M2RAW_SECTOR_SIZE 2336
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# $Id: Makefile.am,v 1.1 2003/03/24 19:01:09 rocky Exp $
|
||||
# $Id: Makefile.am,v 1.2 2003/03/29 17:32:00 rocky Exp $
|
||||
#
|
||||
# Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
#
|
||||
@@ -25,8 +25,14 @@ cdinfo_linux_SOURCES = cdinfo-linux.c
|
||||
cdinfo_linux_LDADD = $(LIBCDIO_LIBS) -lpopt
|
||||
else
|
||||
EXTRA_DIST = cdinfo-linux.c
|
||||
if BUILD_CDIOTEST
|
||||
bin_PROGRAMS = cdinfo cdiotest
|
||||
cdiotest_SOURCES = cdiotest.c
|
||||
cdiotest_LDADD = $(LIBCDIO_LIBS)
|
||||
else
|
||||
bin_PROGRAMS = cdinfo
|
||||
endif
|
||||
endif
|
||||
|
||||
INCLUDES = -I$(top_srcdir) $(LIBCDIO_CFLAGS)
|
||||
|
||||
|
||||
40
src/cdinfo.c
40
src/cdinfo.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
$Id: cdinfo.c,v 1.3 2003/03/25 02:10:41 rocky Exp $
|
||||
$Id: cdinfo.c,v 1.4 2003/03/29 17:32:00 rocky Exp $
|
||||
|
||||
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
|
||||
Copyright (C) 1996,1997,1998 Gerd Knorr <kraxel@bytesex.org>
|
||||
@@ -408,13 +408,24 @@ PARTICULAR PURPOSE.\n\
|
||||
/* some ISO 9660 fiddling */
|
||||
|
||||
static int
|
||||
read_block(int superblock, uint32_t offset, uint8_t bufnum, bool is_green)
|
||||
read_block(int superblock, uint32_t offset, uint8_t bufnum, track_t track_num)
|
||||
{
|
||||
unsigned int track_sec_count = cdio_get_track_sec_count(img, track_num);
|
||||
memset(buffer[bufnum],0,M2F1_SECTOR_SIZE);
|
||||
|
||||
if ( track_sec_count < superblock) {
|
||||
dbg_print(1, "reading block %u skipped track %d has only %u sectors\n",
|
||||
superblock, track_num, track_sec_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbg_print(2, "about to read sector %u\n", offset+superblock);
|
||||
if (cdio_read_mode2_sector(img, buffer[bufnum],
|
||||
offset+superblock, !is_green))
|
||||
|
||||
if (0 > cdio_lseek(img, FORM1_DATA_SIZE*(offset+superblock),SEEK_SET))
|
||||
return -1;
|
||||
|
||||
|
||||
if (0 > cdio_read(img, buffer[bufnum], FORM1_DATA_SIZE))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@@ -479,11 +490,11 @@ get_joliet_level( void )
|
||||
if (is_it(sig)) printf("%s, ", sigs[sig].description)
|
||||
|
||||
static int
|
||||
guess_filesystem(int start_session, bool is_green)
|
||||
guess_filesystem(int start_session, track_t track_num)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (read_block(ISO_SUPERBLOCK_SECTOR, start_session, 0, is_green) < 0)
|
||||
if (read_block(ISO_SUPERBLOCK_SECTOR, start_session, 0, track_num) < 0)
|
||||
return FS_UNKNOWN;
|
||||
|
||||
if (opts.debug_level > 0) {
|
||||
@@ -504,7 +515,7 @@ guess_filesystem(int start_session, bool is_green)
|
||||
return FS_INTERACTIVE;
|
||||
} else { /* read sector 0 ONLY, when NO greenbook CD-I !!!! */
|
||||
|
||||
if (read_block(0, start_session, 1, true) < 0)
|
||||
if (read_block(0, start_session, 1, track_num) < 0)
|
||||
return ret;
|
||||
|
||||
if (opts.debug_level > 0) {
|
||||
@@ -532,7 +543,7 @@ guess_filesystem(int start_session, bool is_green)
|
||||
ret |= ROCKRIDGE;
|
||||
#endif
|
||||
|
||||
if (read_block(BOOT_SECTOR, start_session, 3, true) < 0)
|
||||
if (read_block(BOOT_SECTOR, start_session, 3, track_num) < 0)
|
||||
return ret;
|
||||
|
||||
if (opts.debug_level > 0) {
|
||||
@@ -555,7 +566,7 @@ guess_filesystem(int start_session, bool is_green)
|
||||
&& is_it(IS_CD_RTOS) &&
|
||||
!is_it(IS_PHOTO_CD)) {
|
||||
|
||||
if (read_block(VCD_INFO_SECTOR, start_session, 4, true) < 0)
|
||||
if (read_block(VCD_INFO_SECTOR, start_session, 4, track_num) < 0)
|
||||
return ret;
|
||||
|
||||
if (opts.debug_level > 0) {
|
||||
@@ -571,8 +582,7 @@ guess_filesystem(int start_session, bool is_green)
|
||||
else if (is_it(IS_EXT2)) ret |= FS_EXT2;
|
||||
else if (is_3do()) ret |= FS_3DO;
|
||||
else {
|
||||
|
||||
if (read_block(UFS_SUPERBLOCK_SECTOR, start_session, 2, true) < 0)
|
||||
if (read_block(UFS_SUPERBLOCK_SECTOR, start_session, 2, track_num) < 0)
|
||||
return ret;
|
||||
|
||||
if (opts.debug_level > 0) {
|
||||
@@ -933,12 +943,14 @@ main(int argc, const char *argv[])
|
||||
|
||||
/* CD-I/Ready says start_track <= 30*75 then CDDA */
|
||||
if (start_track > 100 /* 100 is just a guess */) {
|
||||
fs = guess_filesystem(0, false);
|
||||
fs = guess_filesystem(0, 1);
|
||||
if ((fs & FS_MASK) != FS_UNKNOWN)
|
||||
fs |= HIDDEN_TRACK;
|
||||
else {
|
||||
fs &= ~FS_MASK; /* del filesystem info */
|
||||
printf("Oops: %i unused sectors at start, but hidden track check failed.\n",start_track);
|
||||
printf("Oops: %i unused sectors at start, "
|
||||
"but hidden track check failed.\n",
|
||||
start_track);
|
||||
}
|
||||
}
|
||||
print_analysis(fs, num_audio);
|
||||
@@ -971,7 +983,7 @@ main(int argc, const char *argv[])
|
||||
if (start_track < data_start + isofs_size)
|
||||
continue;
|
||||
|
||||
fs = guess_filesystem(start_track, cdio_get_track_green(img, i));
|
||||
fs = guess_filesystem(start_track, i);
|
||||
|
||||
if (i > 1) {
|
||||
/* track is beyond last session -> new session found */
|
||||
|
||||
@@ -14,4 +14,4 @@ CD-ROM with CD-RTOS and ISO 9660 filesystem
|
||||
ISO 9660: 1101 blocks, label `MONVOISIN '
|
||||
XA sectors Video CD
|
||||
session #2 starts at track 2, LSN: 1251, ISO 9660 blocks: 1101
|
||||
ISO 9660: 1101 blocks, label `'
|
||||
ISO 9660: 1101 blocks, label `<EFBFBD><EFBFBD>)*<2A>c]<5D>d<1C><>q^\MvKM<4B><4D>b<EFBFBD><18><>Ǎ<10>%<25>'
|
||||
|
||||
Reference in New Issue
Block a user