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 2782bd967..aa3f1a000 100644 --- a/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/QuillContents.java @@ -19,18 +19,66 @@ package org.apache.poi.hpbf.model; import java.io.FileNotFoundException; import java.io.IOException; +import org.apache.poi.hpbf.model.qcbits.QCBit; +import org.apache.poi.hpbf.model.qcbits.QCTextBit; +import org.apache.poi.hpbf.model.qcbits.UnknownQCBit; import org.apache.poi.poifs.filesystem.DirectoryNode; +import org.apache.poi.util.LittleEndian; /** * Quill -> QuillSub -> CONTENTS */ public class QuillContents extends HPBFPart { + private QCBit[] bits; + public QuillContents(DirectoryNode baseDir) throws FileNotFoundException, IOException { super(baseDir); // Now parse the first 512 bytes, and produce // all our bits + + // Check first 8 bytes + String f8 = new String(data, 0, 8); + if(! f8.equals("CHNKINK ")) { + throw new IllegalArgumentException("Expecting 'CHNKINK ' but was '"+f8+"'"); + } + // Ignore the next 24, for now at least + + // Now, parse all our QC Bits + bits = new QCBit[20]; + for(int i=0; i<20; i++) { + int offset = 0x20 + i*24; + if(data[offset] == 0x18 && data[offset+1] == 0x00) { + // Has some data + String thingType = new String(data, offset+2, 4); + int optA = LittleEndian.getUShort(data, offset+6); + int optB = LittleEndian.getUShort(data, offset+8); + int optC = LittleEndian.getUShort(data, offset+10); + String bitType = new String(data, offset+12, 4); + int from = (int)LittleEndian.getUInt(data, offset+16); + int len = (int)LittleEndian.getUInt(data, offset+20); + + byte[] bitData = new byte[len]; + System.arraycopy(data, from, bitData, 0, len); + + // Create + if(bitType.equals("TEXT")) { + bits[i] = new QCTextBit(thingType, bitType, bitData); + } else { + bits[i] = new UnknownQCBit(thingType, bitType, bitData); + } + bits[i].setOptA(optA); + bits[i].setOptB(optB); + bits[i].setOptC(optC); + } else { + // Doesn't have data + } + } + } + + public QCBit[] getBits() { + return bits; } protected void generateData() { diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCBit.java b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCBit.java new file mode 100644 index 000000000..61c7955f6 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCBit.java @@ -0,0 +1,69 @@ +/* ==================================================================== + 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; + +/** + * Parent of all Quill CONTENTS bits + */ +public abstract class QCBit { + protected String thingType; + protected String bitType; + protected byte[] data; + + protected int optA; + protected int optB; + protected int optC; + + public QCBit(String thingType, String bitType, byte[] data) { + this.thingType = thingType; + this.bitType = bitType; + this.data = data; + } + + /** + * Returns the type of the thing, eg TEXT, FONT + * or TOKN + */ + public String getThingType() { return thingType; } + /** + * Returns the type of the bit data, eg TEXT + * or PLC + */ + public String getBitType() { return bitType; } + public byte[] getData() { return data; } + + public int getOptA() { + return optA; + } + public void setOptA(int optA) { + this.optA = optA; + } + + public int getOptB() { + return optB; + } + public void setOptB(int optB) { + this.optB = optB; + } + + public int getOptC() { + return optC; + } + public void setOptC(int optC) { + this.optC = optC; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCTextBit.java b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCTextBit.java new file mode 100644 index 000000000..2c0e98b41 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/QCTextBit.java @@ -0,0 +1,39 @@ +/* ==================================================================== + 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.StringUtil; + +/** + * A Text based bit of Quill Contents + */ +public class QCTextBit extends QCBit { + public QCTextBit(String thingType, String bitType, byte[] data) { + super(thingType, bitType, data); + } + + public String getText() { + return StringUtil.getFromUnicodeLE( + data, 0, data.length/2 + ); + } + + public void setText(String text) { + data = new byte[text.length()*2]; + StringUtil.putUnicodeLE(text, data, 0); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/UnknownQCBit.java b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/UnknownQCBit.java new file mode 100644 index 000000000..2548b4fca --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hpbf/model/qcbits/UnknownQCBit.java @@ -0,0 +1,27 @@ +/* ==================================================================== + 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; + +/** + * Any Quill Contents bits we don't know + * how to handle explicitly + */ +public class UnknownQCBit extends QCBit { + public UnknownQCBit(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 new file mode 100644 index 000000000..ce6ddf83e --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hpbf/model/TestQuillContents.java @@ -0,0 +1,80 @@ +/* ==================================================================== + 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; + +import java.io.File; +import java.io.FileInputStream; + +import org.apache.poi.hpbf.HPBFDocument; +import org.apache.poi.hpbf.model.qcbits.QCTextBit; + +import junit.framework.TestCase; + +public class TestQuillContents extends TestCase { + private String dir; + + protected void setUp() throws Exception { + dir = System.getProperty("HPBF.testdata.path"); + } + + public void testBasics() throws Exception { + File f = new File(dir, "Sample.pub"); + HPBFDocument doc = new HPBFDocument( + new FileInputStream(f) + ); + + QuillContents qc = doc.getQuillContents(); + assertEquals(20, qc.getBits().length); + for(int i=0; i<19; i++) { + assertNotNull(qc.getBits()[i]); + } + // Last one is blank + assertNull(qc.getBits()[19]); + + // Should be text, then three STSHs + assertEquals("TEXT", qc.getBits()[0].getThingType()); + assertEquals("TEXT", qc.getBits()[0].getBitType()); + assertEquals(0, qc.getBits()[0].getOptA()); + + assertEquals("STSH", qc.getBits()[1].getThingType()); + assertEquals("STSH", qc.getBits()[1].getBitType()); + assertEquals(0, qc.getBits()[1].getOptA()); + + assertEquals("STSH", qc.getBits()[2].getThingType()); + assertEquals("STSH", qc.getBits()[2].getBitType()); + assertEquals(1, qc.getBits()[2].getOptA()); + + assertEquals("STSH", qc.getBits()[3].getThingType()); + assertEquals("STSH", qc.getBits()[3].getBitType()); + assertEquals(2, qc.getBits()[3].getOptA()); + } + + public void testText() throws Exception { + File f = new File(dir, "Sample.pub"); + HPBFDocument doc = new HPBFDocument( + new FileInputStream(f) + ); + + QuillContents qc = doc.getQuillContents(); + assertEquals(20, qc.getBits().length); + + QCTextBit text = (QCTextBit)qc.getBits()[0]; + String t = text.getText(); + assertTrue(t.startsWith("This is some text on the first page")); + assertTrue(t.endsWith("Within doc to page 1\r")); + } +}