Search
lxdream.org :: lxdream/src/gdrom/gdimage.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/gdimage.c
changeset 1023:264e2fd90be8
prev840:c6a778c228a6
next1030:864417a57662
author nkeynes
date Mon Jun 08 04:12:21 2009 +0000 (11 years ago)
permissions -rw-r--r--
last change General cleanup of the GD-rom subsystem
- merge gdrom_image_t and gdrom_disc_t
- Abstract MMC devices using a lower-level scsi transport
- OSX: only look at the whole disc device, and ignore partitions
file annotate diff log raw
1.1 --- a/src/gdrom/gdimage.c Tue Sep 02 03:34:23 2008 +0000
1.2 +++ b/src/gdrom/gdimage.c Mon Jun 08 04:12:21 2009 +0000
1.3 @@ -21,20 +21,17 @@
1.4 #include <string.h>
1.5 #include <ctype.h>
1.6 #include <sys/types.h>
1.7 +#include <sys/stat.h>
1.8 +#include <fcntl.h>
1.9 #include <netinet/in.h>
1.10
1.11 #include "gdrom/gddriver.h"
1.12 #include "gdrom/packet.h"
1.13 #include "ecc.h"
1.14 -#include "bootstrap.h"
1.15
1.16 -static void gdrom_image_destroy( gdrom_disc_t disc );
1.17 +static gboolean gdrom_null_check_status( gdrom_disc_t disc );
1.18 static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba, int mode,
1.19 unsigned char *buf, uint32_t *readlength );
1.20 -static gdrom_error_t gdrom_image_read_toc( gdrom_disc_t disc, unsigned char *buf );
1.21 -static gdrom_error_t gdrom_image_read_session( gdrom_disc_t disc, int session, unsigned char *buf );
1.22 -static gdrom_error_t gdrom_image_read_position( gdrom_disc_t disc, uint32_t lba, unsigned char *buf );
1.23 -static int gdrom_image_drive_status( gdrom_disc_t disc );
1.24
1.25 static uint8_t gdrom_default_sync[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
1.26
1.27 @@ -44,7 +41,11 @@
1.28 /* Data offset (from start of raw sector) by sector mode */
1.29 static int gdrom_data_offset[] = { 16, 16, 16, 24, 24, 0, 8, 0, 0 };
1.30
1.31 -
1.32 +gdrom_image_class_t gdrom_image_classes[] = { &cdrom_device_class,
1.33 + &nrg_image_class,
1.34 + &cdi_image_class,
1.35 + &gdi_image_class,
1.36 + NULL };
1.37
1.38 struct cdrom_sector_header {
1.39 uint8_t sync[12];
1.40 @@ -53,96 +54,139 @@
1.41 uint8_t subhead[8]; // Mode-2 XA sectors only
1.42 };
1.43
1.44 -/**
1.45 - * Initialize a gdrom_disc structure with the gdrom_image_* methods
1.46 - */
1.47 -void gdrom_image_init( gdrom_disc_t disc )
1.48 +gdrom_disc_t gdrom_disc_new( const gchar *filename, FILE *f )
1.49 {
1.50 - memset( disc, 0, sizeof(struct gdrom_disc) ); /* safety */
1.51 - disc->read_sector = gdrom_image_read_sector;
1.52 - disc->read_toc = gdrom_image_read_toc;
1.53 - disc->read_session = gdrom_image_read_session;
1.54 - disc->read_position = gdrom_image_read_position;
1.55 - disc->drive_status = gdrom_image_drive_status;
1.56 - disc->play_audio = NULL; /* not supported yet */
1.57 - disc->run_time_slice = NULL; /* not needed */
1.58 - disc->close = gdrom_image_destroy;
1.59 -}
1.60 -
1.61 -gdrom_disc_t gdrom_image_new( const gchar *filename, FILE *f )
1.62 -{
1.63 - gdrom_image_t image = (gdrom_image_t)g_malloc0(sizeof(struct gdrom_image));
1.64 - if( image == NULL ) {
1.65 + gdrom_disc_t disc = (gdrom_disc_t)g_malloc0(sizeof(struct gdrom_disc));
1.66 + if( disc == NULL ) {
1.67 return NULL;
1.68 }
1.69 - image->disc_type = IDE_DISC_CDROMXA;
1.70 - image->file = f;
1.71 - gdrom_disc_t disc = (gdrom_disc_t)image;
1.72 - gdrom_image_init(disc);
1.73 + disc->disc_type = IDE_DISC_NONE;
1.74 + disc->file = f;
1.75 if( filename == NULL ) {
1.76 disc->name = NULL;
1.77 } else {
1.78 disc->name = g_strdup(filename);
1.79 }
1.80
1.81 + disc->check_status = gdrom_null_check_status;
1.82 + disc->destroy = gdrom_disc_destroy;
1.83 return disc;
1.84 }
1.85
1.86 -static void gdrom_image_destroy( gdrom_disc_t disc )
1.87 +void gdrom_disc_destroy( gdrom_disc_t disc, gboolean close_fh )
1.88 {
1.89 int i;
1.90 FILE *lastfile = NULL;
1.91 - gdrom_image_t img = (gdrom_image_t)disc;
1.92 - if( img->file != NULL ) {
1.93 - fclose(img->file);
1.94 - img->file = NULL;
1.95 + if( disc->file != NULL ) {
1.96 + if( close_fh ) {
1.97 + fclose(disc->file);
1.98 + }
1.99 + disc->file = NULL;
1.100 }
1.101 - for( i=0; i<img->track_count; i++ ) {
1.102 - if( img->track[i].file != NULL && img->track[i].file != lastfile ) {
1.103 - lastfile = img->track[i].file;
1.104 + for( i=0; i<disc->track_count; i++ ) {
1.105 + if( disc->track[i].file != NULL && disc->track[i].file != lastfile ) {
1.106 + lastfile = disc->track[i].file;
1.107 + /* Track files (if any) are closed regardless of the value of close_fh */
1.108 fclose(lastfile);
1.109 - img->track[i].file = NULL;
1.110 + disc->track[i].file = NULL;
1.111 }
1.112 }
1.113 if( disc->name != NULL ) {
1.114 g_free( (gpointer)disc->name );
1.115 disc->name = NULL;
1.116 }
1.117 - free( disc );
1.118 -}
1.119 -
1.120 -void gdrom_image_destroy_no_close( gdrom_disc_t disc )
1.121 -{
1.122 - int i;
1.123 - FILE *lastfile = NULL;
1.124 - gdrom_image_t img = (gdrom_image_t)disc;
1.125 - if( img->file != NULL ) {
1.126 - img->file = NULL;
1.127 - }
1.128 - for( i=0; i<img->track_count; i++ ) {
1.129 - if( img->track[i].file != NULL && img->track[i].file != lastfile ) {
1.130 - lastfile = img->track[i].file;
1.131 - fclose(lastfile);
1.132 - img->track[i].file = NULL;
1.133 - }
1.134 - }
1.135 - if( disc->name != NULL ) {
1.136 - g_free( (gpointer)disc->name );
1.137 - disc->name = NULL;
1.138 + if( disc->display_name != NULL ) {
1.139 + g_free( (gpointer)disc->name );
1.140 + disc->display_name = NULL;
1.141 }
1.142 free( disc );
1.143 }
1.144
1.145 -int gdrom_image_get_track_by_lba( gdrom_image_t image, uint32_t lba )
1.146 +/**
1.147 + * Construct a new gdrom_disc_t and initalize the vtable to the gdrom image
1.148 + * default functions.
1.149 + */
1.150 +gdrom_disc_t gdrom_image_new( const gchar *filename, FILE *f )
1.151 {
1.152 + gdrom_disc_t disc = gdrom_disc_new( filename, f );
1.153 + if( disc != NULL ) {
1.154 + disc->read_sector = gdrom_image_read_sector;
1.155 + disc->play_audio = NULL; /* not supported yet */
1.156 + disc->run_time_slice = NULL; /* not needed */
1.157 + }
1.158 +}
1.159 +
1.160 +
1.161 +gdrom_disc_t gdrom_image_open( const gchar *inFilename )
1.162 +{
1.163 + const gchar *filename = inFilename;
1.164 + const gchar *ext = strrchr(filename, '.');
1.165 + gdrom_disc_t disc = NULL;
1.166 + int fd;
1.167 + FILE *f;
1.168 int i;
1.169 - for( i=0; i<image->track_count; i++ ) {
1.170 - if( image->track[i].lba <= lba &&
1.171 - lba < (image->track[i].lba + image->track[i].sector_count) ) {
1.172 - return i+1;
1.173 + gdrom_image_class_t extclz = NULL;
1.174 +
1.175 + // Check for a url-style filename.
1.176 + char *lizard_lips = strstr( filename, "://" );
1.177 + if( lizard_lips != NULL ) {
1.178 + gchar *path = lizard_lips + 3;
1.179 + int method_len = (lizard_lips-filename);
1.180 + gchar method[method_len + 1];
1.181 + memcpy( method, filename, method_len );
1.182 + method[method_len] = '\0';
1.183 +
1.184 + if( strcasecmp( method, "file" ) == 0 ) {
1.185 + filename = path;
1.186 + } else if( strcasecmp( method, "dvd" ) == 0 ||
1.187 + strcasecmp( method, "cd" ) == 0 ||
1.188 + strcasecmp( method, "cdrom" ) ) {
1.189 + return cdrom_open_device( method, path );
1.190 + } else {
1.191 + ERROR( "Unrecognized URL method '%s' in filename '%s'", method, filename );
1.192 + return NULL;
1.193 }
1.194 }
1.195 - return -1;
1.196 +
1.197 + fd = open( filename, O_RDONLY | O_NONBLOCK );
1.198 + if( fd == -1 ) {
1.199 + return NULL;
1.200 + }
1.201 +
1.202 + f = fdopen(fd, "ro");
1.203 +
1.204 +
1.205 + /* try extensions */
1.206 + if( ext != NULL ) {
1.207 + ext++; /* Skip the '.' */
1.208 + for( i=0; gdrom_image_classes[i] != NULL; i++ ) {
1.209 + if( gdrom_image_classes[i]->extension != NULL &&
1.210 + strcasecmp( gdrom_image_classes[i]->extension, ext ) == 0 ) {
1.211 + extclz = gdrom_image_classes[i];
1.212 + if( extclz->is_valid_file(f) ) {
1.213 + disc = extclz->open_image_file(filename, f);
1.214 + if( disc != NULL )
1.215 + return disc;
1.216 + }
1.217 + break;
1.218 + }
1.219 + }
1.220 + }
1.221 +
1.222 + /* Okay, fall back to magic */
1.223 + gboolean recognized = FALSE;
1.224 + for( i=0; gdrom_image_classes[i] != NULL; i++ ) {
1.225 + if( gdrom_image_classes[i] != extclz &&
1.226 + gdrom_image_classes[i]->is_valid_file(f) ) {
1.227 + recognized = TRUE;
1.228 + disc = gdrom_image_classes[i]->open_image_file(filename, f);
1.229 + if( disc != NULL )
1.230 + return disc;
1.231 + }
1.232 + }
1.233 +
1.234 + fclose(f);
1.235 + return NULL;
1.236 }
1.237
1.238 /**
1.239 @@ -247,6 +291,15 @@
1.240 }
1.241
1.242 /**
1.243 + * Default check media status that does nothing and always returns
1.244 + * false (unchanged).
1.245 + */
1.246 +static gboolean gdrom_null_check_status( gdrom_disc_t disc )
1.247 +{
1.248 + return FALSE;
1.249 +}
1.250 +
1.251 +/**
1.252 * Read a single sector from a disc image. If you thought this would be simple,
1.253 * I have just one thing to say to you: Bwahahahahahahahah.
1.254 *
1.255 @@ -264,23 +317,22 @@
1.256 static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba,
1.257 int mode, unsigned char *buf, uint32_t *length )
1.258 {
1.259 - gdrom_image_t image = (gdrom_image_t)disc;
1.260 struct cdrom_sector_header secthead;
1.261 int file_offset, read_len, track_no;
1.262
1.263 FILE *f;
1.264
1.265 - track_no = gdrom_image_get_track_by_lba( image, lba );
1.266 + track_no = gdrom_disc_get_track_by_lba( disc, lba );
1.267 if( track_no == -1 ) {
1.268 return PKT_ERR_BADREAD;
1.269 }
1.270 - struct gdrom_track *track = &image->track[track_no-1];
1.271 + struct gdrom_track *track = &disc->track[track_no-1];
1.272 file_offset = track->offset + track->sector_size * (lba - track->lba);
1.273 read_len = track->sector_size;
1.274 if( track->file != NULL ) {
1.275 f = track->file;
1.276 } else {
1.277 - f = image->file;
1.278 + f = disc->file;
1.279 }
1.280
1.281 /* First figure out what the real sector mode is for raw/semiraw sectors */
1.282 @@ -387,142 +439,3 @@
1.283 return PKT_ERR_OK;
1.284 }
1.285
1.286 -static gdrom_error_t gdrom_image_read_toc( gdrom_disc_t disc, unsigned char *buf )
1.287 -{
1.288 - gdrom_image_t image = (gdrom_image_t)disc;
1.289 - struct gdrom_toc *toc = (struct gdrom_toc *)buf;
1.290 - int i;
1.291 -
1.292 - for( i=0; i<image->track_count; i++ ) {
1.293 - toc->track[i] = htonl( image->track[i].lba ) | image->track[i].flags;
1.294 - }
1.295 - toc->first = 0x0100 | image->track[0].flags;
1.296 - toc->last = (image->track_count<<8) | image->track[i-1].flags;
1.297 - toc->leadout = htonl(image->track[i-1].lba + image->track[i-1].sector_count) |
1.298 - image->track[i-1].flags;
1.299 - for( ;i<99; i++ )
1.300 - toc->track[i] = 0xFFFFFFFF;
1.301 - return PKT_ERR_OK;
1.302 -}
1.303 -
1.304 -static gdrom_error_t gdrom_image_read_session( gdrom_disc_t disc, int session, unsigned char *buf )
1.305 -{
1.306 - gdrom_image_t image = (gdrom_image_t)disc;
1.307 - struct gdrom_track *last_track = &image->track[image->track_count-1];
1.308 - unsigned int end_of_disc = last_track->lba + last_track->sector_count;
1.309 - int i;
1.310 - buf[0] = 0x01; /* Disc status? */
1.311 - buf[1] = 0;
1.312 -
1.313 - if( session == 0 ) {
1.314 - buf[2] = last_track->session+1; /* last session */
1.315 - buf[3] = (end_of_disc >> 16) & 0xFF;
1.316 - buf[4] = (end_of_disc >> 8) & 0xFF;
1.317 - buf[5] = end_of_disc & 0xFF;
1.318 - return PKT_ERR_OK;
1.319 - } else {
1.320 - session--;
1.321 - for( i=0; i<image->track_count; i++ ) {
1.322 - if( image->track[i].session == session ) {
1.323 - buf[2] = i+1; /* first track of session */
1.324 - buf[3] = (image->track[i].lba >> 16) & 0xFF;
1.325 - buf[4] = (image->track[i].lba >> 8) & 0xFF;
1.326 - buf[5] = image->track[i].lba & 0xFF;
1.327 - return PKT_ERR_OK;
1.328 - }
1.329 - }
1.330 - return PKT_ERR_BADFIELD; /* No such session */
1.331 - }
1.332 -}
1.333 -
1.334 -static gdrom_error_t gdrom_image_read_position( gdrom_disc_t disc, uint32_t lba, unsigned char *buf )
1.335 -{
1.336 - gdrom_image_t image = (gdrom_image_t)disc;
1.337 - int track_no = gdrom_image_get_track_by_lba( image, lba );
1.338 - if( track_no == -1 ) {
1.339 - track_no = 1;
1.340 - lba = 150;
1.341 - }
1.342 - struct gdrom_track *track = &image->track[track_no-1];
1.343 - uint32_t offset = lba - track->lba;
1.344 - buf[4] = track->flags;
1.345 - buf[5] = track_no;
1.346 - buf[6] = 0x01; /* ?? */
1.347 - buf[7] = (offset >> 16) & 0xFF;
1.348 - buf[8] = (offset >> 8) & 0xFF;
1.349 - buf[9] = offset & 0xFF;
1.350 - buf[10] = 0;
1.351 - buf[11] = (lba >> 16) & 0xFF;
1.352 - buf[12] = (lba >> 8) & 0xFF;
1.353 - buf[13] = lba & 0xFF;
1.354 - return PKT_ERR_OK;
1.355 -}
1.356 -
1.357 -static int gdrom_image_drive_status( gdrom_disc_t disc )
1.358 -{
1.359 - gdrom_image_t image = (gdrom_image_t)disc;
1.360 - if( image->disc_type == IDE_DISC_NONE ) {
1.361 - return IDE_DISC_NONE;
1.362 - } else {
1.363 - return image->disc_type | IDE_DISC_READY;
1.364 - }
1.365 -}
1.366 -
1.367 -gdrom_device_t gdrom_device_new( const gchar *name, const gchar *dev_name )
1.368 -{
1.369 - struct gdrom_device *dev = g_malloc0( sizeof(struct gdrom_device) );
1.370 - dev->name = g_strdup(name);
1.371 - dev->device_name = g_strdup(dev_name);
1.372 - return dev;
1.373 -}
1.374 -
1.375 -void gdrom_device_destroy( gdrom_device_t dev )
1.376 -{
1.377 - if( dev->name != NULL ) {
1.378 - g_free( dev->name );
1.379 - dev->name = NULL;
1.380 - }
1.381 - if( dev->device_name != NULL ) {
1.382 - g_free( dev->device_name );
1.383 - dev->device_name = NULL;
1.384 - }
1.385 - g_free( dev );
1.386 -}
1.387 -
1.388 -/**
1.389 - * Check the disc for a useable DC bootstrap, and update the disc
1.390 - * with the title accordingly.
1.391 - * @return TRUE if we found a bootstrap, otherwise FALSE.
1.392 - */
1.393 -gboolean gdrom_image_read_info( gdrom_disc_t d ) {
1.394 - gdrom_image_t disc = (gdrom_image_t)d;
1.395 - if( disc->track_count > 0 ) {
1.396 - /* Find the first data track of the last session */
1.397 - int last_session = disc->track[disc->track_count-1].session;
1.398 - int i, boot_track = -1;
1.399 - for( i=disc->track_count-1; i>=0 && disc->track[i].session == last_session; i-- ) {
1.400 - if( disc->track[i].flags & TRACK_DATA ) {
1.401 - boot_track = i;
1.402 - }
1.403 - }
1.404 - if( boot_track != -1 ) {
1.405 - unsigned char boot_sector[MAX_SECTOR_SIZE];
1.406 - uint32_t length = sizeof(boot_sector);
1.407 - if( d->read_sector( d, disc->track[boot_track].lba, 0x28,
1.408 - boot_sector, &length ) == PKT_ERR_OK ) {
1.409 - if( memcmp( boot_sector, "SEGA SEGAKATANA SEGA ENTERPRISES", 32) == 0 ) {
1.410 - /* Got magic */
1.411 - memcpy( d->title, boot_sector+128, 128 );
1.412 - for( i=127; i>=0; i-- ) {
1.413 - if( !isspace(d->title[i]) )
1.414 - break;
1.415 - }
1.416 - d->title[i+1] = '\0';
1.417 - }
1.418 - bootstrap_dump(boot_sector, FALSE);
1.419 - return TRUE;
1.420 - }
1.421 - }
1.422 - }
1.423 - return FALSE;
1.424 -}
.