From 7493473a8e8f0cfb74cc6f42195f02cd0e95b7ba Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Tue, 24 Dec 2019 19:48:22 +0000 Subject: [PATCH] Replace internal GUID class with ClassID git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1871944 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/poi/hpsf/ClassID.java | 75 ++++-- .../apache/poi/hpsf/ClassIDPredefined.java | 23 +- .../poi/hssf/record/HyperlinkRecord.java | 228 +++--------------- .../poi/hssf/record/TestHyperlinkRecord.java | 71 +++--- 4 files changed, 138 insertions(+), 259 deletions(-) diff --git a/src/java/org/apache/poi/hpsf/ClassID.java b/src/java/org/apache/poi/hpsf/ClassID.java index 47eb272daa..a60b50e86c 100644 --- a/src/java/org/apache/poi/hpsf/ClassID.java +++ b/src/java/org/apache/poi/hpsf/ClassID.java @@ -19,17 +19,20 @@ package org.apache.poi.hpsf; import java.util.Arrays; -import org.apache.poi.util.HexDump; +import org.apache.commons.codec.binary.Hex; +import org.apache.poi.common.Duplicatable; +import org.apache.poi.util.LittleEndianInput; +import org.apache.poi.util.LittleEndianOutput; /** * Represents a class ID (16 bytes). Unlike other little-endian * type the {@link ClassID} is not just 16 bytes stored in the wrong * order. Instead, it is a double word (4 bytes) followed by two * words (2 bytes each) followed by 8 bytes.

- * - * The ClassID (or CLSID) is a UUID - see RFC 4122 + * + * The ClassID (or CLSID) is a UUID - see RFC 4122 */ -public class ClassID { +public class ClassID implements Duplicatable { /** @deprecated use enum {@link ClassIDPredefined} */ @Deprecated public static final ClassID OLE10_PACKAGE = ClassIDPredefined.OLE_V1_PACKAGE.getClassID(); /** @deprecated use enum {@link ClassIDPredefined} */ @Deprecated @@ -84,10 +87,10 @@ public class ClassID { public static final ClassID POWERPOINT2007_MACRO = ClassIDPredefined.POWERPOINT_V12_MACRO.getClassID(); /** @deprecated use enum {@link ClassIDPredefined} */ @Deprecated public static final ClassID EQUATION30 = ClassIDPredefined.EQUATION_V3.getClassID(); - + /** The number of bytes occupied by this object in the byte stream. */ public static final int LENGTH = 16; - + /** * The bytes making out the class ID in correct order, i.e. big-endian. */ @@ -111,11 +114,18 @@ public class ClassID { Arrays.fill(bytes, (byte)0); } + /** + * Clones the given ClassID + */ + public ClassID(ClassID other) { + System.arraycopy(other.bytes, 0, bytes, 0, bytes.length); + } + /** - * Creates a {@link ClassID} from a human-readable representation of the Class ID in standard + * Creates a {@link ClassID} from a human-readable representation of the Class ID in standard * format {@code "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"}. - * + * * @param externalForm representation of the Class ID represented by this object. */ public ClassID(String externalForm) { @@ -124,7 +134,16 @@ public class ClassID { bytes[i/2] = (byte)Integer.parseInt(clsStr.substring(i, i+2), 16); } } - + + /** + * Reads the ClassID from the input + * @param lei the input (stream) + */ + public ClassID(LittleEndianInput lei) { + byte[] buf = bytes.clone(); + lei.readFully(buf); + read(buf, 0); + } /** * @return The number of bytes occupied by this object in the byte stream. @@ -204,7 +223,7 @@ public class ClassID { ("Destination byte[] must have room for at least 16 bytes, " + "but has a length of only " + dst.length + "."); } - + /* Write double word. */ dst[0 + offset] = bytes[3]; dst[1 + offset] = bytes[2]; @@ -223,7 +242,16 @@ public class ClassID { System.arraycopy(bytes, 8, dst, 8 + offset, 8); } - + /** + * Write the class ID to a LittleEndianOutput (stream) + * + * @param leo the output + */ + public void write(LittleEndianOutput leo) { + byte[] buf = bytes.clone(); + write(buf, 0); + leo.write(buf); + } /** * Checks whether this {@code ClassID} is equal to another object. @@ -275,22 +303,23 @@ public class ClassID { } /** - * Returns a human-readable representation of the Class ID in standard + * Returns a human-readable representation of the Class ID in standard * format {@code "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"}. - * + * * @return String representation of the Class ID represented by this object. */ @Override public String toString() { - StringBuilder sbClassId = new StringBuilder(38); - sbClassId.append('{'); - for (int i = 0; i < LENGTH; i++) { - sbClassId.append(HexDump.toHex(bytes[i])); - if (i == 3 || i == 5 || i == 7 || i == 9) { - sbClassId.append('-'); - } - } - sbClassId.append('}'); - return sbClassId.toString(); + String hex = Hex.encodeHexString(bytes, false); + return "{" + hex.substring(0,8) + + "-" + hex.substring(8,12) + + "-" + hex.substring(12,16) + + "-" + hex.substring(16,20) + + "-" + hex.substring(20) + "}"; + } + + @Override + public ClassID copy() { + return new ClassID(this); } } diff --git a/src/java/org/apache/poi/hpsf/ClassIDPredefined.java b/src/java/org/apache/poi/hpsf/ClassIDPredefined.java index 5e81639d41..1974c3164d 100644 --- a/src/java/org/apache/poi/hpsf/ClassIDPredefined.java +++ b/src/java/org/apache/poi/hpsf/ClassIDPredefined.java @@ -86,9 +86,16 @@ public enum ClassIDPredefined { /** Plain Text Persistent Handler **/ TXT_ONLY ("{5e941d80-bf96-11cd-b579-08002b30bfeb}", ".txt", "text/plain"), /** Microsoft Paint **/ - PAINT ("{0003000A-0000-0000-C000-000000000046}", null, null) + PAINT ("{0003000A-0000-0000-C000-000000000046}", null, null), + /** Standard Hyperlink / STD Moniker **/ + STD_MONIKER ("{79EAC9D0-BAF9-11CE-8C82-00AA004BA90B}", null, null), + /** URL Moniker **/ + URL_MONIKER ("{79EAC9E0-BAF9-11CE-8C82-00AA004BA90B}", null, null), + /** File Moniker **/ + FILE_MONIKER ("{00000303-0000-0000-C000-000000000046}", null, null) ; - + + private static final Map LOOKUP = new HashMap<>(); static { @@ -96,18 +103,18 @@ public enum ClassIDPredefined { LOOKUP.put(p.externalForm, p); } } - + private final String externalForm; private ClassID classId; private final String fileExtension; private final String contentType; - + ClassIDPredefined(final String externalForm, final String fileExtension, final String contentType) { this.externalForm = externalForm; this.fileExtension = fileExtension; this.contentType = contentType; } - + public ClassID getClassID() { synchronized (this) { // TODO: init classId directly in the constructor when old statics have been removed from ClassID @@ -125,7 +132,7 @@ public enum ClassIDPredefined { public String getContentType() { return contentType; } - + public static ClassIDPredefined lookup(final String externalForm) { return LOOKUP.get(externalForm); } @@ -133,4 +140,8 @@ public enum ClassIDPredefined { public static ClassIDPredefined lookup(final ClassID classID) { return (classID == null) ? null : LOOKUP.get(classID.toString()); } + + public boolean equals(ClassID classID) { + return getClassID().equals(classID); + } } diff --git a/src/java/org/apache/poi/hssf/record/HyperlinkRecord.java b/src/java/org/apache/poi/hssf/record/HyperlinkRecord.java index ae6ae086a7..97888bac6c 100644 --- a/src/java/org/apache/poi/hssf/record/HyperlinkRecord.java +++ b/src/java/org/apache/poi/hssf/record/HyperlinkRecord.java @@ -17,11 +17,15 @@ package org.apache.poi.hssf.record; +import static org.apache.poi.hpsf.ClassIDPredefined.FILE_MONIKER; +import static org.apache.poi.hpsf.ClassIDPredefined.STD_MONIKER; +import static org.apache.poi.hpsf.ClassIDPredefined.URL_MONIKER; + +import org.apache.poi.hpsf.ClassID; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.util.HexDump; import org.apache.poi.util.HexRead; import org.apache.poi.util.IOUtils; -import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndianInput; import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.POILogFactory; @@ -37,177 +41,11 @@ import org.apache.poi.util.StringUtil; */ public final class HyperlinkRecord extends StandardRecord { public static final short sid = 0x01B8; - private static POILogger logger = POILogFactory.getLogger(HyperlinkRecord.class); + private static final POILogger logger = POILogFactory.getLogger(HyperlinkRecord.class); //arbitrarily selected; may need to increase private static final int MAX_RECORD_LENGTH = 100_000; - // TODO: replace with ClassID - static final class GUID { - /* - * this class is currently only used here, but could be moved to a - * common package if needed - */ - private static final int TEXT_FORMAT_LENGTH = 36; - - public static final int ENCODED_SIZE = 16; - - /** 4 bytes - little endian */ - private final int _d1; - /** 2 bytes - little endian */ - private final int _d2; - /** 2 bytes - little endian */ - private final int _d3; - /** - * 8 bytes - serialized as big endian, stored with inverted endianness here - */ - private final long _d4; - - public GUID(GUID other) { - _d1 = other._d1; - _d2 = other._d2; - _d3 = other._d3; - _d4 = other._d4; - } - - public GUID(LittleEndianInput in) { - this(in.readInt(), in.readUShort(), in.readUShort(), in.readLong()); - } - - public GUID(int d1, int d2, int d3, long d4) { - _d1 = d1; - _d2 = d2; - _d3 = d3; - _d4 = d4; - } - - public void serialize(LittleEndianOutput out) { - out.writeInt(_d1); - out.writeShort(_d2); - out.writeShort(_d3); - out.writeLong(_d4); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof GUID)) { - return false; - } - GUID other = (GUID) obj; - return _d1 == other._d1 && _d2 == other._d2 - && _d3 == other._d3 && _d4 == other._d4; - } - - @Override - public int hashCode() { - assert false : "hashCode not designed"; - return 42; // any arbitrary constant will do - } - - public int getD1() { - return _d1; - } - - public int getD2() { - return _d2; - } - - public int getD3() { - return _d3; - } - - public long getD4() { - byte[] result = new byte[Long.SIZE/Byte.SIZE]; - long l = _d4; - for (int i = result.length-1; i >= 0; i--) { - result[i] = (byte)(l & 0xFF); - l >>= 8; - } - - return LittleEndian.getLong(result, 0); - } - - public String formatAsString() { - - StringBuilder sb = new StringBuilder(36); - - int PREFIX_LEN = "0x".length(); - sb.append(HexDump.intToHex(_d1).substring(PREFIX_LEN)); - sb.append("-"); - sb.append(HexDump.shortToHex(_d2).substring(PREFIX_LEN)); - sb.append("-"); - sb.append(HexDump.shortToHex(_d3).substring(PREFIX_LEN)); - sb.append("-"); - String d4Chars = HexDump.longToHex(getD4()); - sb.append(d4Chars, PREFIX_LEN, PREFIX_LEN+4); - sb.append("-"); - sb.append(d4Chars.substring(PREFIX_LEN+4)); - return sb.toString(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(64); - sb.append(getClass().getName()).append(" ["); - sb.append(formatAsString()); - sb.append("]"); - return sb.toString(); - } - - /** - * Read a GUID in standard text form e.g.
- * 13579BDF-0246-8ACE-0123-456789ABCDEF - *
->
- * 0x13579BDF, 0x0246, 0x8ACE 0x0123456789ABCDEF - */ - public static GUID parse(String rep) { - char[] cc = rep.toCharArray(); - if (cc.length != TEXT_FORMAT_LENGTH) { - throw new RecordFormatException("supplied text is the wrong length for a GUID"); - } - int d0 = (parseShort(cc, 0) << 16) + (parseShort(cc, 4) << 0); - int d1 = parseShort(cc, 9); - int d2 = parseShort(cc, 14); - System.arraycopy(cc, 19, cc, 20, 4); - long d3 = parseLELong(cc, 20); - - return new GUID(d0, d1, d2, d3); - } - - private static long parseLELong(char[] cc, int startIndex) { - long acc = 0; - for (int i = startIndex + 14; i >= startIndex; i -= 2) { - acc <<= 4; - acc += parseHexChar(cc[i + 0]); - acc <<= 4; - acc += parseHexChar(cc[i + 1]); - } - return acc; - } - - private static int parseShort(char[] cc, int startIndex) { - int acc = 0; - for (int i = 0; i < 4; i++) { - acc <<= 4; - acc += parseHexChar(cc[startIndex + i]); - } - return acc; - } - - private static int parseHexChar(char c) { - if (c >= '0' && c <= '9') { - return c - '0'; - } - if (c >= 'A' && c <= 'F') { - return c - 'A' + 10; - } - if (c >= 'a' && c <= 'f') { - return c - 'a' + 10; - } - throw new RecordFormatException("Bad hex char '" + c + "'"); - } - } - /* * Link flags */ @@ -219,9 +57,6 @@ public final class HyperlinkRecord extends StandardRecord { private static final int HLINK_TARGET_FRAME = 0x80; // has 'target frame' private static final int HLINK_UNC_PATH = 0x100; // has UNC path - static final GUID STD_MONIKER = GUID.parse("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B"); - static final GUID URL_MONIKER = GUID.parse("79EAC9E0-BAF9-11CE-8C82-00AA004BA90B"); - static final GUID FILE_MONIKER = GUID.parse("00000303-0000-0000-C000-000000000046"); /** expected Tail of a URL link */ private static final byte[] URL_TAIL = HexRead.readFromString("79 58 81 F4 3B 1D 7F 48 AF 2C 82 5D C4 85 27 63 00 00 00 00 A5 AB 00 00"); /** expected Tail of a file link */ @@ -233,7 +68,7 @@ public final class HyperlinkRecord extends StandardRecord { private CellRangeAddress _range; /** 16-byte GUID */ - private GUID _guid; + private ClassID _guid; /** Some sort of options for file links. */ private int _fileOpts; /** Link options. Can include any of HLINK_* flags. */ @@ -243,7 +78,7 @@ public final class HyperlinkRecord extends StandardRecord { private String _targetFrame; /** Moniker. Makes sense only for URL and file links */ - private GUID _moniker; + private ClassID _moniker; /** in 8:3 DOS format No Unicode string header, * always 8-bit characters, zero-terminated */ private String _shortFilename; @@ -267,12 +102,12 @@ public final class HyperlinkRecord extends StandardRecord { public HyperlinkRecord(HyperlinkRecord other) { super(other); _range = (other._range == null) ? null : other._range.copy(); - _guid = (other._guid == null) ? null : new GUID(other._guid); + _guid = (other._guid == null) ? null : other._guid.copy(); _fileOpts = other._fileOpts; _linkOpts = other._linkOpts; _label = other._label; _targetFrame = other._targetFrame; - _moniker = (other._moniker == null) ? null : new GUID(other._moniker); + _moniker = (other._moniker == null) ? null : other._moniker.copy(); _shortFilename = other._shortFilename; _address = other._address; _textMark = other._textMark; @@ -345,16 +180,16 @@ public final class HyperlinkRecord extends StandardRecord { } /** - * @return 16-byte guid identifier Seems to always equal {@link #STD_MONIKER} + * @return 16-byte guid identifier Seems to always equal {@link org.apache.poi.hpsf.ClassIDPredefined#STD_MONIKER} */ - GUID getGuid() { + ClassID getGuid() { return _guid; } /** * @return 16-byte moniker */ - GUID getMoniker() + ClassID getMoniker() { return _moniker; } @@ -471,9 +306,9 @@ public final class HyperlinkRecord extends StandardRecord { public HyperlinkRecord(RecordInputStream in) { _range = new CellRangeAddress(in); - _guid = new GUID(in); + _guid = new ClassID(in); - /** + /* * streamVersion (4 bytes): An unsigned integer that specifies the version number * of the serialization implementation used to save this structure. This value MUST equal 2. */ @@ -500,11 +335,11 @@ public final class HyperlinkRecord extends StandardRecord { } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { - _moniker = new GUID(in); + _moniker = new ClassID(in); if(URL_MONIKER.equals(_moniker)){ int length = in.readInt(); - /** + /* * The value of length be either the byte size of the url field * (including the terminating NULL character) or the byte size of the url field plus 24. * If the value of this field is set to the byte size of the url field, @@ -517,7 +352,7 @@ public final class HyperlinkRecord extends StandardRecord { } else { int nChars = (length - TAIL_SIZE)/2; _address = in.readUnicodeLEString(nChars); - /** + /* * TODO: make sense of the remaining bytes * According to the spec they consist of: * 1. 16-byte GUID: This field MUST equal @@ -575,7 +410,7 @@ public final class HyperlinkRecord extends StandardRecord { public void serialize(LittleEndianOutput out) { _range.serialize(out); - _guid.serialize(out); + _guid.write(out); out.writeInt(0x00000002); // TODO const out.writeInt(_linkOpts); @@ -594,7 +429,7 @@ public final class HyperlinkRecord extends StandardRecord { } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { - _moniker.serialize(out); + _moniker.write(out); if(URL_MONIKER.equals(_moniker)){ if (_uninterpretedTail == null) { out.writeInt(_address.length()*2); @@ -630,7 +465,7 @@ public final class HyperlinkRecord extends StandardRecord { protected int getDataSize() { int size = 0; size += 2 + 2 + 2 + 2; //rwFirst, rwLast, colFirst, colLast - size += GUID.ENCODED_SIZE; + size += ClassID.LENGTH; size += 4; //label_opts size += 4; //link_opts if ((_linkOpts & HLINK_LABEL) != 0){ @@ -646,7 +481,7 @@ public final class HyperlinkRecord extends StandardRecord { size += _address.length()*2; } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { - size += GUID.ENCODED_SIZE; + size += ClassID.LENGTH; if(URL_MONIKER.equals(_moniker)){ size += 4; //address length size += _address.length()*2; @@ -703,14 +538,14 @@ public final class HyperlinkRecord extends StandardRecord { buffer.append("[HYPERLINK RECORD]\n"); buffer.append(" .range = ").append(_range.formatAsString()).append("\n"); - buffer.append(" .guid = ").append(_guid.formatAsString()).append("\n"); + buffer.append(" .guid = ").append(_guid.toString()).append("\n"); buffer.append(" .linkOpts= ").append(HexDump.intToHex(_linkOpts)).append("\n"); buffer.append(" .label = ").append(getLabel()).append("\n"); if ((_linkOpts & HLINK_TARGET_FRAME) != 0) { buffer.append(" .targetFrame= ").append(getTargetFrame()).append("\n"); } if((_linkOpts & HLINK_URL) != 0 && _moniker != null) { - buffer.append(" .moniker = ").append(_moniker.formatAsString()).append("\n"); + buffer.append(" .moniker = ").append(_moniker.toString()).append("\n"); } if ((_linkOpts & HLINK_PLACE) != 0) { buffer.append(" .textMark= ").append(getTextMark()).append("\n"); @@ -725,6 +560,7 @@ public final class HyperlinkRecord extends StandardRecord { * * @return true, if this is a url link */ + @SuppressWarnings("unused") public boolean isUrlLink() { return (_linkOpts & HLINK_URL) > 0 && (_linkOpts & HLINK_ABS) > 0; @@ -752,10 +588,10 @@ public final class HyperlinkRecord extends StandardRecord { */ public void newUrlLink() { _range = new CellRangeAddress(0, 0, 0, 0); - _guid = STD_MONIKER; + _guid = STD_MONIKER.getClassID(); _linkOpts = HLINK_URL | HLINK_ABS | HLINK_LABEL; setLabel(""); - _moniker = URL_MONIKER; + _moniker = URL_MONIKER.getClassID(); setAddress(""); _uninterpretedTail = URL_TAIL; } @@ -765,11 +601,11 @@ public final class HyperlinkRecord extends StandardRecord { */ public void newFileLink() { _range = new CellRangeAddress(0, 0, 0, 0); - _guid = STD_MONIKER; + _guid = STD_MONIKER.getClassID(); _linkOpts = HLINK_URL | HLINK_LABEL; _fileOpts = 0; setLabel(""); - _moniker = FILE_MONIKER; + _moniker = FILE_MONIKER.getClassID(); setAddress(null); setShortFilename(""); _uninterpretedTail = FILE_TAIL; @@ -780,16 +616,16 @@ public final class HyperlinkRecord extends StandardRecord { */ public void newDocumentLink() { _range = new CellRangeAddress(0, 0, 0, 0); - _guid = STD_MONIKER; + _guid = STD_MONIKER.getClassID(); _linkOpts = HLINK_LABEL | HLINK_PLACE; setLabel(""); - _moniker = FILE_MONIKER; + _moniker = FILE_MONIKER.getClassID(); setAddress(""); setTextMark(""); } @Override - @SuppressWarnings("squid:S2975") + @SuppressWarnings({"squid:S2975", "MethodDoesntCallSuperMethod"}) @Deprecated @Removal(version = "5.0.0") public HyperlinkRecord clone() { diff --git a/src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java b/src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java index b2290b1913..80b62f8d8a 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java @@ -19,9 +19,14 @@ package org.apache.poi.hssf.record; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertNotNull; -import org.apache.poi.hssf.record.HyperlinkRecord.GUID; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; + +import org.apache.poi.hpsf.ClassID; +import org.apache.poi.hpsf.ClassIDPredefined; import org.apache.poi.util.HexDump; import org.apache.poi.util.HexRead; import org.apache.poi.util.LittleEndianByteArrayInputStream; @@ -271,7 +276,7 @@ public final class TestHyperlinkRecord { }; - private void confirmGUID(GUID expectedGuid, GUID actualGuid) { + private void confirmGUID(ClassID expectedGuid, ClassID actualGuid) { assertEquals(expectedGuid, actualGuid); } @@ -283,8 +288,8 @@ public final class TestHyperlinkRecord { assertEquals(2, link.getLastRow()); assertEquals(0, link.getFirstColumn()); assertEquals(0, link.getLastColumn()); - confirmGUID(HyperlinkRecord.STD_MONIKER, link.getGuid()); - confirmGUID(HyperlinkRecord.URL_MONIKER, link.getMoniker()); + confirmGUID(ClassIDPredefined.STD_MONIKER.getClassID(), link.getGuid()); + confirmGUID(ClassIDPredefined.URL_MONIKER.getClassID(), link.getMoniker()); assertEquals(2, link.getLabelOptions()); int opts = HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_ABS | HyperlinkRecord.HLINK_LABEL; assertEquals(0x17, opts); @@ -303,8 +308,8 @@ public final class TestHyperlinkRecord { assertEquals(0, link.getLastRow()); assertEquals(0, link.getFirstColumn()); assertEquals(0, link.getLastColumn()); - confirmGUID(HyperlinkRecord.STD_MONIKER, link.getGuid()); - confirmGUID(HyperlinkRecord.FILE_MONIKER, link.getMoniker()); + confirmGUID(ClassIDPredefined.STD_MONIKER.getClassID(), link.getGuid()); + confirmGUID(ClassIDPredefined.FILE_MONIKER.getClassID(), link.getMoniker()); assertEquals(2, link.getLabelOptions()); int opts = HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_LABEL; assertEquals(0x15, opts); @@ -323,8 +328,8 @@ public final class TestHyperlinkRecord { assertEquals(1, link.getLastRow()); assertEquals(0, link.getFirstColumn()); assertEquals(0, link.getLastColumn()); - confirmGUID(HyperlinkRecord.STD_MONIKER, link.getGuid()); - confirmGUID(HyperlinkRecord.URL_MONIKER, link.getMoniker()); + confirmGUID(ClassIDPredefined.STD_MONIKER.getClassID(), link.getGuid()); + confirmGUID(ClassIDPredefined.URL_MONIKER.getClassID(), link.getMoniker()); assertEquals(2, link.getLabelOptions()); int opts = HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_ABS | HyperlinkRecord.HLINK_LABEL; assertEquals(0x17, opts); @@ -342,7 +347,7 @@ public final class TestHyperlinkRecord { assertEquals(3, link.getLastRow()); assertEquals(0, link.getFirstColumn()); assertEquals(0, link.getLastColumn()); - confirmGUID(HyperlinkRecord.STD_MONIKER, link.getGuid()); + confirmGUID(ClassIDPredefined.STD_MONIKER.getClassID(), link.getGuid()); assertEquals(2, link.getLabelOptions()); int opts = HyperlinkRecord.HLINK_LABEL | HyperlinkRecord.HLINK_PLACE; assertEquals(0x1C, opts); @@ -474,49 +479,47 @@ public final class TestHyperlinkRecord { HyperlinkRecord hr = new HyperlinkRecord(in); byte[] ser = hr.serialize(); TestcaseRecordInputStream.confirmRecordEncoding(HyperlinkRecord.sid, dataUNC, ser); - try { - hr.toString(); - } catch (NullPointerException e) { - fail("Identified bug with option URL and UNC set at same time"); - } + assertNotNull(hr.toString()); } @Test - public void testGUID() { - GUID g; - g = GUID.parse("3F2504E0-4F89-11D3-9A0C-0305E82C3301"); + public void testGUID() throws IOException { + ClassID g; + g = new ClassID("3F2504E0-4F89-11D3-9A0C-0305E82C3301"); confirmGUID(g, 0x3F2504E0, 0x4F89, 0x11D3, 0x9A0C0305E82C3301L); - assertEquals("3F2504E0-4F89-11D3-9A0C-0305E82C3301", g.formatAsString()); + assertEquals("{3F2504E0-4F89-11D3-9A0C-0305E82C3301}", g.toString()); - g = GUID.parse("13579BDF-0246-8ACE-0123-456789ABCDEF"); + g = new ClassID("13579BDF-0246-8ACE-0123-456789ABCDEF"); confirmGUID(g, 0x13579BDF, 0x0246, 0x8ACE, 0x0123456789ABCDEFL); - assertEquals("13579BDF-0246-8ACE-0123-456789ABCDEF", g.formatAsString()); + assertEquals("{13579BDF-0246-8ACE-0123-456789ABCDEF}", g.toString()); byte[] buf = new byte[16]; - g.serialize(new LittleEndianByteArrayOutputStream(buf, 0)); + g.write(new LittleEndianByteArrayOutputStream(buf, 0)); String expectedDump = "[DF, 9B, 57, 13, 46, 02, CE, 8A, 01, 23, 45, 67, 89, AB, CD, EF]"; assertEquals(expectedDump, HexDump.toHex(buf)); // STD Moniker g = createFromStreamDump("[D0, C9, EA, 79, F9, BA, CE, 11, 8C, 82, 00, AA, 00, 4B, A9, 0B]"); - assertEquals("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B", g.formatAsString()); + assertEquals("{79EAC9D0-BAF9-11CE-8C82-00AA004BA90B}", g.toString()); // URL Moniker g = createFromStreamDump("[E0, C9, EA, 79, F9, BA, CE, 11, 8C, 82, 00, AA, 00, 4B, A9, 0B]"); - assertEquals("79EAC9E0-BAF9-11CE-8C82-00AA004BA90B", g.formatAsString()); + assertEquals("{79EAC9E0-BAF9-11CE-8C82-00AA004BA90B}", g.toString()); // File Moniker g = createFromStreamDump("[03, 03, 00, 00, 00, 00, 00, 00, C0, 00, 00, 00, 00, 00, 00, 46]"); - assertEquals("00000303-0000-0000-C000-000000000046", g.formatAsString()); + assertEquals("{00000303-0000-0000-C000-000000000046}", g.toString()); } - private static GUID createFromStreamDump(String s) { - return new GUID(new LittleEndianByteArrayInputStream(HexRead.readFromString(s))); + private static ClassID createFromStreamDump(String s) { + return new ClassID(new LittleEndianByteArrayInputStream(HexRead.readFromString(s))); } - private void confirmGUID(GUID g, int d1, int d2, int d3, long d4) { - assertEquals(HexDump.intToHex(d1), HexDump.intToHex(g.getD1())); - assertEquals(HexDump.shortToHex(d2), HexDump.shortToHex(g.getD2())); - assertEquals(HexDump.shortToHex(d3), HexDump.shortToHex(g.getD3())); - assertEquals(HexDump.longToHex(d4), HexDump.longToHex(g.getD4())); + private void confirmGUID(ClassID g, int d1, int d2, int d3, long d4) throws IOException { + try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(g.getBytes()))) { + assertEquals(d1, dis.readInt()); + assertEquals(d2, dis.readShort() & 0xFFFF); + assertEquals(d3, dis.readShort() & 0xFFFF); + assertEquals(d4, dis.readLong()); + } } @Test @@ -527,8 +530,8 @@ public final class TestHyperlinkRecord { assertEquals(2, link.getLastRow()); assertEquals(0, link.getFirstColumn()); assertEquals(0, link.getLastColumn()); - confirmGUID(HyperlinkRecord.STD_MONIKER, link.getGuid()); - confirmGUID(HyperlinkRecord.URL_MONIKER, link.getMoniker()); + confirmGUID(ClassIDPredefined.STD_MONIKER.getClassID(), link.getGuid()); + confirmGUID(ClassIDPredefined.URL_MONIKER.getClassID(), link.getMoniker()); assertEquals(2, link.getLabelOptions()); int opts = HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_LABEL; assertEquals(opts, link.getLinkOptions());