filename | src/gdrom/cdi.c |
changeset | 759:f16975739abc |
prev | 736:a02d1475ccfd |
next | 999:3d19e3597d9b |
author | nkeynes |
date | Wed Nov 05 10:05:08 2008 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Fix (extremely boneheaded) failure to convert pc to physical address before storing in the translation cache (in other words, the translation cache was effectively disabled for MMU code). MMU code is now about 3 times faster... |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * CDI CD-image file support
5 *
6 * Copyright (c) 2005 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <sys/stat.h>
26 #include "gdrom/gddriver.h"
28 #define CDI_V2_ID 0x80000004
29 #define CDI_V3_ID 0x80000005
30 #define CDI_V35_ID 0x80000006
33 static gboolean cdi_image_is_valid( FILE *f );
34 static gdrom_disc_t cdi_image_open( const gchar *filename, FILE *f );
36 struct gdrom_image_class cdi_image_class = { "DiscJuggler", "cdi",
37 cdi_image_is_valid, cdi_image_open };
39 static const char TRACK_START_MARKER[20] = { 0,0,1,0,0,0,255,255,255,255,
40 0,0,1,0,0,0,255,255,255,255 };
41 static const char EXT_MARKER[9] = {0,255,255,255,255,255,255,255,255 };
43 struct cdi_trailer {
44 uint32_t cdi_version;
45 uint32_t header_offset;
46 };
48 struct cdi_track_data {
49 uint32_t pregap_length;
50 uint32_t length;
51 char unknown2[6];
52 uint32_t mode;
53 char unknown3[0x0c];
54 uint32_t start_lba;
55 uint32_t total_length;
56 char unknown4[0x10];
57 uint32_t sector_size;
58 char unknown5[0x1D];
59 } __attribute__((packed));
61 gboolean cdi_image_is_valid( FILE *f )
62 {
63 int len;
64 struct cdi_trailer trail;
66 fseek( f, -8, SEEK_END );
67 len = ftell(f)+8;
68 fread( &trail, sizeof(trail), 1, f );
69 if( trail.header_offset >= len ||
70 trail.header_offset == 0 )
71 return FALSE;
72 return trail.cdi_version == CDI_V2_ID || trail.cdi_version == CDI_V3_ID ||
73 trail.cdi_version == CDI_V35_ID;
74 }
76 gdrom_disc_t cdi_image_open( const gchar *filename, FILE *f )
77 {
78 gdrom_disc_t disc = NULL;
79 gdrom_image_t image;
80 int i,j;
81 uint16_t session_count;
82 uint16_t track_count;
83 int total_tracks = 0;
84 int posn = 0;
85 long len;
86 struct cdi_trailer trail;
87 char marker[20];
89 fseek( f, -8, SEEK_END );
90 len = ftell(f)+8;
91 fread( &trail, sizeof(trail), 1, f );
92 if( trail.header_offset >= len ||
93 trail.header_offset == 0 )
94 return NULL;
96 if( trail.cdi_version != CDI_V2_ID && trail.cdi_version != CDI_V3_ID &&
97 trail.cdi_version != CDI_V35_ID ) {
98 return NULL;
99 }
101 if( trail.cdi_version == CDI_V35_ID ) {
102 fseek( f, -trail.header_offset, SEEK_END );
103 } else {
104 fseek( f, trail.header_offset, SEEK_SET );
105 }
106 fread( &session_count, sizeof(session_count), 1, f );
108 disc = gdrom_image_new(filename, f);
109 if( disc == NULL ) {
110 ERROR("Unable to allocate memory!");
111 return NULL;
112 }
113 image = (gdrom_image_t)disc;
115 for( i=0; i< session_count; i++ ) {
116 fread( &track_count, sizeof(track_count), 1, f );
117 if( track_count + total_tracks > 99 ) {
118 ERROR( "Invalid number of tracks, bad cdi image\n" );
119 gdrom_image_destroy_no_close(disc);
120 return NULL;
121 }
122 for( j=0; j<track_count; j++ ) {
123 struct cdi_track_data trk;
124 uint32_t new_fmt = 0;
125 uint8_t fnamelen = 0;
126 fread( &new_fmt, sizeof(new_fmt), 1, f );
127 if( new_fmt != 0 ) { /* Additional data 3.00.780+ ?? */
128 fseek( f, 8, SEEK_CUR ); /* Skip */
129 }
130 fread( marker, 20, 1, f );
131 if( memcmp( marker, TRACK_START_MARKER, 20) != 0 ) {
132 ERROR( "Track start marker not found, error reading cdi image\n" );
133 gdrom_image_destroy_no_close(disc);
134 return NULL;
135 }
136 fseek( f, 4, SEEK_CUR );
137 fread( &fnamelen, 1, 1, f );
138 fseek( f, (int)fnamelen, SEEK_CUR ); /* skip over the filename */
139 fseek( f, 19, SEEK_CUR );
140 fread( &new_fmt, sizeof(new_fmt), 1, f );
141 if( new_fmt == 0x80000000 ) {
142 fseek( f, 10, SEEK_CUR );
143 } else {
144 fseek( f, 2, SEEK_CUR );
145 }
146 fread( &trk, sizeof(trk), 1, f );
147 image->track[total_tracks].session = i;
148 image->track[total_tracks].lba = trk.start_lba + 150;
149 image->track[total_tracks].sector_count = trk.length;
150 switch( trk.mode ) {
151 case 0:
152 image->track[total_tracks].mode = GDROM_CDDA;
153 image->track[total_tracks].sector_size = 2352;
154 image->track[total_tracks].flags = 0x01;
155 if( trk.sector_size != 2 ) {
156 ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
157 gdrom_image_destroy_no_close(disc);
158 return NULL;
159 }
160 break;
161 case 1:
162 image->track[total_tracks].mode = GDROM_MODE1;
163 image->track[total_tracks].sector_size = 2048;
164 image->track[total_tracks].flags = 0x41;
165 if( trk.sector_size != 0 ) {
166 ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
167 gdrom_image_destroy_no_close(disc);
168 return NULL;
169 }
170 break;
171 case 2:
172 image->track[total_tracks].flags = 0x41;
173 switch( trk.sector_size ) {
174 case 0:
175 image->track[total_tracks].mode = GDROM_MODE2_FORM1;
176 image->track[total_tracks].sector_size = 2048;
177 break;
178 case 1:
179 image->track[total_tracks].mode = GDROM_SEMIRAW_MODE2;
180 image->track[total_tracks].sector_size = 2336;
181 break;
182 case 2:
183 default:
184 ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
185 gdrom_image_destroy_no_close(disc);
186 return NULL;
187 }
188 break;
189 default:
190 ERROR( "Unsupported track mode %d", trk.mode );
191 gdrom_image_destroy_no_close(disc);
192 return NULL;
193 }
194 image->track[total_tracks].offset = posn +
195 trk.pregap_length * image->track[total_tracks].sector_size ;
196 posn += trk.total_length * image->track[total_tracks].sector_size;
197 total_tracks++;
198 fread( marker, 1, 9, f );
199 if( memcmp( marker, EXT_MARKER, 9 ) == 0 ) {
200 fseek( f, 79, SEEK_CUR );
201 } else {
202 fseek( f, -9, SEEK_CUR );
203 }
204 }
205 fseek( f, 12, SEEK_CUR );
206 }
207 image->track_count = total_tracks;
208 return disc;
209 }
.