--- /dev/null
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.poi.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * This class represents the data of a link in the document.
+ * @author Nick Burch
+ */
+public class ExHyperlink extends RecordContainer {
+ private byte[] _header;
+ private static long _type = 4055;
+
+ // Links to our more interesting children
+ private ExHyperlinkAtom linkAtom;
+ private CString linkDetailsA;
+ private CString linkDetailsB;
+ private Comment2000Atom commentAtom;
+
+ /**
+ * Returns the ExHyperlinkAtom of this link
+ */
+ public ExHyperlinkAtom getExHyperlinkAtom() { return linkAtom; }
+
+ /**
+ * Returns the URL of the link.
+ * TODO: Figure out which of detailsA or detailsB is the
+ * one that always holds it
+ */
+ public String getLinkURL() {
+ return linkDetailsA.getText();
+ }
+
+ /**
+ * Sets the URL of the link
+ * TODO: Figure out if we should always set both
+ */
+ public void setLinkURL(String url) {
+ linkDetailsA.setText(url);
+ linkDetailsB.setText(url);
+ }
+
+ /**
+ * Get the link details (field A)
+ */
+ public String _getDetailsA() {
+ return linkDetailsA.getText();
+ }
+ /**
+ * Get the link details (field B)
+ */
+ public String _getDetailsB() {
+ return linkDetailsB.getText();
+ }
+
+ /**
+ * Set things up, and find our more interesting children
+ */
+ protected ExHyperlink(byte[] source, int start, int len) {
+ // Grab the header
+ _header = new byte[8];
+ System.arraycopy(source,start,_header,0,8);
+
+ // Find our children
+ _children = Record.findChildRecords(source,start+8,len-8);
+ findInterestingChildren();
+ }
+
+ /**
+ * Go through our child records, picking out the ones that are
+ * interesting, and saving those for use by the easy helper
+ * methods.
+ */
+ private void findInterestingChildren() {
+ // First child should be the ExHyperlinkAtom
+ if(_children[0] instanceof ExHyperlinkAtom) {
+ linkAtom = (ExHyperlinkAtom)_children[0];
+ } else {
+ throw new IllegalStateException("First child record wasn't a ExHyperlinkAtom, was of type " + _children[0].getRecordType());
+ }
+
+ // Second child should be the first link details
+ if(_children[1] instanceof CString) {
+ linkDetailsA = (CString)_children[1];
+ } else {
+ throw new IllegalStateException("Second child record wasn't a CString, was of type " + _children[1].getRecordType());
+ }
+ // Third child should be the second link details
+ if(_children[2] instanceof CString) {
+ linkDetailsB = (CString)_children[2];
+ } else {
+ throw new IllegalStateException("Third child record wasn't a CString, was of type " + _children[2].getRecordType());
+ }
+ }
+
+ /**
+ * Create a new ExHyperlink, with blank fields
+ */
+ public ExHyperlink() {
+ _header = new byte[8];
+ _children = new Record[3];
+
+ // Setup our header block
+ _header[0] = 0x0f; // We are a container record
+ LittleEndian.putShort(_header, 2, (short)_type);
+
+ // Setup our child records
+ CString csa = new CString();
+ CString csb = new CString();
+ csa.setCount(0x00);
+ csb.setCount(0x10);
+ _children[0] = new ExHyperlinkAtom();
+ _children[1] = csa;
+ _children[2] = csb;
+ findInterestingChildren();
+ }
+
+ /**
+ * We are of type 4055
+ */
+ public long getRecordType() { return _type; }
+
+ /**
+ * Write the contents of the record back, so it can be written
+ * to disk
+ */
+ public void writeOut(OutputStream out) throws IOException {
+ writeOut(_header[0],_header[1],_type,_children,out);
+ }
+}
--- /dev/null
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+
+import org.apache.poi.hslf.util.SystemTimeUtils;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * Tne atom that holds metadata on a specific Link in the document.
+ * (The actual link is held in a sibling CString record)
+ *
+ * @author Nick Burch
+ */
+
+public class ExHyperlinkAtom extends RecordAtom
+{
+ /**
+ * Record header.
+ */
+ private byte[] _header;
+
+ /**
+ * Record data.
+ */
+ private byte[] _data;
+
+ /**
+ * Constructs a brand new link related atom record.
+ */
+ protected ExHyperlinkAtom() {
+ _header = new byte[8];
+ _data = new byte[4];
+
+ LittleEndian.putShort(_header, 2, (short)getRecordType());
+ LittleEndian.putInt(_header, 4, _data.length);
+
+ // It is fine for the other values to be zero
+ }
+
+ /**
+ * Constructs the link related atom record from its
+ * source data.
+ *
+ * @param source the source data as a byte array.
+ * @param start the start offset into the byte array.
+ * @param len the length of the slice in the byte array.
+ */
+ protected ExHyperlinkAtom(byte[] source, int start, int len) {
+ // Get the header.
+ _header = new byte[8];
+ System.arraycopy(source,start,_header,0,8);
+
+ // Get the record data.
+ _data = new byte[len-8];
+ System.arraycopy(source,start+8,_data,0,len-8);
+
+ // Must be at least 4 bytes long
+ if(_data.length < 4) {
+ throw new IllegalArgumentException("The length of the data for a ExHyperlinkAtom must be at least 4 bytes, but was only " + _data.length);
+ }
+ }
+
+ /**
+ * Gets the link number. This will match the one in the
+ * InteractiveInfoAtom which uses the link.
+ * @return the link number
+ */
+ public int getNumber() {
+ return LittleEndian.getInt(_data,0);
+ }
+
+ /**
+ * Sets the link number
+ * @param number the link number.
+ */
+ public void setNumber(int number) {
+ LittleEndian.putInt(_data,0,number);
+ }
+
+ /**
+ * Gets the record type.
+ * @return the record type.
+ */
+ public long getRecordType() { return RecordTypes.ExHyperlinkAtom.typeID; }
+
+ /**
+ * Write the contents of the record back, so it can be written
+ * to disk
+ *
+ * @param out the output stream to write to.
+ * @throws IOException if an error occurs.
+ */
+ public void writeOut(OutputStream out) throws IOException {
+ out.write(_header);
+ out.write(_data);
+ }
+}
*/
public class InteractiveInfo extends RecordContainer {
private byte[] _header;
- private static long _type = RecordTypes.InteractiveInfo.typeID;
+ private static long _type = 4082;
// Links to our more interesting children
private InteractiveInfoAtom infoAtom;
public static final Type BookmarkEntityAtom = new Type(4048,null);
public static final Type ExLinkAtom = new Type(4049,null);
public static final Type SrKinsokuAtom = new Type(4050,null);
- public static final Type ExHyperlinkAtom = new Type(4051,null);
- public static final Type ExHyperlink = new Type(4055,null);
+ public static final Type ExHyperlinkAtom = new Type(4051,ExHyperlinkAtom.class);
+ public static final Type ExHyperlink = new Type(4055,ExHyperlink.class);
public static final Type SlideNumberMCAtom = new Type(4056,null);
public static final Type HeadersFooters = new Type(4057,null);
public static final Type HeadersFootersAtom = new Type(4058,null);
--- /dev/null
+
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+
+package org.apache.poi.hslf.record;
+
+
+import junit.framework.TestCase;
+import java.io.ByteArrayOutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Tests that ExHyperlink works properly.
+ *
+ * @author Nick Burch (nick at torchbox dot com)
+ */
+public class TestExHyperlink extends TestCase {
+ // From a real file
+ private byte[] data_a = new byte[] {
+ 0x0F, 00, 0xD7-256, 0x0F, 0xA8-256, 00, 00, 00,
+
+ 00, 00, 0xD3-256, 0x0F, 04, 00, 00, 00,
+ 03, 00, 00, 00,
+
+ 00, 00, 0xBA-256, 0x0F, 0x46, 00, 00, 00,
+ 0x68, 00, 0x74, 00, 0x74, 00, 0x70, 00,
+ 0x3A, 00, 0x2F, 00, 0x2F, 00, 0x6A, 00,
+ 0x61, 00, 0x6B, 00, 0x61, 00, 0x72, 00,
+ 0x74, 00, 0x61, 00, 0x2E, 00, 0x61, 00,
+ 0x70, 00, 0x61, 00, 0x63, 00, 0x68, 00,
+ 0x65, 00, 0x2E, 00, 0x6F, 00, 0x72, 00,
+ 0x67, 00, 0x2F, 00, 0x70, 00, 0x6F, 00,
+ 0x69, 00, 0x2F, 00, 0x68, 00, 0x73, 00,
+ 0x73, 00, 0x66, 00, 0x2F, 00,
+
+ 0x10, 00, 0xBA-256, 0x0F, 0x46, 00, 00, 00,
+ 0x68, 00, 0x74, 00, 0x74, 00, 0x70, 00,
+ 0x3A, 00, 0x2F, 00, 0x2F, 00, 0x6A, 00,
+ 0x61, 00, 0x6B, 00, 0x61, 00, 0x72, 00,
+ 0x74, 00, 0x61, 00, 0x2E, 00, 0x61, 00,
+ 0x70, 00, 0x61, 00, 0x63, 00, 0x68, 00,
+ 0x65, 00, 0x2E, 00, 0x6F, 00, 0x72, 00,
+ 0x67, 00, 0x2F, 00, 0x70, 00, 0x6F, 00,
+ 0x69, 00, 0x2F, 00, 0x68, 00, 0x73, 00,
+ 0x73, 00, 0x66, 00, 0x2F, 00
+ };
+
+ public void testRecordType() throws Exception {
+ ExHyperlink eh = new ExHyperlink(data_a, 0, data_a.length);
+ assertEquals(4055l, eh.getRecordType());
+ }
+
+ public void testNumber() throws Exception {
+ ExHyperlink eh = new ExHyperlink(data_a, 0, data_a.length);
+ assertEquals(3, eh.getExHyperlinkAtom().getNumber());
+ }
+
+ public void testLinkURL() throws Exception {
+ ExHyperlink eh = new ExHyperlink(data_a, 0, data_a.length);
+ assertEquals("http://jakarta.apache.org/poi/hssf/", eh.getLinkURL());
+ }
+ public void testDetails() throws Exception {
+ ExHyperlink eh = new ExHyperlink(data_a, 0, data_a.length);
+ assertEquals("http://jakarta.apache.org/poi/hssf/", eh._getDetailsA());
+ assertEquals("http://jakarta.apache.org/poi/hssf/", eh._getDetailsB());
+ }
+
+ public void testWrite() throws Exception {
+ ExHyperlink eh = new ExHyperlink(data_a, 0, data_a.length);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ eh.writeOut(baos);
+ byte[] b = baos.toByteArray();
+
+ assertEquals(data_a.length, b.length);
+ for(int i=0; i<data_a.length; i++) {
+ assertEquals(data_a[i],b[i]);
+ }
+ }
+
+ public void testRealFile() throws Exception {
+ // TODO
+ }
+}
--- /dev/null
+
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+
+package org.apache.poi.hslf.record;
+
+
+import junit.framework.TestCase;
+import java.io.ByteArrayOutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Tests that InteractiveInfoAtom works properly.
+ *
+ * @author Nick Burch (nick at torchbox dot com)
+ */
+public class TestExHyperlinkAtom extends TestCase {
+ // From a real file
+ private byte[] data_a = new byte[] {
+ 00, 00, 0xD3-256, 0x0F, 04, 00, 00, 00,
+ 01, 00, 00, 00
+ };
+ private byte[] data_b = new byte[] {
+ 00, 00, 0xD3-256, 0x0F, 04, 00, 00, 00,
+ 04, 00, 00, 00
+ };
+
+ public void testRecordType() throws Exception {
+ ExHyperlinkAtom eha = new ExHyperlinkAtom(data_a, 0, data_a.length);
+ assertEquals(4051l, eha.getRecordType());
+ }
+
+ public void testGetNumber() throws Exception {
+ ExHyperlinkAtom eha = new ExHyperlinkAtom(data_a, 0, data_a.length);
+ ExHyperlinkAtom ehb = new ExHyperlinkAtom(data_b, 0, data_b.length);
+
+ assertEquals(1, eha.getNumber());
+ assertEquals(4, ehb.getNumber());
+ }
+
+ public void testWrite() throws Exception {
+ ExHyperlinkAtom eha = new ExHyperlinkAtom(data_a, 0, data_a.length);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ eha.writeOut(baos);
+ byte[] b = baos.toByteArray();
+
+ assertEquals(data_a.length, b.length);
+ for(int i=0; i<data_a.length; i++) {
+ assertEquals(data_a[i],b[i]);
+ }
+ }
+
+ // Create A from scratch
+ public void testCreate() throws Exception {
+ ExHyperlinkAtom eha = new ExHyperlinkAtom();
+
+ // Set value
+ eha.setNumber(1);
+
+ // Check it's now the same as a
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ eha.writeOut(baos);
+ byte[] b = baos.toByteArray();
+
+ assertEquals(data_a.length, b.length);
+ for(int i=0; i<data_a.length; i++) {
+ assertEquals(data_a[i],b[i]);
+ }
+ }
+
+ // Try to turn a into b
+ public void testChange() throws Exception {
+ ExHyperlinkAtom eha = new ExHyperlinkAtom(data_a, 0, data_a.length);
+
+ // Change the number
+ eha.setNumber(4);
+
+ // Check bytes are now the same
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ eha.writeOut(baos);
+ byte[] b = baos.toByteArray();
+
+ // Should now be the same
+ assertEquals(data_b.length, b.length);
+ for(int i=0; i<data_b.length; i++) {
+ assertEquals(data_b[i],b[i]);
+ }
+ }
+}