1// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS;
4
5import 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
14class Mnemonic {
15
16private static Integer cachedInts[] = new Integer[64];
17
18static {
19	for (int i = 0; i < cachedInts.length; i++) {
20		cachedInts[i] = new Integer(i);
21	}
22}
23
24/* Strings are case-sensitive. */
25static final int CASE_SENSITIVE = 1;
26
27/* Strings will be stored/searched for in uppercase. */
28static final int CASE_UPPER = 2;
29
30/* Strings will be stored/searched for in lowercase. */
31static final int CASE_LOWER = 3;
32
33private HashMap strings;
34private HashMap values;
35private String description;
36private int wordcase;
37private String prefix;
38private int max;
39private 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 */
48public
49Mnemonic(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 */
58public void
59setMaximum(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 */
67public void
68setPrefix(String prefix) {
69	this.prefix = sanitize(prefix);
70}
71
72/**
73 * Sets whether numeric values stored in strings are acceptable.
74 */
75public void
76setNumericAllowed(boolean numeric) {
77	this.numericok = numeric;
78}
79
80/**
81 * Converts an int into a possibly cached Integer.
82 */
83public static Integer
84toInteger(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 */
93public void
94check(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. */
102private String
103sanitize(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
111private int
112parseNumeric(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 */
128public void
129add(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 */
143public void
144addAlias(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 */
158public void
159addAll(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 */
172public String
173getText(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 */
189public int
190getValue(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