Start to support HPBF PLC parts
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690534 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4b40a5cb0c
commit
0a81ea69b2
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user