8247274: (test) HexPrinter cleanup
Reviewed-by: lancea
This commit is contained in:
parent
99136026b8
commit
120a0d116a
@ -77,10 +77,9 @@ public class HexPrinterTest {
|
||||
Object[][] builtinParams() {
|
||||
return new Object[][]{
|
||||
{"minimal", "", "%02x", 16, "", 64, HexPrinter.Formatters.NONE, ""},
|
||||
{"canonical", "%08x ", "%02x ", 16, "|", 31, HexPrinter.Formatters.ASCII, "|\n"},
|
||||
{"simple", "%5d: ", "%02x ", 16, " // ", 64, HexPrinter.Formatters.PRINTABLE, "\n"},
|
||||
{"source", " ", "(byte)%3d, ", 8, " // ", 64, HexPrinter.Formatters.PRINTABLE,
|
||||
"\n"},
|
||||
{"canonical", "%08x ", "%02x ", 16, "|", 31, HexPrinter.Formatters.PRINTABLE, "|\n"},
|
||||
{"simple", "%5d: ", "%02x ", 16, " // ", 64, HexPrinter.Formatters.ASCII, "\n"},
|
||||
{"source", " ", "(byte)%3d, ", 8, " // ", 64, HexPrinter.Formatters.PRINTABLE, "\n"},
|
||||
};
|
||||
}
|
||||
|
||||
@ -162,6 +161,52 @@ public class HexPrinterTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
static void testPrintable() {
|
||||
String expected =
|
||||
"................................" +
|
||||
" !\"#$%&'()*+,-./0123456789:;<=>?" +
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +
|
||||
"`abcdefghijklmnopqrstuvwxyz{|}~." +
|
||||
"................................" +
|
||||
"................................" +
|
||||
"................................" +
|
||||
"................................";
|
||||
byte[] bytes = new byte[256];
|
||||
for (int i = 0; i < bytes.length; i++)
|
||||
bytes[i] = (byte)i;
|
||||
HexPrinter p = HexPrinter.minimal()
|
||||
.withBytesFormat("", 256)
|
||||
.formatter(HexPrinter.Formatters.PRINTABLE, "", 512);
|
||||
String actual = p.toString(bytes);
|
||||
Assert.assertEquals(actual, expected, "Formatters.Printable mismatch");
|
||||
}
|
||||
|
||||
@Test
|
||||
static void testASCII() {
|
||||
String expected = "\\nul\\soh\\stx\\etx\\eot\\enq\\ack\\bel\\b\\t\\n\\vt\\f\\r\\so\\si\\dle" +
|
||||
"\\dc1\\dc2\\dc3\\dc4\\nak\\syn\\etb\\can\\em\\sub\\esc\\fs\\gs\\rs\\us" +
|
||||
" !\"#$%&'()*+,-./0123456789:;<=>?" +
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +
|
||||
"`abcdefghijklmnopqrstuvwxyz{|}~\\127" +
|
||||
"\\128\\129\\130\\131\\132\\133\\134\\135\\136\\137\\138\\139\\140\\141\\142\\143" +
|
||||
"\\144\\145\\146\\147\\148\\149\\150\\151\\152\\153\\154\\155\\156\\157\\158\\159" +
|
||||
"\\160\\161\\162\\163\\164\\165\\166\\167\\168\\169\\170\\171\\172\\173\\174\\175" +
|
||||
"\\176\\177\\178\\179\\180\\181\\182\\183\\184\\185\\186\\187\\188\\189\\190\\191" +
|
||||
"\\192\\193\\194\\195\\196\\197\\198\\199\\200\\201\\202\\203\\204\\205\\206\\207" +
|
||||
"\\208\\209\\210\\211\\212\\213\\214\\215\\216\\217\\218\\219\\220\\221\\222\\223" +
|
||||
"\\224\\225\\226\\227\\228\\229\\230\\231\\232\\233\\234\\235\\236\\237\\238\\239" +
|
||||
"\\240\\241\\242\\243\\244\\245\\246\\247\\248\\249\\250\\251\\252\\253\\254\\255";
|
||||
byte[] bytes = new byte[256];
|
||||
for (int i = 0; i < bytes.length; i++)
|
||||
bytes[i] = (byte)i;
|
||||
HexPrinter p = HexPrinter.minimal()
|
||||
.withBytesFormat("", 256)
|
||||
.formatter(HexPrinter.Formatters.ASCII, "", 256);
|
||||
String actual = p.toString(bytes);
|
||||
Assert.assertEquals(actual, expected, "Formatters.ASCII mismatch");
|
||||
}
|
||||
|
||||
@DataProvider(name = "PrimitiveFormatters")
|
||||
Object[][] formatterParams() {
|
||||
return new Object[][]{
|
||||
@ -252,6 +297,13 @@ public class HexPrinterTest {
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider(name = "badsources")
|
||||
Object[][] badSources() {
|
||||
return new Object[][]{
|
||||
{genBytes(21), 5, 22},
|
||||
};
|
||||
}
|
||||
|
||||
public static byte[] genData(int len) {
|
||||
// Create a byte array with data for two lines
|
||||
byte[] bytes = new byte[len];
|
||||
@ -312,6 +364,26 @@ public class HexPrinterTest {
|
||||
Assert.assertEquals(r.replace("00", "").length(), 0, "contents not all zeros");
|
||||
}
|
||||
|
||||
@Test(dataProvider = "badsources",
|
||||
expectedExceptions = java.lang.IndexOutOfBoundsException.class)
|
||||
public void testBadToStringByteBuffer(byte[] bytes, int offset, int length) {
|
||||
if (length < 0)
|
||||
length = bytes.length - offset;
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytes, 0, bytes.length);
|
||||
System.out.printf("Source: %s, off: %d, len: %d%n",
|
||||
bytes.getClass().getName(), offset, length);
|
||||
String actual;
|
||||
if (offset == 0 && length < 0) {
|
||||
bb.position(offset);
|
||||
bb.limit(length);
|
||||
actual = HexPrinter.simple().toString(bb);
|
||||
} else
|
||||
actual = HexPrinter.simple().toString(bb, offset, length);
|
||||
System.out.println(actual);
|
||||
String expected = HexPrinter.simple().toString(bytes, offset, length);
|
||||
Assert.assertEquals(actual, expected, "mismatch in format()");
|
||||
}
|
||||
|
||||
@Test(dataProvider = "sources")
|
||||
public void testToStringByteBuffer(byte[] bytes, int offset, int length) {
|
||||
if (length < 0)
|
||||
|
@ -91,7 +91,7 @@ import java.util.Objects;
|
||||
* {@linkplain Formatter Formatter} functions read and interpret the bytes to show the
|
||||
* structure and content of a protocol or data stream.
|
||||
* Built-in formatters include {@link HexPrinter#formatter(Class, String) primitives},
|
||||
* {@link Formatters#PRINTABLE printable ascii},
|
||||
* {@link Formatters#PRINTABLE printable bytes},
|
||||
* and {@link Formatters#utf8Parser(DataInputStream, Appendable) UTF-8 strings}.
|
||||
* The {@link #formatter(Formatter, String, int) formatter} method sets the
|
||||
* formatting function, the delimiter, and the width.
|
||||
@ -238,7 +238,7 @@ public final class HexPrinter {
|
||||
* <LI>each byte value is formatted as 2 hex digits and a space: {@code "%02x "},
|
||||
* <LI>maximum number of byte values per line: {@value initBytesCount},
|
||||
* <LI>delimiter for the annotation: {@code "|"},
|
||||
* <LI>formatter: {@link Formatters#ASCII ASCII bytes}, and
|
||||
* <LI>formatter: {@link Formatters#PRINTABLE printable bytes}, and
|
||||
* <LI>line separator: "|" + {@link System#lineSeparator()},
|
||||
* <LI>destination: {@link System#out System.out}.
|
||||
* </UL>
|
||||
@ -254,7 +254,7 @@ public final class HexPrinter {
|
||||
* @return a new HexPrinter
|
||||
*/
|
||||
public static HexPrinter canonical() {
|
||||
return new HexPrinter(Formatters.ASCII, "%08x ",
|
||||
return new HexPrinter(Formatters.PRINTABLE, "%08x ",
|
||||
"%02x ", initBytesCount,
|
||||
"|", 31, "|" + System.lineSeparator(),
|
||||
System.out);
|
||||
@ -271,7 +271,7 @@ public final class HexPrinter {
|
||||
* <LI>delimiter for the annotation: {@code " // "},
|
||||
* <LI>width for the annotation: {@value initAnnoWidth},
|
||||
* <LI>line separator: {@link System#lineSeparator()},
|
||||
* <LI>formatter: {@link Formatters#PRINTABLE printable ASCII}
|
||||
* <LI>formatter: {@link Formatters#ASCII ASCII bytes}
|
||||
* showing printable characters, mnemonics for control chars, and
|
||||
* otherwise the decimal byte values,
|
||||
* <LI>destination default: {@link System#out System.out}.
|
||||
@ -288,7 +288,7 @@ public final class HexPrinter {
|
||||
* @return a new HexPrinter
|
||||
*/
|
||||
public static HexPrinter simple() {
|
||||
return new HexPrinter(Formatters.PRINTABLE, initOffsetFormat,
|
||||
return new HexPrinter(Formatters.ASCII, initOffsetFormat,
|
||||
initBytesFormat, initBytesCount,
|
||||
initAnnoDelim, initAnnoWidth, System.lineSeparator(),
|
||||
System.out);
|
||||
@ -305,9 +305,8 @@ public final class HexPrinter {
|
||||
* <LI>delimiter for the annotation: {@code " // "},
|
||||
* <LI>width for the annotation: {@value initAnnoWidth},
|
||||
* <LI>line separator: {@link System#lineSeparator()},
|
||||
* <LI>formatter: {@link Formatters#PRINTABLE printable ASCII}
|
||||
* showing printable characters, mnemonics for control chars, and
|
||||
* otherwise the decimal byte values,
|
||||
* <LI>formatter: {@link Formatters#PRINTABLE printable bytes}
|
||||
* showing printable characters and otherwise ".",
|
||||
* <LI>destination default: {@link System#out System.out}.
|
||||
* </UL>
|
||||
*
|
||||
@ -426,34 +425,30 @@ public final class HexPrinter {
|
||||
}
|
||||
|
||||
/**
|
||||
* The formatter function is called repeatedly to read the bytes
|
||||
* from the offset for the length and append the output.
|
||||
* The formatter function is called for the range of the ByteBuffer's contents.
|
||||
* All annotation output is appended and flushed to the output destination.
|
||||
* The ByteBuffer position and limit are unused and not modified.
|
||||
* The ByteBuffer position is not used and not modified.
|
||||
*
|
||||
* @param source a ByteBuffer
|
||||
* @param offset the offset in the ByteBuffer
|
||||
* @param length the length in the ByteBuffer
|
||||
* @param index the index in the ByteBuffer, must be non-negative and
|
||||
* less than {@code limit()}.
|
||||
* @param length the length in the ByteBuffer must be non-negative and
|
||||
* no larger than {@code source.limit() - index}
|
||||
* @return this HexPrinter
|
||||
* @throws java.io.UncheckedIOException if an I/O error occurs
|
||||
* @throws java.lang.IndexOutOfBoundsException if the preconditions on
|
||||
* {@code index} and {@code length} do not hold
|
||||
*/
|
||||
public HexPrinter format(ByteBuffer source, int offset, int length) {
|
||||
public HexPrinter format(ByteBuffer source, int index, int length) {
|
||||
Objects.requireNonNull(source, "ByteBuffer must be non-null");
|
||||
ByteArrayInputStream bais;
|
||||
if (source.hasArray() && !source.isReadOnly()) {
|
||||
bais = new ByteArrayInputStream(source.array(), offset, length);
|
||||
} else {
|
||||
int size = source.limit() - source.position();
|
||||
byte[] bytes = new byte[size];
|
||||
source.get(bytes, offset, length);
|
||||
bais = new ByteArrayInputStream(bytes);
|
||||
}
|
||||
return format(bais, offset);
|
||||
byte[] bytes = new byte[length];
|
||||
source.get(index, bytes, 0, length);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
return format(bais, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* The formatter function is called repeatedly to read all of the bytes
|
||||
* in the source and append the output.
|
||||
* The formatter function is called for the ByteBuffer's contents.
|
||||
* The source bytes are from the {@code ByteBuffer.position()}
|
||||
* to the {@code ByteBuffer.limit()}.
|
||||
* The position is not modified.
|
||||
@ -464,7 +459,7 @@ public final class HexPrinter {
|
||||
* @throws java.io.UncheckedIOException if an I/O error occurs
|
||||
*/
|
||||
public HexPrinter format(ByteBuffer source) {
|
||||
return format(source, source.position(), source.limit());
|
||||
return format(source, source.position(), source.limit() - source.position());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -544,37 +539,36 @@ public final class HexPrinter {
|
||||
}
|
||||
|
||||
/**
|
||||
* The formatter function is called repeatedly to read the bytes
|
||||
* from the offset for the length and return a String.
|
||||
* The ByteBuffer position and limit are unused and not modified.
|
||||
* The formatter function is called for the range of the ByteBuffer contents
|
||||
* and returned as a string.
|
||||
* The ByteBuffer position is not used and not modified.
|
||||
*
|
||||
* @param source a ByteBuffer
|
||||
* @param offset the offset in the ByteBuffer
|
||||
* @param length the length in the ByteBuffer
|
||||
* @param index the index in the ByteBuffer, must be non-negative and
|
||||
* less than {@code limit()}.
|
||||
* @param length the length in the ByteBuffer must be non-negative and
|
||||
* no larger than {@code source.limit() - index}
|
||||
* @return the output as a non-null {@code String}
|
||||
* @throws java.io.UncheckedIOException if an I/O error occurs
|
||||
* @throws java.lang.IndexOutOfBoundsException if the preconditions on
|
||||
* {@code index} and {@code length} do not hold
|
||||
*/
|
||||
public String toString(ByteBuffer source, int offset, int length) {
|
||||
public String toString(ByteBuffer source, int index, int length) {
|
||||
Objects.requireNonNull(source, "ByteBuffer must be non-null");
|
||||
byte[] bytes = new byte[length];
|
||||
source.get(index, bytes, 0, length);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ByteArrayInputStream bais;
|
||||
if (source.hasArray() && !source.isReadOnly()) {
|
||||
bais = new ByteArrayInputStream(source.array(), offset, length);
|
||||
} else {
|
||||
byte[] bytes = new byte[length];
|
||||
source.get(bytes, offset, length);
|
||||
bais = new ByteArrayInputStream(bytes);
|
||||
}
|
||||
try (AnnotationWriter writer =
|
||||
new AnnotationWriter(this, bais, offset, sb)) {
|
||||
new AnnotationWriter(this, bais, index, sb)) {
|
||||
writer.flush();
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The formatter function is called repeatedly to read all of the bytes
|
||||
* in the source and return a String.
|
||||
* The formatter function is called for the ByteBuffer contents
|
||||
* and returned as a string.
|
||||
* The source bytes are from the {@code ByteBuffer.position()}
|
||||
* to the {@code ByteBuffer.limit()}.
|
||||
* The position is not modified.
|
||||
@ -584,7 +578,7 @@ public final class HexPrinter {
|
||||
* @throws java.io.UncheckedIOException if an I/O error occurs
|
||||
*/
|
||||
public String toString(ByteBuffer source) {
|
||||
return toString(source, source.position(), source.limit());
|
||||
return toString(source, source.position(), source.limit() - source.position());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -830,18 +824,20 @@ public final class HexPrinter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in formatters for printable byte, ASCII, UTF-8 and primitive types.
|
||||
* Built-in formatters for printable byte, ASCII byte, UTF-8 and primitive types.
|
||||
* Formatters for primitive types and different formatting options
|
||||
* can be found by calling {@link #ofPrimitive(Class, String)}.
|
||||
*/
|
||||
public enum Formatters implements Formatter {
|
||||
/**
|
||||
* Read a byte and if it is ASCII write it,
|
||||
* otherwise, write its mnemonic or its decimal value.
|
||||
* Read a byte, return the value as a single character string
|
||||
* if it is printable, otherwise return ".".
|
||||
*/
|
||||
PRINTABLE,
|
||||
/**
|
||||
* Read a byte, if it is ASCII write it, otherwise write a ".".
|
||||
* Read a byte and return it as a string.
|
||||
* Return the character if it is ASCII, return its mnemonic if it
|
||||
* is a control character, otherwise return its decimal value as a string.
|
||||
*/
|
||||
ASCII,
|
||||
/**
|
||||
@ -863,10 +859,8 @@ public final class HexPrinter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte and write it as ASCII if it is printable,
|
||||
* print its mnemonic if it is a control character,
|
||||
* and print its decimal value otherwise.
|
||||
* A space separator character is appended for control and decimal values.
|
||||
* Read a byte and return it as a single character string if it is printable,
|
||||
* otherwise return ".".
|
||||
*
|
||||
* @param in a DataInputStream
|
||||
* @param out an Appendable to write to
|
||||
@ -874,17 +868,17 @@ public final class HexPrinter {
|
||||
*/
|
||||
static void bytePrintable(DataInputStream in, Appendable out) throws IOException {
|
||||
int v = in.readUnsignedByte();
|
||||
if (v < 32) {
|
||||
out.append("\\").append(CONTROL_MNEMONICS[v]);
|
||||
} else if (v < 126 && Character.isDefined(v)) {
|
||||
if (!Character.isISOControl(v) && v < 127) {
|
||||
out.append((char) v);
|
||||
} else {
|
||||
out.append("\\").append(Integer.toString(v, 10));
|
||||
out.append('.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte and write it as ASCII if it is printable, otherwise print ".".
|
||||
* Read a byte and return it as a string.
|
||||
* Append the byte if it is ASCII, its mnemonic if it
|
||||
* is a control character, and otherwise its decimal value.
|
||||
*
|
||||
* @param in a DataInputStream
|
||||
* @param out an Appendable to write to
|
||||
@ -892,10 +886,12 @@ public final class HexPrinter {
|
||||
*/
|
||||
static void byteASCII(DataInputStream in, Appendable out) throws IOException {
|
||||
int v = in.readUnsignedByte();
|
||||
if (Character.isDefined(v)) {
|
||||
if (v < 32) {
|
||||
out.append('\\').append(CONTROL_MNEMONICS[v]);
|
||||
} else if (v < 127) {
|
||||
out.append((char) v);
|
||||
} else {
|
||||
out.append('.');
|
||||
out.append('\\').append(Integer.toString(v, 10));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user