Simplified InterfaceHdrRecord and InterfaceEndRecord (some rework after bug 47251 / r892862).
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@893402 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
56c40e3a0f
commit
cc648a0fc0
@ -180,7 +180,7 @@ public final class BiffViewer {
|
||||
case HorizontalPageBreakRecord.sid: return new HorizontalPageBreakRecord(in);
|
||||
case HyperlinkRecord.sid: return new HyperlinkRecord(in);
|
||||
case IndexRecord.sid: return new IndexRecord(in);
|
||||
case InterfaceEndRecord.sid: return new InterfaceEndRecord(in);
|
||||
case InterfaceEndRecord.sid: return InterfaceEndRecord.create(in);
|
||||
case InterfaceHdrRecord.sid: return new InterfaceHdrRecord(in);
|
||||
case IterationRecord.sid: return new IterationRecord(in);
|
||||
case LabelRecord.sid: return new LabelRecord(in);
|
||||
@ -367,13 +367,13 @@ public final class BiffViewer {
|
||||
* <tr><td>--noint</td><td>do not output interpretation of BIFF records</td></tr>
|
||||
* <tr><td>--out</td><td>send output to <fileName>.out</td></tr>
|
||||
* <tr><td>--rawhex</td><td>output raw hex dump of whole workbook stream</td></tr>
|
||||
* <tr><td>--escher</td><td>turn on deserialization of escher records (default is off)</td></tr>
|
||||
* <tr><td>--noheader</td><td>do not print record header (default is on)</td></tr>
|
||||
* <tr><td>--escher</td><td>turn on deserialization of escher records (default is off)</td></tr>
|
||||
* <tr><td>--noheader</td><td>do not print record header (default is on)</td></tr>
|
||||
* </table>
|
||||
*
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
// args = new String[] { "--out", "", };
|
||||
CommandArgs cmdArgs;
|
||||
try {
|
||||
cmdArgs = CommandArgs.parse(args);
|
||||
@ -419,12 +419,12 @@ public final class BiffViewer {
|
||||
private final Writer _hexDumpWriter;
|
||||
private final List<String> _headers;
|
||||
private final boolean _zeroAlignEachRecord;
|
||||
private final boolean _noHeader;
|
||||
private final boolean _noHeader;
|
||||
public BiffRecordListener(Writer hexDumpWriter, boolean zeroAlignEachRecord, boolean noHeader) {
|
||||
_hexDumpWriter = hexDumpWriter;
|
||||
_zeroAlignEachRecord = zeroAlignEachRecord;
|
||||
_noHeader = noHeader;
|
||||
_headers = new ArrayList<String>();
|
||||
_noHeader = noHeader;
|
||||
_headers = new ArrayList<String>();
|
||||
}
|
||||
|
||||
public void processRecord(int globalOffset, int recordCounter, int sid, int dataSize,
|
||||
|
@ -340,35 +340,35 @@ public final class InternalWorkbook {
|
||||
retval.records.setRecords(records);
|
||||
List<FormatRecord> formats = retval.formats;
|
||||
|
||||
records.add(retval.createBOF());
|
||||
records.add(retval.createInterfaceHdr());
|
||||
records.add(retval.createMMS());
|
||||
records.add(retval.createInterfaceEnd());
|
||||
records.add(retval.createWriteAccess());
|
||||
records.add(retval.createCodepage());
|
||||
records.add(retval.createDSF());
|
||||
records.add(retval.createTabId());
|
||||
records.add(createBOF());
|
||||
records.add(new InterfaceHdrRecord(CODEPAGE));
|
||||
records.add(createMMS());
|
||||
records.add(InterfaceEndRecord.instance);
|
||||
records.add(createWriteAccess());
|
||||
records.add(createCodepage());
|
||||
records.add(createDSF());
|
||||
records.add(createTabId());
|
||||
retval.records.setTabpos(records.size() - 1);
|
||||
records.add(retval.createFnGroupCount());
|
||||
records.add(createFnGroupCount());
|
||||
records.add(createWindowProtect());
|
||||
records.add(createProtect());
|
||||
retval.records.setProtpos(records.size() - 1);
|
||||
records.add(createPassword());
|
||||
records.add(createProtectionRev4());
|
||||
records.add(retval.createPasswordRev4());
|
||||
records.add(createPasswordRev4());
|
||||
retval.windowOne = createWindowOne();
|
||||
records.add(retval.windowOne);
|
||||
records.add(retval.createBackup());
|
||||
records.add(createBackup());
|
||||
retval.records.setBackuppos(records.size() - 1);
|
||||
records.add(retval.createHideObj());
|
||||
records.add(retval.createDateWindow1904());
|
||||
records.add(retval.createPrecision());
|
||||
records.add(createHideObj());
|
||||
records.add(createDateWindow1904());
|
||||
records.add(createPrecision());
|
||||
records.add(createRefreshAll());
|
||||
records.add(retval.createBookBool());
|
||||
records.add(retval.createFont());
|
||||
records.add(retval.createFont());
|
||||
records.add(retval.createFont());
|
||||
records.add(retval.createFont());
|
||||
records.add(createBookBool());
|
||||
records.add(createFont());
|
||||
records.add(createFont());
|
||||
records.add(createFont());
|
||||
records.add(createFont());
|
||||
retval.records.setFontpos( records.size() - 1 ); // last font record position
|
||||
retval.numfonts = 4;
|
||||
|
||||
@ -1054,12 +1054,6 @@ public final class InternalWorkbook {
|
||||
return retval;
|
||||
}
|
||||
|
||||
private static InterfaceHdrRecord createInterfaceHdr() {
|
||||
InterfaceHdrRecord retval = new InterfaceHdrRecord();
|
||||
|
||||
retval.setCodepage(CODEPAGE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
private static MMSRecord createMMS() {
|
||||
MMSRecord retval = new MMSRecord();
|
||||
@ -1069,10 +1063,6 @@ public final class InternalWorkbook {
|
||||
return retval;
|
||||
}
|
||||
|
||||
private static InterfaceEndRecord createInterfaceEnd() {
|
||||
return new InterfaceEndRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the WriteAccess record containing the logged in user's name
|
||||
*/
|
||||
|
@ -18,9 +18,6 @@
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
|
||||
/**
|
||||
* Title: Interface End Record (0x00E2)<P>
|
||||
@ -28,50 +25,39 @@ import org.apache.poi.util.POILogFactory;
|
||||
* (has no fields)<P>
|
||||
* REFERENCE: PG 324 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
public final class InterfaceEndRecord extends StandardRecord {
|
||||
private static POILogger logger = POILogFactory.getLogger(InterfaceEndRecord.class);
|
||||
|
||||
public final static short sid = 0x00E2;
|
||||
public static final short sid = 0x00E2;
|
||||
public static final InterfaceEndRecord instance = new InterfaceEndRecord();
|
||||
|
||||
private byte[] _unknownData;
|
||||
|
||||
public InterfaceEndRecord()
|
||||
{
|
||||
private InterfaceEndRecord() {
|
||||
// enforce singleton
|
||||
}
|
||||
|
||||
public InterfaceEndRecord(RecordInputStream in)
|
||||
{
|
||||
if(in.available() > 0){
|
||||
_unknownData = in.readRemainder();
|
||||
logger.log(POILogger.WARN, "encountered unexpected " +
|
||||
_unknownData.length + " bytes in InterfaceEndRecord");
|
||||
public static Record create(RecordInputStream in) {
|
||||
switch (in.remaining()) {
|
||||
case 0:
|
||||
return instance;
|
||||
case 2:
|
||||
return new InterfaceHdrRecord(in);
|
||||
}
|
||||
throw new RecordFormatException("Invalid record data size: " + in.remaining());
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[INTERFACEEND]\n");
|
||||
buffer.append(" unknownData=").append(HexDump.toHex(_unknownData)).append("\n");
|
||||
buffer.append("[/INTERFACEEND]\n");
|
||||
return buffer.toString();
|
||||
public String toString() {
|
||||
return "[INTERFACEEND/]\n";
|
||||
}
|
||||
|
||||
public void serialize(LittleEndianOutput out) {
|
||||
if(_unknownData != null) out.write(_unknownData);
|
||||
// no instance data
|
||||
}
|
||||
|
||||
protected int getDataSize() {
|
||||
int size = 0;
|
||||
if(_unknownData != null) size += _unknownData.length;
|
||||
return size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
{
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -15,86 +14,53 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
|
||||
/**
|
||||
* Title: Interface Header Record<P>
|
||||
* Title: Interface Header Record (0x00E1)<P>
|
||||
* Description: Defines the beginning of Interface records (MMS)<P>
|
||||
* REFERENCE: PG 324 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
|
||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
|
||||
public final class InterfaceHdrRecord
|
||||
extends StandardRecord
|
||||
{
|
||||
public final static short sid = 0xe1;
|
||||
private short field_1_codepage; // = 0;
|
||||
public final class InterfaceHdrRecord extends StandardRecord {
|
||||
public final static short sid = 0x00E1;
|
||||
private final int _codepage;
|
||||
|
||||
/**
|
||||
* suggested (and probably correct) default
|
||||
*/
|
||||
public final static int CODEPAGE = 0x04B0;
|
||||
|
||||
public final static short CODEPAGE = ( short ) 0x4b0;
|
||||
|
||||
public InterfaceHdrRecord()
|
||||
{
|
||||
public InterfaceHdrRecord(int codePage) {
|
||||
_codepage = codePage;
|
||||
}
|
||||
|
||||
public InterfaceHdrRecord(RecordInputStream in)
|
||||
{
|
||||
field_1_codepage = in.readShort();
|
||||
public InterfaceHdrRecord(RecordInputStream in) {
|
||||
_codepage = in.readShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* set the codepage for the file
|
||||
*
|
||||
* @param cp - the codepage
|
||||
* @see #CODEPAGE
|
||||
*/
|
||||
|
||||
public void setCodepage(short cp)
|
||||
{
|
||||
field_1_codepage = cp;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the codepage for the file
|
||||
*
|
||||
* @return the codepage
|
||||
* @see #CODEPAGE
|
||||
*/
|
||||
|
||||
public short getCodepage()
|
||||
{
|
||||
return field_1_codepage;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[INTERFACEHDR]\n");
|
||||
buffer.append(" .codepage = ")
|
||||
.append(Integer.toHexString(getCodepage())).append("\n");
|
||||
buffer.append(" .codepage = ").append(HexDump.shortToHex(_codepage)).append("\n");
|
||||
buffer.append("[/INTERFACEHDR]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public void serialize(LittleEndianOutput out) {
|
||||
out.writeShort(getCodepage());
|
||||
out.writeShort(_codepage);
|
||||
}
|
||||
|
||||
protected int getDataSize() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
{
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package org.apache.poi.hssf.record;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
@ -44,10 +45,10 @@ public final class RecordFactory {
|
||||
|
||||
Class<? extends Record> getRecordClass();
|
||||
}
|
||||
private static final class ReflectionRecordCreator implements I_RecordCreator {
|
||||
private static final class ReflectionConstructorRecordCreator implements I_RecordCreator {
|
||||
|
||||
private final Constructor<? extends Record> _c;
|
||||
public ReflectionRecordCreator(Constructor<? extends Record> c) {
|
||||
public ReflectionConstructorRecordCreator(Constructor<? extends Record> c) {
|
||||
_c = c;
|
||||
}
|
||||
public Record create(RecordInputStream in) {
|
||||
@ -68,6 +69,33 @@ public final class RecordFactory {
|
||||
return _c.getDeclaringClass();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A "create" method is used instead of the usual constructor if the created record might
|
||||
* be of a different class to the declaring class.
|
||||
*/
|
||||
private static final class ReflectionMethodRecordCreator implements I_RecordCreator {
|
||||
|
||||
private final Method _m;
|
||||
public ReflectionMethodRecordCreator(Method m) {
|
||||
_m = m;
|
||||
}
|
||||
public Record create(RecordInputStream in) {
|
||||
Object[] args = { in, };
|
||||
try {
|
||||
return (Record) _m.invoke(null, args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RecordFormatException("Unable to construct record instance" , e.getTargetException());
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<? extends Record> getRecordClass() {
|
||||
return (Class<? extends Record>) _m.getDeclaringClass();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final Class<?>[] CONSTRUCTOR_ARGS = { RecordInputStream.class, };
|
||||
@ -355,11 +383,9 @@ public final class RecordFactory {
|
||||
throw new RuntimeException("duplicate record class (" + recClass.getName() + ")");
|
||||
}
|
||||
|
||||
short sid;
|
||||
Constructor<? extends Record> constructor;
|
||||
int sid;
|
||||
try {
|
||||
sid = recClass.getField("sid").getShort(null);
|
||||
constructor = recClass.getConstructor(CONSTRUCTOR_ARGS);
|
||||
} catch (Exception illegalArgumentException) {
|
||||
throw new RecordFormatException(
|
||||
"Unable to determine record types");
|
||||
@ -370,12 +396,27 @@ public final class RecordFactory {
|
||||
throw new RuntimeException("duplicate record sid 0x" + Integer.toHexString(sid).toUpperCase()
|
||||
+ " for classes (" + recClass.getName() + ") and (" + prevClass.getName() + ")");
|
||||
}
|
||||
result.put(key, new ReflectionRecordCreator(constructor));
|
||||
result.put(key, getRecordCreator(recClass));
|
||||
}
|
||||
// result.put(Integer.valueOf(0x0406), result.get(Integer.valueOf(0x06)));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static I_RecordCreator getRecordCreator(Class<? extends Record> recClass) {
|
||||
try {
|
||||
Constructor<? extends Record> constructor;
|
||||
constructor = recClass.getConstructor(CONSTRUCTOR_ARGS);
|
||||
return new ReflectionConstructorRecordCreator(constructor);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// fall through and look for other construction methods
|
||||
}
|
||||
try {
|
||||
Method m = recClass.getDeclaredMethod("create", CONSTRUCTOR_ARGS);
|
||||
return new ReflectionMethodRecordCreator(m);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Failed to find constructor or create method for (" + recClass.getName() + ").");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create an array of records from an input stream
|
||||
*
|
||||
|
@ -62,6 +62,7 @@ public final class AllRecordTests {
|
||||
result.addTestSuite(TestFontRecord.class);
|
||||
result.addTestSuite(TestFormulaRecord.class);
|
||||
result.addTestSuite(TestHyperlinkRecord.class);
|
||||
result.addTestSuite(TestInterfaceEndRecord.class);
|
||||
result.addTestSuite(TestLabelRecord.class);
|
||||
result.addTestSuite(TestMergeCellsRecord.class);
|
||||
result.addTestSuite(TestNameRecord.class);
|
||||
|
@ -34,13 +34,14 @@ import java.io.ByteArrayInputStream;
|
||||
public final class TestInterfaceEndRecord extends TestCase {
|
||||
|
||||
public void testCreate() {
|
||||
InterfaceEndRecord record = new InterfaceEndRecord();
|
||||
InterfaceEndRecord record = InterfaceEndRecord.instance;
|
||||
assertEquals(0, record.getDataSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Silently swallow unexpected contents in InterfaceEndRecord.
|
||||
* Although it violates the spec, Excel silently reads such files.
|
||||
* Although it violates the spec, Excel silently converts this
|
||||
* data to an {@link InterfaceHdrRecord}.
|
||||
*/
|
||||
public void testUnexpectedBytes_bug47251(){
|
||||
String hex = "" +
|
||||
@ -50,7 +51,9 @@ public final class TestInterfaceEndRecord extends TestCase {
|
||||
byte[] data = HexRead.readFromString(hex);
|
||||
List<Record> records = RecordFactory.createRecords(new ByteArrayInputStream(data));
|
||||
assertEquals(3, records.size());
|
||||
InterfaceEndRecord r = (InterfaceEndRecord)records.get(1);
|
||||
assertEquals("[E2, 00, 02, 00, B0, 04]", HexDump.toHex(r.serialize()));
|
||||
Record rec1 = records.get(1);
|
||||
assertEquals(InterfaceHdrRecord.class, rec1.getClass());
|
||||
InterfaceHdrRecord r = (InterfaceHdrRecord)rec1;
|
||||
assertEquals("[E1, 00, 02, 00, B0, 04]", HexDump.toHex(r.serialize()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,15 +39,15 @@ import org.apache.poi.hssf.usermodel.SanityChecker.CheckRecord;
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
public final class TestSanityChecker extends TestCase {
|
||||
|
||||
private static final Record INTERFACEHDR = new InterfaceHdrRecord(InterfaceHdrRecord.CODEPAGE);
|
||||
private static BoundSheetRecord createBoundSheetRec() {
|
||||
return new BoundSheetRecord("Sheet1");
|
||||
}
|
||||
public void testCheckRecordOrder() {
|
||||
final SanityChecker c = new SanityChecker();
|
||||
List records = new ArrayList();
|
||||
List<Record> records = new ArrayList<Record>();
|
||||
records.add(new BOFRecord());
|
||||
records.add(new InterfaceHdrRecord());
|
||||
records.add(INTERFACEHDR);
|
||||
records.add(createBoundSheetRec());
|
||||
records.add(EOFRecord.instance);
|
||||
CheckRecord[] check = {
|
||||
@ -71,15 +71,15 @@ public final class TestSanityChecker extends TestCase {
|
||||
confirmBadRecordOrder(check, new Record[] {
|
||||
new BOFRecord(),
|
||||
createBoundSheetRec(),
|
||||
new InterfaceHdrRecord(),
|
||||
INTERFACEHDR,
|
||||
EOFRecord.instance,
|
||||
});
|
||||
|
||||
confirmBadRecordOrder(check, new Record[] {
|
||||
new BOFRecord(),
|
||||
new InterfaceHdrRecord(),
|
||||
INTERFACEHDR,
|
||||
createBoundSheetRec(),
|
||||
new InterfaceHdrRecord(),
|
||||
INTERFACEHDR,
|
||||
EOFRecord.instance,
|
||||
});
|
||||
|
||||
@ -92,19 +92,19 @@ public final class TestSanityChecker extends TestCase {
|
||||
});
|
||||
|
||||
confirmBadRecordOrder(check, new Record[] {
|
||||
new InterfaceHdrRecord(),
|
||||
INTERFACEHDR,
|
||||
createBoundSheetRec(),
|
||||
EOFRecord.instance,
|
||||
});
|
||||
|
||||
confirmBadRecordOrder(check, new Record[] {
|
||||
new BOFRecord(),
|
||||
new InterfaceHdrRecord(),
|
||||
INTERFACEHDR,
|
||||
EOFRecord.instance,
|
||||
});
|
||||
|
||||
confirmBadRecordOrder(check, new Record[] {
|
||||
new InterfaceHdrRecord(),
|
||||
INTERFACEHDR,
|
||||
createBoundSheetRec(),
|
||||
new BOFRecord(),
|
||||
EOFRecord.instance,
|
||||
@ -113,7 +113,7 @@ public final class TestSanityChecker extends TestCase {
|
||||
confirmBadRecordOrder(check, new Record[] {
|
||||
new BOFRecord(),
|
||||
createBoundSheetRec(),
|
||||
new InterfaceHdrRecord(),
|
||||
INTERFACEHDR,
|
||||
EOFRecord.instance,
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user