// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_COMMON_H #define NL_COMMON_H #include "types_nl.h" #include #include #include #include #include #include #include #include #include #include #ifdef NL_OS_WINDOWS # include # include # include #else # include # include # include #endif #include "string_common.h" #ifdef NL_OS_WINDOWS typedef HWND nlWindow; #define EmptyWindow NULL #elif defined(NL_OS_MAC) typedef void* nlWindow; #define EmptyWindow NULL #elif defined(NL_OS_UNIX) typedef int nlWindow; #define EmptyWindow 0 #endif /// This namespace contains all miscellaneous classes used by other modules namespace NLMISC { /** Read the time stamp counter. Supports only Intel architectures for now */ #ifdef NL_CPU_INTEL inline uint64 rdtsc() { uint64 ticks; # ifdef NL_OS_WINDOWS # ifdef NL_NO_ASM ticks = uint64(__rdtsc()); # else // We should use the intrinsic code now. ticks = uint64(__rdtsc()); __asm rdtsc __asm mov DWORD PTR [ticks], eax __asm mov DWORD PTR [ticks + 4], edx # endif // NL_NO_ASM # else __asm__ volatile(".byte 0x0f, 0x31" : "=a" (ticks.low), "=d" (ticks.high)); # endif // NL_OS_WINDOWS return ticks; } #endif // NL_CPU_INTEL /** breakable statement, used to allow break call inside parenthesis. */ #define breakable \ switch(1) case 1: default: /** Pi constant in double format. */ const double Pi = 3.1415926535897932384626433832795; // retrieve size of a static array #define sizeofarray(v) (sizeof(v) / sizeof((v)[0])) /** Return a float random inside the interval [0,mod] */ inline float frand(float mod) { double r = (double) rand(); r/= (double) RAND_MAX; return (float)(r * mod); } /** Return -1 if f<0, 0 if f==0, 1 if f>1 */ inline sint fsgn(double f) { if(f<0) return -1; else if(f>0) return 1; else return 0; } /** Return the square of a number */ template inline T sqr(const T &v) { return v * v; } /** Force v to be inside the interval [min,max]. Warning: implicit cast are made if T,U or V are different. */ template inline void clamp(T &v, const U &min, const V &max) { v = (v < min) ? min : v; v = (v > max) ? max : v; } /** MIN/MAX extended functions. */ template inline T minof(const T& a, const T& b, const T& c) {return std::min(std::min(a,b),c);} template inline T minof(const T& a, const T& b, const T& c, const T& d) {return std::min(minof(a,b,c),d);} template inline T minof(const T& a, const T& b, const T& c, const T& d, const T& e) {return std::min(minof(a,b,c,d),e);} template inline T maxof(const T& a, const T& b, const T& c) {return std::max(std::max(a,b),c);} template inline T maxof(const T& a, const T& b, const T& c, const T& d) {return std::max(maxof(a,b,c),d);} template inline T maxof(const T& a, const T& b, const T& c, const T& d, const T& e) {return std::max(maxof(a,b,c,d),e);} /** \c contReset take a container like std::vector or std::deque and put his size to 0 like \c clear() but free all buffers. * This function is useful because \c resize(), \c clear(), \c erase() or \c reserve() methods never realloc when the array size come down. * \param a is the container to reset. */ template inline void contReset (T& a) { a.~T(); new (&a) T; } /** Return the value maximized to the next power of 2 of v. * Example: * raiseToNextPowerOf2(8) is 8 * raiseToNextPowerOf2(5) is 8 */ uint raiseToNextPowerOf2 (uint v); /** Return the power of 2 of v. * Example: * getPowerOf2(8) is 3 * getPowerOf2(5) is 3 */ uint getPowerOf2 (uint v); /** Return \c true if the value is a power of 2. */ bool isPowerOf2 (sint32 v); /** Converts from degrees to radians */ inline float degToRad( float deg ) { return deg * (float)Pi / 180.0f; } /** Converts from radians to degrees */ inline float radToDeg( float rad ) { return rad * 180.0f / (float)Pi; } /** Return true if double is a valid value (not inf nor nan) */ inline double isValidDouble (double v) { #ifdef NL_OS_WINDOWS return _finite(v) && !_isnan(v); #else return !std::isnan(v) && !std::isinf(v); #endif } /** Convert a string in lower case. * \param str a string to transform to lower case */ std::string toLower ( const std::string &str ); void toLower ( char *str ); char toLower ( const char ch ); // convert only one character /** Convert a string in upper case. * \param a string to transform to upper case */ std::string toUpper ( const std::string &str); void toUpper ( char *str); // Remove all the characters <= 32 (tab, space, new line, return, vertical tab etc..) at the beginning and at the end of a string template T trim (const T &str) { typename T::size_type start = 0; const typename T::size_type size = str.size(); while (start < size && str[start] <= 32) start++; typename T::size_type end = size; while (end > start && str[end-1] <= 32) end--; return str.substr (start, end-start); } // remove spaces at the end of the string template T trimRightWhiteSpaces (const T &str) { typename T::size_type end = str.size(); while (end > 0 && str[end-1] == ' ') end--; return str.substr (0, end); } ////////////////////////////////////////////////////////////////////////// // **** DEPRECATED *****: PLEASE DON'T USE THESE METHODS BUT FUNCTIONS ABOVE toLower() and toUpper() ////////////////////////////////////////////////////////////////////////// inline std::string &strlwr ( std::string &str ) { str = toLower(str); return str; } inline std::string strlwr ( const std::string &str ) { return toLower(str); } inline char *strlwr ( char *str ) { toLower(str); return str; } inline std::string &strupr ( std::string &str ) { str = toUpper(str); return str; } inline std::string strupr ( const std::string &str ) { return toUpper(str); } inline char *strupr ( char *str ) { toUpper(str); return str; } /** Compare 2 C-Style strings without regard to case * \return 0 if strings are equal, < 0 if lhs < rhs, > 0 if lhs > rhs * * On Windows, use stricmp * On GNU/Linux, create stricmp using strcasecmp and use stricmp */ #ifndef NL_OS_WINDOWS inline int stricmp(const char *lhs, const char *rhs) { return strcasecmp(lhs, rhs); } inline int strnicmp(const char *lhs, const char *rhs, size_t n) { return strncasecmp(lhs, rhs, n); } #endif inline sint nlstricmp(const char *lhs, const char *rhs) { return stricmp(lhs, rhs); } inline sint nlstricmp(const std::string &lhs, const std::string &rhs) { return stricmp(lhs.c_str(), rhs.c_str()); } inline sint nlstricmp(const std::string &lhs, const char *rhs) { return stricmp(lhs.c_str(),rhs); } inline sint nlstricmp(const char *lhs, const std::string &rhs) { return stricmp(lhs,rhs.c_str()); } /** Signed 64 bit fseek. Same interface as fseek */ int nlfseek64( FILE *stream, sint64 offset, int origin ); // Retrieve position in a file, same interface as ftell sint64 nlftell64(FILE *stream); /** * Base class for all NeL exception. * It enables to construct simple string at the ctor. */ class Exception : public std::exception { protected: std::string _Reason; public: Exception(); Exception(const std::string &reason); Exception(const char *format, ...); virtual ~Exception() throw() {} virtual const char *what() const throw(); }; /** * Portable Sleep() function that suspends the execution of the calling thread for a number of milliseconds. * Note: the resolution of the timer is system-dependant and may be more than 1 millisecond. */ void nlSleep( uint32 ms ); /// Returns Process Id (note: on Linux, Process Id is the same as the Thread Id) #ifdef NL_OS_WINDOWS # define getpid _getpid #endif /// Returns Thread Id (note: on Linux, Process Id is the same as the Thread Id) size_t getThreadId(); /// Returns a readable string from a vector of bytes. unprintable char are replaced by '?' std::string stringFromVector( const std::vector& v, bool limited = true ); /// Convert a string into an sint64 (same as atoi() function but for 64 bits intergers) sint64 atoiInt64 (const char *ident, sint64 base = 10); /// Convert an sint64 into a string (same as itoa() function but for 64 bits intergers) void itoaInt64 (sint64 number, char *str, sint64 base = 10); /// Convert a number in bytes into a string that is easily readable by an human, for example 105123 -> "102kb" std::string bytesToHumanReadable (const std::string &bytes); std::string bytesToHumanReadable (uint64 bytes); /// Convert a human readable into a bytes, for example "102kb" -> 105123 uint32 humanReadableToBytes (const std::string &str); /// Convert a time into a string that is easily readable by an human, for example 3600 -> "1h" std::string secondsToHumanReadable (uint32 time); /// Get a bytes or time in string format and convert it in seconds or bytes uint32 fromHumanReadable (const std::string &str); /// This function executes a program in the background and returns instantly (used for example to launch services in AES). /// The program will be launched in the current directory bool launchProgram (const std::string &programName, const std::string &arguments); /// This function kills a program using his pid (on unix, it uses the kill() POSIX function) bool killProgram(uint32 pid); /// This function kills a program using his pid with abort signal (on unix, it uses the kill() POSIX function) bool abortProgram(uint32 pid); /** Returns a string corresponding to the class T in string format. * Example: * string num = toString (1234); // num = "1234"; */ /*acetemplate std::string toString (const T &t) { std::stringstream ss; ss << t; return ss.str(); } */ /** Returns a string corresponding to the format and parameter (like printf). * Example: * string hexnum = toString ("%x", 255); // hexnum = "ff"; */ /*#ifdef NL_OS_WINDOWS inline std::string _toString (const char *format, ...) #else inline std::string toString (const char *format, ...) #endif { std::string Result; NLMISC_CONVERT_VARGS (Result, format, NLMISC::MaxCStringSize); return Result; } #ifdef NL_OS_WINDOWS CHECK_TYPES(std::string toString, return _toString) #endif // NL_OS_WINDOWS #ifdef NL_OS_UNIX inline std::string toString (const uint8 &t) { std::stringstream ss; ss << (unsigned int)t; return ss.str(); } inline std::string toString (const sint8 &t) { std::stringstream ss; ss << (unsigned int)t; return ss.str(); } #endif // NL_OS_UNIX */ /** Explode a string (or ucstring) into a vector of string with *sep* as separator. If sep can be more than 1 char, in this case, * we find the entire sep to separator (it s not a set of possible separator) * * \param skipEmpty if true, we don't put in the res vector empty string */ template void explode (const T &src, const T &sep, std::vector &res, bool skipEmpty = false) { std::string::size_type oldpos = 0, pos; res.clear (); do { pos = src.find (sep, oldpos); T s; if(pos == std::string::npos) s = src.substr (oldpos); else s = src.substr (oldpos, (pos-oldpos)); if (!skipEmpty || !s.empty()) res.push_back (s); oldpos = pos+sep.size(); } while(pos != std::string::npos); } /* All the code above is used to add our types (uint8, ...) in the stringstream (used by the toString() function). * So we can use stringstream operator << and >> with all NeL simple types (except for ucchar and ucstring) */ /* #ifdef NL_OS_WINDOWS #if _MSC_VER < 1300 // visual or older (on visual .NET, we don't need to do that) #define NLMISC_ADD_BASIC_ISTREAM_OPERATOR(__type,__casttype) \ template \ std::basic_istream<_CharT, _Traits>& __cdecl \ operator>>(std::basic_istream<_CharT, _Traits>& __is, __type& __z) \ { \ __casttype __z2 = (__casttype) __z; \ __is.operator>>(__z2); \ __z = (__type) __z2; \ return __is; \ } \ \ template \ std::basic_ostream<_CharT, _Traits>& __cdecl \ operator<<(std::basic_ostream<_CharT, _Traits>& __os, const __type& __z) \ { \ std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp; \ __tmp << (__casttype) __z; \ return __os << __tmp.str(); \ } NLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint8, unsigned int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint8, signed int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint16, unsigned int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint16, signed int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint32, unsigned int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint32, signed int); #endif // _MSC_VER < 1300 template std::basic_istream<_CharT, _Traits>& __cdecl operator>>(std::basic_istream<_CharT, _Traits>& __is, uint64& __z) { __z = 0; bool neg = false; char c; do { __is >> c; } while (isspace(c)); if (c == '-') { neg = true; __is >> c; } while (isdigit(c)) { __z *= 10; __z += c-'0'; __is >> c; if (__is.fail()) break; } if (neg) __z = 0; return __is; } template std::basic_ostream<_CharT, _Traits>& __cdecl operator<<(std::basic_ostream<_CharT, _Traits>& __os, const uint64& __z) { std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __res; if (__z == 0) { __res << '0'; } else { std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp; uint64 __z2 = __z; while (__z2 != 0) { __tmp << (char)((__z2%10)+'0'); __z2 /= 10; } uint __s = __tmp.str().size(); for (uint i = 0; i < __s; i++) __res << __tmp.str()[__s - 1 - i]; } return __os << __res.str(); } template std::basic_istream<_CharT, _Traits>& __cdecl operator>>(std::basic_istream<_CharT, _Traits>& __is, sint64& __z) { __z = 0; bool neg = false; char c; do { __is >> c; } while (isspace(c)); if (c == '-') { neg = true; __is >> c; } while (isdigit(c)) { __z *= 10; __z += c-'0'; __is >> c; if (__is.fail()) break; } if (neg) __z = -__z; return __is; } template std::basic_ostream<_CharT, _Traits>& __cdecl operator<<(std::basic_ostream<_CharT, _Traits>& __os, const sint64& __z) { std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __res; if (__z == 0) { __res << '0'; } else { sint64 __z2 = __z; if (__z2 < 0) { __res << '-'; } std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp; while (__z2 != 0) { if (__z2 < 0) { __tmp << (char)((-(__z2%10))+'0'); } else { __tmp << (char)((__z2%10)+'0'); } __z2 /= 10; } uint __s = __tmp.str().size(); for (uint i = 0; i < __s; i++) __res << __tmp.str()[__s - 1 - i]; } return __os << __res.str(); } #endif // NL_OS_WINDOWS */ class CLog; /// Display the bits (with 0 and 1) composing a byte (from right to left) void displayByteBits( uint8 b, uint nbits, sint beginpos, bool displayBegin, NLMISC::CLog *log ); /// Display the bits (with 0 and 1) composing a number (uint32) (from right to left) void displayDwordBits( uint32 b, uint nbits, sint beginpos, bool displayBegin, NLMISC::CLog *log ); /// this wrapping is due to a visual bug when calling isprint with big value /// example of crash with VC6 SP4: int a = isprint(0x40e208); #ifdef NL_OS_WINDOWS inline int nlisprint(int c) { if(c>255||c<0) return 0; return isprint(c); } #else #define nlisprint isprint #endif // Open an url in a browser bool openURL (const char *url); // Open a document bool openDoc (const char *document); // AntiBug method that return an epsilon if x==0, else x inline float favoid0(float x) { if(x==0) return 0.00001f; return x; } inline double davoid0(double x) { if(x==0) return 0.00001; return x; } // AntiBug method that return 1 if x==0, else x template inline T iavoid0(T x) { if(x==0) return 1; return x; } } // NLMISC #endif // NL_COMMON_H