0N/A/*
239N/A * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
157N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
157N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
157N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
157N/A * or visit www.oracle.com if you need additional information or have any
157N/A * questions.
0N/A */
0N/A
0N/A#include <setjmp.h>
0N/A#include <stdlib.h>
0N/A#include <string.h>
0N/A
0N/A#include "jni.h"
0N/A#include "jvm.h"
0N/A
0N/Atypedef unsigned short unicode;
0N/A
0N/Astatic char *
0N/Askip_over_fieldname(char *name, jboolean slash_okay,
0N/A unsigned int len);
0N/Astatic char *
0N/Askip_over_field_signature(char *name, jboolean void_okay,
0N/A unsigned int len);
0N/A
0N/A/*
0N/A * Return non-zero if the character is a valid in JVM class name, zero
0N/A * otherwise. The only characters currently disallowed from JVM class
193N/A * names are given in the table below:
0N/A *
0N/A * Character Hex Decimal
0N/A * '.' 0x2e 46
0N/A * '/' 0x2f 47
0N/A * ';' 0x3b 59
0N/A * '[' 0x5b 91
0N/A *
0N/A * (Method names have further restrictions dealing with the '<' and
0N/A * '>' characters.)
0N/A */
0N/Astatic int isJvmIdentifier(unicode ch) {
0N/A if( ch > 91 || ch < 46 )
110N/A return 1; /* Lowercase ASCII letters are > 91 */
110N/A else { /* 46 <= ch <= 91 */
110N/A if (ch <= 90 && ch >= 60) {
110N/A return 1; /* Uppercase ASCII recognized here */
110N/A } else { /* ch == 91 || 46 <= ch <= 59 */
110N/A if (ch == 91 || ch == 59 || ch <= 47)
110N/A return 0;
110N/A else
110N/A return 1;
0N/A }
0N/A }
0N/A}
110N/A
110N/Astatic unicode
110N/Anext_utf2unicode(char **utfstring_ptr, int * valid)
0N/A{
0N/A unsigned char *ptr = (unsigned char *)(*utfstring_ptr);
0N/A unsigned char ch, ch2, ch3;
0N/A int length = 1; /* default length */
0N/A unicode result = 0x80; /* default bad result; */
0N/A *valid = 1;
0N/A switch ((ch = ptr[0]) >> 4) {
0N/A default:
0N/A result = ch;
0N/A break;
0N/A
0N/A case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
0N/A /* Shouldn't happen. */
0N/A *valid = 0;
0N/A break;
0N/A
0N/A case 0xC: case 0xD:
0N/A /* 110xxxxx 10xxxxxx */
0N/A if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
0N/A unsigned char high_five = ch & 0x1F;
0N/A unsigned char low_six = ch2 & 0x3F;
0N/A result = (high_five << 6) + low_six;
0N/A length = 2;
0N/A }
0N/A break;
0N/A
0N/A case 0xE:
0N/A /* 1110xxxx 10xxxxxx 10xxxxxx */
0N/A if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
0N/A if (((ch3 = ptr[2]) & 0xC0) == 0x80) {
0N/A unsigned char high_four = ch & 0x0f;
0N/A unsigned char mid_six = ch2 & 0x3f;
0N/A unsigned char low_six = ch3 & 0x3f;
0N/A result = (((high_four << 6) + mid_six) << 6) + low_six;
0N/A length = 3;
0N/A } else {
0N/A length = 2;
0N/A }
0N/A }
0N/A break;
0N/A } /* end of switch */
110N/A
110N/A *utfstring_ptr = (char *)(ptr + length);
110N/A return result;
110N/A}
0N/A
0N/A/* Take pointer to a string. Skip over the longest part of the string that
0N/A * could be taken as a fieldname. Allow '/' if slash_okay is JNI_TRUE.
51N/A *
51N/A * Return a pointer to just past the fieldname. Return NULL if no fieldname
51N/A * at all was found, or in the case of slash_okay being true, we saw
99N/A * consecutive slashes (meaning we were looking for a qualified path but
110N/A * found something that was badly-formed).
110N/A */
0N/Astatic char *
0N/Askip_over_fieldname(char *name, jboolean slash_okay,
99N/A unsigned int length)
99N/A{
0N/A char *p;
0N/A unicode ch;
0N/A unicode last_ch = 0;
0N/A int valid = 1;
0N/A /* last_ch == 0 implies we are looking at the first char. */
0N/A for (p = name; p != name + length; last_ch = ch) {
0N/A char *old_p = p;
0N/A ch = *p;
0N/A if (ch < 128) {
0N/A p++;
0N/A if (isJvmIdentifier(ch)) {
0N/A continue;
0N/A }
0N/A } else {
0N/A char *tmp_p = p;
0N/A ch = next_utf2unicode(&tmp_p, &valid);
0N/A if (valid == 0)
0N/A return 0;
0N/A p = tmp_p;
0N/A if (isJvmIdentifier(ch)) {
0N/A continue;
0N/A }
0N/A }
0N/A
0N/A if (slash_okay && ch == '/' && last_ch) {
0N/A if (last_ch == '/') {
0N/A return 0; /* Don't permit consecutive slashes */
0N/A }
0N/A } else if (ch == '_' || ch == '$') {
0N/A } else {
0N/A return last_ch ? old_p : 0;
0N/A }
0N/A }
0N/A return last_ch ? p : 0;
0N/A}
0N/A
0N/A/* Take pointer to a string. Skip over the longest part of the string that
0N/A * could be taken as a field signature. Allow "void" if void_okay.
0N/A *
0N/A * Return a pointer to just past the signature. Return NULL if no legal
0N/A * signature is found.
0N/A */
0N/A
0N/Astatic char *
0N/Askip_over_field_signature(char *name, jboolean void_okay,
0N/A unsigned int length)
0N/A{
0N/A unsigned int array_dim = 0;
0N/A for (;length > 0;) {
0N/A switch (name[0]) {
0N/A case JVM_SIGNATURE_VOID:
0N/A if (!void_okay) return 0;
0N/A /* FALL THROUGH */
0N/A case JVM_SIGNATURE_BOOLEAN:
110N/A case JVM_SIGNATURE_BYTE:
110N/A case JVM_SIGNATURE_CHAR:
110N/A case JVM_SIGNATURE_SHORT:
110N/A case JVM_SIGNATURE_INT:
0N/A case JVM_SIGNATURE_FLOAT:
0N/A case JVM_SIGNATURE_LONG:
110N/A case JVM_SIGNATURE_DOUBLE:
108N/A return name + 1;
108N/A
108N/A case JVM_SIGNATURE_CLASS: {
110N/A /* Skip over the classname, if one is there. */
0N/A char *p =
0N/A skip_over_fieldname(name + 1, JNI_TRUE, --length);
0N/A /* The next character better be a semicolon. */
0N/A if (p && p - name - 1 > 0 && p[0] == ';')
0N/A return p + 1;
0N/A return 0;
0N/A }
0N/A
0N/A case JVM_SIGNATURE_ARRAY:
0N/A array_dim++;
0N/A /* JVMS 2nd ed. 4.10 */
0N/A /* The number of dimensions in an array is limited to 255 ... */
0N/A if (array_dim > 255) {
0N/A return 0;
}
/* The rest of what's there better be a legal signature. */
name++;
length--;
void_okay = JNI_FALSE;
break;
default:
return 0;
}
}
return 0;
}
/* Used in java/lang/Class.c */
/* Determine if the specified name is legal
* UTF name for a classname.
*
* Note that this routine expects the internal form of qualified classes:
* the dots should have been replaced by slashes.
*/
JNIEXPORT jboolean
VerifyClassname(char *name, jboolean allowArrayClass)
{
unsigned int length = strlen(name);
char *p;
if (length > 0 && name[0] == JVM_SIGNATURE_ARRAY) {
if (!allowArrayClass) {
return JNI_FALSE;
} else {
/* Everything that's left better be a field signature */
p = skip_over_field_signature(name, JNI_FALSE, length);
}
} else {
/* skip over the fieldname. Slashes are okay */
p = skip_over_fieldname(name, JNI_TRUE, length);
}
return (p != 0 && p - name == (ptrdiff_t)length);
}
/*
* Translates '.' to '/'. Returns JNI_TRUE is any / were present.
*/
JNIEXPORT jboolean
VerifyFixClassname(char *name)
{
char *p = name;
jboolean slashesFound = JNI_FALSE;
int valid = 1;
while (valid != 0 && *p != '\0') {
if (*p == '/') {
slashesFound = JNI_TRUE;
p++;
} else if (*p == '.') {
*p++ = '/';
} else {
next_utf2unicode(&p, &valid);
}
}
return slashesFound && valid != 0;
}