]> source.dussan.org Git - poi.git/commitdiff
Added names of known but uninterpreted BIFF records
authorJosh Micich <josh@apache.org>
Wed, 27 Aug 2008 18:51:03 +0000 (18:51 +0000)
committerJosh Micich <josh@apache.org>
Wed, 27 Aug 2008 18:51:03 +0000 (18:51 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@689559 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/model/RecordOrderer.java
src/java/org/apache/poi/hssf/record/UnknownRecord.java
src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java

index 887497a911192abb5c3f598731e6dd569af302ab..e30e0a2a6e97ded53f937a1029d551bcfffbfdd7 100644 (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.SelectionRecord;
 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.aggregates.ConditionalFormattingTable;
 import org.apache.poi.hssf.record.aggregates.DataValidityTable;
@@ -57,8 +58,6 @@ import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
  * @author Josh Micich
  */
 final class RecordOrderer {
-       // TODO - add UninterpretedRecord as base class for many of these
-       // unimplemented sids
        
        // TODO - simplify logic using a generalised record ordering
 
@@ -126,7 +125,7 @@ final class RecordOrderer {
                                case PrintGridlinesRecord.sid:
                                case GridsetRecord.sid:
                                case DefaultRowHeightRecord.sid:
-                               case 0x0081: // SHEETPR
+                               case UnknownRecord.SHEETPR_0081:
                                        return true;
                                // next is the 'Worksheet Protection Block'
                        }
@@ -149,10 +148,10 @@ final class RecordOrderer {
                                case SCLRecord.sid:
                                case PaneRecord.sid:
                                case SelectionRecord.sid:
-                               case 0x0099:// STANDARDWIDTH
+                               case UnknownRecord.STANDARDWIDTH_0099:
                                // MergedCellsTable usually here 
-                               case 0x015f:// LABELRANGES
-                               case 0x00ef:// PHONETICPR
+                               case UnknownRecord.LABELRANGES_015F:
+                               case UnknownRecord.PHONETICPR_00EF:
                                        return i + 1;
                        }
                }
@@ -168,7 +167,7 @@ final class RecordOrderer {
                                case SCLRecord.sid:
                                case PaneRecord.sid:
                                case SelectionRecord.sid:
-                               case 0x0099:// STANDARDWIDTH
+                               case UnknownRecord.STANDARDWIDTH_0099:
                                        return i + 1;
                        }
                }
@@ -229,16 +228,16 @@ final class RecordOrderer {
                short sid = ((Record)rb).getSid();
                switch(sid) {
                        case WindowTwoRecord.sid:
-                       case 0x00A0: // SCL
+                       case UnknownRecord.SCL_00A0:
                        case PaneRecord.sid:
                        case SelectionRecord.sid:
-                       case 0x0099: // STANDARDWIDTH
+                       case UnknownRecord.STANDARDWIDTH_0099:
                        // MergedCellsTable
-                       case 0x015F: // LABELRANGES
-                       case 0x00EF: // PHONETICPR
+                       case UnknownRecord.LABELRANGES_015F:
+                       case UnknownRecord.PHONETICPR_00EF:
                        // ConditionalFormattingTable
                        case HyperlinkRecord.sid:
-                       case 0x0800: // QUICKTIP
+                       case UnknownRecord.QUICKTIP_0800:
                                return true;
                }
                return false;
@@ -246,9 +245,9 @@ final class RecordOrderer {
 
        private static boolean isDVTSubsequentRecord(short sid) {
                switch(sid) {
-                       case 0x0862: // SHEETLAYOUT
-                       case 0x0867: // SHEETPROTECTION
-                       case 0x0868: // RANGEPROTECTION
+                       case UnknownRecord.SHEETEXT_0862:
+                       case UnknownRecord.SHEETPROTECTION_0867:
+                       case UnknownRecord.RANGEPROTECTION_0868:
                        case EOFRecord.sid:
                                return true;
                }
index d3e76a020f0ec49ec730d76e094d9c555f5ede79..851dbfbf55d339ac3eb8e72921c899f1ec633294 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.LittleEndian;
 
 /**
@@ -31,125 +30,259 @@ import org.apache.poi.util.LittleEndian;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @author Glen Stampoultzis (glens at apache.org)
  */
+public final class UnknownRecord extends Record {
+
+       /*
+        * Some Record IDs used by POI as 'milestones' in the record stream
+        */
+       public static final int PLS_004D             = 0x004D;
+       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;
+       
+       private int _sid;
+       private byte[] _rawData;
+
+       /**
+        * @param id    id of the record -not validated, just stored for serialization
+        * @param data  the data
+        */
+       public UnknownRecord(int id, byte[] data) {
+         _sid = id & 0xFFFF;
+         _rawData = data;
+       }
+
+
+       /**
+        * construct an unknown record.  No fields are interpreted and the record will
+        * be serialized in its original form more or less
+        * @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());
+               }
+       }
+
+       /**
+        * spit the record out AS IS. no interpretation or identification
+        */
+       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;
+       }
+
+       public final int getRecordSize() {
+               return 4 + _rawData.length;
+       }
+
+       /**
+        * NO OP!
+        */
+       protected void validateSid(short id) {
+               // 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])
+        */
+       public final String toString() {
+               String biffName = getBiffName(_sid);
+               if (biffName == null) {
+                       biffName = "UNKNOWNRECORD";
+               }
+               StringBuffer sb = new StringBuffer();
+
+               sb.append("[").append(biffName).append("] (0x");
+               sb.append(Integer.toHexString(_sid).toUpperCase() + ")\n");
+               if (_rawData.length > 0) {
+                       sb.append("  rawData=").append(HexDump.toHex(_rawData)).append("\n");
+               }
+               sb.append("[/").append(biffName).append("]\n");
+               return sb.toString();
+       }
+
+       public final short getSid() {
+               return (short) _sid;
+       }
+
+       /**
+        * 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";
+
+                       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(
+                               "Unknown record cannot be constructed via offset -- we need a copy of the data");
+       }
 
-public class UnknownRecord
-    extends Record
-{
-    private short   sid     = 0;
-    private byte[]  thedata = null;
-
-    public UnknownRecord()
-    {
-    }
-
-    /**
-     * @param id    id of the record -not validated, just stored for serialization
-     * @param data  the data
-     */
-    public UnknownRecord(short id, byte[] data)
-    {
-      this.sid = id;
-      this.thedata = data;
-    }
-
-
-    /**
-     * construct an unknown record.  No fields are interperated and the record will
-     * be serialized in its original form more or less
-     * @param in the RecordInputstream to read the record from
-     */
-
-    public UnknownRecord(RecordInputStream in)
-    {
-        sid     = in.getSid();
-        thedata = in.readRemainder();
-        
-        //System.out.println("UnknownRecord: 0x"+Integer.toHexString(sid));
-    }
-
-    /**
-     * spit the record out AS IS.  no interpretation or identification
-     */
-    public int serialize(int offset, byte [] data)
-    {
-        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()
-    {
-        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!
-     */
-
-    protected void validateSid(short id)
-    {
-
-        // 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])
-     */
-
-    public String toString()
-    {
-        StringBuffer buffer = new StringBuffer();
-
-        buffer.append("[UNKNOWN RECORD:" + Integer.toHexString(sid) + "]\n");
-        buffer.append("    .id        = ").append(Integer.toHexString(sid))
-            .append("\n");
-        buffer.append("[/UNKNOWN RECORD]\n");
-        return buffer.toString();
-    }
-
-    public short getSid()
-    {
-        return sid;
-    }
-
-    /**
-     * called by the constructor, should set class level fields.  Should throw
-     * runtime exception for bad/icomplete data.
-     *
-     * @param in the RecordInputstream to read the record from
-     */
-
-    protected void fillFields(RecordInputStream in)
-    {
-        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();
-      rec.sid = sid;
-      rec.thedata = thedata;
-      return rec;
-    }
+       public final Object clone() {
+               // immutable - ok to return this
+               return this;
+       }
 }
index cc8be417911cea7faa3680d483f623d4b7d176ee..819940e12e1988150a30042a5ad9bb19ff464e5d 100644 (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.RightMarginRecord;
 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.VerticalPageBreakRecord;
 
@@ -99,9 +100,9 @@ public final class PageSettingsBlock extends RecordAggregate {
                        case RightMarginRecord.sid:
                        case TopMarginRecord.sid:
                        case BottomMarginRecord.sid:
-                       case 0x004D: // PLS
+                       case UnknownRecord.PLS_004D:
                        case PrintSetupRecord.sid:
-                       case 0x00E9: // BITMAP
+                       case UnknownRecord.BITMAP_00E9:
                                return true;
                }
                return false;