blob: 2818789fd0d5f9e098d038cd4d29be48ba331b7f [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-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 <ctype.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/types.h>
30#include "jni.h"
31#include "jli_util.h"
32#include "version_comp.h"
33
34/*
35 * A collection of useful strings. One should think of these as #define
36 * entries, but actual strings can be more efficient (with many compilers).
37 */
38static const char *separators = ".-_";
39static const char *zero_string = "0";
40
41/*
42 * Validate a string as parsable as a "Java int". If so parsable,
43 * return true (non-zero) and store the numeric value at the address
44 * passed in as "value"; otherwise return false (zero).
45 *
46 * Note that the maximum allowable value is 2147483647 as defined by
47 * the "Java Language Specification" which precludes the use of native
48 * conversion routines which may have other limits.
49 *
50 * Also note that we don't have to worry about the alternate maximum
51 * allowable value of 2147483648 because it is only allowed after
52 * the unary negation operator and this grammar doesn't have one
53 * of those.
54 *
55 * Finally, note that a value which exceeds the maximum jint value will
56 * return false (zero). This results in the otherwise purely numeric
57 * string being compared as a string of characters (as per the spec.)
58 */
59static int
60isjavaint(const char *s, jint *value)
61{
62 jlong sum = 0;
63 jint digit;
64 while (*s != '\0')
65 if (isdigit(*s)) {
66 digit = (jint)((int)(*s++) - (int)('0'));
67 sum = (sum * 10) + digit;
68 if (sum > 2147483647)
69 return (0); /* Overflows jint (but not jlong) */
70 } else
71 return (0);
72 *value = (jint)sum;
73 return (1);
74}
75
76/*
77 * Modeled after strcmp(), compare two strings (as in the grammar defined
78 * in Appendix A of JSR 56). If both strings can be interpreted as
79 * Java ints, do a numeric comparison, else it is strcmp().
80 */
81static int
82comp_string(const char *s1, const char *s2)
83{
84 jint v1, v2;
85 if (isjavaint(s1, &v1) && isjavaint(s2, &v2))
86 return ((int)(v1 - v2));
87 else
88 return (JLI_StrCmp(s1, s2));
89}
90
91/*
92 * Modeled after strcmp(), compare two version-ids for a Prefix
93 * Match as defined in JSR 56.
94 */
95int
96JLI_PrefixVersionId(const char *id1, char *id2)
97{
98 char *s1 = JLI_StringDup(id1);
99 char *s2 = JLI_StringDup(id2);
100 char *m1 = s1;
101 char *m2 = s2;
102 char *end1 = NULL;
103 char *end2 = NULL;
104 int res = 0;
105
106 do {
107
108 if ((s1 != NULL) && ((end1 = JLI_StrPBrk(s1, ".-_")) != NULL))
109 *end1 = '\0';
110 if ((s2 != NULL) && ((end2 = JLI_StrPBrk(s2, ".-_")) != NULL))
111 *end2 = '\0';
112
113 res = comp_string(s1, s2);
114
115 if (end1 != NULL)
116 s1 = end1 + 1;
117 else
118 s1 = NULL;
119 if (end2 != NULL)
120 s2 = end2 + 1;
121 else
122 s2 = NULL;
123
124 } while (res == 0 && ((s1 != NULL) && (s2 != NULL)));
125
126 JLI_MemFree(m1);
127 JLI_MemFree(m2);
128 return (res);
129}
130
131/*
132 * Modeled after strcmp(), compare two version-ids for an Exact
133 * Match as defined in JSR 56.
134 */
135int
136JLI_ExactVersionId(const char *id1, char *id2)
137{
138 char *s1 = JLI_StringDup(id1);
139 char *s2 = JLI_StringDup(id2);
140 char *m1 = s1;
141 char *m2 = s2;
142 char *end1 = NULL;
143 char *end2 = NULL;
144 int res = 0;
145
146 do {
147
148 if ((s1 != NULL) && ((end1 = JLI_StrPBrk(s1, separators)) != NULL))
149 *end1 = '\0';
150 if ((s2 != NULL) && ((end2 = JLI_StrPBrk(s2, separators)) != NULL))
151 *end2 = '\0';
152
153 if ((s1 != NULL) && (s2 == NULL))
154 res = comp_string(s1, zero_string);
155 else if ((s1 == NULL) && (s2 != NULL))
156 res = comp_string(zero_string, s2);
157 else
158 res = comp_string(s1, s2);
159
160 if (end1 != NULL)
161 s1 = end1 + 1;
162 else
163 s1 = NULL;
164 if (end2 != NULL)
165 s2 = end2 + 1;
166 else
167 s2 = NULL;
168
169 } while (res == 0 && ((s1 != NULL) || (s2 != NULL)));
170
171 JLI_MemFree(m1);
172 JLI_MemFree(m2);
173 return (res);
174}
175
176/*
177 * Return true if this simple-element (as defined in JSR 56) forms
178 * an acceptable match.
179 *
180 * JSR 56 is modified by the Java Web Start <rel> Developer Guide
181 * where it is stated "... Java Web Start will not consider an installed
182 * non-FCS (i.e., milestone) JRE as a match. ... a JRE from Sun
183 * Microsystems, Inc., is by convention a non-FCS (milestone) JRE
184 * if there is a dash (-) in the version string."
185 *
186 * An undocumented caveat to the above is that an exact match with a
187 * hyphen is accepted as a development extension.
188 *
189 * These modifications are addressed by the specific comparisons
190 * for releases with hyphens.
191 */
192static int
193acceptable_simple_element(const char *release, char *simple_element)
194{
195 char *modifier;
196 modifier = simple_element + JLI_StrLen(simple_element) - 1;
197 if (*modifier == '*') {
198 *modifier = '\0';
199 if (JLI_StrChr(release, '-'))
200 return ((JLI_StrCmp(release, simple_element) == 0)?1:0);
201 return ((JLI_PrefixVersionId(release, simple_element) == 0)?1:0);
202 } else if (*modifier == '+') {
203 *modifier = '\0';
204 if (JLI_StrChr(release, '-'))
205 return ((JLI_StrCmp(release, simple_element) == 0)?1:0);
206 return ((JLI_ExactVersionId(release, simple_element) >= 0)?1:0);
207 } else {
208 return ((JLI_ExactVersionId(release, simple_element) == 0)?1:0);
209 }
210}
211
212/*
213 * Return true if this element (as defined in JSR 56) forms
214 * an acceptable match. An element is the intersection (and)
215 * of multiple simple-elements.
216 */
217static int
218acceptable_element(const char *release, char *element)
219{
220 char *end;
221 do {
222 if ((end = JLI_StrChr(element, '&')) != NULL)
223 *end = '\0';
224 if (!acceptable_simple_element(release, element))
225 return (0);
226 if (end != NULL)
227 element = end + 1;
228 } while (end != NULL);
229 return (1);
230}
231
232/*
233 * Checks if release is acceptable by the specification version-string.
234 * Return true if this version-string (as defined in JSR 56) forms
235 * an acceptable match. A version-string is the union (or) of multiple
236 * elements.
237 */
238int
239JLI_AcceptableRelease(const char *release, char *version_string)
240{
241 char *vs;
242 char *m1;
243 char *end;
244 m1 = vs = JLI_StringDup(version_string);
245 do {
246 if ((end = JLI_StrChr(vs, ' ')) != NULL)
247 *end = '\0';
248 if (acceptable_element(release, vs)) {
249 JLI_MemFree(m1);
250 return (1);
251 }
252 if (end != NULL)
253 vs = end + 1;
254 } while (end != NULL);
255 JLI_MemFree(m1);
256 return (0);
257}
258
259/*
260 * Return true if this is a valid simple-element (as defined in JSR 56).
261 *
262 * The official grammar for a simple-element is:
263 *
264 * simple-element ::= version-id | version-id modifier
265 * modifier ::= '+' | '*'
266 * version-id ::= string ( separator string )*
267 * string ::= char ( char )*
268 * char ::= Any ASCII character except a space, an
269 * ampersand, a separator or a modifier
270 * separator ::= '.' | '-' | '_'
271 *
272 * However, for efficiency, it is time to abandon the top down parser
273 * implementation. After deleting the potential trailing modifier, we
274 * are left with a version-id.
275 *
276 * Note that a valid version-id has three simple properties:
277 *
278 * 1) Doesn't contain a space, an ampersand or a modifier.
279 *
280 * 2) Doesn't begin or end with a separator.
281 *
282 * 3) Doesn't contain two adjacent separators.
283 *
284 * Any other line noise constitutes a valid version-id.
285 */
286static int
287valid_simple_element(char *simple_element)
288{
289 char *last;
290 size_t len;
291
292 if ((simple_element == NULL) || ((len = JLI_StrLen(simple_element)) == 0))
293 return (0);
294 last = simple_element + len - 1;
295 if (*last == '*' || *last == '+') {
296 if (--len == 0)
297 return (0);
298 *last-- = '\0';
299 }
300 if (JLI_StrPBrk(simple_element, " &+*") != NULL) /* Property #1 */
301 return (0);
302 if ((JLI_StrChr(".-_", *simple_element) != NULL) || /* Property #2 */
303 (JLI_StrChr(".-_", *last) != NULL))
304 return (0);
305 for (; simple_element != last; simple_element++) /* Property #3 */
306 if ((JLI_StrChr(".-_", *simple_element) != NULL) &&
307 (JLI_StrChr(".-_", *(simple_element + 1)) != NULL))
308 return (0);
309 return (1);
310}
311
312/*
313 * Return true if this is a valid element (as defined in JSR 56).
314 * An element is the intersection (and) of multiple simple-elements.
315 */
316static int
317valid_element(char *element)
318{
319 char *end;
320 if ((element == NULL) || (JLI_StrLen(element) == 0))
321 return (0);
322 do {
323 if ((end = JLI_StrChr(element, '&')) != NULL)
324 *end = '\0';
325 if (!valid_simple_element(element))
326 return (0);
327 if (end != NULL)
328 element = end + 1;
329 } while (end != NULL);
330 return (1);
331}
332
333/*
334 * Validates a version string by the extended JSR 56 grammar.
335 */
336int
337JLI_ValidVersionString(char *version_string)
338{
339 char *vs;
340 char *m1;
341 char *end;
342 if ((version_string == NULL) || (JLI_StrLen(version_string) == 0))
343 return (0);
344 m1 = vs = JLI_StringDup(version_string);
345 do {
346 if ((end = JLI_StrChr(vs, ' ')) != NULL)
347 *end = '\0';
348 if (!valid_element(vs)) {
349 JLI_MemFree(m1);
350 return (0);
351 }
352 if (end != NULL)
353 vs = end + 1;
354 } while (end != NULL);
355 JLI_MemFree(m1);
356 return (1);
357}