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