/[pcsx2_0.9.7]/trunk/pcsx2/CDVD/CDVDisoReader.cpp
ViewVC logotype

Contents of /trunk/pcsx2/CDVD/CDVDisoReader.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years ago) by william
File size: 10994 byte(s)
re-commit (had local access denied errors when committing)
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16
17 /*
18 * Original code from libcdvd by Hiryu & Sjeep (C) 2002
19 * Modified by Florin for PCSX2 emu
20 * Fixed CdRead by linuzappz
21 */
22
23 #include "PrecompiledHeader.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <fcntl.h>
28
29 #include "CDVDisoReader.h"
30
31 static u8 *pbuffer;
32 static u8 cdbuffer[CD_FRAMESIZE_RAW] = {0};
33 static isoFile iso;
34
35 static int psize, cdtype;
36
37 static s32 layer1start = -1;
38 static bool layer1searched = false;
39
40 void CALLBACK ISOclose()
41 {
42 iso.Close();
43 }
44
45 s32 CALLBACK ISOopen(const char* pTitle)
46 {
47 ISOclose(); // just in case
48
49 if( (pTitle == NULL) || (pTitle[0] == 0) )
50 {
51 Console.Error( "CDVDiso Error: No filename specified." );
52 return -1;
53 }
54
55 // The current plugin API doesn't expect exceptions to propagate out of the API
56 // calls, so we need to catch them, log them, and return -1.
57
58 try {
59 iso.Open(fromUTF8(pTitle));
60 }
61 catch( BaseException& ex )
62 {
63 Console.Error( ex.FormatDiagnosticMessage() );
64 return -1;
65 }
66
67 switch (iso.GetType())
68 {
69 case ISOTYPE_DVD:
70 cdtype = CDVD_TYPE_PS2DVD;
71 break;
72 case ISOTYPE_AUDIO:
73 cdtype = CDVD_TYPE_CDDA;
74 break;
75 default:
76 cdtype = CDVD_TYPE_PS2CD;
77 break;
78 }
79
80 layer1start = -1;
81 layer1searched = false;
82
83 return 0;
84 }
85
86 s32 CALLBACK ISOreadSubQ(u32 lsn, cdvdSubQ* subq)
87 {
88 // fake it
89 u8 min, sec, frm;
90 subq->ctrl = 4;
91 subq->mode = 1;
92 subq->trackNum = itob(1);
93 subq->trackIndex = itob(1);
94
95 lba_to_msf(lsn, &min, &sec, &frm);
96 subq->trackM = itob(min);
97 subq->trackS = itob(sec);
98 subq->trackF = itob(frm);
99
100 subq->pad = 0;
101
102 lba_to_msf(lsn + (2*75), &min, &sec, &frm);
103 subq->discM = itob(min);
104 subq->discS = itob(sec);
105 subq->discF = itob(frm);
106
107 return 0;
108 }
109
110 s32 CALLBACK ISOgetTN(cdvdTN *Buffer)
111 {
112 Buffer->strack = 1;
113 Buffer->etrack = 1;
114
115 return 0;
116 }
117
118 s32 CALLBACK ISOgetTD(u8 Track, cdvdTD *Buffer)
119 {
120 if (Track == 0)
121 {
122 Buffer->lsn = iso.GetBlockCount();
123 }
124 else
125 {
126 Buffer->type = CDVD_MODE1_TRACK;
127 Buffer->lsn = 0;
128 }
129
130 return 0;
131 }
132
133 #include "gui/App.h"
134 #include "Utilities/HashMap.h"
135
136 static bool testForPartitionInfo( const u8 (&tempbuffer)[CD_FRAMESIZE_RAW] )
137 {
138 const int off = iso.GetBlockOffset();
139
140 // test for: CD001
141 return (
142 (tempbuffer[off+1] == 0x43) &&
143 (tempbuffer[off+2] == 0x44) &&
144 (tempbuffer[off+3] == 0x30) &&
145 (tempbuffer[off+4] == 0x30) &&
146 (tempbuffer[off+5] == 0x31)
147 );
148 }
149
150 static void FindLayer1Start()
151 {
152 if (iso.GetBlockCount() < 0x230540) return;
153 if (layer1start != -1) return;
154 if (layer1searched) return;
155
156 Console.WriteLn("isoFile: searching for layer1...");
157 layer1searched = true;
158
159 int blockresult = -1;
160
161 // Check the ini file cache first:
162 // Cache is stored in LayerBreakCache.ini, and is associated by hex-encoded hash key of the
163 // complete filename/path of the iso file. :)
164
165 wxString layerCacheFile( Path::Combine(GetSettingsFolder().ToString(), L"LayerBreakCache.ini") );
166 wxFileConfig layerCacheIni( wxEmptyString, wxEmptyString, layerCacheFile, wxEmptyString, wxCONFIG_USE_RELATIVE_PATH );
167
168 FastFormatUnicode cacheKey;
169 cacheKey.Write( L"%X", HashTools::Hash( (s8*)iso.GetFilename().c_str(), iso.GetFilename().Length() * sizeof(wxChar) ) );
170
171 blockresult = layerCacheIni.Read( cacheKey, -1 );
172 if( blockresult != -1 )
173 {
174 u8 tempbuffer[CD_FRAMESIZE_RAW];
175 iso.ReadBlock(tempbuffer, blockresult);
176
177 if( testForPartitionInfo( tempbuffer ) )
178 {
179 Console.WriteLn( "isoFile: loaded second layer from settings cache, sector=0x%08x", blockresult );
180 layer1start = blockresult;
181 }
182 else
183 {
184 Console.Warning( "isoFile: second layer info in the settings cache appears to be obsolete or invalid. Ignoring..." );
185 }
186 }
187 else
188 {
189 DevCon.WriteLn( "isoFile: no cached info for second layer found." );
190 }
191
192 if( layer1start == -1 )
193 {
194
195 // Layer sizes are arbitrary, and either layer could be the smaller (GoW and Rogue Galaxy
196 // both have Layer1 larger than Layer0 for example), so we have to brute-force the search
197 // from some arbitrary start position.
198 //
199 // Method: Inside->out. We start at the middle of the image and work our way out toward
200 // both the beginning and end of the image at the same time. Most images have the layer
201 // break quite close to the middle of the image, so this should be pretty fast in most cases.
202
203 // [TODO] Layer searching can be slow, especially for compressed disc images, so it would
204 // be quite courteous to pop up a status dialog bar that lets the user know that it's
205 // thinking. Since we're not on the GUI thread, we'll need to establish some messages
206 // to create the window and pass progress increments back to it.
207
208
209 uint midsector = (iso.GetBlockCount() / 2) & ~0xf;
210 uint deviation = 0;
211
212 while( (layer1start == -1) && (deviation < midsector-16) )
213 {
214 u8 tempbuffer[CD_FRAMESIZE_RAW];
215 iso.ReadBlock(tempbuffer, midsector-deviation);
216
217 if(testForPartitionInfo( tempbuffer ))
218 layer1start = midsector-deviation;
219 else
220 {
221 iso.ReadBlock(tempbuffer, midsector+deviation);
222 if( testForPartitionInfo( tempbuffer ) )
223 layer1start = midsector+deviation;
224 }
225
226 if( layer1start != -1 )
227 {
228 const int blockofs = iso.GetBlockOffset();
229 if( !pxAssertDev( tempbuffer[blockofs] == 0x01, "Layer1-Detect: CD001 tag found, but the partition type is invalid." ) )
230 {
231 Console.Error( "isoFile: Invalid partition type on layer 1!? (type=0x%x)", tempbuffer[blockofs] );
232 }
233 }
234 deviation += 16;
235 }
236
237 if( layer1start == -1 )
238 {
239 Console.Error("isoFile: Couldn't find layer1... iso image is probably corrupt or incomplete.");
240 }
241 else
242 {
243 Console.WriteLn( Color_Blue, "isoFile: second layer found at sector 0x%08x", layer1start);
244
245 // Save layer information to configuration:
246
247 layerCacheIni.Write( cacheKey, layer1start );
248 }
249 }
250 }
251
252 // Should return 0 if no error occurred, or -1 if layer detection FAILED.
253 s32 CALLBACK ISOgetDualInfo(s32* dualType, u32* _layer1start)
254 {
255 FindLayer1Start();
256
257 if (layer1start < 0)
258 {
259 *dualType = 0;
260 *_layer1start = iso.GetBlockCount();
261 }
262 else
263 {
264 *dualType = 1;
265 *_layer1start = layer1start;
266 }
267 return 0;
268 }
269
270 s32 CALLBACK ISOgetDiskType()
271 {
272 return cdtype;
273 }
274
275 s32 CALLBACK ISOgetTOC(void* toc)
276 {
277 u8 type = ISOgetDiskType();
278 u8* tocBuff = (u8*)toc;
279
280 //CDVD_LOG("CDVDgetTOC\n");
281
282 if (type == CDVD_TYPE_DVDV || type == CDVD_TYPE_PS2DVD)
283 {
284 // get dvd structure format
285 // scsi command 0x43
286 memset(tocBuff, 0, 2048);
287
288 FindLayer1Start();
289
290 if (layer1start < 0)
291 {
292 // fake it
293 tocBuff[ 0] = 0x04;
294 tocBuff[ 1] = 0x02;
295 tocBuff[ 2] = 0xF2;
296 tocBuff[ 3] = 0x00;
297 tocBuff[ 4] = 0x86;
298 tocBuff[ 5] = 0x72;
299
300 tocBuff[16] = 0x00;
301 tocBuff[17] = 0x03;
302 tocBuff[18] = 0x00;
303 tocBuff[19] = 0x00;
304 return 0;
305 }
306 else
307 {
308 // dual sided
309 tocBuff[ 0] = 0x24;
310 tocBuff[ 1] = 0x02;
311 tocBuff[ 2] = 0xF2;
312 tocBuff[ 3] = 0x00;
313 tocBuff[ 4] = 0x41;
314 tocBuff[ 5] = 0x95;
315
316 tocBuff[14] = 0x60; // dual sided, ptp
317
318 tocBuff[16] = 0x00;
319 tocBuff[17] = 0x03;
320 tocBuff[18] = 0x00;
321 tocBuff[19] = 0x00;
322
323 s32 l1s = layer1start + 0x30000 - 1;
324 tocBuff[20] = (l1s >> 24);
325 tocBuff[21] = (l1s >> 16) & 0xff;
326 tocBuff[22] = (l1s >> 8) & 0xff;
327 tocBuff[23] = (l1s >> 0) & 0xff;
328 }
329 }
330 else if ((type == CDVD_TYPE_CDDA) || (type == CDVD_TYPE_PS2CDDA) ||
331 (type == CDVD_TYPE_PS2CD) || (type == CDVD_TYPE_PSCDDA) || (type == CDVD_TYPE_PSCD))
332 {
333 // cd toc
334 // (could be replaced by 1 command that reads the full toc)
335 u8 min, sec, frm;
336 s32 i, err;
337 cdvdTN diskInfo;
338 cdvdTD trackInfo;
339 memset(tocBuff, 0, 1024);
340 if (ISOgetTN(&diskInfo) == -1)
341 {
342 diskInfo.etrack = 0;
343 diskInfo.strack = 1;
344 }
345 if (ISOgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0;
346
347 tocBuff[0] = 0x41;
348 tocBuff[1] = 0x00;
349
350 //Number of FirstTrack
351 tocBuff[2] = 0xA0;
352 tocBuff[7] = itob(diskInfo.strack);
353
354 //Number of LastTrack
355 tocBuff[12] = 0xA1;
356 tocBuff[17] = itob(diskInfo.etrack);
357
358 //DiskLength
359 lba_to_msf(trackInfo.lsn, &min, &sec, &frm);
360 tocBuff[22] = 0xA2;
361 tocBuff[27] = itob(min);
362 tocBuff[28] = itob(sec);
363
364 for (i = diskInfo.strack; i <= diskInfo.etrack; i++)
365 {
366 err = ISOgetTD(i, &trackInfo);
367 lba_to_msf(trackInfo.lsn, &min, &sec, &frm);
368 tocBuff[i*10+30] = trackInfo.type;
369 tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number
370 tocBuff[i*10+37] = itob(min);
371 tocBuff[i*10+38] = itob(sec);
372 tocBuff[i*10+39] = itob(frm);
373 }
374 }
375 else
376 return -1;
377
378 return 0;
379 }
380
381 s32 CALLBACK ISOreadSector(u8* tempbuffer, u32 lsn, int mode)
382 {
383 int _lsn = lsn;
384
385 if (_lsn < 0) lsn = iso.GetBlockCount() + _lsn;
386 if (lsn > iso.GetBlockCount()) return -1;
387
388 if(mode == CDVD_MODE_2352)
389 {
390 iso.ReadBlock(tempbuffer, lsn);
391 return 0;
392 }
393
394 iso.ReadBlock(cdbuffer, lsn);
395
396 pbuffer = cdbuffer;
397
398 switch (mode)
399 {
400 case CDVD_MODE_2352:
401 // Unreachable due to shortcut above.
402 pxAssume(false);
403 break;
404
405 case CDVD_MODE_2340:
406 pbuffer += 12;
407 psize = 2340;
408 break;
409 case CDVD_MODE_2328:
410 pbuffer += 24;
411 psize = 2328;
412 break;
413 case CDVD_MODE_2048:
414 pbuffer += 24;
415 psize = 2048;
416 break;
417
418 jNO_DEFAULT
419 }
420
421 memcpy_fast(tempbuffer, pbuffer, psize);
422
423 return 0;
424 }
425
426 s32 CALLBACK ISOreadTrack(u32 lsn, int mode)
427 {
428 int _lsn = lsn;
429
430 if (_lsn < 0) lsn = iso.GetBlockCount() + _lsn;
431 if (lsn > iso.GetBlockCount()) return -1;
432
433 iso.ReadBlock(cdbuffer, lsn);
434 pbuffer = cdbuffer;
435
436 switch (mode)
437 {
438 case CDVD_MODE_2352:
439 psize = 2352;
440 break;
441 case CDVD_MODE_2340:
442 pbuffer += 12;
443 psize = 2340;
444 break;
445 case CDVD_MODE_2328:
446 pbuffer += 24;
447 psize = 2328;
448 break;
449 case CDVD_MODE_2048:
450 pbuffer += 24;
451 psize = 2048;
452 break;
453 }
454
455 return 0;
456 }
457
458 s32 CALLBACK ISOgetBuffer2(u8* buffer)
459 {
460 memcpy_fast(buffer, pbuffer, psize);
461 return 0;
462 }
463
464 u8* CALLBACK ISOgetBuffer()
465 {
466 return pbuffer;
467 }
468
469 s32 CALLBACK ISOgetTrayStatus()
470 {
471 return CDVD_TRAY_CLOSE;
472 }
473
474 s32 CALLBACK ISOctrlTrayOpen()
475 {
476 return 0;
477 }
478 s32 CALLBACK ISOctrlTrayClose()
479 {
480 return 0;
481 }
482
483 s32 CALLBACK ISOdummyS32()
484 {
485 return 0;
486 }
487
488 void CALLBACK ISOnewDiskCB(void(* /* callback */)())
489 {
490 }
491
492 CDVD_API CDVDapi_Iso =
493 {
494 ISOclose,
495
496 ISOopen,
497 ISOreadTrack,
498 ISOgetBuffer, // emu shouldn't use this one.
499 ISOreadSubQ,
500 ISOgetTN,
501 ISOgetTD,
502 ISOgetTOC,
503 ISOgetDiskType,
504 ISOdummyS32, // trayStatus
505 ISOdummyS32, // trayOpen
506 ISOdummyS32, // trayClose
507
508 ISOnewDiskCB,
509
510 ISOreadSector,
511 ISOgetBuffer2,
512 ISOgetDualInfo,
513 };

  ViewVC Help
Powered by ViewVC 1.1.22