]> source.dussan.org Git - poi.git/commitdiff
Start to support HPBF hyperlinks
authorNick Burch <nick@apache.org>
Sun, 31 Aug 2008 16:37:39 +0000 (16:37 +0000)
committerNick Burch <nick@apache.org>
Sun, 31 Aug 2008 16:37:39 +0000 (16:37 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690726 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/util/StringUtil.java
src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCPLCBit.java
src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt0And10.pub [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10.pub [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10And20And30.pub [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10And20And30And40.pub [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10Longer.pub [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt20.pub [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hpbf/model/TestQuillContents.java

index 673b5246e147c9de21ca6be0951e22ee360eaacd..957068a673d50548c170f512bc949e3c23fcf31b 100644 (file)
@@ -68,7 +68,7 @@ public class StringUtil {
                        throw new ArrayIndexOutOfBoundsException("Illegal offset");
                }
                if ((len < 0) || (((string.length - offset) / 2) < len)) {
-                       throw new IllegalArgumentException("Illegal length");
+                       throw new IllegalArgumentException("Illegal length " + len);
                }
 
                try {
index 92e936528a43facf59f77e1c8fba4df9a887694a..a2eadc52d94c603b75d329824f00b3b3c5a17b0a 100644 (file)
@@ -17,6 +17,7 @@
 package org.apache.poi.hpbf.model.qcbits;
 
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.StringUtil;
 
 
 /**
@@ -168,8 +169,98 @@ public class QCPLCBit extends QCBit {
         * Type 12 holds hyperlinks, and is very complex.
         */
        public static class Type12 extends QCPLCBit {
+               private String[] hyperlinks;
+               
+               private static final int oneStartsAt = 0x4c;
+               private static final int twoStartsAt = 0x68;
+               private static final int threePlusIncrement = 22;
+               
                private Type12(String thingType, String bitType, byte[] data) {
                        super(thingType, bitType, data);
+                       
+                       // How many hyperlinks do we really have?
+                       // (zero hyperlinks gets numberOfPLCs=1)
+                       if(data.length == 0x34) {
+                               hyperlinks = new String[0];
+                       } else {
+                               hyperlinks = new String[numberOfPLCs];
+                       }
+                       
+                       // We have 4 bytes, then the start point of each
+                       //  hyperlink, then the end point of the text.
+                       preData = new int[1+numberOfPLCs+1];
+                       for(int i=0; i<preData.length; i++) {
+                               preData[i] = (int)LittleEndian.getUInt(data, 8+(i*4));
+                       }
+                       
+                       // Then we have a whole bunch of stuff, which grows
+                       //  with the number of hyperlinks
+                       // For now, we think these are shorts
+                       int at = 8+4+(numberOfPLCs*4)+4;
+                       int until = 0x34;
+                       if(numberOfPLCs == 1 && hyperlinks.length == 1) {
+                               until = oneStartsAt;
+                       } else if(numberOfPLCs >= 2) {
+                               until = twoStartsAt + (numberOfPLCs-2)*threePlusIncrement;
+                       }
+                       
+                       plcValA = new long[(until-at)/2];
+                       plcValB = new long[0];
+                       for(int i=0; i<plcValA.length; i++) {
+                               plcValA[i] = LittleEndian.getUShort(data, at+(i*2));
+                       }
+                       
+                       // Finally, we have a series of lengths + hyperlinks
+                       at = until;
+                       for(int i=0; i<hyperlinks.length; i++) {
+                               int len = LittleEndian.getUShort(data, at);
+                               int first = LittleEndian.getUShort(data, at+2);
+                               if(first == 0) {
+                                       // Crazy special case
+                                       // Length is in bytes, from the start
+                                       // Hyperlink appears to be empty
+                                       hyperlinks[i] = "";
+                                       at += len;
+                               } else {
+                                       // Normal case. Length is in characters
+                                       hyperlinks[i] = StringUtil.getFromUnicodeLE(data, at+2, len);
+                                       at += 2 + (2*len);
+                               }
+                       }
+               }
+               
+               /**
+                * Returns the number of hyperlinks, which should 
+                *  either be zero, or the number of PLC bits
+                */
+               public int getNumberOfHyperlinks() {
+                       return hyperlinks.length;
+               }
+
+               /**
+                * Returns the URL of the hyperlink at the
+                *  given index.
+                * @param number The hyperlink number, zero based
+                */
+               public String getHyperlink(int number) {
+                       return hyperlinks[number];
+               }
+               /**
+                * Returns where in the text (in characters) the
+                *  hyperlink at the given index starts 
+                *  applying to.
+                * @param number The hyperlink number, zero based
+                */
+               public int getTextStartAt(int number) {
+                       return preData[1+number];
+               }
+               /**
+                * Returns where in the text that this block
+                *  of hyperlinks stops applying to. Normally,
+                *  but not always the end of the text.
+                */
+               public int getAllTextEndAt() {
+                       return preData[numberOfPLCs+1];
                }
        }
 }
diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt0And10.pub b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt0And10.pub
new file mode 100755 (executable)
index 0000000..c4459fb
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt0And10.pub differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10.pub b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10.pub
new file mode 100755 (executable)
index 0000000..89c4a44
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10.pub differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10And20And30.pub b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10And20And30.pub
new file mode 100755 (executable)
index 0000000..5f7f747
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10And20And30.pub differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10And20And30And40.pub b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10And20And30And40.pub
new file mode 100755 (executable)
index 0000000..d19ddc4
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10And20And30And40.pub differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10Longer.pub b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10Longer.pub
new file mode 100755 (executable)
index 0000000..8a3dcc2
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt10Longer.pub differ
diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt20.pub b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt20.pub
new file mode 100755 (executable)
index 0000000..091a38c
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hpbf/data/LinkAt20.pub differ
index 0295fc5a0603aca5a18b16c8886b84e950dd9b4a..1ba45813c333c021d4a8c7467691916384861b7c 100644 (file)
@@ -244,4 +244,191 @@ public class TestQuillContents extends TestCase {
                assertEquals(0x000004, plc16.getPlcValA()[5]);
                assertEquals(0x000004, plc16.getPlcValB()[5]);
        }
+       
+       public void testNoHyperlinks() throws Exception {
+               File f = new File(dir, "SampleNewsletter.pub");
+               HPBFDocument doc = new HPBFDocument(
+                               new FileInputStream(f)
+               );
+               
+               QuillContents qc = doc.getQuillContents();
+               assertEquals(20, qc.getBits().length);
+               
+               Type12 plc18 = (Type12)qc.getBits()[18];
+               
+               assertEquals(1, plc18.getNumberOfPLCs());
+               assertEquals(0, plc18.getNumberOfHyperlinks());
+               assertEquals(0, plc18.getTextStartAt(0));
+               assertEquals(601, plc18.getAllTextEndAt());
+       }
+       
+       public void testSimpleHyperlink() throws Exception {
+               File f;
+               HPBFDocument doc;
+               QuillContents qc;
+               Type12 hlBit;
+               
+               // Link at 10
+               f = new File(dir, "LinkAt10.pub");
+               doc = new HPBFDocument(
+                               new FileInputStream(f)
+               );
+               qc = doc.getQuillContents();
+               
+               hlBit = (Type12)qc.getBits()[12];
+               assertEquals(1, hlBit.getNumberOfPLCs());
+               assertEquals(1, hlBit.getNumberOfHyperlinks());
+               
+               assertEquals(10, hlBit.getTextStartAt(0));
+               assertEquals(15, hlBit.getAllTextEndAt());
+               assertEquals("http://poi.apache.org/", hlBit.getHyperlink(0));
+               
+               // Longer link at 10
+               f = new File(dir, "LinkAt10Longer.pub");
+               doc = new HPBFDocument(
+                               new FileInputStream(f)
+               );
+               qc = doc.getQuillContents();
+               
+               hlBit = (Type12)qc.getBits()[12];
+               assertEquals(1, hlBit.getNumberOfPLCs());
+               assertEquals(1, hlBit.getNumberOfHyperlinks());
+               
+               assertEquals(10, hlBit.getTextStartAt(0));
+               assertEquals(15, hlBit.getAllTextEndAt());
+               assertEquals("http://poi.apache.org/hpbf/", hlBit.getHyperlink(0));
+               
+               // Link at 20
+               f = new File(dir, "LinkAt20.pub");
+               doc = new HPBFDocument(
+                               new FileInputStream(f)
+               );
+               qc = doc.getQuillContents();
+               
+               hlBit = (Type12)qc.getBits()[12];
+               assertEquals(1, hlBit.getNumberOfPLCs());
+               assertEquals(1, hlBit.getNumberOfHyperlinks());
+               
+               assertEquals(20, hlBit.getTextStartAt(0));
+               assertEquals(25, hlBit.getAllTextEndAt());
+               assertEquals("http://poi.apache.org/", hlBit.getHyperlink(0));
+       }
+       
+       public void testManyHyperlinks() throws Exception {
+               File f;
+               HPBFDocument doc;
+               QuillContents qc;
+               Type12 hlBit;
+               
+               // Link at 10
+               f = new File(dir, "LinkAt10.pub");
+               doc = new HPBFDocument(
+                               new FileInputStream(f)
+               );
+               qc = doc.getQuillContents();
+               
+               hlBit = (Type12)qc.getBits()[12];
+               assertEquals(1, hlBit.getNumberOfPLCs());
+               assertEquals(1, hlBit.getNumberOfHyperlinks());
+               
+               assertEquals(10, hlBit.getTextStartAt(0));
+               assertEquals(15, hlBit.getAllTextEndAt());
+               assertEquals("http://poi.apache.org/", hlBit.getHyperlink(0));
+               
+       }
+       
+       public void testHyperlinkDifferentVersions() throws Exception {
+               File f;
+               HPBFDocument doc;
+               QuillContents qc;
+               Type12 hlBitA;
+               Type12 hlBitB;
+               
+               // Latest version
+               f = new File(dir, "Sample.pub");
+               doc = new HPBFDocument(
+                               new FileInputStream(f)
+               );
+               qc = doc.getQuillContents();
+               
+               hlBitA = (Type12)qc.getBits()[14];
+               assertEquals(2, hlBitA.getNumberOfPLCs());
+               assertEquals(2, hlBitA.getNumberOfHyperlinks());
+               
+               assertEquals(25, hlBitA.getTextStartAt(0));
+               assertEquals(72, hlBitA.getTextStartAt(1));
+               assertEquals(87, hlBitA.getAllTextEndAt());
+               assertEquals("http://poi.apache.org/", hlBitA.getHyperlink(0));
+               assertEquals("C:\\Documents and Settings\\Nick\\My Documents\\Booleans.xlsx", hlBitA.getHyperlink(1));
+               
+               hlBitB = (Type12)qc.getBits()[15];
+               assertEquals(3, hlBitB.getNumberOfPLCs());
+               assertEquals(3, hlBitB.getNumberOfHyperlinks());
+               
+               assertEquals(27, hlBitB.getTextStartAt(0));
+               assertEquals(37, hlBitB.getTextStartAt(1));
+               assertEquals(54, hlBitB.getTextStartAt(2));
+               assertEquals(75, hlBitB.getAllTextEndAt());
+               assertEquals("", hlBitB.getHyperlink(0));
+               assertEquals("mailto:dev@poi.apache.org?subject=HPBF", hlBitB.getHyperlink(1));
+               assertEquals("mailto:dev@poi.apache.org?subject=HPBF", hlBitB.getHyperlink(2));
+               
+               // 2000 version
+               f = new File(dir, "Sample2000.pub");
+               doc = new HPBFDocument(
+                               new FileInputStream(f)
+               );
+               qc = doc.getQuillContents();
+               
+               hlBitA = (Type12)qc.getBits()[13];
+               assertEquals(2, hlBitA.getNumberOfPLCs());
+               assertEquals(2, hlBitA.getNumberOfHyperlinks());
+               
+               assertEquals(25, hlBitA.getTextStartAt(0));
+               assertEquals(72, hlBitA.getTextStartAt(1));
+               assertEquals(87, hlBitA.getAllTextEndAt());
+               assertEquals("http://poi.apache.org/", hlBitA.getHyperlink(0));
+               assertEquals("C:\\Documents and Settings\\Nick\\My Documents\\Booleans.xlsx", hlBitA.getHyperlink(1));
+               
+               hlBitB = (Type12)qc.getBits()[14];
+               assertEquals(3, hlBitB.getNumberOfPLCs());
+               assertEquals(3, hlBitB.getNumberOfHyperlinks());
+               
+               assertEquals(27, hlBitB.getTextStartAt(0));
+               assertEquals(37, hlBitB.getTextStartAt(1));
+               assertEquals(54, hlBitB.getTextStartAt(2));
+               assertEquals(75, hlBitB.getAllTextEndAt());
+               assertEquals("", hlBitB.getHyperlink(0));
+               assertEquals("mailto:dev@poi.apache.org?subject=HPBF", hlBitB.getHyperlink(1));
+               assertEquals("mailto:dev@poi.apache.org?subject=HPBF", hlBitB.getHyperlink(2));
+               
+               // 98 version
+               f = new File(dir, "Sample98.pub");
+               doc = new HPBFDocument(
+                               new FileInputStream(f)
+               );
+               qc = doc.getQuillContents();
+               
+               hlBitA = (Type12)qc.getBits()[13];
+               assertEquals(2, hlBitA.getNumberOfPLCs());
+               assertEquals(2, hlBitA.getNumberOfHyperlinks());
+               
+               assertEquals(25, hlBitA.getTextStartAt(0));
+               assertEquals(72, hlBitA.getTextStartAt(1));
+               assertEquals(87, hlBitA.getAllTextEndAt());
+               assertEquals("http://poi.apache.org/", hlBitA.getHyperlink(0));
+               assertEquals("C:\\Documents and Settings\\Nick\\My Documents\\Booleans.xlsx", hlBitA.getHyperlink(1));
+               
+               hlBitB = (Type12)qc.getBits()[14];
+               assertEquals(3, hlBitB.getNumberOfPLCs());
+               assertEquals(3, hlBitB.getNumberOfHyperlinks());
+               
+               assertEquals(27, hlBitB.getTextStartAt(0));
+               assertEquals(37, hlBitB.getTextStartAt(1));
+               assertEquals(54, hlBitB.getTextStartAt(2));
+               assertEquals(75, hlBitB.getAllTextEndAt());
+               assertEquals("", hlBitB.getHyperlink(0));
+               assertEquals("mailto:dev@poi.apache.org?subject=HPBF", hlBitB.getHyperlink(1));
+               assertEquals("mailto:dev@poi.apache.org?subject=HPBF", hlBitB.getHyperlink(2));
+       }
 }