added names of known but uniterpreted BIFF records

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@689559 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-08-27 18:51:03 +00:00
parent 32388d3d2d
commit afad417d66
3 changed files with 254 additions and 121 deletions

View File

@ -43,6 +43,7 @@ import org.apache.poi.hssf.record.SCLRecord;
import org.apache.poi.hssf.record.SaveRecalcRecord; import org.apache.poi.hssf.record.SaveRecalcRecord;
import org.apache.poi.hssf.record.SelectionRecord; import org.apache.poi.hssf.record.SelectionRecord;
import org.apache.poi.hssf.record.UncalcedRecord; import org.apache.poi.hssf.record.UncalcedRecord;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.WindowTwoRecord; import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable; import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
import org.apache.poi.hssf.record.aggregates.DataValidityTable; import org.apache.poi.hssf.record.aggregates.DataValidityTable;
@ -57,8 +58,6 @@ import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
* @author Josh Micich * @author Josh Micich
*/ */
final class RecordOrderer { final class RecordOrderer {
// TODO - add UninterpretedRecord as base class for many of these
// unimplemented sids
// TODO - simplify logic using a generalised record ordering // TODO - simplify logic using a generalised record ordering
@ -126,7 +125,7 @@ final class RecordOrderer {
case PrintGridlinesRecord.sid: case PrintGridlinesRecord.sid:
case GridsetRecord.sid: case GridsetRecord.sid:
case DefaultRowHeightRecord.sid: case DefaultRowHeightRecord.sid:
case 0x0081: // SHEETPR case UnknownRecord.SHEETPR_0081:
return true; return true;
// next is the 'Worksheet Protection Block' // next is the 'Worksheet Protection Block'
} }
@ -149,10 +148,10 @@ final class RecordOrderer {
case SCLRecord.sid: case SCLRecord.sid:
case PaneRecord.sid: case PaneRecord.sid:
case SelectionRecord.sid: case SelectionRecord.sid:
case 0x0099:// STANDARDWIDTH case UnknownRecord.STANDARDWIDTH_0099:
// MergedCellsTable usually here // MergedCellsTable usually here
case 0x015f:// LABELRANGES case UnknownRecord.LABELRANGES_015F:
case 0x00ef:// PHONETICPR case UnknownRecord.PHONETICPR_00EF:
return i + 1; return i + 1;
} }
} }
@ -168,7 +167,7 @@ final class RecordOrderer {
case SCLRecord.sid: case SCLRecord.sid:
case PaneRecord.sid: case PaneRecord.sid:
case SelectionRecord.sid: case SelectionRecord.sid:
case 0x0099:// STANDARDWIDTH case UnknownRecord.STANDARDWIDTH_0099:
return i + 1; return i + 1;
} }
} }
@ -229,16 +228,16 @@ final class RecordOrderer {
short sid = ((Record)rb).getSid(); short sid = ((Record)rb).getSid();
switch(sid) { switch(sid) {
case WindowTwoRecord.sid: case WindowTwoRecord.sid:
case 0x00A0: // SCL case UnknownRecord.SCL_00A0:
case PaneRecord.sid: case PaneRecord.sid:
case SelectionRecord.sid: case SelectionRecord.sid:
case 0x0099: // STANDARDWIDTH case UnknownRecord.STANDARDWIDTH_0099:
// MergedCellsTable // MergedCellsTable
case 0x015F: // LABELRANGES case UnknownRecord.LABELRANGES_015F:
case 0x00EF: // PHONETICPR case UnknownRecord.PHONETICPR_00EF:
// ConditionalFormattingTable // ConditionalFormattingTable
case HyperlinkRecord.sid: case HyperlinkRecord.sid:
case 0x0800: // QUICKTIP case UnknownRecord.QUICKTIP_0800:
return true; return true;
} }
return false; return false;
@ -246,9 +245,9 @@ final class RecordOrderer {
private static boolean isDVTSubsequentRecord(short sid) { private static boolean isDVTSubsequentRecord(short sid) {
switch(sid) { switch(sid) {
case 0x0862: // SHEETLAYOUT case UnknownRecord.SHEETEXT_0862:
case 0x0867: // SHEETPROTECTION case UnknownRecord.SHEETPROTECTION_0867:
case 0x0868: // RANGEPROTECTION case UnknownRecord.RANGEPROTECTION_0868:
case EOFRecord.sid: case EOFRecord.sid:
return true; return true;
} }

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -16,9 +15,9 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
/** /**
@ -31,125 +30,259 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
* @author Glen Stampoultzis (glens at apache.org) * @author Glen Stampoultzis (glens at apache.org)
*/ */
public final class UnknownRecord extends Record {
public class UnknownRecord /*
extends Record * Some Record IDs used by POI as 'milestones' in the record stream
{ */
private short sid = 0; public static final int PLS_004D = 0x004D;
private byte[] thedata = null; public static final int SHEETPR_0081 = 0x0081;
public static final int STANDARDWIDTH_0099 = 0x0099;
public static final int SCL_00A0 = 0x00A0;
public static final int BITMAP_00E9 = 0x00E9;
public static final int PHONETICPR_00EF = 0x00EF;
public static final int LABELRANGES_015F = 0x015F;
public static final int QUICKTIP_0800 = 0x0800;
public static final int SHEETEXT_0862 = 0x0862; // OOO calls this SHEETLAYOUT
public static final int SHEETPROTECTION_0867 = 0x0867;
public static final int RANGEPROTECTION_0868 = 0x0868;
public UnknownRecord() private int _sid;
{ private byte[] _rawData;
}
/** /**
* @param id id of the record -not validated, just stored for serialization * @param id id of the record -not validated, just stored for serialization
* @param data the data * @param data the data
*/ */
public UnknownRecord(short id, byte[] data) public UnknownRecord(int id, byte[] data) {
{ _sid = id & 0xFFFF;
this.sid = id; _rawData = data;
this.thedata = data;
} }
/** /**
* construct an unknown record. No fields are interperated and the record will * construct an unknown record. No fields are interpreted and the record will
* be serialized in its original form more or less * be serialized in its original form more or less
* @param in the RecordInputstream to read the record from * @param in the RecordInputstream to read the record from
*/ */
public UnknownRecord(RecordInputStream in) {
public UnknownRecord(RecordInputStream in) _sid = in.getSid();
{ _rawData = in.readRemainder();
sid = in.getSid(); if (false && getBiffName(_sid) == null) {
thedata = in.readRemainder(); // unknown sids in the range 0x0004-0x0013 are probably 'sub-records' of ObjectRecord
// those sids are in a different number space.
//System.out.println("UnknownRecord: 0x"+Integer.toHexString(sid)); // TODO - put unknown OBJ sub-records in a different class
System.out.println("Unknown record 0x" + Integer.toHexString(_sid).toUpperCase());
}
} }
/** /**
* spit the record out AS IS. no interpretation or identification * spit the record out AS IS. no interpretation or identification
*/ */
public int serialize(int offset, byte [] data) public final int serialize(int offset, byte[] data) {
{ LittleEndian.putUShort(data, 0 + offset, _sid);
if (thedata == null) int dataSize = _rawData.length;
{ LittleEndian.putUShort(data, 2 + offset, dataSize);
thedata = new byte[ 0 ]; System.arraycopy(_rawData, 0, data, 4 + offset, dataSize);
} return 4 + dataSize;
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, ( short ) (thedata.length));
if (thedata.length > 0)
{
System.arraycopy(thedata, 0, data, 4 + offset, thedata.length);
}
return getRecordSize();
} }
public int getRecordSize() public final int getRecordSize() {
{ return 4 + _rawData.length;
int retval = 4;
if (thedata != null)
{
retval += thedata.length;
}
return retval;
}
protected void fillFields(byte [] data, short sid)
{
this.sid = sid;
thedata = data;
} }
/** /**
* NO OP! * NO OP!
*/ */
protected void validateSid(short id) {
protected void validateSid(short id)
{
// if we had a valid sid we wouldn't be using the "Unknown Record" record now would we? // if we had a valid sid we wouldn't be using the "Unknown Record" record now would we?
} }
/** /**
* print a sort of string representation ([UNKNOWN RECORD] id = x [/UNKNOWN RECORD]) * print a sort of string representation ([UNKNOWN RECORD] id = x [/UNKNOWN RECORD])
*/ */
public final String toString() {
String biffName = getBiffName(_sid);
if (biffName == null) {
biffName = "UNKNOWNRECORD";
}
StringBuffer sb = new StringBuffer();
public String toString() sb.append("[").append(biffName).append("] (0x");
{ sb.append(Integer.toHexString(_sid).toUpperCase() + ")\n");
StringBuffer buffer = new StringBuffer(); if (_rawData.length > 0) {
sb.append(" rawData=").append(HexDump.toHex(_rawData)).append("\n");
buffer.append("[UNKNOWN RECORD:" + Integer.toHexString(sid) + "]\n"); }
buffer.append(" .id = ").append(Integer.toHexString(sid)) sb.append("[/").append(biffName).append("]\n");
.append("\n"); return sb.toString();
buffer.append("[/UNKNOWN RECORD]\n");
return buffer.toString();
} }
public short getSid() public final short getSid() {
{ return (short) _sid;
return sid;
} }
/** /**
* called by the constructor, should set class level fields. Should throw * These BIFF record types are known but still uninterpreted by POI
* runtime exception for bad/icomplete data.
* *
* @param in the RecordInputstream to read the record from * @return the documented name of this BIFF record type
*/ */
private static String getBiffName(int sid) {
// Note to POI developers:
// Make sure you delete the corresponding entry from
// this method any time a new Record subclass is created.
switch (sid) {
case PLS_004D: return "PLS";
case 0x0050: return "DCON";
case 0x007F: return "IMDATA";
case SHEETPR_0081: return "SHEETPR";
case 0x0090: return "SORT";
case 0x0094: return "LHRECORD";
case STANDARDWIDTH_0099: return "STANDARDWIDTH";
case 0x009D: return "AUTOFILTERINFO";
case SCL_00A0: return "SCL";
case 0x00AE: return "SCENMAN";
case 0x00D3: return "OBPROJ";
case 0x00DC: return "PARAMQRY";
case 0x00DE: return "OLESIZE";
case BITMAP_00E9: return "BITMAP";
case PHONETICPR_00EF: return "PHONETICPR";
protected void fillFields(RecordInputStream in) case LABELRANGES_015F: return "LABELRANGES";
{ case 0x01BA: return "CODENAME";
case 0x01A9: return "USERBVIEW";
case 0x01AA: return "USERSVIEWBEGIN";
case 0x01AB: return "USERSVIEWEND";
case 0x01AD: return "QSI";
case 0x01C0: return "EXCEL9FILE";
case 0x0802: return "QSISXTAG";
case 0x0803: return "DBQUERYEXT";
case 0x0805: return "TXTQUERY";
case QUICKTIP_0800: return "QUICKTIP";
case 0x0850: return "CHARTFRTINFO";
case 0x0852: return "STARTBLOCK";
case 0x0853: return "ENDBLOCK";
case 0x0856: return "CATLAB";
case SHEETEXT_0862: return "SHEETEXT";
case 0x0863: return "BOOKEXT";
case SHEETPROTECTION_0867: return "SHEETPROTECTION";
case RANGEPROTECTION_0868: return "RANGEPROTECTION";
case 0x086B: return "DATALABEXTCONTENTS";
case 0x086C: return "CELLWATCH";
case 0x0874: return "DROPDOWNOBJIDS";
case 0x0876: return "DCONN";
case 0x087B: return "CFEX";
case 0x087C: return "XFCRC";
case 0x087D: return "XFEXT";
case 0x088B: return "PLV";
case 0x088C: return "COMPAT12";
case 0x088D: return "DXF";
case 0x088E: return "TABLESTYLES";
case 0x0892: return "STYLEEXT";
case 0x0896: return "THEME";
case 0x0897: return "GUIDTYPELIB";
case 0x089A: return "MTRSETTINGS";
case 0x089B: return "COMPRESSPICTURES";
case 0x089C: return "HEADERFOOTER";
case 0x08A3: return "FORCEFULLCALCULATION";
case 0x08A4: return "SHAPEPROPSSTREAM";
case 0x08A5: return "TEXTPROPSSTREAM";
case 0x08A6: return "RICHTEXTSTREAM";
case 0x08C8: return "PLV{Mac Excel}";
case 0x1051: return "SHAPEPROPSSTREAM";
}
if (isObservedButUnknown(sid)) {
return "UNKNOWN-" + Integer.toHexString(sid).toUpperCase();
}
return null;
}
/**
*
* @return <code>true</code> if the unknown record id has been observed in POI unit tests
*/
private static boolean isObservedButUnknown(int sid) {
switch (sid) {
case 0x0033:
// contains 2 bytes of data: 0x0001 or 0x0003
case 0x0034:
// Seems to be written by MSAccess
// contains text "[Microsoft JET Created Table]0021010"
// appears after last cell value record and before WINDOW2
case 0x01BD:
case 0x01C2:
// Written by Excel 2007
// rawData is multiple of 12 bytes long
// appears after last cell value record and before WINDOW2 or drawing records
case 0x089D:
case 0x089E:
case 0x08A7:
case 0x1001:
case 0x1006:
case 0x1007:
case 0x1009:
case 0x100A:
case 0x100B:
case 0x100C:
case 0x1014:
case 0x1017:
case 0x1018:
case 0x1019:
case 0x101A:
case 0x101B:
case 0x101D:
case 0x101E:
case 0x101F:
case 0x1020:
case 0x1021:
case 0x1022:
case 0x1024:
case 0x1025:
case 0x1026:
case 0x1027:
case 0x1032:
case 0x1033:
case 0x1034:
case 0x1035:
case 0x103A:
case 0x1041:
case 0x1043:
case 0x1044:
case 0x1045:
case 0x1046:
case 0x104A:
case 0x104B:
case 0x104E:
case 0x104F:
case 0x1051:
case 0x105C:
case 0x105D:
case 0x105F:
case 0x1060:
case 0x1062:
case 0x1063:
case 0x1064:
case 0x1065:
case 0x1066:
return true;
}
return false;
}
protected final void fillFields(RecordInputStream in) {
throw new RecordFormatException( throw new RecordFormatException(
"Unknown record cannot be constructed via offset -- we need a copy of the data"); "Unknown record cannot be constructed via offset -- we need a copy of the data");
} }
/** Unlike the other Record.clone methods this is a shallow clone*/ public final Object clone() {
public Object clone() { // immutable - ok to return this
UnknownRecord rec = new UnknownRecord(); return this;
rec.sid = sid;
rec.thedata = thedata;
return rec;
} }
} }

View File

@ -35,6 +35,7 @@ import org.apache.poi.hssf.record.PrintSetupRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RightMarginRecord; import org.apache.poi.hssf.record.RightMarginRecord;
import org.apache.poi.hssf.record.TopMarginRecord; import org.apache.poi.hssf.record.TopMarginRecord;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.VCenterRecord; import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.VerticalPageBreakRecord; import org.apache.poi.hssf.record.VerticalPageBreakRecord;
@ -99,9 +100,9 @@ public final class PageSettingsBlock extends RecordAggregate {
case RightMarginRecord.sid: case RightMarginRecord.sid:
case TopMarginRecord.sid: case TopMarginRecord.sid:
case BottomMarginRecord.sid: case BottomMarginRecord.sid:
case 0x004D: // PLS case UnknownRecord.PLS_004D:
case PrintSetupRecord.sid: case PrintSetupRecord.sid:
case 0x00E9: // BITMAP case UnknownRecord.BITMAP_00E9:
return true; return true;
} }
return false; return false;