]> Shamusworld >> Repos - virtualjaguar/blob - src/cdi.cpp
Virtual Jaguar GCC/SDL v1.0.3 import.
[virtualjaguar] / src / cdi.cpp
1 //
2 // CD Interface handler
3 //
4 // by cal2
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         fprintf(log_get(), "CDI: Opening %s\n", path);
39         return open(path, O_BINARY | O_RDONLY);
40 }
41
42 void cdi_close(int fp)
43 {
44         fprintf(log_get(), "CDI: Closing\n");
45         close(fp);
46 }
47
48 #ifdef __PORT__
49 long tell(int fd)
50 {
51         return lseek(fd, 0LL, SEEK_CUR);
52 }
53 #endif
54
55 s_cdi_descriptor *cdi_get_descriptor(int fp, FILE *stdfp)
56 {
57         s_cdi_descriptor *descriptor;
58         
59         uint32 previous_position=0;
60
61         if (fp==-1)
62                 return(0);
63
64         descriptor=(s_cdi_descriptor *)malloc(sizeof(s_cdi_descriptor));
65         if (descriptor==0)
66                 return(0);
67
68         lseek(fp,0,SEEK_END);
69         descriptor->length=tell(fp);
70         if (descriptor->length<8)
71         {
72                 if (stdfp) fprintf(stdfp,"cdi: image is too short (%i bytes)\n",descriptor->length);
73                 free(descriptor);
74                 return(0);
75         }
76         lseek(fp,descriptor->length-8,SEEK_SET);
77         read(fp,&descriptor->version,4);
78         read(fp,&descriptor->header_offset,4);
79         lseek(fp,descriptor->header_offset,SEEK_SET);
80         read(fp,&descriptor->nb_of_sessions,2);
81
82         descriptor->sessions=(s_cdi_session *)malloc(descriptor->nb_of_sessions*sizeof(s_cdi_session));
83         if (descriptor->sessions==0)
84         {
85                 free(descriptor);
86                 return(0);
87         }
88         if (stdfp) fprintf(stdfp,"cdi: %i sessions\n",descriptor->nb_of_sessions);
89         uint32 track_position=0;
90         for (uint16 session=0;session<descriptor->nb_of_sessions;session++)
91         {
92                 read(fp,&descriptor->sessions[session].nb_of_tracks,2);
93                 descriptor->sessions[session].tracks=(s_cdi_track*)malloc(descriptor->sessions[session].nb_of_tracks*sizeof(s_cdi_track));
94
95                 if (stdfp) fprintf(stdfp,"cdi:\ncdi: reading session %i (%i tracks)\n",session,descriptor->sessions[session].nb_of_tracks);
96
97                 for (uint16 track=0;track<descriptor->sessions[session].nb_of_tracks;track++)
98                 {
99                         static char current_start_mark[10];
100                         s_cdi_track *current_track=&descriptor->sessions[session].tracks[track];
101                         if (stdfp) fprintf(stdfp,"cdi:\ncdi: \t\treading track %i\n",track);
102
103                         uint32 temp_value;
104
105                         read(fp,&temp_value, 4);
106                         if (temp_value != 0)
107                                 lseek(fp, 8, SEEK_CUR); // extra data (DJ 3.00.780 and up)
108         
109                         read(fp,current_start_mark, 10);
110                         if (memcmp(cdi_track_start_mark, current_start_mark, 10)) 
111                         {
112                                 if (stdfp) fprintf(stdfp,"cdi: could not find the track start mark");
113                                 return(0);
114                         }
115                         read(fp,current_start_mark, 10);
116                         if (memcmp(cdi_track_start_mark, current_start_mark, 10)) 
117                         {
118                                 if (stdfp) fprintf(stdfp,"cdi: could not find the track start mark");
119                                 return(0);
120                         }
121
122                         lseek(fp, 4, SEEK_CUR);
123                         read(fp,&current_track->filename_length, 1);
124                         lseek(fp, current_track->filename_length, SEEK_CUR);
125
126                         lseek(fp, 11, SEEK_CUR);
127                         lseek(fp, 4, SEEK_CUR);
128                         lseek(fp, 4, SEEK_CUR);
129                         read(fp,&temp_value, 4);
130                         if (temp_value == 0x80000000)
131                                 lseek(fp, 8, SEEK_CUR); // DJ4
132                         lseek(fp, 2, SEEK_CUR);
133                         
134                         read(fp, &current_track->pregap_length, 4);
135                         if (current_track->pregap_length!=150)
136                         {
137                                 fprintf(log_get(),"cdi: warning: pregap different than 150\n");
138                         }
139                         read(fp, &current_track->length, 4);
140                         if (stdfp) fprintf(stdfp,"cdi: \t\t\tpregap length : %i\n", current_track->pregap_length);
141                         if (stdfp) fprintf(stdfp,"cdi: \t\t\tlength : %i\n", current_track->length);
142
143                         lseek(fp, 6, SEEK_CUR);
144                         
145                         read(fp, &current_track->mode, 4);
146                         if (stdfp) fprintf(stdfp,"cdi: \t\t\tmode : %i\n", current_track->mode);
147
148                         lseek(fp, 12, SEEK_CUR);
149                         read(fp, &current_track->start_lba, 4);
150                         if (stdfp) fprintf(stdfp,"cdi: \t\t\tstart lba : %i\n", current_track->start_lba);
151                         read(fp, &current_track->total_length, 4);
152                         if (stdfp) fprintf(stdfp,"cdi: \t\t\ttotal length : %i\n", current_track->total_length);
153                         lseek(fp, 16, SEEK_CUR);
154                         read(fp, &current_track->sector_size_value, 4);
155                         if (stdfp) fprintf(stdfp,"cdi: \t\t\tsector size : %i\n", current_track->sector_size_value);
156
157                         switch(current_track->sector_size_value)
158                         {
159                         case 0 : current_track->sector_size = 2048; break;
160                         case 1 : current_track->sector_size = 2336; break;
161                         case 2 : current_track->sector_size = 2352; break;
162                         default: {
163                                                 if (stdfp) fprintf(stdfp,"cdi: \t\t\tunsupported %i bytes sector",current_track->sector_size_value);
164                                                 return(0);
165                                         }
166                         }
167                         
168                         if (current_track->mode > 2) 
169                                 if (stdfp) fprintf(stdfp,"cdi: \t\t\ttrack mode %i not supported",current_track->mode);
170
171                         lseek(fp, 29, SEEK_CUR);
172                         if (descriptor->version != CDI_V2)
173                         {
174                                 lseek(fp, 5, SEEK_CUR);
175                                 read(fp,&temp_value, 4);
176                                 if (temp_value == 0xffffffff)
177                                         lseek(fp, 78, SEEK_CUR); // extra data (DJ 3.00.780 and up)
178                         }
179                         current_track->position=track_position;
180                         track_position+=(current_track->pregap_length+current_track->length)*current_track->sector_size;
181                         previous_position=track_position;
182                 }
183                 lseek(fp, 4, SEEK_CUR);
184                 lseek(fp, 8, SEEK_CUR);
185                 if (descriptor->version != CDI_V2)
186                         lseek(fp, 1, SEEK_CUR);
187
188         }
189     if (descriptor->header_offset == 0) 
190                 return(0);
191
192         return(descriptor);
193 }
194
195 void cdi_dump_descriptor(FILE *fp,s_cdi_descriptor *cdi_descriptor)
196 {
197         fprintf(fp,"cdi: %i Mb\n",cdi_descriptor->length>>20);
198         fprintf(fp,"cdi: format version ");
199         switch(cdi_descriptor->version)
200         {
201         case CDI_V2:    fprintf(fp,"2\n"); break;
202         case CDI_V3:    fprintf(fp,"3\n"); break;
203         case CDI_V35:   fprintf(fp,"3.5\n"); break;
204         default:                fprintf(fp,"unknown\n"); break;
205         }
206         fprintf(fp,"cdi: %i sessions\n",cdi_descriptor->nb_of_sessions);
207 }
208
209 uint8 * cdi_extract_boot_code(int fp, s_cdi_descriptor * cdi_descriptor)
210 {
211         s_cdi_track * boot_track = &cdi_descriptor->sessions[1].tracks[0];
212         uint32 boot_track_size = boot_track->length * boot_track->sector_size;
213
214         uint8 * boot_track_data = (uint8 *)malloc(boot_track_size);
215         lseek(fp, 2 + (boot_track->position), SEEK_SET);
216         read(fp, boot_track_data, boot_track_size);
217         
218         uint32 * boot_track_data_32 = (uint32 *)boot_track_data;
219         uint32 offset = 0;
220         while (offset < (boot_track_size >> 2))
221         {
222                 if (boot_track_data_32[offset] == 0x49205452)
223                         break;
224                 offset++;
225         }
226         if (offset == (boot_track_size >> 2))
227         {
228                 fprintf(log_get(), "CDI: Cannot find the boot code\n");
229                 return NULL;
230         }
231
232         offset = (offset << 2) + 4;
233         uint16 * data16 = (uint16 *)&boot_track_data[offset];
234         cdi_load_address = *data16++;
235         cdi_load_address <<= 16;
236         cdi_load_address |= *data16++;
237         cdi_code_length = *data16++;
238         cdi_code_length <<= 16;
239         cdi_code_length |= *data16++;
240         fprintf(log_get(), "CDI: Load address: %08X\n", cdi_load_address);
241         fprintf(log_get(), "CDI: Length: %08X\n", cdi_code_length);
242 //No need for byte swapping any more...
243 /*      fprintf(log_get(), "cdi: byte swapping boot code\n");
244
245         for(uint32 i=0; i<(cdi_code_length >> 1); i++)
246         {
247                 uint16 sdata = data16[i];
248                 sdata = (sdata >> 8) | (sdata << 8);
249                 data16[i] = sdata;
250         }*/
251
252         return (uint8 *)data16;
253 }
254
255 void cdi_load_sector(uint32 sector, uint8 * buffer)
256 {
257         if (sector == 0xFFFFFFFF)
258         {
259                 memset(buffer, 0x00, 2352);
260                 return;
261         }
262
263         sector *= 2352;
264
265         lseek(cdi_fp, 2+sector, SEEK_SET);
266         read(cdi_fp, buffer, 2352);
267
268 //This is probably not needed any more...
269 /*      // byte swap
270         for (uint32 i=0;i<2352;i+=2)
271         {
272                 uint8 sdata=buffer[i+0];
273                 buffer[i+0]=buffer[i+1];
274                 buffer[i+1]=sdata;
275         }*/
276 }