1 // Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
2
3 package org.xbill.DNS;
4
5 import java.util.HashMap;
6
7 /**
8 * A utility class for converting between numeric codes and mnemonics
9 * for those codes. Mnemonics are case insensitive.
10 *
11 * @author Brian Wellington
12 */
13
14 class Mnemonic {
15
16 private static Integer cachedInts[] = new Integer[64];
17
18 static {
19 for (int i = 0; i < cachedInts.length; i++) {
20 cachedInts[i] = new Integer(i);
21 }
22 }
23
24 /* Strings are case-sensitive. */
25 static final int CASE_SENSITIVE = 1;
26
27 /* Strings will be stored/searched for in uppercase. */
28 static final int CASE_UPPER = 2;
29
30 /* Strings will be stored/searched for in lowercase. */
31 static final int CASE_LOWER = 3;
32
33 private HashMap strings;
34 private HashMap values;
35 private String description;
36 private int wordcase;
37 private String prefix;
38 private int max;
39 private boolean numericok;
40
41 /**
42 * Creates a new Mnemonic table.
43 * @param description A short description of the mnemonic to use when
44 * @param wordcase Whether to convert strings into uppercase, lowercase,
45 * or leave them unchanged.
46 * throwing exceptions.
47 */
48 public
Mnemonic(String description, int wordcase)49 Mnemonic(String description, int wordcase) {
50 this.description = description;
51 this.wordcase = wordcase;
52 strings = new HashMap();
53 values = new HashMap();
54 max = Integer.MAX_VALUE;
55 }
56
57 /** Sets the maximum numeric value */
58 public void
setMaximum(int max)59 setMaximum(int max) {
60 this.max = max;
61 }
62
63 /**
64 * Sets the prefix to use when converting to and from values that don't
65 * have mnemonics.
66 */
67 public void
setPrefix(String prefix)68 setPrefix(String prefix) {
69 this.prefix = sanitize(prefix);
70 }
71
72 /**
73 * Sets whether numeric values stored in strings are acceptable.
74 */
75 public void
setNumericAllowed(boolean numeric)76 setNumericAllowed(boolean numeric) {
77 this.numericok = numeric;
78 }
79
80 /**
81 * Converts an int into a possibly cached Integer.
82 */
83 public static Integer
toInteger(int val)84 toInteger(int val) {
85 if (val >= 0 && val < cachedInts.length)
86 return (cachedInts[val]);
87 return new Integer(val);
88 }
89
90 /**
91 * Checks that a numeric value is within the range [0..max]
92 */
93 public void
check(int val)94 check(int val) {
95 if (val < 0 || val > max) {
96 throw new IllegalArgumentException(description + " " + val +
97 "is out of range");
98 }
99 }
100
101 /* Converts a String to the correct case. */
102 private String
sanitize(String str)103 sanitize(String str) {
104 if (wordcase == CASE_UPPER)
105 return str.toUpperCase();
106 else if (wordcase == CASE_LOWER)
107 return str.toLowerCase();
108 return str;
109 }
110
111 private int
parseNumeric(String s)112 parseNumeric(String s) {
113 try {
114 int val = Integer.parseInt(s);
115 if (val >= 0 && val <= max)
116 return val;
117 }
118 catch (NumberFormatException e) {
119 }
120 return -1;
121 }
122
123 /**
124 * Defines the text representation of a numeric value.
125 * @param val The numeric value
126 * @param string The text string
127 */
128 public void
add(int val, String str)129 add(int val, String str) {
130 check(val);
131 Integer value = toInteger(val);
132 str = sanitize(str);
133 strings.put(str, value);
134 values.put(value, str);
135 }
136
137 /**
138 * Defines an additional text representation of a numeric value. This will
139 * be used by getValue(), but not getText().
140 * @param val The numeric value
141 * @param string The text string
142 */
143 public void
addAlias(int val, String str)144 addAlias(int val, String str) {
145 check(val);
146 Integer value = toInteger(val);
147 str = sanitize(str);
148 strings.put(str, value);
149 }
150
151 /**
152 * Copies all mnemonics from one table into another.
153 * @param val The numeric value
154 * @param string The text string
155 * @throws IllegalArgumentException The wordcases of the Mnemonics do not
156 * match.
157 */
158 public void
addAll(Mnemonic source)159 addAll(Mnemonic source) {
160 if (wordcase != source.wordcase)
161 throw new IllegalArgumentException(source.description +
162 ": wordcases do not match");
163 strings.putAll(source.strings);
164 values.putAll(source.values);
165 }
166
167 /**
168 * Gets the text mnemonic corresponding to a numeric value.
169 * @param val The numeric value
170 * @return The corresponding text mnemonic.
171 */
172 public String
getText(int val)173 getText(int val) {
174 check(val);
175 String str = (String) values.get(toInteger(val));
176 if (str != null)
177 return str;
178 str = Integer.toString(val);
179 if (prefix != null)
180 return prefix + str;
181 return str;
182 }
183
184 /**
185 * Gets the numeric value corresponding to a text mnemonic.
186 * @param str The text mnemonic
187 * @return The corresponding numeric value, or -1 if there is none
188 */
189 public int
getValue(String str)190 getValue(String str) {
191 str = sanitize(str);
192 Integer value = (Integer) strings.get(str);
193 if (value != null) {
194 return value.intValue();
195 }
196 if (prefix != null) {
197 if (str.startsWith(prefix)) {
198 int val = parseNumeric(str.substring(prefix.length()));
199 if (val >= 0) {
200 return val;
201 }
202 }
203 }
204 if (numericok) {
205 return parseNumeric(str);
206 }
207 return -1;
208 }
209
210 }
211