Search
lxdream.org :: lxdream/src/drivers/cdrom/sector.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cdrom/sector.c
changeset 1296:30ecee61f811
prev1178:e55ec927d55d
author nkeynes
date Sat Jan 26 14:00:48 2013 +1000 (9 years ago)
permissions -rw-r--r--
last change Change glib includes to #include <glib.h> rather than the individual
headers, as recent glib versions are breaking on this
file annotate diff log raw
nkeynes@1097
     1
/**
nkeynes@1097
     2
 * $Id$
nkeynes@1097
     3
 *
nkeynes@1097
     4
 * low-level 'block device' for input to gdrom discs.
nkeynes@1097
     5
 *
nkeynes@1097
     6
 * Copyright (c) 2009 Nathan Keynes.
nkeynes@1097
     7
 *
nkeynes@1097
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@1097
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@1097
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1097
    11
 * (at your option) any later version.
nkeynes@1097
    12
 *
nkeynes@1097
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@1097
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1097
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1097
    16
 * GNU General Public License for more details.
nkeynes@1097
    17
 */
nkeynes@1097
    18
nkeynes@1097
    19
#include <sys/stat.h>
nkeynes@1296
    20
#include <glib.h>
nkeynes@1097
    21
#include <assert.h>
nkeynes@1097
    22
#include <stdlib.h>
nkeynes@1097
    23
#include <stdio.h>
nkeynes@1097
    24
#include <string.h>
nkeynes@1097
    25
#include <unistd.h>
nkeynes@1097
    26
#include <fcntl.h>
nkeynes@1097
    27
nkeynes@1107
    28
#include "lxpaths.h"
nkeynes@1097
    29
#include "drivers/cdrom/sector.h"
nkeynes@1097
    30
#include "drivers/cdrom/cdrom.h"
nkeynes@1097
    31
#include "drivers/cdrom/ecc.h"
nkeynes@1097
    32
nkeynes@1097
    33
#define CHECK_READ(dev,lba,count) \
nkeynes@1097
    34
    if( !IS_SECTOR_SOURCE(dev) ) { \
nkeynes@1097
    35
        return CDROM_ERROR_NODISC; \
nkeynes@1099
    36
    } else if( (dev)->size != 0 && ((lba) >= (dev)->size || (lba+block_count) > (dev)->size) ) { \
nkeynes@1097
    37
        return CDROM_ERROR_BADREAD; \
nkeynes@1097
    38
    }
nkeynes@1097
    39
nkeynes@1097
    40
/* Default read mode for each sector mode */
nkeynes@1097
    41
const uint32_t cdrom_sector_read_mode[] = { 0,
nkeynes@1097
    42
        CDROM_READ_CDDA|CDROM_READ_DATA, CDROM_READ_MODE1|CDROM_READ_DATA,
nkeynes@1097
    43
        CDROM_READ_MODE2|CDROM_READ_DATA, CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
nkeynes@1097
    44
        CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
nkeynes@1097
    45
        CDROM_READ_MODE2|CDROM_READ_DATA|CDROM_READ_SUBHEADER|CDROM_READ_ECC,
nkeynes@1178
    46
        CDROM_READ_RAW, CDROM_READ_RAW,
nkeynes@1178
    47
        CDROM_READ_CDDA|CDROM_READ_DATA};
nkeynes@1097
    48
nkeynes@1097
    49
/* Block size for each sector mode */
nkeynes@1178
    50
const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352, 2448 };
nkeynes@1097
    51
nkeynes@1097
    52
const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",
nkeynes@1178
    53
        "Mode 2 semiraw", "XA Raw", "Non-XA Raw", "CDDA+Subchan" };
nkeynes@1097
    54
nkeynes@1097
    55
nkeynes@1097
    56
/********************* Public functions *************************/
nkeynes@1097
    57
cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
nkeynes@1097
    58
{
nkeynes@1097
    59
    CHECK_READ(device,lba,block_count);
nkeynes@1097
    60
    return device->read_blocks(device, lba, block_count, buf);
nkeynes@1097
    61
}
nkeynes@1097
    62
nkeynes@1097
    63
cdrom_error_t sector_source_read_sectors( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
nkeynes@1097
    64
                                          unsigned char *buf, size_t *length )
nkeynes@1097
    65
{
nkeynes@1097
    66
    CHECK_READ(device,lba,block_count);
nkeynes@1097
    67
    return device->read_sectors(device, lba, block_count, mode, buf, length);
nkeynes@1097
    68
}
nkeynes@1097
    69
nkeynes@1097
    70
void sector_source_ref( sector_source_t device )
nkeynes@1097
    71
{
nkeynes@1097
    72
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    73
    device->ref_count++;
nkeynes@1097
    74
}
nkeynes@1097
    75
nkeynes@1097
    76
void sector_source_unref( sector_source_t device )
nkeynes@1097
    77
{
nkeynes@1097
    78
    if( device == NULL )
nkeynes@1097
    79
        return;
nkeynes@1097
    80
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    81
    if( device->ref_count > 0 )
nkeynes@1097
    82
        device->ref_count--;
nkeynes@1097
    83
    if( device->ref_count == 0 )
nkeynes@1097
    84
        device->destroy(device);
nkeynes@1097
    85
}
nkeynes@1097
    86
nkeynes@1097
    87
void sector_source_release( sector_source_t device )
nkeynes@1097
    88
{
nkeynes@1097
    89
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    90
    if( device->ref_count == 0 )
nkeynes@1097
    91
        device->destroy(device);
nkeynes@1097
    92
}
nkeynes@1097
    93
nkeynes@1097
    94
/************************** Sector mangling ***************************/
nkeynes@1097
    95
/*
nkeynes@1097
    96
 * Private functions used to pack/unpack sectors, determine mode, and
nkeynes@1097
    97
 * evaluate sector reads.
nkeynes@1097
    98
 */
nkeynes@1097
    99
nkeynes@1097
   100
/** Basic data sector header structure */
nkeynes@1097
   101
struct cdrom_sector_header {
nkeynes@1097
   102
    uint8_t sync[12];
nkeynes@1097
   103
    uint8_t msf[3];
nkeynes@1097
   104
    uint8_t mode;
nkeynes@1097
   105
    uint8_t subhead[8]; // Mode-2 XA sectors only
nkeynes@1097
   106
};
nkeynes@1097
   107
nkeynes@1097
   108
static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
nkeynes@1097
   109
nkeynes@1097
   110
/* Field combinations that are legal for mode 1 or mode 2 (formless) reads */
nkeynes@1097
   111
static const uint8_t legal_nonxa_fields[] =
nkeynes@1097
   112
{ TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   113
  TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   114
  TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   115
  FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
nkeynes@1097
   116
nkeynes@1097
   117
/* Field combinations that are legal for mode 2 form 1 or form 2 reads */
nkeynes@1097
   118
static const uint8_t legal_xa_fields[] =
nkeynes@1097
   119
{ TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
nkeynes@1097
   120
  TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   121
  TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
nkeynes@1097
   122
  FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
nkeynes@1097
   123
nkeynes@1097
   124
/**
nkeynes@1097
   125
 * Position per sector mode of each of the fields
nkeynes@1097
   126
 *   sync, header, subheader, data, ecc.
nkeynes@1097
   127
 *
nkeynes@1097
   128
 */
nkeynes@1097
   129
static const uint32_t sector_field_positions[][6] = {
nkeynes@1097
   130
        { 0, 0, 0, 0, 0, 0 },    /* Unknown */
nkeynes@1097
   131
        { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */
nkeynes@1097
   132
        { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */
nkeynes@1097
   133
        { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */
nkeynes@1097
   134
        { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */
nkeynes@1097
   135
        { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */
nkeynes@1097
   136
nkeynes@1097
   137
nkeynes@1097
   138
nkeynes@1097
   139
/**
nkeynes@1097
   140
 * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,
nkeynes@1097
   141
 * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes
nkeynes@1097
   142
 * will return BADREADMODE, as it's impossible to tell.
nkeynes@1097
   143
 *
nkeynes@1097
   144
 * @param track_mode one of the CDROM_MODE* constants
nkeynes@1097
   145
 * @param read_mode the full read mode
nkeynes@1097
   146
 */
nkeynes@1097
   147
static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )
nkeynes@1097
   148
{
nkeynes@1097
   149
    int read_sector_type = CDROM_READ_TYPE(read_mode);
nkeynes@1097
   150
    int read_sector_fields = CDROM_READ_FIELDS(read_mode);
nkeynes@1097
   151
nkeynes@1097
   152
    /* Check the sector type is consistent */
nkeynes@1097
   153
    switch( read_sector_type ) {
nkeynes@1097
   154
    case CDROM_READ_ANY: break;
nkeynes@1097
   155
    case CDROM_READ_CDDA:
nkeynes@1178
   156
        if( sector_mode != SECTOR_CDDA && sector_mode != SECTOR_CDDA_SUBCHANNEL )
nkeynes@1097
   157
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   158
        break;
nkeynes@1097
   159
    case CDROM_READ_MODE1:
nkeynes@1097
   160
    case CDROM_READ_MODE2_FORM1:
nkeynes@1097
   161
        if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )
nkeynes@1097
   162
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   163
        break;
nkeynes@1097
   164
    case CDROM_READ_MODE2_FORM2:
nkeynes@1097
   165
        if( sector_mode != SECTOR_MODE2_FORM2 )
nkeynes@1097
   166
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   167
        break;
nkeynes@1097
   168
    case CDROM_READ_MODE2:
nkeynes@1097
   169
        if( sector_mode != SECTOR_MODE2_FORMLESS )
nkeynes@1097
   170
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   171
        break;
nkeynes@1097
   172
    default: /* Illegal read mode */
nkeynes@1097
   173
        return CDROM_ERROR_BADFIELD;
nkeynes@1097
   174
    }
nkeynes@1097
   175
nkeynes@1097
   176
    /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */
nkeynes@1097
   177
    switch( sector_mode ) {
nkeynes@1097
   178
    case SECTOR_CDDA:
nkeynes@1178
   179
    case SECTOR_CDDA_SUBCHANNEL:
nkeynes@1097
   180
        return CDROM_ERROR_OK; /* Everything is OK */
nkeynes@1097
   181
    case SECTOR_MODE2_FORM1:
nkeynes@1097
   182
    case SECTOR_MODE2_FORM2:
nkeynes@1097
   183
        if( !legal_xa_fields[read_sector_fields>>11] )
nkeynes@1097
   184
            return CDROM_ERROR_BADFIELD;
nkeynes@1097
   185
        else
nkeynes@1097
   186
            return CDROM_ERROR_OK;
nkeynes@1097
   187
    case SECTOR_MODE1:
nkeynes@1097
   188
    case SECTOR_MODE2_FORMLESS:
nkeynes@1097
   189
        if( !legal_nonxa_fields[read_sector_fields>>11] )
nkeynes@1097
   190
            return CDROM_ERROR_BADFIELD;
nkeynes@1097
   191
        else
nkeynes@1097
   192
            return CDROM_ERROR_OK;
nkeynes@1097
   193
    default:
nkeynes@1097
   194
        return CDROM_ERROR_BADFIELD;
nkeynes@1097
   195
    }
nkeynes@1097
   196
}
nkeynes@1097
   197
nkeynes@1097
   198
static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )
nkeynes@1097
   199
{
nkeynes@1097
   200
    struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;
nkeynes@1097
   201
nkeynes@1097
   202
    switch( raw_mode ) {
nkeynes@1097
   203
    case SECTOR_SEMIRAW_MODE2: /* XA sectors */
nkeynes@1097
   204
    case SECTOR_RAW_XA:
nkeynes@1097
   205
        switch( header->mode ) {
nkeynes@1097
   206
        case 1: return SECTOR_MODE1;
nkeynes@1097
   207
        case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;
nkeynes@1097
   208
        default: return SECTOR_UNKNOWN;
nkeynes@1097
   209
        }
nkeynes@1097
   210
    case SECTOR_RAW_NONXA:
nkeynes@1097
   211
        switch( header->mode ) {
nkeynes@1097
   212
        case 1: return SECTOR_MODE1;
nkeynes@1097
   213
        case 2: return SECTOR_MODE2_FORMLESS;
nkeynes@1097
   214
        default: return SECTOR_UNKNOWN;
nkeynes@1097
   215
        }
nkeynes@1097
   216
    default:
nkeynes@1097
   217
        return raw_mode;
nkeynes@1097
   218
    }
nkeynes@1097
   219
}
nkeynes@1097
   220
nkeynes@1097
   221
/**
nkeynes@1097
   222
 * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where
nkeynes@1097
   223
 * necessary.
nkeynes@1097
   224
 */
nkeynes@1097
   225
static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )
nkeynes@1097
   226
{
nkeynes@1097
   227
    cdrom_error_t err;
nkeynes@1097
   228
nkeynes@1097
   229
    switch( device->mode ) {
nkeynes@1097
   230
    case SECTOR_RAW_XA:
nkeynes@1097
   231
    case SECTOR_RAW_NONXA:
nkeynes@1097
   232
        return device->read_blocks(device, lba, 1, buf);
nkeynes@1097
   233
    case SECTOR_SEMIRAW_MODE2:
nkeynes@1097
   234
        memcpy( buf, cdrom_sync_data, 12 );
nkeynes@1097
   235
        cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);
nkeynes@1097
   236
        return device->read_blocks(device, lba, 1, &buf[16]);
nkeynes@1097
   237
    case SECTOR_MODE1:
nkeynes@1097
   238
    case SECTOR_MODE2_FORMLESS:
nkeynes@1097
   239
        err = device->read_blocks(device, lba, 1, &buf[16]);
nkeynes@1097
   240
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   241
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   242
        }
nkeynes@1097
   243
        return err;
nkeynes@1097
   244
    case SECTOR_MODE2_FORM1:
nkeynes@1097
   245
        *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;
nkeynes@1097
   246
        err = device->read_blocks(device, lba, 1, &buf[24]);
nkeynes@1097
   247
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   248
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   249
        }
nkeynes@1097
   250
        return err;
nkeynes@1097
   251
    case SECTOR_MODE2_FORM2:
nkeynes@1097
   252
        *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;
nkeynes@1097
   253
        err = device->read_blocks(device, lba, 1, &buf[24]);
nkeynes@1097
   254
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   255
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   256
        }
nkeynes@1097
   257
        return err;
nkeynes@1097
   258
    default:
nkeynes@1097
   259
        abort();
nkeynes@1097
   260
    }
nkeynes@1097
   261
}
nkeynes@1097
   262
nkeynes@1097
   263
static cdrom_error_t extract_sector_fields( unsigned char *raw_sector, sector_mode_t mode, int fields, unsigned char *buf, size_t *length )
nkeynes@1097
   264
{
nkeynes@1097
   265
    int start=-1,end=0;
nkeynes@1097
   266
    int i;
nkeynes@1097
   267
nkeynes@1097
   268
    for( i=0; i<5; i++ ) {
nkeynes@1097
   269
        if( fields & (0x8000>>i) ) {
nkeynes@1097
   270
            if( start == -1 )
nkeynes@1097
   271
                start = sector_field_positions[mode][i];
nkeynes@1097
   272
            else if( end != sector_field_positions[mode][i] )
nkeynes@1097
   273
                return CDROM_ERROR_BADFIELD;
nkeynes@1097
   274
            end = sector_field_positions[mode][i+1];
nkeynes@1097
   275
        }
nkeynes@1097
   276
    }
nkeynes@1097
   277
    if( start == -1 ) {
nkeynes@1097
   278
        *length = 0;
nkeynes@1097
   279
    } else {
nkeynes@1097
   280
        memcpy( buf, &raw_sector[start], end-start );
nkeynes@1097
   281
        *length = end-start;
nkeynes@1097
   282
    }
nkeynes@1097
   283
    return CDROM_ERROR_OK;
nkeynes@1097
   284
}
nkeynes@1097
   285
nkeynes@1097
   286
cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
nkeynes@1097
   287
{
nkeynes@1097
   288
    sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );
nkeynes@1097
   289
    if( sector_mode == SECTOR_UNKNOWN )
nkeynes@1097
   290
        return CDROM_ERROR_BADREAD;
nkeynes@1097
   291
    cdrom_error_t status = is_legal_read( sector_mode, mode );
nkeynes@1097
   292
    if( status != CDROM_ERROR_OK )
nkeynes@1097
   293
        return status;
nkeynes@1097
   294
    return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );
nkeynes@1097
   295
}
nkeynes@1097
   296
nkeynes@1097
   297
/**
nkeynes@1097
   298
 * This is horribly complicated by the need to handle mapping between all possible
nkeynes@1097
   299
 * sector modes + read modes, but fortunately most sources can just supply
nkeynes@1097
   300
 * a single block type and not care about the details here.
nkeynes@1097
   301
 */
nkeynes@1097
   302
cdrom_error_t default_sector_source_read_sectors( sector_source_t device,
nkeynes@1097
   303
        cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
nkeynes@1097
   304
        unsigned char *buf, size_t *length )
nkeynes@1097
   305
{
nkeynes@1178
   306
    unsigned char tmp[2448];
nkeynes@1097
   307
    int read_sector_type = CDROM_READ_TYPE(mode);
nkeynes@1097
   308
    int read_sector_fields = CDROM_READ_FIELDS(mode);
nkeynes@1097
   309
    int i;
nkeynes@1097
   310
    size_t len = 0;
nkeynes@1097
   311
    cdrom_error_t err;
nkeynes@1097
   312
nkeynes@1097
   313
    CHECK_READ(device, lba, count);
nkeynes@1097
   314
nkeynes@1097
   315
    switch(device->mode) {
nkeynes@1097
   316
    case SECTOR_CDDA:
nkeynes@1097
   317
        if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
nkeynes@1097
   318
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   319
        if( read_sector_fields != 0 ) {
nkeynes@1097
   320
            len = block_count * CDROM_MAX_SECTOR_SIZE;
nkeynes@1097
   321
            device->read_blocks( device, lba, block_count, buf );
nkeynes@1097
   322
        }
nkeynes@1097
   323
        break;
nkeynes@1178
   324
    case SECTOR_CDDA_SUBCHANNEL:
nkeynes@1178
   325
        if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
nkeynes@1178
   326
            return CDROM_ERROR_BADREADMODE;
nkeynes@1178
   327
        if( read_sector_fields != 0 ) {
nkeynes@1178
   328
            len = block_count * 2352;
nkeynes@1178
   329
            for( i=0; i<block_count; i++ ) {
nkeynes@1178
   330
                device->read_blocks( device, lba+i, 1, tmp );
nkeynes@1178
   331
                memcpy( &buf[2352*i], tmp, 2352 );
nkeynes@1178
   332
            }
nkeynes@1178
   333
        }
nkeynes@1178
   334
        break;
nkeynes@1097
   335
    case SECTOR_RAW_XA:
nkeynes@1097
   336
    case SECTOR_RAW_NONXA:
nkeynes@1097
   337
    case SECTOR_SEMIRAW_MODE2:
nkeynes@1097
   338
        /* We (may) have to break the raw sector up into requested fields.
nkeynes@1097
   339
         * Process sectors one at a time
nkeynes@1097
   340
         */
nkeynes@1097
   341
        for( i=0; i<block_count; i++ ) {
nkeynes@1097
   342
            size_t tmplen;
nkeynes@1097
   343
            err = read_raw_sector( device, lba+i, tmp );
nkeynes@1097
   344
            if( err != CDROM_ERROR_OK )
nkeynes@1097
   345
                return err;
nkeynes@1097
   346
            err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );
nkeynes@1097
   347
            if( err != CDROM_ERROR_OK )
nkeynes@1097
   348
                return err;
nkeynes@1097
   349
            len += tmplen;
nkeynes@1097
   350
        }
nkeynes@1097
   351
        break;
nkeynes@1097
   352
    default: /* Data-only blocks */
nkeynes@1097
   353
        err = is_legal_read( device->mode, mode );
nkeynes@1097
   354
        if( err != CDROM_ERROR_OK )
nkeynes@1097
   355
            return err;
nkeynes@1097
   356
        if( read_sector_fields == 0 ) { /* Read nothing */
nkeynes@1099
   357
            if( length != NULL )
nkeynes@1099
   358
                *length = 0;
nkeynes@1097
   359
            return CDROM_ERROR_OK;
nkeynes@1097
   360
        } else if( read_sector_fields == CDROM_READ_DATA ) {
nkeynes@1097
   361
            /* Data-only */
nkeynes@1099
   362
            if( length != NULL )
nkeynes@1099
   363
                *length = block_count * CDROM_SECTOR_SIZE(device->mode);
nkeynes@1097
   364
            return device->read_blocks( device, lba, block_count, buf );
nkeynes@1097
   365
        } else if( read_sector_fields == CDROM_READ_RAW ) {
nkeynes@1097
   366
            for( i=0; i<block_count; i++ ) {
nkeynes@1097
   367
                err = read_raw_sector( device, lba+i, &buf[2352*i] );
nkeynes@1097
   368
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   369
                    return err;
nkeynes@1097
   370
            }
nkeynes@1097
   371
            len = block_count * CDROM_MAX_SECTOR_SIZE;
nkeynes@1097
   372
        } else {
nkeynes@1097
   373
            for( i=0; i<block_count; i++ ) {
nkeynes@1097
   374
                size_t tmplen;
nkeynes@1097
   375
                err = read_raw_sector( device, lba+i, tmp );
nkeynes@1097
   376
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   377
                    return err;
nkeynes@1097
   378
                err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );
nkeynes@1097
   379
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   380
                    return err;
nkeynes@1097
   381
                len += tmplen;
nkeynes@1097
   382
            }
nkeynes@1097
   383
        }
nkeynes@1097
   384
    }
nkeynes@1099
   385
    if( length != NULL )
nkeynes@1099
   386
        *length = len;
nkeynes@1097
   387
    return CDROM_ERROR_OK;
nkeynes@1097
   388
nkeynes@1097
   389
}
nkeynes@1097
   390
nkeynes@1097
   391
/************************ Base implementation *************************/
nkeynes@1097
   392
nkeynes@1097
   393
/**
nkeynes@1097
   394
 * Default destroy implementation - clears the tag and frees memory.
nkeynes@1097
   395
 */
nkeynes@1097
   396
void default_sector_source_destroy( sector_source_t device )
nkeynes@1097
   397
{
nkeynes@1097
   398
    assert( device != NULL && device->ref_count == 0 );
nkeynes@1097
   399
    device->tag = 0;
nkeynes@1097
   400
    g_free( device );
nkeynes@1097
   401
}
nkeynes@1097
   402
nkeynes@1097
   403
sector_source_t sector_source_init( sector_source_t device, sector_source_type_t type, sector_mode_t mode, cdrom_count_t size,
nkeynes@1097
   404
                        sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )
nkeynes@1097
   405
{
nkeynes@1097
   406
    device->tag = SECTOR_SOURCE_TAG;
nkeynes@1097
   407
    device->ref_count = 0;
nkeynes@1097
   408
    device->type = type;
nkeynes@1097
   409
    device->mode = mode;
nkeynes@1097
   410
    device->size = size;
nkeynes@1097
   411
    device->read_blocks = readfn;
nkeynes@1097
   412
    device->read_sectors = default_sector_source_read_sectors;
nkeynes@1097
   413
    if( destroyfn == NULL )
nkeynes@1097
   414
        device->destroy = default_sector_source_destroy;
nkeynes@1097
   415
    else
nkeynes@1097
   416
        device->destroy = destroyfn;
nkeynes@1097
   417
    return device;
nkeynes@1097
   418
}
nkeynes@1097
   419
nkeynes@1097
   420
/************************ Null device implementation *************************/
nkeynes@1097
   421
cdrom_error_t null_sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
nkeynes@1097
   422
{
nkeynes@1097
   423
    memset( buf, 0,  block_count*CDROM_SECTOR_SIZE(device->mode) );
nkeynes@1097
   424
    return CDROM_ERROR_OK;
nkeynes@1097
   425
}
nkeynes@1097
   426
nkeynes@1097
   427
sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )
nkeynes@1097
   428
{
nkeynes@1097
   429
    return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,
nkeynes@1097
   430
            null_sector_source_read, default_sector_source_destroy );
nkeynes@1097
   431
}
nkeynes@1097
   432
nkeynes@1097
   433
/************************ File device implementation *************************/
nkeynes@1097
   434
typedef struct file_sector_source {
nkeynes@1097
   435
    struct sector_source dev;
nkeynes@1097
   436
    FILE *file;
nkeynes@1097
   437
    uint32_t offset; /* offset in file where source begins */
nkeynes@1097
   438
    sector_source_t ref; /* Parent source reference */
nkeynes@1097
   439
    gboolean closeOnDestroy;
nkeynes@1097
   440
} *file_sector_source_t;
nkeynes@1097
   441
nkeynes@1097
   442
void file_sector_source_destroy( sector_source_t dev )
nkeynes@1097
   443
{
nkeynes@1097
   444
    assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
nkeynes@1097
   445
    file_sector_source_t fdev = (file_sector_source_t)dev;
nkeynes@1097
   446
nkeynes@1097
   447
    if( fdev->closeOnDestroy && fdev->file != NULL ) {
nkeynes@1097
   448
        fclose( fdev->file );
nkeynes@1097
   449
    }
nkeynes@1097
   450
    sector_source_unref( fdev->ref );
nkeynes@1097
   451
    fdev->file = NULL;
nkeynes@1097
   452
    default_sector_source_destroy(dev);
nkeynes@1097
   453
}
nkeynes@1097
   454
nkeynes@1097
   455
cdrom_error_t file_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
nkeynes@1097
   456
{
nkeynes@1097
   457
    assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
nkeynes@1097
   458
    file_sector_source_t fdev = (file_sector_source_t)dev;
nkeynes@1097
   459
nkeynes@1097
   460
    uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);
nkeynes@1097
   461
    uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
nkeynes@1097
   462
    fseek( fdev->file, off, SEEK_SET );
nkeynes@1097
   463
nkeynes@1097
   464
    size_t len = fread( buf, 1, size, fdev->file );
nkeynes@1097
   465
    if( len == -1 ) {
nkeynes@1097
   466
        return CDROM_ERROR_READERROR;
nkeynes@1097
   467
    } else if( len < size ) {
nkeynes@1097
   468
        /* zero-fill */
nkeynes@1097
   469
        memset( buf + len, 0, size-len );
nkeynes@1097
   470
    }
nkeynes@1097
   471
    return CDROM_ERROR_OK;
nkeynes@1097
   472
}
nkeynes@1097
   473
nkeynes@1097
   474
sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   475
                                        cdrom_count_t sector_count, gboolean closeOnDestroy )
nkeynes@1097
   476
{
nkeynes@1097
   477
    if( sector_count == FILE_SECTOR_FULL_FILE ) {
nkeynes@1097
   478
        unsigned int sector_size = CDROM_SECTOR_SIZE(mode);
nkeynes@1097
   479
        if( sector_size == 0 )
nkeynes@1097
   480
            sector_size = 2048;
nkeynes@1097
   481
        struct stat st;
nkeynes@1097
   482
nkeynes@1097
   483
        if( f == NULL || fstat( fileno(f), &st ) != 0 ) {
nkeynes@1097
   484
            /* can't stat file? */
nkeynes@1097
   485
            return NULL;
nkeynes@1097
   486
        }
nkeynes@1097
   487
nkeynes@1097
   488
        sector_count = (st.st_size + sector_size-1) / sector_size;
nkeynes@1097
   489
    }
nkeynes@1097
   490
nkeynes@1097
   491
    file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));
nkeynes@1097
   492
    dev->file = f;
nkeynes@1097
   493
    dev->offset = offset;
nkeynes@1097
   494
    dev->closeOnDestroy = closeOnDestroy;
nkeynes@1097
   495
    dev->ref = NULL;
nkeynes@1097
   496
    return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode,  sector_count, file_sector_source_read, file_sector_source_destroy );
nkeynes@1097
   497
}
nkeynes@1097
   498
nkeynes@1097
   499
sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )
nkeynes@1097
   500
{
nkeynes@1097
   501
    return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );
nkeynes@1097
   502
}
nkeynes@1097
   503
nkeynes@1097
   504
sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   505
                                                 cdrom_count_t sector_count )
nkeynes@1097
   506
{
nkeynes@1097
   507
    int fd = open( filename, O_RDONLY|O_NONBLOCK );
nkeynes@1097
   508
    if( fd == -1 ) {
nkeynes@1097
   509
        return NULL;
nkeynes@1097
   510
    }
nkeynes@1097
   511
    FILE *f = fdopen( fd , "ro" );
nkeynes@1097
   512
    if( f == NULL ) {
nkeynes@1097
   513
        close(fd);
nkeynes@1097
   514
        return NULL;
nkeynes@1097
   515
    } else {
nkeynes@1097
   516
        return file_sector_source_new( f, mode, offset, sector_count, TRUE );
nkeynes@1097
   517
    }
nkeynes@1097
   518
}
nkeynes@1097
   519
nkeynes@1097
   520
sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   521
                                               cdrom_count_t sector_count )
nkeynes@1097
   522
{
nkeynes@1097
   523
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   524
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   525
nkeynes@1097
   526
    sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );
nkeynes@1097
   527
    ((file_sector_source_t)source)->ref = ref;
nkeynes@1097
   528
    sector_source_ref(ref);
nkeynes@1097
   529
    return source;
nkeynes@1097
   530
}
nkeynes@1097
   531
nkeynes@1097
   532
FILE *file_sector_source_get_file( sector_source_t ref )
nkeynes@1097
   533
{
nkeynes@1097
   534
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   535
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   536
    return fref->file;
nkeynes@1097
   537
}
nkeynes@1097
   538
nkeynes@1097
   539
int file_sector_source_get_fd( sector_source_t ref )
nkeynes@1097
   540
{
nkeynes@1097
   541
    return fileno(file_sector_source_get_file(ref));
nkeynes@1097
   542
}
nkeynes@1097
   543
nkeynes@1097
   544
void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )
nkeynes@1097
   545
{
nkeynes@1097
   546
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   547
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   548
    fref->closeOnDestroy = closeOnDestroy;
nkeynes@1097
   549
}
nkeynes@1097
   550
nkeynes@1107
   551
/********************** Temporary file implementation ************************/
nkeynes@1107
   552
/**
nkeynes@1107
   553
 * The tmpfile source behaves exactly like a regular file source, except that
nkeynes@1107
   554
 * it creates a new temporary file, which is deleted on destruction or program
nkeynes@1107
   555
 * exit. The file is initially empty, so the user will need to get the fd and
nkeynes@1107
   556
 * write something to it before use.
nkeynes@1107
   557
 */
nkeynes@1107
   558
nkeynes@1107
   559
typedef struct tmpfile_sector_source {
nkeynes@1107
   560
    struct file_sector_source file;
nkeynes@1107
   561
    const char *filename;
nkeynes@1107
   562
} *tmpfile_sector_source_t;
nkeynes@1107
   563
nkeynes@1107
   564
static GList *tmpfile_open_list = NULL;
nkeynes@1107
   565
static gboolean tmpfile_atexit_installed = 0; /* TRUE to indicate atexit hook is registered */
nkeynes@1107
   566
nkeynes@1121
   567
static void tmpfile_sector_close( sector_source_t dev )
nkeynes@1121
   568
{
nkeynes@1121
   569
    assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
nkeynes@1121
   570
    tmpfile_sector_source_t fdev = (tmpfile_sector_source_t)dev;
nkeynes@1121
   571
nkeynes@1121
   572
    if( fdev->file.file != NULL ) {
nkeynes@1121
   573
        fclose( fdev->file.file );
nkeynes@1121
   574
        fdev->file.file = NULL;
nkeynes@1121
   575
    }
nkeynes@1121
   576
    if( fdev->filename != NULL ) {
nkeynes@1121
   577
        unlink(fdev->filename);
nkeynes@1121
   578
        g_free((char *)fdev->filename);
nkeynes@1121
   579
        fdev->filename = NULL;
nkeynes@1121
   580
    }
nkeynes@1121
   581
}
nkeynes@1121
   582
nkeynes@1121
   583
nkeynes@1107
   584
/**
nkeynes@1121
   585
 * atexit hook to close any open tmpfiles - make sure they're deleted.
nkeynes@1107
   586
 */
nkeynes@1107
   587
static void tmpfile_atexit_hook(void)
nkeynes@1107
   588
{
nkeynes@1107
   589
    GList *ptr;
nkeynes@1121
   590
    for( ptr = tmpfile_open_list; ptr != NULL; ptr = ptr->next ) {
nkeynes@1121
   591
        sector_source_t source = (sector_source_t)ptr->data;
nkeynes@1121
   592
        tmpfile_sector_close(source);
nkeynes@1107
   593
    }
nkeynes@1107
   594
}
nkeynes@1107
   595
nkeynes@1107
   596
nkeynes@1107
   597
static void tmpfile_sector_source_destroy( sector_source_t dev )
nkeynes@1107
   598
{
nkeynes@1121
   599
    tmpfile_sector_close(dev);
nkeynes@1121
   600
    tmpfile_open_list = g_list_remove(tmpfile_open_list, dev);
nkeynes@1107
   601
    default_sector_source_destroy(dev);
nkeynes@1107
   602
}
nkeynes@1107
   603
nkeynes@1107
   604
sector_source_t tmpfile_sector_source_new( sector_mode_t mode )
nkeynes@1107
   605
{
nkeynes@1107
   606
    if( !tmpfile_atexit_installed ) {
nkeynes@1107
   607
        atexit(tmpfile_atexit_hook);
nkeynes@1107
   608
    }
nkeynes@1107
   609
nkeynes@1107
   610
    gchar *tmpdir = getenv("TMPDIR");
nkeynes@1107
   611
    if( tmpdir == NULL ) {
nkeynes@1107
   612
        tmpdir = "/tmp";
nkeynes@1107
   613
    }
nkeynes@1107
   614
    gchar *tempfile = get_filename_at(tmpdir, "cd.XXXXXXX");
nkeynes@1107
   615
    int fd = mkstemp( tempfile );
nkeynes@1107
   616
    if( fd == -1 ) {
nkeynes@1107
   617
        g_free(tempfile);
nkeynes@1107
   618
        return FALSE;
nkeynes@1107
   619
    }
nkeynes@1107
   620
nkeynes@1107
   621
    FILE *f = fdopen( fd, "w+" );
nkeynes@1107
   622
    if( f == NULL ) {
nkeynes@1107
   623
        close(fd);
nkeynes@1107
   624
        unlink(tempfile);
nkeynes@1107
   625
        g_free(tempfile);
nkeynes@1107
   626
        return NULL;
nkeynes@1107
   627
    }
nkeynes@1107
   628
nkeynes@1107
   629
    tmpfile_sector_source_t dev = g_malloc0(sizeof(struct tmpfile_sector_source));
nkeynes@1107
   630
    dev->file.file = f;
nkeynes@1107
   631
    dev->filename = tempfile;
nkeynes@1107
   632
    sector_source_t source = sector_source_init( &dev->file.dev, FILE_SECTOR_SOURCE, mode, 0, file_sector_source_read, tmpfile_sector_source_destroy );
nkeynes@1107
   633
    tmpfile_open_list = g_list_append(tmpfile_open_list, source);
nkeynes@1108
   634
    return source;
nkeynes@1107
   635
}
nkeynes@1107
   636
nkeynes@1107
   637
/************************ Memory device implementation *************************/
nkeynes@1107
   638
typedef struct mem_sector_source {
nkeynes@1107
   639
    struct sector_source dev;
nkeynes@1107
   640
    unsigned char *buffer;
nkeynes@1107
   641
    gboolean freeOnDestroy;
nkeynes@1107
   642
} *mem_sector_source_t;
nkeynes@1107
   643
nkeynes@1107
   644
static void mem_sector_source_destroy( sector_source_t dev )
nkeynes@1107
   645
{
nkeynes@1107
   646
    assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
nkeynes@1107
   647
    mem_sector_source_t mdev = (mem_sector_source_t)dev;
nkeynes@1107
   648
nkeynes@1107
   649
    if( mdev->freeOnDestroy ) {
nkeynes@1107
   650
        free(mdev->buffer);
nkeynes@1107
   651
    }
nkeynes@1107
   652
    mdev->buffer = NULL;
nkeynes@1107
   653
    default_sector_source_destroy(dev);
nkeynes@1107
   654
}
nkeynes@1107
   655
nkeynes@1107
   656
static cdrom_error_t mem_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
nkeynes@1107
   657
{
nkeynes@1107
   658
    assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
nkeynes@1107
   659
    mem_sector_source_t mdev = (mem_sector_source_t)dev;
nkeynes@1107
   660
nkeynes@1107
   661
    if( (lba + block_count) >= dev->size )
nkeynes@1107
   662
        return CDROM_ERROR_BADREAD;
nkeynes@1107
   663
    uint32_t off = lba * CDROM_SECTOR_SIZE(dev->mode);
nkeynes@1107
   664
    uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
nkeynes@1107
   665
nkeynes@1107
   666
    memcpy( buf, mdev->buffer + off, size );
nkeynes@1107
   667
    return CDROM_ERROR_OK;
nkeynes@1107
   668
}
nkeynes@1107
   669
nkeynes@1107
   670
sector_source_t mem_sector_source_new_buffer( unsigned char *buffer, sector_mode_t mode,
nkeynes@1107
   671
                                       cdrom_count_t sector_count, gboolean freeOnDestroy )
nkeynes@1107
   672
{
nkeynes@1107
   673
    assert( mode != SECTOR_UNKNOWN );
nkeynes@1107
   674
    assert( buffer != NULL );
nkeynes@1107
   675
    mem_sector_source_t dev = g_malloc(sizeof(struct mem_sector_source));
nkeynes@1107
   676
    dev->buffer = buffer;
nkeynes@1107
   677
    dev->freeOnDestroy = freeOnDestroy;
nkeynes@1107
   678
    return sector_source_init( &dev->dev, MEM_SECTOR_SOURCE, mode, sector_count, mem_sector_source_read, mem_sector_source_destroy );
nkeynes@1107
   679
}
nkeynes@1107
   680
nkeynes@1107
   681
sector_source_t mem_sector_source_new( sector_mode_t mode, cdrom_count_t sector_count )
nkeynes@1107
   682
{
nkeynes@1107
   683
    return mem_sector_source_new_buffer( g_malloc( sector_count * CDROM_SECTOR_SIZE(mode) ), mode,
nkeynes@1107
   684
                                         sector_count, TRUE );
nkeynes@1107
   685
}
nkeynes@1107
   686
nkeynes@1107
   687
unsigned char *mem_sector_source_get_buffer( sector_source_t dev )
nkeynes@1107
   688
{
nkeynes@1107
   689
    assert( IS_SECTOR_SOURCE_TYPE(dev,MEM_SECTOR_SOURCE) );
nkeynes@1107
   690
    mem_sector_source_t mdev = (mem_sector_source_t)dev;
nkeynes@1107
   691
    return mdev->buffer;
nkeynes@1107
   692
}
nkeynes@1107
   693
nkeynes@1107
   694
nkeynes@1097
   695
/************************ Track device implementation *************************/
nkeynes@1097
   696
typedef struct track_sector_source {
nkeynes@1097
   697
    struct sector_source dev;
nkeynes@1097
   698
    cdrom_disc_t disc;
nkeynes@1097
   699
    uint32_t start_lba;
nkeynes@1097
   700
} *track_sector_source_t;
nkeynes@1097
   701
nkeynes@1097
   702
cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
nkeynes@1097
   703
                                               unsigned char *out )
nkeynes@1097
   704
{
nkeynes@1097
   705
    size_t length;
nkeynes@1097
   706
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   707
    assert( dev->mode != SECTOR_UNKNOWN );
nkeynes@1097
   708
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   709
    return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );
nkeynes@1097
   710
}
nkeynes@1097
   711
nkeynes@1097
   712
cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
nkeynes@1097
   713
                                                cdrom_read_mode_t mode, unsigned char *out, size_t *length )
nkeynes@1097
   714
{
nkeynes@1097
   715
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   716
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   717
nkeynes@1097
   718
    return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );
nkeynes@1097
   719
}
nkeynes@1097
   720
nkeynes@1097
   721
void track_sector_source_destroy( sector_source_t dev )
nkeynes@1097
   722
{
nkeynes@1097
   723
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   724
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   725
    sector_source_unref( &tdev->disc->source );
nkeynes@1097
   726
    default_sector_source_destroy(dev);
nkeynes@1097
   727
}
nkeynes@1097
   728
nkeynes@1097
   729
sector_source_t track_sector_source_new( cdrom_disc_t disc, sector_mode_t mode, cdrom_lba_t lba, cdrom_count_t count )
nkeynes@1097
   730
{
nkeynes@1097
   731
    if( disc == NULL ) {
nkeynes@1097
   732
        return NULL;
nkeynes@1097
   733
    }
nkeynes@1097
   734
    track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));
nkeynes@1097
   735
    dev->disc = disc;
nkeynes@1097
   736
    dev->start_lba = lba;
nkeynes@1097
   737
    sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,
nkeynes@1097
   738
                        track_sector_source_read_blocks, track_sector_source_destroy );
nkeynes@1097
   739
    dev->dev.read_sectors = track_sector_source_read_sectors;
nkeynes@1097
   740
    sector_source_ref( &disc->source );
nkeynes@1097
   741
    return &dev->dev;
nkeynes@1097
   742
}
.