diff --git a/src/dorkbox/network/dns/Mnemonic.java b/src/dorkbox/network/dns/Mnemonic.java index 33c0587d..0a0945d6 100644 --- a/src/dorkbox/network/dns/Mnemonic.java +++ b/src/dorkbox/network/dns/Mnemonic.java @@ -2,7 +2,9 @@ package dorkbox.network.dns; -import java.util.HashMap; +import com.esotericsoftware.kryo.util.IntMap; + +import dorkbox.util.collections.ObjectIntMap; /** * A utility class for converting between numeric codes and mnemonics @@ -13,29 +15,21 @@ import java.util.HashMap; public class Mnemonic { - private static Integer cachedInts[] = new Integer[64]; /* Strings are case-sensitive. */ public static final int CASE_SENSITIVE = 1; /* Strings will be stored/searched for in uppercase. */ public static final int CASE_UPPER = 2; /* Strings will be stored/searched for in lowercase. */ public static final int CASE_LOWER = 3; - - - private HashMap strings; - private HashMap values; + private static final int INVALID_VALUE = -1; + private ObjectIntMap strings; + private IntMap values; private String description; private int wordcase; private String prefix; private int max; private boolean numericok; - static { - for (int i = 0; i < cachedInts.length; i++) { - cachedInts[i] = new Integer(i); - } - } - /** * Creates a new Mnemonic table. * @@ -48,8 +42,8 @@ class Mnemonic { Mnemonic(String description, int wordcase) { this.description = description; this.wordcase = wordcase; - strings = new HashMap(); - values = new HashMap(); + strings = new ObjectIntMap(); + values = new IntMap(); max = Integer.MAX_VALUE; } @@ -93,29 +87,17 @@ class Mnemonic { /** * Defines the text representation of a numeric value. * - * @param val The numeric value + * @param value The numeric value * @param string The text string */ public - void add(int val, String string) { - check(val); - Integer value = toInteger(val); + void add(int value, String string) { + check(value); string = sanitize(string); strings.put(string, value); values.put(value, string); } - /** - * Converts an int into a possibly cached Integer. - */ - public static - Integer toInteger(int val) { - if (val >= 0 && val < cachedInts.length) { - return (cachedInts[val]); - } - return new Integer(val); - } - /** * Checks that a numeric value is within the range [0..max] */ @@ -130,13 +112,12 @@ class Mnemonic { * Defines an additional text representation of a numeric value. This will * be used by getValue(), but not getText(). * - * @param val The numeric value + * @param value The numeric value * @param string The text string */ public - void addAlias(int val, String string) { - check(val); - Integer value = toInteger(val); + void addAlias(int value, String string) { + check(value); string = sanitize(string); strings.put(string, value); } @@ -154,6 +135,7 @@ class Mnemonic { if (wordcase != source.wordcase) { throw new IllegalArgumentException(source.description + ": wordcases do not match"); } + strings.putAll(source.strings); values.putAll(source.values); } @@ -161,18 +143,19 @@ class Mnemonic { /** * Gets the text mnemonic corresponding to a numeric value. * - * @param val The numeric value + * @param value The numeric value * * @return The corresponding text mnemonic. */ public - String getText(int val) { - check(val); - String str = (String) values.get(toInteger(val)); + String getText(int value) { + check(value); + String str = values.get(value); if (str != null) { return str; } - str = Integer.toString(val); + + str = Integer.toString(value); if (prefix != null) { return prefix + str; } @@ -189,9 +172,10 @@ class Mnemonic { public int getValue(String str) { str = sanitize(str); - Integer value = (Integer) strings.get(str); - if (value != null) { - return value.intValue(); + int value = strings.get(str, INVALID_VALUE); + + if (value != INVALID_VALUE) { + return value; } if (prefix != null) { if (str.startsWith(prefix)) { @@ -204,7 +188,8 @@ class Mnemonic { if (numericok) { return parseNumeric(str); } - return -1; + + return INVALID_VALUE; } private @@ -214,9 +199,9 @@ class Mnemonic { if (val >= 0 && val <= max) { return val; } - } catch (NumberFormatException e) { + } catch (NumberFormatException ignored) { } - return -1; - } + return INVALID_VALUE; + } } diff --git a/src/dorkbox/network/dns/constants/DnsRecordType.java b/src/dorkbox/network/dns/constants/DnsRecordType.java index 058e7ca8..ff243ce5 100644 --- a/src/dorkbox/network/dns/constants/DnsRecordType.java +++ b/src/dorkbox/network/dns/constants/DnsRecordType.java @@ -2,12 +2,11 @@ package dorkbox.network.dns.constants; -import java.util.HashMap; - import dorkbox.network.dns.Mnemonic; import dorkbox.network.dns.exceptions.InvalidTypeException; import dorkbox.network.dns.records.DnsRecord; import dorkbox.network.dns.records.DnsTypeProtoAssignment; +import dorkbox.util.collections.IntMap; import io.netty.util.internal.StringUtil; /** @@ -449,25 +448,26 @@ class DnsRecordType { public static class TypeMnemonic extends Mnemonic { - private HashMap objects; + private IntMap objects; public TypeMnemonic() { super("DnsRecordType", CASE_UPPER); setPrefix("TYPE"); - objects = new HashMap(); + objects = new IntMap(); } public - void add(int val, String str, DnsRecord proto) { - super.add(val, str); - objects.put(Mnemonic.toInteger(val), proto); + void add(int value, String str, DnsRecord proto) { + super.add(value, str); + objects.put(value, proto); } + @SuppressWarnings("unchecked") public - T getProto(int val) { - check(val); - return (T) objects.get(toInteger(val)); + T getProto(int value) { + check(value); + return (T) objects.get(value); } @Override diff --git a/src/dorkbox/network/dns/records/TSIG.java b/src/dorkbox/network/dns/records/TSIG.java index 1b0994b8..0cad79e0 100644 --- a/src/dorkbox/network/dns/records/TSIG.java +++ b/src/dorkbox/network/dns/records/TSIG.java @@ -5,16 +5,14 @@ package dorkbox.network.dns.records; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Arrays; -import java.util.Collections; import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import com.esotericsoftware.kryo.util.ObjectMap; + import dorkbox.network.dns.DnsOutput; import dorkbox.network.dns.Name; import dorkbox.network.dns.constants.DnsClass; @@ -32,6 +30,7 @@ import dorkbox.util.Base64Fast; * @see TSIGRecord */ +@SuppressWarnings("WeakerAccess") public class TSIG { @@ -72,9 +71,10 @@ class TSIG { */ public static final Name HMAC_SHA512 = Name.fromConstantString("hmac-sha512."); - private static Map algMap; + private static final ObjectMap algMap = new ObjectMap(); + /** - * The default fudge value for outgoing packets. Can be overriden by the + * The default fudge value for outgoing packets. Can be overridden by the * tsigfudge option. */ public static final short FUDGE = 300; @@ -82,14 +82,12 @@ class TSIG { private Mac hmac; static { - Map out = new HashMap(); - out.put(HMAC_MD5, "HmacMD5"); - out.put(HMAC_SHA1, "HmacSHA1"); - out.put(HMAC_SHA224, "HmacSHA224"); - out.put(HMAC_SHA256, "HmacSHA256"); - out.put(HMAC_SHA384, "HmacSHA384"); - out.put(HMAC_SHA512, "HmacSHA512"); - algMap = Collections.unmodifiableMap(out); + algMap.put(HMAC_MD5, "HmacMD5"); + algMap.put(HMAC_SHA1, "HmacSHA1"); + algMap.put(HMAC_SHA224, "HmacSHA224"); + algMap.put(HMAC_SHA256, "HmacSHA256"); + algMap.put(HMAC_SHA384, "HmacSHA384"); + algMap.put(HMAC_SHA512, "HmacSHA512"); } /** @@ -143,7 +141,7 @@ class TSIG { public static String nameToAlgorithm(Name name) { - String alg = (String) algMap.get(name); + String alg = algMap.get(name); if (alg != null) { return alg; } @@ -177,14 +175,13 @@ class TSIG { public static Name algorithmToName(String alg) { - Iterator it = algMap.entrySet() - .iterator(); - while (it.hasNext()) { - Map.Entry entry = (Map.Entry) it.next(); - if (alg.equalsIgnoreCase((String) entry.getValue())) { - return (Name) entry.getKey(); - } + + // false identity check because it's string comparisons. + Name foundKey = algMap.findKey(alg, false); + if (foundKey != null) { + return foundKey; } + throw new IllegalArgumentException("Unknown algorithm"); } diff --git a/src/dorkbox/network/dns/records/TypeBitmap.java b/src/dorkbox/network/dns/records/TypeBitmap.java index abe41e78..782fb6b3 100644 --- a/src/dorkbox/network/dns/records/TypeBitmap.java +++ b/src/dorkbox/network/dns/records/TypeBitmap.java @@ -15,59 +15,66 @@ import java.util.TreeSet; import dorkbox.network.dns.DnsInput; import dorkbox.network.dns.DnsOutput; -import dorkbox.network.dns.Mnemonic; import dorkbox.network.dns.constants.DnsRecordType; import dorkbox.network.dns.exceptions.WireParseException; import dorkbox.network.dns.utils.Tokenizer; +import dorkbox.util.collections.IntMap; +import dorkbox.util.collections.IntMap.Keys; final class TypeBitmap implements Serializable { private static final long serialVersionUID = -125354057735389003L; - private TreeSet types; + private IntMap types; public TypeBitmap(int[] array) { this(); for (int i = 0; i < array.length; i++) { DnsRecordType.check(array[i]); - types.add(new Integer(array[i])); + types.put(array[i], Boolean.TRUE); } } private TypeBitmap() { - types = new TreeSet(); + types = new IntMap(); } public TypeBitmap(DnsInput in) throws WireParseException { this(); int lastbase = -1; + while (in.remaining() > 0) { if (in.remaining() < 2) { throw new WireParseException("invalid bitmap descriptor"); } + int mapbase = in.readU8(); if (mapbase < lastbase) { throw new WireParseException("invalid ordering"); } + int maplength = in.readU8(); if (maplength > in.remaining()) { throw new WireParseException("invalid bitmap"); } + for (int i = 0; i < maplength; i++) { int current = in.readU8(); if (current == 0) { continue; } + for (int j = 0; j < 8; j++) { if ((current & (1 << (7 - j))) == 0) { continue; } + int typecode = mapbase * 256 + +i * 8 + j; - types.add(Mnemonic.toInteger(typecode)); + types.put(typecode, Boolean.TRUE); } } } @@ -76,54 +83,71 @@ class TypeBitmap implements Serializable { public TypeBitmap(Tokenizer st) throws IOException { this(); + while (true) { Tokenizer.Token t = st.get(); if (!t.isString()) { break; } + int typecode = DnsRecordType.value(t.value); if (typecode < 0) { throw st.exception("Invalid type: " + t.value); } - types.add(Mnemonic.toInteger(typecode)); + + types.put(typecode, Boolean.TRUE); } st.unget(); } public int[] toArray() { - int[] array = new int[types.size()]; + int[] array = new int[types.size]; int n = 0; - for (Iterator it = types.iterator(); it.hasNext(); ) { - array[n++] = ((Integer) it.next()).intValue(); + + + Keys keys = types.keys(); + while (keys.hasNext) { + array[n++] = keys.next(); } + return array; } + @Override public String toString() { StringBuilder sb = new StringBuilder(); - for (Iterator it = types.iterator(); it.hasNext(); ) { - int t = ((Integer) it.next()).intValue(); - sb.append(DnsRecordType.string(t)); - if (it.hasNext()) { - sb.append(' '); - } + + Keys keys = types.keys(); + while (keys.hasNext) { + int t = keys.next(); + sb.append(DnsRecordType.string(t)) + .append(' '); } + + // remove the last ' ' + int length = sb.length(); + if (length > 1) { + sb.delete(length - 1, length); + } + return sb.toString(); } public void toWire(DnsOutput out) { - if (types.size() == 0) { + if (types.size == 0) { return; } int mapbase = -1; TreeSet map = new TreeSet(); - for (Iterator it = types.iterator(); it.hasNext(); ) { - int t = ((Integer) it.next()).intValue(); + Keys keys = types.keys(); + while (keys.hasNext) { + int t = keys.next(); + int base = t >> 8; if (base != mapbase) { if (map.size() > 0) { @@ -134,20 +158,27 @@ class TypeBitmap implements Serializable { } map.add(new Integer(t)); } + mapToWire(out, map, mapbase); } + /** + * @param map this must be an ordered data structure! + */ private static void mapToWire(DnsOutput out, TreeSet map, int mapbase) { int arraymax = (((Integer) map.last()).intValue()) & 0xFF; int arraylength = (arraymax / 8) + 1; int[] array = new int[arraylength]; + out.writeU8(mapbase); out.writeU8(arraylength); + for (Iterator it = map.iterator(); it.hasNext(); ) { int typecode = ((Integer) it.next()).intValue(); array[(typecode & 0xFF) / 8] |= (1 << (7 - typecode % 8)); } + for (int j = 0; j < arraylength; j++) { out.writeU8(array[j]); } @@ -155,12 +186,11 @@ class TypeBitmap implements Serializable { public boolean empty() { - return types.isEmpty(); + return types.size == 0; } public boolean contains(int typecode) { - return types.contains(Mnemonic.toInteger(typecode)); + return types.containsKey(typecode); } - } diff --git a/test/dorkbox/network/dns/records/MnemonicTest.java b/test/dorkbox/network/dns/records/MnemonicTest.java index 581940dd..2dec6cd6 100644 --- a/test/dorkbox/network/dns/records/MnemonicTest.java +++ b/test/dorkbox/network/dns/records/MnemonicTest.java @@ -54,39 +54,12 @@ class MnemonicTest extends TestCase { m_mn = new Mnemonic(MnemonicTest.class.getName() + " UPPER", Mnemonic.CASE_UPPER); } - public - void test_toInteger() { - Integer i = Mnemonic.toInteger(64); - assertEquals(new Integer(64), i); - Integer i2 = Mnemonic.toInteger(64); - assertEquals(i, i2); - assertNotSame(i, i2); - - i = Mnemonic.toInteger(-1); - assertEquals(new Integer(-1), i); - i2 = Mnemonic.toInteger(-1); - assertEquals(i, i2); - assertNotSame(i, i2); - - i = Mnemonic.toInteger(0); - assertEquals(new Integer(0), i); - i2 = Mnemonic.toInteger(0); - assertEquals(i, i2); - assertSame(i, i2); - - i = Mnemonic.toInteger(63); - assertEquals(new Integer(63), i); - i2 = Mnemonic.toInteger(63); - assertEquals(i, i2); - assertSame(i, i2); - } - public void test_no_maximum() { try { m_mn.check(-1); fail("IllegalArgumentException not thrown"); - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException ignored) { } try { m_mn.check(0); @@ -117,7 +90,7 @@ class MnemonicTest extends TestCase { try { m_mn.check(-1); fail("IllegalArgumentException not thrown"); - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException ignored) { } try { m_mn.check(0); @@ -132,7 +105,7 @@ class MnemonicTest extends TestCase { try { m_mn.check(16); fail("IllegalArgumentException not thrown"); - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException ignored) { } // need numericok to exercise the usage of max in parseNumeric