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