openmohaa/code/gamespy/common/gsPlatformUtil.c

1898 lines
45 KiB
C
Raw Normal View History

2023-02-04 21:00:01 +01:00
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#include "gsCommon.h"
#include "gsPlatformUtil.h"
// Include platform separated functions
#if defined(_X360)
//#include "x360/gsUtilX360.c"
#elif defined(_XBOX)
//#include "xbox/gsUtilXBox.c"
#elif defined(_WIN32)
#include "win32/gsUtilWin32.c"
#elif defined(_LINUX)
#include "linux/gsUtilLinux.c"
#elif defined(_MACOSX)
#include "macosx/gsUtilMacOSX.c"
#elif defined(_NITRO)
#include "nitro/gsUtilNitro.c"
#elif defined(_PS2)
#include "ps2/gsUtilPs2.c"
#elif defined(_PS3)
#include "ps3/gsUtilPs3.c"
#elif defined(_PSP)
#include "psp/gsUtilPSP.c"
#elif defined(_REVOLUTION)
#include "revolution/gsUtilRevolution.c"
#else
#error "Missing or unsupported platform"
#endif
#if defined(__cplusplus)
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// ********** ASYNC DNS ********** //
//struct is used in both threaded and non-threaded versions
typedef struct GSIResolveHostnameInfo
{
char * hostname;
unsigned int ip;
#if defined(_WIN32) /*|| defined(_PS2)*/ || defined(_UNIX) || defined (_REVOLUTION)
int finishedResolving;
GSIThreadID threadID;
#endif
/*#if defined(_PSP)
int finishedResolving;
GSIThreadID threadID;
#endif*/
} GSIResolveHostnameInfo;
////////////////////////////////////////////////////////////////////////////////
// for asynch DNS, must have:
// * platform that supports threaded lookup AND
// * threading enabled
// * and async lookup enabled
////////////////////////////////////////////////////////////////////////////////
#if (defined(_WIN32) || /*defined(_PS2) ||*/ defined(_UNIX) || defined (_REVOLUTION)) && !defined(GSI_NO_THREADS) && !defined(GSI_NO_ASYNC_DNS)
////////////////////////////////////////////////////////////////////////////////
#if defined(_WIN32) /*|| defined(_PS2)*/
#if defined(_WIN32)
DWORD WINAPI gsiResolveHostnameThread(void * arg)
/*#elif defined(_PS2)
static void gsiResolveHostnameThread(void * arg)*/
#endif
{
HOSTENT * hostent;
GSIResolveHostnameHandle handle = (GSIResolveHostnameHandle)arg;
SocketStartUp();
#ifdef SN_SYSTEMS
sockAPIregthr();
#endif
// do the gethostbyname
hostent = gethostbyname(handle->hostname);
if(hostent)
{
// got the ip
handle->ip = *(unsigned int *)hostent->h_addr_list[0];
}
else
{
// didn't resolve
handle->ip = GSI_ERROR_RESOLVING_HOSTNAME;
}
SocketShutDown();
// finished resolving
handle->finishedResolving = 1;
#ifdef SN_SYSTEMS
sockAPIderegthr();
#endif
// explicitly exit the thread to free resources
gsiExitThread(handle->threadID);
#if defined(_WIN32)
return 0;
#endif
}
#endif //defined _WIN32
////////////////////////////////////////////////////////////////////////////////
#ifdef _REVOLUTION
///////////////////////////////////////////////////////////////////////////////
static void *gsiResolveHostnameThread(void * arg)
{
static GSICriticalSection aHostnameCrit;
static int aInitialized = 0;
//SOAddrInfo *aHostAddr;
HOSTENT *aHostAddr;
//int retval;
GSIResolveHostnameHandle handle = (GSIResolveHostnameHandle)arg;
if (!aInitialized)
{
gsiInitializeCriticalSection(&aHostnameCrit);
aInitialized = 1;
}
gsiEnterCriticalSection(&aHostnameCrit);
//retval = getaddrinfo(handle->hostname, NULL, NULL, &aHostAddr);
aHostAddr = gethostbyname(handle->hostname);
if (aHostAddr != 0)
{
char * ip;
// first convert to character string for debug output
ip = inet_ntoa(*(in_addr *)aHostAddr->addrList[0]);
gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment,
"Resolved host '%s' to ip '%s'\n", handle->hostname, ip);
handle->ip = inet_addr(ip);
//freeaddrinfo(aHostAddr);
}
else
{
// couldnt reach host - debug output is printed later
handle->ip = GSI_ERROR_RESOLVING_HOSTNAME;
}
// finished resolving
handle->finishedResolving = 1;
gsiLeaveCriticalSection(&aHostnameCrit);
}
#endif // _REVOLUTION
////////////////////////////////////////////////////////////////////////////////
//
// Linux/MacOSX implementation of multithreaded DNS lookup
// Uses getaddrinfo instead of gethostbyname - since the latter
// has static declarations and is thus un-safe for pthreads
//
// NOTE: The compiler option "-lpthread" must used for this
#if defined(_UNIX)
////////////////////////////////////////////////////////////////////////////////
static void gsiResolveHostnameThread(void * arg)
{
GSIResolveHostnameHandle handle = (GSIResolveHostnameHandle)arg;
struct addrinfo hints, *result = NULL;
int error;
char *ip;
SocketStartUp();
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
// DNS lookup (works with pthreads)
error = getaddrinfo(handle->hostname, "http", &hints, &result);
if (!error)
{
// first convert to character string for debug output
ip = inet_ntoa((*(struct sockaddr_in*)result->ai_addr).sin_addr);
gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment,
"Resolved host '%s' to ip '%s'\n", handle->hostname, ip);
// now convert to unsigned int and store it
handle->ip = inet_addr(ip);
// free the memory used
freeaddrinfo(result);
}
else
{
// couldnt reach host - debug output is printed later
handle->ip = GSI_ERROR_RESOLVING_HOSTNAME;
}
SocketShutDown();
// finished resolving
handle->finishedResolving = 1;
// explicitly exit the thread to free resources
gsiExitThread(handle->threadID);
}
#endif //_UNIX
////////////////////////////////////////////////////////////////////////////////
int gsiStartResolvingHostname(const char * hostname, GSIResolveHostnameHandle * handle)
{
GSIResolveHostnameInfo * info;
//PS2 Threading unsupported in current build - this should never be reached
#if defined(_PS2)
GS_ASSERT_STR(gsi_false, "PS2 Threading unsupported in current version of the SDK\n");
#endif
// allocate a handle
info = (GSIResolveHostnameInfo *)gsimalloc(sizeof(GSIResolveHostnameInfo));
if(!info)
return -1;
// make a copy of the hostname so the thread has access to it
info->hostname = goastrdup(hostname);
if(!info->hostname)
{
gsifree(info);
return -1;
}
// not resolved yet
info->finishedResolving = 0;
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_State, GSIDebugLevel_Comment,
"(Asynchrounous) DNS lookup starting\n");
// start the thread
if(gsiStartThread(gsiResolveHostnameThread, (0x1000), info, &info->threadID) == -1)
{
gsifree(info->hostname);
info->hostname = NULL;
gsifree(info);
info = NULL;
return -1;
}
// set the handle to the info
*handle = info;
return 0;
}
void gsiCancelResolvingHostname(GSIResolveHostnameHandle handle)
{
// cancel the thread
gsiCancelThread(handle->threadID);
if (handle->hostname)
{
gsifree(handle->hostname);
handle->hostname = NULL;
}
gsifree(handle);
handle = NULL;
}
unsigned int gsiGetResolvedIP(GSIResolveHostnameHandle handle)
{
unsigned int ip;
// check if we haven't finished
if(!handle->finishedResolving)
return GSI_STILL_RESOLVING_HOSTNAME;
// save the ip
ip = handle->ip;
// free resources
gsiCleanupThread(handle->threadID);
gsifree(handle->hostname);
gsifree(handle);
handle = NULL;
return ip;
}
#else // if * not a supported platform OR * no threads allowed OR * no async lookup allowed
///////////////////////////////////////////////////////////////////////////////////
// if !(_WIN32 ||_PS2 || _LINUX || _MACOSX || _REVOLUTION) || GSI_NO_THREADS || GSI_NO_ASYNC_DNS
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// ********** NON-ASYNC DNS ********** //
//
// These are the non-threaded version of the above functions.
// The following platforms have synchronous DNS lookups:
// _NITRO || _XBOX || _X360 || _PS3 || _PS2 || _PSP
///////////////////////////////////////////////////////////////////////////////
int gsiStartResolvingHostname(const char * hostname, GSIResolveHostnameHandle * handle)
{
GSIResolveHostnameInfo * info;
HOSTENT * hostent;
gsDebugFormat(GSIDebugCat_HTTP, GSIDebugType_State, GSIDebugLevel_Comment,
"(NON-Asynchrounous) DNS lookup starting\n");
// do the lookup now
hostent = gethostbyname(hostname);
if(hostent == NULL)
return -1;
// allocate info to store the result
info = (GSIResolveHostnameHandle)gsimalloc(sizeof(GSIResolveHostnameInfo));
if(!info)
return -1;
// we already have the ip
info->ip = *(unsigned int *)hostent->h_addr_list[0];
// set the handle to the info
*handle = info;
return 0;
}
void gsiCancelResolvingHostname(GSIResolveHostnameHandle handle)
{
gsifree(handle);
handle = NULL;
}
unsigned int gsiGetResolvedIP(GSIResolveHostnameHandle handle)
{
// we always do the resolve in the initial call for systems without
// an async version, so we'll always have the IP at this point
unsigned int ip = handle->ip;
gsifree(handle);
handle = NULL;
return ip;
}
///////////////////////////////////////////////////////////////////////////////
#endif // synch DNS lookup
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
char * goastrdup(const char *src)
{
char *res;
if(src == NULL) //PANTS|02.11.00|check for NULL before strlen
return NULL;
res = (char *)gsimalloc(strlen(src) + 1);
if(res != NULL) //PANTS|02.02.00|check for NULL before strcpy
strcpy(res, src);
return res;
}
unsigned short * goawstrdup(const unsigned short *src)
{
unsigned short *res;
if(src == NULL)
return NULL;
res = (unsigned short *)gsimalloc((wcslen((wchar_t*)src) + 1) * sizeof(unsigned short));
if(res != NULL)
wcscpy((wchar_t*)res, (const wchar_t*)src);
return res;
}
#if !defined(_WIN32)
char *_strlwr(char *string)
{
char *hold = string;
while (*string)
{
*string = (char)tolower(*string);
string++;
}
return hold;
}
char *_strupr(char *string)
{
char *hold = string;
while (*string)
{
*string = (char)toupper(*string);
string++;
}
return hold;
}
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void SocketStartUp()
{
#if defined(_WIN32)
WSADATA data;
#if defined(_X360)
XNetStartupParams xnsp;
memset(&xnsp,0,sizeof(xnsp));
xnsp.cfgSizeOfStruct=sizeof(xnsp);
xnsp.cfgFlags=XNET_STARTUP_BYPASS_SECURITY;
if(0 != XNetStartup(&xnsp))
{
OutputDebugString("XNetStartup failed\n");
}
#endif
// added support for winsock2
#if (!defined(_XBOX) || defined(_X360)) && (defined(GSI_WINSOCK2) || defined(_X360))
WSAStartup(MAKEWORD(2,2), &data);
#else
WSAStartup(MAKEWORD(1,1), &data);
#endif
// end added
#endif
}
void SocketShutDown()
{
#if defined(_WIN32)
WSACleanup();
2023-02-04 21:00:01 +01:00
#if defined(_X360)
XNetCleanup();
#endif
#endif
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifdef _PS2
extern int sceCdReadClock();
#if !defined(__MWERKS__) && !defined(_PS2)
typedef unsigned char u_char;
#endif
typedef struct {
u_char stat; /* status */
u_char second; /* second */
u_char minute; /* minute */
u_char hour; /* hour */
u_char pad; /* pad */
u_char day; /* day */
u_char month; /* month */
u_char year; /* year */
} sceCdCLOCK;
static unsigned long GetTicks()
{
unsigned long ticks;
asm volatile (" mfc0 %0, $9 " : "=r" (ticks));
return ticks;
}
#define DEC(x) (10*(x/16)+(x%16))
#define _BASE_YEAR 70L
#define _MAX_YEAR 138L
#define _LEAP_YEAR_ADJUST 17L
int _days[] = {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364};
static time_t _gmtotime_t (
int yr, /* 0 based */
int mo, /* 1 based */
int dy, /* 1 based */
int hr,
int mn,
int sc
)
{
int tmpdays;
long tmptim;
struct tm tb;
if ( ((long)(yr -= 1900) < _BASE_YEAR) || ((long)yr > _MAX_YEAR) )
return (time_t)(-1);
tmpdays = dy + _days[mo - 1];
if ( !(yr & 3) && (mo > 2) )
tmpdays++;
tmptim = (long)yr - _BASE_YEAR;
tmptim = ( ( ( ( tmptim ) * 365L
+ ((long)(yr - 1) >> 2) - (long)_LEAP_YEAR_ADJUST
+ (long)tmpdays )
* 24L + (long)hr )
* 60L + (long)mn )
* 60L + (long)sc;
tb.tm_yday = tmpdays;
tb.tm_year = yr;
tb.tm_mon = mo - 1;
tb.tm_hour = hr;
return (tmptim >= 0) ? (time_t)tmptim : (time_t)(-1);
}
time_t time(time_t *timer)
{
time_t tim;
sceCdCLOCK clocktime; /* defined in libcdvd.h */
sceCdReadClock(&clocktime); /* libcdvd.a */
tim = _gmtotime_t ( DEC(clocktime.year)+2000,
DEC(clocktime.month),
DEC(clocktime.day),
DEC(clocktime.hour),
DEC(clocktime.minute),
DEC(clocktime.second));
if(timer)
*timer = tim;
return tim;
}
#endif /* _PS2 */
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
gsi_time current_time() //returns current time in milliseconds
{
#if defined(_WIN32)
return (GetTickCount());
#elif defined(_PS2)
unsigned int ticks;
static unsigned int msec = 0;
static unsigned int lastticks = 0;
sceCdCLOCK lasttimecalled; /* defined in libcdvd.h */
if(!msec)
{
sceCdReadClock(&lasttimecalled); /* libcdvd.a */
msec = (unsigned int)(DEC(lasttimecalled.day) * 86400000) +
(unsigned int)(DEC(lasttimecalled.hour) * 3600000) +
(unsigned int)(DEC(lasttimecalled.minute) * 60000) +
(unsigned int)(DEC(lasttimecalled.second) * 1000);
}
ticks = (unsigned int)GetTicks();
if(lastticks > ticks)
msec += (unsigned int)(((unsigned int)(-1) - lastticks) + ticks) / 300000;
else
msec += (unsigned int)(ticks-lastticks) / 300000;
lastticks = ticks;
return msec;
#elif defined(_UNIX)
struct timeval time;
gettimeofday(&time, NULL);
return (time.tv_sec * 1000 + time.tv_usec / 1000);
#elif defined(_NITRO)
assert(OS_IsTickAvailable() == TRUE);
return (gsi_time)OS_TicksToMilliSeconds(OS_GetTick());
#elif defined(_PSP)
struct SceRtcTick ticks;
int result = 0;
result = sceRtcGetCurrentTick(&ticks);
if (result < 0)
{
ScePspDateTime time;
result = sceRtcGetCurrentClock(&time, 0);
if (result < 0)
return 0; // um...error handling? //Nope, should return zero since time cannot be zero
result = sceRtcGetTick(&time, &ticks);
if (result < 0)
return 0; //Nope, should return zero since time cannot be zero
}
return (gsi_time)(ticks.tick / 1000);
#elif defined(_PS3)
return (gsi_time)(sys_time_get_system_time()/1000);
#elif defined(_REVOLUTION)
OSTick aTickNow= OSGetTick();
gsi_time aMilliseconds = (gsi_time)OSTicksToMilliseconds(aTickNow);
return aMilliseconds;
#else
// unrecognized platform! contact devsupport
assert(0);
#endif
}
gsi_time current_time_hires() // returns current time in microseconds
{
#ifdef _WIN32
#if (!defined(_M_IX86) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64))
static LARGE_INTEGER counterFrequency;
static BOOL haveCounterFrequency = FALSE;
static BOOL haveCounter = FALSE;
LARGE_INTEGER count;
if(!haveCounterFrequency)
{
haveCounter = QueryPerformanceFrequency(&counterFrequency);
haveCounterFrequency = TRUE;
}
if(haveCounter)
{
if(QueryPerformanceCounter(&count))
{
return (gsi_time)(count.QuadPart * 1000000 / counterFrequency.QuadPart);
}
}
#endif
return (current_time() / 1000);
#endif
#ifdef _PS2
unsigned int ticks;
static unsigned int msec = 0;
static unsigned int lastticks = 0;
sceCdCLOCK lasttimecalled; /* defined in libcdvd.h */
if(!msec)
{
sceCdReadClock(&lasttimecalled); /* libcdvd.a */
msec = (unsigned int)(DEC(lasttimecalled.day) * 86400000) +
(unsigned int)(DEC(lasttimecalled.hour) * 3600000) +
(unsigned int)(DEC(lasttimecalled.minute) * 60000) +
(unsigned int)(DEC(lasttimecalled.second) * 1000);
msec *= 1000;
}
ticks = (unsigned int)GetTicks();
if(lastticks > ticks)
msec += ((sizeof(unsigned int) - lastticks) + ticks) / 300;
else
msec += (unsigned int)(ticks-lastticks) / 300;
lastticks = ticks;
return msec;
#endif
#ifdef _PSP
struct SceRtcTick ticks;
int result = 0;
result = sceRtcGetCurrentTick(&ticks);
if (result < 0)
{
ScePspDateTime time;
result = sceRtcGetCurrentClock(&time, 0);
if (result < 0)
return 0; // um...error handling? //Nope, should return zero since time cannot be zero
result = sceRtcGetTick(&time, &ticks);
if (result < 0)
return 0; //Nope, should return zero since time cannot be zero
}
return (gsi_time)(ticks.tick);
#endif
#ifdef _UNIX
struct timeval time;
gettimeofday(&time, NULL);
return (time.tv_sec * 1000000 + time.tv_usec);
#endif
#ifdef _NITRO
assert(OS_IsTickAvailable() == TRUE);
return (gsi_time)OS_TicksToMicroSeconds(OS_GetTick());
#endif
#ifdef _PS3
return (gsi_time)sys_time_get_system_time();
#endif
}
void msleep(gsi_time msec)
{
#if defined(_WIN32)
Sleep(msec);
#elif defined(_PS2)
#ifdef SN_SYSTEMS
sn_delay((int)msec);
#endif
#ifdef EENET
if(msec >= 1000)
{
sleep(msec / 1000);
msec -= (msec / 1000);
}
if(msec)
usleep(msec * 1000);
#endif
#ifdef INSOCK
DelayThread(msec * 1000);
#endif
#elif defined(_PSP)
sceKernelDelayThread(msec * 1000);
#elif defined(_UNIX)
usleep(msec * 1000);
#elif defined(_NITRO)
OS_Sleep(msec);
#elif defined(_PS3)
sys_timer_usleep(msec* 1000);
#elif defined (_REVOLUTION)
OSSleepMilliseconds(msec);
#else
assert(0); // missing platform handler, contact devsupport
#endif
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Cross-platform GSI wrapper time conversion functions
//
// NOTE: some portions of this copied from standard C library
#if defined(_NITRO) || defined(_REVOLUTION)
// if an error occurs when calling mktime, return -1
#define MKTIME_ERROR (time_t)(-1)
// define common conversions for mktime
#define DAY_SEC (24L * 60L * 60L) /* secs in a day */
#define YEAR_SEC (365L * DAY_SEC) /* secs in a year */
#define FOUR_YEAR_SEC (1461L * DAY_SEC) /* secs in a 4 year interval */
#define DEC_SEC 315532800L /* secs in 1970-1979 */
#define BASE_DOW 4 /* 01-01-70 was a Thursday */
#define BASE_YEAR 70L /* 1970 is the base year */
#define LEAP_YEAR_ADJUST 17L /* Leap years 1900 - 1970 */
#define MAX_YEAR 138L /* 2038 is the max year */
// ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed
#define ChkAdd(dest, src1, src2) ( ((src1 >= 0L) && (src2 >= 0L) \
&& (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) )
// ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed
#define ChkMul(dest, src1, src2) ( src1 ? (dest/src1 != src2) : 0 )
int _lpdays[] = { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
int _days[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 };
const char _dnames[] = { "SunMonTueWedThuFriSat" };
/* Month names must be Three character abbreviations strung together */
const char _mnames[] = { "JanFebMarAprMayJunJulAugSepOctNovDec" };
static struct tm tb = { 0 }; /* time block used in SecondsToDate */
static char buf[26]; /* buffer used to store string in SecondsToString */
static char * store_dt(char *, int);
static char * store_dt(char *p, int val)
{
*p++ = (char)(_T('0') + val / 10);
*p++ = (char)(_T('0') + val % 10);
return(p);
}
#endif //_NITRO || _REVOLUTION
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// GSI equivalent of Standard C-lib "gmtime function"
struct tm * gsiSecondsToDate(const time_t *timp)
{
#if !defined(_NITRO) && !defined(_REVOLUTION)
// for all platforms that support the standard C 'gmtime' use that
return gmtime(timp);
#else
time_t caltim = *timp; /* calendar time to convert */
int islpyr = 0; /* is-current-year-a-leap-year flag */
int tmptim;
int *mdays; /* pointer to days or lpdays */
struct tm *ptb = &tb;
if ( caltim < 0L )
return(NULL);
/*
* Determine years since 1970. First, identify the four-year interval
* since this makes handling leap-years easy (note that 2000 IS a
* leap year and 2100 is out-of-range).
*/
tmptim = (int)(caltim / FOUR_YEAR_SEC);
caltim -= ((long)tmptim * FOUR_YEAR_SEC);
/*
* Determine which year of the interval
*/
tmptim = (tmptim * 4) + 70; /* 1970, 1974, 1978,...,etc. */
if ( caltim >= YEAR_SEC )
{
tmptim++; /* 1971, 1975, 1979,...,etc. */
caltim -= YEAR_SEC;
if ( caltim >= YEAR_SEC )
{
tmptim++; /* 1972, 1976, 1980,...,etc. */
caltim -= YEAR_SEC;
/*
* Note, it takes 366 days-worth of seconds to get past a leap
* year.
*/
if ( caltim >= (YEAR_SEC + DAY_SEC) )
{
tmptim++; /* 1973, 1977, 1981,...,etc. */
caltim -= (YEAR_SEC + DAY_SEC);
}
else
{
/*
* In a leap year after all, set the flag.
*/
islpyr++;
}
}
}
/*
* tmptim now holds the value for tm_year. caltim now holds the
* number of elapsed seconds since the beginning of that year.
*/
ptb->tm_year = tmptim;
/*
* Determine days since January 1 (0 - 365). This is the tm_yday value.
* Leave caltim with number of elapsed seconds in that day.
*/
ptb->tm_yday = (int)(caltim / DAY_SEC);
caltim -= (long)(ptb->tm_yday) * DAY_SEC;
/*
* Determine months since January (0 - 11) and day of month (1 - 31)
*/
if ( islpyr )
mdays = _lpdays;
else
mdays = _days;
for ( tmptim = 1 ; mdays[tmptim] < ptb->tm_yday ; tmptim++ ) ;
ptb->tm_mon = --tmptim;
ptb->tm_mday = ptb->tm_yday - mdays[tmptim];
/*
* Determine days since Sunday (0 - 6)
*/
ptb->tm_wday = ((int)(*timp / DAY_SEC) + BASE_DOW) % 7;
/*
* Determine hours since midnight (0 - 23), minutes after the hour
* (0 - 59), and seconds after the minute (0 - 59).
*/
ptb->tm_hour = (int)(caltim / 3600);
caltim -= (long)ptb->tm_hour * 3600L;
ptb->tm_min = (int)(caltim / 60);
ptb->tm_sec = (int)(caltim - (ptb->tm_min) * 60);
ptb->tm_isdst = 0;
return( (struct tm *)ptb );
#endif
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// GSI equivalent of Standard C-lib "mktime function"
time_t gsiDateToSeconds(struct tm *tb)
{
#if !defined(_NITRO) && !defined(_REVOLUTION)
// for all platforms that support the standard C 'mktime' use that
return mktime(tb);
#else
time_t tmptm1, tmptm2, tmptm3;
struct tm *tbtemp;
/*
* First, make sure tm_year is reasonably close to being in range.
*/
if ( ((tmptm1 = tb->tm_year) < BASE_YEAR - 1) || (tmptm1 > MAX_YEAR + 1) )
return MKTIME_ERROR;
/*
* Adjust month value so it is in the range 0 - 11. This is because
* we don't know how many days are in months 12, 13, 14, etc.
*/
if ( (tb->tm_mon < 0) || (tb->tm_mon > 11) ) {
/*
* no danger of overflow because the range check above.
*/
tmptm1 += (tb->tm_mon / 12);
if ( (tb->tm_mon %= 12) < 0 ) {
tb->tm_mon += 12;
tmptm1--;
}
/*
* Make sure year count is still in range.
*/
if ( (tmptm1 < BASE_YEAR - 1) || (tmptm1 > MAX_YEAR + 1) )
return MKTIME_ERROR;
}
/***** HERE: tmptm1 holds number of elapsed years *****/
/*
* Calculate days elapsed minus one, in the given year, to the given
* month. Check for leap year and adjust if necessary.
*/
tmptm2 = _days[tb->tm_mon];
if ( !(tmptm1 & 3) && (tb->tm_mon > 1) )
tmptm2++;
/*
* Calculate elapsed days since base date (midnight, 1/1/70, UTC)
*
*
* 365 days for each elapsed year since 1970, plus one more day for
* each elapsed leap year. no danger of overflow because of the range
* check (above) on tmptm1.
*/
tmptm3 = (tmptm1 - BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2)
- LEAP_YEAR_ADJUST;
/*
* elapsed days to current month (still no possible overflow)
*/
tmptm3 += tmptm2;
/*
* elapsed days to current date. overflow is now possible.
*/
tmptm1 = tmptm3 + (tmptm2 = (long)(tb->tm_mday));
if ( ChkAdd(tmptm1, tmptm3, tmptm2) )
return MKTIME_ERROR;
/***** HERE: tmptm1 holds number of elapsed days *****/
/*
* Calculate elapsed hours since base date
*/
tmptm2 = tmptm1 * 24L;
if ( ChkMul(tmptm2, tmptm1, 24L) )
return MKTIME_ERROR;
tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_hour);
if ( ChkAdd(tmptm1, tmptm2, tmptm3) )
return MKTIME_ERROR;
/***** HERE: tmptm1 holds number of elapsed hours *****/
/*
* Calculate elapsed minutes since base date
*/
tmptm2 = tmptm1 * 60L;
if ( ChkMul(tmptm2, tmptm1, 60L) )
return MKTIME_ERROR;
tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_min);
if ( ChkAdd(tmptm1, tmptm2, tmptm3) )
return MKTIME_ERROR;
/***** HERE: tmptm1 holds number of elapsed minutes *****/
/*
* Calculate elapsed seconds since base date
*/
tmptm2 = tmptm1 * 60L;
if ( ChkMul(tmptm2, tmptm1, 60L) )
return MKTIME_ERROR;
tmptm1 = tmptm2 + (tmptm3 = (long)tb->tm_sec);
if ( ChkAdd(tmptm1, tmptm2, tmptm3) )
return MKTIME_ERROR;
/***** HERE: tmptm1 holds number of elapsed seconds *****/
if ( (tbtemp = gsiSecondsToDate(&tmptm1)) == NULL )
return MKTIME_ERROR;
/***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/
/***** for local time if requested *****/
*tb = *tbtemp;
return (time_t)tmptm1;
#endif
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// GSI equivalent of Standard C-lib "ctime function"
char * gsiSecondsToString(const time_t *timp)
{
#if !defined(_NITRO) && !defined(_REVOLUTION)
// for all platforms that support the standard C 'ctime' use that
return ctime(timp);
#else
char *p = buf;
int day, mon;
int i;
struct tm *ptm;
ptm = gsiSecondsToDate(timp); /* parse seconds into date structure */
p = buf; /* use static buffer */
/* copy day and month names into the buffer */
day = ptm->tm_wday * 3; /* index to correct day string */
mon = ptm->tm_mon * 3; /* index to correct month string */
for (i=0; i < 3; i++,p++) {
*p = *(_dnames + day + i);
*(p+4) = *(_mnames + mon + i);
}
*p = _T(' '); /* blank between day and month */
p += 4;
*p++ = _T(' ');
p = store_dt(p, ptm->tm_mday); /* day of the month (1-31) */
*p++ = _T(' ');
p = store_dt(p, ptm->tm_hour); /* hours (0-23) */
*p++ = _T(':');
p = store_dt(p, ptm->tm_min); /* minutes (0-59) */
*p++ = _T(':');
p = store_dt(p, ptm->tm_sec); /* seconds (0-59) */
*p++ = _T(' ');
p = store_dt(p, 19 + (ptm->tm_year/100)); /* year (after 1900) */
p = store_dt(p, ptm->tm_year%100);
*p++ = _T('\n');
*p = _T('\0');
return ((char *) buf);
#endif
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Cross platform random number generator
#define RANa 16807 // multiplier
#define LONGRAND_MAX 2147483647L // 2**31 - 1
static long randomnum = 1;
static long nextlongrand(long seed)
{
unsigned
long lo, hi;
lo = RANa *(unsigned long)(seed & 0xFFFF);
hi = RANa *((unsigned long)seed >> 16);
lo += (hi & 0x7FFF) << 16;
if (lo > LONGRAND_MAX)
{
lo &= LONGRAND_MAX;
++lo;
}
lo += hi >> 15;
if (lo > LONGRAND_MAX)
{
lo &= LONGRAND_MAX;
++lo;
}
return(long)lo;
}
// return next random long
static long longrand(void)
{
randomnum = nextlongrand(randomnum);
return randomnum;
}
// to seed it
void Util_RandSeed(unsigned long seed)
{
// nonzero seed
randomnum = seed ? (long)(seed & LONGRAND_MAX) : 1;
}
int Util_RandInt(int low, int high)
{
unsigned int range = (unsigned int)high-low;
int num;
if (range == 0)
return (low); // Prevent divide by zero
num = (int)(longrand() % range);
return(num + low);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/*****************************
UNICODE ENCODING
******************************/
static void QuartToTrip(char *quart, char *trip, int inlen)
{
if (inlen >= 2)
trip[0] = (char)(quart[0] << 2 | quart[1] >> 4);
if (inlen >= 3)
trip[1] = (char)((quart[1] & 0x0F) << 4 | quart[2] >> 2);
if (inlen >= 4)
trip[2] = (char)((quart[2] & 0x3) << 6 | quart[3]);
}
static void TripToQuart(const char *trip, char *quart, int inlen)
{
unsigned char triptemp[3];
int i;
for (i = 0; i < inlen ; i++)
{
triptemp[i] = (unsigned char)trip[i];
}
while (i < 3) //fill the rest with 0
{
triptemp[i] = 0;
i++;
}
quart[0] = (char)(triptemp[0] >> 2);
quart[1] = (char)(((triptemp[0] & 3) << 4) | (triptemp[1] >> 4));
quart[2] = (char)((triptemp[1] & 0x0F) << 2 | (triptemp[2] >> 6));
quart[3] = (char)(triptemp[2] & 0x3F);
}
const char defaultEncoding[] = {'+','/','='};
const char alternateEncoding[] = {'[',']','_'};
const char urlSafeEncodeing[] = {'-','_','='};
void B64Decode(const char *input, char *output, int inlen, int * outlen, int encodingType)
{
const char *encoding = NULL;
const char *holdin = input;
int readpos = 0;
int writepos = 0;
char block[4];
//int outlen = -1;
//int inlen = (int)strlen(input);
// 10-31-2004 : Added by Saad Nader
// now supports URL safe encoding
////////////////////////////////////////////////
switch(encodingType)
{
case 1:
encoding = alternateEncoding;
break;
case 2:
encoding = urlSafeEncodeing;
break;
default: encoding = defaultEncoding;
}
GS_ASSERT(inlen >= 0);
if (inlen <= 0)
{
if (outlen)
*outlen = 0;
output[0] = '\0';
return;
}
// Break at end of string or padding character
while (readpos < inlen && input[readpos] != encoding[2])
{
// 'A'-'Z' maps to 0-25
// 'a'-'z' maps to 26-51
// '0'-'9' maps to 52-61
// 62 maps to encoding[0]
// 63 maps to encoding[1]
if (input[readpos] >= '0' && input[readpos] <= '9')
block[readpos%4] = (char)(input[readpos] - 48 + 52);
else if (input[readpos] >= 'a' && input[readpos] <= 'z')
block[readpos%4] = (char)(input[readpos] - 71);
else if (input[readpos] >= 'A' && input[readpos] <= 'Z')
block[readpos%4] = (char)(input[readpos] - 65);
else if (input[readpos] == encoding[0])
block[readpos%4] = 62;
else if (input[readpos] == encoding[1])
block[readpos%4] = 63;
// padding or '\0' characters also mark end of input
else if (input[readpos] == encoding[2])
break;
else if (input[readpos] == '\0')
break;
else
{
// (assert(0)); //bad input data
if (outlen)
*outlen = 0;
output[0] = '\0';
return; //invaid data
}
// every 4 bytes, convert QuartToTrip into destination
if (readpos%4==3) // zero based, so (3%4) means four bytes, 0-1-2-3
{
QuartToTrip(block, &output[writepos], 4);
writepos += 3;
}
readpos++;
}
// Convert any leftover characters in block
if ((readpos != 0) && (readpos%4 != 0))
{
// fill block with pad (required for QuartToTrip)
memset(&block[readpos%4], encoding[2], (unsigned int)4-(readpos%4));
QuartToTrip(block, &output[writepos], readpos%4);
// output bytes depend on the number of non-pad input bytes
if (readpos%4 == 3)
writepos += 2;
else
writepos += 1;
}
if (outlen)
*outlen = writepos;
GSI_UNUSED(holdin);
}
void B64Encode(const char *input, char *output, int inlen, int encodingType)
{
const char *encoding;
char *holdout = output;
char *lastchar;
int todo = inlen;
// 10-31-2004 : Added by Saad Nader
// now supports URL safe encoding
////////////////////////////////////////////////
switch(encodingType)
{
case 1:
encoding = alternateEncoding;
break;
case 2:
encoding = urlSafeEncodeing;
break;
default: encoding = defaultEncoding;
}
//assume interval of 3
while (todo > 0)
{
TripToQuart(input, output, min(todo, 3));
output += 4;
input += 3;
todo -= 3;
}
lastchar = output;
if (inlen % 3 == 1)
lastchar -= 2;
else if (inlen % 3 == 2)
lastchar -= 1;
*output = 0; //null terminate!
while (output > holdout)
{
output--;
if (output >= lastchar) //pad the end
*output = encoding[2];
else if (*output <= 25)
*output = (char)(*output + 65);
else if (*output <= 51)
*output = (char)(*output + 71);
else if (*output <= 61)
*output = (char)(*output + 48 - 52);
else if (*output == 62)
*output = encoding[0];
else if (*output == 63)
*output = encoding[1];
}
}
int B64DecodeLen(const char *input, int encodingType)
{
const char *encoding;
const char *holdin = input;
switch(encodingType)
{
case 1:
encoding = alternateEncoding;
break;
case 2:
encoding = urlSafeEncodeing;
break;
default: encoding = defaultEncoding;
}
while (*input)
{
if (*input == encoding[2])
return (input - holdin) / 4 * 3 + (input - holdin - 1) % 4;
input++;
}
return (input - holdin) / 4 * 3;
}
void B64InitEncodeStream(B64StreamData *data, const char *input, int len, int encodingType)
{
data->input = input;
data->len = len;
data->encodingType = encodingType;
}
gsi_bool B64EncodeStream(B64StreamData *data, char output[4])
{
const char *encoding;
char *c;
int i;
if(data->len <= 0)
return gsi_false;
// 10-31-2004 : Added by Saad Nader
// now supports URL safe encoding
////////////////////////////////////////////////
switch(data->encodingType)
{
case 1:
encoding = alternateEncoding;
break;
case 2:
encoding = urlSafeEncodeing;
break;
default: encoding = defaultEncoding;
}
TripToQuart(data->input, output, min(data->len, 3));
data->input += 3;
data->len -= 3;
for(i = 0 ; i < 4 ; i++)
{
c = &output[i];
if (*c <= 25)
*c = (char)(*c + 65);
else if (*c <= 51)
*c = (char)(*c + 71);
else if (*c <= 61)
*c = (char)(*c + 48 - 52);
else if (*c == 62)
*c = encoding[0];
else if (*c == 63)
*c = encoding[1];
}
if(data->len < 0)
{
output[3] = encoding[2];
if(data->len == -2)
output[2] = encoding[2];
}
return gsi_true;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void gsiPadRight(char *cArray, char padChar, int cLength);
char * gsiXxteaAlg(const char *sIn, int nIn, char key[XXTEA_KEY_SIZE], int bEnc, int *nOut);
void gsiPadRight(char *cArray, char padChar, int cLength)
{
int diff;
int length = (int)strlen(cArray);
diff = cLength - length;
memset(&cArray[length], padChar, (size_t)diff);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// The heart of the XXTEA encryption/decryption algorithm.
//
// sIn: Input stream.
// nIn: Input length (bytes).
// key: Key (only first 128 bits are significant).
// bEnc: Encrypt (else decrypt)?
char * gsiXxteaAlg(const char *sIn, int nIn, char key[XXTEA_KEY_SIZE], int bEnc, int *nOut)
{
int i, p, n1;
unsigned int *k, *v, z, y;
char *oStr = NULL, *pStr = NULL;
char *sIn2 = NULL;
/////////////////////////////////
// ERROR CHECK!
if (!sIn || !key[0] || nIn == 0)
return NULL;
// Convert stream length to a round number of 32-bit words
// Convert byte count to 32-bit word count
if (nIn % 4 == 0) // Fix for null terminated strings divisible by 4
nIn = (nIn/4)+1;
else
nIn = (nIn + 3)/4;
if ( nIn <= 1 ) // XXTEA requires at least 64 bits
nIn = 2;
// Load and zero-pad first 16 characters (128 bits) of key
gsiPadRight( key , '\0', XXTEA_KEY_SIZE);
k = (unsigned int *)key;
// Load and zero-pad entire input stream as 32-bit words
sIn2 = (char *)gsimalloc((size_t)(4 * nIn));
strcpy(sIn2, sIn);
gsiPadRight( sIn2, '\0', 4*nIn);
v = (unsigned int *)sIn2;
// Prepare to encrypt or decrypt
n1 = nIn - 1;
z = v[ n1 ];
y = v[ 0 ];
i = ( int )( 6 + 52/nIn );
if (bEnc == 1) // Encrypt
{
unsigned int sum = 0;
while ( i-- != 0 )
{
int e;
sum += 0x9E3779B9;
e = ( int )( sum >> 2 );
for ( p = -1; ++p < nIn; )
{
y = v[( p < n1 ) ? p + 1 : 0 ];
z = ( v[ p ] +=
( (( z >> 5 ) ^ ( y << 2 ))
+ (( y >> 3 ) ^ ( z << 4 )))
^ ( ( sum ^ y )
+ ( k[( p ^ e ) & 3 ] ^ z )));
}
}
}
else if (bEnc == 0) // Decrypt
{
unsigned int sum = ( unsigned int ) i * 0x9E3779B9;
while ( sum != 0 )
{
int e = ( int )( sum >> 2 );
for ( p = nIn; p-- != 0; )
{
z = v[( p != 0 ) ? p - 1 : n1 ];
y = ( v[ p ] -=
( (( z >> 5 ) ^ ( y << 2 ))
+ (( y >> 3 ) ^ ( z << 4 )))
^ ( ( sum ^ y )
+ ( k[( p ^ e ) & 3 ] ^ z )));
}
sum -= 0x9E3779B9;
}
}
else return NULL;
// Convert result from 32-bit words to a byte stream
oStr = (char *)gsimalloc((size_t)(4 * nIn + 1));
pStr = oStr;
*nOut = 4 *nIn;
for ( i = -1; ++i < nIn; )
{
unsigned int q = v[ i ];
*pStr++ = (char)(q & 0xFF);
*pStr++ = (char)(( q >> 8 ) & 0xFF);
*pStr++ = (char)(( q >> 16 ) & 0xFF);
*pStr++ = (char)(( q >> 24 ) & 0xFF);
}
*pStr = '\0';
gsifree(sIn2);
return oStr;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// XXTEA Encrpyt
// params
// iStr : the input string to be encrypted
// iLength : the length of the input string
// key : the key used to encrypt
char * gsXxteaEncrypt(const char * iStr, int iLength, char key[XXTEA_KEY_SIZE], int *oLength)
{
return gsiXxteaAlg( iStr, iLength, key, 1, oLength );
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// XXTEA Decrypt
// params
// iStr : the input string to be decrypted
// iLength : the length of the input string
// key : the key used to decrypt
char * gsXxteaDecrypt(const char * iStr, int iLength, char key[XXTEA_KEY_SIZE], int *oLength)
{
return gsiXxteaAlg( iStr, iLength, key, 0, oLength);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#if defined(_DEBUG)
void gsiCheckStack(void)
{
#if defined(_NITRO)
#if 1
OS_CheckStack(OS_GetCurrentThread());
#elif 1
static gsi_bool checkFailed = gsi_false;
if(!checkFailed)
{
OSStackStatus status = OS_GetStackStatus(OS_GetCurrentThread());
if(status != 0)
{
const char * reason;
if(status == OS_STACK_OVERFLOW)
reason = "OVERFLOW";
else if(status == OS_STACK_ABOUT_TO_OVERFLOW)
reason = "ABOUT TO OVERFLOW";
else if(status == OS_STACK_UNDERFLOW)
reason = "UNDERFLOW";
else
reason = "UNKOWN REASON";
OS_TPrintf("STACK CHECK FAILED!: %s\n", reason);
checkFailed = gsi_true;
}
}
#endif
#endif // nitro
}
#endif // _DEBUG
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifdef SN_SYSTEMS
int GOAGetLastError(SOCKET s)
{
int val = 0;
int soval = sizeof(val);
if (0 != getsockopt(s,SOL_SOCKET,SO_ERROR,&val,&soval))
return 0; // getsockopt failed
else
return val;
}
#endif
#ifdef _NITRO
static const char * GOAGetUniqueID_Internal(void)
{
static char keyval[17];
u8 MAC[MAC_ALEN];
// check if we already have the Unique ID
if(keyval[0])
return keyval;
// get the MAC
IP_GetMacAddr(NULL, MAC);
// format it
sprintf(keyval, "%02X%02X%02X%02X%02X%02X0000",
MAC[0] & 0xFF,
MAC[1] & 0xFF,
MAC[2] & 0xFF,
MAC[3] & 0xFF,
MAC[4] & 0xFF,
MAC[5] & 0xFF);
return keyval;
}
#endif
#ifdef _PS2
#ifdef UNIQUEID
#if defined(EENET)
#include <net/if_dl.h>
// Removed due to updated sony libraries, Saad Nader
//#include <net/if_types.h>
#include <net/if_ether.h>
static const char * GetMAC(void)
{
static struct sceEENetEtherAddr linkAddress;
struct sceEENetIfname * interfaces;
struct sceEENetIfname * interface;
int num;
int type;
int len;
int i;
const unsigned char * MAC = NULL;
// get the local interfaces
sceEENetGetIfnames(NULL, &num);
interfaces = (struct sceEENetIfname *)gsimalloc(num * sizeof(struct sceEENetIfname));
if(!interfaces)
return NULL;
sceEENetGetIfnames(interfaces, &num);
// loop through the interfaces
for(i = 0 ; i < num ; i++)
{
// the next interface
interface = &interfaces[i];
//printf("eenet%d: %s\n", i, interface->ifn_name);
// get the type
len = sizeof(type);
if(sceEENetGetIfinfo(interface->ifn_name, sceEENET_IFINFO_IFTYPE, &type, &len) != 0)
continue;
//printf("eenet%d type: %d\n", i, type);
// check for ethernet
if(type != sceEENET_IFTYPE_ETHER)
continue;
//printf("eenet%d: ethernet\n", i);
// get the address
len = sizeof(linkAddress);
if(sceEENetGetIfinfo(interface->ifn_name, sceEENET_IFINFO_MACADDR, &linkAddress, &len) != 0)
continue;
MAC = linkAddress.ether_addr_octet;
//printf("eenet%d: MAC: %02X-%02X-%02X-%02X-%02X-%02X\n", i, MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
break;
}
// free the interfaces
gsifree(interfaces);
return MAC;
}
#elif defined(SN_SYSTEMS)
static const char * GetMAC(void)
{
static char MAC[6];
int len = sizeof(MAC);
int rcode;
// get the MAC
rcode = sndev_get_status(0, SN_DEV_STAT_MAC, MAC, &len);
if((rcode != 0) || (len != 6))
return NULL;
return MAC;
}
#elif defined(INSOCK)
static const char * GetMAC(void)
{
// Get the MAC address using the interface control
static char MAC[16];
extern sceSifMClientData gGSIInsockClientData;
extern u_int gGSIInsockSocketBuffer[NETBUFSIZE] __attribute__((aligned(64)));
int result = sceInetInterfaceControl(&gGSIInsockClientData, &gGSIInsockSocketBuffer,
1, sceInetCC_GetHWaddr, MAC, sizeof(MAC));
if (result == sceINETE_OK)
return MAC;
// error
return NULL;
}
#endif
static const char * GOAGetUniqueID_Internal(void)
{
static char keyval[17];
const char * MAC;
// check if we already have the Unique ID
if(keyval[0])
return keyval;
// get the MAC
MAC = GetMAC();
if(!MAC)
{
// error getting the MAC
static char errorMAC[6] = { 1, 2, 3, 4, 5, 6 };
MAC = errorMAC;
}
// format it
sprintf(keyval, "%02X%02X%02X%02X%02X%02X0000",
MAC[0] & 0xFF,
MAC[1] & 0xFF,
MAC[2] & 0xFF,
MAC[3] & 0xFF,
MAC[4] & 0xFF,
MAC[5] & 0xFF);
return keyval;
}
#endif // UNIQUEID
#endif // _PS2
#if ((defined(_WIN32) && !defined(_XBOX)) || defined(_UNIX))
static void GenerateID(char *keyval)
{
int i;
const char crypttab[63] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
#ifdef _WIN32
LARGE_INTEGER l1;
UINT seed;
if (QueryPerformanceCounter(&l1))
seed = (l1.LowPart ^ l1.HighPart);
else
seed = 0;
Util_RandSeed(seed ^ GetTickCount() ^ (unsigned long)time(NULL) ^ clock());
#else
Util_RandSeed(time(NULL) ^ clock());
#endif
for (i = 0; i < 19; i++)
if (i == 4 || i == 9 || i == 14)
keyval[i] = '-';
else
keyval[i] = crypttab[Util_RandInt(0, 62)];
keyval[19] = 0;
}
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#ifdef _WIN32
#define REG_KEY "Software\\GameSpy\\GameSpy 3D\\Registration"
#endif
const char * GOAGetUniqueID_Internal(void)
{
static char keyval[PATH_MAX] = "";
unsigned int ret;
#ifdef _WIN32
int docreate;
HKEY thekey;
DWORD thetype = REG_SZ;
DWORD len = MAX_PATH;
DWORD disp;
if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_KEY, 0, KEY_ALL_ACCESS, &thekey) != ERROR_SUCCESS)
docreate = 1;
else
docreate = 0;
ret = RegQueryValueExA(thekey, (LPCSTR)"Crypt", 0, &thetype, (LPBYTE)keyval, &len);
#else
FILE *f;
f = fopen("id.bin","r");
if (!f)
ret = 0;
else
{
ret = fread(keyval,1,19,f);
keyval[ret] = 0;
fclose(f);
}
#endif
if (ret != 0 || strlen(keyval) != 19)//need to generate a new key
{
GenerateID(keyval);
#ifdef _WIN32
if (docreate)
{
ret = RegCreateKeyExA(HKEY_CURRENT_USER, REG_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &thekey, &disp);
}
RegSetValueExA(thekey, (LPCSTR)"Crypt", 0, REG_SZ, (const LPBYTE)keyval, strlen(keyval)+1);
#else
f = fopen("id.bin","w");
if (f)
{
fwrite(keyval,1,19,f);
fclose(f);
} else
keyval[0] = 0; //don't generate one each time!!
#endif
}
#ifdef _WIN32
RegCloseKey(thekey);
#endif
// Strip out the -'s.
/////////////////////
memmove(keyval + 4, keyval + 5, 4);
memmove(keyval + 8, keyval + 10, 4);
memmove(keyval + 12, keyval + 15, 4);
keyval[16] = '\0';
return keyval;
}
#endif
#ifdef _PSP
// Included here so that the implementation can appear in gsPlatformPSP.c
const char * GOAGetUniqueID_Internal(void);
#endif
#if (!defined(_PS2) && !defined(_PS3) && !defined(_XBOX) && !defined(_PSP)) || defined(UNIQUEID)
GetUniqueIDFunction GOAGetUniqueID = GOAGetUniqueID_Internal;
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
}
#endif