]> Shamusworld >> Repos - virtualjaguar/blob - src/cdi.cpp
0e737dccb466a75c1c32cd705245ac71b7b4532f
[virtualjaguar] / src / cdi.cpp
1 //
2 // CD Interface handler
3 //
4 // by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Cleanups by James L. Hammons
7 //
8
9 #include "cdi.h"
10
11 /* Added by SDLEMU (http://sdlemu.ngemu.com) */
12 /* Added for GCC UNIX compatibility          */
13 #ifdef __GCCUNIX__
14 #include <unistd.h>
15 #include <sys/types.h>
16 #include <fcntl.h>
17
18 #define O_BINARY (0)
19 #endif
20
21 #define CDI_V2  0x80000004
22 #define CDI_V3  0x80000005
23 #define CDI_V35 0x80000006
24
25 static uint8 cdi_track_start_mark[10] =
26         { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
27
28 int cdi_fp;
29 uint32 cdi_load_address;
30 uint32 cdi_code_length;
31 s_cdi_descriptor * cdi_descriptor;
32 s_cdi_track ** cdi_tracks;
33 uint32 cdi_tracks_count;
34
35
36 int cdi_open(char * path)
37 {
38         WriteLog("CDI: Opening %s\n", path);
39         return open(path, O_BINARY | O_RDONLY);
40 }
41
42 void cdi_close(int fp)
43 {
44         WriteLog("CDI: Closing\n");
45         close(fp);
46 }
47
48
49 /*long tell(int fd)
50 {
51         return lseek(fd, 0LL, SEEK_CUR);
52 }*/
53
54
55 s_cdi_descriptor * cdi_get_descriptor(int fp, FILE * stdfp)
56 {
57         s_cdi_descriptor * descriptor;
58         uint32 previous_position = 0;
59
60         if (fp == -1)
61                 return 0;
62
63         descriptor = (s_cdi_descriptor *)malloc(sizeof(s_cdi_descriptor));
64
65         if (descriptor == NULL)
66                 return 0;
67
68         lseek(fp, 0, SEEK_END);
69 //Why???        descriptor->length=tell(fp);
70         descriptor->length = lseek(fp, 0LL, SEEK_CUR);
71
72         if (descriptor->length < 8)
73         {
74                 if (stdfp)
75                         fprintf(stdfp, "CDI: Image is too short (%i bytes)\n", (int)descriptor->length);
76                 free(descriptor);
77                 return 0;
78         }
79
80         lseek(fp, descriptor->length - 8, SEEK_SET);
81         read(fp, &descriptor->version, 4);
82         read(fp, &descriptor->header_offset, 4);
83         lseek(fp, descriptor->header_offset, SEEK_SET);
84         read(fp, &descriptor->nb_of_sessions, 2);
85
86         descriptor->sessions=(s_cdi_session *)malloc(descriptor->nb_of_sessions * sizeof(s_cdi_session));
87
88         if (descriptor->sessions == NULL)
89         {
90                 free(descriptor);
91                 return 0;
92         }
93
94         if (stdfp)
95                 fprintf(stdfp, "CDI: %i sessions\n", descriptor->nb_of_sessions);
96
97         uint32 track_position = 0;
98         for(uint16 session=0; session<descriptor->nb_of_sessions; session++)
99         {
100                 read(fp, &descriptor->sessions[session].nb_of_tracks, 2);
101                 descriptor->sessions[session].tracks = (s_cdi_track *)malloc(descriptor->sessions[session].nb_of_tracks * sizeof(s_cdi_track));
102
103                 if (stdfp)
104                         fprintf(stdfp, "CDI:\nCDI: Reading session %i (%i tracks)\n", session, descriptor->sessions[session].nb_of_tracks);
105
106                 for (uint16 track=0; track<descriptor->sessions[session].nb_of_tracks; track++)
107                 {
108                         static char current_start_mark[10];
109                         s_cdi_track * current_track=&descriptor->sessions[session].tracks[track];
110                         if (stdfp)
111                                 fprintf(stdfp, "CDI:\nCDI: \t\tReading track %i\n",track);
112
113                         uint32 temp_value;
114
115                         read(fp, &temp_value, 4);
116
117                         if (temp_value != 0)
118                                 lseek(fp, 8, SEEK_CUR); // extra data (DJ 3.00.780 and up)
119         
120                         read(fp, current_start_mark, 10);
121
122                         if (memcmp(cdi_track_start_mark, current_start_mark, 10)) 
123                         {
124                                 if (stdfp)
125                                         fprintf(stdfp, "CDI: Could not find the track start mark\n");
126                                 return 0;
127                         }
128
129                         read(fp, current_start_mark, 10);
130
131                         if (memcmp(cdi_track_start_mark, current_start_mark, 10)) 
132                         {
133                                 if (stdfp)
134                                         fprintf(stdfp, "CDI: Could not find the track start mark\n");
135                                 return 0;
136                         }
137
138                         lseek(fp, 4, SEEK_CUR);
139                         read(fp, &current_track->filename_length, 1);
140                         lseek(fp, current_track->filename_length, SEEK_CUR);
141
142                         lseek(fp, 11, SEEK_CUR);
143                         lseek(fp, 4, SEEK_CUR);
144                         lseek(fp, 4, SEEK_CUR);
145                         read(fp, &temp_value, 4);
146
147                         if (temp_value == 0x80000000)
148                                 lseek(fp, 8, SEEK_CUR); // DJ4
149
150                         lseek(fp, 2, SEEK_CUR);
151                         
152                         read(fp, &current_track->pregap_length, 4);
153
154                         if (current_track->pregap_length != 150)
155                                 WriteLog("CDI: Warning: Pregap different than 150\n");
156
157                         read(fp, &current_track->length, 4);
158
159                         if (stdfp)
160                                 fprintf(stdfp, "CDI: \t\t\tPregap length: %i\n", (int)current_track->pregap_length);
161                         if (stdfp)
162                                 fprintf(stdfp, "CDI: \t\t\tLength: %i\n", (int)current_track->length);
163
164                         lseek(fp, 6, SEEK_CUR);
165                         
166                         read(fp, &current_track->mode, 4);
167
168                         if (stdfp)
169                                 fprintf(stdfp, "CDI: \t\t\tMode: %i\n", (int)current_track->mode);
170
171                         lseek(fp, 12, SEEK_CUR);
172                         read(fp, &current_track->start_lba, 4);
173
174                         if (stdfp)
175                                 fprintf(stdfp, "CDI: \t\t\tStart LBA: %i\n", (int)current_track->start_lba);
176
177                         read(fp, &current_track->total_length, 4);
178
179                         if (stdfp)
180                                 fprintf(stdfp, "CDI: \t\t\tTotal length: %i\n", (int)current_track->total_length);
181
182                         lseek(fp, 16, SEEK_CUR);
183                         read(fp, &current_track->sector_size_value, 4);
184
185                         if (stdfp)
186                                 fprintf(stdfp, "CDI: \t\t\tSector size: %i\n", (int)current_track->sector_size_value);
187
188                         switch(current_track->sector_size_value)
189                         {
190                         case 0: current_track->sector_size = 2048; break;
191                         case 1: current_track->sector_size = 2336; break;
192                         case 2: current_track->sector_size = 2352; break;
193                         default:
194                         {
195                                 if (stdfp)
196                                         fprintf(stdfp, "CDI: \t\t\tUnsupported %i bytes sector\n", (int)current_track->sector_size_value);
197                                 return 0;
198                         }
199                         }
200                         
201                         if (current_track->mode > 2)
202                                 if (stdfp)
203                                         fprintf(stdfp, "CDI: \t\t\tTrack mode %i not supported\n", (int)current_track->mode);
204
205                         lseek(fp, 29, SEEK_CUR);
206
207                         if (descriptor->version != CDI_V2)
208                         {
209                                 lseek(fp, 5, SEEK_CUR);
210                                 read(fp, &temp_value, 4);
211
212                                 if (temp_value == 0xFFFFFFFF)
213                                         lseek(fp, 78, SEEK_CUR); // extra data (DJ 3.00.780 and up)
214                         }
215
216                         current_track->position = track_position;
217                         track_position += (current_track->pregap_length+current_track->length) * current_track->sector_size;
218                         previous_position = track_position;
219                 }
220
221                 lseek(fp, 4, SEEK_CUR);
222                 lseek(fp, 8, SEEK_CUR);
223
224                 if (descriptor->version != CDI_V2)
225                         lseek(fp, 1, SEEK_CUR);
226
227         }
228
229     if (descriptor->header_offset == 0) 
230                 return 0;
231
232         return descriptor;
233 }
234
235 void cdi_dump_descriptor(FILE * fp, s_cdi_descriptor * cdi_descriptor)
236 {
237         fprintf(fp, "CDI: %i Mb\n", (int)(cdi_descriptor->length >> 20));
238         fprintf(fp, "CDI: Format version ");
239         switch(cdi_descriptor->version)
240         {
241         case CDI_V2:
242                 fprintf(fp, "2\n");
243                 break;
244         case CDI_V3:
245                 fprintf(fp, "3\n");
246                 break;
247         case CDI_V35:
248                 fprintf(fp, "3.5\n");
249                 break;
250         default:
251                 fprintf(fp, "unknown\n");
252         }
253         fprintf(fp, "CDI: %i sessions\n", cdi_descriptor->nb_of_sessions);
254 }
255
256 uint8 * cdi_extract_boot_code(int fp, s_cdi_descriptor * cdi_descriptor)
257 {
258         s_cdi_track * boot_track = &cdi_descriptor->sessions[1].tracks[0];
259         uint32 boot_track_size = boot_track->length * boot_track->sector_size;
260
261         uint8 * boot_track_data = (uint8 *)malloc(boot_track_size);
262         lseek(fp, 2 + (boot_track->position), SEEK_SET);
263         read(fp, boot_track_data, boot_track_size);
264         
265         uint32 * boot_track_data_32 = (uint32 *)boot_track_data;
266         uint32 offset = 0;
267         while (offset < (boot_track_size >> 2))
268         {
269                 if (boot_track_data_32[offset] == 0x49205452)
270                         break;
271                 offset++;
272         }
273         if (offset == (boot_track_size >> 2))
274         {
275                 WriteLog("CDI: Cannot find the boot code\n");
276                 return NULL;
277         }
278
279 //This is likely wrong, but won't get a chance to fix it until I can get a CD image
280 //to work with...
281         offset = (offset << 2) + 4;
282         uint16 * data16 = (uint16 *)&boot_track_data[offset];
283         cdi_load_address = *data16++;
284         cdi_load_address <<= 16;
285         cdi_load_address |= *data16++;
286         cdi_code_length = *data16++;
287         cdi_code_length <<= 16;
288         cdi_code_length |= *data16++;
289         WriteLog("CDI: Load address: %08X\n", cdi_load_address);
290         WriteLog("CDI: Length: %08X\n", cdi_code_length);
291 //No need for byte swapping any more...
292 /*      WriteLog("cdi: byte swapping boot code\n");
293
294         for(uint32 i=0; i<(cdi_code_length >> 1); i++)
295         {
296                 uint16 sdata = data16[i];
297                 sdata = (sdata >> 8) | (sdata << 8);
298                 data16[i] = sdata;
299         }*/
300
301         return (uint8 *)data16;
302 }
303
304 void cdi_load_sector(uint32 sector, uint8 * buffer)
305 {
306         if (sector == 0xFFFFFFFF)
307         {
308                 memset(buffer, 0x00, 2352);
309                 return;
310         }
311
312         sector *= 2352;
313
314         lseek(cdi_fp, 2+sector, SEEK_SET);
315         read(cdi_fp, buffer, 2352);
316
317 //This is probably not needed any more...
318 /*      // byte swap
319         for (uint32 i=0;i<2352;i+=2)
320         {
321                 uint8 sdata=buffer[i+0];
322                 buffer[i+0]=buffer[i+1];
323                 buffer[i+1]=sdata;
324         }*/
325 }