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 
NumberValue(Number value, int radix)45     public NumberValue(Number value, int radix) {
46     	this.value = value;
47 	this.radix = radix;
48     }
49 
toString()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 
NumberOptionValue(String name)72     protected NumberOptionValue(String name) {
73 	this.name = name;
74 	nums = null;
75 	valid = false;
76     }
77 
setValue(Object value)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 
getName()201     public String getName() {
202 	return name;
203     }
204 
getValue()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 
toString()219     public String toString() {
220 	return (getName() + "=" + getValue());
221     }
222 
isValid()223     public boolean isValid() {
224 	return valid;
225     }
226 
clone()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 }
236