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