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