/* * @(#) $(JCGO)/native/jcgojnu.c -- * a part of the JCGO native layer library (native layer API implementation). ** * Project: JCGO (http://www.ivmaisoft.com/jcgo/) * Copyright (C) 2001-2013 Ivan Maidanski * All rights reserved. */ /* * Used control macros: JCGO_DOWCSTOMBS, JCGO_HUGEARR, JCGO_NOJNI, * JCGO_SYSWCHAR, JCGO_THREADS, JCGO_UTFWCTOMB, JCGO_WMAIN. * Macros for tuning: JNUBIGEXPORT. */ /* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. ** * This software is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ #define JCGO_BUILDING_JNU #ifdef JCGO_VER #include "jcgojnu.h" #else #include "jcgojnu.h" #ifdef JCGO_NOJNI #ifndef JCGO_SEPARATED #define JCGO_SEPARATED #endif #include "jcgortl.h" jint *JNICALL jcgo_jnuStringLengthPtr( jstring str ); jchar *JNICALL jcgo_jnuStringChars( jstring str, int *pisbytes ); jstring JNICALL jcgo_jnuStringCreate( JNIEnv *pJniEnv, jint len ); #endif #endif #ifdef JCGO_VER #ifndef JCGO_UTFWCTOMB /* #include */ /* const int MB_CUR_MAX; */ #ifdef JCGO_DOWCSTOMBS /* #include */ /* size_t mbstowcs(wchar_t *, const char *, size_t); */ /* size_t wcstombs(char *, const wchar_t *, size_t); */ #else /* #include */ /* int mbtowc(wchar_t *, const char *, size_t); */ /* int wctomb(char *, wchar_t); */ #endif #ifndef _LIMITS_H #include #endif #ifndef MB_LEN_MAX #define MB_LEN_MAX 6 #endif #endif /* !JCGO_UTFWCTOMB */ #ifndef JNUBIGEXPORT #define JNUBIGEXPORT JNIEXPORT #endif #ifndef JCGO_JNUMSG_BADARG #define JCGO_JNUMSG_BADARG "" /* in 'UTF-8' encoding */ #endif #ifndef JCGO_NOJNI #ifndef JCGO_ALLOCSIZE_T #ifdef JCGO_HUGEARR #define JCGO_ALLOCSIZE_T unsigned long #else #define JCGO_ALLOCSIZE_T unsigned #endif #endif #endif #ifndef JCGO_HPTR_MOD #ifdef JCGO_HUGEARR #define JCGO_HPTR_MOD __huge #else #define JCGO_HPTR_MOD /* empty */ #endif #endif #ifndef JCGO_JNUNEWSTRING_WBUFSIZE #define JCGO_JNUNEWSTRING_WBUFSIZE 128 #endif #ifdef JCGO_NOJNI JNIEXPORT #else JNUBIGEXPORT #endif jbyte *JNICALL jcgo_JnuGetByteArrayElemsRegion( JNIEnv *pJniEnv, jbyteArray arr, jint offset, jint len ) { #ifdef JCGO_NOJNI JCGO_UNUSED_VAR(pJniEnv); JCGO_UNUSED_VAR(len); return (jbyte *)&JCGO_ARR_INTERNALACC(jbyte, (jbyteArr)arr, offset); #else jbyte *bytes = (*pJniEnv)->GetByteArrayElements(pJniEnv, arr, NULL); if (bytes == NULL) return NULL; if ((offset | len) < 0 || (*pJniEnv)->GetArrayLength(pJniEnv, (jarray)arr) - offset < len) { (*pJniEnv)->FatalError(pJniEnv, JCGO_JNUMSG_BADARG); return NULL; } return (jbyte *)((jbyte JCGO_HPTR_MOD *)bytes + (JCGO_ALLOCSIZE_T)offset); #endif } JNIEXPORT void JNICALL jcgo_JnuReleaseByteArrayElemsRegion( JNIEnv *pJniEnv, jbyteArray arr, jbyte *bytes, jint offset ) { #ifdef JCGO_NOJNI JCGO_UNUSED_VAR(pJniEnv); JCGO_UNUSED_VAR(arr); JCGO_UNUSED_VAR(bytes); JCGO_UNUSED_VAR(offset); #else (*pJniEnv)->ReleaseByteArrayElements(pJniEnv, arr, (jbyte *)((jbyte JCGO_HPTR_MOD *)bytes - (JCGO_ALLOCSIZE_T)offset), 0); #endif } JNIEXPORT jint JNICALL jcgo_JnuGetIntArrayElement( JNIEnv *pJniEnv, jintArray arr, jint index ) { #ifdef JCGO_NOJNI JCGO_UNUSED_VAR(pJniEnv); return JCGO_ARR_INTERNALACC(jint, (jintArr)arr, index); #else jint value = 0; (*pJniEnv)->GetIntArrayRegion(pJniEnv, arr, (jsize)index, 1, &value); return value; #endif } JNIEXPORT void JNICALL jcgo_JnuSetIntArrayElement( JNIEnv *pJniEnv, jintArray arr, jint index, jint value ) { #ifdef JCGO_NOJNI JCGO_UNUSED_VAR(pJniEnv); JCGO_ARR_INTERNALACC(jint, (jintArr)arr, index) = value; #else (*pJniEnv)->SetIntArrayRegion(pJniEnv, arr, (jsize)index, 1, &value); #endif } JNIEXPORT void JNICALL jcgo_JnuSetLongArrayElement( JNIEnv *pJniEnv, jlongArray arr, jint index, jlong value ) { #ifdef JCGO_NOJNI JCGO_UNUSED_VAR(pJniEnv); JCGO_ARR_INTERNALACC(jlong, (jlongArr)arr, index) = value; #else (*pJniEnv)->SetLongArrayRegion(pJniEnv, arr, (jsize)index, 1, &value); #endif } JNUBIGEXPORT unsigned JNICALL jcgo_JnuStringSizeOfPlatform( JNIEnv *pJniEnv, jstring str ) { unsigned len = 0; #ifdef JCGO_NOJNI jint count = *jcgo_jnuStringLengthPtr(str); JCGO_UNUSED_VAR(pJniEnv); #else jint count = (jint)(*pJniEnv)->GetStringLength(pJniEnv, str); #endif if (count > 0) { #ifdef JCGO_UTFWCTOMB len = count <= (jint)(((((unsigned)-1) >> 1) - 16) / 3) ? (unsigned)count * 3 : (((unsigned)-1) >> 1) - (unsigned)16; #else len = (unsigned)count; if (count > (jint)((((unsigned)-1) >> 1) - 16)) len = (((unsigned)-1) >> 1) - (unsigned)16; #ifdef MB_CUR_MAX count = (jint)MB_CUR_MAX; if (count != 1) #endif { #ifdef MB_CUR_MAX if ((unsigned)count < (unsigned)MB_LEN_MAX && *(volatile jint *)&count != 0) len = ((((unsigned)-1) >> 1) - (unsigned)16) / (unsigned)count >= len ? (unsigned)count * len : (((unsigned)-1) >> 1) - (unsigned)16; else #endif { len = len <= ((((unsigned)-1) >> 1) - (unsigned)16) / (unsigned)MB_LEN_MAX ? len * (unsigned)MB_LEN_MAX : (((unsigned)-1) >> 1) - (unsigned)16; } } #endif } return len + 1; } JNUBIGEXPORT int JNICALL jcgo_JnuStringToPlatformChars( JNIEnv *pJniEnv, jstring str, char *cbuf, unsigned size ) { int cnt; int i; unsigned pos; unsigned len; int noerr = -1; jint count; CONST jchar JCGO_HPTR_MOD *chars; #ifdef JCGO_NOJNI int isbytes; #endif #ifdef JCGO_UTFWCTOMB jchar wch; #else int res; #ifdef JCGO_DOWCSTOMBS wchar_t wbuf[2]; #else int j; char mbbuf[MB_LEN_MAX]; #endif #endif if (cbuf != NULL && size) { #ifdef JCGO_NOJNI JCGO_UNUSED_VAR(pJniEnv); chars = jcgo_jnuStringChars(str, &isbytes); count = *jcgo_jnuStringLengthPtr(str); #else chars = (*pJniEnv)->GetStringChars(pJniEnv, str, NULL); if (chars == NULL) return noerr; count = (jint)(*pJniEnv)->GetStringLength(pJniEnv, str); #endif len = (((unsigned)-1) >> 1) - (unsigned)16; pos = 0; noerr = 1; if (size <= len) len = size - 1; cnt = (int)len; if ((jint)cnt > count) cnt = (int)count; #ifndef JCGO_UTFWCTOMB #ifdef JCGO_DOWCSTOMBS wbuf[1] = (wchar_t)0; #else *(volatile char *)&mbbuf[0] = (char)wctomb(NULL, (wchar_t)0); #endif #endif for (i = 0; i < cnt; i++) { #ifdef JCGO_UTFWCTOMB #ifdef JCGO_NOJNI wch = isbytes ? (unsigned char)(*((volatile jbyte JCGO_HPTR_MOD *)chars + (unsigned)i)) : *(chars + (unsigned)i); #else wch = *(chars + (unsigned)i); #endif if (wch < 0x80 && wch) { if (pos >= len) break; cbuf[pos] = (char)wch; } else { if (wch < 0x800) { if (pos + 1 >= len) break; cbuf[pos] = (char)((wch >> 6) | 0xc0); } else { if (pos + 2 >= len) break; cbuf[pos] = (char)((wch >> 12) | 0xe0); cbuf[pos + 1] = (char)(((wch >> 6) & 0x3f) | 0x80); pos++; } cbuf[++pos] = (char)((wch & 0x3f) | 0x80); } pos++; #else #ifdef JCGO_DOWCSTOMBS #ifdef JCGO_NOJNI wbuf[0] = (wchar_t)(isbytes ? (unsigned char)(*((volatile jbyte JCGO_HPTR_MOD *)chars + (unsigned)i)) : *(chars + (unsigned)i)); #else wbuf[0] = (wchar_t)(*(chars + (unsigned)i)); #endif res = (int)wcstombs(&cbuf[pos], wbuf, len - pos); #else #ifdef JCGO_NOJNI res = wctomb(len - pos < sizeof(mbbuf) ? mbbuf : &cbuf[pos], (wchar_t)(isbytes ? (unsigned char)(*((volatile jbyte JCGO_HPTR_MOD *)chars + (unsigned)i)) : *(chars + (unsigned)i))); #else res = wctomb(len - pos < sizeof(mbbuf) ? mbbuf : &cbuf[pos], (wchar_t)(*(chars + (unsigned)i))); #endif #endif if (res > 0) { #ifndef JCGO_DOWCSTOMBS if (len - pos < sizeof(mbbuf)) { if (pos + (unsigned)res > len) break; for (j = 0; j < res; j++) cbuf[pos + j] = mbbuf[j]; } #endif pos = (unsigned)res + pos; } else { if (pos >= len) break; if (res < 0) { noerr = 0; cbuf[pos++] = '?'; } else cbuf[pos++] = '\0'; } #endif } #ifndef JCGO_NOJNI (*pJniEnv)->ReleaseStringChars(pJniEnv, str, (CONST jchar *)chars); #endif if ((jint)i < count) { noerr = 0; if (pos < len) cbuf[pos++] = '?'; else { if (len) cbuf[len - 1] = '?'; } } cbuf[pos] = '\0'; } #ifndef JCGO_NOJNI else (*pJniEnv)->FatalError(pJniEnv, JCGO_JNUMSG_BADARG); #endif return noerr; } JNUBIGEXPORT jstring JNICALL jcgo_JnuNewStringPlatform( JNIEnv *pJniEnv, CONST char *cstr ) { #ifdef JCGO_UTFWCTOMB jchar wch; char ch; unsigned pos; #else #ifndef JCGO_DOWCSTOMBS wchar_t wch; int res; unsigned pos; #endif #endif unsigned len = 0; int i = (int)(((unsigned)-1) >> 1) - 16; jstring str = NULL; jchar *chars; #ifndef JCGO_NOJNI jcharArray arr; jchar buf[JCGO_JNUNEWSTRING_WBUFSIZE]; #endif if (cstr != NULL) { while (*(cstr + len)) len++; if (len >= (unsigned)i) len = (unsigned)i; #ifdef JCGO_NOJNI str = jcgo_jnuStringCreate(pJniEnv, (jint)len); chars = NULL; if (str != NULL) chars = jcgo_jnuStringChars(str, &i); #else arr = NULL; chars = buf; if (len > sizeof(buf) / sizeof(jchar)) { arr = (*pJniEnv)->NewCharArray(pJniEnv, (jsize)len); chars = NULL; if (arr != NULL) chars = (*pJniEnv)->GetCharArrayElements(pJniEnv, arr, NULL); } #endif if (chars != NULL) { i = 0; #ifdef JCGO_UTFWCTOMB for (pos = 0; pos < len; pos++) { wch = (unsigned char)cstr[pos]; if (wch >= 0x80 && (wch > 0xef || ((ch = cstr[++pos]) & 0xc0) != 0x80 || (wch < 0xe0 ? (wch = (jchar)(((wch & 0x1f) << 6) | (ch & 0x3f))) < 0x80 && wch : (wch = (jchar)((wch << 12) | ((jchar)(ch & 0x3f) << 6) | (cstr[++pos] & 0x3f))) < 0x800 || (cstr[pos] & 0xc0) != 0x80))) { *chars = (jchar)0x3f; /*'?'*/ if (i <= 0) i = 1; break; } *(chars + (i++)) = wch; } #else #ifdef JCGO_DOWCSTOMBS if (len && (i = (int)mbstowcs(chars, cstr, len)) < 0) { *chars = (jchar)0x3f; /*'?'*/ for (i = 1; i < (int)len; i++) if (!(*(chars + i))) break; } #else *(volatile wchar_t *)&wch = (wchar_t)mbtowc(&wch, NULL, 0); for (pos = 0; pos < len; pos = (unsigned)res + pos) { if ((res = mbtowc(&wch, cstr + pos, len - pos + 1)) <= 0) { if (!res) break; if ((res = mbtowc(&wch, cstr + pos, 1)) <= 0) { if (!res) break; *chars = (jchar)0x3f; /*'?'*/ if (i <= 0) i = 1; break; } } *(chars + (i++)) = (jchar)wch; } #endif #endif #ifdef JCGO_NOJNI *jcgo_jnuStringLengthPtr(str) = i; #else str = (*pJniEnv)->NewString(pJniEnv, chars, (jsize)i); if (arr != NULL) (*pJniEnv)->ReleaseCharArrayElements(pJniEnv, arr, chars, 0); #endif } #ifndef JCGO_NOJNI if (arr != NULL) (*pJniEnv)->DeleteLocalRef(pJniEnv, (jobject)arr); #endif } #ifndef JCGO_NOJNI else (*pJniEnv)->FatalError(pJniEnv, JCGO_JNUMSG_BADARG); #endif return str; } #ifdef JCGO_SYSWCHAR JNIEXPORT unsigned JNICALL jcgo_JnuStringSizeOfWide( JNIEnv *pJniEnv, jstring str ) { #ifdef JCGO_NOJNI jint count = *jcgo_jnuStringLengthPtr(str); JCGO_UNUSED_VAR(pJniEnv); #else jint count = (jint)(*pJniEnv)->GetStringLength(pJniEnv, str); #endif return count > 0 ? (count < (jint)(((((unsigned)-1) >> 1) - 16) / sizeof(wchar_t)) ? ((unsigned)count + 1) * sizeof(wchar_t) : (((unsigned)-1) >> 1) + sizeof(wchar_t) - 16) : sizeof(wchar_t); } JNUBIGEXPORT int JNICALL jcgo_JnuStringToWideChars( JNIEnv *pJniEnv, jstring str, wchar_t *wbuf, unsigned size ) { int cnt; int i; int noerr = -1; jint count; CONST jchar JCGO_HPTR_MOD *chars; #ifdef JCGO_NOJNI int isbytes; #endif if (wbuf != NULL && size >= sizeof(wchar_t)) { #ifdef JCGO_NOJNI JCGO_UNUSED_VAR(pJniEnv); chars = jcgo_jnuStringChars(str, &isbytes); count = *jcgo_jnuStringLengthPtr(str); #else chars = (*pJniEnv)->GetStringChars(pJniEnv, str, NULL); if (chars == NULL) return noerr; count = (jint)(*pJniEnv)->GetStringLength(pJniEnv, str); #endif cnt = (int)(((unsigned)-1) >> 1) - 16; if (size <= (unsigned)cnt) cnt = (int)size; cnt = (int)((unsigned)cnt / sizeof(wchar_t)) - 1; noerr = 1; if ((jint)cnt < count) { noerr = 0; if (cnt) wbuf[cnt - 1] = (wchar_t)0x3f; /*'?'*/ } else cnt = (int)count; #ifdef JCGO_NOJNI if (isbytes) { for (i = 0; i < cnt; i++) wbuf[i] = (wchar_t)((unsigned char)( *((volatile jbyte JCGO_HPTR_MOD *)chars + i))); } else { for (i = 0; i < cnt; i++) wbuf[i] = (wchar_t)(*(chars + i)); } #else for (i = 0; i < cnt; i++) wbuf[i] = (wchar_t)(*(chars + i)); (*pJniEnv)->ReleaseStringChars(pJniEnv, str, (CONST jchar *)chars); #endif wbuf[cnt] = (wchar_t)0; } #ifndef JCGO_NOJNI else (*pJniEnv)->FatalError(pJniEnv, JCGO_JNUMSG_BADARG); #endif return noerr; } #else /* JCGO_SYSWCHAR */ #ifndef JCGO_WMAIN #define JCGO_EXCLUDE_NEWSTRINGWIDE #endif #endif /* ! JCGO_SYSWCHAR */ #ifndef JCGO_EXCLUDE_NEWSTRINGWIDE JNUBIGEXPORT jstring JNICALL jcgo_JnuNewStringWide( JNIEnv *pJniEnv, CONST wchar_t *wstr ) { unsigned len = 0; int i = (int)(((((unsigned)-1) >> 1) - 16) / sizeof(wchar_t)); jstring str = NULL; jchar *chars; #ifndef JCGO_NOJNI jcharArray arr; jchar buf[JCGO_JNUNEWSTRING_WBUFSIZE]; #endif if (wstr != NULL) { while (*(wstr + len)) len++; if (len >= (unsigned)i) len = (unsigned)i; #ifdef JCGO_NOJNI str = jcgo_jnuStringCreate(pJniEnv, (jint)len); chars = NULL; if (str != NULL) chars = jcgo_jnuStringChars(str, &i); #else arr = NULL; chars = buf; if (len > sizeof(buf) / sizeof(jchar)) { arr = (*pJniEnv)->NewCharArray(pJniEnv, (jsize)len); chars = NULL; if (arr != NULL) chars = (*pJniEnv)->GetCharArrayElements(pJniEnv, arr, NULL); } #endif if (chars != NULL) { for (i = 0; i < (int)len; i++) *(chars + i) = (jchar)(*(wstr + i)); #ifdef JCGO_NOJNI *jcgo_jnuStringLengthPtr(str) = (int)len; #else str = (*pJniEnv)->NewString(pJniEnv, chars, (jsize)len); if (arr != NULL) (*pJniEnv)->ReleaseCharArrayElements(pJniEnv, arr, chars, 0); #endif } #ifndef JCGO_NOJNI if (arr != NULL) (*pJniEnv)->DeleteLocalRef(pJniEnv, (jobject)arr); #endif } #ifndef JCGO_NOJNI else (*pJniEnv)->FatalError(pJniEnv, JCGO_JNUMSG_BADARG); #endif return str; } #endif /* ! JCGO_EXCLUDE_NEWSTRINGWIDE */ #endif