public static final int WebKitCreateInstance( GUID clsid, long /*int*/ pUnkOuter, GUID iid, long /*int*/[] ppvObject) { byte[] rclsid = new byte[GUID.sizeof]; OS.IIDFromString((clsid.toString() + '\0').toCharArray(), rclsid); byte[] refiid = new byte[GUID.sizeof]; OS.IIDFromString((iid.toString() + '\0').toCharArray(), refiid); return WebKitCreateInstance(rclsid, pUnkOuter, refiid, ppvObject); }
public void serialize(LittleEndianOutput out) { _range.serialize(out); _guid.serialize(out); out.writeInt(0x00000002); // TODO const out.writeInt(_linkOpts); if ((_linkOpts & HLINK_LABEL) != 0) { out.writeInt(_label.length()); StringUtil.putUnicodeLE(_label, out); } if ((_linkOpts & HLINK_TARGET_FRAME) != 0) { out.writeInt(_targetFrame.length()); StringUtil.putUnicodeLE(_targetFrame, out); } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) != 0) { out.writeInt(_address.length()); StringUtil.putUnicodeLE(_address, out); } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { _moniker.serialize(out); if (URL_MONIKER.equals(_moniker)) { if (_uninterpretedTail == null) { out.writeInt(_address.length() * 2); StringUtil.putUnicodeLE(_address, out); } else { out.writeInt(_address.length() * 2 + TAIL_SIZE); StringUtil.putUnicodeLE(_address, out); writeTail(_uninterpretedTail, out); } } else if (FILE_MONIKER.equals(_moniker)) { out.writeShort(_fileOpts); out.writeInt(_shortFilename.length()); StringUtil.putCompressedUnicode(_shortFilename, out); writeTail(_uninterpretedTail, out); if (_address == null) { out.writeInt(0); } else { int addrLen = _address.length() * 2; out.writeInt(addrLen + 6); out.writeInt(addrLen); out.writeShort(0x0003); // TODO const StringUtil.putUnicodeLE(_address, out); } } } if ((_linkOpts & HLINK_PLACE) != 0) { out.writeInt(_textMark.length()); StringUtil.putUnicodeLE(_textMark, out); } }
@Override public boolean equals(Object o) { if (!(o instanceof Token)) { return false; } return id.equals(((Token) o).id); }
/** * Convert the token into a hash map. This is used to ship all of the properties for the token to * other apps that do need access to the <code>Token</code> class. * * @return A map containing the properties of the token. */ public TokenTransferData toTransferData() { TokenTransferData td = new TokenTransferData(); td.setName(name); td.setPlayers(ownerList); td.setVisible(isVisible); td.setLocation(new Point(x, y)); td.setFacing(facing); // Set the properties td.put(TokenTransferData.ID, id.toString()); td.put(TokenTransferData.ASSET_ID, imageAssetMap.get(null)); td.put(TokenTransferData.Z, z); td.put(TokenTransferData.SNAP_TO_SCALE, snapToScale); td.put(TokenTransferData.WIDTH, scaleX); td.put(TokenTransferData.HEIGHT, scaleY); td.put(TokenTransferData.SNAP_TO_GRID, snapToGrid); td.put(TokenTransferData.OWNER_TYPE, ownerType); td.put(TokenTransferData.VISIBLE_OWNER_ONLY, visibleOnlyToOwner); td.put(TokenTransferData.TOKEN_TYPE, tokenShape); td.put(TokenTransferData.NOTES, notes); td.put(TokenTransferData.GM_NOTES, gmNotes); td.put(TokenTransferData.GM_NAME, gmName); // Put all of the serializable state into the map for (String key : getStatePropertyNames()) { Object value = getState(key); if (value instanceof Serializable) td.put(key, value); } td.putAll(state); // Create the image from the asset and add it to the map Image image = ImageManager.getImageAndWait(imageAssetMap.get(null)); if (image != null) td.setToken(new ImageIcon(image)); // Image icon makes it serializable. return td; }
protected int getDataSize() { int size = 0; size += 2 + 2 + 2 + 2; // rwFirst, rwLast, colFirst, colLast size += GUID.ENCODED_SIZE; size += 4; // label_opts size += 4; // link_opts if ((_linkOpts & HLINK_LABEL) != 0) { size += 4; // link length size += _label.length() * 2; } if ((_linkOpts & HLINK_TARGET_FRAME) != 0) { size += 4; // int nChars size += _targetFrame.length() * 2; } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) != 0) { size += 4; // int nChars size += _address.length() * 2; } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { size += GUID.ENCODED_SIZE; if (URL_MONIKER.equals(_moniker)) { size += 4; // address length size += _address.length() * 2; if (_uninterpretedTail != null) { size += TAIL_SIZE; } } else if (FILE_MONIKER.equals(_moniker)) { size += 2; // file_opts size += 4; // address length size += _shortFilename.length(); size += TAIL_SIZE; size += 4; if (_address != null) { size += 6; size += _address.length() * 2; } } } if ((_linkOpts & HLINK_PLACE) != 0) { size += 4; // address length size += _textMark.length() * 2; } return size; }
public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[HYPERLINK RECORD]\n"); buffer.append(" .range = ").append(_range.formatAsString()).append("\n"); buffer.append(" .guid = ").append(_guid.formatAsString()).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"); } if ((_linkOpts & HLINK_PLACE) != 0) { buffer.append(" .textMark= ").append(getTextMark()).append("\n"); } buffer.append(" .address = ").append(getAddress()).append("\n"); buffer.append("[/HYPERLINK RECORD]\n"); return buffer.toString(); }
public GUID newGUID() { return GUID.randomGUID(); }
public void manage(GUID guid) { guid.manage(); }
// MUST RUN THIS TEST FIRST public void testMixedProtocol() throws Exception { DatagramPacket pack = null; UDP_ACCESS = new DatagramSocket(); for (int i = 0; i < testUP.length; i++) { assertTrue("not open", testUP[i].isOpen()); assertTrue("not up->leaf", testUP[i].isSupernodeClientConnection()); drain(testUP[i], 500); if ((i == 2)) { // i'll send 0 later.... testUP[i].send(MessagesSupportedVendorMessage.instance()); testUP[i].flush(); } } testUP[0].send(MessagesSupportedVendorMessage.instance()); testUP[0].flush(); // first we need to set up GUESS capability UDP_ACCESS.setSoTimeout(TIMEOUT * 2); // ---------------------------------------- // set up solicited UDP support PrivilegedAccessor.setValue(rs.getUdpService(), "_acceptedSolicitedIncoming", Boolean.TRUE); // set up unsolicited UDP support PrivilegedAccessor.setValue(rs.getUdpService(), "_acceptedUnsolicitedIncoming", Boolean.TRUE); // you also have to set up TCP incoming.... { Socket sock = null; OutputStream os = null; try { sock = Sockets.connect(InetAddress.getLocalHost().getHostAddress(), SERVER_PORT, 12); os = sock.getOutputStream(); os.write("\n\n".getBytes()); } catch (IOException ignored) { } catch (SecurityException ignored) { } catch (Throwable t) { ErrorService.error(t); } finally { if (sock != null) try { sock.close(); } catch (IOException ignored) { } if (os != null) try { os.close(); } catch (IOException ignored) { } } } // ---------------------------------------- Thread.sleep(250); // we should now be guess capable and tcp incoming capable.... assertTrue(RouterService.isGUESSCapable()); assertTrue(RouterService.acceptedIncomingConnection()); // get rid of any messages that are stored up. drainAll(); // first of all, we should confirm that we are sending out a OOB query. GUID queryGuid = new GUID(RouterService.newQueryGUID()); assertTrue( GUID.addressesMatch( queryGuid.bytes(), RouterService.getAddress(), RouterService.getPort())); RouterService.query(queryGuid.bytes(), "susheel"); Thread.sleep(250); // some connected UPs should get a OOB query for (int i = 0; i < testUP.length; i++) { QueryRequest qr = getFirstQueryRequest(testUP[i], TIMEOUT); assertNotNull("up " + i + " didn't get query", qr); assertEquals(new GUID(qr.getGUID()), queryGuid); if ((i == 0) || (i == 2)) assertTrue(qr.desiresOutOfBandReplies()); else assertTrue(!qr.desiresOutOfBandReplies()); } // now confirm that we leaf guide the 'even' guys but not the others. Message m = null; // ensure that we'll get a QueryStatusResponse from the Responses // we're sending. for (int i = 0; i < testUP.length; i++) { Response[] res = new Response[7]; res[0] = new Response(10, 10, "susheel" + i); res[1] = new Response(10, 10, "susheel smells good" + i); res[2] = new Response(10, 10, "anita is sweet" + i); res[3] = new Response(10, 10, "anita is prety" + i); res[4] = new Response(10, 10, "susheel smells bad" + i); res[5] = new Response(10, 10, "renu is sweet " + i); res[6] = new Response(10, 10, "prety is spelled pretty " + i); m = new QueryReply( queryGuid.bytes(), (byte) 1, 6355, myIP(), 0, res, GUID.makeGuid(), new byte[0], false, false, true, true, false, false, null); testUP[i].send(m); testUP[i].flush(); } // all UPs should get a QueryStatusResponse for (int i = 0; i < testUP.length; i++) { QueryStatusResponse stat = getFirstQueryStatus(testUP[i]); if ((i == 0) || (i == 2)) { assertNotNull(stat); assertEquals(new GUID(stat.getGUID()), queryGuid); assertEquals(5, stat.getNumResults()); } else assertNull(stat); } // shut off the query.... RouterService.stopQuery(queryGuid); // all UPs should get a QueryStatusResponse with 65535 for (int i = 0; i < testUP.length; i++) { QueryStatusResponse stat = getFirstQueryStatus(testUP[i]); if ((i == 0) || (i == 2)) { assertNotNull(stat); assertEquals(new GUID(stat.getGUID()), queryGuid); assertEquals(65535, stat.getNumResults()); } else assertNull(stat); } }
@Override public int hashCode() { return id.hashCode(); }
/** * The <code>HyperlinkRecord</code> (0x01B8) wraps an HLINK-record from the Excel-97 format. * Supports only external links for now (eg http://) * * @author Mark Hissink Muller <a href="mailto:[email protected] >mark&064;hissinkmuller.nl</a> * @author Yegor Kozlov (yegor at apache dot org) */ public final class HyperlinkRecord extends StandardRecord { public static final short sid = 0x01B8; private POILogger logger = POILogFactory.getLogger(getClass()); 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(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) { GUID other = (GUID) obj; if (obj == null || !(obj instanceof GUID)) return false; return _d1 == other._d1 && _d2 == other._d2 && _d3 == other._d3 && _d4 == other._d4; } public int getD1() { return _d1; } public int getD2() { return _d2; } public int getD3() { return _d3; } public long getD4() { // ByteArrayOutputStream baos = new ByteArrayOutputStream(8); try { new DataOutputStream(baos).writeLong(_d4); } catch (IOException e) { throw new RuntimeException(e); } byte[] buf = baos.toByteArray(); return new LittleEndianByteArrayInputStream(buf).readLong(); } public String formatAsString() { StringBuilder sb = new StringBuilder(36); int PREFIX_LEN = "0x".length(); sb.append(HexDump.intToHex(_d1), PREFIX_LEN, 8); sb.append("-"); sb.append(HexDump.shortToHex(_d2), PREFIX_LEN, 4); sb.append("-"); sb.append(HexDump.shortToHex(_d3), PREFIX_LEN, 4); sb.append("-"); char[] d4Chars = HexDump.longToHex(getD4()); sb.append(d4Chars, PREFIX_LEN, 4); sb.append("-"); sb.append(d4Chars, PREFIX_LEN + 4, 12); 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); for (int i = 23; i > 19; i--) { cc[i] = cc[i - 1]; } 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 */ static final int HLINK_URL = 0x01; // File link or URL. static final int HLINK_ABS = 0x02; // Absolute path. static final int HLINK_LABEL = 0x14; // Has label/description. /** Place in worksheet. If set, the {@link #_textMark} field will be present */ static final int HLINK_PLACE = 0x08; 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 */ private static final byte[] FILE_TAIL = HexRead.readFromString( "FF FF AD DE 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); private static final int TAIL_SIZE = FILE_TAIL.length; /** cell range of this hyperlink */ private CellRangeAddress _range; /** 16-byte GUID */ private GUID _guid; /** Some sort of options for file links. */ private int _fileOpts; /** Link options. Can include any of HLINK_* flags. */ private int _linkOpts; /** Test label */ private String _label; private String _targetFrame; /** Moniker. Makes sense only for URL and file links */ private GUID _moniker; /** in 8:3 DOS format No Unicode string header, always 8-bit characters, zero-terminated */ private String _shortFilename; /** Link */ private String _address; /** * Text describing a place in document. In Excel UI, this is appended to the address, (after a '#' * delimiter).<br> * This field is optional. If present, the {@link #HLINK_PLACE} must be set. */ private String _textMark; private byte[] _uninterpretedTail; /** Create a new hyperlink */ public HyperlinkRecord() {} /** @return the 0-based column of the first cell that contains this hyperlink */ public int getFirstColumn() { return _range.getFirstColumn(); } /** Set the first column (zero-based)of the range that contains this hyperlink */ public void setFirstColumn(int col) { _range.setFirstColumn(col); } /** @return the 0-based column of the last cell that contains this hyperlink */ public int getLastColumn() { return _range.getLastColumn(); } /** Set the last column (zero-based)of the range that contains this hyperlink */ public void setLastColumn(int col) { _range.setLastColumn(col); } /** @return the 0-based row of the first cell that contains this hyperlink */ public int getFirstRow() { return _range.getFirstRow(); } /** Set the first row (zero-based)of the range that contains this hyperlink */ public void setFirstRow(int col) { _range.setFirstRow(col); } /** @return the 0-based row of the last cell that contains this hyperlink */ public int getLastRow() { return _range.getLastRow(); } /** Set the last row (zero-based)of the range that contains this hyperlink */ public void setLastRow(int col) { _range.setLastRow(col); } /** @return 16-byte guid identifier Seems to always equal {@link #STD_MONIKER} */ GUID getGuid() { return _guid; } /** @return 16-byte moniker */ GUID getMoniker() { return _moniker; } private static String cleanString(String s) { if (s == null) { return null; } int idx = s.indexOf('\u0000'); if (idx < 0) { return s; } return s.substring(0, idx); } private static String appendNullTerm(String s) { if (s == null) { return null; } return s + '\u0000'; } /** * Return text label for this hyperlink * * @return text to display */ public String getLabel() { return cleanString(_label); } /** * Sets text label for this hyperlink * * @param label text label for this hyperlink */ public void setLabel(String label) { _label = appendNullTerm(label); } public String getTargetFrame() { return cleanString(_targetFrame); } /** * Hyperlink address. Depending on the hyperlink type it can be URL, e-mail, path to a file, etc. * * @return the address of this hyperlink */ public String getAddress() { if ((_linkOpts & HLINK_URL) != 0 && FILE_MONIKER.equals(_moniker)) return cleanString(_address != null ? _address : _shortFilename); else if ((_linkOpts & HLINK_PLACE) != 0) return cleanString(_textMark); else return cleanString(_address); } /** * Hyperlink address. Depending on the hyperlink type it can be URL, e-mail, path to a file, etc. * * @param address the address of this hyperlink */ public void setAddress(String address) { if ((_linkOpts & HLINK_URL) != 0 && FILE_MONIKER.equals(_moniker)) _shortFilename = appendNullTerm(address); else if ((_linkOpts & HLINK_PLACE) != 0) _textMark = appendNullTerm(address); else _address = appendNullTerm(address); } public String getShortFilename() { return cleanString(_shortFilename); } public void setShortFilename(String shortFilename) { _shortFilename = appendNullTerm(shortFilename); } public String getTextMark() { return cleanString(_textMark); } public void setTextMark(String textMark) { _textMark = appendNullTerm(textMark); } /** Link options. Must be a combination of HLINK_* constants. For testing only */ int getLinkOptions() { return _linkOpts; } /** Label options */ public int getLabelOptions() { return 2; // always 2 } /** Options for a file link */ public int getFileOptions() { return _fileOpts; } public HyperlinkRecord(RecordInputStream in) { _range = new CellRangeAddress(in); _guid = new GUID(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. */ int streamVersion = in.readInt(); if (streamVersion != 0x00000002) { throw new RecordFormatException("Stream Version must be 0x2 but found " + streamVersion); } _linkOpts = in.readInt(); if ((_linkOpts & HLINK_LABEL) != 0) { int label_len = in.readInt(); _label = in.readUnicodeLEString(label_len); } if ((_linkOpts & HLINK_TARGET_FRAME) != 0) { int len = in.readInt(); _targetFrame = in.readUnicodeLEString(len); } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) != 0) { _moniker = null; int nChars = in.readInt(); _address = in.readUnicodeLEString(nChars); } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { _moniker = new GUID(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, * then the tail bytes fields are not present. */ int remaining = in.remaining(); if (length == remaining) { int nChars = length / 2; _address = in.readUnicodeLEString(nChars); } 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 {0xF4815879, 0x1D3B, 0x487F, 0xAF, 0x2C, 0x82, * 0x5D, 0xC4, 0x85, 0x27, 0x63} 2. Serial version, this field MUST equal 0 if present. 3. * URI Flags */ _uninterpretedTail = readTail(URL_TAIL, in); } } else if (FILE_MONIKER.equals(_moniker)) { _fileOpts = in.readShort(); int len = in.readInt(); _shortFilename = StringUtil.readCompressedUnicode(in, len); _uninterpretedTail = readTail(FILE_TAIL, in); int size = in.readInt(); if (size > 0) { int charDataSize = in.readInt(); // From the spec: An optional unsigned integer that MUST be 3 if present // but some files has 4 int usKeyValue = in.readUShort(); _address = StringUtil.readUnicodeLE(in, charDataSize / 2); } else { _address = null; } } else if (STD_MONIKER.equals(_moniker)) { _fileOpts = in.readShort(); int len = in.readInt(); byte[] path_bytes = new byte[len]; in.readFully(path_bytes); _address = new String(path_bytes); } } if ((_linkOpts & HLINK_PLACE) != 0) { int len = in.readInt(); _textMark = in.readUnicodeLEString(len); } if (in.remaining() > 0) { logger.log( POILogger.WARN, "Hyperlink data remains: " + in.remaining() + " : " + HexDump.toHex(in.readRemainder())); } } public void serialize(LittleEndianOutput out) { _range.serialize(out); _guid.serialize(out); out.writeInt(0x00000002); // TODO const out.writeInt(_linkOpts); if ((_linkOpts & HLINK_LABEL) != 0) { out.writeInt(_label.length()); StringUtil.putUnicodeLE(_label, out); } if ((_linkOpts & HLINK_TARGET_FRAME) != 0) { out.writeInt(_targetFrame.length()); StringUtil.putUnicodeLE(_targetFrame, out); } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) != 0) { out.writeInt(_address.length()); StringUtil.putUnicodeLE(_address, out); } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { _moniker.serialize(out); if (URL_MONIKER.equals(_moniker)) { if (_uninterpretedTail == null) { out.writeInt(_address.length() * 2); StringUtil.putUnicodeLE(_address, out); } else { out.writeInt(_address.length() * 2 + TAIL_SIZE); StringUtil.putUnicodeLE(_address, out); writeTail(_uninterpretedTail, out); } } else if (FILE_MONIKER.equals(_moniker)) { out.writeShort(_fileOpts); out.writeInt(_shortFilename.length()); StringUtil.putCompressedUnicode(_shortFilename, out); writeTail(_uninterpretedTail, out); if (_address == null) { out.writeInt(0); } else { int addrLen = _address.length() * 2; out.writeInt(addrLen + 6); out.writeInt(addrLen); out.writeShort(0x0003); // TODO const StringUtil.putUnicodeLE(_address, out); } } } if ((_linkOpts & HLINK_PLACE) != 0) { out.writeInt(_textMark.length()); StringUtil.putUnicodeLE(_textMark, out); } } protected int getDataSize() { int size = 0; size += 2 + 2 + 2 + 2; // rwFirst, rwLast, colFirst, colLast size += GUID.ENCODED_SIZE; size += 4; // label_opts size += 4; // link_opts if ((_linkOpts & HLINK_LABEL) != 0) { size += 4; // link length size += _label.length() * 2; } if ((_linkOpts & HLINK_TARGET_FRAME) != 0) { size += 4; // int nChars size += _targetFrame.length() * 2; } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) != 0) { size += 4; // int nChars size += _address.length() * 2; } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { size += GUID.ENCODED_SIZE; if (URL_MONIKER.equals(_moniker)) { size += 4; // address length size += _address.length() * 2; if (_uninterpretedTail != null) { size += TAIL_SIZE; } } else if (FILE_MONIKER.equals(_moniker)) { size += 2; // file_opts size += 4; // address length size += _shortFilename.length(); size += TAIL_SIZE; size += 4; if (_address != null) { size += 6; size += _address.length() * 2; } } } if ((_linkOpts & HLINK_PLACE) != 0) { size += 4; // address length size += _textMark.length() * 2; } return size; } private static byte[] readTail(byte[] expectedTail, LittleEndianInput in) { byte[] result = new byte[TAIL_SIZE]; in.readFully(result); if (false) { // Quite a few examples in the unit tests which don't have the exact expected tail for (int i = 0; i < expectedTail.length; i++) { if (expectedTail[i] != result[i]) { System.err.println( "Mismatch in tail byte [" + i + "]" + "expected " + (expectedTail[i] & 0xFF) + " but got " + (result[i] & 0xFF)); } } } return result; } private static void writeTail(byte[] tail, LittleEndianOutput out) { out.write(tail); } public short getSid() { return HyperlinkRecord.sid; } public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[HYPERLINK RECORD]\n"); buffer.append(" .range = ").append(_range.formatAsString()).append("\n"); buffer.append(" .guid = ").append(_guid.formatAsString()).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"); } if ((_linkOpts & HLINK_PLACE) != 0) { buffer.append(" .textMark= ").append(getTextMark()).append("\n"); } buffer.append(" .address = ").append(getAddress()).append("\n"); buffer.append("[/HYPERLINK RECORD]\n"); return buffer.toString(); } /** Based on the link options, is this a url? */ public boolean isUrlLink() { return (_linkOpts & HLINK_URL) > 0 && (_linkOpts & HLINK_ABS) > 0; } /** Based on the link options, is this a file? */ public boolean isFileLink() { return (_linkOpts & HLINK_URL) > 0 && (_linkOpts & HLINK_ABS) == 0; } /** Based on the link options, is this a document? */ public boolean isDocumentLink() { return (_linkOpts & HLINK_PLACE) > 0; } /** Initialize a new url link */ public void newUrlLink() { _range = new CellRangeAddress(0, 0, 0, 0); _guid = STD_MONIKER; _linkOpts = HLINK_URL | HLINK_ABS | HLINK_LABEL; setLabel(""); _moniker = URL_MONIKER; setAddress(""); _uninterpretedTail = URL_TAIL; } /** Initialize a new file link */ public void newFileLink() { _range = new CellRangeAddress(0, 0, 0, 0); _guid = STD_MONIKER; _linkOpts = HLINK_URL | HLINK_LABEL; _fileOpts = 0; setLabel(""); _moniker = FILE_MONIKER; setAddress(null); setShortFilename(""); _uninterpretedTail = FILE_TAIL; } /** Initialize a new document link */ public void newDocumentLink() { _range = new CellRangeAddress(0, 0, 0, 0); _guid = STD_MONIKER; _linkOpts = HLINK_LABEL | HLINK_PLACE; setLabel(""); _moniker = FILE_MONIKER; setAddress(""); setTextMark(""); } public Object clone() { HyperlinkRecord rec = new HyperlinkRecord(); rec._range = _range.copy(); rec._guid = _guid; rec._linkOpts = _linkOpts; rec._fileOpts = _fileOpts; rec._label = _label; rec._address = _address; rec._moniker = _moniker; rec._shortFilename = _shortFilename; rec._targetFrame = _targetFrame; rec._textMark = _textMark; rec._uninterpretedTail = _uninterpretedTail; return rec; } }
public HyperlinkRecord(RecordInputStream in) { _range = new CellRangeAddress(in); _guid = new GUID(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. */ int streamVersion = in.readInt(); if (streamVersion != 0x00000002) { throw new RecordFormatException("Stream Version must be 0x2 but found " + streamVersion); } _linkOpts = in.readInt(); if ((_linkOpts & HLINK_LABEL) != 0) { int label_len = in.readInt(); _label = in.readUnicodeLEString(label_len); } if ((_linkOpts & HLINK_TARGET_FRAME) != 0) { int len = in.readInt(); _targetFrame = in.readUnicodeLEString(len); } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) != 0) { _moniker = null; int nChars = in.readInt(); _address = in.readUnicodeLEString(nChars); } if ((_linkOpts & HLINK_URL) != 0 && (_linkOpts & HLINK_UNC_PATH) == 0) { _moniker = new GUID(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, * then the tail bytes fields are not present. */ int remaining = in.remaining(); if (length == remaining) { int nChars = length / 2; _address = in.readUnicodeLEString(nChars); } 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 {0xF4815879, 0x1D3B, 0x487F, 0xAF, 0x2C, 0x82, * 0x5D, 0xC4, 0x85, 0x27, 0x63} 2. Serial version, this field MUST equal 0 if present. 3. * URI Flags */ _uninterpretedTail = readTail(URL_TAIL, in); } } else if (FILE_MONIKER.equals(_moniker)) { _fileOpts = in.readShort(); int len = in.readInt(); _shortFilename = StringUtil.readCompressedUnicode(in, len); _uninterpretedTail = readTail(FILE_TAIL, in); int size = in.readInt(); if (size > 0) { int charDataSize = in.readInt(); // From the spec: An optional unsigned integer that MUST be 3 if present // but some files has 4 int usKeyValue = in.readUShort(); _address = StringUtil.readUnicodeLE(in, charDataSize / 2); } else { _address = null; } } else if (STD_MONIKER.equals(_moniker)) { _fileOpts = in.readShort(); int len = in.readInt(); byte[] path_bytes = new byte[len]; in.readFully(path_bytes); _address = new String(path_bytes); } } if ((_linkOpts & HLINK_PLACE) != 0) { int len = in.readInt(); _textMark = in.readUnicodeLEString(len); } if (in.remaining() > 0) { logger.log( POILogger.WARN, "Hyperlink data remains: " + in.remaining() + " : " + HexDump.toHex(in.readRemainder())); } }
/** * Hyperlink address. Depending on the hyperlink type it can be URL, e-mail, path to a file, etc. * * @param address the address of this hyperlink */ public void setAddress(String address) { if ((_linkOpts & HLINK_URL) != 0 && FILE_MONIKER.equals(_moniker)) _shortFilename = appendNullTerm(address); else if ((_linkOpts & HLINK_PLACE) != 0) _textMark = appendNullTerm(address); else _address = appendNullTerm(address); }
/** * Hyperlink address. Depending on the hyperlink type it can be URL, e-mail, path to a file, etc. * * @return the address of this hyperlink */ public String getAddress() { if ((_linkOpts & HLINK_URL) != 0 && FILE_MONIKER.equals(_moniker)) return cleanString(_address != null ? _address : _shortFilename); else if ((_linkOpts & HLINK_PLACE) != 0) return cleanString(_textMark); else return cleanString(_address); }