/*
 * Xailer source code:
 *
 * Util.c
 * Funciones utiles en C
 *
 * Copyright 2003, 2007 Jose F. Gimenez
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#ifndef _LINUX_
   #define _WIN32_WINNT 0x0600
   #include <windows.h>
   #include <io.h>
   #include <sys\stat.h>
#else
   #define isdigit( c ) ((c>='0') && (c<='9'))
   #define itoa( v, s, r ) sprintf(s,"%d",v)
#endif
#include <fcntl.h>
#include <hbapifs.h>
#include <xailer.h>
#include <hbset.h>
#include <hbapierr.h>


//--------------------------------------------------------------------------

XA_EXPORT void LogFile( const char *cText, ... ) // LogFile( <cText>, [<...>] ) --> void
{
   const unsigned char szEOL[ 2 ] = { HB_CHAR_CR, HB_CHAR_LF };
   int h;
   va_list ap;

   if ( cText )
      {
      h = hb_fsOpen( "Log.txt", 2 );
      if ( h <= 0 )
         h = hb_fsCreate( "Log.txt", 0 );
      if ( h > 0 )
         {
         hb_fsSeek( h, 0, 2 );
         va_start( ap, cText );
         do {
            hb_fsWriteLarge( h, cText, strlen( cText ) );
            cText = va_arg( ap, char * );
            }
         while ( cText );
         va_end( ap );
         hb_fsWrite( h, szEOL, 2 );
         hb_fsClose( h );
         }
      }
}

//--------------------------------------------------------------------------

XA_FUNC( LOGFILE )   // LogFile( <cText> ) --> n/a
{
   LogFile( hb_parc( 1 ), NULL );
}

//--------------------------------------------------------------------------

XA_EXPORT char * Dec( int nValue ) // Dec( <nValue> ) --> char *
{
   static char cDec[4][16];
   static int n = 0;

   n++; if ( n > 3 ) n = 0;
   itoa( nValue, cDec[ n ], 10 );

   return( cDec[ n ] );
}

//--------------------------------------------------------------------------

XA_EXPORT char * Hex( int n ) // Hex( <nValue> ) --> char *
{
   static char cHex[9];

   itoa( n, cHex, 16 );

   return( cHex );
}

//--------------------------------------------------------------------------

XA_FUNC( HEX ) // Hex( <nValue> ) --> cHex
{
   hb_retc( Hex( hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_EXPORT char * X2Hex( HB_LONGLONG n, int nLen ) // X2Hex( <llNum>, <nLen> ) --> char *
{
   static char cHex[17];
   char *p;

   nLen <<= 1;
   p = &cHex[ nLen ];
   *p-- = 0;
   while( nLen-- )
      {
      *p = n & 0x0f;
      *p += *p <= 9 ? '0' : 'A' - 10;
      p--;
      n = ( (HB_ULONGLONG) n ) >> 4;
      }

   return( cHex );
}

//--------------------------------------------------------------------------

XA_EXPORT char * MemToHex( const char * cString, int nLen ) // MemToHex( <cString>, <nLen> ) --> char *
{
   char *cHex, *p, c;

   if( nLen == 0 )
      nLen = strlen( cString );

   cHex = hb_xgrab( nLen * 2 + nLen / 4 + 4 );
   p = cHex;
   while( nLen-- )
      {
      c = ( (unsigned char) ( *cString & 0xf0 ) ) >> 4;
      *p++ = c + ( c <= 9 ? '0' : 'A' - 10 );
      c = *cString++ & 0x0f;
      *p++ = c + ( c <= 9 ? '0' : 'A' - 10 );
      if( ( (HB_SIZE) cString & 3 ) == 0 )
         *p++ = '·';
      }
   *p = 0;

   return( cHex );
}

//--------------------------------------------------------------------------

XA_EXPORT char * StringToHex( const char * cString, int nLen ) // StringToHex( <cString>, <nLen> ) --> char *
{
   char *cHex, *p, c;

   if( cString && ( nLen == 0 ) )
      nLen = strlen( cString );

   cHex = hb_xgrab( nLen * 2 + 1 );
   p = cHex;
   while( nLen-- )
      {
      c = ( (unsigned char) ( *cString & 0xf0 ) ) >> 4;
      *p++ = c + ( c <= 9 ? '0' : 'A' - 10 );
      c = *cString++ & 0x0f;
      *p++ = c + ( c <= 9 ? '0' : 'A' - 10 );
      }
   *p = 0;

   return( cHex );
}

//--------------------------------------------------------------------------

XA_EXPORT char * HexToString( const char * cHex ) // HexToString( <cHex> ) --> char *
{
   char * cString, *p, c;
   int nLen = cHex ? strlen( cHex ) / 2 : 0;

   cString = hb_xgrab( nLen + 1 );
   p = cString;
   while( nLen-- )
      {
      c = *cHex++;
      c -= c <= '9' ? '0' : c <= 'F' ? 'A' - 10 : 'a' - 10;
      *p = ( (unsigned char) c ) << 4;
      c = *cHex++;
      c -= c <= '9' ? '0' : c <= 'F' ? 'A' - 10 : 'a' - 10;
      *p++ += c;
      }
   *p = 0;

   return( cString );
}

//--------------------------------------------------------------------------

XA_FUNC( MEMTOHEX )  // MemToHex( <cString>, [<nLen>] ) --> cHex
{
   int nLen = hb_parnl( 2 );
   LPSTR cHex = MemToHex( hb_parc( 1 ), ( nLen == 0 ? (int) hb_parclen( 1 ) : nLen ) );

   hb_retc_buffer( cHex );
}

//--------------------------------------------------------------------------

XA_FUNC( STRINGTOHEX )  // StringToHex( <cString>, [<nLen>] ) --> cHex
{
   int nLen = hb_parnl( 2 );
   LPSTR cHex = StringToHex( hb_parc( 1 ), ( nLen == 0 ? (int) hb_parclen( 1 ) : nLen ) );

   hb_retc_buffer( cHex );
}

//--------------------------------------------------------------------------

XA_FUNC( HEXTOSTRING )  // HexToString( <cHex> ) --> cString
{
   LPSTR cString = HexToString( hb_parc( 1 ) );

   hb_retclen_buffer( cString, hb_parclen( 1 ) / 2 );
}

//--------------------------------------------------------------------------

XA_FUNC( B2HEX )  // B2Hex( <nByte> ) --> cHex
{
   hb_retc( B2Hex( (BYTE) hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( W2HEX )  // W2Hex( <nWord> ) --> cHex
{
   hb_retc( W2Hex( (WORD) hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( L2HEX )  // L2Hex( <nLong> ) --> cHex
{
   hb_retc( L2Hex( hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( LL2HEX ) // LL2Hex( <nLongLong> ) --> cHex
{
   hb_retc( LL2Hex( hb_parnll( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_EXPORT LONG Hex2X( const char * hex, int nLen ) // Hex2X( <cHex>, <nLen> ) --> LONG
{
   LONG l = 0;
   char c;

   if( hex )
      {
      while( nLen-- )
         {
         c = *hex++;
         c -= c <= '9' ? '0' : c <= 'F' ? 'A' - 10 : 'a' - 10;
         l <<= 4;
         l += c;
         }
      }

   return( l );
}

//--------------------------------------------------------------------------

XA_EXPORT unsigned char Hex2B( const char * hex ) // Hex2B( <cHex> ) --> unsigned char
{
   return( Hex2X( hex, 2 ) );
}

//--------------------------------------------------------------------------

XA_EXPORT unsigned short Hex2W( const char * hex ) // Hex2W( <cHex> ) --> unsigned short
{
   return( Hex2X( hex, 4 ) );
}

//--------------------------------------------------------------------------

XA_EXPORT unsigned int Hex2L( const char * hex ) // Hex2L( <cHex> ) --> unsigned int
{
   return( Hex2X( hex, 8 ) );
}

//--------------------------------------------------------------------------

XA_EXPORT HB_LONGLONG Hex2LL( const char * hex ) // Hex2LL( <cHex> ) --> HB_LONGLONG
{
   HB_LONGLONG ll = 0;
   char c;
   int nLen = 16;

   if( hex )
      {
      while( nLen-- )
         {
         c = *hex++;
         c -= c <= '9' ? '0' : c <= 'F' ? 'A' - 10 : 'a' - 10;
         ll <<= 4;
         ll += c;
         }
      }

   return( ll );
}

//--------------------------------------------------------------------------

XA_FUNC( HEXTODEC )  // HexToDec( <cHex> ) --> nResult
{
   const char * h = hb_parc( 1 );
   HB_LONGLONG d = 0;

   if( h )
      {
      while ( *h )
         {
         d = d << 4;
         if ( *h >= '0' && *h <= '9' )
            d += *h - '0';
         else if ( *h >= 'A' && *h <= 'F' )
            d += (*h) - 55;
         else if ( *h >= 'a' && *h <= 'f' )
            d += (*h) - 87;
         else
            d = 0;
         h++;
         }
      }

   hb_retnll( d );
}

//--------------------------------------------------------------------------

#ifdef __GNUC__

char *stpcpy( char * dest, const char * src )
{
   while( ( *dest = *src++ ) != 0 )
      dest++;

   return dest;
}

#endif

//--------------------------------------------------------------------------

XA_EXPORT void OutDebug( const char *cText, ... ) // OutDebug( <cText>, [<...>] ) --> void
{
   va_list ap;
   char *cString = hb_xgrab( 65536 ), *p = cString;

   if ( cText )
      {
      va_start( ap, cText );
      while ( cText && ( p - cString < 65534 ) )
         {
         while( *cText && ( p - cString < 65534 ) )
            *p++ = *cText++;
         *p++ = ' ';
         *p = 0;
         cText = va_arg( ap, char * );
         }
      va_end( ap );
#ifdef _WINDOWS_
      OutputDebugString( cString );
#else
      // Enviar a STDERR
      hb_fsWrite( 2, cString, strlen( cString ) );
#endif
      }

   hb_xfree( cString );
}

//--------------------------------------------------------------------------

XA_FUNC( OUTDEBUG )  // OutDebug( <cString> ) --> n/a
{
#ifdef _WINDOWS_
   OutputDebugString( hb_parc( 1 ) );
#endif
}

//--------------------------------------------------------------------------

/* NOTA: La memoria reservada por AnsiToWide, WideToAnsi y UTF8ToAnsi debe
         ser liberada por la funcion que efectua la llamada, p.e.:

         ( TESTFUNC )
         {
            LPSTR lpTitle = AnsiToWide( hb_parc( 1 ) );

            ...
            hb_xfree( lpTitle );
         }
*/

#ifdef _WINDOWS_

XA_EXPORT LPWSTR AnsiToWide( LPCSTR cAnsi ) // AnsiToWide( <lpString> ) --> cWideString
{
   LPWSTR cString = NULL;
   int nLen;

   nLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, cAnsi, -1, 0, 0 );
   if( nLen )
      {
      cString = hb_xgrab( nLen * 2 );
      MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, cAnsi, -1, cString, nLen );
      }

   return( cString );
}

//--------------------------------------------------------------------------

XA_EXPORT LPSTR WideToAnsi( LPCWSTR cWide ) // WideToAnsi( <lpWideString> ) --> lpText
{
   LPSTR cString = NULL;
   int nLen;

   nLen = WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, cWide, -1, 0, 0, NULL, NULL );
   if( nLen )
      {
      cString = hb_xgrab( nLen );
      WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, cWide, -1, cString, nLen, NULL, NULL );
      }

   return( cString );
}

#endif

//--------------------------------------------------------------------------

XA_EXPORT LPSTR UTF8ToAnsi( LPCSTR cUTF8 ) // UTF8ToAnsi( <lpUTF8String> ) --> lpString
{
   int nLen;
   LPSTR cString = NULL;
#ifdef _WINDOWS_
   LPWSTR cWide;

   nLen = MultiByteToWideChar( CP_UTF8, 0, cUTF8, -1, 0, 0 );
   if( nLen )
      {
      cWide = hb_xgrab( nLen * 2 );
      MultiByteToWideChar( CP_UTF8, 0, cUTF8, -1, cWide, nLen );
      nLen = WideCharToMultiByte( CP_ACP, 0, cWide, -1, 0, 0, NULL, NULL );
      if( nLen )
         {
         cString = hb_xgrab( nLen );
         WideCharToMultiByte( CP_ACP, 0, cWide, -1, cString, nLen, NULL, NULL );
         }
      hb_xfree( cWide );
      }
#else
   PHB_CODEPAGE cdp = hb_vmCDP();
   int nLenSrc = hb_cdpUTF8StringLength( cUTF8, -1 );

   nLen = hb_cdpUTF8AsStrLen( cdp, cUTF8, nLenSrc, 0 );
   cString = hb_xgrab( nLen + 1 );
   hb_cdpUTF8ToStr( cdp, cUTF8, nLenSrc, cString, nLen + 1 );
#endif

   return( cString );
}

//--------------------------------------------------------------------------

XA_EXPORT LPSTR AnsiToUTF8( LPCSTR cAnsi ) // AnsiToUTF8( <lpText> ) --> lpUTF8String
{
   int nLen;
   LPSTR cString = NULL;
#ifdef _WINDOWS_
   LPWSTR cWide;

   cWide = AnsiToWide( cAnsi );
   if( cWide )
      {
      nLen = WideCharToMultiByte( CP_UTF8, 0, cWide, -1, 0, 0, NULL, NULL );
      if( nLen )
         {
         cString = hb_xgrab( nLen );
         WideCharToMultiByte( CP_UTF8, 0, cWide, -1, cString, nLen, NULL, NULL );
         }

      hb_xfree( cWide );
      }
#else
   PHB_CODEPAGE cdp = hb_vmCDP();
   int nLenSrc = strlen( cAnsi );

   nLen = hb_cdpStrAsUTF8Len( cdp, cAnsi, nLenSrc, 0 );
   cString = hb_xgrab( nLen + 1 );
   hb_cdpStrToUTF8( cdp, cAnsi, nLenSrc, cString, nLen + 1 );
#endif

   return( cString );
}

//--------------------------------------------------------------------------

XA_FUNC( ANSITOWIDE )  // AnsiToWide( <cAnsiString> ) --> cWideString
{
#ifdef _WINDOWS_
   int nLen;
   LPCSTR cAnsiStr = hb_parc( 1 );
   LPSTR cOut;

   nLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, cAnsiStr, -1, 0, 0 );
   if( nLen )
      {
      cOut = ( char * ) hb_xgrab( nLen * 2 + 1 );  // NOTA: Harbour añade un chr(0) al final del buffer
      MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, cAnsiStr, -1,
                           ( LPWSTR ) cOut, nLen );
      hb_retclen_buffer( cOut, nLen * 2 );
      }
   else
#endif
      hb_retc( "" );
}

//--------------------------------------------------------------------------

XA_FUNC( WIDETOANSI )  // WideToAnsi( <cWideString> ) --> cAnsiString
{
#ifdef _WINDOWS_
   int nLen;
   LPCWSTR cWideStr = (LPCWSTR) hb_parc( 1 );
   LPSTR cOut;

   nLen = WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, cWideStr, -1,
                               0, 0, NULL, NULL );
   if( nLen )
      {
      cOut = ( char * ) hb_xgrab( nLen );
      WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, cWideStr, -1,
                           cOut, nLen, NULL, NULL );
      hb_retc_buffer( cOut );
      }
   else
#endif
      hb_retc( "" );
}


//--------------------------------------------------------------------------

XA_FUNC( ANSITOUTF8 )  // AnsiToUTF8( <cString> ) --> cString
{
   hb_retc_buffer( AnsiToUTF8( hb_parc( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( UTF8TOANSI )  // UTF8TOAnsi( <cString> ) --> cString
{
   hb_retc_buffer( UTF8ToAnsi( hb_parc( 1 ) ) );
}

//--------------------------------------------------------------------------

#ifdef _WINDOWS_

XA_FUNC( GETWINDOWSDIRECTORY )   // GetWindowsDirectory() --> cDirectory
{
   char szDir[ MAX_PATH ];

   GetWindowsDirectory( szDir, MAX_PATH );

   hb_retc( szDir );
}

//--------------------------------------------------------------------------

XA_FUNC( GETSYSTEMDIRECTORY )    // GetSystemDirectory() --> cDirectory
{
   char szDir[ MAX_PATH ];

   GetSystemDirectory( szDir, MAX_PATH );

   hb_retc( szDir );
}

//--------------------------------------------------------------------------

XA_FUNC( GETTEMPDIRECTORY )   // GetTempDirectory() --> cDirectory
{
   char szDir[ MAX_PATH ];

   GetTempPath( MAX_PATH, szDir );

   hb_retc( szDir );
}

//--------------------------------------------------------------------------

XA_FUNC( GETTEMPDIRECTORYLONG )  // GetTempDirectoryLong() --> cDirectory
{
   char szDir[ MAX_PATH ];
   char szPath[ MAX_PATH ];
   DWORD dwLen = 0;

   if( GetTempPath( MAX_PATH, szDir ) )
      dwLen = GetLongPathName( szDir, szPath, MAX_PATH );

   if( dwLen )
      hb_retclen( szPath, dwLen );
   else
      hb_retc( "" );
}

//--------------------------------------------------------------------------

XA_FUNC( GETLONGPATHNAME ) // GetLongPathName( <cPath> ) --> cLongPath
{
   char szPath[ MAX_PATH ];
   DWORD dwLen = 0;

   if( HB_ISCHAR( 1 ) )
      dwLen = GetLongPathName( hb_parc( 1 ), szPath, MAX_PATH );

   if( dwLen )
      hb_retclen( szPath, dwLen );
   else
      hb_retc( "" );
}

//--------------------------------------------------------------------------

XA_FUNC( GETSHORTPATHNAME )   // GetShortPathName( <cPath> ) --> cShortPath
{
   char szPath[ MAX_PATH ];
   DWORD dwLen = 0;

   if( HB_ISCHAR( 1 ) )
      dwLen = GetShortPathName( hb_parc( 1 ), szPath, MAX_PATH );

   if( dwLen )
      hb_retclen( szPath, dwLen );
   else
      hb_retc( "" );
}

//--------------------------------------------------------------------------

XA_FUNC( GETCURRENTDIRECTORY )   // GetCurrentDirectory() --> cDirectory
{
   char szDir[ MAX_PATH ];

   GetCurrentDirectory( MAX_PATH, szDir );

   hb_retc( szDir );
}

//--------------------------------------------------------------------------

XA_FUNC( GETFILEATTRIBUTES )  // GetFileAttributes( <cFilename> ) --> nAttributes
{
   if( HB_ISCHAR( 1 ) )
      hb_retni( GetFileAttributes( hb_parc( 1 ) ) );
   else
      hb_retni( 0 );
}

//--------------------------------------------------------------------------

XA_FUNC( SETFILEATTRIBUTES )  // SetFileAttributes( <cFilename>, <nAttributes> ) --> lSuccess
{
   if( HB_ISCHAR( 1 ) && HB_ISNUM( 2 ) )
      hb_retl( SetFileAttributes( hb_parc( 1 ), hb_parni( 2 ) ) );
   else
      hb_retl( FALSE );
}

//--------------------------------------------------------------------------

HB_FUNC( FILEDATETIME ) // FileDateTime( <cFilename> ) --> <dDateTime>
{
   WIN32_FIND_DATA fd;
   HANDLE hSearch;
   SYSTEMTIME st;

   hb_retds( "" );
   hSearch = FindFirstFile( hb_parc( 1 ), &fd );
   if ( hSearch != INVALID_HANDLE_VALUE )
      {
      FindClose( hSearch );
      FileTimeToSystemTime( &fd.ftLastWriteTime, &st );
      hb_rettdt( hb_dateEncode( st.wYear, st.wMonth, st.wDay ),
                 hb_timeEncode( st.wHour, st.wMinute, st.wSecond, st.wMilliseconds ) );
   }
}

//--------------------------------------------------------------------------

HB_FUNC( FILEDATETIMELOCAL ) // FileDateTimeLocal( <cFilename> ) --> <dDateTimeLocal>
{
   WIN32_FIND_DATA fd;
   HANDLE hSearch;
   SYSTEMTIME st;
   FILETIME ft;

   hb_retds( "" );
   hSearch = FindFirstFile( hb_parc( 1 ), &fd );
   if ( hSearch != INVALID_HANDLE_VALUE )
      {
      FindClose( hSearch );
      FileTimeToLocalFileTime( &fd.ftLastWriteTime, &ft );
      FileTimeToSystemTime( &ft, &st );
      hb_rettdt( hb_dateEncode( st.wYear, st.wMonth, st.wDay ),
                 hb_timeEncode( st.wHour, st.wMinute, st.wSecond, st.wMilliseconds ) );
   }
}

//--------------------------------------------------------------------------

HB_FUNC( SETFILEDATETIME ) // SetFileDateTime( <cFilename>, <dNewDateTime> ) --> <lSuccess>
{
   SYSTEMTIME st;
   FILETIME ft, ftutc;
   long lJulian, lMillisec;
   int iYear, iMonth, iDay, iHour, iMinutes, iSeconds, iMSec;

   hb_retl( FALSE );
   if ( hb_partdt( &lJulian, &lMillisec, 2 ) )
      {
      hb_dateDecode( lJulian, &iYear, &iMonth, &iDay );
      hb_timeDecode( lMillisec, &iHour, &iMinutes, &iSeconds, &iMSec  );

      st.wSecond = iSeconds;
      st.wMinute = iMinutes;
      st.wHour = iHour;
      st.wDay = iDay;
      st.wMonth = iMonth;
      st.wYear = iYear;
      st.wMilliseconds = iMSec;
      if( SystemTimeToFileTime( &st, &ft ) && LocalFileTimeToFileTime( &ft, &ftutc ) )
         {
         HB_FHANDLE hFile = hb_fsOpen( hb_parc( 1 ), FO_WRITE );
         if( hFile )
            {
            hb_retl( SetFileTime( (HANDLE) hb_fsGetOsHandle( hFile ), &ftutc, &ftutc, &ftutc ) );
            hb_fsClose( hFile );
            }
         }
      }
}

//------------------------------------------------------------------------------

#if defined(__BORLANDC__)
   BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION zi, LPSYSTEMTIME lt, LPSYSTEMTIME st)
   {
      typedef BOOL ( WINAPI * P_TZSPECIFICLOCALTIMETOSYSTEMTIME )( LPTIME_ZONE_INFORMATION, LPSYSTEMTIME, LPSYSTEMTIME );
      static BOOL fInit = TRUE;
      static P_TZSPECIFICLOCALTIMETOSYSTEMTIME s_pTzSpecificLocalTimeToSystemTime = NULL;

      if( fInit )
      {
         HMODULE hModule = GetModuleHandle( "kernel32" );
         if( hModule )
            s_pTzSpecificLocalTimeToSystemTime = ( P_TZSPECIFICLOCALTIMETOSYSTEMTIME )
               GetProcAddress( hModule, "TzSpecificLocalTimeToSystemTime" );
         fInit = FALSE;
      }
      if( s_pTzSpecificLocalTimeToSystemTime )
         return s_pTzSpecificLocalTimeToSystemTime( zi, lt, st );
      else
         return FALSE;
   }
#elif ( __GNUC__ < 7 )
   WINBASEAPI BOOL WINAPI TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION,LPSYSTEMTIME,LPSYSTEMTIME);
#endif

//------------------------------------------------------------------------------

#define DATE_START   210866803200 // 1970-01-01 00:00:00

HB_FUNC( XA_UNIXTIMESTAMP2DATETIME ) // XA_UnixTimeStamp2DateTime( <nTimeStamp> )  --> <dDateTime>
{
   PHB_ITEM pNum = hb_param( 1, HB_IT_NUMERIC );

   hb_rettd( ( hb_itemGetND( pNum ) + DATE_START ) / HB_SECONDS_PER_DAY );
}

//------------------------------------------------------------------------------

HB_FUNC( XA_LOCAL2UTC ) // XA_Local2Utc( <dtLocalDateTime> )  --> <dtUtcDateTime>
{
   SYSTEMTIME st, st2;
   long lJulian, lMillisec;
   int iYear, iMonth, iDay, iHour, iMinutes, iSeconds, iMSec;

   hb_ret();
   if ( hb_partdt( &lJulian, &lMillisec, 1 ) )
      {
      hb_dateDecode( lJulian, &iYear, &iMonth, &iDay );
      hb_timeDecode( lMillisec, &iHour, &iMinutes, &iSeconds, &iMSec  );

      st.wSecond = iSeconds;
      st.wMinute = iMinutes;
      st.wHour = iHour;
      st.wDay = iDay;
      st.wMonth = iMonth;
      st.wYear = iYear;
      st.wMilliseconds = iMSec;
      if( TzSpecificLocalTimeToSystemTime( NULL, &st, &st2 ) )
            hb_rettdt( hb_dateEncode( st2.wYear, st2.wMonth, st2.wDay ),
                       hb_timeEncode( st2.wHour, st2.wMinute, st2.wSecond, st2.wMilliseconds ) );
      }
}

//------------------------------------------------------------------------------

HB_FUNC( XA_UTC2LOCAL ) // XA_Utc2Local( <dtUtcDateTime> )  --> <dtLocalDateTime>
{
   SYSTEMTIME st, st2;
   long lJulian, lMillisec;
   int iYear, iMonth, iDay, iHour, iMinutes, iSeconds, iMSec;

   hb_ret();
   if ( hb_partdt( &lJulian, &lMillisec, 1 ) )
      {
      hb_dateDecode( lJulian, &iYear, &iMonth, &iDay );
      hb_timeDecode( lMillisec, &iHour, &iMinutes, &iSeconds, &iMSec  );

      st.wSecond = iSeconds;
      st.wMinute = iMinutes;
      st.wHour = iHour;
      st.wDay = iDay;
      st.wMonth = iMonth;
      st.wYear = iYear;
      st.wMilliseconds = iMSec;
      if( SystemTimeToTzSpecificLocalTime( NULL, &st, &st2 ) )
            hb_rettdt( hb_dateEncode( st2.wYear, st2.wMonth, st2.wDay ),
                       hb_timeEncode( st2.wHour, st2.wMinute, st2.wSecond, st2.wMilliseconds ) );
      }
}

//------------------------------------------------------------------------------

HB_FUNC( XA_DATETIMEZ2LOCAL ) // XA_DateTimeZ2Local( <cDateTimeZ> ) --> <dtLocalDateTime>
// <cDateTimeZ> "0000-00-00T00:00:00.000Z"
{
   char *pDate = (LPSTR) hb_parc( 1 );
   SYSTEMTIME t1, t2;

   t1.wYear  = ( *pDate++ - '0' ) * 1000;
   t1.wYear += ( *pDate++ - '0' ) * 100;
   t1.wYear += ( *pDate++ - '0' ) * 10;
   t1.wYear += ( *pDate++ - '0' );
   pDate++;
   t1.wMonth  = ( *pDate++ - '0' ) * 10;
   t1.wMonth += ( *pDate++ - '0' );
   pDate++;
   t1.wDay  = ( *pDate++ - '0' ) * 10;
   t1.wDay += ( *pDate++ - '0' );
   pDate++;
   t1.wHour  = ( *pDate++ - '0' ) * 10;
   t1.wHour += ( *pDate++ - '0' );
   pDate++;
   t1.wMinute  = ( *pDate++ - '0' ) * 10;
   t1.wMinute += ( *pDate++ - '0' );
   pDate++;
   t1.wSecond  = ( *pDate++ - '0' ) * 10;
   t1.wSecond += ( *pDate++ - '0' );
   pDate++;
   t1.wMilliseconds = 0;
   while( HB_ISDIGIT( *pDate ) )
      t1.wMilliseconds = t1.wMilliseconds * 10 + ( *pDate++ - '0' );
   SystemTimeToTzSpecificLocalTime( NULL, &t1, &t2 );
   hb_rettdt( hb_dateEncode( t2.wYear, t2.wMonth, t2.wDay ),
              hb_timeEncode( t2.wHour, t2.wMinute, t2.wSecond, t2.wMilliseconds ) );
}

#endif

//--------------------------------------------------------------------------

#ifdef _WINDOWS_
XA_FUNC( ISCHARALPHANUMERIC ) // IsCharAlphaNumeric( <cChar> ) --> lResult
{
   hb_retl( IsCharAlphaNumeric( hb_parni( 1 ) ) );
}
#endif

//--------------------------------------------------------------------------

XA_FUNC( ISSTRINGNUMERIC ) // IsStringNumeric( <cString> ) --> lResult
{
   LPCSTR pStr = hb_parc( 1 );

   while( *pStr )
   {
      //if( !isdigit( *pStr ) && *pStr != '.' )
      if( !isdigit( *pStr ) && *pStr != '.' && *pStr != '-' && *pStr != '+' )
      {
         hb_retl( FALSE );
         return;
      }
      pStr++;
   }

   hb_retl( TRUE );
}

//--------------------------------------------------------------------------

#ifdef _WINDOWS_

XA_FUNC( GETVERSIONEX )    // GetVersionEx() --> aVersionEx
{
   OSVERSIONINFO vi;

   memset( &vi, 0, sizeof(OSVERSIONINFO) );
   vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

   GetVersionEx( &vi );

   hb_reta( 4 );
   // { nMajor + nMinor, nBuild, nPlatformID, cVersion }
   hb_storvnd( vi.dwMajorVersion + vi.dwMinorVersion / 100.0, -1, 1 );
   hb_storvnl( vi.dwBuildNumber & 0xffff, -1, 2 );
   hb_storvnl( vi.dwPlatformId , -1, 3 );
   hb_storvc( vi.szCSDVersion , -1, 4 );
}

//--------------------------------------------------------------------------

XA_EXPORT DWORD XA_GetWinVer( void ) // XA_GetWinVer() --> DWORD
{
   static DWORD nWinVer = 0;

   if( nWinVer == 0 )
   {
      DWORD dwVersion = GetVersion();

      nWinVer = ( LOBYTE( LOWORD( dwVersion ) ) << 8 ) | HIBYTE( LOWORD( dwVersion ) );
   }

   return nWinVer;
}

//--------------------------------------------------------------------------

XA_EXPORT DWORD GetWinPlatform( void ) // GetWinPlatform() --> DWORD
{
   OSVERSIONINFO vi;

   memset( &vi, 0, sizeof( OSVERSIONINFO ) );

   vi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
   GetVersionEx( &vi );

   return vi.dwPlatformId;
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_ExistDir( const char * cDirName ) // XA_ExistDir( <cDirectory> ) --> BOOL
{
   DWORD nAttr = GetFileAttributes( cDirName );

   return ( ( nAttr != 0xFFFFFFFF ) && ( nAttr & FILE_ATTRIBUTE_DIRECTORY ) );
}

//--------------------------------------------------------------------------

XA_FUNC( EXISTDIR )  // ExistDir( <cDirectory> ) --> lResult
{
   hb_retl( XA_ExistDir( hb_parc( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsWin9X( void ) // XA_IsWin9X() --> BOOL
{
   return GetWinPlatform() == VER_PLATFORM_WIN32_WINDOWS;
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsWinNT( void ) // XA_IsWinNT() --> BOOL
{
   return GetWinPlatform() == VER_PLATFORM_WIN32_NT;
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsXPOrHigher( void ) // XA_IsXPOrHigher() --> BOOL
{
   return XA_GetWinVer() >= WINVER_XP;
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsVistaOrHigher( void ) // XA_IsVistaOrHigher() --> BOOL
{
   return XA_GetWinVer() >= WINVER_VISTA;
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISWIN9X )   // XA_IsWin9x() --> lResult
{
   hb_retl( XA_IsWin9X() );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISWINNT )   // XA_IsWinNT() --> lResult
{
   hb_retl( XA_IsWinNT() );
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsWinVista( void ) // XA_IsWinVista() --> BOOL
{
   OSVERSIONINFOEX vi;
   BOOL bOk;

   memset( &vi, 0, sizeof( OSVERSIONINFOEX ) );
   vi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
   bOk = GetVersionEx( (OSVERSIONINFO *) &vi );

   if( bOk )
      bOk = ( vi.dwMajorVersion == 6 &&
              vi.dwMinorVersion == 0 && vi.wProductType == VER_NT_WORKSTATION );

   return bOk;
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISWINVISTA )   // XA_IsWinVista() --> lResult
{
   hb_retl( XA_IsWinVista() );
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsWin7( void ) // XA_IsWin7() --> BOOL
{
   OSVERSIONINFOEX vi;
   BOOL bOk;

   memset( &vi, 0, sizeof( OSVERSIONINFOEX ) );
   vi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
   bOk = GetVersionEx( (OSVERSIONINFO *) &vi );

   if( bOk )
      bOk = ( vi.dwMajorVersion == 6 &&
              vi.dwMinorVersion == 1 && vi.wProductType == VER_NT_WORKSTATION );

   return bOk;
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsWin8( void ) // XA_IsWin8() --> BOOL
{
   OSVERSIONINFOEX vi;
   BOOL bOk;

   memset( &vi, 0, sizeof( OSVERSIONINFOEX ) );
   vi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
   bOk = GetVersionEx( (OSVERSIONINFO *) &vi );

   if( bOk )
      bOk = ( vi.dwMajorVersion == 6 &&
              vi.dwMinorVersion > 1 && vi.wProductType == VER_NT_WORKSTATION );

   return bOk;
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsWin10( void ) // XA_IsWin10() --> BOOL
{
   OSVERSIONINFOEX vi;
   BOOL bOk;

   memset( &vi, 0, sizeof( OSVERSIONINFOEX ) );
   vi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
   bOk = GetVersionEx( (OSVERSIONINFO *) &vi );

   if( bOk )
      bOk = ( vi.dwBuildNumber < 22000 &&
              vi.wProductType == VER_NT_WORKSTATION  &&
              vi.dwMajorVersion == 10 &&
              vi.dwMinorVersion == 0 );

   return bOk;
}

//--------------------------------------------------------------------------

XA_EXPORT BOOL XA_IsWin11( void ) // XA_IsWin11() --> BOOL
{
   OSVERSIONINFOEX vi;
   BOOL bOk;

   memset( &vi, 0, sizeof( OSVERSIONINFOEX ) );
   vi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
   bOk = GetVersionEx( (OSVERSIONINFO *) &vi );

   if( bOk )
      bOk = ( vi.dwBuildNumber >= 22000 &&
              vi.wProductType == VER_NT_WORKSTATION  &&
              vi.dwMajorVersion == 10 &&
              vi.dwMinorVersion == 0 );

   return bOk;
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISWIN7 )   // XA_IsWin7() --> lResult
{
   hb_retl( XA_IsWin7() );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISWIN10 )   // XA_IsWin10() --> lResult
{
   hb_retl( XA_IsWin10() );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISWIN11 )   // XA_IsWin11() --> lResult
{
   hb_retl( XA_IsWin11() );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISWIN8 )   // XA_IsWin8() --> lResult
{
   hb_retl( XA_IsWin8() );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISXPORHIGHER )   // XA_IsXPOrHigher() --> lResult
{
   hb_retl( XA_IsXPOrHigher() );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISVISTAORHIGHER )   // XA_IsVistaOrHigher() --> lResult
{
   hb_retl( XA_IsVistaOrHigher() );
}

//--------------------------------------------------------------------------

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

#if ( __GNUC__ >= 7 )
   #pragma GCC diagnostic ignored "-Wattributes"
#endif

BOOL WINAPI IsWow64Process( HANDLE hProcess, PBOOL bIsWow64 )
{
   LPFN_ISWOW64PROCESS fnIsWow64Process;
   BOOL lSuccess = FALSE;

   *bIsWow64 = FALSE;
   fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( GetModuleHandle( "kernel32" ), "IsWow64Process" );
   if( fnIsWow64Process )
     lSuccess = fnIsWow64Process( hProcess, bIsWow64 );

   return( lSuccess );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_ISWOW64 )   // XA_IsWow64() --> lResult
{
   BOOL bIsWow64 = FALSE;

   IsWow64Process( GetCurrentProcess(), &bIsWow64 );

   hb_retl( bIsWow64 );
}

#endif

//--------------------------------------------------------------------------

XA_FUNC( STRENCODEESCAPE ) // StrEncodeEscape( <cString>, <lForSave> ) --> cResult
{
   int nStrLen = hb_parclen( 1 ), nLen = 0;
   const char *cText = hb_parc( 1 );
   char *cString = hb_xgrab( nStrLen * 2 + 4 ), *pText = cString, c;
   BOOL lForSave = hb_parl( 2 ), lExtended = FALSE;

   if( lForSave )
      {
      *pText++ = 'e';
      *pText++ = '"';
      nLen += 2;
      }

   while( nStrLen-- )
      {
      c = *cText++;
      switch( c )
         {
         case '"':
            if( lForSave )
               {
               lExtended = TRUE;
               *pText++ = '\\';
               nLen++;
               }
            break;
         case 13:
            lExtended = TRUE;
            *pText++ = '\\';
            c = 'r';
            nLen++;
            break;
         case 10:
            lExtended = TRUE;
            *pText++ = '\\';
            c = 'n';
            nLen++;
            break;
         case 9:
            lExtended = TRUE;
            *pText++ = '\\';
            c = 't';
            nLen++;
            break;
         case '\\':
            lExtended = TRUE;
            *pText++ = c;
            nLen++;
            break;
         case 0:
            lExtended = TRUE;
            *pText++ = '\\';
            c = '0';
            nLen++;
            break;
         }
      *pText++ = c;
      nLen++;
      }

   if( lForSave )
      {
      *pText++ = '"';
      nLen++;
      }
   *pText = 0;

   pText = cString;
   if( lForSave && !lExtended )
      {
      nLen--;
      pText++;
      }

   hb_retclen( pText, nLen );
   hb_xfree( cString );
}

//--------------------------------------------------------------------------

XA_FUNC( STRDECODEESCAPE ) // StrDecodeEscape( <cString> ) --> cResult
{
   const char *cString = hb_parc( 1 ), *cText = cString;
   char *cOut = hb_xgrab( hb_parclen( 1 ) + 1 ), *pText = cOut, c;
   int nLen = 0;

   while( ( c = *cText++ ) != 0 )
      {
      if( c == '\\' )
         switch( *cText )
            {
            case '"':
               c = '"';
               cText++;
               break;
            case 'n':
               c = 10;
               cText++;
               break;
            case 'r':
               c = 13;
               cText++;
               break;
            case 't':
               c = 9;
               cText++;
               break;
            case '\\':
               cText++;
               break;
            case '0':
               c = 0;
               cText++;
               break;
            }
      *pText++ = c;
      nLen++;
      }
   *pText = 0;

   hb_retclen_buffer( cOut, nLen );
}

//--------------------------------------------------------------------------

HB_FUNC( XA_URLENCODE ) // XA_UrlEncode( <cUrl> ) --> <cUrlUtf8>
{
   static char cDest[][10] = { "%E2%82%AC", "%81", "%E2%80%9A", "%C6%92", "%E2%80%9E", "%E2%80%A6", "%E2%80%A0", "%E2%80%A1", "%CB%86", "%E2%80%B0", "%C5%A0", "%E2%80%B9", "%C5%92", "%C5%8D", "%C5%BD", "%8F",
                               "%C2%90", "%E2%80%98", "%E2%80%99", "%E2%80%9C", "%E2%80%9D", "%E2%80%A2", "%E2%80%93", "%E2%80%94", "%CB%9C", "%E2%84", "%C5%A1", "%E2%80", "%C5%93", "%9D", "%C5%BE", "%C5%B8",
                               "%C2%A0", "%C2%A1", "%C2%A2", "%C2%A3", "%C2%A4", "%C2%A5", "%C2%A6", "%C2%A7", "%C2%A8", "%C2%A9", "%C2%AA", "%C2%AB", "%C2%AC", "%C2%AD", "%C2%AE", "%C2%AF",
                               "%C2%B0", "%C2%B1", "%C2%B2", "%C2%B3", "%C2%B4", "%C2%B5", "%C2%B6", "%C2%B7", "%C2%B8", "%C2%B9", "%C2%BA", "%C2%BB", "%C2%BC", "%C2%BD", "%C2%BE", "%C2%BF",
                               "%C3%80", "%C3%81", "%C3%82", "%C3%83", "%C3%84", "%C3%85", "%C3%86", "%C3%87", "%C3%88", "%C3%89", "%C3%8A", "%C3%8B", "%C3%8C", "%C3%8D", "%C3%8E", "%C3%8F",
                               "%C3%90", "%C3%91", "%C3%92", "%C3%93", "%C3%94", "%C3%95", "%C3%96", "%C3%97", "%C3%98", "%C3%99", "%C3%9A", "%C3%9B", "%C3%9C", "%C3%9D", "%C3%9E", "%C3%9F",
                               "%C3%A0", "%C3%A1", "%C3%A2", "%C3%A3", "%C3%A4", "%C3%A5", "%C3%A6", "%C3%A7", "%C3%A8", "%C3%A9", "%C3%AA", "%C3%AB", "%C3%AC", "%C3%AD", "%C3%AE", "%C3%AF",
                               "%C3%B0", "%C3%B1", "%C3%B2", "%C3%B3", "%C3%B4", "%C3%B5", "%C3%B6", "%C3%B7", "%C3%B8", "%C3%B9", "%C3%BA", "%C3%BB", "%C3%BC", "%C3%BD", "%C3%BE", "%C3%BF" };
   char *pIn, *pOut, *cOut = hb_xgrab( hb_parclen( 1 ) * 9 + 1 );

   pIn = (char *) hb_parc( 1 );
   pOut = cOut;
   while( *pIn ) {
      if( (BYTE) *pIn >= 0x80 )
         pOut = stpcpy( pOut, cDest[ ( (BYTE) *pIn ) - 0x80 ] );
      else if( *pIn == 0x20 )
         pOut = stpcpy( pOut, "%20" );
      else if( *pIn == '%' )
         pOut = stpcpy( pOut, "%25" );
      else if( *pIn > 0x20 )
         *pOut++ = *pIn;
      pIn++;
      }
   *pOut = 0;

   hb_retc_buffer( cOut );
}

//------------------------------------------------------------------------------

static BYTE HexToChar( char **pInput )
{
   BYTE c = **pInput;

   (*pInput)++;
   if( c == '%' ) {
      if( ( **pInput >= '0' ) && ( **pInput <= '9' ) )
         c = ( **pInput - '0' ) << 4;
      else if( ( **pInput >= 'A' ) && ( **pInput <= 'F' ) )
         c = ( **pInput - 'A' + 10 ) << 4;
      else if( ( **pInput >= 'a' ) && ( **pInput <= 'f' ) )
         c = ( **pInput - 'a' + 10 ) << 4;
      else
         return '%';

      (*pInput)++;
      if( ( **pInput >= '0' ) && ( **pInput <= '9' ) )
         c |= ( **pInput - '0' );
      else if( ( **pInput >= 'A' ) && ( **pInput <= 'F' ) )
         c |= ( **pInput - 'A' + 10 );
      else if( ( **pInput >= 'a' ) && ( **pInput <= 'f' ) )
         c |= ( **pInput - 'a' + 10 );
      else {
         (*pInput)--;
         return '%';
         }
      (*pInput)++;
   }

   return c;
}

//------------------------------------------------------------------------------

HB_FUNC( XA_URLDECODE ) // XA_UrlDecode( <cUrlEncoded> ) --> <cUrlUtf8>
{
   char *pIn = (char *) hb_parc( 1 );
   char *cOut = hb_xgrab( hb_parclen( 1 ) + 1 ), *pOut = cOut;

   while( *pIn ) {
      if( *pIn == '+' ) {
         *pOut++ = ' ';
         pIn++;
         }
      else
         *pOut++ = HexToChar( &pIn );
      }
   *pOut = 0;

   hb_retc_buffer( cOut );
}

//------------------------------------------------------------------------------

HB_FUNC( XA_URLDECODETOANSI ) // XA_UrlDecodeToAnsi( <cUrlEncoded> ) --> <cUrlAnsi>
{
   char *pIn = (char *) hb_parc( 1 );
   char *cOut = hb_xgrab( hb_parclen( 1 ) + 1 ), *pOut = cOut;
   BYTE c;

   while( *pIn ) {
      if( *pIn == '%' ) {
         pIn++;
         c = HexToChar( &pIn );
         switch( c ) {
            case 0xc2: *pOut++ = HexToChar( &pIn ); break;
            case 0xc3: *pOut++ = HexToChar( &pIn ) + 0x40; break;
            case 0xc6: *pOut++ = HexToChar( &pIn ) - 0x0F; break;
            case 0xcb: switch( HexToChar( &pIn ) ) {
                          case 0x86: *pOut++ = 0x88; break;
                          case 0x9c: *pOut++ = 0x98; break;
                          default: *pOut++ = c; pIn--;
                          } break;
            case 0xc5: switch( HexToChar( &pIn ) ) {
                          case 0xa0: *pOut++ = 0x8a; break;
                          case 0x92: *pOut++ = 0x8c; break;
                          case 0x8d: *pOut++ = 0x8d; break;
                          case 0xbd: *pOut++ = 0x8e; break;
                          case 0xa1: *pOut++ = 0x9a; break;
                          case 0x93: *pOut++ = 0x9c; break;
                          case 0xbe: *pOut++ = 0x9e; break;
                          case 0xb8: *pOut++ = 0x9f; break;
                          default: *pOut++ = c; pIn--;
                          } break;
            case 0xe2: switch( HexToChar( &pIn ) ) {
                          case 0x84: *pOut++ = 0x99; break;
                          case 0x82: if( HexToChar( &pIn ) == 0xac ) *pOut++ = 0x80; else { *pOut++ = c; pIn -= 2; }; break;
                          case 0x80: switch( HexToChar( &pIn ) ) {
                                        case 0x9a: *pOut++ = 0x82; break;
                                        case 0x9e: *pOut++ = 0x84; break;
                                        case 0xa6: *pOut++ = 0x85; break;
                                        case 0xa0: *pOut++ = 0x86; break;
                                        case 0xa1: *pOut++ = 0x87; break;
                                        case 0xb0: *pOut++ = 0x89; break;
                                        case 0xb9: *pOut++ = 0x8b; break;
                                        case 0x98: *pOut++ = 0x91; break;
                                        case 0x99: *pOut++ = 0x92; break;
                                        case 0x9c: *pOut++ = 0x93; break;
                                        case 0x9d: *pOut++ = 0x94; break;
                                        case 0xa2: *pOut++ = 0x95; break;
                                        case 0x93: *pOut++ = 0x96; break;
                                        case 0x94: *pOut++ = 0x97; break;
                                        default: *pOut++ = 0x9b; pIn--;
                                        } break;
                          default: *pOut++ = c; pIn--;
                          }
                       break;
            default: *pOut++ = c;
            }
         }
      else if( *pIn == '+' ) {
         *pOut++ = ' ';
         pIn++;
         }
      else
         *pOut++ = *pIn++;
      }
   *pOut = 0;

   hb_retc_buffer( cOut );
}

//------------------------------------------------------------------------------

#ifdef _WINDOWS_

XA_FUNC( COPYFILE )  // CopyFile( <cSource>, <cTarget> ) --> lSuccess
{
   hb_retl( CopyFile( hb_parc( 1 ), hb_parc( 2 ), FALSE ) );
}

//--------------------------------------------------------------------------

XA_FUNC( SNDPLAYSOUND ) // SndPlaySound( <cFilename>, <lAsynchronous> ) --> lSuccess
{
   UINT fuSound = SND_NODEFAULT;

   if( HB_ISLOG( 2 ) && hb_parl( 2 ) )
      fuSound |= SND_ASYNC;

   hb_retl( sndPlaySound( hb_parc( 1 ), fuSound ) );
}

//--------------------------------------------------------------------------

XA_FUNC( PLAYSOUND ) // PlaySound( <cFilename>, <hModule>, <nFlags> ) --> lSuccess
{
   DWORD dwFlags = SND_FILENAME | SND_NODEFAULT | SND_SYNC;

   if( hb_parnl( 3 ) )
      dwFlags = hb_parnl( 3 );

   hb_retl( PlaySound( hb_parclen( 1 ) ? hb_parc( 1 ) : NULL, (HMODULE) hb_parnl( 2 ), dwFlags ) );
}

//--------------------------------------------------------------------------

XA_FUNC( BEEP )   // Beep( <nFrec, nDuration> ) --> n/a
{
   Beep( HB_ISNUM( 1 ) ? (UINT) hb_parni( 1 ) : 1000,
         HB_ISNUM( 2 ) ? (UINT) hb_parni( 2 ) : 100);
}
//--------------------------------------------------------------------------

HB_FUNC( GETUSERNAME )  // GetUserName() --> cUserName
{
    TCHAR lpBuffer[ 255 ];
    DWORD nSize = 255;
    GetUserName( lpBuffer, &nSize );
    hb_retclen( lpBuffer, nSize - 1 );
}

//--------------------------------------------------------------------------

HB_FUNC( GETCOMPUTERNAME ) // GetComputerName() --> cComputerName
{
    TCHAR lpBuffer[ MAX_COMPUTERNAME_LENGTH + 1 ];
    DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
    GetComputerName( lpBuffer, &nSize );
    hb_retclen( lpBuffer, nSize  );
}

//--------------------------------------------------------------------------

HB_FUNC( ISUSERANADMIN )   // IsUserAnAdmin() --> lIsUserAnAdmin
{
   BOOL b = FALSE;
   SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY };
   PSID AdministratorsGroup;

   b = AllocateAndInitializeSid( &NtAuthority, 2,
                                 SECURITY_BUILTIN_DOMAIN_RID,
                                 DOMAIN_ALIAS_RID_ADMINS,
                                 0, 0, 0, 0, 0, 0,
                                 &AdministratorsGroup );
   if( b )
   {
      typedef BOOL ( WINAPI * FN )( HANDLE, PSID, PBOOL );
      FN _CheckTokenMembership = ( FN ) GetProcAddress( GetModuleHandle( "advapi32.dll" ), "CheckTokenMembership" );

      if( _CheckTokenMembership )
         if( !_CheckTokenMembership( NULL, AdministratorsGroup, &b ) )
            b = FALSE;

      FreeSid( AdministratorsGroup );
   }

   hb_retl( b );
}

//--------------------------------------------------------------------------

#ifdef __BORLANDC__
   typedef struct _TOKEN_ELEVATION {
      DWORD TokenIsElevated;
   } TOKEN_ELEVATION, *PTOKEN_ELEVATION;
   #define TokenElevation 21
#endif

BOOL IsElevated( void )
{
   BOOL lElevated = FALSE;
   HANDLE hToken = NULL;

   if( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) )
      {
      TOKEN_ELEVATION Elevation;
      DWORD cbSize = sizeof( TOKEN_ELEVATION );

      if( GetTokenInformation( hToken, TokenElevation, &Elevation, sizeof( Elevation ), &cbSize ) )
         lElevated = Elevation.TokenIsElevated;
      }
   if( hToken )
      CloseHandle( hToken );

   return lElevated;
}

//------------------------------------------------------------------------------

HB_FUNC( ISELEVATED )   // IsElevated() --> lValue
{
   hb_retl( IsElevated() );
}

//------------------------------------------------------------------------------

HB_FUNC( PTINRECT ) // PtInRect( <aRect>, <aPoint> ) --> lInRect
{
   RECT rect;
   POINT pt;

   rect.left   = hb_parvnl( 1, 1 );
   rect.top    = hb_parvnl( 1, 2 );
   rect.right  = hb_parvnl( 1, 3 );
   rect.bottom = hb_parvnl( 1, 4 );
   pt.x        = hb_parvnl( 2, 1 );
   pt.y        = hb_parvnl( 2, 2 );

   hb_retl( PtInRect( &rect, pt ) );
}

//--------------------------------------------------------------------------

static BOOL CALLBACK EnumWndProc( HWND hWnd, LPARAM lParam )
{
   if( IsWindow( hWnd ) )
      {
      PHB_ITEM pItem = hb_itemNew( NULL );
      hb_arrayAddForward( (PHB_ITEM) lParam, hb_itemPutNL( pItem, (long) hWnd ) );
      hb_itemRelease( pItem );
      }

   return TRUE;
}

//------------------------------------------------------------------------------

HB_FUNC( ENUMWINDOWS ) // EnumWindows() --> aWindows
{
   PHB_ITEM aWindows = hb_itemArrayNew( 0 );
   EnumWindows( EnumWndProc, (LPARAM) aWindows );
   hb_itemReturnForward( aWindows );
   hb_itemRelease( aWindows );
}

//------------------------------------------------------------------------------

HB_FUNC( GETCURRENTPROCESSID )   // GetCurrentProcessId() --> nProcessId
{
   hb_retnl( GetCurrentProcessId() );
}

//------------------------------------------------------------------------------

HB_FUNC( GETWINDOWTHREADPROCESSID ) // GetWindowThreadProcessId( hWnd ) --> hProcesssID
{
   DWORD pid = 0;

   GetWindowThreadProcessId( (HWND) hb_parnl( 1 ), &pid );
   hb_retnl( pid );
}

#endif

//------------------------------------------------------------------------------

HB_FUNC( XA_TRIM ) // XA_Trim( <cString> ) --> cString
{
   PHB_ITEM pText = hb_param( 1, HB_IT_STRING );

   if( pText )
   {
      const char * cText = hb_itemGetCPtr( pText );
      int nLen = hb_strRTrimLen( cText, hb_itemGetCLen( pText ), TRUE );

      hb_retclen( cText, nLen );
   }
   else
      hb_errRT_BASE_SubstR( EG_ARG, 1100, NULL, "XA_TRIM", HB_ERR_ARGS_BASEPARAMS );
}

//------------------------------------------------------------------------------

HB_FUNC( SWAPCHR ) // SwapChr( <@cString>, <nAt>, <nAscii|cChar> ) --> lSuccess
{
   PHB_ITEM pItem = hb_param( 1, HB_IT_STRING );
   char *   buffer;
   HB_SIZE  nSize;
   HB_SIZE  nPos = hb_parnl( 2 );
   char Chr;

   hb_retl( HB_FALSE );  //Recomendacion de Druzus

   if( HB_ISCHAR( 3 ) )
      Chr = hb_parc( 3 )[ 0 ];
   else if( HB_ISNUM( 3 ) )
      Chr = hb_parni( 3 );
   else
      Chr = 0;

   if( pItem && HB_ISBYREF( 1 ) && nPos && Chr &&
      hb_itemGetWriteCL( pItem, &buffer, &nSize ) && nPos <= nSize )
   {
      *( buffer + nPos - 1 ) = Chr;
      hb_retl( HB_TRUE );
   }
   else
      hb_errRT_BASE_SubstR( EG_ARG, 1100, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

//------------------------------------------------------------------------------

#ifdef _WINDOWS_

HB_FUNC( GETENVIRONMENTVARIABLE ) // GetEnvironmentVariable( <cName> ) --> cValue
{
   LPSTR cValue, cVar = (LPSTR) hb_parc( 1 );
   DWORD nSize;

   hb_retc( "" );
   if( cVar && *cVar )
      {
      nSize = GetEnvironmentVariable( cVar, "", 0 );
      if( nSize++ )
         {
         cValue = hb_xgrab( nSize );
         GetEnvironmentVariable( cVar, cValue, nSize );
         hb_retc( cValue );
         hb_xfree( cValue );
         }
      }
}

//------------------------------------------------------------------------------

HB_FUNC( SETENVIRONMENTVARIABLE ) // SetEnvironmentVariable( <cName>, <cValue> ) --> lSuccess
{
   LPSTR cVar = (LPSTR) hb_parc( 1 );
   LPSTR cValue = (LPSTR) hb_parc( 2 );

   if( cVar && *cVar && cValue && *cValue )
      hb_retl( SetEnvironmentVariable( cVar, cValue ) );
   else
      hb_retl( FALSE );
}

#endif

//------------------------------------------------------------------------------

XA_FUNC( ISALLDIGITS )  // IsAllDigits( <cString>, [<lDecPoint>] ) --> bResult
{
   const char * h = hb_parc( 1 );
   HB_BOOL lDec = hb_parl( 2 );
   HB_BOOL lResult = FALSE;

   if( h )
      while( *h && ( lResult = ( *h >= '0' && *h <= '9' ) || ( lDec && *h == '.' ) ) != 0 )
         h++;

   hb_retl( lResult );
}

//------------------------------------------------------------------------------

XA_FUNC( XA_REMOVETAGS ) // XA_RemoveTags( cText ) --> cText
{
   const char *p1 = hb_parc( 1 ) ;
   char * cResult = hb_xgrab(  hb_parclen( 1 ) + 2 );
   char *p2 = cResult;
   HB_BOOL lInTag = FALSE;
   do
      {
      if ( *p1 == '<' )
         lInTag = TRUE;
      else if ( *p1 == '>' )
         lInTag = FALSE;
      else if ( !lInTag )
         *p2++ = *p1;
      }
   while( *p1++ );

   *p2 = '\0';

   hb_retc_buffer( cResult );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_LINECOUNT ) // XA_LineCount( cString ) --> nLines
{
   const char *p = hb_parc( 1 );
   char c;
   int n = 1;

   while( ( c = *p++ ) != 0 )
      {
      if( c == '\\' )
         {
         if ( *p == 'n' )
            n++;
         }
      else if( c == 10 )
         n++;
      }

   hb_retnl( n );
}

//--------------------------------------------------------------------------

XA_FUNC( REPLACECHARS )    // ReplaceChars( cInput, cSearch, cReplace ) -> cOutput
{
   char const *p = hb_parc( 1 ), *cSearch = hb_parc( 2 ), *cReplace = hb_parc( 3 );
   char *cOutput = hb_xgrab( hb_parclen( 1 ) + 1 ), *s = cOutput, *q;
   int nLenReplace = hb_parclen( 3 );

   if( p && *p && cSearch && *cSearch && cReplace && *cReplace )
      {
      while( *p )
         {
         *s = *p;
         q = (char *) cSearch;
         while( *q )
            if( *q++ == *p )
               {
               if( q - cSearch <= nLenReplace )
                  *s = cReplace[ q - cSearch - 1 ];
               break;
               }
         s++;
         p++;
         }
      }

   *s = 0;
   hb_retc_buffer( cOutput );
}

//------------------------------------------------------------------------------

static BOOL XA_CallFunction( void )
{
   PHB_DYNS pFunc = hb_dynsymFindName( hb_parc( 1 ) );
   HB_ULONG nParams = hb_pcount(), n;

   if( pFunc && hb_dynsymIsFunction( pFunc ) )
      {
      hb_vmPushDynSym( pFunc );
      hb_vmPushNil();
      for( n = 2; n <= nParams; n++ )
         hb_vmPush( hb_stackItemFromBase( n ) );
      hb_vmProc( ( HB_USHORT ) nParams - 1 );
      return TRUE;
      }
   else
      {
      hb_ret();
      return FALSE;
      }
}

//------------------------------------------------------------------------------

XA_FUNC( XA_CALLFUNCTION )
{
   if( !XA_CallFunction() )
      {
      OutDebug( "Function does not exist:", hb_parc( 1 ), NULL );
      hb_ret();
      }
}

//------------------------------------------------------------------------------

XA_FUNC( XA_CALLIFEXISTS )
{
   XA_CallFunction();
}

//------------------------------------------------------------------------------

XA_FUNC( XA_FUNCTIONEXISTS )
{
   hb_retl( hb_dynsymFindName( hb_parc( 1 ) ) != NULL );
}

//------------------------------------------------------------------------------

XA_FUNC( XA_VARSEQUAL ) // XA_VarsEqual( xValue1, xValue2 ) ->lEqual
{
   int iResult;

   if( hb_itemCompare( hb_param( 1, HB_IT_ANY ),
                       hb_param( 2, HB_IT_ANY ),
                       HB_TRUE, &iResult ) )
      hb_retl( iResult == 0 );
   else
      hb_retl( HB_FALSE );
}

//------------------------------------------------------------------------------

#ifndef _LINUX_
XA_FUNC( UUIDCREATE )   // UuidCreate() -> cUuid
{
   UUID uuid;
   unsigned char *cUuid;

   hb_retc( "" );
   if( UuidCreate( &uuid ) == RPC_S_OK )
      {
      UuidToString( &uuid, &cUuid );
      hb_retc( (LPSTR) cUuid );
      RpcStringFree( &cUuid );
      }
}
#endif

//------------------------------------------------------------------------------

HB_FUNC( XA_NOACCENTS ) // XA_NOACCENTS( <cString> ) --> cSring
{
   LPTSTR cFrom, cTo, p1, p2;

   cFrom = (LPSTR) hb_parc( 1 );
   cTo   = hb_xgrab( hb_parclen( 1 ) + 1 );
   p1    = cFrom;
   p2    = cTo;

   while( *p1 )
      {
      *p2 = *p1++;
      switch( *p2 )
         {
         case 'á':
         case 'à':
         case 'ä':
         case 'â':
            *p2 = 'a';
            break;
         case 'Á':
         case 'À':
         case 'Ä':
         case 'Â':
            *p2 = 'A';
            break;
         case 'é':
         case 'è':
         case 'ë':
         case 'ê':
            *p2 = 'e';
            break;
         case 'É':
         case 'È':
         case 'Ë':
         case 'Ê':
            *p2 = 'E';
            break;
         case 'í':
         case 'ì':
         case 'ï':
         case 'î':
            *p2 = 'i';
            break;
         case 'Í':
         case 'Ì':
         case 'Ï':
         case 'Î':
            *p2 = 'I';
            break;
         case 'ó':
         case 'ò':
         case 'ö':
         case 'ô':
            *p2 = 'o';
            break;
         case 'Ó':
         case 'Ò':
         case 'Ö':
         case 'Ô':
            *p2 = 'O';
            break;
         case 'ú':
         case 'ù':
         case 'ü':
         case 'û':
            *p2 = 'u';
            break;
         case 'Ú':
         case 'Ù':
         case 'Ü':
         case 'Û':
            *p2 = 'U';
            break;
         }
      p2++;
      }
   *p2=0;

   hb_retc_buffer( cTo );
}

//------------------------------------------------------------------------------
