mirror of https://github.com/apache/poi.git
Replace internal GUID class with ClassID
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1871944 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
03fe2ded64
commit
7493473a8e
|
@ -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.<p>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String,ClassIDPredefined> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.<br>
|
||||
* 13579BDF-0246-8ACE-0123-456789ABCDEF
|
||||
* <br> -> <br>
|
||||
* 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 <code>length<code> 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() {
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue