win32.cc 12.3 KB
Newer Older
1 2
// win32.cc - Helper functions for Microsoft-flavored OSs.

3
/* Copyright (C) 2002, 2003, 2006  Free Software Foundation
4 5 6 7 8 9 10 11

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

#include <config.h>
12
#include <platform.h>
13
#include <sys/timeb.h>
14
#include <stdlib.h>
15
#include <string.h>
16
#include <fcntl.h>
17

18 19
#include <java-stack.h>

20
#include <java/lang/ArithmeticException.h>
Mohan Embar committed
21 22 23
#include <java/lang/UnsupportedOperationException.h>
#include <java/io/IOException.h>
#include <java/net/SocketException.h>
24
#include <java/util/Properties.h>
25 26

static LONG CALLBACK
27 28 29 30 31 32 33 34 35
win32_exception_handler (LPEXCEPTION_POINTERS e)
{
  if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
    _Jv_ThrowNullPointerException();
  else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
    throw new java::lang::ArithmeticException;
  else
    return EXCEPTION_CONTINUE_SEARCH;
}
36

Andrew Haley committed
37 38 39 40 41 42 43 44 45
// Platform-specific executable name
static char exec_name[MAX_PATH];
  // initialized in _Jv_platform_initialize()

const char *_Jv_ThisExecutable (void)
{
  return exec_name;
}

Mohan Embar committed
46 47
// Helper classes and methods implementation
  
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
#ifdef MINGW_LIBGCJ_UNICODE

// We're using the OS W (UNICODE) API, which means that we're speaking
// the same language....
jstring
_Jv_Win32NewString (LPCTSTR pcsz)
{
  return JvNewString ((jchar*) pcsz, _tcslen (pcsz));
}

#else

// We're using the OS A functions, which means we need to translate between
// UNICODE and the native character set.

// First, let's set up some helper translation functions....

// Converts the native string to any specified jstring, returning the
// length of the jstring. If the specified jstring is null, we simply
// compute and return the length.
static int nativeToUnicode(LPCSTR pcsz, jstring jstr = 0)
{
  jchar* buf = 0;
  int len = 0;
  if (jstr)
    {
      len = jstr->length();
      buf = JvGetStringChars(jstr);
    }
  return ::MultiByteToWideChar(GetACP(), 0, pcsz,
    strlen(pcsz), (LPWSTR) buf, len);
}

// Does the inverse of nativeToUnicode, with the same calling semantics.
static int unicodeToNative(jstring jstr, LPSTR buf, int buflen)
{
  return ::WideCharToMultiByte(GetACP(), 0, (LPWSTR) JvGetStringChars(jstr),
    jstr->length(), buf, buflen, NULL, NULL);
}

// Convenience function when the caller only wants to compute the length
// of the native string.
static int unicodeToNative(jstring jstr)
{
  return unicodeToNative(jstr, 0, 0);
}

jstring
_Jv_Win32NewString (LPCTSTR pcsz)
{
  // Compute the length, allocate the jstring, then perform the conversion.
  int len = nativeToUnicode(pcsz);
  jstring jstr = JvAllocString(len);
  nativeToUnicode(pcsz, jstr);
  return jstr;
}

#endif // MINGW_LIBGCJ_UNICODE

// class _Jv_Win32TempString
_Jv_Win32TempString::_Jv_Win32TempString(jstring jstr):
  buf_(0)
{
  if (jstr == 0)
    return;
    
  // We need space for the string length plus a null terminator.
  // Determine whether to use our stack-allocated buffer or a heap-
  // allocated one.
#ifdef MINGW_LIBGCJ_UNICODE
  // A UNICODE character is a UNICODE character is a UNICODE character....
  int len = jstr->length();
#else
  // Compute the length of the native character string.
  int len = unicodeToNative(jstr);
#endif // MINGW_LIBGCJ_UNICODE

  int bytesNeeded = (len + 1) * sizeof(TCHAR);
  if (bytesNeeded <= (int) sizeof(stackbuf_))
    buf_ = stackbuf_;
  else
    buf_ = (LPTSTR) _Jv_Malloc(bytesNeeded);
    
#ifdef MINGW_LIBGCJ_UNICODE
  // Copy the UNICODE characters to our buffer.
  _tcsncpy(buf_, (LPCTSTR) JvGetStringChars (jstr), len);
#else
  // Convert the UNICODE string to a native one.
  unicodeToNative(jstr, buf_, len);
#endif // MINGW_LIBGCJ_UNICODE

  buf_[len] = 0;
}

_Jv_Win32TempString::~_Jv_Win32TempString()
{
  if (buf_ && buf_ != stackbuf_)
    _Jv_Free (buf_);
}

Mohan Embar committed
148
// class WSAEventWrapper
149 150 151 152 153 154
WSAEventWrapper::WSAEventWrapper ():
  m_hEvent(0),
  m_fd(0),
  m_dwSelFlags(0)
{}

Mohan Embar committed
155 156
WSAEventWrapper::WSAEventWrapper (int fd, DWORD dwSelFlags):
  m_hEvent(0),
157 158 159 160 161 162 163
  m_fd(0),
  m_dwSelFlags(0)
{
  init(fd, dwSelFlags);
}

void WSAEventWrapper::init(int fd, DWORD dwSelFlags)
Mohan Embar committed
164
{
165 166
  m_fd = fd;
  m_dwSelFlags = dwSelFlags;
Mohan Embar committed
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
  m_hEvent = WSACreateEvent ();
  if (dwSelFlags)
    WSAEventSelect(fd, m_hEvent, dwSelFlags);
}

WSAEventWrapper::~WSAEventWrapper ()
{
  if (m_dwSelFlags)
  {
    WSAEventSelect(m_fd, m_hEvent, 0);
    if (m_dwSelFlags & (FD_ACCEPT | FD_CONNECT))
    {
      // Set the socket back to non-blocking mode.
      // Ignore any error since we're in a destructor.
      unsigned long lSockOpt = 0L;
        // blocking mode
      ::ioctlsocket (m_fd, FIONBIO, &lSockOpt);
    }
  }
  WSACloseEvent (m_hEvent);
}

// Error string text.
jstring
_Jv_WinStrError (LPCTSTR lpszPrologue, int nErrorCode)
{
  LPTSTR lpMsgBuf = 0;

  DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS;

  FormatMessage (dwFlags,
    NULL,
    (DWORD) nErrorCode,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) &lpMsgBuf,
    0,
    NULL);

  jstring ret;
  if (lpszPrologue)
    {
      LPTSTR lpszTemp =
211 212 213 214 215 216 217
        (LPTSTR) _Jv_Malloc ((_tcslen (lpszPrologue) +
          _tcslen (lpMsgBuf) + 3) * sizeof(TCHAR) );
      _tcscpy (lpszTemp, lpszPrologue);
      _tcscat (lpszTemp, _T(": "));
      _tcscat (lpszTemp, lpMsgBuf);
      ret = _Jv_Win32NewString (lpszTemp);
      _Jv_Free (lpszTemp);
Mohan Embar committed
218 219 220
    } 
  else
    {
221
      ret = _Jv_Win32NewString (lpMsgBuf);
Mohan Embar committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
    }

  LocalFree(lpMsgBuf);
  return ret;
}

jstring
_Jv_WinStrError (int nErrorCode)
{
  return _Jv_WinStrError (0, nErrorCode);
}

void _Jv_ThrowIOException (DWORD dwErrorCode)
{
  throw new java::io::IOException (_Jv_WinStrError (dwErrorCode));
}

void _Jv_ThrowIOException()
{
  DWORD dwErrorCode = WSAGetLastError ();
  _Jv_ThrowIOException (dwErrorCode);
}

void _Jv_ThrowSocketException (DWORD dwErrorCode)
{
  throw new java::net::SocketException (_Jv_WinStrError (dwErrorCode));
}

void _Jv_ThrowSocketException()
{
  DWORD dwErrorCode = WSAGetLastError ();
  _Jv_ThrowSocketException (dwErrorCode);
}

256 257 258 259 260 261
// Platform-specific VM initialization.
void
_Jv_platform_initialize (void)
{
  // Initialise winsock for networking
  WSADATA data;
262
  if (WSAStartup (MAKEWORD (2, 2), &data))
263
    MessageBox (NULL, _T("Error initialising winsock library."), _T("Error"),
Mohan Embar committed
264 265
    MB_OK | MB_ICONEXCLAMATION);

266 267
  // Install exception handler
  SetUnhandledExceptionFilter (win32_exception_handler);
Mohan Embar committed
268

269 270 271 272 273
  // Initialize our executable name.
  // FIXME: We unconditionally use the ANSI function because
  // _Jv_ThisExecutable returns a const char*. We should really
  // change _Jv_ThisExecutable to return a jstring.
  GetModuleFileNameA(NULL, exec_name, sizeof(exec_name));
274
}
275 276

// gettimeofday implementation.
277 278
jlong
_Jv_platform_gettimeofday ()
279
{
280 281
  struct timeb t;
  ftime (&t);
282
  return t.time * 1000LL + t.millitm;
283 284
}

285 286 287 288 289 290
jlong
_Jv_platform_nanotime ()
{
  return _Jv_platform_gettimeofday () * 1000LL;
}

291
static bool dirExists (LPCTSTR dir)
292 293 294 295 296 297
{
  DWORD dwAttrs = ::GetFileAttributes (dir);
  return dwAttrs != 0xFFFFFFFF &&
    (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
}

298
static void getUserHome(LPTSTR userHome, LPCTSTR userId)
299
{
300
  LPTSTR uh = _tgetenv (_T("USERPROFILE"));
301 302
  if (uh)
    {
303
      _tcscpy(userHome, uh);
304 305 306 307 308 309 310 311 312 313 314 315
    }
  else
    {
      // Make a half-hearted attempt to support this
      // legacy version of Windows. Try %WINDIR%\Profiles\%USERNAME%
      // and failing this, use %WINDIR%.
      //
      // See:http://java.sun.com/docs/books/tutorial/security1.2/summary/files.html#UserPolicy
      //
      // To do this correctly, we'd have to factor in the
      // Windows version, but if we did that, then this attempt
      // wouldn't be half-hearted.
316
      TCHAR userHomePath[MAX_PATH], winHome[MAX_PATH];
317 318 319
      ::GetWindowsDirectory(winHome, MAX_PATH);
        // assume this call always succeeds

320
      _stprintf(userHomePath, _T("%s\\Profiles\\%s"), winHome, userId);
321
      if (dirExists (userHomePath))
322
        _tcscpy(userHome, userHomePath);
323
      else
324
        _tcscpy(userHome, winHome);
325 326 327
    }
}

328 329 330 331 332 333
// Set platform-specific System properties.
void
_Jv_platform_initProperties (java::util::Properties* newprops)
{
  // A convenience define.
#define SET(Prop,Val) \
334
  newprops->put(JvNewStringLatin1 (Prop), _Jv_Win32NewString (Val))
335

336 337 338
  SET ("file.separator", _T("\\"));
  SET ("path.separator", _T(";"));
  SET ("line.separator", _T("\r\n"));
339 340 341

  // Use GetCurrentDirectory to set 'user.dir'.
  DWORD buflen = MAX_PATH;
342
  TCHAR buffer[buflen];
343 344 345
  if (buffer != NULL)
    {
      if (GetCurrentDirectory (buflen, buffer))
Mohan Embar committed
346
  SET ("user.dir", buffer);
347 348

      if (GetTempPath (buflen, buffer))
Mohan Embar committed
349
  SET ("java.io.tmpdir", buffer);
350
    }
Mohan Embar committed
351

352 353
  // Use GetUserName to set 'user.name'.
  buflen = 257;  // UNLEN + 1
354
  TCHAR userName[buflen];
355 356 357 358
  if (GetUserName (userName, &buflen))
    SET ("user.name", userName);

  // Set user.home
359
  TCHAR userHome[MAX_PATH];
360 361
  getUserHome(userHome, userName);
  SET ("user.home", userHome);
362 363 364 365 366 367 368 369 370

  // Get and set some OS info.
  OSVERSIONINFO osvi;
  ZeroMemory (&osvi, sizeof(OSVERSIONINFO));
  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  if (GetVersionEx (&osvi))
    {
      if (buffer != NULL)
        {
371
          _stprintf (buffer, _T("%d.%d"), (int) osvi.dwMajorVersion,
Mohan Embar committed
372
           (int) osvi.dwMinorVersion);
373 374 375 376 377 378 379
          SET ("os.version", buffer);
        }

      switch (osvi.dwPlatformId)
        {
          case VER_PLATFORM_WIN32_WINDOWS:
            if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
380
              SET ("os.name", _T("Windows 95"));
381
            else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
382
              SET ("os.name", _T("Windows 98"));
383
            else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
384
              SET ("os.name", _T("Windows Me"));
385
            else
386
              SET ("os.name", _T("Windows ??"));
387 388 389 390
            break;

          case VER_PLATFORM_WIN32_NT:
            if (osvi.dwMajorVersion <= 4 )
391
              SET ("os.name", _T("Windows NT"));
392
            else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
393
              SET ("os.name", _T("Windows 2000"));
394
            else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
395
              SET ("os.name", _T("Windows XP"));
396
            else
397
              SET ("os.name", _T("Windows NT ??"));
398 399 400
            break;

          default:
401
            SET ("os.name", _T("Windows UNKNOWN"));
402 403 404 405 406 407 408
            break;
       }
  }

  // Set the OS architecture.
  SYSTEM_INFO si;
  GetSystemInfo (&si);
409
  switch (si.wProcessorArchitecture)
410
    {
411
      case PROCESSOR_ARCHITECTURE_INTEL:
412
        SET ("os.arch", _T("x86"));
413
        break;
414
      case PROCESSOR_ARCHITECTURE_MIPS:
415
        SET ("os.arch", _T("mips"));
416
        break;
417
      case PROCESSOR_ARCHITECTURE_ALPHA:
418
        SET ("os.arch", _T("alpha"));
419
        break;
420 421
      case PROCESSOR_ARCHITECTURE_PPC:  
        SET ("os.arch", _T("ppc"));
422
        break;
423
      case PROCESSOR_ARCHITECTURE_IA64:
424
        SET ("os.arch", _T("ia64"));
425
        break;
426
      case PROCESSOR_ARCHITECTURE_UNKNOWN:
427
      default:
428
        SET ("os.arch", _T("unknown"));
429 430 431
        break;
    }
}
432

Mohan Embar committed
433
int
434 435 436 437
_Jv_pipe (int filedes[2])
{
  return _pipe (filedes, 4096, _O_BINARY);
}
438 439 440 441 442 443 444 445

void
_Jv_platform_close_on_exec (HANDLE h)
{
  // Mark the handle as non-inheritable. This has
  // no effect under Win9X.
  SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
}
446 447 448 449 450

// Given an address, find the object that defines it and the nearest
// defined symbol to that address.  Returns 0 if no object defines this
// address.
int
451
_Jv_platform_dladdr (void *addr, _Jv_AddrInfo *info)
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
{
  // Since we do not have dladdr() on Windows, we use a trick involving
  // VirtualQuery() to find the module (EXE or DLL) that contains a given
  // address.  This was taken from Matt Pietrek's "Under the Hood" column
  // for the April 1997 issue of Microsoft Systems Journal.

  MEMORY_BASIC_INFORMATION mbi;
  if (!VirtualQuery (addr, &mbi, sizeof (mbi)))
  {
    return 0;
  }
  
  HMODULE hMod = (HMODULE) mbi.AllocationBase;

  char moduleName[MAX_PATH];

  // FIXME: We explicitly use the ANSI variant of the function here.
  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
  {
    return 0;
  }

  char *file_name = (char *)(malloc (strlen (moduleName) + 1));
  strcpy (file_name, moduleName);
  info->file_name = file_name;

  // FIXME.
  info->base = NULL;
  info->sym_name = NULL;
  info->sym_addr = NULL;

  return 1;
}