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 }