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) {
_sid = in.getSid();
_rawData = in.readRemainder();
if (false && getBiffName(_sid) == null) {
// unknown sids in the range 0x0004-0x0013 are probably 'sub-records' of ObjectRecord
// those sids are in a different number space.
// TODO - put unknown OBJ sub-records in a different class
System.out.println("Unknown record 0x" + Integer.toHexString(_sid).toUpperCase());
}
}
public UnknownRecord(RecordInputStream in) /**
{ * spit the record out AS IS. no interpretation or identification
sid = in.getSid(); */
thedata = in.readRemainder(); public final int serialize(int offset, byte[] data) {
LittleEndian.putUShort(data, 0 + offset, _sid);
int dataSize = _rawData.length;
LittleEndian.putUShort(data, 2 + offset, dataSize);
System.arraycopy(_rawData, 0, data, 4 + offset, dataSize);
return 4 + dataSize;
}
//System.out.println("UnknownRecord: 0x"+Integer.toHexString(sid)); public final int getRecordSize() {
} return 4 + _rawData.length;
}
/** /**
* spit the record out AS IS. no interpretation or identification * NO OP!
*/ */
public int serialize(int offset, byte [] data) protected void validateSid(short id) {
{ // if we had a valid sid we wouldn't be using the "Unknown Record" record now would we?
if (thedata == null) }
{
thedata = new byte[ 0 ];
}
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() /**
{ * print a sort of string representation ([UNKNOWN RECORD] id = x [/UNKNOWN RECORD])
int retval = 4; */
public final String toString() {
String biffName = getBiffName(_sid);
if (biffName == null) {
biffName = "UNKNOWNRECORD";
}
StringBuffer sb = new StringBuffer();
if (thedata != null) sb.append("[").append(biffName).append("] (0x");
{ sb.append(Integer.toHexString(_sid).toUpperCase() + ")\n");
retval += thedata.length; if (_rawData.length > 0) {
} sb.append(" rawData=").append(HexDump.toHex(_rawData)).append("\n");
return retval; }
} sb.append("[/").append(biffName).append("]\n");
return sb.toString();
}
protected void fillFields(byte [] data, short sid) public final short getSid() {
{ return (short) _sid;
this.sid = sid; }
thedata = data;
}
/** /**
* NO OP! * These BIFF record types are known but still uninterpreted by POI
*/ *
* @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 validateSid(short id) 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";
// if we had a valid sid we wouldn't be using the "Unknown Record" record now would we? case 0x01C0: return "EXCEL9FILE";
}
/** case 0x0802: return "QSISXTAG";
* print a sort of string representation ([UNKNOWN RECORD] id = x [/UNKNOWN RECORD]) case 0x0803: return "DBQUERYEXT";
*/ case 0x0805: return "TXTQUERY";
public String toString() case QUICKTIP_0800: return "QUICKTIP";
{ case 0x0850: return "CHARTFRTINFO";
StringBuffer buffer = new StringBuffer(); 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";
buffer.append("[UNKNOWN RECORD:" + Integer.toHexString(sid) + "]\n"); case 0x08C8: return "PLV{Mac Excel}";
buffer.append(" .id = ").append(Integer.toHexString(sid))
.append("\n");
buffer.append("[/UNKNOWN RECORD]\n");
return buffer.toString();
}
public short getSid() case 0x1051: return "SHAPEPROPSSTREAM";
{
return sid;
}
/** }
* called by the constructor, should set class level fields. Should throw if (isObservedButUnknown(sid)) {
* runtime exception for bad/icomplete data. return "UNKNOWN-" + Integer.toHexString(sid).toUpperCase();
* }
* @param in the RecordInputstream to read the record from
*/
protected void fillFields(RecordInputStream in) return null;
{ }
throw new RecordFormatException(
"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 Object clone() { *
UnknownRecord rec = new UnknownRecord(); * @return <code>true</code> if the unknown record id has been observed in POI unit tests
rec.sid = sid; */
rec.thedata = thedata; private static boolean isObservedButUnknown(int sid) {
return rec; 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(
"Unknown record cannot be constructed via offset -- we need a copy of the data");
}
public final Object clone() {
// immutable - ok to return this
return this;
}
} }

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;