]> source.dussan.org Git - poi.git/commitdiff
Simplified InterfaceHdrRecord and InterfaceEndRecord (some rework after bug 47251...
authorJosh Micich <josh@apache.org>
Wed, 23 Dec 2009 04:35:37 +0000 (04:35 +0000)
committerJosh Micich <josh@apache.org>
Wed, 23 Dec 2009 04:35:37 +0000 (04:35 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@893402 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/dev/BiffViewer.java
src/java/org/apache/poi/hssf/model/InternalWorkbook.java
src/java/org/apache/poi/hssf/record/InterfaceEndRecord.java
src/java/org/apache/poi/hssf/record/InterfaceHdrRecord.java
src/java/org/apache/poi/hssf/record/RecordFactory.java
src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
src/testcases/org/apache/poi/hssf/record/TestInterfaceEndRecord.java
src/testcases/org/apache/poi/hssf/usermodel/TestSanityChecker.java

index e0da764e6c563ab16643120ea523151602a8a0d9..db8a813980f94266bff421354513d321cc8202eb 100644 (file)
@@ -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 &lt;fileName&gt;.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,
index 1a887eec6fd6aeaae8ccb5fbecb274acd35ef469..3c2a210acbe97848d233cb261806849ce50ab5c8 100644 (file)
@@ -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
      */
index 865906040b8c6922179db0ac83da9f92d53db7fa..44224a9c43be351c8e8db93069af1a7b8ba9cbee 100644 (file)
@@ -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;
     }
 }
index cb4bbe842b22e836250dbc022c508593fe4daf72..afd7705343970f2440d25a0bda929b92f129ccc0 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    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();
-    }
-
-    /**
-     * 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;
     }
 }
index 86f947b92df5a2746bc7d36aa326f05ed24433f7..6937c7dbe88bb38d84d65be51e3ca933fe8d1b0d 100644 (file)
@@ -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
         *
index d20940989f30653e13fae0d24a9e85d04f7e8743..6d913bb5dfee3f790893b3b284ddd0ff007f101d 100644 (file)
@@ -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);
index 9de79b3fdfbe268c19120b964017d55477fe1cbf..528f8e3644bb2fbb76127f8147e00fa94a742728 100644 (file)
@@ -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()));
     }
-}
\ No newline at end of file
+}
index 28a24a1a75ee276305c2f374365673ebdafe1d65..f5839fa83b47b6dc3de1f26790a76a52a7d661fc 100644 (file)
@@ -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,
                });
        }