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 #include <fcntl.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdarg.h>
13 #include <stdlib.h>
14 #include <locale.h>
15 #include <math.h>
16 
17 #include "stringptr.h"
18 #include "utils.h"
19 #include "stristr.h"
20 #include "openbor.h"
21 #include "packfile.h"
22 
23 #if PSP || WIN || LINUX || GP2X || DINGOO || SYMBIAN
24 #include <dirent.h>
25 #endif
26 
27 #if GP2X || LINUX || DINGOO
28 #include <sys/stat.h>
29 #endif
30 
31 #ifdef DOS
32 #include <direct.h>
33 #include "dosport.h"
34 #include "savepng.h"
35 #endif
36 
37 #ifdef SDL
38 #include <unistd.h>
39 #include "sdlport.h"
40 #include "savepng.h"
41 #endif
42 
43 #ifdef DC
44 #include "dcport.h"
45 #endif
46 
47 #ifdef XBOX
48 #include "xboxport.h"
49 #include "savepng.h"
50 #endif
51 
52 #ifdef PSP
53 #include "image.h"
54 #endif
55 
56 
57 #if WII && !SDL
58 #include "wiiport.h"
59 #include "savepng.h"
60 #endif
61 
62 #if PSP || GP2X || LINUX || DINGOO || WII || SYMBIAN
63 #define MKDIR(x) mkdir(x, 0777)
64 #else
65 #define MKDIR(x) mkdir(x)
66 #endif
67 
68 #ifdef XBOX
69 #define CHECK_LOGFILE(type)  type ? fileExists("d:\\Logs\\OpenBorLog.txt") : fileExists("d:\\Logs\\ScriptLog.txt")
70 #define OPEN_LOGFILE(type)   type ? fopen("d:\\Logs\\OpenBorLog.txt", "wt") : fopen("d:\\Logs\\ScriptLog.txt", "wt")
71 #define APPEND_LOGFILE(type) type ? fopen("d:\\Logs\\OpenBorLog.txt", "at") : fopen("d:\\Logs\\ScriptLog.txt", "at")
72 #define READ_LOGFILE(type)   type ? fopen("d:\\Logs\\OpenBorLog.txt", "rt") : fopen("d:\\Logs\\ScriptLog.txt", "rt")
73 #define COPY_ROOT_PATH(buf, name) strncpy(buf, "d:\\", 3); strncat(buf, name, strlen(name)); strncat(buf, "\\", 1)
74 #define COPY_PAKS_PATH(buf, name) strncpy(buf, "d:\\Paks\\", 8); strncat(buf, name, strlen(name))
75 #elif WII && !SDL
76 #define CHECK_LOGFILE(type)  type ? fileExists(getFullPath("Logs/OpenBorLog.txt")) : fileExists(getFullPath("Logs/ScriptLog.txt"))
77 #define OPEN_LOGFILE(type)   type ? fopen(getFullPath("Logs/OpenBorLog.txt"), "wt") : fopen(getFullPath("Logs/ScriptLog.txt"), "wt")
78 #define APPEND_LOGFILE(type) type ? fopen(getFullPath("Logs/OpenBorLog.txt"), "at") : fopen(getFullPath("Logs/ScriptLog.txt"), "at")
79 #define READ_LOGFILE(type)   type ? fopen(getFullPath("Logs/OpenBorLog.txt"), "rt") : fopen(getFullPath("Logs/ScriptLog.txt"), "rt")
80 #define COPY_ROOT_PATH(buf, name) strcpy(buf, rootDir); strncat(buf, name, strlen(name)); strncat(buf, "/", 1);
81 #define COPY_PAKS_PATH(buf, name) strncpy(buf, paksDir, strlen(paksDir)); strncat(buf, "/", 1); strncat(buf, name, strlen(name));
82 #elif WII && SDL
83 #define CHECK_LOGFILE(type)  type ? fileExists("sd:/apps/OpenBOR/Logs/OpenBorLog.txt") : fileExists("sd:/apps/OpenBOR/Logs/ScriptLog.txt")
84 #define OPEN_LOGFILE(type)   type ? fopen("sd:/apps/OpenBOR/Logs/OpenBorLog.txt", "wt") : fopen("sd:/apps/OpenBOR/Logs/ScriptLog.txt", "wt")
85 #define APPEND_LOGFILE(type) type ? fopen("sd:/apps/OpenBOR/Logs/OpenBorLog.txt", "at") : fopen("sd:/apps/OpenBOR/Logs/ScriptLog.txt", "at")
86 #define READ_LOGFILE(type)   type ? fopen("sd:/apps/OpenBOR/Logs/OpenBorLog.txt", "rt") : fopen("sd:/apps/OpenBOR/Logs/ScriptLog.txt", "rt")
87 #define COPY_ROOT_PATH(buf, name) strncpy(buf, "sd:/apps/OpenBOR/", 17); strncat(buf, name, strlen(name)); strncat(buf, "/", 1);
88 #define COPY_PAKS_PATH(buf, name) strncpy(buf, "sd:/apps/OpenBOR/Paks/", 22); strncat(buf, name, strlen(name));
89 #else
90 #define CHECK_LOGFILE(type)  type ? fileExists("./Logs/OpenBorLog.txt") : fileExists("./Logs/ScriptLog.txt")
91 #define OPEN_LOGFILE(type)   type ? fopen("./Logs/OpenBorLog.txt", "wt") : fopen("./Logs/ScriptLog.txt", "wt")
92 #define APPEND_LOGFILE(type) type ? fopen("./Logs/OpenBorLog.txt", "at") : fopen("./Logs/ScriptLog.txt", "at")
93 #define READ_LOGFILE(type)   type ? fopen("./Logs/OpenBorLog.txt", "rt") : fopen("./Logs/ScriptLog.txt", "rt")
94 #define COPY_ROOT_PATH(buf, name) strncpy(buf, "./", 2); strncat(buf, name, strlen(name)); strncat(buf, "/", 1);
95 #define COPY_PAKS_PATH(buf, name) strncpy(buf, "./Paks/", 7); strncat(buf, name, strlen(name));
96 #endif
97 
debugBuf(unsigned char * buf,size_t size,int columns)98 void debugBuf(unsigned char* buf, size_t size, int columns) {
99 	size_t pos = 0;
100 	int i;
101 	while(pos<size) {
102 		for(i=0;i<columns;i++) {
103 			if(pos >= size) break;
104 			printf("%02x", buf[pos]);
105 			pos++;
106 		}
107 		printf("\n");
108 	}
109 }
110 
111 //lowercases a buffer inplace
lc(char * buf,size_t size)112 void lc(char* buf, size_t size) {
113 	ptrdiff_t i;
114 	for(i=0;i<size;i++)
115 		buf[i] = tolower((int)buf[i]);
116 }
117 
118 // returns position after next newline in buf
getNewLineStart(char * buf)119 size_t getNewLineStart(char* buf) {
120 	size_t res = 0;
121 	while(buf[res] && buf[res]!='\n' && buf[res]!='\r') ++res;
122 	while(buf[res] && (buf[res]=='\n' || buf[res]=='\r')) ++res;
123 	return res;
124 }
125 
126 FILE* openborLog = NULL;
127 FILE* scriptLog = NULL;
128 char debug_msg[2048];
129 u32 debug_time = 0;
130 
getBasePath(char * newName,char * name,int type)131 void getBasePath(char *newName, char *name, int type)
132 {
133 #ifndef DC
134 	char buf[128] = {""};
135 	switch(type)
136 	{
137 		case 0:
138 			COPY_ROOT_PATH(buf, name);
139 			break;
140 		case 1:
141 			COPY_PAKS_PATH(buf, name);
142 			break;
143 	}
144 	memcpy(newName, buf, sizeof(buf));
145 #else
146 	memcpy(newName, name, 128);
147 #endif
148 }
149 
150 
151 
152 #ifndef DC
dirExists(char * dname,int create)153 int dirExists(char *dname, int create)
154 {
155 	char realName[128] = {""};
156 #ifdef XBOX
157 	getBasePath(realName, dname, 0);
158 	return CreateDirectory(realName, NULL);
159 #else
160 	DIR	*fd1 = NULL;
161 	int  fd2 = -1;
162 	strncpy(realName, dname, 128);
163 	fd1 = opendir(realName);
164 	if(fd1 != NULL)
165 	{
166 		closedir(fd1);
167 		return 1;
168 	}
169 	if(create)
170 	{
171 		fd2 = MKDIR(realName);
172 		if(fd2 < 0) return 0;
173 #ifdef DARWIN
174 		chmod(realName, 0777);
175 #endif
176 		return 1;
177 	}
178 #endif
179 	return 0;
180 }
181 
fileExists(char * fnam)182 int fileExists(char *fnam)
183 {
184 	FILE *handle = NULL;
185 	if((handle=fopen(fnam,"rb")) == NULL) return 0;
186 	fclose(handle);
187 	return 1;
188 }
189 
readFromLogFile(int which)190 stringptr* readFromLogFile(int which)
191 {
192 	long  size;
193 	FILE* handle = NULL;
194 	stringptr* buffer = NULL;
195 	handle = READ_LOGFILE((which ? OPENBOR_LOG : SCRIPT_LOG));
196 	if(handle == NULL) return NULL;
197 	fseek(handle, 0, SEEK_END);
198 	size = ftell(handle);
199 	rewind(handle);
200 	if (size == 0) goto CLOSE_AND_QUIT;
201 	// allocate memory to contain the whole file:
202 	//buffer = (char*)malloc(sizeof(char)*(size+1)); // alloc one additional byte for the
203 	buffer = new_string(size);
204 	if(buffer == NULL) goto CLOSE_AND_QUIT;
205 	fread(buffer->ptr, 1, size, handle);
206 	CLOSE_AND_QUIT:
207 	fclose(handle);
208 	return buffer;
209 }
210 #endif
211 
writeToLogFile(const char * msg,...)212 void writeToLogFile(const char * msg, ...)
213 {
214 	va_list arglist;
215 
216 #ifdef DC
217 	va_start(arglist, msg);
218 	vfprintf(stdout, msg, arglist);
219 	va_end(arglist);
220 	fflush(stdout);
221 #else
222 	if(openborLog == NULL)
223 	{
224 		openborLog = OPEN_LOGFILE(OPENBOR_LOG);
225 		if(openborLog == NULL) return;
226 	}
227 	va_start(arglist, msg);
228 	vfprintf(openborLog, msg, arglist);
229 	va_end(arglist);
230 	fflush(openborLog);
231 #endif
232 }
233 
writeToScriptLog(const char * msg)234 void writeToScriptLog(const char *msg)
235 {
236 #ifndef DC
237 	if(scriptLog == NULL)
238 	{
239 		scriptLog = OPEN_LOGFILE(SCRIPT_LOG);
240 		if(scriptLog == NULL) return;
241 	}
242 	fwrite(msg, 1, strlen(msg), scriptLog);
243 	fflush(scriptLog);
244 #endif
245 }
246 
debug_printf(char * format,...)247 void debug_printf(char *format, ...){
248 	va_list arglist;
249 
250 	va_start(arglist, format);
251 	vsprintf(debug_msg, format, arglist);
252 	va_end(arglist);
253 
254 	debug_time = 0xFFFFFFFF;
255 }
256 
getPakName(char * name,int type)257 void getPakName(char* name, int type){
258 
259 	int i,x,y;
260 	char mod[256] = {""};
261 
262 	strncpy(mod,packfile,strlen(packfile)-4);
263 
264 	switch(type){
265 		case 0:
266 			strncat(mod,".sav",4);
267 			break;
268 		case 1:
269 			strncat(mod,".hi",3);
270 			break;
271 		case 2:
272 			strncat(mod,".scr",4);
273 			break;
274 		case 3:
275 			strncat(mod,".inp",4);
276 			break;
277 		case 4:
278 			strncat(mod,".cfg",4);
279 			break;
280 		default:
281 			// Loose extension!
282 			break;
283 	}
284 
285 	x=0;
286 	for(i=0; i<(int)strlen(mod); i++){
287 		if((mod[i] == '/') || (mod[i] == '\\')) x = i;
288 	}
289 	y=0;
290 	for(i=0; i<(int)strlen(mod); i++){
291 		// For packfiles without '/'
292 		if(x == 0){
293 			name[y] = mod[i];
294 			y++;
295 		}
296 		// For packfiles with '/'
297 		if(x != 0 && i > x){
298 			name[y] = mod[i];
299 			y++;
300 		}
301 	}
302 	name[y] = 0;
303 }
304 
screenshot(s_screen * vscreen,unsigned char * pal,int ingame)305 void screenshot(s_screen *vscreen, unsigned char *pal, int ingame){
306 #ifndef DC
307 	int	 shotnum = 0;
308 	char shotname[128] = {""};
309 	char modname[128]  = {""};
310 
311 	getPakName(modname,99);
312 #ifdef PSP
313 	if(dirExists("ms0:/PICTURE/", 1) && dirExists("ms0:/PICTURE/Beats Of Rage/", 1)){
314 #endif
315 		do{
316 #if PSP
317 			sprintf(shotname, "ms0:/PICTURE/Beats Of Rage/%s - ScreenShot - %02u.png", modname,shotnum);
318 #elif DOS
319 			sprintf(shotname, "./SShots/s%04u.png", shotnum);
320 #elif XBOX
321 			sprintf(shotname, "d:\\ScreenShots\\%s - %04u.png", modname,shotnum);
322 #elif WII && SDL
323 			sprintf(shotname, "sd:/apps/OpenBOR/ScreenShots/%s - %04u.png", modname,shotnum);
324 #elif WII
325 			sprintf(shotname, "%s/%s - %04u.png", screenShotsDir,modname,shotnum);
326 #else
327 			sprintf(shotname, "./ScreenShots/%s - %04u.png", modname,shotnum);
328 #endif
329 			++shotnum;
330 		}while(fileExists(shotname) && shotnum<10000);
331 
332 #ifdef PSP
333 		if(shotnum<10000) saveImage(shotname);
334 #else
335 		if(shotnum<10000) savepng(shotname, vscreen, pal);
336 #endif
337 		if(ingame) debug_printf("Saved %s", shotname);
338 #ifdef PSP
339 	}
340 #endif
341 #endif
342 }
343 
344 #ifdef XBOX
findmods(void)345 int findmods(void)
346 {
347 	int i = 0;
348 	HANDLE hFind;
349 	WIN32_FIND_DATAA oFindData;
350 	hFind = FindFirstFile("d:\\Paks\\*", &oFindData);
351 	if(hFind == INVALID_HANDLE_VALUE) return 1;
352 	do
353 	{
354 		if(stristr(oFindData.cFileName, ".pak") && stricmp(oFindData.cFileName, "menu.pak") != 0)
355 		{
356 			strncpy(paklist[i].filename, oFindData.cFileName, 128-strlen(oFindData.cFileName));
357 			i++;
358 		}
359 	}
360 	while(FindNextFile(hFind, &oFindData));
361 	FindClose(hFind);
362 	return i;
363 }
364 #endif
365 
readlsb32(const unsigned char * src)366 unsigned readlsb32(const unsigned char *src)
367 {
368 	return
369 		((((unsigned)(src[0])) & 0xFF) <<  0) |
370 		((((unsigned)(src[1])) & 0xFF) <<  8) |
371 		((((unsigned)(src[2])) & 0xFF) << 16) |
372 		((((unsigned)(src[3])) & 0xFF) << 24);
373 }
374 
375 // Optimized search in an arranged string table, return the index
searchList(const char * list[],const char * value,int length)376 int searchList(const char* list[], const char* value, int length)
377 {
378 	int i;
379 	int a = 0;
380 	int b = length / 2;
381 	int c = length - 1;
382 	int v = value[0];
383 
384 	// We must convert uppercase values to lowercase,
385 	// since this is how every command is written in
386 	// our source.  Refer to an ASCII Chart
387 	if(v >= 0x41 && v <= 0x5A) v += 0x20;
388 
389 	// Index value equals middle value,
390 	// Lets search starting from center.
391 	if(v == list[b][0])
392 	{
393 		if(stricmp(list[b], value) == 0) return b;
394 
395 		// Search Down the List.
396 		if(v == list[b-1][0])
397 		{
398 			for(i=b-1 ; i>=0; i--)
399 			{
400 				if(stricmp(list[i], value) == 0) return i;
401 				if(v != list[i-1][0]) break;
402 			}
403 		}
404 
405 		// Search Up the List.
406 		if(v == list[b+1][0])
407 		{
408 			for(i=b+1; i<length; i++)
409 			{
410 				if(stricmp(list[i], value) == 0) return i;
411 				if(v != list[i+1][0]) break;
412 			}
413 		}
414 
415 		// No match, return failure.
416 		goto searchListFailed;
417 	}
418 
419 	// Define the starting point.
420 	if(v >= list[b+1][0]) a = b+1;
421 	else if(v <= list[b-1][0]) c = b-1;
422 	else goto searchListFailed;
423 
424 	// Search Up from starting point.
425 	for(i=a; i<=c; i++)
426 	{
427 		if(v == list[i][0])
428 		{
429 			if(stricmp(list[i], value) == 0) return i;
430 			if(v != list[i+1][0]) break;
431 		}
432 	}
433 
434 searchListFailed:
435 
436 	// The search failed!
437 	// On five reasons for failure!
438 	// 1. Is the list in alphabetical order?
439 	// 2. Is the first letter lowercase in list?
440 	// 3. Does the value exist in the list?
441 	// 4. Is it a typo?
442 	// 5. Is it a text file error?
443 	return -1;
444 }
445 
commaprint(u64 n)446 char *commaprint(u64 n)
447 {
448 	static int comma = '\0';
449 	static char retbuf[30];
450 	char *p = &retbuf[sizeof(retbuf)-1];
451 	int i = 0;
452 
453 	if(comma == '\0')
454 	{
455 		struct lconv *lcp = localeconv();
456 		if(lcp != NULL)
457 		{
458 			if(lcp->thousands_sep != NULL &&
459 			   *lcp->thousands_sep != '\0')
460 				comma = *lcp->thousands_sep;
461 			else
462 				comma = ',';
463 		}
464 	}
465 
466 	*p = '\0';
467 
468 	do {
469 		if(i%3 == 0 && i != 0)
470 			*--p = comma;
471 		*--p = '0' + n % 10;
472 		n /= 10;
473 		i++;
474 	} while(n != 0);
475 
476 	return p;
477 }
478 
479 //! Increase or Decrease an array à la \e vector
480 /**
481 	\param f_caller : name of the calling function for logging purpose
482 	\param array : the array to consider
483 	\param new_size : new size needed for the array (in BYTE) :
484 		-# if new_size <= 0 : Deallocation of the array
485 		-# new_size < \a curr_size_allocated - \a grow_step => Decrease of the array
486 		-# new_size >= \a curr_size_allocated => Increase of the array
487 	\param curr_size_allocated : current allocated size to the array (in BYTE)
488 	\param grow_step : bloc size of expansion of the array (in BYTE)
489 */
490 void
Array_Check_Size(const char * f_caller,char ** array,int new_size,int * curr_size_allocated,int grow_step)491 Array_Check_Size( const char* f_caller, char** array, int new_size, int* curr_size_allocated, int grow_step )
492 {
493 	// Deallocation
494 	if( new_size <= 0 )
495 	{
496 		if( *array != NULL )
497 		{
498 			free(*array);
499 			*array = NULL;
500 		}
501 		*curr_size_allocated = 0;
502 	}
503 
504 	// First allocation
505 	else if( *array == NULL )
506 	{
507 		*curr_size_allocated = grow_step;
508 		*array = malloc(*curr_size_allocated );
509 		if( *array == NULL)
510 			shutdown(1, "Out Of Memory!  Failed in %s\n", f_caller);
511 		memset( *array, 0, *curr_size_allocated );
512 		return;
513 	}
514 
515 	// No need to decrease or increase the array
516 	else if( new_size > (*curr_size_allocated - grow_step ) && new_size <= *curr_size_allocated )
517 		return;
518 
519 	//-------------------------------------------
520 	// Must increase or decrease the array size
521 
522 	int old_size = *curr_size_allocated;
523 
524 	// Recompute needed size
525 	*curr_size_allocated = ((int)ceil((float)new_size / (float)grow_step)) * grow_step;
526 
527 	// Alloc a new array
528 	void* copy = malloc(*curr_size_allocated );
529 	if(copy == NULL)
530 		shutdown(1, "Out Of Memory!  Failed in %s\n", f_caller);
531 
532 	// Copy the previous content of the array
533 	memcpy(copy, *array, ( (old_size<new_size) ?old_size :new_size) );
534 
535 	// Init the new allocations
536 	if( old_size < *curr_size_allocated )
537 		memset( copy + old_size, 0, *curr_size_allocated - old_size );
538 
539 	// Free previous array memory
540 	free(*array);
541 
542 	// ReAssign the new allocated array
543 	*array = copy;
544 }
545 
546