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