10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7298SMark.J.Nelson@Sun.COM * Common Development and Distribution License (the "License"). 6*7298SMark.J.Nelson@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 220Sstevel@tonic-gate * Copyright (c) 1999 by Sun Microsystems, Inc. 230Sstevel@tonic-gate * All rights reserved. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate // ServiceLocationAttributeV1.java: SLPv1 character encoding and decoding 280Sstevel@tonic-gate // Author: James Kempf 290Sstevel@tonic-gate // Created On: Fri Oct 9 19:18:17 1998 300Sstevel@tonic-gate // Last Modified By: James Kempf 310Sstevel@tonic-gate // Last Modified On: Sat Oct 24 13:17:58 1998 320Sstevel@tonic-gate // Update Count: 15 330Sstevel@tonic-gate // 340Sstevel@tonic-gate 350Sstevel@tonic-gate package com.sun.slp; 360Sstevel@tonic-gate 370Sstevel@tonic-gate import java.util.*; 380Sstevel@tonic-gate 390Sstevel@tonic-gate /** 400Sstevel@tonic-gate * Handles attribute string encoding and decoding for SLPv1. 410Sstevel@tonic-gate * 420Sstevel@tonic-gate * @author James Kempf 430Sstevel@tonic-gate */ 440Sstevel@tonic-gate 450Sstevel@tonic-gate class ServiceLocationAttributeV1 extends ServiceLocationAttribute { 460Sstevel@tonic-gate 470Sstevel@tonic-gate String charCode = IANACharCode.UTF8; // how to encode the attribute. 480Sstevel@tonic-gate 490Sstevel@tonic-gate // Characters to escape. 500Sstevel@tonic-gate 510Sstevel@tonic-gate final private static String UNESCAPABLE_CHARS = ",=!></*()"; 520Sstevel@tonic-gate final private static String ESCAPABLE_CHARS = 530Sstevel@tonic-gate UNESCAPABLE_CHARS + "&#;"; 540Sstevel@tonic-gate 550Sstevel@tonic-gate /** 560Sstevel@tonic-gate * Handles radix64 string encoding and decoding for SLPv1. 570Sstevel@tonic-gate * 580Sstevel@tonic-gate * @author James Kempf 590Sstevel@tonic-gate */ 600Sstevel@tonic-gate 610Sstevel@tonic-gate static class Radix64 extends Object { 620Sstevel@tonic-gate 630Sstevel@tonic-gate /** 640Sstevel@tonic-gate * Translates the 6 bit value to the corresponding radix 64 650Sstevel@tonic-gate * representation. 660Sstevel@tonic-gate */ LUT(char cin)670Sstevel@tonic-gate private static char LUT(char cin) { 680Sstevel@tonic-gate 690Sstevel@tonic-gate int i = (int)(cin & (char)0x00FF); 700Sstevel@tonic-gate char result = ' '; 710Sstevel@tonic-gate 720Sstevel@tonic-gate if (i < 26) { 730Sstevel@tonic-gate result = (char)((char)i + 'A'); 740Sstevel@tonic-gate 750Sstevel@tonic-gate } else if (i < 52) { 760Sstevel@tonic-gate result = (char)((char)(i - 26) + 'a'); 770Sstevel@tonic-gate 780Sstevel@tonic-gate } else if (i < 62) { 790Sstevel@tonic-gate result = (char)((char)(i - 52) + '0'); 800Sstevel@tonic-gate 810Sstevel@tonic-gate } else if (i == 62) { 820Sstevel@tonic-gate result = '+'; 830Sstevel@tonic-gate 840Sstevel@tonic-gate } else if (i == 63) { 850Sstevel@tonic-gate result = '/'; 860Sstevel@tonic-gate 870Sstevel@tonic-gate } 880Sstevel@tonic-gate 890Sstevel@tonic-gate return result; 900Sstevel@tonic-gate } 910Sstevel@tonic-gate 920Sstevel@tonic-gate /** 930Sstevel@tonic-gate * Translates a radix 64 representation to the 64 bit value which 940Sstevel@tonic-gate * corresponds to it. 950Sstevel@tonic-gate */ LUT2(char cin, String s)960Sstevel@tonic-gate private static char LUT2(char cin, String s) 970Sstevel@tonic-gate throws ServiceLocationException { 980Sstevel@tonic-gate 990Sstevel@tonic-gate int i = (int)(cin & 0x00ff); 1000Sstevel@tonic-gate char c = (char) 0xffff; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate if (((char)i >= 'A') && ((char)i <= 'Z')) { 1030Sstevel@tonic-gate c = (char)((char)i - 'A'); 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate } 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate if (((char)i >= 'a') && ((char)i <= 'z')) { 1080Sstevel@tonic-gate c = (char)((char)i - 'a' +(char) 26); 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate } 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate if (((char)i >= '0') && ((char)i <= '9')) { 1130Sstevel@tonic-gate c = (char)((char)i - '0' +(char) 52); 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate if ((char)i == '+') { 1180Sstevel@tonic-gate c = (char)62; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate if ((char)i == '/') { 1230Sstevel@tonic-gate c = (char)63; 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate if ((char)i == '=') { 1280Sstevel@tonic-gate c = (char)0; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate if (c == 0xffff) { 1330Sstevel@tonic-gate throw 1340Sstevel@tonic-gate new ServiceLocationException( 1350Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 1360Sstevel@tonic-gate "v1_radix64_error", 1370Sstevel@tonic-gate new Object[] {s}); 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate return c; 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate // format of the encoding is "(###:encoding)" where ### is the length 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate // convert a string in the encoding to the buffer format 1470Sstevel@tonic-gate radix64ToOpaque(String s)1480Sstevel@tonic-gate static Opaque radix64ToOpaque(String s) 1490Sstevel@tonic-gate throws ServiceLocationException { 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate if (s == null || s.trim().length() == 0) { 1520Sstevel@tonic-gate return new Opaque(new byte[0]); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate int oplen = 0; 1570Sstevel@tonic-gate int scan = 0; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate while (scan < s.length()) { 1600Sstevel@tonic-gate if (s.charAt(scan) == '(') { 1610Sstevel@tonic-gate break; // scan till begins 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate scan++; 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate scan++; // past the '(' 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate while (scan < s.length()) { 1710Sstevel@tonic-gate if (Character.isWhitespace(s.charAt(scan)) == false) { 1720Sstevel@tonic-gate break; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate scan++; 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate while (scan < s.length()) { 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate if (Character.isDigit(s.charAt(scan))) { 1810Sstevel@tonic-gate oplen *= 10; 1820Sstevel@tonic-gate oplen += (s.charAt(scan) - '0'); 1830Sstevel@tonic-gate scan++; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate } else { 1860Sstevel@tonic-gate break; 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate if (scan >= s.length()) { 1920Sstevel@tonic-gate throw 1930Sstevel@tonic-gate new ServiceLocationException( 1940Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 1950Sstevel@tonic-gate "v1_radix64_error", 1960Sstevel@tonic-gate new Object[] {s}); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate if (s.charAt(scan) != ':') { 2020Sstevel@tonic-gate throw 2030Sstevel@tonic-gate new ServiceLocationException( 2040Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 2050Sstevel@tonic-gate "v1_radix64_error", 2060Sstevel@tonic-gate new Object[] {s}); 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate scan++; // past the ':' 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate byte b[] = new byte[oplen]; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate int pos = 0; 2150Sstevel@tonic-gate int timesthrough = (oplen/3); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate if ((oplen %3) != 0) { 2180Sstevel@tonic-gate timesthrough++; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate for (int i = 0; i < timesthrough; i++) { 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate // get 4 bytes to make 3 with, skipping blanks 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate char v[] = new char[4]; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate for (int x = 0; x < 4; x++) { 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate while ((scan < s.length()) && 2310Sstevel@tonic-gate Character.isWhitespace(s.charAt(scan))) { 2320Sstevel@tonic-gate scan++; // eat white 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate if (scan >= s.length()) { 2370Sstevel@tonic-gate throw 2380Sstevel@tonic-gate new ServiceLocationException( 2390Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 2400Sstevel@tonic-gate "v1_radix64_error", 2410Sstevel@tonic-gate new Object[] {s}); 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate v[x] = LUT2(s.charAt(scan), s); 2460Sstevel@tonic-gate scan++; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate b[pos++] = 2500Sstevel@tonic-gate (byte) (((0x3F & v[0]) << 2) + ((0x30 & v[1]) >> 4)); 2510Sstevel@tonic-gate if (pos >= oplen) break; 2520Sstevel@tonic-gate b[pos++] = 2530Sstevel@tonic-gate (byte) (((0x0F & v[1]) << 4) + ((0x3C & v[2]) >> 2)); 2540Sstevel@tonic-gate if (pos >= oplen) break; 2550Sstevel@tonic-gate b[pos++] = (byte) (((0x03 & v[2]) << 6) + (0x3F & v[3])); 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate } // end of conversion loop 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate if (scan >= s.length()) { 2600Sstevel@tonic-gate throw 2610Sstevel@tonic-gate new ServiceLocationException( 2620Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 2630Sstevel@tonic-gate "v1_radix64_error", 2640Sstevel@tonic-gate new Object[] {s}); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate if (s.charAt(scan) != ')') {// check for too many chars. 2680Sstevel@tonic-gate throw 2690Sstevel@tonic-gate new ServiceLocationException( 2700Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 2710Sstevel@tonic-gate "v1_radix64_error", 2720Sstevel@tonic-gate new Object[] {s}); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate return new Opaque(b); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate // convert an Opaque to the encoding 2800Sstevel@tonic-gate opaqueToRadix64(Opaque oq)2810Sstevel@tonic-gate static String opaqueToRadix64(Opaque oq) { 2820Sstevel@tonic-gate byte[] b = oq.bytes; 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate if (b == null) { 2850Sstevel@tonic-gate return new String(""); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate StringBuffer sb = new StringBuffer("("+b.length+":"); 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate int datalen; 2920Sstevel@tonic-gate int fill = b.length%3; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate if (fill == 0) { 2950Sstevel@tonic-gate datalen = (b.length / 3) * 4; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate } else { 2980Sstevel@tonic-gate datalen = ((b.length / 3) + 1) * 4; 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate int dataoffset = 0; 3030Sstevel@tonic-gate int more = (b.length%3); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate if (more != 0) { 3060Sstevel@tonic-gate more = 1; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate int a[] = new int[4]; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate for (int i = 0; i < ((b.length/3)+more-1); i++) { 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate a[0] = (int)(0xFC & (char)b[ dataoffset ]) >> 2; 3150Sstevel@tonic-gate a[1] = ((int)(0x03 & (char)b[ dataoffset ]) << 4) + 3160Sstevel@tonic-gate ((int)(0xF0 & (char)b[ dataoffset + 1]) >> 4); 3170Sstevel@tonic-gate a[2] = ((int)(0x0F & (char)b[ dataoffset + 1]) << 2) + 3180Sstevel@tonic-gate ((int)(0xC0 & (char)b[ dataoffset + 2]) >> 6); 3190Sstevel@tonic-gate a[3] = (int)(0x3F & (char)b[ dataoffset + 2]); 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate for (int j = 0; j < 4; j++) { 3220Sstevel@tonic-gate sb.append(LUT((char)a[j])); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate dataoffset += 3; 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate byte f1 = 0, f2 = 0; 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate if (fill == 0) { 3320Sstevel@tonic-gate f1 = b[ dataoffset + 1 ]; 3330Sstevel@tonic-gate f2 = b[ dataoffset + 2 ]; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate } else if (fill == 2) { 3360Sstevel@tonic-gate f1 = b[ dataoffset + 1 ]; 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate a[0] = (int) (0xFC & (char)b[ dataoffset ]) >> 2; 3410Sstevel@tonic-gate a[1] = ((int) (0x03 & (char)b[ dataoffset ]) << 4) + 3420Sstevel@tonic-gate ((int) (0xF0 & (char)f1) >> 4); 3430Sstevel@tonic-gate a[2] = ((int) (0x0F & (char)f1) << 2) + 3440Sstevel@tonic-gate ((int) (0xC0 & (char)f2) >> 6); 3450Sstevel@tonic-gate a[3] = (int) (0x3F & (char)f2); 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate for (int j = 0; j < 4; j++) { 3480Sstevel@tonic-gate sb.append(LUT((char) a[j])); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate sb.append(")"); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate return sb.toString(); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate // Create an SLPv1 attribute from a general attribute. 3590Sstevel@tonic-gate ServiceLocationAttributeV1(ServiceLocationAttribute attr)3600Sstevel@tonic-gate ServiceLocationAttributeV1(ServiceLocationAttribute attr) { 3610Sstevel@tonic-gate id = attr.id; 3620Sstevel@tonic-gate values = attr.values; 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate // Create an SLPv1 attribute from the parenthesized expression, using 3670Sstevel@tonic-gate // charCode to decode any encodings. 3680Sstevel@tonic-gate ServiceLocationAttributeV1(String exp, String charCode, boolean allowMultiValuedBooleans)3690Sstevel@tonic-gate ServiceLocationAttributeV1(String exp, 3700Sstevel@tonic-gate String charCode, 3710Sstevel@tonic-gate boolean allowMultiValuedBooleans) 3720Sstevel@tonic-gate throws ServiceLocationException { 3730Sstevel@tonic-gate this.charCode = charCode; 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate // If start and end paren, then parse out assignment. 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate if (exp.startsWith("(") && exp.endsWith(")")) { 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate StringTokenizer tk = 3800Sstevel@tonic-gate new StringTokenizer(exp.substring(1, exp.length() - 1), 3810Sstevel@tonic-gate "=", 3820Sstevel@tonic-gate true); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate try { 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate // Get the tag. 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate id = 3890Sstevel@tonic-gate unescapeAttributeString(tk.nextToken(), charCode); 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate if (id.length() <= 0) { 3920Sstevel@tonic-gate throw 3930Sstevel@tonic-gate new ServiceLocationException( 3940Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 3950Sstevel@tonic-gate "null_id", 3960Sstevel@tonic-gate new Object[] {exp}); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate tk.nextToken(); // get rid of "=" 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate // Gather the rest. 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate String rest = tk.nextToken(""); 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate // Parse the comma separated list. 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate values = SrvLocHeader.parseCommaSeparatedListIn(rest, true); 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate // Convert to objects. 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate int i, n = values.size(); 4120Sstevel@tonic-gate Class vecClass = null; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate for (i = 0; i < n; i++) { 4150Sstevel@tonic-gate String value = (String)values.elementAt(i); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate // Need to determine which type to use. 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate Object o = evaluate(value, charCode); 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate // Convert Opaque to byte array. 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate if (o instanceof Opaque) { 4240Sstevel@tonic-gate o = ((Opaque)o).bytes; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate values.setElementAt(o, i); 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate } catch (NoSuchElementException ex) { 4330Sstevel@tonic-gate throw 4340Sstevel@tonic-gate new ServiceLocationException( 4350Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 4360Sstevel@tonic-gate "assignment_syntax_err", 4370Sstevel@tonic-gate new Object[] {exp}); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate verifyValueTypes(values, allowMultiValuedBooleans); 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate } else { 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate // Check to make sure there's no parens. 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate if (exp.indexOf('(') != -1 || exp.indexOf(')') != -1) { 4470Sstevel@tonic-gate throw 4480Sstevel@tonic-gate new ServiceLocationException( 4490Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 4500Sstevel@tonic-gate "assignment_syntax_err", 4510Sstevel@tonic-gate new Object[] {exp}); 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate // Unescape the keyword. 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate id = unescapeAttributeString(exp, charCode); 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate // Duplicate of the one in ServiceLocatioAttribute, except we use our 4620Sstevel@tonic-gate // unescapeAttributeString. 4630Sstevel@tonic-gate evaluate(String value, String charCode)4640Sstevel@tonic-gate static Object evaluate(String value, String charCode) 4650Sstevel@tonic-gate throws ServiceLocationException { 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate Object o = null; 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate // If it can be converted into an integer, then convert it. 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate try { 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate o = Integer.valueOf(value); 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate } catch (NumberFormatException ex) { 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate // Wasn't an integer. Try boolean. 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate if (value.equalsIgnoreCase(TRUE) || 4800Sstevel@tonic-gate value.equalsIgnoreCase(FALSE)) { 4810Sstevel@tonic-gate o = Boolean.valueOf(value); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate } else { 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate // Process the string to remove escapes. 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate String val = (String)value; 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate // If it begins with the opaque prefix, treat it as an 4900Sstevel@tonic-gate // opaque. Use radix64 parser to convert. 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate if (val.startsWith("(")) { 4930Sstevel@tonic-gate o = Radix64.radix64ToOpaque(val); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate } else { 4960Sstevel@tonic-gate o = unescapeAttributeString(val, charCode); 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate } 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate return o; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate // Externalize the attribute, using its charCode to encode any reserved 5070Sstevel@tonic-gate // characters. 5080Sstevel@tonic-gate externalize()5090Sstevel@tonic-gate String externalize() 5100Sstevel@tonic-gate throws ServiceLocationException { 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate if (values == null) { // keyword attribute... 5130Sstevel@tonic-gate return escapeAttributeString(id, charCode); 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate Vector v = new Vector(); 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate for (Enumeration e = values.elements(); e.hasMoreElements(); ) { 5190Sstevel@tonic-gate Object o = e.nextElement(); 5200Sstevel@tonic-gate String s = null; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate s = escapeValueInternal(o, charCode); 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate v.addElement(s); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate StringBuffer buf = 5280Sstevel@tonic-gate new StringBuffer("(" + 5290Sstevel@tonic-gate escapeAttributeString(id, charCode) + 5300Sstevel@tonic-gate "="); 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate buf.append(SrvLocHeader.vectorToCommaSeparatedList(v)); 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate buf.append(")"); 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate return buf.toString(); 5370Sstevel@tonic-gate } 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate // Exactly like the one in ServiceLocationAttribute, but use our 5400Sstevel@tonic-gate // escapeAttributeString. 5410Sstevel@tonic-gate escapeValueInternal(Object val, String charCode)5420Sstevel@tonic-gate private static String escapeValueInternal(Object val, String charCode) { 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate String s; 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate // Escape any characters needing it. 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate if (val instanceof String) { 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate try { 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate s = escapeAttributeString((String)val, charCode); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate } catch (ServiceLocationException ex) { 5550Sstevel@tonic-gate throw 5560Sstevel@tonic-gate new IllegalArgumentException(ex.getMessage()); 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate } else if (val instanceof Opaque) { 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate // Convert to radix 64. 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate s = Radix64.opaqueToRadix64((Opaque)val); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate } else { 5670Sstevel@tonic-gate s = val.toString(); 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate return s; 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate // Escape an attribute string with the char code. 5750Sstevel@tonic-gate escapeAttributeString(String string, String charCode)5760Sstevel@tonic-gate static String escapeAttributeString(String string, 5770Sstevel@tonic-gate String charCode) 5780Sstevel@tonic-gate throws ServiceLocationException { 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate StringBuffer buf = new StringBuffer(); 5810Sstevel@tonic-gate int i, n = string.length(); 5820Sstevel@tonic-gate boolean is8bit = 5830Sstevel@tonic-gate (charCode.equals(IANACharCode.ASCII) || 5840Sstevel@tonic-gate charCode.equals(IANACharCode.LATIN1)); 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate for (i = 0; i < n; i++) { 5870Sstevel@tonic-gate char c = string.charAt(i); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate if (ESCAPABLE_CHARS.indexOf(c) != -1) { 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate buf.append("&#"); 5920Sstevel@tonic-gate buf.append(IANACharCode.escapeChar(c, charCode)); 5930Sstevel@tonic-gate buf.append(";"); 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate } else { 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate // Need to check ASCII and LATIN1 to make sure that 5980Sstevel@tonic-gate // the character is not outside their range of 5990Sstevel@tonic-gate // representation. 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate if (is8bit && (short)c > 255) { 6020Sstevel@tonic-gate throw 6030Sstevel@tonic-gate new ServiceLocationException( 6040Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6050Sstevel@tonic-gate "v1_8bit_error", 6060Sstevel@tonic-gate new Object[] {new Character(c)}); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate buf.append(c); 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate return buf.toString(); 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate // Unescape attribute string, using charCode for reserved characters. 6180Sstevel@tonic-gate unescapeAttributeString(String string, String charCode)6190Sstevel@tonic-gate static String unescapeAttributeString(String string, 6200Sstevel@tonic-gate String charCode) 6210Sstevel@tonic-gate throws ServiceLocationException { 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate // Process escapes. 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate int i, n = string.length(); 6260Sstevel@tonic-gate StringBuffer buf = new StringBuffer(n); 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate for (i = 0; i < n; i++) { 6290Sstevel@tonic-gate char c = string.charAt(i); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate // Check for invalids. 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate int idx = -1; 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate if ((idx = UNESCAPABLE_CHARS.indexOf(c)) != -1) { 6360Sstevel@tonic-gate throw 6370Sstevel@tonic-gate new ServiceLocationException( 6380Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6390Sstevel@tonic-gate "v1_escape_error", 6400Sstevel@tonic-gate new Object[] {string}); 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate // Check for escapes. 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate if (c != '&') { 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate buf.append(c); 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate } else { 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate // Check to be sure we've got enough characters left. We need 6520Sstevel@tonic-gate // at least 3. 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate if ((i + 1) >= n) { 6550Sstevel@tonic-gate throw 6560Sstevel@tonic-gate new ServiceLocationException( 6570Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6580Sstevel@tonic-gate "v1_escape_error", 6590Sstevel@tonic-gate new Object[] {string}); 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate c = string.charAt(++i); 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate if (c != '#') { 6650Sstevel@tonic-gate throw 6660Sstevel@tonic-gate new ServiceLocationException( 6670Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6680Sstevel@tonic-gate "v1_escape_error", 6690Sstevel@tonic-gate new Object[] {string}); 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate // Iterate through numbers, collecting. 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate StringBuffer num = new StringBuffer(n); 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate for (i++; i < n; i++) { 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate c = string.charAt(i); 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate if (!Character.isDigit(c)) { 6810Sstevel@tonic-gate break; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate num.append(c); 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate // If the buffer is empty, then throw exception 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate if (num.length() <= 0) { 6900Sstevel@tonic-gate throw 6910Sstevel@tonic-gate new ServiceLocationException( 6920Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 6930Sstevel@tonic-gate "v1_escape_error", 6940Sstevel@tonic-gate new Object[] {string}); 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate // If the last one isn't ";", we've got a problem. 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate if (c != ';') { 7000Sstevel@tonic-gate throw 7010Sstevel@tonic-gate new ServiceLocationException( 7020Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 7030Sstevel@tonic-gate "v1_escape_error", 7040Sstevel@tonic-gate new Object[] {string}); 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate // OK, now convert to a character and add to buffer. 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate try { 7100Sstevel@tonic-gate buf.append(IANACharCode.unescapeChar(num.toString(), 7110Sstevel@tonic-gate charCode)); 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate } catch (NumberFormatException ex) { 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate throw 7160Sstevel@tonic-gate new ServiceLocationException( 7170Sstevel@tonic-gate ServiceLocationException.PARSE_ERROR, 7180Sstevel@tonic-gate "v1_escape_error", 7190Sstevel@tonic-gate new Object[] {string}); 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate return buf.toString(); 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate } 727