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 1099:566cdeb157ec
prev1097:d4807997e450
next1107:7b279d10f46f
author nkeynes
date Wed Feb 10 18:16:19 2010 +1000 (10 years ago)
permissions -rw-r--r--
last change First draft of basic ISO9660 filesystem reader
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@1097
    20
#include <glib/gmem.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@1097
    28
#include "drivers/cdrom/sector.h"
nkeynes@1097
    29
#include "drivers/cdrom/cdrom.h"
nkeynes@1097
    30
#include "drivers/cdrom/ecc.h"
nkeynes@1097
    31
nkeynes@1097
    32
#define CHECK_READ(dev,lba,count) \
nkeynes@1097
    33
    if( !IS_SECTOR_SOURCE(dev) ) { \
nkeynes@1097
    34
        return CDROM_ERROR_NODISC; \
nkeynes@1099
    35
    } else if( (dev)->size != 0 && ((lba) >= (dev)->size || (lba+block_count) > (dev)->size) ) { \
nkeynes@1097
    36
        return CDROM_ERROR_BADREAD; \
nkeynes@1097
    37
    }
nkeynes@1097
    38
nkeynes@1097
    39
/* Default read mode for each sector mode */
nkeynes@1097
    40
const uint32_t cdrom_sector_read_mode[] = { 0,
nkeynes@1097
    41
        CDROM_READ_CDDA|CDROM_READ_DATA, CDROM_READ_MODE1|CDROM_READ_DATA,
nkeynes@1097
    42
        CDROM_READ_MODE2|CDROM_READ_DATA, CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
nkeynes@1097
    43
        CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
nkeynes@1097
    44
        CDROM_READ_MODE2|CDROM_READ_DATA|CDROM_READ_SUBHEADER|CDROM_READ_ECC,
nkeynes@1097
    45
        CDROM_READ_RAW, CDROM_READ_RAW };
nkeynes@1097
    46
nkeynes@1097
    47
/* Block size for each sector mode */
nkeynes@1097
    48
const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352 };
nkeynes@1097
    49
nkeynes@1097
    50
const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",
nkeynes@1097
    51
        "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };
nkeynes@1097
    52
nkeynes@1097
    53
nkeynes@1097
    54
/********************* Public functions *************************/
nkeynes@1097
    55
cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
nkeynes@1097
    56
{
nkeynes@1097
    57
    CHECK_READ(device,lba,block_count);
nkeynes@1097
    58
    return device->read_blocks(device, lba, block_count, buf);
nkeynes@1097
    59
}
nkeynes@1097
    60
nkeynes@1097
    61
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
    62
                                          unsigned char *buf, size_t *length )
nkeynes@1097
    63
{
nkeynes@1097
    64
    CHECK_READ(device,lba,block_count);
nkeynes@1097
    65
    return device->read_sectors(device, lba, block_count, mode, buf, length);
nkeynes@1097
    66
}
nkeynes@1097
    67
nkeynes@1097
    68
void sector_source_ref( sector_source_t device )
nkeynes@1097
    69
{
nkeynes@1097
    70
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    71
    device->ref_count++;
nkeynes@1097
    72
}
nkeynes@1097
    73
nkeynes@1097
    74
void sector_source_unref( sector_source_t device )
nkeynes@1097
    75
{
nkeynes@1097
    76
    if( device == NULL )
nkeynes@1097
    77
        return;
nkeynes@1097
    78
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    79
    if( device->ref_count > 0 )
nkeynes@1097
    80
        device->ref_count--;
nkeynes@1097
    81
    if( device->ref_count == 0 )
nkeynes@1097
    82
        device->destroy(device);
nkeynes@1097
    83
}
nkeynes@1097
    84
nkeynes@1097
    85
void sector_source_release( sector_source_t device )
nkeynes@1097
    86
{
nkeynes@1097
    87
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    88
    if( device->ref_count == 0 )
nkeynes@1097
    89
        device->destroy(device);
nkeynes@1097
    90
}
nkeynes@1097
    91
nkeynes@1097
    92
/************************** Sector mangling ***************************/
nkeynes@1097
    93
/*
nkeynes@1097
    94
 * Private functions used to pack/unpack sectors, determine mode, and
nkeynes@1097
    95
 * evaluate sector reads.
nkeynes@1097
    96
 */
nkeynes@1097
    97
nkeynes@1097
    98
/** Basic data sector header structure */
nkeynes@1097
    99
struct cdrom_sector_header {
nkeynes@1097
   100
    uint8_t sync[12];
nkeynes@1097
   101
    uint8_t msf[3];
nkeynes@1097
   102
    uint8_t mode;
nkeynes@1097
   103
    uint8_t subhead[8]; // Mode-2 XA sectors only
nkeynes@1097
   104
};
nkeynes@1097
   105
nkeynes@1097
   106
static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
nkeynes@1097
   107
nkeynes@1097
   108
/* Field combinations that are legal for mode 1 or mode 2 (formless) reads */
nkeynes@1097
   109
static const uint8_t legal_nonxa_fields[] =
nkeynes@1097
   110
{ TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   111
  TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   112
  TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   113
  FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
nkeynes@1097
   114
nkeynes@1097
   115
/* Field combinations that are legal for mode 2 form 1 or form 2 reads */
nkeynes@1097
   116
static const uint8_t legal_xa_fields[] =
nkeynes@1097
   117
{ TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
nkeynes@1097
   118
  TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   119
  TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
nkeynes@1097
   120
  FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
nkeynes@1097
   121
nkeynes@1097
   122
/**
nkeynes@1097
   123
 * Position per sector mode of each of the fields
nkeynes@1097
   124
 *   sync, header, subheader, data, ecc.
nkeynes@1097
   125
 *
nkeynes@1097
   126
 */
nkeynes@1097
   127
static const uint32_t sector_field_positions[][6] = {
nkeynes@1097
   128
        { 0, 0, 0, 0, 0, 0 },    /* Unknown */
nkeynes@1097
   129
        { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */
nkeynes@1097
   130
        { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */
nkeynes@1097
   131
        { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */
nkeynes@1097
   132
        { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */
nkeynes@1097
   133
        { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */
nkeynes@1097
   134
nkeynes@1097
   135
nkeynes@1097
   136
nkeynes@1097
   137
/**
nkeynes@1097
   138
 * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,
nkeynes@1097
   139
 * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes
nkeynes@1097
   140
 * will return BADREADMODE, as it's impossible to tell.
nkeynes@1097
   141
 *
nkeynes@1097
   142
 * @param track_mode one of the CDROM_MODE* constants
nkeynes@1097
   143
 * @param read_mode the full read mode
nkeynes@1097
   144
 */
nkeynes@1097
   145
static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )
nkeynes@1097
   146
{
nkeynes@1097
   147
    int read_sector_type = CDROM_READ_TYPE(read_mode);
nkeynes@1097
   148
    int read_sector_fields = CDROM_READ_FIELDS(read_mode);
nkeynes@1097
   149
nkeynes@1097
   150
    /* Check the sector type is consistent */
nkeynes@1097
   151
    switch( read_sector_type ) {
nkeynes@1097
   152
    case CDROM_READ_ANY: break;
nkeynes@1097
   153
    case CDROM_READ_CDDA:
nkeynes@1097
   154
        if( sector_mode != SECTOR_CDDA )
nkeynes@1097
   155
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   156
        break;
nkeynes@1097
   157
    case CDROM_READ_MODE1:
nkeynes@1097
   158
    case CDROM_READ_MODE2_FORM1:
nkeynes@1097
   159
        if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )
nkeynes@1097
   160
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   161
        break;
nkeynes@1097
   162
    case CDROM_READ_MODE2_FORM2:
nkeynes@1097
   163
        if( sector_mode != SECTOR_MODE2_FORM2 )
nkeynes@1097
   164
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   165
        break;
nkeynes@1097
   166
    case CDROM_READ_MODE2:
nkeynes@1097
   167
        if( sector_mode != SECTOR_MODE2_FORMLESS )
nkeynes@1097
   168
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   169
        break;
nkeynes@1097
   170
    default: /* Illegal read mode */
nkeynes@1097
   171
        return CDROM_ERROR_BADFIELD;
nkeynes@1097
   172
    }
nkeynes@1097
   173
nkeynes@1097
   174
    /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */
nkeynes@1097
   175
    switch( sector_mode ) {
nkeynes@1097
   176
    case SECTOR_CDDA:
nkeynes@1097
   177
        return CDROM_ERROR_OK; /* Everything is OK */
nkeynes@1097
   178
    case SECTOR_MODE2_FORM1:
nkeynes@1097
   179
    case SECTOR_MODE2_FORM2:
nkeynes@1097
   180
        if( !legal_xa_fields[read_sector_fields>>11] )
nkeynes@1097
   181
            return CDROM_ERROR_BADFIELD;
nkeynes@1097
   182
        else
nkeynes@1097
   183
            return CDROM_ERROR_OK;
nkeynes@1097
   184
    case SECTOR_MODE1:
nkeynes@1097
   185
    case SECTOR_MODE2_FORMLESS:
nkeynes@1097
   186
        if( !legal_nonxa_fields[read_sector_fields>>11] )
nkeynes@1097
   187
            return CDROM_ERROR_BADFIELD;
nkeynes@1097
   188
        else
nkeynes@1097
   189
            return CDROM_ERROR_OK;
nkeynes@1097
   190
    default:
nkeynes@1097
   191
        return CDROM_ERROR_BADFIELD;
nkeynes@1097
   192
    }
nkeynes@1097
   193
}
nkeynes@1097
   194
nkeynes@1097
   195
static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )
nkeynes@1097
   196
{
nkeynes@1097
   197
    struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;
nkeynes@1097
   198
nkeynes@1097
   199
    switch( raw_mode ) {
nkeynes@1097
   200
    case SECTOR_SEMIRAW_MODE2: /* XA sectors */
nkeynes@1097
   201
    case SECTOR_RAW_XA:
nkeynes@1097
   202
        switch( header->mode ) {
nkeynes@1097
   203
        case 1: return SECTOR_MODE1;
nkeynes@1097
   204
        case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;
nkeynes@1097
   205
        default: return SECTOR_UNKNOWN;
nkeynes@1097
   206
        }
nkeynes@1097
   207
    case SECTOR_RAW_NONXA:
nkeynes@1097
   208
        switch( header->mode ) {
nkeynes@1097
   209
        case 1: return SECTOR_MODE1;
nkeynes@1097
   210
        case 2: return SECTOR_MODE2_FORMLESS;
nkeynes@1097
   211
        default: return SECTOR_UNKNOWN;
nkeynes@1097
   212
        }
nkeynes@1097
   213
    default:
nkeynes@1097
   214
        return raw_mode;
nkeynes@1097
   215
    }
nkeynes@1097
   216
}
nkeynes@1097
   217
nkeynes@1097
   218
/**
nkeynes@1097
   219
 * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where
nkeynes@1097
   220
 * necessary.
nkeynes@1097
   221
 */
nkeynes@1097
   222
static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )
nkeynes@1097
   223
{
nkeynes@1097
   224
    cdrom_error_t err;
nkeynes@1097
   225
nkeynes@1097
   226
    switch( device->mode ) {
nkeynes@1097
   227
    case SECTOR_RAW_XA:
nkeynes@1097
   228
    case SECTOR_RAW_NONXA:
nkeynes@1097
   229
        return device->read_blocks(device, lba, 1, buf);
nkeynes@1097
   230
    case SECTOR_SEMIRAW_MODE2:
nkeynes@1097
   231
        memcpy( buf, cdrom_sync_data, 12 );
nkeynes@1097
   232
        cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);
nkeynes@1097
   233
        return device->read_blocks(device, lba, 1, &buf[16]);
nkeynes@1097
   234
    case SECTOR_MODE1:
nkeynes@1097
   235
    case SECTOR_MODE2_FORMLESS:
nkeynes@1097
   236
        err = device->read_blocks(device, lba, 1, &buf[16]);
nkeynes@1097
   237
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   238
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   239
        }
nkeynes@1097
   240
        return err;
nkeynes@1097
   241
    case SECTOR_MODE2_FORM1:
nkeynes@1097
   242
        *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;
nkeynes@1097
   243
        err = device->read_blocks(device, lba, 1, &buf[24]);
nkeynes@1097
   244
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   245
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   246
        }
nkeynes@1097
   247
        return err;
nkeynes@1097
   248
    case SECTOR_MODE2_FORM2:
nkeynes@1097
   249
        *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;
nkeynes@1097
   250
        err = device->read_blocks(device, lba, 1, &buf[24]);
nkeynes@1097
   251
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   252
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   253
        }
nkeynes@1097
   254
        return err;
nkeynes@1097
   255
    default:
nkeynes@1097
   256
        abort();
nkeynes@1097
   257
    }
nkeynes@1097
   258
}
nkeynes@1097
   259
nkeynes@1097
   260
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
   261
{
nkeynes@1097
   262
    int start=-1,end=0;
nkeynes@1097
   263
    int i;
nkeynes@1097
   264
nkeynes@1097
   265
    for( i=0; i<5; i++ ) {
nkeynes@1097
   266
        if( fields & (0x8000>>i) ) {
nkeynes@1097
   267
            if( start == -1 )
nkeynes@1097
   268
                start = sector_field_positions[mode][i];
nkeynes@1097
   269
            else if( end != sector_field_positions[mode][i] )
nkeynes@1097
   270
                return CDROM_ERROR_BADFIELD;
nkeynes@1097
   271
            end = sector_field_positions[mode][i+1];
nkeynes@1097
   272
        }
nkeynes@1097
   273
    }
nkeynes@1097
   274
    if( start == -1 ) {
nkeynes@1097
   275
        *length = 0;
nkeynes@1097
   276
    } else {
nkeynes@1097
   277
        memcpy( buf, &raw_sector[start], end-start );
nkeynes@1097
   278
        *length = end-start;
nkeynes@1097
   279
    }
nkeynes@1097
   280
    return CDROM_ERROR_OK;
nkeynes@1097
   281
}
nkeynes@1097
   282
nkeynes@1097
   283
cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
nkeynes@1097
   284
{
nkeynes@1097
   285
    sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );
nkeynes@1097
   286
    if( sector_mode == SECTOR_UNKNOWN )
nkeynes@1097
   287
        return CDROM_ERROR_BADREAD;
nkeynes@1097
   288
    cdrom_error_t status = is_legal_read( sector_mode, mode );
nkeynes@1097
   289
    if( status != CDROM_ERROR_OK )
nkeynes@1097
   290
        return status;
nkeynes@1097
   291
    return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );
nkeynes@1097
   292
}
nkeynes@1097
   293
nkeynes@1097
   294
/**
nkeynes@1097
   295
 * This is horribly complicated by the need to handle mapping between all possible
nkeynes@1097
   296
 * sector modes + read modes, but fortunately most sources can just supply
nkeynes@1097
   297
 * a single block type and not care about the details here.
nkeynes@1097
   298
 */
nkeynes@1097
   299
cdrom_error_t default_sector_source_read_sectors( sector_source_t device,
nkeynes@1097
   300
        cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
nkeynes@1097
   301
        unsigned char *buf, size_t *length )
nkeynes@1097
   302
{
nkeynes@1097
   303
    unsigned char tmp[CDROM_MAX_SECTOR_SIZE];
nkeynes@1097
   304
    int read_sector_type = CDROM_READ_TYPE(mode);
nkeynes@1097
   305
    int read_sector_fields = CDROM_READ_FIELDS(mode);
nkeynes@1097
   306
    int i;
nkeynes@1097
   307
    size_t len = 0;
nkeynes@1097
   308
    cdrom_error_t err;
nkeynes@1097
   309
nkeynes@1097
   310
    CHECK_READ(device, lba, count);
nkeynes@1097
   311
nkeynes@1097
   312
    switch(device->mode) {
nkeynes@1097
   313
    case SECTOR_CDDA:
nkeynes@1097
   314
        if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
nkeynes@1097
   315
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   316
        if( read_sector_fields != 0 ) {
nkeynes@1097
   317
            len = block_count * CDROM_MAX_SECTOR_SIZE;
nkeynes@1097
   318
            device->read_blocks( device, lba, block_count, buf );
nkeynes@1097
   319
        }
nkeynes@1097
   320
        break;
nkeynes@1097
   321
    case SECTOR_RAW_XA:
nkeynes@1097
   322
    case SECTOR_RAW_NONXA:
nkeynes@1097
   323
    case SECTOR_SEMIRAW_MODE2:
nkeynes@1097
   324
        /* We (may) have to break the raw sector up into requested fields.
nkeynes@1097
   325
         * Process sectors one at a time
nkeynes@1097
   326
         */
nkeynes@1097
   327
        for( i=0; i<block_count; i++ ) {
nkeynes@1097
   328
            size_t tmplen;
nkeynes@1097
   329
            err = read_raw_sector( device, lba+i, tmp );
nkeynes@1097
   330
            if( err != CDROM_ERROR_OK )
nkeynes@1097
   331
                return err;
nkeynes@1097
   332
            err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );
nkeynes@1097
   333
            if( err != CDROM_ERROR_OK )
nkeynes@1097
   334
                return err;
nkeynes@1097
   335
            len += tmplen;
nkeynes@1097
   336
        }
nkeynes@1097
   337
        break;
nkeynes@1097
   338
    default: /* Data-only blocks */
nkeynes@1097
   339
        err = is_legal_read( device->mode, mode );
nkeynes@1097
   340
        if( err != CDROM_ERROR_OK )
nkeynes@1097
   341
            return err;
nkeynes@1097
   342
        if( read_sector_fields == 0 ) { /* Read nothing */
nkeynes@1099
   343
            if( length != NULL )
nkeynes@1099
   344
                *length = 0;
nkeynes@1097
   345
            return CDROM_ERROR_OK;
nkeynes@1097
   346
        } else if( read_sector_fields == CDROM_READ_DATA ) {
nkeynes@1097
   347
            /* Data-only */
nkeynes@1099
   348
            if( length != NULL )
nkeynes@1099
   349
                *length = block_count * CDROM_SECTOR_SIZE(device->mode);
nkeynes@1097
   350
            return device->read_blocks( device, lba, block_count, buf );
nkeynes@1097
   351
        } else if( read_sector_fields == CDROM_READ_RAW ) {
nkeynes@1097
   352
            for( i=0; i<block_count; i++ ) {
nkeynes@1097
   353
                err = read_raw_sector( device, lba+i, &buf[2352*i] );
nkeynes@1097
   354
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   355
                    return err;
nkeynes@1097
   356
            }
nkeynes@1097
   357
            len = block_count * CDROM_MAX_SECTOR_SIZE;
nkeynes@1097
   358
        } else {
nkeynes@1097
   359
            for( i=0; i<block_count; i++ ) {
nkeynes@1097
   360
                size_t tmplen;
nkeynes@1097
   361
                err = read_raw_sector( device, lba+i, tmp );
nkeynes@1097
   362
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   363
                    return err;
nkeynes@1097
   364
                err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );
nkeynes@1097
   365
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   366
                    return err;
nkeynes@1097
   367
                len += tmplen;
nkeynes@1097
   368
            }
nkeynes@1097
   369
        }
nkeynes@1097
   370
    }
nkeynes@1099
   371
    if( length != NULL )
nkeynes@1099
   372
        *length = len;
nkeynes@1097
   373
    return CDROM_ERROR_OK;
nkeynes@1097
   374
nkeynes@1097
   375
}
nkeynes@1097
   376
nkeynes@1097
   377
/************************ Base implementation *************************/
nkeynes@1097
   378
nkeynes@1097
   379
/**
nkeynes@1097
   380
 * Default destroy implementation - clears the tag and frees memory.
nkeynes@1097
   381
 */
nkeynes@1097
   382
void default_sector_source_destroy( sector_source_t device )
nkeynes@1097
   383
{
nkeynes@1097
   384
    assert( device != NULL && device->ref_count == 0 );
nkeynes@1097
   385
    device->tag = 0;
nkeynes@1097
   386
    g_free( device );
nkeynes@1097
   387
}
nkeynes@1097
   388
nkeynes@1097
   389
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
   390
                        sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )
nkeynes@1097
   391
{
nkeynes@1097
   392
    device->tag = SECTOR_SOURCE_TAG;
nkeynes@1097
   393
    device->ref_count = 0;
nkeynes@1097
   394
    device->type = type;
nkeynes@1097
   395
    device->mode = mode;
nkeynes@1097
   396
    device->size = size;
nkeynes@1097
   397
    device->read_blocks = readfn;
nkeynes@1097
   398
    device->read_sectors = default_sector_source_read_sectors;
nkeynes@1097
   399
    if( destroyfn == NULL )
nkeynes@1097
   400
        device->destroy = default_sector_source_destroy;
nkeynes@1097
   401
    else
nkeynes@1097
   402
        device->destroy = destroyfn;
nkeynes@1097
   403
    return device;
nkeynes@1097
   404
}
nkeynes@1097
   405
nkeynes@1097
   406
/************************ Null device implementation *************************/
nkeynes@1097
   407
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
   408
{
nkeynes@1097
   409
    memset( buf, 0,  block_count*CDROM_SECTOR_SIZE(device->mode) );
nkeynes@1097
   410
    return CDROM_ERROR_OK;
nkeynes@1097
   411
}
nkeynes@1097
   412
nkeynes@1097
   413
sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )
nkeynes@1097
   414
{
nkeynes@1097
   415
    return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,
nkeynes@1097
   416
            null_sector_source_read, default_sector_source_destroy );
nkeynes@1097
   417
}
nkeynes@1097
   418
nkeynes@1097
   419
/************************ File device implementation *************************/
nkeynes@1097
   420
typedef struct file_sector_source {
nkeynes@1097
   421
    struct sector_source dev;
nkeynes@1097
   422
    FILE *file;
nkeynes@1097
   423
    uint32_t offset; /* offset in file where source begins */
nkeynes@1097
   424
    sector_source_t ref; /* Parent source reference */
nkeynes@1097
   425
    gboolean closeOnDestroy;
nkeynes@1097
   426
} *file_sector_source_t;
nkeynes@1097
   427
nkeynes@1097
   428
void file_sector_source_destroy( sector_source_t dev )
nkeynes@1097
   429
{
nkeynes@1097
   430
    assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
nkeynes@1097
   431
    file_sector_source_t fdev = (file_sector_source_t)dev;
nkeynes@1097
   432
nkeynes@1097
   433
    if( fdev->closeOnDestroy && fdev->file != NULL ) {
nkeynes@1097
   434
        fclose( fdev->file );
nkeynes@1097
   435
    }
nkeynes@1097
   436
    sector_source_unref( fdev->ref );
nkeynes@1097
   437
    fdev->file = NULL;
nkeynes@1097
   438
    default_sector_source_destroy(dev);
nkeynes@1097
   439
}
nkeynes@1097
   440
nkeynes@1097
   441
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
   442
{
nkeynes@1097
   443
    assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
nkeynes@1097
   444
    file_sector_source_t fdev = (file_sector_source_t)dev;
nkeynes@1097
   445
nkeynes@1097
   446
    uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);
nkeynes@1097
   447
    uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
nkeynes@1097
   448
    fseek( fdev->file, off, SEEK_SET );
nkeynes@1097
   449
nkeynes@1097
   450
    size_t len = fread( buf, 1, size, fdev->file );
nkeynes@1097
   451
    if( len == -1 ) {
nkeynes@1097
   452
        return CDROM_ERROR_READERROR;
nkeynes@1097
   453
    } else if( len < size ) {
nkeynes@1097
   454
        /* zero-fill */
nkeynes@1097
   455
        memset( buf + len, 0, size-len );
nkeynes@1097
   456
    }
nkeynes@1097
   457
    return CDROM_ERROR_OK;
nkeynes@1097
   458
}
nkeynes@1097
   459
nkeynes@1097
   460
sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   461
                                        cdrom_count_t sector_count, gboolean closeOnDestroy )
nkeynes@1097
   462
{
nkeynes@1097
   463
    if( sector_count == FILE_SECTOR_FULL_FILE ) {
nkeynes@1097
   464
        unsigned int sector_size = CDROM_SECTOR_SIZE(mode);
nkeynes@1097
   465
        if( sector_size == 0 )
nkeynes@1097
   466
            sector_size = 2048;
nkeynes@1097
   467
        struct stat st;
nkeynes@1097
   468
nkeynes@1097
   469
        if( f == NULL || fstat( fileno(f), &st ) != 0 ) {
nkeynes@1097
   470
            /* can't stat file? */
nkeynes@1097
   471
            return NULL;
nkeynes@1097
   472
        }
nkeynes@1097
   473
nkeynes@1097
   474
        sector_count = (st.st_size + sector_size-1) / sector_size;
nkeynes@1097
   475
    }
nkeynes@1097
   476
nkeynes@1097
   477
    file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));
nkeynes@1097
   478
    dev->file = f;
nkeynes@1097
   479
    dev->offset = offset;
nkeynes@1097
   480
    dev->closeOnDestroy = closeOnDestroy;
nkeynes@1097
   481
    dev->ref = NULL;
nkeynes@1097
   482
    return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode,  sector_count, file_sector_source_read, file_sector_source_destroy );
nkeynes@1097
   483
}
nkeynes@1097
   484
nkeynes@1097
   485
sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )
nkeynes@1097
   486
{
nkeynes@1097
   487
    return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );
nkeynes@1097
   488
}
nkeynes@1097
   489
nkeynes@1097
   490
sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   491
                                                 cdrom_count_t sector_count )
nkeynes@1097
   492
{
nkeynes@1097
   493
    int fd = open( filename, O_RDONLY|O_NONBLOCK );
nkeynes@1097
   494
    if( fd == -1 ) {
nkeynes@1097
   495
        return NULL;
nkeynes@1097
   496
    }
nkeynes@1097
   497
    FILE *f = fdopen( fd , "ro" );
nkeynes@1097
   498
    if( f == NULL ) {
nkeynes@1097
   499
        close(fd);
nkeynes@1097
   500
        return NULL;
nkeynes@1097
   501
    } else {
nkeynes@1097
   502
        return file_sector_source_new( f, mode, offset, sector_count, TRUE );
nkeynes@1097
   503
    }
nkeynes@1097
   504
}
nkeynes@1097
   505
nkeynes@1097
   506
sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   507
                                               cdrom_count_t sector_count )
nkeynes@1097
   508
{
nkeynes@1097
   509
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   510
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   511
nkeynes@1097
   512
    sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );
nkeynes@1097
   513
    ((file_sector_source_t)source)->ref = ref;
nkeynes@1097
   514
    sector_source_ref(ref);
nkeynes@1097
   515
    return source;
nkeynes@1097
   516
}
nkeynes@1097
   517
nkeynes@1097
   518
FILE *file_sector_source_get_file( sector_source_t ref )
nkeynes@1097
   519
{
nkeynes@1097
   520
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   521
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   522
    return fref->file;
nkeynes@1097
   523
}
nkeynes@1097
   524
nkeynes@1097
   525
int file_sector_source_get_fd( sector_source_t ref )
nkeynes@1097
   526
{
nkeynes@1097
   527
    return fileno(file_sector_source_get_file(ref));
nkeynes@1097
   528
}
nkeynes@1097
   529
nkeynes@1097
   530
void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )
nkeynes@1097
   531
{
nkeynes@1097
   532
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   533
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   534
    fref->closeOnDestroy = closeOnDestroy;
nkeynes@1097
   535
}
nkeynes@1097
   536
nkeynes@1097
   537
/************************ Track device implementation *************************/
nkeynes@1097
   538
typedef struct track_sector_source {
nkeynes@1097
   539
    struct sector_source dev;
nkeynes@1097
   540
    cdrom_disc_t disc;
nkeynes@1097
   541
    uint32_t start_lba;
nkeynes@1097
   542
} *track_sector_source_t;
nkeynes@1097
   543
nkeynes@1097
   544
cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
nkeynes@1097
   545
                                               unsigned char *out )
nkeynes@1097
   546
{
nkeynes@1097
   547
    size_t length;
nkeynes@1097
   548
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   549
    assert( dev->mode != SECTOR_UNKNOWN );
nkeynes@1097
   550
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   551
    return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );
nkeynes@1097
   552
}
nkeynes@1097
   553
nkeynes@1097
   554
cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
nkeynes@1097
   555
                                                cdrom_read_mode_t mode, unsigned char *out, size_t *length )
nkeynes@1097
   556
{
nkeynes@1097
   557
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   558
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   559
nkeynes@1097
   560
    return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );
nkeynes@1097
   561
}
nkeynes@1097
   562
nkeynes@1097
   563
void track_sector_source_destroy( sector_source_t dev )
nkeynes@1097
   564
{
nkeynes@1097
   565
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   566
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   567
    sector_source_unref( &tdev->disc->source );
nkeynes@1097
   568
    default_sector_source_destroy(dev);
nkeynes@1097
   569
}
nkeynes@1097
   570
nkeynes@1097
   571
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
   572
{
nkeynes@1097
   573
    if( disc == NULL ) {
nkeynes@1097
   574
        return NULL;
nkeynes@1097
   575
    }
nkeynes@1097
   576
    track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));
nkeynes@1097
   577
    dev->disc = disc;
nkeynes@1097
   578
    dev->start_lba = lba;
nkeynes@1097
   579
    sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,
nkeynes@1097
   580
                        track_sector_source_read_blocks, track_sector_source_destroy );
nkeynes@1097
   581
    dev->dev.read_sectors = track_sector_source_read_sectors;
nkeynes@1097
   582
    sector_source_ref( &disc->source );
nkeynes@1097
   583
    return &dev->dev;
nkeynes@1097
   584
}
.