1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright 1998-2002 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 package com.sun.dhcpmgr.data; 29 30 import java.io.Serializable; 31 import java.util.*; 32 import java.math.BigInteger; 33 34 /** 35 * This class provides a way to retain the radix specified by the user 36 * when entering the data. Currently only support 10 and 16 for radix. 37 */ 38 class NumberValue implements Serializable { 39 private Number value; 40 private int radix; 41 42 // Serialization id for this class 43 static final long serialVersionUID = -3480903816949402385L; 44 45 public NumberValue(Number value, int radix) { 46 this.value = value; 47 this.radix = radix; 48 } 49 50 public String toString() { 51 if (value instanceof BigInteger) { 52 return ((BigInteger)value).toString(radix); 53 } 54 // Handle hex specially 55 if (radix == 16) { 56 return "0x" + Long.toHexString(value.longValue()); 57 } else { 58 return Long.toString(value.longValue()); 59 } 60 } 61 } 62 63 public class NumberOptionValue extends OptionValue { 64 private String name; 65 private Vector nums; 66 private boolean valid; 67 private int radix; 68 69 // Serialization id for this class 70 static final long serialVersionUID = -5824132577553748971L; 71 72 protected NumberOptionValue(String name) { 73 this.name = name; 74 nums = null; 75 valid = false; 76 } 77 78 public void setValue(Object value) throws ValidationException { 79 // Find option in option definition table in order to validate the data 80 Option option = OptionsTable.getTable().get(name); 81 if (option == null) { 82 Object [] args = { name }; 83 throwException("invalid_option", args); 84 } 85 86 // The granularity attribute must be interpreted in context 87 // of what kind of number option we're dealing with. If this 88 // is a NUMBER option, then granularity defines the number of 89 // octets the number will contain (in other words the size). 90 // For all other number types it defines how many numbers of 91 // that type make make a valid option of that type. Note that 92 // in the case of NUMBER options that granularity always defaults 93 // to one. XXX Swill code here. Should probably define a new class and 94 // create an array of them and simply loop. 95 byte type = option.getType(); 96 boolean isUnsigned = false; 97 int bits = option.getGranularity() * 8; 98 int realGranularity = option.getGranularity(); 99 100 if (type == Option.types[Option.NUMBER].getCode()) { 101 realGranularity = 1; 102 } else if (type == Option.types[Option.SNUMBER8].getCode()) { 103 bits = 7; 104 } else if (type == Option.types[Option.UNUMBER8].getCode()) { 105 bits = 8; 106 isUnsigned = true; 107 } else if (type == Option.types[Option.SNUMBER16].getCode()) { 108 bits = 15; 109 } else if (type == Option.types[Option.UNUMBER16].getCode()) { 110 bits = 16; 111 isUnsigned = true; 112 } else if (type == Option.types[Option.SNUMBER32].getCode()) { 113 bits = 31; 114 } else if (type == Option.types[Option.UNUMBER32].getCode()) { 115 bits = 32; 116 isUnsigned = true; 117 } else if (type == Option.types[Option.SNUMBER64].getCode()) { 118 bits = 63; 119 } else if (type == Option.types[Option.UNUMBER64].getCode()) { 120 bits = 64; 121 isUnsigned = true; 122 } 123 124 Vector newNums = new Vector(); 125 if (value instanceof String) { 126 if (((String)value).length() == 0) { 127 // Empty strings are not acceptable 128 Object [] args = { name, 129 Option.getTypeDhcptabString(type) }; 130 throwException("invalid_option_value", args); 131 } 132 // Parse each token into an object of the correct numeric type 133 StringTokenizer st = new StringTokenizer((String)value, " "); 134 while (st.hasMoreTokens()) { 135 int radix = 10; 136 String s = st.nextToken(); 137 if (s.startsWith("0x") || s.startsWith("0X")) { 138 radix = 16; 139 s = s.substring(2); 140 } else if (s.startsWith("0") && (s.length() > 1)) { 141 radix = 8; 142 s = s.substring(1); 143 } 144 145 BigInteger b; 146 try { 147 b = new BigInteger(s, radix); 148 if (b.bitLength() > bits) { 149 Object [] args = { name, 150 Option.getTypeDhcptabString(type) }; 151 throwException("invalid_option_value", args); 152 } 153 if (isUnsigned && b.compareTo(BigInteger.ZERO) < 0) { 154 Object [] args = { name, 155 Option.getTypeDhcptabString(type) }; 156 throwException("invalid_option_value", args); 157 } 158 newNums.addElement(new NumberValue(b, radix)); 159 } catch (NumberFormatException e) { 160 Object [] args = { name, 161 Option.getTypeDhcptabString(type) }; 162 throwException("invalid_option_value", args); 163 } 164 } 165 } else if (value instanceof Number) { 166 newNums.addElement(new NumberValue((Number)value, 10)); 167 } else if (!(value instanceof Vector)) { 168 Object [] args = { name, 169 Option.getTypeDhcptabString(type) }; 170 throwException("invalid_option_value", args); 171 } else { 172 // Caller supplied a vector; make sure each value is a number 173 Enumeration en = ((Vector)value).elements(); 174 while (en.hasMoreElements()) { 175 Object o = en.nextElement(); 176 if (!(o instanceof Number)) { 177 Object [] args = { name, 178 Option.getTypeDhcptabString(type) }; 179 throwException("invalid_option_value", args); 180 } else { 181 newNums.addElement(new NumberValue((Number)o, 10)); 182 } 183 } 184 } 185 186 // We now have a vector of numbers; check count against expected 187 if (newNums.size() % realGranularity != 0) { 188 Object [] args = { name, Integer.toString(realGranularity) }; 189 throwException("invalid_option_granularity", args); 190 } 191 if ((option.getMaximum() != 0) 192 && (newNums.size() / realGranularity > option.getMaximum())) { 193 Object [] args = { name, Integer.toString(option.getMaximum()) }; 194 throwException("invalid_option_maximum", args); 195 } 196 197 nums = newNums; 198 valid = true; 199 } 200 201 public String getName() { 202 return name; 203 } 204 205 public String getValue() { 206 if (nums == null || nums.size() == 0) { 207 return ""; 208 } 209 StringBuffer buf = new StringBuffer(); 210 for (Enumeration en = nums.elements(); en.hasMoreElements(); ) { 211 if (buf.length() != 0) { 212 buf.append(' '); 213 } 214 buf.append(en.nextElement().toString()); 215 } 216 return buf.toString(); 217 } 218 219 public String toString() { 220 return (getName() + "=" + getValue()); 221 } 222 223 public boolean isValid() { 224 return valid; 225 } 226 227 public Object clone() { 228 NumberOptionValue v = new NumberOptionValue(name); 229 if (nums != null) { 230 v.nums = (Vector)nums.clone(); 231 } 232 v.valid = valid; 233 return v; 234 } 235 }