# HG changeset patch # User Tom Rodriguez # Date 1462557700 25200 # Node ID 3039c53c72d3597bc3f70b954a9dd49c25179e89 # Parent ae27c683c12882fb019bc4d525eea4ee96c39188 Add explicit version number to binary IGV format and add some backwards compatibility logic diff -r ae27c683c128 -r 3039c53c72d3 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Fri May 06 13:21:20 2016 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Fri May 06 11:01:40 2016 -0700 @@ -70,6 +70,7 @@ private static final String NO_BLOCK = "noBlock"; private static final Charset utf8 = Charset.forName("UTF-8"); + private static final Charset utf16 = Charset.forName("UTF-16"); private final GroupCallback callback; private final List constantPool; @@ -82,6 +83,37 @@ private MessageDigest digest; + private Charset stringCharset; + + private int majorVersion; + private int minorVersion; + + static final int CURRENT_MAJOR_VERSION = 1; + static final int CURRENT_MINOR_VERSION = 0; + static final String CURRENT_VERSION = versionPair(CURRENT_MAJOR_VERSION, CURRENT_MINOR_VERSION); + + static class VersionMismatchException extends RuntimeException { + VersionMismatchException(String message) { + super(message); + } + } + + static final byte[] magicBytes = { 'B', 'I', 'G', 'V' }; + + private static String versionPair(int major, int minor) { + return major + "." + minor; + } + + private void setVersion(int newMajorVersion, int newMinorVersion) { + if (newMajorVersion > CURRENT_MAJOR_VERSION || (newMajorVersion == CURRENT_MAJOR_VERSION && newMinorVersion > CURRENT_MINOR_VERSION)) { + throw new VersionMismatchException("File format version " + versionPair(newMajorVersion, newMinorVersion) + " unsupported. Current version is " + CURRENT_VERSION); + } + + majorVersion = newMajorVersion; + minorVersion = newMinorVersion; + stringCharset = utf8; + } + private enum Length { S, M, @@ -341,7 +373,27 @@ } private String readString() throws IOException { - return new String(readBytes(), utf8).intern(); + if (stringCharset == utf8) { + return new String(readBytes(), utf8).intern(); + } else if (stringCharset == utf16) { + int len = readInt(); + byte[] b = readBytes(len * 2); + return new String(b, utf16).intern(); + } + int len = readInt(); + // Backwards compatibility + if (len == 0) { + return ""; + } + byte[] b = peekBytes(1); + if (b[0] == '\0') { + // Assume UTF16 encoding + stringCharset = utf16; + return new String(readBytes(len * 2), utf16).intern(); + } else { + setVersion(1, 0); + return new String(readBytes(len), utf8).intern(); + } } private byte[] readBytes() throws IOException { @@ -349,6 +401,10 @@ if (len < 0) { return null; } + return readBytes(len); + } + + private byte[] readBytes(int len) throws IOException { byte[] b = new byte[len]; int bytesRead = 0; while (bytesRead < b.length) { @@ -359,6 +415,15 @@ } return b; } + + private byte[] peekBytes(int len) throws IOException { + ensureAvailable(len); + byte[] b = new byte[len]; + buffer.mark(); + buffer.get(b); + buffer.reset(); + return b; + } private String readIntsToString() throws IOException { int len = readInt(); @@ -587,6 +652,13 @@ monitor.setState("Starting parsing"); } try { + // Check for a version specification + byte[] magic = peekBytes(magicBytes.length); + if (Arrays.equals(magicBytes, magic)) { + // Consume the bytes for real + readBytes(magicBytes.length); + setVersion(readByte(), readByte()); + } while(true) { parseRoot(); }