utils.cpp

Go to the documentation of this file.
00001 
00002 //            Copyright (C) 2004-2007 by The Allacrost Project
00003 //                         All Rights Reserved
00004 //
00005 // This code is licensed under the GNU GPL version 2. It is free software
00006 // and you may modify it and/or redistribute it under the terms of this license.
00007 // See http://www.gnu.org/copyleft/gpl.html for details.
00009 
00016 #include "utils.h"
00017 
00018 // Headers included for directory manipulation. Windows has its own way of
00019 // dealing with directories, hence the need for conditional includes
00020 #ifdef _WIN32
00021   #include <direct.h>
00022 #else
00023   #include <dirent.h>
00024 #endif
00025 
00026 #include <sys/stat.h>
00027 #include "socket.h"
00028 
00029 using namespace std;
00030 using namespace hoa_socket;
00031 
00032 namespace hoa_utils {
00033 
00034 bool UTILS_DEBUG = false;
00035 
00039 
00040 uint32 RoundUpPow2(uint32 x) {
00041   x -= 1;
00042   x |= x >>  1;
00043   x |= x >>  2;
00044   x |= x >>  4;
00045   x |= x >>  8;
00046   x |= x >> 16;
00047   return x + 1;
00048 }
00049 
00050 
00051 
00052 bool IsPowerOfTwo(uint32 x) {
00053   return ((x & (x-1)) == 0);
00054 }
00055 
00056 
00057 
00058 bool IsOddNumber(uint32 x) {
00059   // NOTE: this happens to work for both little and big endian systems
00060   return (x & 0x00000001);
00061 }
00062 
00063 
00064 
00065 bool IsFloatInRange(float value, float lower, float upper) {
00066   return (value >= lower && value <= upper);
00067 }
00068 
00069 
00070 float FloorToFloatMultiple (const float value, const float multiple)
00071 {
00072   return multiple * floor(value / multiple);
00073 }
00074 
00075 
00076 
00080 
00081 const size_t ustring::npos = ~0;
00082 
00083 
00084 
00085 ustring::ustring() {
00086   _str.push_back(0);
00087 }
00088 
00089 
00090 
00091 ustring::ustring(const uint16 *s) {
00092   _str.clear();
00093 
00094   if (!s) {
00095     _str.push_back(0);
00096     return;
00097   }
00098 
00099   while (*s != 0) {
00100     _str.push_back(*s);
00101     ++s;
00102   }
00103 
00104   _str.push_back(0);
00105 }
00106 
00107 
00108 // Return a substring starting at pos, continuing for n elements
00109 ustring ustring::substr(size_t pos, size_t n) const
00110 {
00111   size_t len = length();
00112 
00113   if (pos >= len)
00114     throw std::out_of_range("pos passed to substr() was too large");
00115 
00116   ustring s;
00117   while (n > 0 && pos < len) {
00118     s += _str[pos];
00119     ++pos;
00120     --n;
00121   }
00122 
00123   return s;
00124 }
00125 
00126 
00127 // Concatenates string to another
00128 ustring & ustring::operator + (const ustring& s)
00129 {
00130   // nothing to do for empty string
00131   if (s.empty())
00132     return *this;
00133 
00134   // add first character of string into the null character spot
00135   _str[length()] = s[0];
00136 
00137   // add rest of characters afterward
00138   size_t len = s.length();
00139   for (size_t j = 1; j < len; ++j) {
00140     _str.push_back(s[j]);
00141   }
00142 
00143   // Finish off with a null character
00144   _str.push_back(0);
00145 
00146   return *this;
00147 }
00148 
00149 
00150 // Adds a character to end of this string
00151 ustring & ustring::operator += (uint16 c) {
00152   _str[length()] = c;
00153   _str.push_back(0);
00154 
00155   return *this;
00156 }
00157 
00158 
00159 // Concatenate another string on to the end of this string
00160 ustring & ustring::operator += (const ustring &s) {
00161   // nothing to do for empty string
00162   if (s.empty())
00163     return *this;
00164 
00165   // add first character of string into the null character spot
00166   _str[length()] = s[0];
00167 
00168   // add rest of characters afterward
00169   size_t len = s.length();
00170   for (size_t j = 1; j < len; ++j) {
00171     _str.push_back(s[j]);
00172   }
00173 
00174   // Finish off with a null character
00175   _str.push_back(0);
00176 
00177   return *this;
00178 }
00179 
00180 
00181 // Will assign the current string to this string
00182 ustring & ustring::operator = (const ustring &s) {
00183   clear();
00184   operator += (s);
00185 
00186   return *this;
00187 } // ustring & ustring::operator = (const ustring &s)
00188 
00189 
00190 // Finds a character within a string, starting at pos. If nothing is found, npos is returned
00191 size_t ustring::find(uint16 c, size_t pos) const {
00192   size_t len = length();
00193 
00194   for (size_t j = pos; j < len; ++j) {
00195     if (_str[j] == c)
00196       return j;
00197   }
00198 
00199   return npos;
00200 } // size_t ustring::find(uint16 c, size_t pos) const
00201 
00202 
00203 // Finds a string within a string, starting at pos. If nothing is found, npos is returned
00204 size_t ustring::find(const ustring &s, size_t pos) const {
00205   size_t len = length();
00206   size_t total_chars = s.length();
00207   size_t chars_found = 0;
00208 
00209   for (size_t j = pos; j < len; ++j) {
00210     if (_str[j] == s[chars_found]) {
00211       ++chars_found;
00212       if (chars_found == total_chars) {
00213         return (j - chars_found + 1);
00214       }
00215     }
00216     else {
00217       chars_found = 0;
00218     }
00219   }
00220 
00221   return npos;
00222 } // size_t ustring::find(const ustring &s, size_t pos) const
00223 
00227 
00228 // Returns true if the given text is a number
00229 bool IsStringNumeric(const string& text) {
00230   if (text.empty())
00231     return false;
00232 
00233   // Keep track of whether decimal point is allowed. It is allowed to be present in the text zero or one times only.
00234   bool decimal_allowed = true;
00235 
00236   size_t len = text.length();
00237 
00238   // Check each character of the string one at a time
00239   for (size_t c = 0; c < len; ++c) {
00240     // The only non numeric characters allowed are a - or + as the first character, and one decimal point anywhere
00241     bool numeric_char = (isdigit(static_cast<int32>(text[c]))) || (c==0 && (text[c] == '-' || text[c] == '+'));
00242 
00243     if (!numeric_char) {
00244       // Check if the 'bad' character is a decimal point first before labeling the string invalid
00245       if (decimal_allowed && text[c] == '.') {
00246         decimal_allowed = false; // Decimal points are now invalid for the rest of the string
00247       }
00248       else {
00249         return false;
00250       }
00251     }
00252   }
00253 
00254   return true;
00255 } // bool IsStringNumeric(const string& text)
00256 
00257 
00258 // Creates a ustring from a normal string
00259 ustring MakeUnicodeString(const string& text) {
00260   int32 length = static_cast<int32>(text.length());
00261   uint16 *ubuff = new uint16[length+1];
00262   ubuff[length] = static_cast<uint16>('\0');
00263 
00264   for (int32 c = 0; c < length; ++c) {
00265     ubuff[c] = static_cast<uint16>(text[c]);
00266   }
00267 
00268   ustring new_ustr(ubuff);
00269   delete[] ubuff;
00270 
00271   return new_ustr;
00272 } // ustring MakeUnicodeString(const string& text)
00273 
00274 
00275 // Creates a normal string from a ustring
00276 string MakeStandardString(const ustring& text) {
00277   int32 length = static_cast<int32>(text.length());
00278 
00279   unsigned char *strbuff = new unsigned char[length+1];
00280   strbuff[length] = '\0';
00281 
00282   for (int32 c = 0; c < length; ++c) {
00283     uint16 curr_char = text[c];
00284 
00285     if(curr_char > 0xff)
00286       strbuff[c] = '?';
00287     else
00288       strbuff[c] = static_cast<unsigned char>(curr_char);
00289   }
00290 
00291   string new_str(reinterpret_cast<char*>(strbuff));
00292   delete [] strbuff;
00293 
00294   return new_str;
00295 } // string MakeStandardString(const ustring& text)
00296 
00300 
00301 float RandomFloat() {
00302   return (static_cast<float>(rand()) / static_cast<float>(RAND_MAX));
00303 }
00304 
00305 
00306 // Returns a random integer between two inclusive bounds
00307 int32 RandomBoundedInteger(int32 lower_bound, int32 upper_bound) {
00308   int32 range;  // The number of possible values we may return
00309   float result;
00310 
00311   range = upper_bound - lower_bound + 1;
00312   if (range < 0) { // Oops, someone accidentally switched the lower/upper bound arguments
00313     if (UTILS_DEBUG) cerr << "UTILS WARNING: Call to RandomNumber had bound arguments swapped." << endl;
00314     range = range * -1;
00315   }
00316 
00317   result = range * RandomFloat();
00318   result = result + lower_bound; // Shift result so that it is within the correct bounds
00319 
00320   return static_cast<int32>(result);
00321 } // int32 RandomBoundedInteger(int32 lower_bound, int32 upper_bound)
00322 
00323 // Creates a Gaussian random interger value.
00324 // std_dev and positive_value are optional arguments with default values 10.0f and true respectively
00325 int32 GaussianRandomValue(int32 mean, float std_dev, bool positive_value) {
00326   float x, y, r;  // x and y are coordinates on the unit circle
00327   float grv_unit; // Used to hold a Gaussian random variable on a normal distribution curve (mean 0, stand dev 1)
00328   float result;
00329 
00330   // Make sure that the standard deviation is positive
00331   if (std_dev < 0) {
00332     cerr << "UTILS WARNING: negative value for standard deviation argument in function GaussianValue" << endl;
00333     std_dev = -1.0f * std_dev;
00334   }
00335 
00336   // Computes a standard Gaussian random number using the the polar form of the Box-Muller transformation.
00337   // The algorithm computes a random point (x, y) inside the unit circle centered at (0, 0) with radius 1.
00338   // Then a Gaussian random variable with mean 0 and standard deviation 1 is computed by:
00339   //
00340   // x * sqrt(-2.0 * log(r) / r)
00341   //
00342   // Reference: Knuth, The Art of Computer Programming, Volume 2, p. 122
00343 
00344   // This loop is executed 4 / pi = 1.273 times on average
00345   do {
00346     x = 2.0f * RandomFloat() - 1.0f;     // Get a random x-coordinate [-1.0f, 1.0f]
00347     y = 2.0f * RandomFloat() - 1.0f;     // Get a random y-coordinate [-1.0f, 1.0f]
00348     r = x*x + y*y;
00349   } while (r > 1.0f || r == 0.0f);
00350   grv_unit = x * sqrt(-2.0f * log(r) / r);
00351 
00352   // Use the standard gaussian value to create a random number with the desired mean and standard deviation.
00353   result = (grv_unit * std_dev) + mean;
00354 
00355   // Return zero if a negative result was found and only positive values were to be returned
00356   if (result < 0.0f && positive_value)
00357     return 0;
00358   else
00359     return static_cast<int32>(result);
00360 } // int32 GaussianValue(int32 mean, float std_dev = 6.667f, bool positive_value = false)
00361 
00362 // Returns true/false depending on the chance
00363 bool Probability(uint32 chance) {
00364   uint32 value = static_cast<uint32>(RandomBoundedInteger(1, 100));
00365   if (value <= chance)
00366     return true;
00367   else
00368     return false;
00369 }
00370 
00374 
00375 bool DoesFileExist(const std::string& file_name) {
00376   struct stat buf;
00377   if (stat(file_name.c_str(), &buf) == 0)
00378     return true;
00379   else
00380     return false;
00381 }
00382 
00383 
00384 
00385 bool MoveFile(const std::string& source_name, const std::string& destination_name) {
00386   return (rename(source_name.c_str(), destination_name.c_str()) == 0);
00387 }
00388 
00389 
00390 
00391 bool MakeDirectory(const std::string& dir_name) {
00392   // Don't do anything if the directory already exists
00393   struct stat buf;
00394   int32 i = stat(dir_name.c_str(), &buf);
00395   if (i == 0)
00396     return true;
00397 
00398   // Create the directory with mkdir(). Note that Windows does not require file permissions to be set, but
00399   // all other operating systems do.
00400 
00401   #ifdef _WIN32
00402     int32 success = mkdir(dir_name.c_str());
00403   #else
00404     int32 success = mkdir(dir_name.c_str(), S_IRWXG | S_IRWXO | S_IRWXU);
00405   #endif
00406 
00407   if (success == -1) {
00408     cerr << "UTILS ERROR: could not create directory: " << dir_name.c_str() << endl;
00409     return false;
00410   }
00411 
00412   return true;
00413 }
00414 
00415 
00416 
00417 bool CleanDirectory(const std::string& dir_name) {
00418   // Don't do anything if the directory doesn't exist
00419   struct stat buf;
00420   int32 i = stat(dir_name.c_str(), &buf);
00421   if (i != 0)
00422     return true;
00423 
00424   #ifdef _WIN32
00425     //--- WINDOWS --------------------------------------------------------------
00426 
00427     // Get the current directory that the Allacrost application resides in
00428     char app_path[1024];
00429     GetCurrentDirectoryA(1024, app_path);
00430 
00431     int32 app_path_len = static_cast<int32>(strlen(app_path));
00432     if (app_path_len <= 0)
00433       return false;
00434     if(app_path[app_path_len-1] == '\\')    // Remove the ending slash if one is there
00435       app_path[app_path_len-1] = '\0';
00436 
00437     string full_path = app_path;
00438 
00439     if (dir_name[0] == '/' || dir_name[0] == '\\') {
00440       full_path += dir_name;
00441     }
00442     else {
00443       full_path += "\\";
00444       full_path += dir_name;
00445     }
00446 
00447     char file_found[1024];
00448     WIN32_FIND_DATAA info;
00449     HANDLE hp;
00450     sprintf(file_found, "%s\\*.*", full_path.c_str());
00451     hp = FindFirstFileA(file_found, &info);
00452 
00453     if (hp != INVALID_HANDLE_VALUE) {
00454       // Remove each file from the full_path directory
00455       do {
00456         sprintf(file_found, "%s\\%s", full_path.c_str(), info.cFileName);
00457         DeleteFileA(file_found);
00458       } while(FindNextFileA(hp, &info));
00459     }
00460     FindClose(hp);
00461 
00462   #else
00463     //--- NOT WINDOWS ----------------------------------------------------------
00464 
00465   DIR *parent_dir;
00466   struct dirent *dir_file;
00467 
00468   parent_dir = opendir(dir_name.c_str());   // open the directory we want to clean
00469   if (!parent_dir) {
00470     cerr << "UTILS ERROR: failed to clean directory: " << dir_name << endl;
00471     return false;
00472   }
00473 
00474   string base_dir = dir_name;
00475   if (base_dir[base_dir.length()-1] != '/')
00476     base_dir += "/";
00477 
00478   // Remove each file found in the parent directory
00479   while ((dir_file = readdir(parent_dir))) {
00480     string file_name = base_dir + dir_file->d_name;
00481     remove(file_name.c_str());
00482   }
00483 
00484   closedir(parent_dir);
00485 
00486   #endif
00487 
00488   return true;
00489 }
00490 
00491 
00492 
00493 bool RemoveDirectory(const std::string& dir_name)
00494 {
00495   // Don't do anything if the directory doesn't exist
00496   struct stat buf;
00497   int32 i = stat(dir_name.c_str(), &buf);
00498   if (i != 0)
00499     return true;
00500 
00501   // Remove any files that still reside in the directory
00502   CleanDirectory(dir_name);
00503 
00504   // Finally, remove the folder itself with rmdir()
00505   int32 success = rmdir(dir_name.c_str());
00506 
00507   if (success == -1) {
00508     cerr << "UTILS ERROR: could not delete directory: " << dir_name << endl;
00509     return false;
00510   }
00511 
00512   return true;
00513 }
00514 
00515 #define VERSION_HOST "rabidtinker.mine.nu"
00516 #define VERSION_PATH "/~alistair/allacrost-version.txt"
00517 #define ALLACROST_MAJOR_VERSION 0
00518 #define ALLACROST_MINOR_VERSION 1
00519 #define ALLACROST_PATCH 0
00520 
00521 static std::string temp_version_str;
00522 
00523 bool IsLatestVersion ()
00524 {
00525   uint32 rversionmajor;
00526   uint32 rversionminor;
00527   uint32 rpatch;
00528   /*rversion = atof ( system(VERSION_URL) );
00529   rpatch = atoi ( system(PATCH_URL) );*/
00530   /*FILE* fp = popen ( "curl -s " VERSION_URL, "r" );
00531   if (!fp)
00532     return true;
00533   fscanf ( fp, "%d.%d.%d", &rversionmajor, &rversionminor, &rpatch );
00534   pclose ( fp );*/
00535   Socket conn;
00536   conn.Connect ( VERSION_HOST, 80 );
00537   if (!conn.IsConnected()) // could not connect
00538     return true; // assume latest version
00539   conn.Write ( "GET http://%s%s\r\n", VERSION_HOST, VERSION_PATH );
00540   conn.IsQueued ( 300 );
00541   conn.ScanLine ( "%d.%d.%d", &rversionmajor, &rversionminor, &rpatch );
00542   conn.Disconnect();
00543 
00544   char vstring[255];
00545   sprintf ( vstring, "%d.%d.%d", rversionmajor, rversionminor, rpatch );
00546   temp_version_str = vstring;
00547 
00548   if (rversionmajor > ALLACROST_MAJOR_VERSION)
00549     return false;
00550   else if (rversionmajor == ALLACROST_MAJOR_VERSION)
00551   {
00552     if (rversionminor > ALLACROST_MINOR_VERSION)
00553       return false;
00554     else if (rversionminor == ALLACROST_MINOR_VERSION)
00555     {
00556       if (rpatch > ALLACROST_PATCH)
00557         return false;
00558     }
00559   }
00560   return true;
00561 }
00562 
00563 string GetLatestVersion ()
00564 {
00565   return temp_version_str;
00566 }
00567 
00568 } // namespace utils

Generated on Fri Jul 6 23:11:25 2007 for Hero of Allacrost by  doxygen 1.5.1