diff options
4 files changed, 245 insertions, 11 deletions
diff --git a/src/scratchpad/src/org/apache/poi/hpbf/dev/PLCDumper.java b/src/scratchpad/src/org/apache/poi/hpbf/dev/PLCDumper.java index 368755efc0..cdec78c8cf 100644 --- a/src/scratchpad/src/org/apache/poi/hpbf/dev/PLCDumper.java +++ b/src/scratchpad/src/org/apache/poi/hpbf/dev/PLCDumper.java @@ -20,17 +20,11 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import org.apache.poi.ddf.DefaultEscherRecordFactory; -import org.apache.poi.ddf.EscherRecord; import org.apache.poi.hpbf.HPBFDocument; import org.apache.poi.hpbf.model.QuillContents; import org.apache.poi.hpbf.model.qcbits.QCBit; -import org.apache.poi.poifs.filesystem.DirectoryNode; -import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.HexDump; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.StringUtil; /** * For dumping out the PLC contents of QC Bits of a @@ -41,8 +35,8 @@ public class PLCDumper { private HPBFDocument doc; private QuillContents qc; - public PLCDumper(HPBFDocument doc) { - this.doc = doc; + public PLCDumper(HPBFDocument hpbfDoc) { + doc = hpbfDoc; qc = doc.getQuillContents(); } public PLCDumper(POIFSFileSystem fs) throws IOException { @@ -67,7 +61,6 @@ public class PLCDumper { } private void dumpPLC() { - QuillContents qc = doc.getQuillContents(); QCBit[] bits = qc.getBits(); for(int i=0; i<bits.length; i++) { @@ -82,8 +75,8 @@ public class PLCDumper { System.out.println(""); System.out.println("Dumping " + bit.getBitType() + " bit at " + index); System.out.println(" Is a " + bit.getThingType() + ", number is " + bit.getOptA()); - System.out.println(" Starts at " + bit.getDataOffset() + " (" + Integer.toHexString(bit.getDataOffset()) + ")"); - System.out.println(" Runs for " + bit.getLength() + " (" + Integer.toHexString(bit.getLength()) + ")"); + System.out.println(" Starts at " + bit.getDataOffset() + " (0x" + Integer.toHexString(bit.getDataOffset()) + ")"); + System.out.println(" Runs for " + bit.getLength() + " (0x" + Integer.toHexString(bit.getLength()) + ")"); System.out.println(HexDump.dump(bit.getData(), 0, 0)); } diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java b/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java index b8d4ad298a..56f7bfcc9c 100644 --- a/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java @@ -19,6 +19,7 @@ package org.apache.poi.hpbf.model; import java.io.IOException; import org.apache.poi.hpbf.model.qcbits.QCBit; +import org.apache.poi.hpbf.model.qcbits.QCPLCBit; import org.apache.poi.hpbf.model.qcbits.QCTextBit; import org.apache.poi.hpbf.model.qcbits.UnknownQCBit; import org.apache.poi.poifs.filesystem.DirectoryNode; @@ -64,6 +65,8 @@ public final class QuillContents extends HPBFPart { // Create if(bitType.equals("TEXT")) { bits[i] = new QCTextBit(thingType, bitType, bitData); + } else if(bitType.equals("PLC ")) { + bits[i] = QCPLCBit.createQCPLCBit(thingType, bitType, bitData); } else { bits[i] = new UnknownQCBit(thingType, bitType, bitData); } diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCPLCBit.java b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCPLCBit.java new file mode 100644 index 0000000000..92e936528a --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCPLCBit.java @@ -0,0 +1,175 @@ +/* ==================================================================== + 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.hpbf.model.qcbits; + +import org.apache.poi.util.LittleEndian; + + +/** + * A "PLC " (PLC) based bit of Quill Contents. The exact + * format is determined by the type of the PLCs. + */ +public class QCPLCBit extends QCBit { + protected int numberOfPLCs; + protected int typeOfPLCS; + /** + * The data which goes before the main PLC entries. + * This is apparently always made up of 2 byte + * un-signed ints.. + */ + protected int[] preData; + /** The first value of each PLC, normally 4 bytes */ + protected long[] plcValA; + /** The second value of each PLC, normally 4 bytes */ + protected long[] plcValB; + + + private QCPLCBit(String thingType, String bitType, byte[] data) { + super(thingType, bitType, data); + + // First four bytes are the number + numberOfPLCs = (int)LittleEndian.getUInt(data, 0); + + // Next four bytes are the type + typeOfPLCS = (int)LittleEndian.getUInt(data, 4); + + // Init the arrays that we can + plcValA = new long[numberOfPLCs]; + plcValB = new long[numberOfPLCs]; + } + + + + public int getNumberOfPLCs() { + return numberOfPLCs; + } + public int getTypeOfPLCS() { + return typeOfPLCS; + } + + public int[] getPreData() { + return preData; + } + + public long[] getPlcValA() { + return plcValA; + } + public long[] getPlcValB() { + return plcValB; + } + + + + public static QCPLCBit createQCPLCBit(String thingType, String bitType, byte[] data) { + // Grab the type + int type = (int)LittleEndian.getUInt(data, 4); + switch(type) { + case 0: + return new Type0(thingType, bitType, data); + case 4: + return new Type4(thingType, bitType, data); + case 8: + return new Type8(thingType, bitType, data); + case 12: // 0xc + return new Type12(thingType, bitType, data); + default: + throw new IllegalArgumentException("Sorry, I don't know how to deal with PLCs of type " + type); + } + } + + + /** + * Type 0 seem to be somewhat rare. They have 8 bytes of pre-data, + * then 2x 2 byte values. + */ + public static class Type0 extends QCPLCBit { + private Type0(String thingType, String bitType, byte[] data) { + super(thingType, bitType, data); + + // Grab our 4x pre-data + preData = new int[4]; + preData[0] = LittleEndian.getUShort(data, 8+0); + preData[1] = LittleEndian.getUShort(data, 8+2); + preData[2] = LittleEndian.getUShort(data, 8+4); + preData[3] = LittleEndian.getUShort(data, 8+6); + + // And grab the 2 byte values + for(int i=0; i<numberOfPLCs; i++) { + plcValA[i] = LittleEndian.getUShort(data, 16+(4*i)); + plcValB[i] = LittleEndian.getUShort(data, 16+(4*i)+2); + } + } + } + + /** + * Type 4 is quite common. They have 8 bytes of pre-data, + * then 2x 4 byte values. + */ + public static class Type4 extends QCPLCBit { + private Type4(String thingType, String bitType, byte[] data) { + super(thingType, bitType, data); + + // Grab our 4x pre-data + preData = new int[4]; + preData[0] = LittleEndian.getUShort(data, 8+0); + preData[1] = LittleEndian.getUShort(data, 8+2); + preData[2] = LittleEndian.getUShort(data, 8+4); + preData[3] = LittleEndian.getUShort(data, 8+6); + + // And grab the 4 byte values + for(int i=0; i<numberOfPLCs; i++) { + plcValA[i] = LittleEndian.getUInt(data, 16+(8*i)); + plcValB[i] = LittleEndian.getUInt(data, 16+(8*i)+4); + } + } + } + + /** + * Type 8 is quite common. They have 14 bytes of pre-data, + * then 2x 4 byte values. + */ + public static class Type8 extends QCPLCBit { + private Type8(String thingType, String bitType, byte[] data) { + super(thingType, bitType, data); + + // Grab our 7x pre-data + preData = new int[7]; + preData[0] = LittleEndian.getUShort(data, 8+0); + preData[1] = LittleEndian.getUShort(data, 8+2); + preData[2] = LittleEndian.getUShort(data, 8+4); + preData[3] = LittleEndian.getUShort(data, 8+6); + preData[4] = LittleEndian.getUShort(data, 8+8); + preData[5] = LittleEndian.getUShort(data, 8+10); + preData[6] = LittleEndian.getUShort(data, 8+12); + + // And grab the 4 byte values + for(int i=0; i<numberOfPLCs; i++) { + plcValA[i] = LittleEndian.getUInt(data, 22+(8*i)); + plcValB[i] = LittleEndian.getUInt(data, 22+(8*i)+4); + } + } + } + + /** + * Type 12 holds hyperlinks, and is very complex. + */ + public static class Type12 extends QCPLCBit { + private Type12(String thingType, String bitType, byte[] data) { + super(thingType, bitType, data); + } + } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hpbf/model/TestQuillContents.java b/src/scratchpad/testcases/org/apache/poi/hpbf/model/TestQuillContents.java index ce6ddf83ef..ecbc226098 100644 --- a/src/scratchpad/testcases/org/apache/poi/hpbf/model/TestQuillContents.java +++ b/src/scratchpad/testcases/org/apache/poi/hpbf/model/TestQuillContents.java @@ -21,6 +21,8 @@ import java.io.FileInputStream; import org.apache.poi.hpbf.HPBFDocument; import org.apache.poi.hpbf.model.qcbits.QCTextBit; +import org.apache.poi.hpbf.model.qcbits.QCPLCBit.Type4; +import org.apache.poi.hpbf.model.qcbits.QCPLCBit.Type8; import junit.framework.TestCase; @@ -77,4 +79,65 @@ public class TestQuillContents extends TestCase { assertTrue(t.startsWith("This is some text on the first page")); assertTrue(t.endsWith("Within doc to page 1\r")); } + + public void testPLC() throws Exception { + File f = new File(dir, "Simple.pub"); + HPBFDocument doc = new HPBFDocument( + new FileInputStream(f) + ); + + QuillContents qc = doc.getQuillContents(); + assertEquals(20, qc.getBits().length); + + assertTrue(qc.getBits()[9] instanceof Type4); + assertTrue(qc.getBits()[10] instanceof Type4); + assertTrue(qc.getBits()[12] instanceof Type8); + + Type4 plc9 = (Type4)qc.getBits()[9]; + Type4 plc10 = (Type4)qc.getBits()[10]; + Type8 plc12 = (Type8)qc.getBits()[12]; + + + assertEquals(1, plc9.getNumberOfPLCs()); + assertEquals(4, plc9.getPreData().length); + assertEquals(1, plc9.getPlcValA().length); + assertEquals(1, plc9.getPlcValB().length); + + assertEquals(0, plc9.getPreData()[0]); + assertEquals(0, plc9.getPreData()[1]); + assertEquals(0, plc9.getPreData()[2]); + assertEquals(0, plc9.getPreData()[3]); + assertEquals(0x356, plc9.getPlcValA()[0]); + assertEquals(0x600, plc9.getPlcValB()[0]); + + + assertEquals(1, plc10.getNumberOfPLCs()); + assertEquals(4, plc10.getPreData().length); + assertEquals(1, plc10.getPlcValA().length); + assertEquals(1, plc10.getPlcValB().length); + + assertEquals(0, plc10.getPreData()[0]); + assertEquals(0, plc10.getPreData()[1]); + assertEquals(0, plc10.getPreData()[2]); + assertEquals(0, plc10.getPreData()[3]); + assertEquals(0x356, plc10.getPlcValA()[0]); + assertEquals(0x800, plc10.getPlcValB()[0]); + + assertEquals(2, plc12.getNumberOfPLCs()); + assertEquals(7, plc12.getPreData().length); + assertEquals(2, plc12.getPlcValA().length); + assertEquals(2, plc12.getPlcValB().length); + + assertEquals(0xff, plc12.getPreData()[0]); + assertEquals(0, plc12.getPreData()[1]); + assertEquals(0x3d, plc12.getPreData()[2]); + assertEquals(0, plc12.getPreData()[3]); + assertEquals(0x6e, plc12.getPreData()[4]); + assertEquals(0, plc12.getPreData()[5]); + assertEquals(0, plc12.getPreData()[6]); + assertEquals(0xa0000, plc12.getPlcValA()[0]); + assertEquals(0x22000000, plc12.getPlcValB()[0]); + assertEquals(0x05, plc12.getPlcValA()[1]); + assertEquals(0x04, plc12.getPlcValB()[1]); + } } |