--- /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 Links in the document.
+ * (The actual link is held Document.ExObjList.ExHyperlink)
+ *
+ * @author Nick Burch
+ */
+
+public class InteractiveInfoAtom extends RecordAtom
+{
+ /**
+ * Record header.
+ */
+ private byte[] _header;
+
+ /**
+ * Record data.
+ */
+ private byte[] _data;
+
+ /**
+ * Constructs a brand new link related atom record.
+ */
+ protected InteractiveInfoAtom() {
+ _header = new byte[8];
+ _data = new byte[16];
+
+ 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 InteractiveInfoAtom(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 16 bytes long
+ if(_data.length < 16) {
+ throw new IllegalArgumentException("The length of the data for a InteractiveInfoAtom must be at least 16 bytes, but was only " + _data.length);
+ }
+
+ // First 4 bytes - no idea, normally 0
+ // Second 4 bytes - the id of the link (from 1 onwards)
+ // Third 4 bytes - no idea, normally 4
+ // Fourth 4 bytes - no idea, normally 8
+ }
+
+ /**
+ * Gets the link number. You will normally look the
+ * ExHyperlink with this number to get the details.
+ * @return the link number
+ */
+ public int getNumber() {
+ return LittleEndian.getInt(_data,4);
+ }
+
+ /**
+ * Sets the link number
+ * @param number the link number.
+ */
+ public void setNumber(int number) {
+ LittleEndian.putInt(_data,4,number);
+ }
+
+ /**
+ * Get the first number - meaning unknown
+ */
+ public int _getNumber1() {
+ return LittleEndian.getInt(_data,0);
+ }
+ protected void _setNumber1(int val) {
+ LittleEndian.putInt(_data, 0, val);
+ }
+
+ /**
+ * Get the third number - meaning unknown
+ */
+ public int _getNumber3() {
+ return LittleEndian.getInt(_data,8);
+ }
+ protected void _setNumber3(int val) {
+ LittleEndian.putInt(_data, 8, val);
+ }
+
+ /**
+ * Get the fourth number - meaning unknown
+ */
+ public int _getNumber4() {
+ return LittleEndian.getInt(_data,12);
+ }
+ protected void _setNumber4(int val) {
+ LittleEndian.putInt(_data, 12, val);
+ }
+
+ /**
+ * Gets the record type.
+ * @return the record type.
+ */
+ public long getRecordType() { return RecordTypes.InteractiveInfoAtom.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);
+ }
+}
--- /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 TestInteractiveInfoAtom extends TestCase {
+ // From a real file
+ private byte[] data_a = new byte[] {
+ 00, 00, 0xF3-256, 0x0F, 0x10, 00, 00, 00,
+ 00, 00, 00, 00, 01, 00, 00, 00,
+ 04, 00, 00, 00, 8, 00, 00, 00
+ };
+ private byte[] data_b = new byte[] {
+ 00, 00, 0xF3-256, 0x0F, 0x10, 00, 00, 00,
+ 00, 00, 00, 00, 04, 00, 00, 00,
+ 04, 00, 00, 00, 8, 00, 00, 00
+ };
+
+ public void testRecordType() throws Exception {
+ InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
+ assertEquals(4083l, ia.getRecordType());
+ }
+
+ public void testGetNumber() throws Exception {
+ InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
+ InteractiveInfoAtom ib = new InteractiveInfoAtom(data_b, 0, data_b.length);
+
+ assertEquals(1, ia.getNumber());
+ assertEquals(4, ib.getNumber());
+ }
+
+ public void testGetRest() throws Exception {
+ InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
+ InteractiveInfoAtom ib = new InteractiveInfoAtom(data_b, 0, data_b.length);
+
+ assertEquals(0, ia._getNumber1());
+ assertEquals(0, ib._getNumber1());
+
+ assertEquals(4, ia._getNumber3());
+ assertEquals(4, ib._getNumber3());
+
+ assertEquals(8, ia._getNumber4());
+ assertEquals(8, ib._getNumber4());
+ }
+
+ public void testWrite() throws Exception {
+ InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ia.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 {
+ InteractiveInfoAtom ia = new InteractiveInfoAtom();
+
+ // Set values
+ ia.setNumber(1);
+ ia._setNumber1(0);
+ ia._setNumber3(4);
+ ia._setNumber4(8);
+
+ // Check it's now the same as a
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ia.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 {
+ InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
+
+ // Change the number
+ ia.setNumber(4);
+
+ // Check bytes are now the same
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ia.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]);
+ }
+ }
+}