1 /*
   2  * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <stdlib.h>
  27 #include <string.h>
  28 #include <windows.h>
  29 #include <locale.h>
  30 
  31 #include "jni.h"
  32 #include "jni_util.h"
  33 
  34 static void getParent(const TCHAR *path, TCHAR *dest) {
  35     char* lastSlash = max(strrchr(path, '\\'), strrchr(path, '/'));
  36     if (lastSlash == NULL) {
  37         *dest = 0;
  38         return;
  39     }
  40     if (path != dest)
  41         strcpy(dest, path);
  42     *lastSlash = 0;
  43 }
  44 
  45 BOOL useNativeConverter(JNIEnv *env) {
  46     static BOOL initialized;
  47     static BOOL useNative;
  48     if (!initialized) {
  49         HMODULE jvm = GetModuleHandle("jvm");
  50         useNative = FALSE;
  51         if (jvm != NULL) {
  52             TCHAR *jvmPath = NULL;
  53             int bufferSize = MAX_PATH;
  54             while (jvmPath == NULL) {
  55                 DWORD result;
  56                 jvmPath = malloc(bufferSize);
  57                 if (jvmPath == NULL)
  58                     return FALSE;
  59                 result = GetModuleFileName(jvm, jvmPath, bufferSize);
  60                 if (result == 0)
  61                     return FALSE;
  62                 if (result == bufferSize) { // didn't fit
  63                     bufferSize += MAX_PATH; // increase buffer size, try again
  64                     free(jvmPath);
  65                     jvmPath = NULL;
  66                 }
  67             }
  68 
  69             getParent(jvmPath, jvmPath);
  70             useNative = (!strcmp("kernel", jvmPath + strlen(jvmPath) -
  71                     strlen("kernel"))); // true if jvm.dll lives in "kernel"
  72             if (useNative)
  73                 setlocale(LC_ALL, "");
  74             free(jvmPath);
  75         }
  76         initialized = TRUE;
  77     }
  78     return useNative;
  79 }
  80 
  81 jstring nativeNewStringPlatform(JNIEnv *env, const char *str) {
  82     static jmethodID String_char_constructor;
  83     if (useNativeConverter(env)) {
  84         // use native Unicode conversion so Kernel isn't required during
  85         // System.initProperties
  86         jcharArray chars = 0;
  87         wchar_t *utf16;
  88         int len;
  89         jstring result = NULL;
  90 
  91         if (getFastEncoding() == NO_ENCODING_YET)
  92             initializeEncoding(env);
  93 
  94         len = mbstowcs(NULL, str, strlen(str));
  95         if (len == -1)
  96             return NULL;
  97         utf16 = calloc(len + 1, 2);
  98         if (mbstowcs(utf16, str, len) == -1)
  99             return NULL;
 100         chars = (*env)->NewCharArray(env, len);
 101         if (chars == NULL)
 102             return NULL;
 103         (*env)->SetCharArrayRegion(env, chars, 0, len, utf16);
 104         if (String_char_constructor == NULL)
 105             String_char_constructor = (*env)->GetMethodID(env,
 106                     JNU_ClassString(env), "<init>", "([C)V");
 107         result = (*env)->NewObject(env, JNU_ClassString(env),
 108                 String_char_constructor, chars);
 109         free(utf16);
 110         return result;
 111     }
 112     else
 113         return NULL;
 114 }
 115 
 116 
 117 char* nativeGetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy) {
 118     if (useNativeConverter(env)) {
 119         // use native Unicode conversion so Kernel isn't required during
 120         // System.initProperties
 121         char *result = NULL;
 122         size_t len;
 123         const jchar* utf16 = (*env)->GetStringChars(env, jstr, NULL);
 124         len = wcstombs(NULL, utf16, (*env)->GetStringLength(env, jstr) * 4) + 1;
 125         if (len == -1)
 126             return NULL;
 127         result = (char*) malloc(len);
 128         if (result != NULL) {
 129             if (wcstombs(result, utf16, len) == -1)
 130                 return NULL;
 131             (*env)->ReleaseStringChars(env, jstr, utf16);
 132             if (isCopy)
 133                 *isCopy = JNI_TRUE;
 134         }
 135         return result;
 136     }
 137     else
 138         return NULL;
 139 }
 140 
 141 void* getProcessHandle() {
 142     return (void*)GetModuleHandle(NULL);
 143 }
 144 
 145 /*
 146  * Windows symbols can be simple like JNI_OnLoad or __stdcall format
 147  * like _JNI_OnLoad@8. We need to handle both.
 148  */
 149 void buildJniFunctionName(const char *sym, const char *cname,
 150                           char *jniEntryName) {
 151     if (cname != NULL) {
 152         char *p = strrchr(sym, '@');
 153         if (p != NULL && p != sym) {
 154             // sym == _JNI_OnLoad@8
 155             strncpy(jniEntryName, sym, (p - sym));
 156             jniEntryName[(p-sym)] = '\0';
 157             // jniEntryName == _JNI_OnLoad
 158             strcat(jniEntryName, "_");
 159             strcat(jniEntryName, cname);
 160             strcat(jniEntryName, p);
 161             //jniEntryName == _JNI_OnLoad_cname@8
 162         } else {
 163             strcpy(jniEntryName, sym);
 164             strcat(jniEntryName, "_");
 165             strcat(jniEntryName, cname);
 166         }
 167     } else {
 168         strcpy(jniEntryName, sym);
 169     }
 170     return;
 171 }