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