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