1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2010 by The Allacrost Project
3 //                         All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See http://www.gnu.org/copyleft/gpl.html for details.
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 /** ****************************************************************************
11 *** \file    utils.cpp
12 *** \author  Tyler Olsen, roots@allacrost.org
13 *** \brief   Source file for Allacrost utility code.
14 *** ***************************************************************************/
15 
16 // Headers included for directory manipulation. Windows has its own way of
17 // dealing with directories, hence the need for conditional includes
18 #ifdef _WIN32
19 	#include <direct.h>
20 	#include <shlobj.h>
21 #else
22 	#include <dirent.h>
23 	#include <sys/types.h>
24 	#include <unistd.h>
25 	#include <pwd.h>
26 #endif
27 
28 #include <fstream>
29 #include <sys/stat.h>
30 #include <iconv.h>
31 
32 #include "utils.h"
33 #include <SDL/SDL.h>
34 
35 using namespace std;
36 
37 namespace hoa_utils {
38 
39 bool UTILS_DEBUG = false;
40 
41 ////////////////////////////////////////////////////////////////////////////////
42 ///// Numeric utility functions
43 ////////////////////////////////////////////////////////////////////////////////
44 
RoundUpPow2(uint32 x)45 uint32 RoundUpPow2(uint32 x) {
46 	x -= 1;
47 	x |= x >>  1;
48 	x |= x >>  2;
49 	x |= x >>  4;
50 	x |= x >>  8;
51 	x |= x >> 16;
52 	return x + 1;
53 }
54 
55 
56 
IsPowerOfTwo(uint32 x)57 bool IsPowerOfTwo(uint32 x) {
58 	return ((x & (x-1)) == 0);
59 }
60 
61 
62 
IsOddNumber(uint32 x)63 bool IsOddNumber(uint32 x) {
64 	// NOTE: this happens to work for both little and big endian systems
65 	return (x & 0x00000001);
66 }
67 
68 
69 
IsFloatInRange(float value,float lower,float upper)70 bool IsFloatInRange(float value, float lower, float upper) {
71 	return (value >= lower && value <= upper);
72 }
73 
74 
75 
IsFloatEqual(float value,float base,float delta)76 bool IsFloatEqual(float value, float base, float delta) {
77 	return (value >= (base - delta) && value <= (base + delta));
78 }
79 
80 
81 
GetFloatFraction(float value)82 float GetFloatFraction(float value) {
83 	return  (value - GetFloatInteger(value));
84 }
85 
86 
87 
GetFloatInteger(float value)88 float GetFloatInteger(float value) {
89 	return static_cast<float>(static_cast<int>(value));
90 }
91 
92 
93 
FloorToFloatMultiple(const float value,const float multiple)94 float FloorToFloatMultiple (const float value, const float multiple) {
95 	return multiple * floor(value / multiple);
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 ///// ustring Class
100 ////////////////////////////////////////////////////////////////////////////////
101 
102 const size_t ustring::npos = ~0;
103 
104 
105 
ustring()106 ustring::ustring() {
107 	_str.push_back(0);
108 }
109 
110 
111 
ustring(const uint16 * s)112 ustring::ustring(const uint16 *s) {
113 	_str.clear();
114 
115 	if (!s) {
116 		_str.push_back(0);
117 		return;
118 	}
119 
120 	while (*s != 0) {
121 		_str.push_back(*s);
122 		++s;
123 	}
124 
125 	_str.push_back(0);
126 }
127 
128 
129 // Return a substring starting at pos, continuing for n elements
substr(size_t pos,size_t n) const130 ustring ustring::substr(size_t pos, size_t n) const
131 {
132 	size_t len = length();
133 
134 	if (pos >= len)
135 		throw std::out_of_range("pos passed to substr() was too large");
136 
137 	ustring s;
138 	while (n > 0 && pos < len) {
139 		s += _str[pos];
140 		++pos;
141 		--n;
142 	}
143 
144 	return s;
145 }
146 
147 
148 // Concatenates string to another
operator +(const ustring & s)149 ustring & ustring::operator + (const ustring& s)
150 {
151 	// nothing to do for empty string
152 	if (s.empty())
153 		return *this;
154 
155 	// add first character of string into the null character spot
156 	_str[length()] = s[0];
157 
158 	// add rest of characters afterward
159 	size_t len = s.length();
160 	for (size_t j = 1; j < len; ++j) {
161 		_str.push_back(s[j]);
162 	}
163 
164 	// Finish off with a null character
165 	_str.push_back(0);
166 
167 	return *this;
168 }
169 
170 
171 // Adds a character to end of this string
operator +=(uint16 c)172 ustring & ustring::operator += (uint16 c) {
173 	_str[length()] = c;
174 	_str.push_back(0);
175 
176 	return *this;
177 }
178 
179 
180 // Concatenate another string on to the end of this string
operator +=(const ustring & s)181 ustring & ustring::operator += (const ustring &s) {
182 	// nothing to do for empty string
183 	if (s.empty())
184 		return *this;
185 
186 	// add first character of string into the null character spot
187 	_str[length()] = s[0];
188 
189 	// add rest of characters afterward
190 	size_t len = s.length();
191 	for (size_t j = 1; j < len; ++j) {
192 		_str.push_back(s[j]);
193 	}
194 
195 	// Finish off with a null character
196 	_str.push_back(0);
197 
198 	return *this;
199 }
200 
201 
202 // Will assign the current string to this string
operator =(const ustring & s)203 ustring & ustring::operator = (const ustring &s) {
204 	clear();
205 	operator += (s);
206 
207 	return *this;
208 } // ustring & ustring::operator = (const ustring &s)
209 
210 
211 // Finds a character within a string, starting at pos. If nothing is found, npos is returned
find(uint16 c,size_t pos) const212 size_t ustring::find(uint16 c, size_t pos) const {
213 	size_t len = length();
214 
215 	for (size_t j = pos; j < len; ++j) {
216 		if (_str[j] == c)
217 			return j;
218 	}
219 
220 	return npos;
221 } // size_t ustring::find(uint16 c, size_t pos) const
222 
223 
224 // Finds a string within a string, starting at pos. If nothing is found, npos is returned
find(const ustring & s,size_t pos) const225 size_t ustring::find(const ustring &s, size_t pos) const {
226 	size_t len = length();
227 	size_t total_chars = s.length();
228 	size_t chars_found = 0;
229 
230 	for (size_t j = pos; j < len; ++j) {
231 		if (_str[j] == s[chars_found]) {
232 			++chars_found;
233 			if (chars_found == total_chars) {
234 				return (j - chars_found + 1);
235 			}
236 		}
237 		else {
238 			chars_found = 0;
239 		}
240 	}
241 
242 	return npos;
243 } // size_t ustring::find(const ustring &s, size_t pos) const
244 
245 
246 ////////////////////////////////////////////////////////////////////////////////
247 ///// Exception class
248 ////////////////////////////////////////////////////////////////////////////////
249 
Exception(const std::string & message,const std::string & file,const int line,const std::string & function)250 Exception::Exception(const std::string & message, const std::string & file, const int line, const std::string & function) throw() :
251     _message(message),
252     _file(file),
253     _line(line),
254     _function(function)
255 {}
256 
257 
258 
~Exception()259 Exception::~Exception() throw()
260 {}
261 
262 
263 
ToString() const264 string Exception::ToString() const throw() {
265     return string("EXCEPTION:" + _file + ":" + _function + ":" + NumberToString(_line) + ": " + _message);
266 }
267 
268 
GetMessage() const269 string Exception::GetMessage() const throw() {
270     return _message;
271 }
272 
273 
GetFile() const274 string Exception::GetFile() const throw() {
275     return _file;
276 }
277 
278 
GetLine() const279 int Exception::GetLine() const throw() {
280     return _line;
281 }
282 
283 
GetFunction() const284 string Exception::GetFunction() const throw() {
285     return _function;
286 }
287 
288 ////////////////////////////////////////////////////////////////////////////////
289 ///// string and ustring manipulator functions
290 ////////////////////////////////////////////////////////////////////////////////
291 
292 // Returns true if the given text is a number
IsStringNumeric(const string & text)293 bool IsStringNumeric(const string& text) {
294 	if (text.empty())
295 		return false;
296 
297 	// Keep track of whether decimal point is allowed. It is allowed to be present in the text zero or one times only.
298 	bool decimal_allowed = true;
299 
300 	size_t len = text.length();
301 
302 	// Check each character of the string one at a time
303 	for (size_t c = 0; c < len; ++c) {
304 		// The only non numeric characters allowed are a - or + as the first character, and one decimal point anywhere
305 		bool numeric_char = (isdigit(static_cast<int32>(text[c]))) || (c==0 && (text[c] == '-' || text[c] == '+'));
306 
307 		if (!numeric_char) {
308 			// Check if the 'bad' character is a decimal point first before labeling the string invalid
309 			if (decimal_allowed && text[c] == '.') {
310 				decimal_allowed = false; // Decimal points are now invalid for the rest of the string
311 			}
312 			else {
313 				return false;
314 			}
315 		}
316 	}
317 
318 	return true;
319 } // bool IsStringNumeric(const string& text)
320 
321 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
322   #define UTF_16_ICONV_NAME "UTF-16LE"
323 #else
324   #define UTF_16_ICONV_NAME "UTF-16BE"
325 #endif
326 
327 #define UTF_16_BOM_STD 0xFEFF
328 #define UTF_16_BOM_REV 0xFFFE
329 
330 // Converts from UTF16 to UTF8, using iconv
UTF16ToUTF8(const uint16 * source,char * dest,size_t length)331 bool UTF16ToUTF8(const uint16 *source, char *dest, size_t length) {
332 	if (!length)
333 		return true;
334 
335 	iconv_t convertor = iconv_open("UTF-8", UTF_16_ICONV_NAME);
336 	if (convertor == (iconv_t) -1) {
337 		return false;
338 	}
339 
340 	const char *source_char = reinterpret_cast<const char *>(source);
341 	#if (defined(_LIBICONV_VERSION) && _LIBICONV_VERSION == 0x0109)
342 	// We are using an iconv API that uses const char*
343 	const char *sourceChar = source_char;
344 	#else
345 	// The iconv API doesn't specify a const source for legacy support reasons.
346 	// Versions after 0x0109 changed back to char* for POSIX reasons.
347 	char *sourceChar = const_cast<char *>(source_char);
348 	#endif
349 	char *destChar   = dest;
350 	size_t sourceLen = length;
351 	size_t destLen   = length;
352 	size_t ret = iconv(convertor, &sourceChar, &sourceLen,
353 				      &destChar,   &destLen);
354 	iconv_close(convertor);
355 	if (ret == (size_t) -1) {
356 		perror("iconv");
357 		return false;
358 	}
359 	return true;
360 }
361 
362 // Converts from UTF8 to UTF16, including the Byte Order Mark, using iconv
363 // Skip the first uint16 to skip the BOM.
UTF8ToUTF16(const char * source,uint16 * dest,size_t length)364 bool UTF8ToUTF16(const char *source, uint16 *dest, size_t length) {
365 	if (!length)
366 		return true;
367 
368 	iconv_t convertor = iconv_open(UTF_16_ICONV_NAME, "UTF-8");
369 	if (convertor == (iconv_t) -1) {
370 		return false;
371 	}
372 
373 	#if (defined(_LIBICONV_VERSION) && _LIBICONV_VERSION == 0x0109)
374 		// We are using an iconv API that uses const char*
375 		const char *sourceChar = source;
376 	#else
377 		// The iconv API doesn't specify a const source for legacy support reasons.
378 		// Versions after 0x0109 changed back to char* for POSIX reasons.
379 		char *sourceChar = const_cast<char *>(source);
380 	#endif
381 	char *destChar   = reinterpret_cast<char *>(dest);
382 	size_t sourceLen = length;
383 	size_t destLen   = (length + 1) * 2;
384 	size_t ret = iconv(convertor, &sourceChar, &sourceLen,
385 				      &destChar,   &destLen);
386 	iconv_close(convertor);
387 	if (ret == (size_t) -1) {
388 		perror("iconv");
389 		return false;
390 	}
391 	return true;
392 }
393 
394 // Creates a ustring from a normal string
MakeUnicodeString(const string & text)395 ustring MakeUnicodeString(const string& text) {
396 	int32 length = static_cast<int32>(text.length() + 1);
397 	uint16 *ubuff = new uint16[length + 1];
398 	memset(ubuff, 0, 2*(length+1));
399 	uint16 *utf16String = ubuff;
400 
401 	if (UTF8ToUTF16(text.c_str(), ubuff, length)) {
402 		// Skip the "Byte Order Mark" from the UTF16 specification
403 		if (utf16String[0] == UTF_16_BOM_STD ||  utf16String[0] == UTF_16_BOM_REV) {
404 			utf16String = ubuff + 1;
405 		}
406 
407 		#if SDL_BYTEORDER == SDL_BIG_ENDIAN
408 			// For some reason, using UTF-16BE to iconv on big-endian machines
409 			// still does not create correctly accented characters, so this
410 			// byte swapping must be performed (only for irregular characters,
411 			// hence the mask).
412 
413 			for (int32 c = 0; c < length; c++)
414 				if (utf16String[c] & 0xFF80)
415 					utf16String[c] = (utf16String[c] << 8) | (utf16String[c] >> 8);
416 		#endif
417 	}
418 	else {
419 		for (int32 c = 0; c < length; ++c) {
420 			ubuff[c] = static_cast<uint16>(text[c]);
421 		}
422 	}
423 
424 	ustring new_ustr(utf16String);
425 	delete[] ubuff;
426 
427 	return new_ustr;
428 } // ustring MakeUnicodeString(const string& text)
429 
430 
431 // Creates a normal string from a ustring
MakeStandardString(const ustring & text)432 string MakeStandardString(const ustring& text) {
433 	int32 length = static_cast<int32>(text.length());
434 
435 	unsigned char *strbuff = new unsigned char[length+1];
436 	strbuff[length] = '\0';
437 
438 	for (int32 c = 0; c < length; ++c) {
439 		uint16 curr_char = text[c];
440 
441 		if(curr_char > 0xff)
442 			strbuff[c] = '?';
443 		else
444 			strbuff[c] = static_cast<unsigned char>(curr_char);
445 	}
446 
447 	string new_str(reinterpret_cast<char*>(strbuff));
448 	delete [] strbuff;
449 
450 	return new_str;
451 } // string MakeStandardString(const ustring& text)
452 
453 ////////////////////////////////////////////////////////////////////////////////
454 ///// Random number generator functions
455 ////////////////////////////////////////////////////////////////////////////////
456 
RandomFloat()457 float RandomFloat() {
458 	return (static_cast<float>(rand()) / static_cast<float>(RAND_MAX));
459 }
460 
461 
462 
RandomFloat(float a,float b)463 float RandomFloat(float a, float b) {
464 	if (a > b) {
465 		float c = a;
466 		a = b;
467 		b = c;
468 	}
469 
470 	float r = static_cast<float>(rand() % 10001);
471 	return a + (b - a) * r / 10000.0f;
472 }
473 
474 // Returns a random integer between two inclusive bounds
RandomBoundedInteger(int32 lower_bound,int32 upper_bound)475 int32 RandomBoundedInteger(int32 lower_bound, int32 upper_bound) {
476 	int32 range;  // The number of possible values we may return
477 	float result;
478 
479 	range = upper_bound - lower_bound + 1;
480 	if (range < 0) { // Oops, someone accidentally switched the lower/upper bound arguments
481 		if (UTILS_DEBUG) cerr << "UTILS WARNING: Call to RandomNumber had bound arguments swapped." << endl;
482 		range = range * -1;
483 	}
484 
485 	result = range * RandomFloat();
486 	result = result + lower_bound; // Shift result so that it is within the correct bounds
487 
488 	return static_cast<int32>(result);
489 } // int32 RandomBoundedInteger(int32 lower_bound, int32 upper_bound)
490 
491 // Creates a Gaussian random interger value.
492 // std_dev and positive_value are optional arguments with default values 10.0f and true respectively
GaussianRandomValue(int32 mean,float std_dev,bool positive_value)493 int32 GaussianRandomValue(int32 mean, float std_dev, bool positive_value) {
494 	float x, y, r;  // x and y are coordinates on the unit circle
495 	float grv_unit; // Used to hold a Gaussian random variable on a normal distribution curve (mean 0, stand dev 1)
496 	float result;
497 
498 	// Make sure that the standard deviation is positive
499 	if (std_dev < 0) {
500 		cerr << "UTILS WARNING: negative value for standard deviation argument in function GaussianValue" << endl;
501 		std_dev = -1.0f * std_dev;
502 	}
503 
504 	// Computes a standard Gaussian random number using the the polar form of the Box-Muller transformation.
505 	// The algorithm computes a random point (x, y) inside the unit circle centered at (0, 0) with radius 1.
506 	// Then a Gaussian random variable with mean 0 and standard deviation 1 is computed by:
507 	//
508 	// x * sqrt(-2.0 * log(r) / r)
509 	//
510 	// Reference: Knuth, The Art of Computer Programming, Volume 2, p. 122
511 
512 	// This loop is executed 4 / pi = 1.273 times on average
513 	do {
514 		x = 2.0f * RandomFloat() - 1.0f;     // Get a random x-coordinate [-1.0f, 1.0f]
515 		y = 2.0f * RandomFloat() - 1.0f;     // Get a random y-coordinate [-1.0f, 1.0f]
516 		r = x*x + y*y;
517 	} while (r > 1.0f || r == 0.0f);
518 	grv_unit = x * sqrt(-2.0f * log(r) / r);
519 
520 	// Use the standard gaussian value to create a random number with the desired mean and standard deviation.
521 	result = (grv_unit * std_dev) + mean;
522 
523 	// Return zero if a negative result was found and only positive values were to be returned
524 	if (result < 0.0f && positive_value)
525 		return 0;
526 	else
527 		return static_cast<int32>(result);
528 } // int32 GaussianValue(int32 mean, float std_dev = 6.667f, bool positive_value = false)
529 
530 // Returns true/false depending on the chance
Probability(uint32 chance)531 bool Probability(uint32 chance) {
532 	uint32 value = static_cast<uint32>(RandomBoundedInteger(1, 100));
533 	if (value <= chance)
534 		return true;
535 	else
536 		return false;
537 }
538 
539 ////////////////////////////////////////////////////////////////////////////////
540 ///// Directory manipulation functions
541 ////////////////////////////////////////////////////////////////////////////////
542 
DoesFileExist(const std::string & file_name)543 bool DoesFileExist(const std::string& file_name) {
544 	// Modified to use platform specific code because on windows stat does not work on directories,
545 	// but on POSIX compliant systems it does, and GetFileAttributes works for both folders and
546 	// directories on win32
547 	#ifdef _WIN32
548 		return GetFileAttributes(file_name.c_str()) != INVALID_FILE_ATTRIBUTES;
549 	#else
550 		struct stat buf;
551 		if (stat(file_name.c_str(), &buf) == 0)
552 			return true;
553 		else
554 			return false;
555 	#endif
556 }
557 
558 
559 
MoveFile(const std::string & source_name,const std::string & destination_name)560 bool MoveFile(const std::string& source_name, const std::string& destination_name) {
561 	if (DoesFileExist(destination_name))
562 		remove(destination_name.c_str());
563 	return (rename(source_name.c_str(), destination_name.c_str()) == 0);
564 }
565 
566 
567 
CopyFile(const std::string & source,const std::string & destination)568 void CopyFile(const std::string& source, const std::string& destination) {
569 	if (DoesFileExist(destination))
570 		remove(destination.c_str());
571 	ifstream src(source.c_str());
572 	ofstream dst(destination.c_str());
573 	dst << src.rdbuf();
574 }
575 
576 
577 
MakeDirectory(const std::string & dir_name)578 bool MakeDirectory(const std::string& dir_name) {
579 	// Don't do anything if the directory already exists
580 	struct stat buf;
581 	int32 i = stat(dir_name.c_str(), &buf);
582 	if (i == 0)
583 		return true;
584 
585 	// Create the directory with mkdir(). Note that Windows does not require file permissions to be set, but
586 	// all other operating systems do.
587 
588 	#ifdef _WIN32
589 		int32 success = mkdir(dir_name.c_str());
590 	#else
591 		int32 success = mkdir(dir_name.c_str(), S_IRWXG | S_IRWXO | S_IRWXU);
592 	#endif
593 
594 	if (success == -1) {
595 		cerr << "UTILS ERROR: could not create directory: " << dir_name.c_str() << endl;
596 		return false;
597 	}
598 
599 	return true;
600 }
601 
602 
603 
CleanDirectory(const std::string & dir_name)604 bool CleanDirectory(const std::string& dir_name) {
605 	// Don't do anything if the directory doesn't exist
606 	struct stat buf;
607 	int32 i = stat(dir_name.c_str(), &buf);
608 	if (i != 0)
609 		return true;
610 
611 	#ifdef _WIN32
612 		//--- WINDOWS --------------------------------------------------------------
613 
614 		// Get the current directory that the Allacrost application resides in
615 		char app_path[1024];
616 		GetCurrentDirectoryA(1024, app_path);
617 
618 		int32 app_path_len = static_cast<int32>(strlen(app_path));
619 		if (app_path_len <= 0)
620 			return false;
621 		if(app_path[app_path_len-1] == '\\')    // Remove the ending slash if one is there
622 			app_path[app_path_len-1] = '\0';
623 
624 		string full_path = app_path;
625 
626 		if (dir_name[0] == '/' || dir_name[0] == '\\') {
627 			full_path += dir_name;
628 		}
629 		else {
630 			full_path += "\\";
631 			full_path += dir_name;
632 		}
633 
634 		char file_found[1024];
635 		WIN32_FIND_DATAA info;
636 		HANDLE hp;
637 		sprintf(file_found, "%s\\*.*", full_path.c_str());
638 		hp = FindFirstFileA(file_found, &info);
639 
640 		if (hp != INVALID_HANDLE_VALUE) {
641 			// Remove each file from the full_path directory
642 			do {
643 				sprintf(file_found, "%s\\%s", full_path.c_str(), info.cFileName);
644 				DeleteFileA(file_found);
645 			} while(FindNextFileA(hp, &info));
646 		}
647 		FindClose(hp);
648 
649 	#else
650 		//--- NOT WINDOWS ----------------------------------------------------------
651 
652 	DIR *parent_dir;
653 	struct dirent *dir_file;
654 
655 	parent_dir = opendir(dir_name.c_str());   // open the directory we want to clean
656 	if (!parent_dir) {
657 		cerr << "UTILS ERROR: failed to clean directory: " << dir_name << endl;
658 		return false;
659 	}
660 
661 	string base_dir = dir_name;
662 	if (base_dir[base_dir.length()-1] != '/')
663 		base_dir += "/";
664 
665 	// Remove each file found in the parent directory
666 	while ((dir_file = readdir(parent_dir))) {
667 		string file_name = base_dir + dir_file->d_name;
668 		remove(file_name.c_str());
669 	}
670 
671 	closedir(parent_dir);
672 
673 	#endif
674 
675 	return true;
676 }
677 
678 
679 
RemoveDirectory(const std::string & dir_name)680 bool RemoveDirectory(const std::string& dir_name) {
681 	// Don't do anything if the directory doesn't exist
682 	struct stat buf;
683 	int32 i = stat(dir_name.c_str(), &buf);
684 	if (i != 0)
685 		return true;
686 
687 	// Remove any files that still reside in the directory
688 	CleanDirectory(dir_name);
689 
690 	// Finally, remove the folder itself with rmdir()
691 	int32 success = rmdir(dir_name.c_str());
692 
693 	if (success == -1) {
694 		cerr << "UTILS ERROR: could not delete directory: " << dir_name << endl;
695 		return false;
696 	}
697 
698 	return true;
699 }
700 
ListDirectory(const std::string & dir_name,const std::string & filter)701 vector<string> ListDirectory(const std::string& dir_name, const std::string& filter) {
702 	//create our vector
703 	vector<string> directoryList;
704 
705 	//Don't try to list if the directory does not exist
706 	struct stat buf;
707 	int32 i = stat(dir_name.c_str(), &buf);
708 	if (i != 0)
709 		return directoryList;
710 
711 	//directory exists so lets list
712 	#if defined _WIN32
713 	//Windows platform
714 
715 		// Get the current directory that the Allacrost application resides in
716 		char app_path[1024];
717 		GetCurrentDirectoryA(1024, app_path);
718 
719 		int32 app_path_len = static_cast<int32>(strlen(app_path));
720 		if (app_path_len <= 0)
721 			return directoryList;
722 		if(app_path[app_path_len-1] == '\\')    // Remove the ending slash if one is there
723 			app_path[app_path_len-1] = '\0';
724 
725 		string full_path = app_path;
726 
727 		if (dir_name[0] == '/' || dir_name[0] == '\\') {
728 			full_path += dir_name;
729 		}
730 		else {
731 			full_path += "\\";
732 			full_path += dir_name;
733 		}
734 
735 		char file_found[1024];
736 		WIN32_FIND_DATAA info;
737 		HANDLE hp;
738 		sprintf(file_found, "%s\\*.*", full_path.c_str());
739 		hp = FindFirstFileA(file_found, &info);
740 
741 		if (hp != INVALID_HANDLE_VALUE) {
742 			// List each file from the full_path directory
743 			do {
744 			   std::string fileName(file_found);
745 				if(filter == "")
746 					directoryList.push_back(file_found);
747 				else if(fileName.find(filter) != string::npos)
748 					directoryList.push_back(file_found);
749 			} while(FindNextFileA(hp, &info));
750 		}
751 		FindClose(hp);
752 	#else
753 	//Not Windows
754 	DIR *dir;
755 	struct dirent *dir_file;
756 	dir = opendir(dir_name.c_str()); //open the directory for listing
757 	if(!dir) {
758 		cerr << "UTILS ERROR: Failed to list directory: " << dir_name << endl;
759 		return directoryList;
760 	}
761 
762 	//List each file found in the directory as long as it end with .lua
763 	while ((dir_file = readdir(dir))) {
764 		string fileName = dir_file->d_name;
765 		//contains a .lua ending so put it in the directory
766 		if(filter == "")
767 			directoryList.push_back(dir_file->d_name);
768 		else if(fileName.find(filter) != string::npos)
769 			directoryList.push_back(dir_file->d_name);
770 	}
771 
772 	closedir(dir);
773 
774 	#endif
775 
776 	return directoryList;
777 }
778 
DeleteFile(const std::string & filename)779 bool DeleteFile(const std::string &filename) {
780 	if(DoesFileExist(filename.c_str())) {
781 		remove(filename.c_str());
782 		if(!DoesFileExist(filename.c_str()))
783 			return true;
784 	}
785 	return false;
786 }
787 
788 
789 
790 
GetUserDataPath(bool user_files)791 const std::string GetUserDataPath(bool user_files) {
792 	#if defined _WIN32
793 		TCHAR path[MAX_PATH];
794 
795 		if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, path))) {
796 			string user_path = string(path) + "/Allacrost/";
797 			if (DoesFileExist(user_path) == false)
798 				MakeDirectory(user_path);
799 			return user_path;
800 		}
801 
802 	#elif defined __MACH__
803 		passwd *pw = getpwuid(getuid());
804 		if (pw) {
805 			string path = "";
806 			if (user_files)
807 				path = string(pw->pw_dir) + "/Library/Application Support/Allacrost/";
808 			else
809 				path = string(pw->pw_dir) + "/Library/Preferences/Allacrost/";
810 			if (DoesFileExist(path) == false)
811 				MakeDirectory(path);
812 			return path;
813 		}
814 
815 	#else // Linux, BSD, other POSIX systems
816 		passwd *pw = getpwuid(getuid());
817 		if (pw) {
818 			string path = string(pw->pw_dir) + "/.allacrost/";
819 			if (DoesFileExist(path) == false)
820 				MakeDirectory(path);
821 			return path;
822 		}
823 	#endif
824 
825 	// Default path if a specific solution could not be found. Note that this path may
826 	// not be writable by the user since it could be installed in administrator/root space
827 	PRINT_WARNING << "could not idenfity user path, defaulting to system path" << endl;
828 	return "dat/";
829 }
830 
GetUserProfilePath()831 const std::string GetUserProfilePath()
832 {
833 	string profile_path = GetUserDataPath(false) + "profiles/";
834 	if(!DoesFileExist(profile_path))
835 		MakeDirectory(profile_path);
836 
837 	return profile_path;
838 }
839 
840 
841 
GetSettingsFilename()842 const std::string GetSettingsFilename() {
843 	std::string settings_file;
844 
845 	settings_file = GetUserProfilePath() + "settings.lua";
846 	if (DoesFileExist(settings_file) == false) {
847 		settings_file = "dat/config/settings.lua";
848 		if (DoesFileExist(settings_file) == false) {
849 			PRINT_WARNING << "settings.lua file not found." << endl;
850 		}
851 	}
852 
853 	return settings_file;
854 }
855 
856 } // namespace utils
857