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:
Josh Micich 2009-12-23 04:35:37 +00:00
parent 56c40e3a0f
commit cc648a0fc0
8 changed files with 122 additions and 135 deletions

View 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,

View 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
*/

View 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;
}
}

View 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
@ -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;
}
}

View 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
*

View 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);

View 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()));
}
}
}

View 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,
});
}