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 1298:d0eb2307b847
prev1296:30ecee61f811
author nkeynes
date Fri May 29 18:47:05 2015 +1000 (8 years ago)
permissions -rw-r--r--
last change Fix test case
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@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
}
.