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);
* <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);
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,
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;
return retval;
}
- private static InterfaceHdrRecord createInterfaceHdr() {
- InterfaceHdrRecord retval = new InterfaceHdrRecord();
-
- retval.setCodepage(CODEPAGE);
- return retval;
- }
private static MMSRecord createMMS() {
MMSRecord retval = new MMSRecord();
return retval;
}
- private static InterfaceEndRecord createInterfaceEnd() {
- return new InterfaceEndRecord();
- }
-
/**
* creates the WriteAccess record containing the logged in user's name
*/
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>
* (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;
}
}
-
/* ====================================================================
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;
}
}
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.*;
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) {
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, };
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");
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
*
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);
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 = "" +
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
+}
* @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 = {
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,
});
});
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,
confirmBadRecordOrder(check, new Record[] {
new BOFRecord(),
createBoundSheetRec(),
- new InterfaceHdrRecord(),
+ INTERFACEHDR,
EOFRecord.instance,
});
}