OSDN Git Service

2006-07-04 Andreas Tobler <a.tobler@schweiz.ch>
[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 // The following definitions "fake out" mingw to think that -mthreads
292 // was enabled and that mingwthr.dll was linked. GCJ-compiled
293 // applications don't need this helper library because we can safely
294 // detect thread death (return from Thread.run()).
295
296 int _CRT_MT = 1;
297
298 extern "C" int
299 __mingwthr_key_dtor (DWORD, void (*) (void *))
300 {
301   // FIXME: for now we do nothing; this causes a memory leak of
302   //        approximately 24 bytes per thread created.
303   return 0;
304 }
305
306 static bool dirExists (LPCTSTR dir)
307 {
308   DWORD dwAttrs = ::GetFileAttributes (dir);
309   return dwAttrs != 0xFFFFFFFF &&
310     (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
311 }
312
313 static void getUserHome(LPTSTR userHome, LPCTSTR userId)
314 {
315   LPTSTR uh = _tgetenv (_T("USERPROFILE"));
316   if (uh)
317     {
318       _tcscpy(userHome, uh);
319     }
320   else
321     {
322       // Make a half-hearted attempt to support this
323       // legacy version of Windows. Try %WINDIR%\Profiles\%USERNAME%
324       // and failing this, use %WINDIR%.
325       //
326       // See:http://java.sun.com/docs/books/tutorial/security1.2/summary/files.html#UserPolicy
327       //
328       // To do this correctly, we'd have to factor in the
329       // Windows version, but if we did that, then this attempt
330       // wouldn't be half-hearted.
331       TCHAR userHomePath[MAX_PATH], winHome[MAX_PATH];
332       ::GetWindowsDirectory(winHome, MAX_PATH);
333         // assume this call always succeeds
334
335       _stprintf(userHomePath, _T("%s\\Profiles\\%s"), winHome, userId);
336       if (dirExists (userHomePath))
337         _tcscpy(userHome, userHomePath);
338       else
339         _tcscpy(userHome, winHome);
340     }
341 }
342
343 // Set platform-specific System properties.
344 void
345 _Jv_platform_initProperties (java::util::Properties* newprops)
346 {
347   // A convenience define.
348 #define SET(Prop,Val) \
349   newprops->put(JvNewStringLatin1 (Prop), _Jv_Win32NewString (Val))
350
351   SET ("file.separator", _T("\\"));
352   SET ("path.separator", _T(";"));
353   SET ("line.separator", _T("\r\n"));
354
355   // Use GetCurrentDirectory to set 'user.dir'.
356   DWORD buflen = MAX_PATH;
357   TCHAR buffer[buflen];
358   if (buffer != NULL)
359     {
360       if (GetCurrentDirectory (buflen, buffer))
361   SET ("user.dir", buffer);
362
363       if (GetTempPath (buflen, buffer))
364   SET ("java.io.tmpdir", buffer);
365     }
366
367   // Use GetUserName to set 'user.name'.
368   buflen = 257;  // UNLEN + 1
369   TCHAR userName[buflen];
370   if (GetUserName (userName, &buflen))
371     SET ("user.name", userName);
372
373   // Set user.home
374   TCHAR userHome[MAX_PATH];
375   getUserHome(userHome, userName);
376   SET ("user.home", userHome);
377
378   // Get and set some OS info.
379   OSVERSIONINFO osvi;
380   ZeroMemory (&osvi, sizeof(OSVERSIONINFO));
381   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
382   if (GetVersionEx (&osvi))
383     {
384       if (buffer != NULL)
385         {
386           _stprintf (buffer, _T("%d.%d"), (int) osvi.dwMajorVersion,
387            (int) osvi.dwMinorVersion);
388           SET ("os.version", buffer);
389         }
390
391       switch (osvi.dwPlatformId)
392         {
393           case VER_PLATFORM_WIN32_WINDOWS:
394             if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
395               SET ("os.name", _T("Windows 95"));
396             else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
397               SET ("os.name", _T("Windows 98"));
398             else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
399               SET ("os.name", _T("Windows Me"));
400             else
401               SET ("os.name", _T("Windows ??"));
402             break;
403
404           case VER_PLATFORM_WIN32_NT:
405             if (osvi.dwMajorVersion <= 4 )
406               SET ("os.name", _T("Windows NT"));
407             else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
408               SET ("os.name", _T("Windows 2000"));
409             else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
410               SET ("os.name", _T("Windows XP"));
411             else
412               SET ("os.name", _T("Windows NT ??"));
413             break;
414
415           default:
416             SET ("os.name", _T("Windows UNKNOWN"));
417             break;
418        }
419   }
420
421   // Set the OS architecture.
422   SYSTEM_INFO si;
423   GetSystemInfo (&si);
424   switch (si.wProcessorArchitecture)
425     {
426       case PROCESSOR_ARCHITECTURE_INTEL:
427         SET ("os.arch", _T("x86"));
428         break;
429       case PROCESSOR_ARCHITECTURE_MIPS:
430         SET ("os.arch", _T("mips"));
431         break;
432       case PROCESSOR_ARCHITECTURE_ALPHA:
433         SET ("os.arch", _T("alpha"));
434         break;
435       case PROCESSOR_ARCHITECTURE_PPC:  
436         SET ("os.arch", _T("ppc"));
437         break;
438       case PROCESSOR_ARCHITECTURE_IA64:
439         SET ("os.arch", _T("ia64"));
440         break;
441       case PROCESSOR_ARCHITECTURE_UNKNOWN:
442       default:
443         SET ("os.arch", _T("unknown"));
444         break;
445     }
446 }
447
448 int
449 _Jv_pipe (int filedes[2])
450 {
451   return _pipe (filedes, 4096, _O_BINARY);
452 }
453
454 void
455 _Jv_platform_close_on_exec (HANDLE h)
456 {
457   // Mark the handle as non-inheritable. This has
458   // no effect under Win9X.
459   SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
460 }
461
462 // Given an address, find the object that defines it and the nearest
463 // defined symbol to that address.  Returns 0 if no object defines this
464 // address.
465 int
466 _Jv_platform_dladdr (void *addr, _Jv_AddrInfo *info)
467 {
468   // Since we do not have dladdr() on Windows, we use a trick involving
469   // VirtualQuery() to find the module (EXE or DLL) that contains a given
470   // address.  This was taken from Matt Pietrek's "Under the Hood" column
471   // for the April 1997 issue of Microsoft Systems Journal.
472
473   MEMORY_BASIC_INFORMATION mbi;
474   if (!VirtualQuery (addr, &mbi, sizeof (mbi)))
475   {
476     return 0;
477   }
478   
479   HMODULE hMod = (HMODULE) mbi.AllocationBase;
480
481   char moduleName[MAX_PATH];
482
483   // FIXME: We explicitly use the ANSI variant of the function here.
484   if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
485   {
486     return 0;
487   }
488
489   char *file_name = (char *)(malloc (strlen (moduleName) + 1));
490   strcpy (file_name, moduleName);
491   info->file_name = file_name;
492
493   // FIXME.
494   info->base = NULL;
495   info->sym_name = NULL;
496   info->sym_addr = NULL;
497
498   return 1;
499 }