initial commit
[iso2ps2.git] / ps2classic / iso.c
1 #include "iso.h"
2
3 #include <stdio.h>
4 #include <fcntl.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <errno.h>
8
9
10 void *_openfile(const char *filename, int flags)
11 {
12
13 if (flags & O_WRONLY)
14 return fopen(filename, "wb");
15 else
16 return fopen(filename, "rb");
17 }
18
19
20 u64 _tellfile(void *handle)
21 {
22 s64 cursize = ftell(handle);
23 if (cursize == -1)
24 {
25 // try 64bit
26 cursize = ftello(handle);
27 if (cursize < -1)
28 {
29 // zero top 32 bits
30 cursize &= 0xffffffff;
31 }
32 }
33 return cursize;
34 }
35
36 int _seekfile(void *handle, u64 offset, int whence)
37 {
38 int seekerr = fseeko(handle, offset, whence);
39
40 if (seekerr == -1) printf("failed to seek\n");
41
42 return seekerr;
43 }
44
45 int _readfile(void *handle, void *dst, int size)
46 {
47 return fread(dst, 1, size, handle);
48 }
49
50 int _writefile(void *handle, void *src, int size)
51 {
52 return fwrite(src, 1, size, handle);
53 }
54
55 void _closefile(void *handle)
56 {
57 fclose(handle);
58 }
59
60
61 int detect(struct isoFile *iso)
62 {
63 u8 buf[2448];
64 struct cdVolDesc *volDesc;
65
66 if (isoReadBlock(iso, buf + iso->blockofs, 16) == -1) return -1;
67
68 volDesc = (struct cdVolDesc *)(buf + 24);
69
70 if (strncmp((char*)volDesc->volID, "CD001", 5)) return 0;
71
72 if (volDesc->rootToc.tocSize == 2048)
73 iso->type = ISOTYPE_CD;
74 else
75 iso->type = ISOTYPE_DVD;
76
77 return 1;
78 }
79
80 int _isoReadDtable(struct isoFile *iso)
81 {
82 int ret;
83 int i;
84
85 _seekfile(iso->handle, 0, SEEK_END);
86 iso->dtablesize = (_tellfile(iso->handle) - 16) / (iso->blocksize + 4);
87 iso->dtable = (u32*)malloc(iso->dtablesize * 4);
88
89 for (i = 0; i < iso->dtablesize; i++)
90 {
91 _seekfile(iso->handle, 16 + (iso->blocksize + 4)*i, SEEK_SET);
92 ret = _readfile(iso->handle, &iso->dtable[i], 4);
93 if (ret < 4) return -1;
94 }
95
96 return 0;
97 }
98
99 int isoDetect(struct isoFile *iso) // based on florin's CDVDbin detection code :)
100 {
101 char buf[32];
102 int len;
103
104 iso->type = ISOTYPE_ILLEGAL;
105
106 len = strlen(iso->filename);
107
108 _seekfile(iso->handle, 0, SEEK_SET);
109 _readfile(iso->handle, buf, 4);
110
111 if (strncmp(buf, "BDV2", 4) == 0)
112 {
113 iso->flags = ISOFLAGS_BLOCKDUMP;
114 _readfile(iso->handle, &iso->blocksize, 4);
115 _readfile(iso->handle, &iso->blocks, 4);
116 _readfile(iso->handle, &iso->blockofs, 4);
117 _isoReadDtable(iso);
118 return detect(iso) == 1 ? 0 : -1;
119 }
120 else
121 {
122 iso->blocks = 16;
123 }
124
125 // ISO 2048
126 iso->blocksize = 2048;
127 iso->offset = 0;
128 iso->blockofs = 24;
129 if (detect(iso) == 1) return 0;
130
131 // RAW 2336
132 iso->blocksize = 2336;
133 iso->offset = 0;
134 iso->blockofs = 16;
135 if (detect(iso) == 1) return 0;
136
137 // RAW 2352
138 iso->blocksize = 2352;
139 iso->offset = 0;
140 iso->blockofs = 0;
141 if (detect(iso) == 1) return 0;
142
143 // RAWQ 2448
144 iso->blocksize = 2448;
145 iso->offset = 0;
146 iso->blockofs = 0;
147 if (detect(iso) == 1) return 0;
148
149 // NERO ISO 2048
150 iso->blocksize = 2048;
151 iso->offset = 150 * 2048;
152 iso->blockofs = 24;
153 if (detect(iso) == 1) return 0;
154
155 // NERO RAW 2352
156 iso->blocksize = 2352;
157 iso->offset = 150 * 2048;
158 iso->blockofs = 0;
159 if (detect(iso) == 1) return 0;
160
161 // NERO RAWQ 2448
162 iso->blocksize = 2448;
163 iso->offset = 150 * 2048;
164 iso->blockofs = 0;
165 if (detect(iso) == 1) return 0;
166
167 // ISO 2048
168 iso->blocksize = 2048;
169 iso->offset = -8;
170 iso->blockofs = 24;
171 if (detect(iso) == 1) return 0;
172
173 // RAW 2352
174 iso->blocksize = 2352;
175 iso->offset = -8;
176 iso->blockofs = 0;
177 if (detect(iso) == 1) return 0;
178
179 // RAWQ 2448
180 iso->blocksize = 2448;
181 iso->offset = -8;
182 iso->blockofs = 0;
183 if (detect(iso) == 1) return 0;
184
185 iso->offset = 0;
186 iso->blocksize = 2352;
187 iso->type = ISOTYPE_AUDIO;
188 return 0;
189
190 return -1;
191 }
192
193 struct isoFile *isoOpen(const char *filename)
194 {
195 struct isoFile *iso;
196 int i;
197
198 iso = (struct isoFile*)malloc(sizeof(struct isoFile));
199 if (iso == NULL) return NULL;
200
201 memset(iso, 0, sizeof(struct isoFile));
202 strcpy(iso->filename, filename);
203
204 iso->handle = _openfile(iso->filename, O_RDONLY);
205 if (iso->handle == NULL)
206 {
207 printf("Error loading %s\n", iso->filename);
208 return NULL;
209 }
210
211 if (isoDetect(iso) == -1) return NULL;
212
213 //printf("detected blocksize = %d\n", iso->blocksize);
214
215 if (strlen(iso->filename) > 3 && strncmp(iso->filename + (strlen(iso->filename) - 3), "I00", 3) == 0)
216 {
217 _closefile(iso->handle);
218 iso->flags |= ISOFLAGS_MULTI;
219 iso->blocks = 0;
220 for (i = 0; i < 8; i++)
221 {
222 iso->filename[strlen(iso->filename) - 1] = '0' + i;
223 iso->multih[i].handle = _openfile(iso->filename, O_RDONLY);
224 if (iso->multih[i].handle == NULL)
225 {
226 break;
227 }
228 iso->multih[i].slsn = iso->blocks;
229 _seekfile(iso->multih[i].handle, 0, SEEK_END);
230 iso->blocks += (u32)((_tellfile(iso->multih[i].handle) - iso->offset) /
231 (iso->blocksize));
232 iso->multih[i].elsn = iso->blocks - 1;
233 }
234
235 if (i == 0)
236 {
237 return NULL;
238 }
239 }
240
241 if (iso->flags == 0)
242 {
243 _seekfile(iso->handle, 0, SEEK_END);
244 iso->blocks = (u32)((_tellfile(iso->handle) - iso->offset) /
245 (iso->blocksize));
246 }
247
248
249 //printf("isoOpen: %s ok\n", iso->filename);
250 /*printf("offset = %d\n", iso->offset);
251 printf("blockofs = %d\n", iso->blockofs);
252 printf("blocksize = %d\n", iso->blocksize);
253 printf("blocks = %d\n", iso->blocks);*/
254 //printf("type = %d\n", iso->type);
255
256 return iso;
257 }
258
259 struct isoFile *isoCreate(const char *filename, int flags)
260 {
261 struct isoFile *iso;
262 char Zfile[256];
263
264 iso = (struct isoFile*)malloc(sizeof(struct isoFile));
265 if (iso == NULL) return NULL;
266
267 memset(iso, 0, sizeof(struct isoFile));
268 strcpy(iso->filename, filename);
269 iso->flags = flags;
270 iso->offset = 0;
271 iso->blockofs = 24;
272 iso->blocksize = CD_FRAMESIZE_RAW;
273 iso->blocksize = 2048;
274
275 if (iso->flags & (ISOFLAGS_Z | ISOFLAGS_Z2 | ISOFLAGS_BZ2))
276 {
277 sprintf(Zfile, "%s.table", iso->filename);
278 iso->htable = _openfile(Zfile, O_WRONLY);
279 if (iso->htable == NULL)
280 {
281 return NULL;
282 }
283 }
284
285 iso->handle = _openfile(iso->filename, O_WRONLY | O_CREAT);
286 if (iso->handle == NULL)
287 {
288 printf("Error loading %s\n", iso->filename);
289 return NULL;
290 }
291 printf("isoCreate: %s ok\n", iso->filename);
292 printf("offset = %d\n", iso->offset);
293
294 return iso;
295 }
296
297 int isoSetFormat(struct isoFile *iso, int blockofs, int blocksize, int blocks)
298 {
299 iso->blocksize = blocksize;
300 iso->blocks = blocks;
301 iso->blockofs = blockofs;
302 printf("blockofs = %d\n", iso->blockofs);
303 printf("blocksize = %d\n", iso->blocksize);
304 printf("blocks = %d\n", iso->blocks);
305 if (iso->flags & ISOFLAGS_BLOCKDUMP)
306 {
307 if (_writefile(iso->handle, "BDV2", 4) < 4) return -1;
308 if (_writefile(iso->handle, &blocksize, 4) < 4) return -1;
309 if (_writefile(iso->handle, &blocks, 4) < 4) return -1;
310 if (_writefile(iso->handle, &blockofs, 4) < 4) return -1;
311 }
312
313 return 0;
314 }
315
316 s32 MSFtoLSN(u8 *Time)
317 {
318 u32 lsn;
319
320 lsn = Time[2];
321 lsn += (Time[1] - 2) * 75;
322 lsn += Time[0] * 75 * 60;
323 return lsn;
324 }
325
326 void LSNtoMSF(u8 *Time, s32 lsn)
327 {
328 u8 m, s, f;
329
330 lsn += 150;
331 m = lsn / 4500; // minuten
332 lsn = lsn - m * 4500; // minuten rest
333 s = lsn / 75; // sekunden
334 f = lsn - (s * 75); // sekunden rest
335 Time[0] = itob(m);
336 Time[1] = itob(s);
337 Time[2] = itob(f);
338 }
339
340 int _isoReadBlock(struct isoFile *iso, u8 *dst, int lsn)
341 {
342 u64 ofs = (u64)lsn * iso->blocksize + iso->offset;
343 u32 ret;
344
345 memset(dst, 0, iso->blockofs);
346 _seekfile(iso->handle, ofs, SEEK_SET);
347 ret = _readfile(iso->handle, dst, iso->blocksize);
348 if (ret < iso->blocksize)
349 {
350 printf("read error %d\n", ret);
351 return -1;
352 }
353
354 return 0;
355 }
356
357 int _isoReadBlockD(struct isoFile *iso, u8 *dst, u32 lsn)
358 {
359 u32 ret;
360 int i;
361
362 // printf("_isoReadBlockD %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs);
363 memset(dst, 0, iso->blockofs);
364 for (i = 0; i < iso->dtablesize;i++)
365 {
366 if (iso->dtable[i] != lsn) continue;
367
368 _seekfile(iso->handle, 16 + i*(iso->blocksize + 4) + 4, SEEK_SET);
369 ret = _readfile(iso->handle, dst, iso->blocksize);
370 if (ret < iso->blocksize) return -1;
371
372 return 0;
373 }
374 printf("block %d not found in dump\n", lsn);
375
376 return -1;
377 }
378
379 int _isoReadBlockM(struct isoFile *iso, u8 *dst, u32 lsn)
380 {
381 u64 ofs;
382 u32 ret;
383 int i;
384
385 for (i = 0; i < 8; i++)
386 {
387 if (lsn >= iso->multih[i].slsn &&
388 lsn <= iso->multih[i].elsn)
389 {
390 break;
391 }
392 }
393 if (i == 8) return -1;
394
395 ofs = (u64)(lsn - iso->multih[i].slsn) * iso->blocksize + iso->offset;
396 // printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs);
397 memset(dst, 0, iso->blockofs);
398 _seekfile(iso->multih[i].handle, ofs, SEEK_SET);
399 ret = _readfile(iso->multih[i].handle, dst, iso->blocksize);
400
401 if (ret < iso->blocksize)
402 {
403 printf("read error %d\n", ret);
404 return -1;
405 }
406
407 return 0;
408 }
409
410 int isoReadBlock(struct isoFile *iso, u8 *dst, u32 lsn)
411 {
412 int ret;
413
414 if (lsn > iso->blocks)
415 {
416 printf("isoReadBlock: %d > %d\n", lsn, iso->blocks);
417 return -1;
418 }
419
420 if (iso->flags & ISOFLAGS_BLOCKDUMP)
421 ret = _isoReadBlockD(iso, dst, lsn);
422 else if (iso->flags & ISOFLAGS_MULTI)
423 ret = _isoReadBlockM(iso, dst, lsn);
424 else
425 ret = _isoReadBlock(iso, dst, lsn);
426
427 if (ret == -1) return ret;
428
429 if (iso->type == ISOTYPE_CD)
430 {
431 LSNtoMSF(dst + 12, lsn);
432 dst[15] = 2;
433 }
434
435 return 0;
436 }
437
438
439 int _isoWriteBlock(struct isoFile *iso, u8 *src, u32 lsn)
440 {
441 u64 ofs = (u64)lsn * iso->blocksize + iso->offset;
442 u32 ret;
443
444 _seekfile(iso->handle, ofs, SEEK_SET);
445 ret = _writefile(iso->handle, src, iso->blocksize);
446 if (ret < iso->blocksize) return -1;
447
448 return 0;
449 }
450
451 int _isoWriteBlockD(struct isoFile *iso, u8 *src, u32 lsn)
452 {
453 u32 ret;
454
455 // printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs);
456 ret = _writefile(iso->handle, &lsn, 4);
457 if (ret < 4) return -1;
458 ret = _writefile(iso->handle, src, iso->blocksize);
459 // printf("_isoWriteBlock %d\n", ret);
460 if (ret < iso->blocksize) return -1;
461
462 return 0;
463 }
464
465 int isoWriteBlock(struct isoFile *iso, u8 *src, u32 lsn)
466 {
467 int ret;
468
469 if (iso->flags & ISOFLAGS_BLOCKDUMP)
470 ret = _isoWriteBlockD(iso, src, lsn);
471 else
472 ret = _isoWriteBlock(iso, src, lsn);
473
474 if (ret == -1) return ret;
475 return 0;
476 }
477
478 void isoClose(struct isoFile *iso)
479 {
480 if (iso->handle) _closefile(iso->handle);
481 if (iso->htable) _closefile(iso->htable);
482 if (iso->buffer) free(iso->buffer);
483
484 free(iso);
485 }
486
487 void print_ps2image_info(const char *image_name)
488 {
489 struct isoFile *iso;
490 u8 * buffer;
491
492 iso = isoOpen(image_name);
493
494 printf("\nImage info:\n\n");
495
496 printf("offset:\t\t %d\n", iso->offset);
497 printf("blockofs:\t %d\n", iso->blockofs);
498 printf("blocksize:\t %d\n", iso->blocksize);
499 printf("blocks:\t\t %d\n", iso->blocks);
500
501 if((iso->blocksize*iso->blocks) % 0x4000 == 0)
502 printf("image size:\t OK\n");
503 else
504 printf("image size:\t NG\n");
505
506
507 buffer = (u8*)malloc(iso->blocksize);
508 isoReadBlock(iso, buffer, iso->blocks - 8);
509
510 if(strncmp(buffer, "LIMG", 4) && be32(buffer+4) != 1 && be32(buffer+8) != ((iso->blocks) - 8 / 0x800) && be32(buffer+12) != 0x800)
511 printf("LIMG block:\t NG\n");
512 else
513 printf("LIMG block:\t OK\n");
514
515 isoClose(iso);
516 }
517
518
519 void prepare_iso(char image_name[])
520 {
521
522 FILE * in;
523 u64 data_size;
524 u32 data_append;
525 u64 ret;
526 u8 buffer[0x4000];
527 u8 header_buffer[0x10];
528 char limg_header[4] = "LIMG";
529
530 memset(buffer, 0, 0x4000);
531
532 in = fopen(image_name, "r+b");
533
534 printf("\nPreparing Image:\n\n");
535
536 //get file info
537 fseeko(in, 0, SEEK_END);
538 data_size = ftello(in);
539
540
541 //append iso
542 data_append = 0x4000 - (data_size % 0x4000);
543
544 if(data_append != 0x4000)
545 {
546 fwrite(buffer, data_append, 1, in);
547 data_size += data_append;
548 printf("\timage size:\t FIXED\n");
549 }else{
550 printf("\timage size:\t OK\n");
551 }
552
553
554 //add limg header
555 fseeko(in, data_size - 0x4000, SEEK_SET);
556 ret = fread(header_buffer, 0x10, 1, in);
557
558 if(memcmp(header_buffer, limg_header, 4) && be32(header_buffer+4) != 1 && be32(header_buffer+8) != (data_size/0x800) && be32(header_buffer+12) != 0x800)
559 {
560 memcpy(buffer, limg_header, 4);
561 wbe32(buffer+8, data_size/0x800);
562 wbe32(buffer+12, 0x800);
563 wbe32(buffer+4, 1);
564
565 if(memcmp(header_buffer, limg_header, 4))
566 fseeko(in, 0, SEEK_END);
567 else
568 fseeko(in, data_size - 0x4000, SEEK_SET);
569 fwrite(buffer, 0x4000, 1, in);
570 printf("\tLIMG sector:\t ADDED/FIXED\n");
571 }else{
572 printf("\tLIMG sector:\t OK\n");
573 }
574
575 fclose(in);
576 }