From: Josh Micich Date: Wed, 23 Dec 2009 04:35:37 +0000 (+0000) Subject: Simplified InterfaceHdrRecord and InterfaceEndRecord (some rework after bug 47251... X-Git-Tag: REL_3_7_BETA1~190 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8221d395851c8f4b208df0a72dad9a4813f16e88;p=poi.git 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 --- diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java index e0da764e6c..db8a813980 100644 --- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java +++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java @@ -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 { * --nointdo not output interpretation of BIFF records * --outsend output to <fileName>.out * --rawhexoutput raw hex dump of whole workbook stream - * --escherturn on deserialization of escher records (default is off) - * --noheaderdo not print record header (default is on) + * --escherturn on deserialization of escher records (default is off) + * --noheaderdo not print record header (default is on) * * */ 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 _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(); + _noHeader = noHeader; + _headers = new ArrayList(); } public void processRecord(int globalOffset, int recordCounter, int sid, int dataSize, diff --git a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java index 1a887eec6f..3c2a210acb 100644 --- a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java +++ b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java @@ -340,35 +340,35 @@ public final class InternalWorkbook { retval.records.setRecords(records); List 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 */ diff --git a/src/java/org/apache/poi/hssf/record/InterfaceEndRecord.java b/src/java/org/apache/poi/hssf/record/InterfaceEndRecord.java index 865906040b..44224a9c43 100644 --- a/src/java/org/apache/poi/hssf/record/InterfaceEndRecord.java +++ b/src/java/org/apache/poi/hssf/record/InterfaceEndRecord.java @@ -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)

@@ -28,50 +25,39 @@ import org.apache.poi.util.POILogFactory; * (has no fields)

* REFERENCE: PG 324 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @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; } } diff --git a/src/java/org/apache/poi/hssf/record/InterfaceHdrRecord.java b/src/java/org/apache/poi/hssf/record/InterfaceHdrRecord.java index cb4bbe842b..afd7705343 100644 --- a/src/java/org/apache/poi/hssf/record/InterfaceHdrRecord.java +++ b/src/java/org/apache/poi/hssf/record/InterfaceHdrRecord.java @@ -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

+ * Title: Interface Header Record (0x00E1)

* Description: Defines the beginning of Interface records (MMS)

* REFERENCE: PG 324 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @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(); - } - - /** - * 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 InterfaceHdrRecord(RecordInputStream in) { + _codepage = in.readShort(); } - 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; } } diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index 86f947b92d..6937c7dbe8 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -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 getRecordClass(); } - private static final class ReflectionRecordCreator implements I_RecordCreator { + private static final class ReflectionConstructorRecordCreator implements I_RecordCreator { private final Constructor _c; - public ReflectionRecordCreator(Constructor c) { + public ReflectionConstructorRecordCreator(Constructor 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 getRecordClass() { + return (Class) _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 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 recClass) { + try { + Constructor 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 * diff --git a/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java b/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java index d20940989f..6d913bb5df 100644 --- a/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java +++ b/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java @@ -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); diff --git a/src/testcases/org/apache/poi/hssf/record/TestInterfaceEndRecord.java b/src/testcases/org/apache/poi/hssf/record/TestInterfaceEndRecord.java index 9de79b3fdf..528f8e3644 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestInterfaceEndRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestInterfaceEndRecord.java @@ -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 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())); } -} \ No newline at end of file +} diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestSanityChecker.java b/src/testcases/org/apache/poi/hssf/usermodel/TestSanityChecker.java index 28a24a1a75..f5839fa83b 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestSanityChecker.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestSanityChecker.java @@ -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 records = new ArrayList(); 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, }); }