Author: mheath
Date: Mon Jun 11 16:27:22 2007
New Revision: 546318
URL: http://svn.apache.org/viewvc?view=rev&rev=546318
Log:
Added error checking to putEnumSet.
Added getEnum/putEnum methods.
Modified:
mina/trunk/core/src/main/java/org/apache/mina/common/ByteBuffer.java
mina/trunk/core/src/test/java/org/apache/mina/common/ByteBufferTest.java
Modified: mina/trunk/core/src/main/java/org/apache/mina/common/ByteBuffer.java
URL:
http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/common/ByteBuffer.java?view=diff&rev=546318&r1=546317&r2=546318
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/common/ByteBuffer.java
(original)
+++ mina/trunk/core/src/main/java/org/apache/mina/common/ByteBuffer.java Mon
Jun 11 16:27:22 2007
@@ -1936,6 +1936,99 @@
return this;
}
+ //////////////////////////
+ // Enum methods //
+ //////////////////////////
+
+ /**
+ * Reads a byte from the buffer and returns the correlating enum constant
defined
+ * by the specified enum type.
+ *
+ * @param <E> The enum type to return
+ * @param enumClass The enum's class object
+ * @return
+ */
+ public <E extends Enum<E>> E getEnum(Class<E> enumClass) {
+ return toEnum(enumClass, get());
+ }
+
+ /**
+ * Reads a short from the buffer and returns the correlating enum constant
defined
+ * by the specified enum type.
+ *
+ * @param <E> The enum type to return
+ * @param enumClass The enum's class object
+ * @return
+ */
+ public <E extends Enum<E>> E getEnumShort(Class<E> enumClass) {
+ return toEnum(enumClass, getShort());
+ }
+
+ /**
+ * Reads an int from the buffer and returns the correlating enum constant
defined
+ * by the specified enum type.
+ *
+ * @param <E> The enum type to return
+ * @param enumClass The enum's class object
+ * @return
+ */
+ public <E extends Enum<E>> E getEnumInt(Class<E> enumClass) {
+ return toEnum(enumClass, getInt());
+ }
+
+ /**
+ * Writes an enum's ordinal value to the buffer as a byte.
+ *
+ * @param e The enum to write to the buffer
+ */
+ public void putEnum(Enum e) {
+ if (e.ordinal() > Byte.MAX_VALUE) {
+ throw new IllegalArgumentException(enumConversionErrorMessage(e,
"byte"));
+ }
+ put((byte)e.ordinal());
+ }
+
+ /**
+ * Writes an enum's ordinal value to the buffer as a short.
+ *
+ * @param e The enum to write to the buffer
+ */
+ public void putEnumShort(Enum e) {
+ if (e.ordinal() > Short.MAX_VALUE) {
+ throw new IllegalArgumentException(enumConversionErrorMessage(e,
"short"));
+ }
+ putShort((short)e.ordinal());
+ }
+
+ /**
+ * Writes an enum's ordinal value to the buffer as an integer.
+ *
+ * @param e The enum to write to the buffer
+ */
+ public void putEnumInt(Enum e) {
+ putInt(e.ordinal());
+ }
+
+ private <E> E toEnum(Class<E> enumClass, int i) {
+ E[] enumConstants = enumClass.getEnumConstants();
+ if (i > enumConstants.length) {
+ throw new IndexOutOfBoundsException(String.format("%d is too large
of an ordinal to convert to the enum %s", i, enumClass.getName()));
+ }
+ return enumConstants[i];
+ }
+
+ private String enumConversionErrorMessage(Enum e, String type) {
+ return String.format("%s.%s has an ordinal value too large for a %s",
e.getClass().getName(), e.name(), type);
+ }
+
+ //////////////////////////
+ // EnumSet methods //
+ //////////////////////////
+
+ private static final long BYTE_MASK = 0xFFL;
+ private static final long SHORT_MASK = 0xFFFFL;
+ private static final long INT_MASK = 0xFFFFFFFFL;
+
/**
* Reads a byte sized bit vector and converts it to an [EMAIL PROTECTED]
EnumSet}.
*
@@ -1948,7 +2041,7 @@
* @return the EnumSet representation of the bit vector
*/
public <E extends Enum<E>> EnumSet<E> getEnumSet(Class<E> enumClass) {
- return toEnumSet(enumClass, (long) get() & 0xFFL);
+ return toEnumSet(enumClass, (long) get() & BYTE_MASK);
}
/**
@@ -1960,7 +2053,7 @@
* @return the EnumSet representation of the bit vector
*/
public <E extends Enum<E>> EnumSet<E> getEnumSetShort(Class<E> enumClass) {
- return toEnumSet(enumClass, ((long) getShort()) & 0xFFFFL);
+ return toEnumSet(enumClass, ((long) getShort()) & SHORT_MASK);
}
/**
@@ -1972,7 +2065,7 @@
* @return the EnumSet representation of the bit vector
*/
public <E extends Enum<E>> EnumSet<E> getEnumSetInt(Class<E> enumClass) {
- return toEnumSet(enumClass, (long) getInt() & 0xFFFFFFFFL);
+ return toEnumSet(enumClass, (long) getInt() & INT_MASK);
}
/**
@@ -2009,7 +2102,11 @@
* @param set the enum set to write to the buffer
*/
public <E extends Enum<E>> ByteBuffer putEnumSet(EnumSet<E> set) {
- put((byte) toLong(set));
+ long vector = toLong(set);
+ if ((vector & ~BYTE_MASK) != 0) {
+ throw new IllegalArgumentException("The enum set is too large to
fit in a byte: " + set);
+ }
+ put((byte) vector);
return this;
}
@@ -2020,7 +2117,11 @@
* @param set the enum set to write to the buffer
*/
public <E extends Enum<E>> ByteBuffer putEnumSetShort(EnumSet<E> set) {
- putShort((short) toLong(set));
+ long vector = toLong(set);
+ if ((vector & ~SHORT_MASK) != 0) {
+ throw new IllegalArgumentException("The enum set is too large to
fit in a short: " + set);
+ }
+ putShort((short) vector);
return this;
}
@@ -2031,7 +2132,11 @@
* @param set the enum set to write to the buffer
*/
public <E extends Enum<E>> ByteBuffer putEnumSetInt(EnumSet<E> set) {
- putInt((int) toLong(set));
+ long vector = toLong(set);
+ if ((vector & ~INT_MASK) != 0) {
+ throw new IllegalArgumentException("The enum set is too large to
fit in an int: " + set);
+ }
+ putInt((int) vector);
return this;
}
@@ -2049,9 +2154,12 @@
/**
* Utility method for converting an EnumSet to a bit vector.
*/
- private <E extends Enum<E>> long toLong(EnumSet<E> s) {
+ private <E extends Enum<E>> long toLong(EnumSet<E> set) {
long vector = 0;
- for (E e : s) {
+ for (E e : set) {
+ if (e.ordinal() >= Long.SIZE) {
+ throw new IllegalArgumentException("The enum set is too large
to fit in a bit vector: " + set);
+ }
vector |= 1L << e.ordinal();
}
return vector;
Modified:
mina/trunk/core/src/test/java/org/apache/mina/common/ByteBufferTest.java
URL:
http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/common/ByteBufferTest.java?view=diff&rev=546318&r1=546317&r2=546318
==============================================================================
--- mina/trunk/core/src/test/java/org/apache/mina/common/ByteBufferTest.java
(original)
+++ mina/trunk/core/src/test/java/org/apache/mina/common/ByteBufferTest.java
Mon Jun 11 16:27:22 2007
@@ -735,6 +735,14 @@
E49, E50, E51, E52, E53, E54, E55, E56, E57, E58, E59, E60, E61, E62,
E63, E64
}
+ private static enum TooBigEnum {
+ E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16,
+ E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30,
E31, E32,
+ E33, E34, E35, E36, E37, E38, E39, E40, E41, E42, E43, E44, E45, E46,
E77, E48,
+ E49, E50, E51, E52, E53, E54, E55, E56, E57, E58, E59, E60, E61, E62,
E63, E64,
+ E65
+ }
+
public void testPutEnumSet() {
ByteBuffer buf = ByteBuffer.allocate(8);
@@ -909,5 +917,54 @@
buf.putLong(Long.MIN_VALUE + 1);
buf.flip();
assertEquals(EnumSet.of(TestEnum.E1, TestEnum.E64),
buf.getEnumSetLong(TestEnum.class));
+ }
+
+ public void testBitVectorOverFlow() {
+ ByteBuffer buf = ByteBuffer.allocate(8);
+ try {
+ buf.putEnumSet(EnumSet.of(TestEnum.E9));
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+
+ try {
+ buf.putEnumSetShort(EnumSet.of(TestEnum.E17));
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+
+ try {
+ buf.putEnumSetInt(EnumSet.of(TestEnum.E33));
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+
+ try {
+ buf.putEnumSetLong(EnumSet.of(TooBigEnum.E65));
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+ }
+
+ public void testGetPutEnum() {
+ ByteBuffer buf = ByteBuffer.allocate(4);
+
+ buf.putEnum(TestEnum.E64);
+ buf.flip();
+ assertEquals(TestEnum.E64, buf.getEnum(TestEnum.class));
+
+ buf.clear();
+ buf.putEnumShort(TestEnum.E64);
+ buf.flip();
+ assertEquals(TestEnum.E64, buf.getEnumShort(TestEnum.class));
+
+ buf.clear();
+ buf.putEnumInt(TestEnum.E64);
+ buf.flip();
+ assertEquals(TestEnum.E64, buf.getEnumInt(TestEnum.class));
}
}