OSDN Git Service

PR middle-end/38584
[pf3gnuchains/gcc-fork.git] / libjava / win32.cc
1 // win32.cc - Helper functions for Microsoft-flavored OSs.
2
3 /* Copyright (C) 2002, 2003, 2006  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #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 #include <java-stack.h>
19
20 #include <java/lang/ArithmeticException.h>
21 #include <java/lang/UnsupportedOperationException.h>
22 #include <java/io/IOException.h>
23 #include <java/net/SocketException.h>
24 #include <java/util/Properties.h>
25
26 static LONG CALLBACK
27 win32_exception_handler (LPEXCEPTION_POINTERS e)
28 {
29   if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
30     _Jv_ThrowNullPointerException();
31   else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
32     throw new java::lang::ArithmeticException;
33   else
34     return EXCEPTION_CONTINUE_SEARCH;
35 }
36
37 // Platform-specific executable name
38 static char exec_name[MAX_PATH];
39   // initialized in _Jv_platform_initialize()
40
41 const char *_Jv_ThisExecutable (void)
42 {
43   return exec_name;
44 }
45
46 // Helper classes and methods implementation
47   
48 #ifdef MINGW_LIBGCJ_UNICODE
49
50 // We're using the OS W (UNICODE) API, which means that we're speaking
51 // the same language....
52 jstring
53 _Jv_Win32NewString (LPCTSTR pcsz)
54 {
55   return JvNewString ((jchar*) pcsz, _tcslen (pcsz));
56 }
57
58 #else
59
60 // We're using the OS A functions, which means we need to translate between
61 // UNICODE and the native character set.
62
63 // First, let's set up some helper translation functions....
64
65 // Converts the native string to any specified jstring, returning the
66 // length of the jstring. If the specified jstring is null, we simply
67 // compute and return the length.
68 static int nativeToUnicode(LPCSTR pcsz, jstring jstr = 0)
69 {
70   jchar* buf = 0;
71   int len = 0;
72   if (jstr)
73     {
74       len = jstr->length();
75       buf = JvGetStringChars(jstr);
76     }
77   return ::MultiByteToWideChar(GetACP(), 0, pcsz,
78     strlen(pcsz), (LPWSTR) buf, len);
79 }
80
81 // Does the inverse of nativeToUnicode, with the same calling semantics.
82 static int unicodeToNative(jstring jstr, LPSTR buf, int buflen)
83 {
84   return ::WideCharToMultiByte(GetACP(), 0, (LPWSTR) JvGetStringChars(jstr),
85     jstr->length(), buf, buflen, NULL, NULL);
86 }
87
88 // Convenience function when the caller only wants to compute the length
89 // of the native string.
90 static int unicodeToNative(jstring jstr)
91 {
92   return unicodeToNative(jstr, 0, 0);
93 }
94
95 jstring
96 _Jv_Win32NewString (LPCTSTR pcsz)
97 {
98   // Compute the length, allocate the jstring, then perform the conversion.
99   int len = nativeToUnicode(pcsz);
100   jstring jstr = JvAllocString(len);
101   nativeToUnicode(pcsz, jstr);
102   return jstr;
103 }
104
105 #endif // MINGW_LIBGCJ_UNICODE
106
107 // class _Jv_Win32TempString
108 _Jv_Win32TempString::_Jv_Win32TempString(jstring jstr):
109   buf_(0)
110 {
111   if (jstr == 0)
112     return;
113     
114   // We need space for the string length plus a null terminator.
115   // Determine whether to use our stack-allocated buffer or a heap-
116   // allocated one.
117 #ifdef MINGW_LIBGCJ_UNICODE
118   // A UNICODE character is a UNICODE character is a UNICODE character....
119   int len = jstr->length();
120 #else
121   // Compute the length of the native character string.
122   int len = unicodeToNative(jstr);
123 #endif // MINGW_LIBGCJ_UNICODE
124
125   int bytesNeeded = (len + 1) * sizeof(TCHAR);
126   if (bytesNeeded <= (int) sizeof(stackbuf_))
127     buf_ = stackbuf_;
128   else
129     buf_ = (LPTSTR) _Jv_Malloc(bytesNeeded);
130     
131 #ifdef MINGW_LIBGCJ_UNICODE
132   // Copy the UNICODE characters to our buffer.
133   _tcsncpy(buf_, (LPCTSTR) JvGetStringChars (jstr), len);
134 #else
135   // Convert the UNICODE string to a native one.
136   unicodeToNative(jstr, buf_, len);
137 #endif // MINGW_LIBGCJ_UNICODE
138
139   buf_[len] = 0;
140 }
141
142 _Jv_Win32TempString::~_Jv_Win32TempString()
143 {
144   if (buf_ && buf_ != stackbuf_)
145     _Jv_Free (buf_);
146 }
147
148 // class WSAEventWrapper
149 WSAEventWrapper::WSAEventWrapper ():
150   m_hEvent(0),
151   m_fd(0),
152   m_dwSelFlags(0)
153 {}
154
155 WSAEventWrapper::WSAEventWrapper (int fd, DWORD dwSelFlags):
156   m_hEvent(0),
157   m_fd(0),
158   m_dwSelFlags(0)
159 {
160   init(fd, dwSelFlags);
161 }
162
163 void WSAEventWrapper::init(int fd, DWORD dwSelFlags)
164 {
165   m_fd = fd;
166   m_dwSelFlags = dwSelFlags;
167   m_hEvent = WSACreateEvent ();
168   if (dwSelFlags)
169     WSAEventSelect(fd, m_hEvent, dwSelFlags);
170 }
171
172 WSAEventWrapper::~WSAEventWrapper ()
173 {
174   if (m_dwSelFlags)
175   {
176     WSAEventSelect(m_fd, m_hEvent, 0);
177     if (m_dwSelFlags & (FD_ACCEPT | FD_CONNECT))
178     {
179       // Set the socket back to non-blocking mode.
180       // Ignore any error since we're in a destructor.
181       unsigned long lSockOpt = 0L;
182         // blocking mode
183       ::ioctlsocket (m_fd, FIONBIO, &lSockOpt);
184     }
185   }
186   WSACloseEvent (m_hEvent);
187 }
188
189 // Error string text.
190 jstring
191 _Jv_WinStrError (LPCTSTR lpszPrologue, int nErrorCode)
192 {
193   LPTSTR lpMsgBuf = 0;
194
195   DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
196     FORMAT_MESSAGE_FROM_SYSTEM |
197     FORMAT_MESSAGE_IGNORE_INSERTS;
198
199   FormatMessage (dwFlags,
200     NULL,
201     (DWORD) nErrorCode,
202     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
203     (LPTSTR) &lpMsgBuf,
204     0,
205     NULL);
206
207   jstring ret;
208   if (lpszPrologue)
209     {
210       LPTSTR lpszTemp =
211         (LPTSTR) _Jv_Malloc ((_tcslen (lpszPrologue) +
212           _tcslen (lpMsgBuf) + 3) * sizeof(TCHAR) );
213       _tcscpy (lpszTemp, lpszPrologue);
214       _tcscat (lpszTemp, _T(": "));
215       _tcscat (lpszTemp, lpMsgBuf);
216       ret = _Jv_Win32NewString (lpszTemp);
217       _Jv_Free (lpszTemp);
218     } 
219   else
220     {
221       ret = _Jv_Win32NewString (lpMsgBuf);
222     }
223
224   LocalFree(lpMsgBuf);
225   return ret;
226 }
227
228 jstring
229 _Jv_WinStrError (int nErrorCode)
230 {
231   return _Jv_WinStrError (0, nErrorCode);
232 }
233
234 void _Jv_ThrowIOException (DWORD dwErrorCode)
235 {
236   throw new java::io::IOException (_Jv_WinStrError (dwErrorCode));
237 }
238
239 void _Jv_ThrowIOException()
240 {
241   DWORD dwErrorCode = WSAGetLastError ();
242   _Jv_ThrowIOException (dwErrorCode);
243 }
244
245 void _Jv_ThrowSocketException (DWORD dwErrorCode)
246 {
247   throw new java::net::SocketException (_Jv_WinStrError (dwErrorCode));
248 }
249
250 void _Jv_ThrowSocketException()
251 {
252   DWORD dwErrorCode = WSAGetLastError ();
253   _Jv_ThrowSocketException (dwErrorCode);
254 }
255
256 // Platform-specific VM initialization.
257 void
258 _Jv_platform_initialize (void)
259 {
260   // Initialise winsock for networking
261   WSADATA data;
262   if (WSAStartup (MAKEWORD (2, 2), &data))
263     MessageBox (NULL, _T("Error initialising winsock library."), _T("Error"),
264     MB_OK | MB_ICONEXCLAMATION);
265
266   // Install exception handler
267   SetUnhandledExceptionFilter (win32_exception_handler);
268
269   // Initialize our executable name.
270   // FIXME: We unconditionally use the ANSI function because
271   // _Jv_ThisExecutable returns a const char*. We should really
272   // change _Jv_ThisExecutable to return a jstring.
273   GetModuleFileNameA(NULL, exec_name, sizeof(exec_name));
274 }
275
276 // gettimeofday implementation.
277 jlong
278 _Jv_platform_gettimeofday ()
279 {
280   struct timeb t;
281   ftime (&t);
282   return t.time * 1000LL + t.millitm;
283 }
284
285 jlong
286 _Jv_platform_nanotime ()
287 {
288   return _Jv_platform_gettimeofday () * 1000LL;
289 }
290
291 static bool dirExists (LPCTSTR dir)
292 {
293   DWORD dwAttrs = ::GetFileAttributes (dir);
294   return dwAttrs != 0xFFFFFFFF &&
295     (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
296 }
297
298 static void getUserHome(LPTSTR userHome, LPCTSTR userId)
299 {
300   LPTSTR uh = _tgetenv (_T("USERPROFILE"));
301   if (uh)
302     {
303       _tcscpy(userHome, uh);
304     }
305   else
306     {
307       // Make a half-hearted attempt to support this
308       // legacy version of Windows. Try %WINDIR%\Profiles\%USERNAME%
309       // and failing this, use %WINDIR%.
310       //
311       // See:http://java.sun.com/docs/books/tutorial/security1.2/summary/files.html#UserPolicy
312       //
313       // To do this correctly, we'd have to factor in the
314       // Windows version, but if we did that, then this attempt
315       // wouldn't be half-hearted.
316       TCHAR userHomePath[MAX_PATH], winHome[MAX_PATH];
317       ::GetWindowsDirectory(winHome, MAX_PATH);
318         // assume this call always succeeds
319
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 // Set platform-specific System properties.
329 void
330 _Jv_platform_initProperties (java::util::Properties* newprops)
331 {
332   // A convenience define.
333 #define SET(Prop,Val) \
334   newprops->put(JvNewStringLatin1 (Prop), _Jv_Win32NewString (Val))
335
336   SET ("file.separator", _T("\\"));
337   SET ("path.separator", _T(";"));
338   SET ("line.separator", _T("\r\n"));
339
340   // Use GetCurrentDirectory to set 'user.dir'.
341   DWORD buflen = MAX_PATH;
342   TCHAR buffer[buflen];
343   if (buffer != NULL)
344     {
345       if (GetCurrentDirectory (buflen, buffer))
346   SET ("user.dir", buffer);
347
348       if (GetTempPath (buflen, buffer))
349   SET ("java.io.tmpdir", buffer);
350     }
351
352   // Use GetUserName to set 'user.name'.
353   buflen = 257;  // UNLEN + 1
354   TCHAR userName[buflen];
355   if (GetUserName (userName, &buflen))
356     SET ("user.name", userName);
357
358   // Set user.home
359   TCHAR userHome[MAX_PATH];
360   getUserHome(userHome, userName);
361   SET ("user.home", userHome);
362
363   // Get and set some OS info.
364   OSVERSIONINFO osvi;
365   ZeroMemory (&osvi, sizeof(OSVERSIONINFO));
366   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
367   if (GetVersionEx (&osvi))
368     {
369       if (buffer != NULL)
370         {
371           _stprintf (buffer, _T("%d.%d"), (int) osvi.dwMajorVersion,
372            (int) osvi.dwMinorVersion);
373           SET ("os.version", buffer);
374         }
375
376       switch (osvi.dwPlatformId)
377         {
378           case VER_PLATFORM_WIN32_WINDOWS:
379             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             break;
388
389           case VER_PLATFORM_WIN32_NT:
390             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             break;
399
400           default:
401             SET ("os.name", _T("Windows UNKNOWN"));
402             break;
403        }
404   }
405
406   // Set the OS architecture.
407   SYSTEM_INFO si;
408   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       case PROCESSOR_ARCHITECTURE_PPC:  
421         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         break;
430     }
431 }
432
433 int
434 _Jv_pipe (int filedes[2])
435 {
436   return _pipe (filedes, 4096, _O_BINARY);
437 }
438
439 void
440 _Jv_platform_close_on_exec (HANDLE h)
441 {
442   // Mark the handle as non-inheritable. This has
443   // no effect under Win9X.
444   SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
445 }
446
447 // Given an address, find the object that defines it and the nearest
448 // defined symbol to that address.  Returns 0 if no object defines this
449 // address.
450 int
451 _Jv_platform_dladdr (void *addr, _Jv_AddrInfo *info)
452 {
453   // Since we do not have dladdr() on Windows, we use a trick involving
454   // VirtualQuery() to find the module (EXE or DLL) that contains a given
455   // address.  This was taken from Matt Pietrek's "Under the Hood" column
456   // for the April 1997 issue of Microsoft Systems Journal.
457
458   MEMORY_BASIC_INFORMATION mbi;
459   if (!VirtualQuery (addr, &mbi, sizeof (mbi)))
460   {
461     return 0;
462   }
463   
464   HMODULE hMod = (HMODULE) mbi.AllocationBase;
465
466   char moduleName[MAX_PATH];
467
468   // FIXME: We explicitly use the ANSI variant of the function here.
469   if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
470   {
471     return 0;
472   }
473
474   char *file_name = (char *)(malloc (strlen (moduleName) + 1));
475   strcpy (file_name, moduleName);
476   info->file_name = file_name;
477
478   // FIXME.
479   info->base = NULL;
480   info->sym_name = NULL;
481   info->sym_addr = NULL;
482
483   return 1;
484 }