1/*
2 * Copyright (c) 1997, 2008, 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 <assert.h>
27#include <limits.h>
28#include <setjmp.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "jni.h"
33#include "jvm.h"
34
35typedef unsigned short unicode;
36
37static char *
38skip_over_fieldname(char *name, jboolean slash_okay,
39 unsigned int len);
40static char *
41skip_over_field_signature(char *name, jboolean void_okay,
42 unsigned int len);
43
44/*
45 * Return non-zero if the character is a valid in JVM class name, zero
46 * otherwise. The only characters currently disallowed from JVM class
47 * names are given in the table below:
48 *
49 * Character Hex Decimal
50 * '.' 0x2e 46
51 * '/' 0x2f 47
52 * ';' 0x3b 59
53 * '[' 0x5b 91
54 *
55 * (Method names have further restrictions dealing with the '<' and
56 * '>' characters.)
57 */
58static int isJvmIdentifier(unicode ch) {
59 if( ch > 91 || ch < 46 )
60 return 1; /* Lowercase ASCII letters are > 91 */
61 else { /* 46 <= ch <= 91 */
62 if (ch <= 90 && ch >= 60) {
63 return 1; /* Uppercase ASCII recognized here */
64 } else { /* ch == 91 || 46 <= ch <= 59 */
65 if (ch == 91 || ch == 59 || ch <= 47)
66 return 0;
67 else
68 return 1;
69 }
70 }
71}
72
73static unicode
74next_utf2unicode(char **utfstring_ptr, int * valid)
75{
76 unsigned char *ptr = (unsigned char *)(*utfstring_ptr);
77 unsigned char ch, ch2, ch3;
78 int length = 1; /* default length */
79 unicode result = 0x80; /* default bad result; */
80 *valid = 1;
81 switch ((ch = ptr[0]) >> 4) {
82 default:
83 result = ch;
84 break;
85
86 case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
87 /* Shouldn't happen. */
88 *valid = 0;
89 break;
90
91 case 0xC: case 0xD:
92 /* 110xxxxx 10xxxxxx */
93 if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
94 unsigned char high_five = ch & 0x1F;
95 unsigned char low_six = ch2 & 0x3F;
96 result = (high_five << 6) + low_six;
97 length = 2;
98 }
99 break;
100
101 case 0xE:
102 /* 1110xxxx 10xxxxxx 10xxxxxx */
103 if (((ch2 = ptr[1]) & 0xC0) == 0x80) {
104 if (((ch3 = ptr[2]) & 0xC0) == 0x80) {
105 unsigned char high_four = ch & 0x0f;
106 unsigned char mid_six = ch2 & 0x3f;
107 unsigned char low_six = ch3 & 0x3f;
108 result = (((high_four << 6) + mid_six) << 6) + low_six;
109 length = 3;
110 } else {
111 length = 2;
112 }
113 }
114 break;
115 } /* end of switch */
116
117 *utfstring_ptr = (char *)(ptr + length);
118 return result;
119}
120
121/* Take pointer to a string. Skip over the longest part of the string that
122 * could be taken as a fieldname. Allow '/' if slash_okay is JNI_TRUE.
123 *
124 * Return a pointer to just past the fieldname. Return NULL if no fieldname
125 * at all was found, or in the case of slash_okay being true, we saw
126 * consecutive slashes (meaning we were looking for a qualified path but
127 * found something that was badly-formed).
128 */
129static char *
130skip_over_fieldname(char *name, jboolean slash_okay,
131 unsigned int length)
132{
133 char *p;
134 unicode ch;
135 unicode last_ch = 0;
136 int valid = 1;
137 /* last_ch == 0 implies we are looking at the first char. */
138 for (p = name; p != name + length; last_ch = ch) {
139 char *old_p = p;
140 ch = *p;
141 if (ch < 128) {
142 p++;
143 if (isJvmIdentifier(ch)) {
144 continue;
145 }
146 } else {
147 char *tmp_p = p;
148 ch = next_utf2unicode(&tmp_p, &valid);
149 if (valid == 0)
150 return 0;
151 p = tmp_p;
152 if (isJvmIdentifier(ch)) {
153 continue;
154 }
155 }
156
157 if (slash_okay && ch == '/' && last_ch) {
158 if (last_ch == '/') {
159 return 0; /* Don't permit consecutive slashes */
160 }
161 } else if (ch == '_' || ch == '$') {
162 } else {
163 return last_ch ? old_p : 0;
164 }
165 }
166 return last_ch ? p : 0;
167}
168
169/* Take pointer to a string. Skip over the longest part of the string that
170 * could be taken as a field signature. Allow "void" if void_okay.
171 *
172 * Return a pointer to just past the signature. Return NULL if no legal
173 * signature is found.
174 */
175
176static char *
177skip_over_field_signature(char *name, jboolean void_okay,
178 unsigned int length)
179{
180 unsigned int array_dim = 0;
181 for (;length > 0;) {
182 switch (name[0]) {
183 case JVM_SIGNATURE_VOID:
184 if (!void_okay) return 0;
185 /* FALL THROUGH */
186 case JVM_SIGNATURE_BOOLEAN:
187 case JVM_SIGNATURE_BYTE:
188 case JVM_SIGNATURE_CHAR:
189 case JVM_SIGNATURE_SHORT:
190 case JVM_SIGNATURE_INT:
191 case JVM_SIGNATURE_FLOAT:
192 case JVM_SIGNATURE_LONG:
193 case JVM_SIGNATURE_DOUBLE:
194 return name + 1;
195
196 case JVM_SIGNATURE_CLASS: {
197 /* Skip over the classname, if one is there. */
198 char *p =
199 skip_over_fieldname(name + 1, JNI_TRUE, --length);
200 /* The next character better be a semicolon. */
201 if (p && p - name - 1 > 0 && p[0] == ';')
202 return p + 1;
203 return 0;
204 }
205
206 case JVM_SIGNATURE_ARRAY:
207 array_dim++;
208 /* JVMS 2nd ed. 4.10 */
209 /* The number of dimensions in an array is limited to 255 ... */
210 if (array_dim > 255) {
211 return 0;
212 }
213 /* The rest of what's there better be a legal signature. */
214 name++;
215 length--;
216 void_okay = JNI_FALSE;
217 break;
218
219 default:
220 return 0;
221 }
222 }
223 return 0;
224}
225
226
227/* Used in java/lang/Class.c */
228/* Determine if the specified name is legal
229 * UTF name for a classname.
230 *
231 * Note that this routine expects the internal form of qualified classes:
232 * the dots should have been replaced by slashes.
233 */
234JNIEXPORT jboolean
235VerifyClassname(char *name, jboolean allowArrayClass)
236{
237 size_t s = strlen(name);
238 assert(s <= UINT_MAX);
239 unsigned int length = (unsigned int)s;
240 char *p;
241
242 if (length > 0 && name[0] == JVM_SIGNATURE_ARRAY) {
243 if (!allowArrayClass) {
244 return JNI_FALSE;
245 } else {
246 /* Everything that's left better be a field signature */
247 p = skip_over_field_signature(name, JNI_FALSE, length);
248 }
249 } else {
250 /* skip over the fieldname. Slashes are okay */
251 p = skip_over_fieldname(name, JNI_TRUE, length);
252 }
253 return (p != 0 && p - name == (ptrdiff_t)length);
254}
255
256/*
257 * Translates '.' to '/'. Returns JNI_TRUE is any / were present.
258 */
259JNIEXPORT jboolean
260VerifyFixClassname(char *name)
261{
262 char *p = name;
263 jboolean slashesFound = JNI_FALSE;
264 int valid = 1;
265
266 while (valid != 0 && *p != '\0') {
267 if (*p == '/') {
268 slashesFound = JNI_TRUE;
269 p++;
270 } else if (*p == '.') {
271 *p++ = '/';
272 } else {
273 next_utf2unicode(&p, &valid);
274 }
275 }
276
277 return slashesFound && valid != 0;
278}
279