1 /*
2 * OpenBOR - http://www.LavaLit.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2011 OpenBOR Team
7 */
8
9 /*
10 Code to read files from packfiles.
11
12 ============= Format description (a bit cryptical) ================
13
14 dword 4B434150 ("PACK")
15 dword version
16 ????? filedata
17 {
18 dword structsize
19 dword filestart
20 dword filesize
21 bytes name
22 } rep
23 dword headerstart
24 */
25 #include <assert.h>
26 #ifndef SPK_SUPPORTED
27
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include "utils.h"
32 #include "borendian.h"
33 #include "stristr.h"
34 #include "packfile.h"
35 #include "filecache.h"
36 #include "globals.h"
37 #include "openbor.h"
38
39 #ifdef PS2
40 #include <sifdev.h>
41 #endif
42
43 #if GP2X || LINUX || DINGOO || SYMBIAN
44 #define stricmp strcasecmp
45 #endif
46
47 #ifndef DC
48 #pragma pack (1)
49 #endif
50
51
52 /////////////////////////////////////////////////////////////////////////////
53 //
54 // Requirements for Compressed Packfiles.
55 //
56 #define MAXPACKHANDLES 8
57 #define PACKMAGIC 0x4B434150
58 #define PACKVERSION 0x00000000
59 static const size_t USED_FLAG = (((size_t) 1) << ((sizeof(size_t)*8) - 1));
60
61 /////////////////////////////////////////////////////////////////////////////
62 //
63 // This defines are only used for Cached code
64 // CACHEBLOCKSIZE*CACHEBLOCKS is the size of the ever-present file cache
65 // cacheblocks must be 255 or less!
66 //
67 #define CACHEBLOCKSIZE (32768)
68 #ifndef DINGOO
69 #define CACHEBLOCKS (96)
70 #else
71 #define CACHEBLOCKS (8)
72 #endif
73
74 static int pak_initialized;
75 int printFileUsageStatistics = 0;
76
77 /////////////////////////////////////////////////////////////////////////////
78 //
79 // This variables are only used for Non-Cached code
80 //
81 // Actual file handles.
82 static int packhandle[MAXPACKHANDLES] = { -1,-1,-1,-1,-1,-1,-1,-1 };
83
84 // Own file pointers and sizes
85 static unsigned int packfilepointer[MAXPACKHANDLES];
86 static unsigned int packfilesize[MAXPACKHANDLES];
87 //char packfile[128] <- defined in sdl/sdlport.c... hmmm
88 List* filenamelist = NULL;
89
90 /////////////////////////////////////////////////////////////////////////////
91 //
92 // This variables are only used for with Caching code
93 //
94 static int pakfd;
95 static int paksize;
96 static int pak_vfdexists[MAXPACKHANDLES];
97 static int pak_vfdstart[MAXPACKHANDLES];
98 static int pak_vfdsize[MAXPACKHANDLES];
99 static int pak_vfdpos[MAXPACKHANDLES];
100 static int pak_vfdreadahead[MAXPACKHANDLES];
101 static int pak_headerstart;
102 static int pak_headersize;
103 static unsigned char *pak_cdheader;
104 static unsigned char *pak_header;
105
106 /////////////////////////////////////////////////////////////////////////////
107 /////////////////////////////////////////////////////////////////////////////
108 //
109 // Pointers to the Real Functions
110 //
111 typedef int (*OpenPackfile)(const char*, const char*);
112 typedef int (*ReadPackfile)(int, void*, int);
113 typedef int (*SeekPackfile)(int, int, int);
114 typedef int (*ClosePackfile)(int);
115
116 int openPackfile(const char*, const char*);
117 int readPackfile(int, void*, int);
118 int seekPackfile(int, int, int);
119 int closePackfile(int);
120 int openPackfileCached(const char*, const char*);
121 int readPackfileCached(int, void*, int);
122 int seekPackfileCached(int, int, int);
123 int closePackfileCached(int);
124
125 static OpenPackfile pOpenPackfile;
126 static ReadPackfile pReadPackfile;
127 static SeekPackfile pSeekPackfile;
128 static ClosePackfile pClosePackfile;
129
130 /////////////////////////////////////////////////////////////////////////////
131 //
132 // Generic but useful functions
133 //
134
tolowerOneChar(const char * c)135 char tolowerOneChar(const char* c)
136 {
137 static const char diff = 'a' - 'A';
138 switch(*c) {
139 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
140 case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
141 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
142 return *c + diff;
143 case '\\':
144 return '/';
145 default:
146 return *c;
147 }
148 return '\0'; //should never be reached
149 }
150
151 // file name lowercase in-place.
fnlc(char * buf)152 void fnlc(char* buf) {
153 char* copy = buf;
154 while(copy && *copy) {
155 *copy = tolowerOneChar(copy);
156 copy++;
157 }
158 }
159
160 // we only return 0 on success, and non 0 on failure, to speed it up
myfilenamecmp(const char * a,size_t asize,const char * b,size_t bsize)161 int myfilenamecmp(const char *a, size_t asize, const char *b, size_t bsize)
162 {
163 char* ca;
164 char* cb;
165
166 if (a == b) return 0;
167 if(asize != bsize) return 1;
168
169 ca = (char*) a;
170 cb = (char*) b;
171
172 for (;;) {
173 if (!*ca) {
174 if (*cb) return -1;
175 else return 0; // default exit on match
176 }
177 if (!*cb) return 1;
178 if (*ca == *cb) goto cont;
179 if (tolowerOneChar(ca) != tolowerOneChar(cb)) return 1;
180 cont:
181 ca++;
182 cb++;
183 }
184 return -2; // should never be reached
185 }
186
187 // Convert slashes (UNIX) to backslashes (DOS).
188 // Return a pointer to buffer with filename converted to DOS format.
slashback(const char * sz)189 static char * slashback(const char *sz)
190 {
191 int i=0;
192 static char new[256];
193 while(sz[i] && i<255)
194 {
195 new[i] = sz[i];
196 if(new[i]=='/') new[i]='\\';
197 ++i;
198 }
199 new[i] = 0;
200 return new;
201 }
202
203 #ifndef WIN
204 // Convert backslashes (DOS) to forward slashes (everything else).
205 // Return a pointer to buffer with filename using forward slash as separator.
slashfwd(const char * sz)206 static char * slashfwd(const char *sz)
207 {
208 int i=0;
209 static char new[256];
210 while(sz[i] && i<255)
211 {
212 new[i] = sz[i];
213 if(new[i]=='\\') new[i]='/';
214 ++i;
215 }
216 new[i] = 0;
217 return new;
218 }
219 #endif
220
221 #ifdef LINUX
casesearch(const char * dir,const char * filepath)222 char * casesearch(const char *dir, const char *filepath)
223 {
224 DIR *d;
225 struct dirent *entry;;
226 char filename[256] = {""}, *rest_of_path;
227 static char fullpath[256];
228 int i=0;
229 #ifdef VERBOSE
230 printf("casesearch: %s, %s\n", dir, filepath);
231 #endif
232
233 if ((d=opendir(dir)) == NULL) return NULL;
234
235 // are we searching for a file or a directory?
236 rest_of_path = strchr(filepath, '/');
237 if (rest_of_path != NULL) // directory
238 {
239 assert(rest_of_path-filepath > 0);
240 strncat(filename, filepath, rest_of_path-filepath);
241 rest_of_path++;
242 } else strcpy(filename, filepath); // file
243
244 while ((entry=readdir(d)) != NULL)
245 {
246 if (stricmp(entry->d_name, filename) == 0)
247 {
248 i = 1;
249 break;
250 }
251 }
252
253 if (entry != NULL && entry->d_name != NULL)
254 sprintf(fullpath, "%s/%s", dir, entry->d_name);
255
256 if (closedir(d)) return NULL;
257 if (i == 0) return NULL;
258
259 return rest_of_path == NULL ? fullpath : casesearch(fullpath, rest_of_path);
260 }
261
262 #endif
263
264 /////////////////////////////////////////////////////////////////////////////
265
getFreeHandle(void)266 int getFreeHandle(void) {
267 int h;
268 for(h=0; h<MAXPACKHANDLES && packhandle[h]>-1; h++); // Find free handle
269 if(h>=MAXPACKHANDLES) {
270 printf ("no free handles\n"); // since this condition shuts down openbor, we can savely give more info.
271 return -1; // No free handles
272 }
273 return h;
274 }
275
276
packfile_mode(int mode)277 void packfile_mode(int mode)
278 {
279 if(!mode)
280 {
281 #ifdef DC
282 fs_chdir("/cd");
283 #endif
284 pOpenPackfile = openPackfile;
285 pReadPackfile = readPackfile;
286 pSeekPackfile = seekPackfile;
287 pClosePackfile = closePackfile;
288 return;
289 }
290 pOpenPackfile = openPackfileCached;
291 pReadPackfile = readPackfileCached;
292 pSeekPackfile = seekPackfileCached;
293 pClosePackfile = closePackfileCached;
294 }
295
296
297 /////////////////////////////////////////////////////////////////////////////
298
isRawData()299 int isRawData()
300 {
301 DIR *d;
302 if ((d=opendir("data")) == NULL) return 0;
303 closedir(d);
304 return 1;
305 }
306
307 /////////////////////////////////////////////////////////////////////////////
308
openpackfile(const char * filename,const char * packfilename)309 int openpackfile(const char *filename, const char *packfilename)
310 {
311 #ifdef VERBOSE
312 char* pointsto;
313
314 if (pOpenPackfile == openPackfileCached)
315 pointsto = "oPackCached";
316 else if (pOpenPackfile == openPackfile)
317 pointsto = "openPackFile";
318 else
319 pointsto = "unknown destination";
320 printf ("openpackfile called: f: %s, p: %s, dest: %s\n", filename, packfilename, pointsto);
321 #endif
322 return pOpenPackfile(filename, packfilename);
323 }
324
openPackfile(const char * filename,const char * packfilename)325 int openPackfile(const char *filename, const char *packfilename)
326 {
327 int h, handle;
328 unsigned int magic, version, headerstart, p;
329 pnamestruct pn;
330 #ifdef LINUX
331 char *fspath;
332 #endif
333
334 h = getFreeHandle();
335 if (h == -1) return -1;
336
337 #ifdef WIN
338 // Convert slashes to backslashes
339 filename = slashback(filename);
340 #else
341 // Convert backslashes to slashes
342 filename = slashfwd(filename);
343 #endif
344
345 packfilepointer[h] = 0;
346
347 // Separate file present?
348 if((handle=open(filename, O_RDONLY|O_BINARY, 777))!=-1)
349 {
350 if((packfilesize[h]=lseek(handle,0,SEEK_END))==-1)
351 {
352 #ifdef VERBOSE
353 printf ("err handles 1\n");
354 #endif
355 close(handle);
356 return -1;
357 }
358 if(lseek(handle,0,SEEK_SET)==-1)
359 {
360 #ifdef VERBOSE
361 printf ("err handles 2\n");
362 #endif
363 close(handle);
364 return -1;
365 }
366 packhandle[h] = handle;
367 return h;
368 }
369
370 #ifdef LINUX
371 // Try a case-insensitive search for a separate file.
372 fspath = casesearch(".", filename);
373 if (fspath != NULL)
374 {
375 if((handle=open(fspath, O_RDONLY|O_BINARY, 777))!=-1)
376 {
377 if((packfilesize[h]=lseek(handle,0,SEEK_END))==-1)
378 {
379 #ifdef VERBOSE
380 printf ("err handles 3\n");
381 #endif
382 close(handle);
383 return -1;
384 }
385 if(lseek(handle,0,SEEK_SET)==-1)
386 {
387 #ifdef VERBOSE
388 printf ("err handles 4\n");
389 #endif
390 close(handle);
391 return -1;
392 }
393 packhandle[h] = handle;
394 return h;
395 }
396 }
397 #endif
398
399 #ifndef WIN
400 // Convert slashes to backslashes
401 filename = slashback(filename);
402 #endif
403
404 // Try to open packfile
405 if((handle=open(packfilename, O_RDONLY|O_BINARY, 777))==-1) {
406 #ifdef VERBOSE
407 printf ("perm err\n");
408 #endif
409 return -1;
410 }
411
412
413 // Read magic dword ("PACK" identifier)
414 if(read(handle,&magic,4)!=4 || magic!=SwapLSB32(PACKMAGIC))
415 {
416 #ifdef VERBOSE
417 printf ("err magic\n");
418 #endif
419 close(handle);
420 return -1;
421 }
422 // Read version from packfile
423 if(read(handle,&version,4)!=4 || version!=SwapLSB32(PACKVERSION))
424 {
425 #ifdef VERBOSE
426 printf ("err version\n");
427 #endif
428
429 close(handle);
430 return -1;
431 }
432
433 // Seek to position of headerstart indicator
434 if(lseek(handle,-4,SEEK_END)==-1)
435 {
436 #ifdef VERBOSE
437 printf ("seek failed\n");
438 #endif
439 close(handle);
440 return -1;
441 }
442 // Read headerstart
443 if(read(handle,&headerstart,4)!=4)
444 {
445 #ifdef VERBOSE
446 printf ("err header\n");
447 #endif
448 close(handle);
449 return -1;
450 }
451
452 headerstart = SwapLSB32(headerstart);
453
454 // Seek to headerstart
455 if(lseek(handle,headerstart,SEEK_SET)==-1)
456 {
457 #ifdef VERBOSE
458 printf ("err headerstart 1\n");
459 #endif
460 close(handle);
461 return -1;
462 }
463
464 p = headerstart;
465
466 // Search for filename
467 while(read(handle,&pn,sizeof(pn))>12)
468 {
469 pn.filesize = SwapLSB32(pn.filesize);
470 pn.filestart = SwapLSB32(pn.filestart);
471 pn.pns_len = SwapLSB32(pn.pns_len);
472
473 if(stricmp(filename,pn.namebuf)==0)
474 {
475 packhandle[h] = handle;
476 packfilesize[h] = pn.filesize;
477 lseek(handle,pn.filestart,SEEK_SET);
478 return h;
479 }
480 p += pn.pns_len;
481 if(lseek(handle,p,SEEK_SET)==-1)
482 {
483 #ifdef VERBOSE
484 printf ("err seek handles\n");
485 #endif
486 close(handle);
487 return -1;
488 }
489 }
490 // Filename not found
491 #ifdef VERBOSE
492 printf ("err filename not found\n");
493 #endif
494 close(handle);
495 return -1;
496 }
497
update_filecache_vfd(int vfd)498 void update_filecache_vfd(int vfd)
499 {
500 if(pak_vfdexists[vfd]) filecache_setvfd(vfd, pak_vfdstart[vfd], (pak_vfdstart[vfd] + pak_vfdpos[vfd]) / CACHEBLOCKSIZE, (pak_vfdreadahead[vfd] + (CACHEBLOCKSIZE-1)) / CACHEBLOCKSIZE);
501 else filecache_setvfd(vfd, -1, -1, 0);
502 }
503
makefilenamecache(void)504 void makefilenamecache(void) {
505 ptrdiff_t hpos;
506 char target[256];
507
508 if(!filenamelist)
509 filenamelist = malloc(sizeof(List));
510 List_Init(filenamelist);
511
512 // look for filename in the header
513
514 hpos = 0;
515 for(;;)
516 {
517 if((hpos + 12) >= pak_headersize)
518 return;
519 strncpy(target, (char*)pak_header + hpos + 12, 256);
520 fnlc(target);
521 List_InsertAfter(filenamelist, (void*) hpos, target);
522 hpos += readlsb32(pak_header + hpos);
523 }
524 }
525
freefilenamecache(void)526 void freefilenamecache(void) {
527 Node* n;
528 size_t count = 0;
529 size_t total = 0;
530 if(filenamelist) {
531 if(printFileUsageStatistics) {
532 printf("unused files in the pack:\n");
533 List_GotoFirst(filenamelist);
534 n = List_GetCurrentNode(filenamelist);
535 while(n) {
536 if(((size_t) n->value & USED_FLAG) != USED_FLAG) {
537 count++;
538 printf("%s\n",n->name);
539 }
540 if(List_GotoNext(filenamelist))
541 n = List_GetCurrentNode(filenamelist);
542 else break;
543 total++;
544 }
545 printf("Summary: %d of %d files have been unused\n", (int) count, (int) total);
546 printf("WARNING\n");
547 printf("to be completely sure if a file is unused, you have to play the entire mod\n");
548 printf("in every possible branch, including every possible player, and so forth.\n");
549 printf("so only remove stuff from a foreign mod if you're completely sure that it is unused.\n");
550 }
551 List_Clear(filenamelist);
552 free(filenamelist);
553 filenamelist = NULL;
554 }
555 }
556
openreadaheadpackfile(const char * filename,const char * packfilename,int readaheadsize,int prebuffersize)557 int openreadaheadpackfile(const char *filename, const char *packfilename, int readaheadsize, int prebuffersize)
558 {
559 size_t hpos;
560 int vfd;
561 size_t fnl;
562 size_t al;
563 char target[256];
564 Node* n;
565
566 if(packfilename != packfile) {
567 fnl = strlen(packfile);
568 al = strlen(packfilename);
569 if(myfilenamecmp(packfilename, al, packfile, fnl))
570 {
571 printf("tried to open from unknown pack file (%s)\n", packfilename);
572 return -1;
573 }
574 }
575
576 if(!filenamelist)
577 makefilenamecache();
578
579 strncpy(target, filename, 256);
580 fnlc(target);
581
582 n = List_GetNodeByName(filenamelist, target);
583 if (!n)
584 return -1;
585
586 hpos = (size_t) n->value & ~USED_FLAG;
587 n->value = (void*) (((size_t) n->value) | USED_FLAG);
588
589 // find a free vfd
590 for(vfd = 0; vfd < MAXPACKHANDLES; vfd++) if(!pak_vfdexists[vfd]) break;
591 if(vfd >= MAXPACKHANDLES) return -1;
592
593 pak_vfdstart[vfd] = readlsb32(pak_header + hpos + 4);
594 pak_vfdsize[vfd] = readlsb32(pak_header + hpos + 8);
595
596 pak_vfdpos[vfd] = 0;
597 pak_vfdexists[vfd] = 1;
598 pak_vfdreadahead[vfd] = readaheadsize;
599
600 // notify filecache that we have a new vfd
601 update_filecache_vfd(vfd);
602
603 // if we want prebuffering, wait for it
604 if(prebuffersize > 0) filecache_wait_for_prebuffer(vfd, (prebuffersize + ((CACHEBLOCKSIZE)-1)) / CACHEBLOCKSIZE);
605 return vfd;
606 }
607
openPackfileCached(const char * filename,const char * packfilename)608 int openPackfileCached(const char *filename, const char *packfilename)
609 {
610 return openreadaheadpackfile(filename, packfilename, 0, 0);
611 }
612
613 /////////////////////////////////////////////////////////////////////////////
614
readpackfile(int handle,void * buf,int len)615 int readpackfile(int handle, void *buf, int len)
616 {
617 return pReadPackfile(handle, buf, len);
618 }
619
readPackfile(int handle,void * buf,int len)620 int readPackfile(int handle, void *buf, int len)
621 {
622 int realhandle;
623 if(handle<0 || handle>=MAXPACKHANDLES) return -1;
624 if(len<0) return -1;
625 if(len==0) return 0;
626 realhandle = packhandle[handle];
627 if(realhandle == -1) return -1;
628 if(len + packfilepointer[handle] > packfilesize[handle])
629 len = packfilesize[handle] - packfilepointer[handle];
630 if((len = read(realhandle,buf,len))==-1) return -1;
631 packfilepointer[handle] += len;
632 return len;
633 }
634
pak_isvalidhandle(int handle)635 int pak_isvalidhandle(int handle)
636 {
637 if(handle < 0 || handle >= MAXPACKHANDLES) return 0;
638 if(!pak_vfdexists[handle]) return 0;
639 return 1;
640 }
641
pak_rawread(int fd,unsigned char * dest,int len,int blocking)642 static int pak_rawread(int fd, unsigned char *dest, int len, int blocking)
643 {
644 int end;
645 int r;
646 int total = 0;
647 int pos = pak_vfdstart[fd] + pak_vfdpos[fd];
648
649 if(pos < 0) return 0;
650 if(pos >= paksize) return 0;
651 if((pos + len) > paksize) { len = paksize - pos; }
652 end = pos + len;
653
654 update_filecache_vfd(fd);
655
656 while(pos < end)
657 {
658 int b = pos / CACHEBLOCKSIZE;
659 int startthisblock = pos % CACHEBLOCKSIZE;
660 int sizethisblock = CACHEBLOCKSIZE - startthisblock;
661 if(sizethisblock > (end-pos)) sizethisblock = (end-pos);
662 r = filecache_readpakblock(dest, b, startthisblock, sizethisblock, blocking);
663 if(r >= 0)
664 {
665 total += r;
666 pak_vfdpos[fd] += r;
667 update_filecache_vfd(fd);
668 }
669 if(r < sizethisblock) break;
670
671 dest += sizethisblock;
672 pos += sizethisblock;
673 }
674 return total;
675 }
676
readpackfileblocking(int fd,void * buf,int len,int blocking)677 int readpackfileblocking(int fd, void *buf, int len, int blocking)
678 {
679 int n;
680 if(!pak_isvalidhandle(fd)) return -1;
681 if(pak_vfdpos[fd] < 0) return 0;
682 if(pak_vfdpos[fd] > pak_vfdsize[fd]) pak_vfdpos[fd] = pak_vfdsize[fd];
683 if((len + pak_vfdpos[fd]) > pak_vfdsize[fd]) { len = pak_vfdsize[fd] - pak_vfdpos[fd]; }
684 if(len < 1) return 0;
685 update_filecache_vfd(fd);
686 n = pak_rawread(fd, buf, len, blocking);
687 if(n < 0) n = 0;
688 if(pak_vfdpos[fd] > pak_vfdsize[fd]) pak_vfdpos[fd] = pak_vfdsize[fd];
689 update_filecache_vfd(fd);
690 return n;
691 }
692
readpackfile_noblock(int handle,void * buf,int len)693 int readpackfile_noblock(int handle, void *buf, int len)
694 {
695 return readpackfileblocking(handle, buf, len, 0);
696 }
697
readPackfileCached(int handle,void * buf,int len)698 int readPackfileCached(int handle, void *buf, int len)
699 {
700 return readpackfileblocking(handle, buf, len, 1);
701 }
702
703 /////////////////////////////////////////////////////////////////////////////
704
closepackfile(int handle)705 int closepackfile(int handle)
706 {
707 #ifdef VERBOSE
708 char* pointsto;
709
710 if (pClosePackfile == closePackfileCached)
711 pointsto = "closePackCached";
712 else if (pClosePackfile == closePackfile)
713 pointsto = "closePackFile";
714 else
715 pointsto = "unknown destination";
716 printf ("closepackfile called: h: %d, dest: %s\n", handle, pointsto);
717 #endif
718 return pClosePackfile(handle);
719 }
720
closePackfile(int handle)721 int closePackfile(int handle)
722 {
723 #ifdef VERBOSE
724 printf ("closePackfile called: h: %d\n", handle);
725 #endif
726
727 if(handle<0 || handle>=MAXPACKHANDLES)
728 {
729 #ifdef VERBOSE
730 printf("handle too small/big\n");
731 #endif
732 return -1;
733 }
734 if(packhandle[handle] == -1) {
735 #ifdef VERBOSE
736 printf("packhandle -1\n");
737 #endif
738 return -1;
739 }
740 close(packhandle[handle]);
741 packhandle[handle] = -1;
742 return 0;
743 }
744
closePackfileCached(int handle)745 int closePackfileCached(int handle)
746 {
747 if(!pak_isvalidhandle(handle)) return -1;
748 pak_vfdexists[handle] = 0;
749 update_filecache_vfd(handle);
750 return 0;
751 }
752
753
754 /////////////////////////////////////////////////////////////////////////////
755
seekpackfile(int handle,int offset,int whence)756 int seekpackfile(int handle, int offset, int whence)
757 {
758 return pSeekPackfile(handle, offset, whence);
759 }
760
seekPackfile(int handle,int offset,int whence)761 int seekPackfile(int handle, int offset, int whence)
762 {
763 int realhandle;
764 int desiredoffs;
765
766 if(handle<0 || handle>=MAXPACKHANDLES) return -1;
767 realhandle = packhandle[handle];
768 if(realhandle == -1) return -1;
769
770 switch(whence)
771 {
772 case SEEK_SET:
773 desiredoffs = offset;
774 if(desiredoffs>packfilesize[handle])
775 desiredoffs = packfilesize[handle];
776 else if(desiredoffs<0)
777 desiredoffs = 0;
778 break;
779
780 case SEEK_CUR:
781 desiredoffs = packfilepointer[handle] + offset;
782 if(desiredoffs>packfilesize[handle])
783 desiredoffs = packfilesize[handle];
784 else if(desiredoffs<0)
785 desiredoffs = 0;
786 break;
787
788 case SEEK_END:
789 desiredoffs = packfilesize[handle] + offset;
790 if(desiredoffs>packfilesize[handle])
791 desiredoffs = packfilesize[handle];
792 else if(desiredoffs<0)
793 desiredoffs = 0;
794 break;
795
796 default:
797 return -1;
798 }
799 desiredoffs -= packfilepointer[handle];
800 if((lseek(realhandle,desiredoffs,SEEK_CUR))==-1) return -1;
801 packfilepointer[handle] += desiredoffs;
802 return packfilepointer[handle];
803 }
804
seekPackfileCached(int handle,int offset,int whence)805 int seekPackfileCached(int handle, int offset, int whence)
806 {
807 if(!pak_isvalidhandle(handle)) return -1;
808 switch(whence)
809 {
810 case 0: pak_vfdpos[handle] = offset; break; // set
811 case 1: pak_vfdpos[handle] += offset; break; // cur
812 case 2: pak_vfdpos[handle] = pak_vfdsize[handle] + offset; break; // end
813 default: return -1;
814 }
815 // original code had this check too, so do it here
816 if(pak_vfdpos[handle] < 0) pak_vfdpos[handle] = 0;
817 if(pak_vfdpos[handle] > pak_vfdsize[handle]) pak_vfdpos[handle] = pak_vfdsize[handle];
818 update_filecache_vfd(handle);
819 return pak_vfdpos[handle];
820 }
821
822 #ifdef PS2
flushfd(int fd)823 static void flushfd(int fd)
824 {
825 int busy = 1;
826 while(busy) sceIoctl(fd, SCE_FS_EXECUTING, &busy);
827 }
828 #endif
829
830 /////////////////////////////////////////////////////////////////////////////
831 //
832 // returns number of sectors read successfully
833 //
pak_getsectors(void * dest,int lba,int n)834 static int pak_getsectors(void *dest, int lba, int n)
835 {
836 #ifdef PS2
837 sceLseek(pakfd, lba << 11, SCE_SEEK_SET);
838 flushfd(pakfd);
839 sceRead(pakfd, dest, n << 11);
840 flushfd(pakfd);
841 #elif DC
842 if((lba+n) > ((paksize+0x7FF)/0x800)) {
843 n = ((paksize+0x7FF)/0x800)-lba;
844 }
845 if(pakfd >= 0) {
846 lseek(pakfd, lba << 11, SEEK_SET);
847 read(pakfd, dest, n << 11);
848 } else {
849 gdrom_readsectors(dest, (-pakfd)+lba, n);
850 while(gdrom_poll());
851 }
852 #else
853 int disCcWarns;
854 lseek(pakfd, lba << 11, SEEK_SET);
855 disCcWarns = read(pakfd, dest, n << 11);
856 #endif
857 return n;
858 }
859
860 #ifdef DC
861 /////////////////////////////////////////////////////////////////////////////
862 //
863 // returns 0 if they match
864 //
fncmp(const char * filename,const char * isofilename,int isolen)865 static int fncmp(const char *filename, const char *isofilename, int isolen)
866 {
867 for(; isolen > 0; isolen--)
868 {
869 char cf = *filename++;
870 char ci = *isofilename++;
871 if(!cf)
872 {
873 // allowed to omit the version on filename
874 if(ci == ';' || ci == 0) return 0;
875 return 1;
876 }
877 if(cf >= 'A' && cf <= 'Z') cf += 'a' - 'A';
878 if(ci >= 'A' && ci <= 'Z') ci += 'a' - 'A';
879 if(cf != ci) return 1;
880 }
881 // allowed to omit the version on isofilename too O_o
882 if(*filename == ';' || *filename == 0) return 0;
883 return 1;
884 }
885
886 /////////////////////////////////////////////////////////////////////////////
887 //
888 // input: starting lba of the track
889 // returns starting lba of the file, or 0 on failure
890 //
find_iso_file(const char * filename,int lba,int * bytes)891 int find_iso_file(const char *filename, int lba, int *bytes)
892 {
893 int dirlen;
894 unsigned char sector[4096];
895 int secofs;
896
897 // read the root descriptor
898 gdrom_readsectors(sector, lba+16, 1); while(gdrom_poll());
899 // get the root directory extent and size
900 lba = 150 + readmsb32(sector+156+6);
901 dirlen = readmsb32(sector+156+14);
902
903 // at this point, lba is the lba of the root dir
904 secofs = 4096;
905 while(dirlen > 0) {
906 if(secofs >= 4096 || ((secofs + sector[secofs]) > 4096)) {
907 memcpy(sector, sector+2048, 2048);
908 gdrom_readsectors(sector+2048, lba, 1); while(gdrom_poll());
909 lba++;
910 secofs -= 2048;
911 }
912 if(!sector[secofs]) break;
913 if(!fncmp(filename, sector+secofs+33, sector[secofs+32])) {
914 lba = 150 + readmsb32(sector+secofs+6);
915 if(bytes) *bytes = readmsb32(sector+secofs+14);
916 return lba;
917 }
918 secofs += sector[secofs];
919 dirlen -= sector[secofs];
920 }
921 // didn't find the file
922 return 0;
923 }
924 #endif
925
926 /////////////////////////////////////////////////////////////////////////////
927
pak_term()928 void pak_term()
929 {
930 int i;
931 if(!pak_initialized) return;
932 if(pak_cdheader != NULL)
933 {
934 free(pak_cdheader);
935 pak_cdheader = NULL;
936 }
937 filecache_term();
938 close(pakfd);
939 pakfd = -1;
940 paksize = -1;
941 pak_headerstart = -1;
942 pak_headersize = -1;
943 for(i=0; i<MAXPACKHANDLES; i++)
944 {
945 pak_vfdexists[i] = -1;
946 pak_vfdstart[i] = -1;
947 pak_vfdsize[i] = -1;
948 pak_vfdpos[i] = -1;
949 pak_vfdreadahead[i] = -1;
950 }
951 pak_initialized = 0;
952 }
953
954 /////////////////////////////////////////////////////////////////////////////
955
pak_init()956 int pak_init()
957 {
958 int i;
959 unsigned char *sectors;
960 unsigned int magic, version;
961
962 if(pak_initialized)
963 {
964 printf("pak_init already initialized!");
965 return 0;
966 }
967
968 if(isRawData())
969 {
970 pak_initialized = 1;
971 return 0;
972 }
973
974 pOpenPackfile = openPackfileCached;
975 pReadPackfile = readPackfileCached;
976 pSeekPackfile = seekPackfileCached;
977 pClosePackfile = closePackfileCached;
978
979 #if DC
980 if(cd_lba)
981 {
982 paksize = 0;
983 pakfd = find_iso_file(packfile, cd_lba, &paksize);
984 if(pakfd <= 0) { printf("unable to find pak file on cd\n"); return 0; }
985 pakfd = -pakfd;
986 }
987 else
988 {
989 #endif
990
991 #ifdef PS2
992 pakfd = sceOpen(ps2gethostfilename(packfile), SCE_RDONLY|SCE_NOWAIT, 0);
993 #else
994 pakfd = open(packfile, O_RDONLY|O_BINARY, 777);
995 #endif
996
997 if(pakfd < 0)
998 {
999 printf("error opening %s (%d) - could not get a valid device descriptor.\n%s\n", packfile, pakfd, strerror(errno));
1000 return 0;
1001 }
1002
1003 #ifdef PS2
1004 paksize = sceLseek(pakfd, 0, SCE_SEEK_END);
1005 #else
1006 paksize = lseek(pakfd, 0, SEEK_END);
1007 #endif
1008
1009 #ifdef DC
1010 }
1011 #endif
1012
1013 // Is it a valid Packfile
1014 #ifdef PS2
1015 sceClose(pakfd);
1016 pakfd = sceOpen(ps2gethostfilename(packfile), SCE_RDONLY, 0);
1017 #else
1018 close(pakfd);
1019 pakfd = open(packfile, O_RDONLY|O_BINARY, 777);
1020 #endif
1021
1022 // Read magic dword ("PACK")
1023 if(read(pakfd,&magic,4)!=4 || magic!=SwapLSB32(PACKMAGIC))
1024 {
1025 close(pakfd);
1026 return -1;
1027 }
1028 // Read version from packfile
1029 if(read(pakfd,&version,4)!=4 || version!=SwapLSB32(PACKVERSION))
1030 {
1031 close(pakfd);
1032 return -1;
1033 }
1034
1035 sectors = malloc(4096);
1036 if(!sectors) { printf("sector malloc failed\n"); return 0; }
1037 {
1038 int getptrfrom = paksize - 4;
1039 if(pak_getsectors(sectors, getptrfrom >> 11, 2) < 1)
1040 {
1041 printf("unable to read pak header pointer\n");
1042 return 0;
1043 }
1044 pak_headerstart = readlsb32(sectors + (getptrfrom & 0x7FF));
1045 }
1046 free(sectors);
1047 if(pak_headerstart >= paksize || pak_headerstart < 0)
1048 {
1049 printf("invalid pak header pointer\n");
1050 return 0;
1051 }
1052 pak_headersize = paksize - pak_headerstart;
1053 {
1054 // let's cache it on CD sector boundaries
1055 int pak_cdheaderstart = pak_headerstart & (~0x7FF);
1056 int pak_cdheadersize = ((paksize - pak_cdheaderstart) + 0x7FF) & (~0x7FF);
1057 if(pak_cdheadersize > 524288)
1058 {
1059 // Original value was 262144, which has been doubled.
1060 // I can not find a reason why it was orginally set to
1061 // this size. Hence, I have doubled it. This could
1062 // pose a problem on optical media, but that is yet to be
1063 // determined.
1064 printf("Warning: pak header is too large: %d / 524288\n",pak_cdheadersize);
1065 //return 0;
1066 }
1067 pak_cdheader = malloc(pak_cdheadersize);
1068 if(!pak_cdheader) { printf("pak_cdheader malloc failed\n"); return 0; }
1069 if(pak_getsectors(pak_cdheader, pak_cdheaderstart >> 11, pak_cdheadersize >> 11) != (pak_cdheadersize >> 11))
1070 {
1071 printf("unable to read pak header\n");
1072 return 0;
1073 }
1074 // ok, header is now cached
1075 pak_header = pak_cdheader + (pak_headerstart & 0x7FF);
1076 }
1077 // header does not include the last 4-byte stuff
1078 if(pak_headersize >= 4)
1079 {
1080 pak_headersize -= 4;
1081 // add a trailing null o/~
1082 pak_header[pak_headersize] = 0;
1083 }
1084 //printf("pak cached header (%d bytes)\n", pak_headersize);
1085 // initialize vfd table
1086 for(i = 0; i < MAXPACKHANDLES; i++) pak_vfdexists[i] = 0;
1087 // finally, initialize the filecache
1088 filecache_init(pakfd, (paksize + 0x7FF) / 0x800, CACHEBLOCKSIZE, CACHEBLOCKS, MAXPACKHANDLES);
1089 pak_initialized = 1;
1090 return (CACHEBLOCKSIZE * CACHEBLOCKS + 64);
1091 }
1092
1093 /////////////////////////////////////////////////////////////////////////////
1094
packfileeof(int handle)1095 int packfileeof(int handle)
1096 {
1097 if(!pak_isvalidhandle(handle)) return -1;
1098 return (pak_vfdpos[handle] >= pak_vfdsize[handle]);
1099 }
1100
1101 /////////////////////////////////////////////////////////////////////////////
1102
packfile_supported(struct dirent * ds)1103 int packfile_supported(struct dirent* ds)
1104 {
1105 if(stricmp(ds->d_name, "menu.pak") != 0)
1106 {
1107 if (stristr(ds->d_name, ".pak")) return 1;
1108 }
1109 return 0;
1110 }
1111
1112 /////////////////////////////////////////////////////////////////////////////
1113
packfile_get_titlename(char In[80],char Out[80])1114 void packfile_get_titlename(char In[80], char Out[80])
1115 {
1116 int i, x=0, y=0;
1117 for(i=0; i<(int)strlen(In); i++){
1118 if((In[i] == '/') || (In[i] == '\\')) x = i;
1119 }
1120 for(i=0; i<(int)strlen(In); i++){
1121 if(i > x){
1122 Out[y] = In[i];
1123 y++;
1124 }
1125 }
1126 }
1127
packfile_music_read(fileliststruct * filelist,int dListTotal)1128 void packfile_music_read(fileliststruct *filelist, int dListTotal)
1129 {
1130 pnamestruct pn;
1131 FILE *fd;
1132 int len, i;
1133 unsigned int off;
1134 char pack[4], *p = NULL;
1135 for(i = 0; i < dListTotal; i++)
1136 {
1137 getBasePath(packfile, filelist[i].filename, 1);
1138 if(stristr(packfile, ".pak"))
1139 {
1140 memset(filelist[i].bgmTracks, 0, sizeof(filelist[i].bgmTracks));
1141 filelist[i].nTracks = 0;
1142 fd = fopen(packfile, "rb");
1143 if(fd == NULL) continue;
1144 if(!fread(pack, 4, 1, fd)) goto closepak;
1145 if(fseek(fd, -4, SEEK_END) < 0) goto closepak;
1146 if(!fread(&off, 4, 1, fd)) goto closepak;
1147 if(fseek(fd, off, SEEK_SET) < 0) goto closepak;
1148 while((len = fread(&pn, 1, sizeof(pn), fd)) > 12) {
1149 p = strrchr(pn.namebuf, '.');
1150 if((p && !stricmp(p, ".bor")) || (stristr(pn.namebuf, "music"))) {
1151 if(!stristr(pn.namebuf, ".bor")) goto nextpak;
1152 if(filelist[i].nTracks < 256)
1153 {
1154 packfile_get_titlename(pn.namebuf, filelist[i].bgmFileName[filelist[i].nTracks]);
1155 filelist[i].bgmTracks[filelist[i].nTracks] = off;
1156 filelist[i].nTracks++;
1157 }
1158 }
1159 nextpak:
1160 off += pn.pns_len;
1161 if(fseek(fd, off, SEEK_SET) < 0) goto closepak;
1162 }
1163 closepak:
1164 fclose(fd);
1165 }
1166 }
1167 }
1168
1169 /////////////////////////////////////////////////////////////////////////////
1170
packfile_music_play(struct fileliststruct * filelist,FILE * bgmFile,int bgmLoop,int curPos,int scrPos)1171 int packfile_music_play(struct fileliststruct* filelist, FILE *bgmFile, int bgmLoop, int curPos, int scrPos)
1172 {
1173 pnamestruct pn;
1174 int len;
1175 getBasePath(packfile, filelist[curPos+scrPos].filename, 1);
1176 if (bgmFile)
1177 {
1178 fclose(bgmFile);
1179 bgmFile = NULL;
1180 }
1181 bgmFile = fopen(packfile, "rb");
1182 if (!bgmFile) return 0;
1183 if (stristr(packfile, ".pak"))
1184 {
1185 if(fseek(bgmFile, filelist[curPos+scrPos].bgmTracks[filelist[curPos+scrPos].bgmTrack], SEEK_SET) < 0) return 0;
1186 if((len = fread(&pn, 1, sizeof(pn), bgmFile)) > 12) sound_open_music(pn.namebuf, packfile, savedata.musicvol, bgmLoop, 0);
1187 }
1188 return 1;
1189 }
1190
1191 #endif
1192
1193
1194
1195