1/*
2 * Copyright (c) 2004, 2014, 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
34static 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
45void* getProcessHandle() {
46    return (void*)GetModuleHandle(NULL);
47}
48
49/*
50 * Windows symbols can be simple like JNI_OnLoad or __stdcall format
51 * like _JNI_OnLoad@8. We need to handle both.
52 */
53void buildJniFunctionName(const char *sym, const char *cname,
54                          char *jniEntryName) {
55    if (cname != NULL) {
56        char *p = strrchr(sym, '@');
57        if (p != NULL && p != sym) {
58            // sym == _JNI_OnLoad@8
59            strncpy(jniEntryName, sym, (p - sym));
60            jniEntryName[(p-sym)] = '\0';
61            // jniEntryName == _JNI_OnLoad
62            strcat(jniEntryName, "_");
63            strcat(jniEntryName, cname);
64            strcat(jniEntryName, p);
65            //jniEntryName == _JNI_OnLoad_cname@8
66        } else {
67            strcpy(jniEntryName, sym);
68            strcat(jniEntryName, "_");
69            strcat(jniEntryName, cname);
70        }
71    } else {
72        strcpy(jniEntryName, sym);
73    }
74    return;
75}
76
77size_t
78getLastErrorString(char *utf8_jvmErrorMsg, size_t cbErrorMsg)
79{
80    size_t n = 0;
81    if (cbErrorMsg > 0) {
82        BOOLEAN noError = FALSE;
83        WCHAR *utf16_osErrorMsg = (WCHAR *)malloc(cbErrorMsg*sizeof(WCHAR));
84        if (utf16_osErrorMsg == NULL) {
85            // OOM accident
86            strncpy(utf8_jvmErrorMsg, "Out of memory", cbErrorMsg);
87            // truncate if too long
88            utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0';
89            n = strlen(utf8_jvmErrorMsg);
90        } else {
91            DWORD errval = GetLastError();
92            if (errval != 0) {
93                // WIN32 error
94                n = (size_t)FormatMessageW(
95                    FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
96                    NULL,
97                    errval,
98                    0,
99                    utf16_osErrorMsg,
100                    (DWORD)cbErrorMsg,
101                    NULL);
102                if (n > 3) {
103                    // Drop final '.', CR, LF
104                    if (utf16_osErrorMsg[n - 1] == L'\n') --n;
105                    if (utf16_osErrorMsg[n - 1] == L'\r') --n;
106                    if (utf16_osErrorMsg[n - 1] == L'.') --n;
107                    utf16_osErrorMsg[n] = L'\0';
108                }
109            } else if (errno != 0) {
110                // C runtime error that has no corresponding WIN32 error code
111                int ret = _wcserror_s(utf16_osErrorMsg, cbErrorMsg, errno);
112                if (ret == 0)
113                    n = wcslen(utf16_osErrorMsg);
114            } else
115                noError = TRUE; //OS has no error to report
116
117            if (!noError) {
118                if (n > 0) {
119                    n = WideCharToMultiByte(
120                        CP_UTF8,
121                        0,
122                        utf16_osErrorMsg,
123                        (int)n,
124                        utf8_jvmErrorMsg,
125                        (int)cbErrorMsg,
126                        NULL,
127                        NULL);
128
129                    // no way to die
130                    if (n > 0)
131                        utf8_jvmErrorMsg[min(cbErrorMsg - 1, n)] = '\0';
132                }
133
134                if (n <= 0) {
135                    strncpy(utf8_jvmErrorMsg, "Secondary error while OS message extraction", cbErrorMsg);
136                    // truncate if too long
137                    utf8_jvmErrorMsg[cbErrorMsg - 1] = '\0';
138                    n = strlen(utf8_jvmErrorMsg);
139                }
140            }
141            free(utf16_osErrorMsg);
142        }
143    }
144    return n;
145}
146
147int
148getErrorString(int err, char *buf, size_t len)
149{
150    int ret = 0;
151    if (err == 0 || len < 1) return 0;
152    ret = strerror_s(buf, len, err);
153    return ret;
154}
155