nkeynes@1097 | 1 | /**
|
nkeynes@1097 | 2 | * $Id$
|
nkeynes@1097 | 3 | *
|
nkeynes@1097 | 4 | * Copyright (c) 2009 Nathan Keynes.
|
nkeynes@1097 | 5 | *
|
nkeynes@1097 | 6 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@1097 | 7 | * it under the terms of the GNU General Public License as published by
|
nkeynes@1097 | 8 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@1097 | 9 | * (at your option) any later version.
|
nkeynes@1097 | 10 | *
|
nkeynes@1097 | 11 | * This program is distributed in the hope that it will be useful,
|
nkeynes@1097 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@1097 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@1097 | 14 | * GNU General Public License for more details.
|
nkeynes@1097 | 15 | */
|
nkeynes@1097 | 16 |
|
nkeynes@1097 | 17 | #include <assert.h>
|
nkeynes@1097 | 18 | #include <errno.h>
|
nkeynes@1097 | 19 | #include <fcntl.h>
|
nkeynes@1097 | 20 | #include <stdio.h>
|
nkeynes@1097 | 21 | #include <string.h>
|
nkeynes@1296 | 22 | #include <glib.h>
|
nkeynes@1097 | 23 | #include "lxdream.h"
|
nkeynes@1097 | 24 | #include "drivers/cdrom/cdrom.h"
|
nkeynes@1097 | 25 | #include "drivers/cdrom/cdimpl.h"
|
nkeynes@1108 | 26 | #include "drivers/cdrom/isofs.h"
|
nkeynes@1097 | 27 |
|
nkeynes@1097 | 28 | extern struct cdrom_disc_factory linux_cdrom_drive_factory;
|
nkeynes@1097 | 29 | extern struct cdrom_disc_factory nrg_disc_factory;
|
nkeynes@1097 | 30 | extern struct cdrom_disc_factory cdi_disc_factory;
|
nkeynes@1097 | 31 | extern struct cdrom_disc_factory gdi_disc_factory;
|
nkeynes@1097 | 32 |
|
nkeynes@1097 | 33 | cdrom_disc_factory_t cdrom_disc_factories[] = {
|
nkeynes@1097 | 34 | #ifdef HAVE_LINUX_CDROM
|
nkeynes@1097 | 35 | &linux_cdrom_drive_factory,
|
nkeynes@1097 | 36 | #endif
|
nkeynes@1097 | 37 | &nrg_disc_factory,
|
nkeynes@1097 | 38 | &cdi_disc_factory,
|
nkeynes@1097 | 39 | &gdi_disc_factory,
|
nkeynes@1097 | 40 | NULL };
|
nkeynes@1097 | 41 |
|
nkeynes@1097 | 42 | /********************* Implementation Support functions ************************/
|
nkeynes@1097 | 43 |
|
nkeynes@1097 | 44 | cdrom_error_t default_image_read_blocks( sector_source_t source, cdrom_lba_t lba, cdrom_count_t count,
|
nkeynes@1097 | 45 | unsigned char *buf )
|
nkeynes@1097 | 46 | {
|
nkeynes@1097 | 47 | assert( 0 && "read_blocks called on a cdrom disc" );
|
nkeynes@1097 | 48 | return CDROM_ERROR_BADREAD;
|
nkeynes@1097 | 49 | }
|
nkeynes@1097 | 50 |
|
nkeynes@1097 | 51 | cdrom_error_t default_image_read_sectors( sector_source_t source, cdrom_lba_t lba, cdrom_count_t count,
|
nkeynes@1097 | 52 | cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
|
nkeynes@1097 | 53 | {
|
nkeynes@1097 | 54 | assert( IS_SECTOR_SOURCE_TYPE(source,DISC_SECTOR_SOURCE) );
|
nkeynes@1097 | 55 | cdrom_disc_t disc = (cdrom_disc_t)source;
|
nkeynes@1097 | 56 | size_t len = 0, tmplen;
|
nkeynes@1097 | 57 | cdrom_count_t current = 0;
|
nkeynes@1097 | 58 |
|
nkeynes@1097 | 59 | while( current < count ) {
|
nkeynes@1097 | 60 | cdrom_track_t track = cdrom_disc_get_track_by_lba( disc, lba + current );
|
nkeynes@1097 | 61 | if( track == NULL )
|
nkeynes@1097 | 62 | return CDROM_ERROR_BADREAD;
|
nkeynes@1097 | 63 | uint32_t track_size = cdrom_disc_get_track_size( disc, track );
|
nkeynes@1097 | 64 | cdrom_lba_t track_offset = lba + current - track->lba;
|
nkeynes@1097 | 65 | cdrom_count_t sub_count = count - current;
|
nkeynes@1097 | 66 | if( track_size - track_offset < sub_count )
|
nkeynes@1097 | 67 | /* Read breaks across track boundaries. This will probably fail (due
|
nkeynes@1097 | 68 | * to inter-track gaps), but try it just in case
|
nkeynes@1097 | 69 | */
|
nkeynes@1097 | 70 | sub_count = track_size - track_offset;
|
nkeynes@1097 | 71 | cdrom_error_t err = track->source->read_sectors( track->source, track_offset, sub_count, mode, &buf[len], &tmplen );
|
nkeynes@1097 | 72 | if( err != CDROM_ERROR_OK )
|
nkeynes@1097 | 73 | return err;
|
nkeynes@1097 | 74 | len += tmplen;
|
nkeynes@1097 | 75 | current += sub_count;
|
nkeynes@1097 | 76 | }
|
nkeynes@1099 | 77 | if( length != NULL )
|
nkeynes@1099 | 78 | *length = len;
|
nkeynes@1097 | 79 | return CDROM_ERROR_OK;
|
nkeynes@1097 | 80 | }
|
nkeynes@1097 | 81 |
|
nkeynes@1097 | 82 | void default_cdrom_disc_destroy( sector_source_t source )
|
nkeynes@1097 | 83 | {
|
nkeynes@1097 | 84 | assert( IS_SECTOR_SOURCE_TYPE(source,DISC_SECTOR_SOURCE) );
|
nkeynes@1097 | 85 | cdrom_disc_t disc = (cdrom_disc_t)source;
|
nkeynes@1097 | 86 | int i;
|
nkeynes@1097 | 87 |
|
nkeynes@1097 | 88 | for( i=0; i<disc->track_count; i++ ) {
|
nkeynes@1097 | 89 | sector_source_unref( disc->track[i].source );
|
nkeynes@1097 | 90 | }
|
nkeynes@1097 | 91 | sector_source_unref( disc->base_source );
|
nkeynes@1097 | 92 | g_free( (char *)disc->name );
|
nkeynes@1097 | 93 |
|
nkeynes@1097 | 94 | default_sector_source_destroy( source );
|
nkeynes@1097 | 95 | }
|
nkeynes@1097 | 96 |
|
nkeynes@1097 | 97 | cdrom_disc_t cdrom_disc_init( cdrom_disc_t disc, const char *filename )
|
nkeynes@1097 | 98 | {
|
nkeynes@1097 | 99 | sector_source_init( &disc->source, DISC_SECTOR_SOURCE, SECTOR_UNKNOWN, 0, default_image_read_blocks,
|
nkeynes@1097 | 100 | default_cdrom_disc_destroy );
|
nkeynes@1097 | 101 | disc->source.read_sectors = default_image_read_sectors;
|
nkeynes@1097 | 102 | disc->disc_type = CDROM_DISC_NONE;
|
nkeynes@1097 | 103 | disc->track_count = disc->session_count = 0;
|
nkeynes@1097 | 104 | for( int i=0; i<99; i++ ) {
|
nkeynes@1097 | 105 | disc->track[i].trackno = i+1;
|
nkeynes@1097 | 106 | }
|
nkeynes@1097 | 107 | if( filename != NULL )
|
nkeynes@1097 | 108 | disc->name = g_strdup(filename);
|
nkeynes@1097 | 109 | return disc;
|
nkeynes@1097 | 110 | }
|
nkeynes@1097 | 111 |
|
nkeynes@1097 | 112 | cdrom_disc_t cdrom_disc_new( const char *name, ERROR *err )
|
nkeynes@1097 | 113 | {
|
nkeynes@1097 | 114 | cdrom_disc_t disc = g_malloc0( sizeof(struct cdrom_disc) );
|
nkeynes@1097 | 115 | if( disc != NULL ) {
|
nkeynes@1097 | 116 | cdrom_disc_init( disc, name );
|
nkeynes@1097 | 117 | } else {
|
nkeynes@1109 | 118 | SET_ERROR(err, LX_ERR_NOMEM, "Unable to allocate memory for cdrom disc");
|
nkeynes@1097 | 119 | }
|
nkeynes@1097 | 120 | return disc;
|
nkeynes@1097 | 121 | }
|
nkeynes@1097 | 122 |
|
nkeynes@1097 | 123 | /**
|
nkeynes@1097 | 124 | * Construct a new image-based disc using the given filename as the base source.
|
nkeynes@1097 | 125 | * TOC is initialized to the empty values.
|
nkeynes@1097 | 126 | */
|
nkeynes@1097 | 127 | static cdrom_disc_t cdrom_disc_image_new( const char *filename, ERROR *err )
|
nkeynes@1097 | 128 | {
|
nkeynes@1097 | 129 | cdrom_disc_t disc = cdrom_disc_new( filename, err );
|
nkeynes@1097 | 130 | if( disc != NULL && filename != NULL ) {
|
nkeynes@1097 | 131 | disc->base_source = file_sector_source_new_filename( filename, SECTOR_UNKNOWN, 0, FILE_SECTOR_FULL_FILE );
|
nkeynes@1097 | 132 | if( disc->base_source == NULL ) {
|
nkeynes@1109 | 133 | SET_ERROR( err, LX_ERR_FILE_NOOPEN, "Unable to open cdrom file '%s': %s", filename, strerror(errno) );
|
nkeynes@1097 | 134 | cdrom_disc_unref(disc);
|
nkeynes@1097 | 135 | disc = NULL;
|
nkeynes@1097 | 136 | } else {
|
nkeynes@1097 | 137 | sector_source_ref(disc->base_source);
|
nkeynes@1097 | 138 | }
|
nkeynes@1097 | 139 |
|
nkeynes@1097 | 140 | }
|
nkeynes@1097 | 141 | return disc;
|
nkeynes@1097 | 142 | }
|
nkeynes@1097 | 143 |
|
nkeynes@1097 | 144 | cdrom_lba_t cdrom_disc_compute_leadout( cdrom_disc_t disc )
|
nkeynes@1097 | 145 | {
|
nkeynes@1097 | 146 | if( disc->track_count == 0 ) {
|
nkeynes@1097 | 147 | disc->leadout = 0;
|
nkeynes@1097 | 148 | } else {
|
nkeynes@1097 | 149 | cdrom_track_t last_track = &disc->track[disc->track_count-1];
|
nkeynes@1097 | 150 | if( last_track->source != NULL ) {
|
nkeynes@1097 | 151 | cdrom_lba_t leadout = last_track->lba + last_track->source->size;
|
nkeynes@1097 | 152 | if( leadout > disc->leadout )
|
nkeynes@1097 | 153 | disc->leadout = leadout;
|
nkeynes@1097 | 154 | }
|
nkeynes@1097 | 155 | }
|
nkeynes@1097 | 156 | return disc->leadout;
|
nkeynes@1097 | 157 | }
|
nkeynes@1097 | 158 |
|
nkeynes@1097 | 159 |
|
nkeynes@1097 | 160 | void cdrom_disc_set_default_disc_type( cdrom_disc_t disc )
|
nkeynes@1097 | 161 | {
|
nkeynes@1097 | 162 | int type = CDROM_DISC_NONE, i;
|
nkeynes@1097 | 163 | for( i=0; i<disc->track_count; i++ ) {
|
nkeynes@1298 | 164 | if( ((disc->track[i].flags & TRACK_FLAG_DATA) == 0) ) {
|
nkeynes@1097 | 165 | if( type == CDROM_DISC_NONE )
|
nkeynes@1097 | 166 | type = CDROM_DISC_AUDIO;
|
nkeynes@1097 | 167 | } else if( disc->track[i].source != NULL &&
|
nkeynes@1097 | 168 | (disc->track[i].source->mode == SECTOR_MODE1 ||
|
nkeynes@1097 | 169 | disc->track[i].source->mode == SECTOR_RAW_NONXA) ) {
|
nkeynes@1097 | 170 | if( type != CDROM_DISC_XA )
|
nkeynes@1097 | 171 | type = CDROM_DISC_NONXA;
|
nkeynes@1097 | 172 | } else {
|
nkeynes@1097 | 173 | type = CDROM_DISC_XA;
|
nkeynes@1097 | 174 | break;
|
nkeynes@1097 | 175 | }
|
nkeynes@1097 | 176 | }
|
nkeynes@1097 | 177 | disc->disc_type = type;
|
nkeynes@1097 | 178 | }
|
nkeynes@1097 | 179 |
|
nkeynes@1097 | 180 | void cdrom_disc_clear_toc( cdrom_disc_t disc )
|
nkeynes@1097 | 181 | {
|
nkeynes@1097 | 182 | disc->disc_type = CDROM_DISC_NONE;
|
nkeynes@1097 | 183 | disc->leadout = 0;
|
nkeynes@1097 | 184 | disc->track_count = 0;
|
nkeynes@1097 | 185 | disc->session_count = 0;
|
nkeynes@1097 | 186 | for( unsigned i=0; i< CDROM_MAX_TRACKS; i++ ) {
|
nkeynes@1097 | 187 | if( disc->track[i].source != NULL ) {
|
nkeynes@1097 | 188 | sector_source_unref( disc->track[i].source );
|
nkeynes@1097 | 189 | disc->track[i].source = NULL;
|
nkeynes@1097 | 190 | }
|
nkeynes@1097 | 191 | }
|
nkeynes@1097 | 192 | }
|
nkeynes@1097 | 193 |
|
nkeynes@1097 | 194 | gboolean cdrom_disc_read_toc( cdrom_disc_t disc, ERROR *err )
|
nkeynes@1097 | 195 | {
|
nkeynes@1108 | 196 | if( disc->read_toc != NULL ) {
|
nkeynes@1108 | 197 | /* First set the defaults for an empty disc */
|
nkeynes@1108 | 198 | cdrom_disc_clear_toc(disc);
|
nkeynes@1097 | 199 |
|
nkeynes@1108 | 200 | if( disc->read_toc(disc, err ) ) {
|
nkeynes@1108 | 201 | /* Success - update disc type and leadout if the TOC read didn't set them */
|
nkeynes@1108 | 202 | if( disc->disc_type == CDROM_DISC_NONE )
|
nkeynes@1108 | 203 | cdrom_disc_set_default_disc_type(disc);
|
nkeynes@1108 | 204 | cdrom_disc_compute_leadout(disc);
|
nkeynes@1108 | 205 | return TRUE;
|
nkeynes@1108 | 206 | } else {
|
nkeynes@1108 | 207 | /* Reset to an empty disc in case the reader left things in an
|
nkeynes@1108 | 208 | * inconsistent state */
|
nkeynes@1108 | 209 | cdrom_disc_clear_toc(disc);
|
nkeynes@1108 | 210 | return FALSE;
|
nkeynes@1108 | 211 | }
|
nkeynes@1108 | 212 | } else {
|
nkeynes@1097 | 213 | return TRUE;
|
nkeynes@1097 | 214 | }
|
nkeynes@1097 | 215 | }
|
nkeynes@1097 | 216 |
|
nkeynes@1097 | 217 | FILE *cdrom_disc_get_base_file( cdrom_disc_t disc )
|
nkeynes@1097 | 218 | {
|
nkeynes@1097 | 219 | return file_sector_source_get_file(disc->base_source);
|
nkeynes@1097 | 220 | }
|
nkeynes@1097 | 221 |
|
nkeynes@1097 | 222 | /*************************** Public functions ***************************/
|
nkeynes@1097 | 223 |
|
nkeynes@1097 | 224 | cdrom_disc_t cdrom_disc_open( const char *inFilename, ERROR *err )
|
nkeynes@1097 | 225 | {
|
nkeynes@1097 | 226 | const gchar *filename = inFilename;
|
nkeynes@1097 | 227 | const gchar *ext = strrchr(filename, '.');
|
nkeynes@1097 | 228 | int i;
|
nkeynes@1097 | 229 | cdrom_disc_factory_t extclz = NULL;
|
nkeynes@1097 | 230 |
|
nkeynes@1097 | 231 | /* Ask the drive list if it recognizes the name first */
|
nkeynes@1097 | 232 | cdrom_drive_t drive = cdrom_drive_find(inFilename);
|
nkeynes@1097 | 233 | if( drive != NULL ) {
|
nkeynes@1097 | 234 | return cdrom_drive_open(drive, err);
|
nkeynes@1097 | 235 | }
|
nkeynes@1097 | 236 |
|
nkeynes@1097 | 237 | cdrom_disc_t disc = cdrom_disc_image_new( filename, err );
|
nkeynes@1097 | 238 | if( disc == NULL )
|
nkeynes@1097 | 239 | return NULL;
|
nkeynes@1097 | 240 |
|
nkeynes@1097 | 241 | /* check file extensions first */
|
nkeynes@1097 | 242 | FILE *f = file_sector_source_get_file(disc->base_source);
|
nkeynes@1097 | 243 | if( ext != NULL ) {
|
nkeynes@1097 | 244 | ext++; /* Skip the '.' */
|
nkeynes@1097 | 245 | for( i=0; cdrom_disc_factories[i] != NULL; i++ ) {
|
nkeynes@1097 | 246 | if( cdrom_disc_factories[i]->extension != NULL &&
|
nkeynes@1097 | 247 | strcasecmp( cdrom_disc_factories[i]->extension, ext ) == 0 ) {
|
nkeynes@1097 | 248 | extclz = cdrom_disc_factories[i];
|
nkeynes@1097 | 249 | if( extclz->is_valid_file(f) ) {
|
nkeynes@1097 | 250 | disc->read_toc = extclz->read_toc;
|
nkeynes@1097 | 251 | }
|
nkeynes@1097 | 252 | break;
|
nkeynes@1097 | 253 | }
|
nkeynes@1097 | 254 | }
|
nkeynes@1097 | 255 | }
|
nkeynes@1097 | 256 |
|
nkeynes@1097 | 257 | if( disc->read_toc == NULL ) {
|
nkeynes@1097 | 258 | /* Okay, fall back to magic */
|
nkeynes@1097 | 259 | for( i=0; cdrom_disc_factories[i] != NULL; i++ ) {
|
nkeynes@1097 | 260 | if( cdrom_disc_factories[i] != extclz &&
|
nkeynes@1097 | 261 | cdrom_disc_factories[i]->is_valid_file(f) ) {
|
nkeynes@1097 | 262 | disc->read_toc = cdrom_disc_factories[i]->read_toc;
|
nkeynes@1097 | 263 | break;
|
nkeynes@1097 | 264 | }
|
nkeynes@1097 | 265 | }
|
nkeynes@1097 | 266 | }
|
nkeynes@1097 | 267 |
|
nkeynes@1177 | 268 | if( disc->read_toc == NULL ) {
|
nkeynes@1097 | 269 | /* No handler found for file */
|
nkeynes@1097 | 270 | cdrom_disc_unref( disc );
|
nkeynes@1109 | 271 | SET_ERROR( err, LX_ERR_FILE_UNKNOWN, "File '%s' could not be recognized as any known image file or device type", filename );
|
nkeynes@1097 | 272 | return NULL;
|
nkeynes@1177 | 273 | } else if( !cdrom_disc_read_toc( disc, err ) ) {
|
nkeynes@1177 | 274 | cdrom_disc_unref( disc );
|
nkeynes@1177 | 275 | assert( err == NULL || err->code != LX_ERR_NONE ); /* Read-toc should have set an error code in this case */
|
nkeynes@1177 | 276 | return NULL;
|
nkeynes@1177 | 277 | } else {
|
nkeynes@1177 | 278 | /* All good */
|
nkeynes@1177 | 279 | return disc;
|
nkeynes@1097 | 280 | }
|
nkeynes@1097 | 281 | }
|
nkeynes@1097 | 282 |
|
nkeynes@1097 | 283 | /**
|
nkeynes@1108 | 284 | * Construct a disc around a source track.
|
nkeynes@1108 | 285 | * @param type Disc type, which must be compatible with the track mode
|
nkeynes@1108 | 286 | * @param track The source of data for the main track
|
nkeynes@1108 | 287 | * @param lba The position on disc of the main track. If non-zero,
|
nkeynes@1108 | 288 | * a filler track is added before it, in 2 separate sessions.
|
nkeynes@1108 | 289 | */
|
nkeynes@1109 | 290 | cdrom_disc_t cdrom_disc_new_from_track( cdrom_disc_type_t type, sector_source_t track, cdrom_lba_t lba, ERROR *err )
|
nkeynes@1108 | 291 | {
|
nkeynes@1108 | 292 | cdrom_disc_t disc = cdrom_disc_new( NULL, NULL );
|
nkeynes@1108 | 293 | if( disc != NULL ) {
|
nkeynes@1108 | 294 | disc->disc_type = type;
|
nkeynes@1108 | 295 | int trackno = 0;
|
nkeynes@1108 | 296 | if( lba != 0 ) {
|
nkeynes@1108 | 297 | cdrom_count_t size = lba - 150;
|
nkeynes@1108 | 298 | if( lba < 150 )
|
nkeynes@1108 | 299 | size = lba;
|
nkeynes@1108 | 300 | disc->track[0].trackno = 1;
|
nkeynes@1108 | 301 | disc->track[0].sessionno = 1;
|
nkeynes@1108 | 302 | disc->track[0].lba = 0;
|
nkeynes@1108 | 303 | disc->track[0].flags = 0;
|
nkeynes@1108 | 304 | disc->track[0].source = null_sector_source_new( SECTOR_CDDA, size );
|
nkeynes@1108 | 305 | sector_source_ref( disc->track[0].source );
|
nkeynes@1108 | 306 | trackno++;
|
nkeynes@1108 | 307 | }
|
nkeynes@1108 | 308 | disc->track[trackno].trackno = trackno+1;
|
nkeynes@1108 | 309 | disc->track[trackno].sessionno = trackno+1;
|
nkeynes@1108 | 310 | disc->track[trackno].lba = lba;
|
nkeynes@1108 | 311 | disc->track[trackno].flags = (track->mode == SECTOR_CDDA ? 0 : TRACK_FLAG_DATA);
|
nkeynes@1108 | 312 | disc->track[trackno].source = track;
|
nkeynes@1108 | 313 | sector_source_ref(track);
|
nkeynes@1108 | 314 |
|
nkeynes@1108 | 315 | disc->track_count = trackno+1;
|
nkeynes@1108 | 316 | disc->session_count = trackno+1;
|
nkeynes@1108 | 317 | cdrom_disc_compute_leadout(disc);
|
nkeynes@1109 | 318 | } else {
|
nkeynes@1109 | 319 | SET_ERROR(err, LX_ERR_NOMEM, "Unable to allocate memory for cdrom disc");
|
nkeynes@1108 | 320 | }
|
nkeynes@1108 | 321 | return disc;
|
nkeynes@1108 | 322 | }
|
nkeynes@1108 | 323 |
|
nkeynes@1108 | 324 | /**
|
nkeynes@1108 | 325 | * Construct a disc around an IsoImage track (convenience function)
|
nkeynes@1108 | 326 | */
|
nkeynes@1108 | 327 | cdrom_disc_t cdrom_disc_new_from_iso_image( cdrom_disc_type_t type, IsoImage *iso, cdrom_lba_t lba,
|
nkeynes@1108 | 328 | const char *bootstrap, ERROR *err )
|
nkeynes@1108 | 329 | {
|
nkeynes@1108 | 330 | sector_mode_t mode = (type == CDROM_DISC_NONXA ? SECTOR_MODE1 : SECTOR_MODE2_FORM1 );
|
nkeynes@1108 | 331 | sector_source_t source = iso_sector_source_new( iso, mode, lba, bootstrap, err );
|
nkeynes@1108 | 332 | if( source != NULL ) {
|
nkeynes@1109 | 333 | cdrom_disc_t disc = cdrom_disc_new_from_track(type, source, lba, err);
|
nkeynes@1108 | 334 | if( disc == NULL ) {
|
nkeynes@1108 | 335 | sector_source_unref( source );
|
nkeynes@1108 | 336 | } else {
|
nkeynes@1108 | 337 | return disc;
|
nkeynes@1108 | 338 | }
|
nkeynes@1108 | 339 | }
|
nkeynes@1108 | 340 | return NULL;
|
nkeynes@1108 | 341 | }
|
nkeynes@1108 | 342 |
|
nkeynes@1108 | 343 | /**
|
nkeynes@1097 | 344 | * Get the track information for the given track. If there is no such track,
|
nkeynes@1097 | 345 | * return NULL;
|
nkeynes@1097 | 346 | */
|
nkeynes@1097 | 347 | cdrom_track_t cdrom_disc_get_track( cdrom_disc_t disc, cdrom_trackno_t track )
|
nkeynes@1097 | 348 | {
|
nkeynes@1097 | 349 | if( track < 1 || track >= disc->track_count )
|
nkeynes@1097 | 350 | return NULL;
|
nkeynes@1097 | 351 | return &disc->track[track-1];
|
nkeynes@1097 | 352 | }
|
nkeynes@1097 | 353 |
|
nkeynes@1097 | 354 | /**
|
nkeynes@1097 | 355 | * Get the track information for the first track of the given session. If there
|
nkeynes@1097 | 356 | * is no such session, return NULL;
|
nkeynes@1097 | 357 | */
|
nkeynes@1097 | 358 | cdrom_track_t cdrom_disc_get_session( cdrom_disc_t disc, cdrom_sessionno_t session )
|
nkeynes@1097 | 359 | {
|
nkeynes@1097 | 360 | for( unsigned i=0; i< disc->track_count; i++ ) {
|
nkeynes@1097 | 361 | if( disc->track[i].sessionno == session )
|
nkeynes@1097 | 362 | return &disc->track[i];
|
nkeynes@1097 | 363 | }
|
nkeynes@1097 | 364 | return NULL;
|
nkeynes@1097 | 365 | }
|
nkeynes@1097 | 366 |
|
nkeynes@1097 | 367 | cdrom_count_t cdrom_disc_get_track_size( cdrom_disc_t disc, cdrom_track_t track )
|
nkeynes@1097 | 368 | {
|
nkeynes@1097 | 369 | if( track->trackno == disc->track_count )
|
nkeynes@1097 | 370 | return disc->leadout - track->lba;
|
nkeynes@1097 | 371 | else
|
nkeynes@1097 | 372 | return disc->track[track->trackno].lba - track->lba;
|
nkeynes@1097 | 373 | }
|
nkeynes@1097 | 374 |
|
nkeynes@1097 | 375 | cdrom_track_t cdrom_disc_get_last_track( cdrom_disc_t disc )
|
nkeynes@1097 | 376 | {
|
nkeynes@1097 | 377 | if( disc->track_count == 0 )
|
nkeynes@1097 | 378 | return NULL;
|
nkeynes@1097 | 379 | return &disc->track[disc->track_count-1];
|
nkeynes@1097 | 380 | }
|
nkeynes@1097 | 381 |
|
nkeynes@1099 | 382 | cdrom_track_t cdrom_disc_get_last_data_track( cdrom_disc_t disc )
|
nkeynes@1099 | 383 | {
|
nkeynes@1099 | 384 | for( unsigned i=disc->track_count; i>0; i-- ) {
|
nkeynes@1099 | 385 | if( disc->track[i-1].flags & TRACK_FLAG_DATA ) {
|
nkeynes@1099 | 386 | return &disc->track[i-1];
|
nkeynes@1099 | 387 | }
|
nkeynes@1099 | 388 | }
|
nkeynes@1099 | 389 | return NULL;
|
nkeynes@1099 | 390 | }
|
nkeynes@1097 | 391 | cdrom_track_t cdrom_disc_prev_track( cdrom_disc_t disc, cdrom_track_t track )
|
nkeynes@1097 | 392 | {
|
nkeynes@1097 | 393 | if( track->trackno <= 1 )
|
nkeynes@1097 | 394 | return NULL;
|
nkeynes@1097 | 395 | return cdrom_disc_get_track( disc, track->trackno-1 );
|
nkeynes@1097 | 396 | }
|
nkeynes@1097 | 397 |
|
nkeynes@1097 | 398 | cdrom_track_t cdrom_disc_next_track( cdrom_disc_t disc, cdrom_track_t track )
|
nkeynes@1097 | 399 | {
|
nkeynes@1097 | 400 | if( track->trackno >= disc->track_count )
|
nkeynes@1097 | 401 | return NULL;
|
nkeynes@1097 | 402 | return cdrom_disc_get_track( disc, track->trackno+1 );
|
nkeynes@1097 | 403 | }
|
nkeynes@1097 | 404 |
|
nkeynes@1097 | 405 | /**
|
nkeynes@1097 | 406 | * Find the track containing the sector specified by LBA.
|
nkeynes@1097 | 407 | * Note: this function does not check for media change.
|
nkeynes@1097 | 408 | * @return The track, or NULL if no track contains the sector.
|
nkeynes@1097 | 409 | */
|
nkeynes@1097 | 410 | cdrom_track_t cdrom_disc_get_track_by_lba( cdrom_disc_t disc, cdrom_lba_t lba )
|
nkeynes@1097 | 411 | {
|
nkeynes@1097 | 412 | if( disc->track_count == 0 || disc->track[0].lba > lba || lba >= disc->leadout )
|
nkeynes@1097 | 413 | return NULL; /* LBA outside disc bounds */
|
nkeynes@1097 | 414 |
|
nkeynes@1097 | 415 | for( unsigned i=1; i< disc->track_count; i++ ) {
|
nkeynes@1097 | 416 | if( lba < disc->track[i].lba )
|
nkeynes@1097 | 417 | return &disc->track[i-1];
|
nkeynes@1097 | 418 | }
|
nkeynes@1097 | 419 | return &disc->track[disc->track_count-1];
|
nkeynes@1097 | 420 | }
|
nkeynes@1097 | 421 |
|
nkeynes@1097 | 422 | cdrom_error_t cdrom_disc_read_sectors( cdrom_disc_t disc, cdrom_lba_t lba, cdrom_count_t count,
|
nkeynes@1097 | 423 | cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
|
nkeynes@1097 | 424 | {
|
nkeynes@1097 | 425 | return disc->source.read_sectors( &disc->source, lba, count, mode, buf, length );
|
nkeynes@1097 | 426 | }
|
nkeynes@1097 | 427 |
|
nkeynes@1097 | 428 | /**
|
nkeynes@1097 | 429 | * Check if the disc contains valid media.
|
nkeynes@1097 | 430 | * @return CDROM_ERROR_OK if disc is present, otherwise CDROM_ERROR_NODISC
|
nkeynes@1097 | 431 | */
|
nkeynes@1097 | 432 | cdrom_error_t cdrom_disc_check_media( cdrom_disc_t disc )
|
nkeynes@1097 | 433 | {
|
nkeynes@1097 | 434 | if( disc == NULL )
|
nkeynes@1097 | 435 | return CDROM_ERROR_NODISC;
|
nkeynes@1097 | 436 | if( disc->check_media != NULL )
|
nkeynes@1097 | 437 | disc->check_media(disc);
|
nkeynes@1097 | 438 | return disc->disc_type == CDROM_DISC_NONE ? CDROM_ERROR_NODISC : CDROM_ERROR_OK;
|
nkeynes@1097 | 439 | }
|
nkeynes@1097 | 440 |
|
nkeynes@1097 | 441 | void cdrom_disc_print_toc( FILE *f, cdrom_disc_t disc )
|
nkeynes@1097 | 442 | {
|
nkeynes@1097 | 443 | int i;
|
nkeynes@1097 | 444 | int session = 0;
|
nkeynes@1097 | 445 |
|
nkeynes@1097 | 446 | if( disc == NULL || disc->track_count == 0 ) {
|
nkeynes@1097 | 447 | fprintf( f, "No disc\n" );
|
nkeynes@1097 | 448 | return;
|
nkeynes@1097 | 449 | }
|
nkeynes@1097 | 450 | for( i=0; i<disc->track_count; i++ ) {
|
nkeynes@1097 | 451 | cdrom_track_t track = &disc->track[i];
|
nkeynes@1097 | 452 | if( track->sessionno != session ) {
|
nkeynes@1097 | 453 | session = disc->track[i].sessionno;
|
nkeynes@1097 | 454 | fprintf( f, "Session %d:\n", session );
|
nkeynes@1097 | 455 | }
|
nkeynes@1097 | 456 | fprintf( f, " %02d. %6d %02x\n", track->trackno, track->lba, track->flags );
|
nkeynes@1097 | 457 | }
|
nkeynes@1097 | 458 | }
|
nkeynes@1097 | 459 |
|
nkeynes@1097 | 460 | void cdrom_disc_dump_toc( cdrom_disc_t disc )
|
nkeynes@1097 | 461 | {
|
nkeynes@1097 | 462 | cdrom_disc_print_toc( stderr, disc );
|
nkeynes@1097 | 463 | }
|