]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-63924...
authorNick Burch <nick@apache.org>
Thu, 28 Aug 2008 13:26:12 +0000 (13:26 +0000)
committerNick Burch <nick@apache.org>
Thu, 28 Aug 2008 13:26:12 +0000 (13:26 +0000)
https://svn.apache.org/repos/asf/poi/trunk

........
  r689544 | josh | 2008-08-27 19:13:46 +0100 (Wed, 27 Aug 2008) | 1 line

  Fixed size of TblPtg
........
  r689559 | josh | 2008-08-27 19:51:03 +0100 (Wed, 27 Aug 2008) | 1 line

  added names of known but uniterpreted BIFF records
........
  r689636 | josh | 2008-08-27 22:54:20 +0100 (Wed, 27 Aug 2008) | 1 line

  should have been submitted with c689559
........
  r689704 | josh | 2008-08-28 03:54:47 +0100 (Thu, 28 Aug 2008) | 1 line

  Fix for bug 45698 - allow LinkTable to read EXTERNSHEET records
........
  r689716 | josh | 2008-08-28 05:27:41 +0100 (Thu, 28 Aug 2008) | 1 line

  Fix for bug 45699 - RowRecordsAggregate needs to tolerate MergeCellsRecords between row/cell records
........
  r689719 | josh | 2008-08-28 06:13:31 +0100 (Thu, 28 Aug 2008) | 1 line

  Should have been submitted with c689716 (bug 45699)
........
  r689721 | josh | 2008-08-28 06:25:24 +0100 (Thu, 28 Aug 2008) | 1 line

  Removed unused methods from CellValueRecordInterface. Converted FormulaRecordAggregate to RecordAggregate subclass
........

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@689811 13f79535-47bb-0310-9956-ffa450edef68

28 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/model/LinkTable.java
src/java/org/apache/poi/hssf/model/RecordOrderer.java
src/java/org/apache/poi/hssf/model/Sheet.java
src/java/org/apache/poi/hssf/record/BlankRecord.java
src/java/org/apache/poi/hssf/record/BoolErrRecord.java
src/java/org/apache/poi/hssf/record/CellValueRecordInterface.java
src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
src/java/org/apache/poi/hssf/record/FormulaRecord.java
src/java/org/apache/poi/hssf/record/LabelRecord.java
src/java/org/apache/poi/hssf/record/LabelSSTRecord.java
src/java/org/apache/poi/hssf/record/NumberRecord.java
src/java/org/apache/poi/hssf/record/RKRecord.java
src/java/org/apache/poi/hssf/record/UnknownRecord.java
src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
src/java/org/apache/poi/hssf/record/aggregates/SharedFormulaHolder.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
src/java/org/apache/poi/hssf/record/formula/TblPtg.java
src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
src/testcases/org/apache/poi/hssf/data/ex45698-22488.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/model/TestSheet.java
src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java
src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java

index bfc44a828f2045f12c328a84409e6f88b4fa1237..3d49ffca0ccfcecab58f9f43f960a5af6df04cf3 100644 (file)
@@ -64,6 +64,8 @@
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
         </release>
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45699 - Fix RowRecordsAggregate to tolerate intervening MERGEDCELLS records</action>
+           <action dev="POI-DEVELOPERS" type="fix">45698 - Fix LinkTable to tolerate multiple EXTERNSHEET records</action>
            <action dev="POI-DEVELOPERS" type="fix">45682 - Fix for cloning of CFRecordsAggregate</action>
            <action dev="POI-DEVELOPERS" type="add">Initial support for evaluating external add-in functions like YEARFRAC</action>
            <action dev="POI-DEVELOPERS" type="fix">45672 - Fix for MissingRecordAwareHSSFListener to prevent multiple LastCellOfRowDummyRecords when shared formulas are present</action>
index 5ed54a515b910ef0b4b823b9bbdb5fcd6f2c4d90..05475a52eeb2112816191f4e0ff8f24b0a820401 100644 (file)
@@ -61,6 +61,8 @@
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
         </release>
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45699 - Fix RowRecordsAggregate to tolerate intervening MERGEDCELLS records</action>
+           <action dev="POI-DEVELOPERS" type="fix">45698 - Fix LinkTable to tolerate multiple EXTERNSHEET records</action>
            <action dev="POI-DEVELOPERS" type="fix">45682 - Fix for cloning of CFRecordsAggregate</action>
            <action dev="POI-DEVELOPERS" type="add">Initial support for evaluating external add-in functions like YEARFRAC</action>
            <action dev="POI-DEVELOPERS" type="fix">45672 - Fix for MissingRecordAwareHSSFListener to prevent multiple LastCellOfRowDummyRecords when shared formulas are present</action>
index 9d1707558d63792de794dadbbf2f3c0e17d05211..a64f134fed9ffab831eeebd1b0b10a402c55c334 100755 (executable)
@@ -159,8 +159,7 @@ final class LinkTable {
                
                if (_externalBookBlocks.length > 0) {
                        // If any ExternalBookBlock present, there is always 1 of ExternSheetRecord
-                       Record next = rs.getNext();
-                       _externSheetRecord = (ExternSheetRecord) next;
+                       _externSheetRecord = readExtSheetRecord(rs);
                } else {
                        _externSheetRecord = null;
                }
@@ -176,6 +175,28 @@ final class LinkTable {
                _workbookRecordList.getRecords().addAll(inputList.subList(startIndex, startIndex + _recordCount));
        }
 
+       private static ExternSheetRecord readExtSheetRecord(RecordStream rs) {
+               List temp = new ArrayList(2);
+               while(rs.peekNextClass() == ExternSheetRecord.class) {
+                       temp.add(rs.getNext());
+               }
+               
+               int nItems = temp.size();
+               if (nItems < 1) {
+                       throw new RuntimeException("Expected an EXTERNSHEET record but got (" 
+                                       + rs.peekNextClass().getName() + ")");
+               }
+               if (nItems == 1) {
+                       // this is the normal case. There should be just one ExternSheetRecord
+                       return (ExternSheetRecord) temp.get(0);
+               }
+               // Some apps generate multiple ExternSheetRecords (see bug 45698).
+               // It seems like the best thing to do might be to combine these into one
+               ExternSheetRecord[] esrs = new ExternSheetRecord[nItems];
+               temp.toArray(esrs);
+               return ExternSheetRecord.combine(esrs);
+       }
+
        public LinkTable(short numberOfSheets, WorkbookRecordList workbookRecordList) {
                _workbookRecordList = workbookRecordList;
                _definedNames = new ArrayList();
index 887497a911192abb5c3f598731e6dd569af302ab..291bd077150283bdeb2efdee1fd50ae7ee0dae4c 100644 (file)
@@ -22,16 +22,20 @@ import java.util.List;
 import org.apache.poi.hssf.record.BOFRecord;
 import org.apache.poi.hssf.record.CalcCountRecord;
 import org.apache.poi.hssf.record.CalcModeRecord;
+import org.apache.poi.hssf.record.DVALRecord;
 import org.apache.poi.hssf.record.DateWindow1904Record;
 import org.apache.poi.hssf.record.DefaultRowHeightRecord;
 import org.apache.poi.hssf.record.DeltaRecord;
 import org.apache.poi.hssf.record.DimensionsRecord;
+import org.apache.poi.hssf.record.DrawingRecord;
+import org.apache.poi.hssf.record.DrawingSelectionRecord;
 import org.apache.poi.hssf.record.EOFRecord;
 import org.apache.poi.hssf.record.GridsetRecord;
 import org.apache.poi.hssf.record.GutsRecord;
 import org.apache.poi.hssf.record.HyperlinkRecord;
 import org.apache.poi.hssf.record.IndexRecord;
 import org.apache.poi.hssf.record.IterationRecord;
+import org.apache.poi.hssf.record.ObjRecord;
 import org.apache.poi.hssf.record.PaneRecord;
 import org.apache.poi.hssf.record.PrecisionRecord;
 import org.apache.poi.hssf.record.PrintGridlinesRecord;
@@ -42,7 +46,10 @@ import org.apache.poi.hssf.record.RefModeRecord;
 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.TextObjectRecord;
 import org.apache.poi.hssf.record.UncalcedRecord;
+import org.apache.poi.hssf.record.UnknownRecord;
+import org.apache.poi.hssf.record.WindowOneRecord;
 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 +64,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 +131,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 +154,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;
                        }
                }
@@ -162,13 +167,20 @@ final class RecordOrderer {
        private static int findInsertPosForNewMergedRecordTable(List records) {
                for (int i = records.size() - 2; i >= 0; i--) { // -2 to skip EOF record
                        Object rb = records.get(i);
+                       if (!(rb instanceof Record)) {
+                               // DataValidityTable, ConditionalFormattingTable, 
+                               // even PageSettingsBlock (which doesn't normally appear after 'View Settings')
+                               continue; 
+                       }
                        Record rec = (Record) rb;
                        switch (rec.getSid()) {
+                               // 'View Settings' (4 records) 
                                case WindowTwoRecord.sid:
                                case SCLRecord.sid:
                                case PaneRecord.sid:
                                case SelectionRecord.sid:
-                               case 0x0099:// STANDARDWIDTH
+
+                               case UnknownRecord.STANDARDWIDTH_0099:
                                        return i + 1;
                        }
                }
@@ -229,16 +241,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 +258,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;
                }
@@ -307,4 +319,29 @@ final class RecordOrderer {
                }
                return false;
        }
+       /**
+        * @return <code>true</code> if the specified record ID terminates a sequence of Row block records
+        * It is assumed that at least one row or cell value record has been found prior to the current 
+        * record
+        */
+       public static boolean isEndOfRowBlock(short sid) {
+               switch(sid) {
+                       case DrawingRecord.sid:
+                       case DrawingSelectionRecord.sid:
+                       case ObjRecord.sid:
+                       case TextObjectRecord.sid:
+
+                       case WindowOneRecord.sid:
+                               // should really be part of workbook stream, but some apps seem to put this before WINDOW2
+                       case WindowTwoRecord.sid:
+                               return true;
+
+                       case DVALRecord.sid:
+                               return true;
+                       case EOFRecord.sid: 
+                               // WINDOW2 should always be present, so shouldn't have got this far
+                               throw new RuntimeException("Found EOFRecord before WindowTwoRecord was encountered");
+               }
+               return PageSettingsBlock.isComponentRecord(sid);
+       }
 }
index 336b1dbd46054d10d36c0a3aaf63fac06e867356..b5db343d8e7e23de47405628cc0be623bd7f6197 100644 (file)
@@ -122,7 +122,8 @@ public final class Sheet implements Model {
     
     protected WindowTwoRecord            windowTwo         =     null;
     protected SelectionRecord            selection         =     null;
-    private   MergedCellsTable           _mergedCellsTable;
+    /** java object always present, but if empty no BIFF records are written */
+    private final MergedCellsTable       _mergedCellsTable;
     /** always present in this POI object, not always written to Excel file */
     /*package*/ColumnInfoRecordsAggregate _columnInfos;
     /** the DimensionsRecord is always present */
@@ -146,8 +147,8 @@ public final class Sheet implements Model {
      * Creates new Sheet with no initialization --useless at this point
      * @see #createSheet(List,int,int)
      */
-    public Sheet()
-    {
+    public Sheet() {
+       _mergedCellsTable = new MergedCellsTable();
     }
 
     /**
@@ -158,7 +159,7 @@ public final class Sheet implements Model {
      * to the passed in records and references to those records held. This function
      * is normally called via Workbook.
      *
-     * @param recs array containing those records in the sheet in sequence (normally obtained from RecordFactory)
+     * @param inRecs array containing those records in the sheet in sequence (normally obtained from RecordFactory)
      * @param sheetnum integer specifying the sheet's number (0,1 or 2 in this release)
      * @param offset of the sheet's BOF record
      *
@@ -167,19 +168,19 @@ public final class Sheet implements Model {
      * @see org.apache.poi.hssf.model.Workbook
      * @see org.apache.poi.hssf.record.Record
      */
-    public static Sheet createSheet(List recs, int sheetnum, int offset)
+    public static Sheet createSheet(List inRecs, int sheetnum, int offset)
     {
         if (log.check( POILogger.DEBUG ))
             log.logFormatted(POILogger.DEBUG,
                     "Sheet createSheet (existing file) with %",
-                    new Integer(recs.size()));
+                    new Integer(inRecs.size()));
         Sheet     retval             = new Sheet();
-        ArrayList records            = new ArrayList(recs.size() / 5);
-        boolean   isfirstcell        = true;
-        int       bofEofNestingLevel = 0;
+        ArrayList records            = new ArrayList(inRecs.size() / 5);
+        // TODO - take chart streams off into separate java objects
+        int       bofEofNestingLevel = 0;  // nesting level can only get to 2 (when charts are present)
 
-        for (int k = offset; k < recs.size(); k++) {
-            Record rec = ( Record ) recs.get(k);
+        for (int k = offset; k < inRecs.size(); k++) {
+            Record rec = ( Record ) inRecs.get(k);
             if ( rec.getSid() == DBCellRecord.sid ) {
                 continue;
             }
@@ -193,7 +194,7 @@ public final class Sheet implements Model {
             }
             
             if ( rec.getSid() == CFHeaderRecord.sid ) {
-                RecordStream rs = new RecordStream(recs, k);
+                RecordStream rs = new RecordStream(inRecs, k);
                 retval.condFormatting = new ConditionalFormattingTable(rs);
                 k += rs.getCountRead()-1;
                 records.add(retval.condFormatting);
@@ -201,43 +202,34 @@ public final class Sheet implements Model {
             }
             
             if (rec.getSid() == ColumnInfoRecord.sid) {
-                RecordStream rs = new RecordStream(recs, k);
+                RecordStream rs = new RecordStream(inRecs, k);
                 retval._columnInfos = new ColumnInfoRecordsAggregate(rs);
                 k += rs.getCountRead()-1;
                 records.add(retval._columnInfos);
                 continue;
             }
             if ( rec.getSid() == DVALRecord.sid) {
-                RecordStream rs = new RecordStream(recs, k);
+                RecordStream rs = new RecordStream(inRecs, k);
                 retval._dataValidityTable = new DataValidityTable(rs);
                 k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based
                 records.add(retval._dataValidityTable);
                 continue;
             }
             // TODO construct RowRecordsAggregate from RecordStream
-            if ( rec.getSid() == RowRecord.sid ) {
-                RowRecord row = (RowRecord)rec;
-                if (retval._rowsAggregate == null) {
-                    retval._rowsAggregate = new RowRecordsAggregate();
-                    records.add(retval._rowsAggregate); //only add the aggregate once
+            if ((rec.getSid() == RowRecord.sid || rec.isValue()) && bofEofNestingLevel == 1 ) {
+                //only add the aggregate once
+                if (retval._rowsAggregate != null) {
+                    throw new RuntimeException("row/cell records found in the wrong place");
                 }
-                retval._rowsAggregate.insertRow(row);
+                int lastRowCellRec = findEndOfRowBlock(inRecs, k, retval._mergedCellsTable);
+                retval._rowsAggregate = new RowRecordsAggregate(inRecs, k, lastRowCellRec);
+                records.add(retval._rowsAggregate); //only add the aggregate once
+                k = lastRowCellRec -1;
                 continue;
             }
-            if ( rec.isValue() && bofEofNestingLevel == 1 ) {
-                if (isfirstcell) {
-                    isfirstcell = false;
-                    if (retval._rowsAggregate == null) {
-                        retval._rowsAggregate = new RowRecordsAggregate();
-                        records.add(retval._rowsAggregate); //only add the aggregate once
-                    }
-                    retval._rowsAggregate.constructCellValues( k, recs );
-                }
-               continue;
-            }
              
             if (PageSettingsBlock.isComponentRecord(rec.getSid())) {
-                RecordStream rs = new RecordStream(recs, k);
+                RecordStream rs = new RecordStream(inRecs, k);
                 PageSettingsBlock psb = new PageSettingsBlock(rs);
                 if (bofEofNestingLevel == 1) {
                     if (retval._psBlock == null) {
@@ -253,9 +245,10 @@ public final class Sheet implements Model {
             }
             
             if (rec.getSid() == MergeCellsRecord.sid) {
-                RecordStream rs = new RecordStream(recs, k);
-                retval._mergedCellsTable = new MergedCellsTable(rs);
-                records.add(retval._mergedCellsTable);
+               // when the MergedCellsTable is found in the right place, we expect those records to be contiguous
+                RecordStream rs = new RecordStream(inRecs, k);
+                retval._mergedCellsTable.read(rs);
+                k += rs.getCountRead()-1;
                 continue;
             }
             
@@ -337,6 +330,11 @@ public final class Sheet implements Model {
         if (retval._dimensions == null) {
             throw new RuntimeException("DimensionsRecord was not found");
         }
+        if (retval.windowTwo == null) {
+            throw new RuntimeException("WINDOW2 was not found");
+        }
+        // put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */
+        RecordOrderer.addNewSheetRecord(records, retval._mergedCellsTable);
         retval.records = records;
         retval.checkRows();
         if (log.check( POILogger.DEBUG ))
@@ -344,6 +342,26 @@ public final class Sheet implements Model {
         return retval;
     }
 
+    /**
+     * Also collects any rogue MergeCellRecords
+     * @return the index one after the last row/cell record
+     */
+    private static int findEndOfRowBlock(List recs, int startIx, MergedCellsTable mergedCellsTable) {
+        for(int i=startIx; i<recs.size(); i++) {
+            Record rec = (Record) recs.get(i);
+            if (RecordOrderer.isEndOfRowBlock(rec.getSid())) {
+                return i;
+            }
+            if (rec.getSid() == MergeCellsRecord.sid) {
+                    // Some apps scatter these records between the rows/cells but they are supposed to
+                    // be well after the row/cell records.  We collect them here 
+                    // see bug 45699
+                    mergedCellsTable.add((MergeCellsRecord) rec);
+            }
+        }
+        throw new RuntimeException("Failed to find end of row/cell records");
+    }
+
     private static final class RecordCloner implements RecordVisitor {
 
         private final List _destList;
@@ -447,9 +465,12 @@ public final class Sheet implements Model {
         retval._dimensions = createDimensions();
         records.add(retval._dimensions);
         retval.dimsloc = records.size()-1;
+        // 'Sheet View Settings'
         records.add(retval.windowTwo = retval.createWindowTwo());
         retval.selection = createSelection();
         records.add(retval.selection);
+
+        records.add(retval._mergedCellsTable); // MCT comes after 'Sheet View Settings' 
         records.add(EOFRecord.instance);
 
 
@@ -468,11 +489,7 @@ public final class Sheet implements Model {
         }
     }
     private MergedCellsTable getMergedRecords() {
-        if (_mergedCellsTable == null) {
-            MergedCellsTable mct = new MergedCellsTable();
-            RecordOrderer.addNewSheetRecord(records, mct);
-            _mergedCellsTable = mct;
-        }
+        // always present
         return _mergedCellsTable;
     }
 
@@ -872,7 +889,7 @@ public final class Sheet implements Model {
     /**
      * creates the BOF record
      */
-    private static BOFRecord createBOF() {
+    /* package */ static BOFRecord createBOF() {
         BOFRecord retval = new BOFRecord();
 
         retval.setVersion(( short ) 0x600);
index e4f04287611e61a780a6d6d937716701381bce88..bfb308bd589954fdb4829a57301ef63ae7c331b7 100644 (file)
@@ -34,13 +34,8 @@ import org.apache.poi.util.LittleEndian;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @version 2.0-pre
  */
-
-public class BlankRecord
-    extends Record
-    implements CellValueRecordInterface, Comparable
-{
+public final class BlankRecord extends Record implements CellValueRecordInterface {
     public final static short sid = 0x201;
-    //private short             field_1_row;
     private int             field_1_row;
     private short             field_2_col;
     private short             field_3_xf;
@@ -152,50 +147,6 @@ public class BlankRecord
         field_2_col = col;
     }
 
-    public boolean isBefore(CellValueRecordInterface i)
-    {
-        if (this.getRow() > i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() > i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isAfter(CellValueRecordInterface i)
-    {
-        if (this.getRow() < i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() < i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isEqual(CellValueRecordInterface i)
-    {
-        return ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()));
-    }
-
     public boolean isInValueSection()
     {
         return true;
@@ -254,50 +205,6 @@ public class BlankRecord
         return 10;
     }
 
-    public int compareTo(Object obj)
-    {
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return 0;
-        }
-        if (this.getRow() < loc.getRow())
-        {
-            return -1;
-        }
-        if (this.getRow() > loc.getRow())
-        {
-            return 1;
-        }
-        if (this.getColumn() < loc.getColumn())
-        {
-            return -1;
-        }
-        if (this.getColumn() > loc.getColumn())
-        {
-            return 1;
-        }
-        return -1;
-    }
-
-    public boolean equals(Object obj)
-    {
-        if (!(obj instanceof CellValueRecordInterface))
-        {
-            return false;
-        }
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return true;
-        }
-        return false;
-    }
-
     public Object clone() {
       BlankRecord rec = new BlankRecord();
       rec.field_1_row = field_1_row;
index f2b9d928ab47de0341728fa5d8f450fbd3f661cd..43bdda900c3fdb5f243d93822999df0fd220e1b9 100644 (file)
@@ -33,14 +33,9 @@ import org.apache.poi.util.LittleEndian;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @version 2.0-pre
  */
-
-public class BoolErrRecord
-    extends Record
-    implements CellValueRecordInterface, Comparable
-{
+public final class BoolErrRecord extends Record implements CellValueRecordInterface {
     public final static short sid = 0x205;
-    //private short             field_1_row;
-    private int             field_1_row;
+    private int               field_1_row;
     private short             field_2_column;
     private short             field_3_xf_index;
     private byte              field_4_bBoolErr;
@@ -273,50 +268,6 @@ public class BoolErrRecord
         return sid;
     }
 
-    public boolean isBefore(CellValueRecordInterface i)
-    {
-        if (this.getRow() > i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() > i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isAfter(CellValueRecordInterface i)
-    {
-        if (this.getRow() < i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() < i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isEqual(CellValueRecordInterface i)
-    {
-        return ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()));
-    }
-
     public boolean isInValueSection()
     {
         return true;
@@ -327,50 +278,6 @@ public class BoolErrRecord
         return true;
     }
 
-    public int compareTo(Object obj)
-    {
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return 0;
-        }
-        if (this.getRow() < loc.getRow())
-        {
-            return -1;
-        }
-        if (this.getRow() > loc.getRow())
-        {
-            return 1;
-        }
-        if (this.getColumn() < loc.getColumn())
-        {
-            return -1;
-        }
-        if (this.getColumn() > loc.getColumn())
-        {
-            return 1;
-        }
-        return -1;
-    }
-
-    public boolean equals(Object obj)
-    {
-        if (!(obj instanceof CellValueRecordInterface))
-        {
-            return false;
-        }
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return true;
-        }
-        return false;
-    }
-
     public Object clone() {
       BoolErrRecord rec = new BoolErrRecord();
       rec.field_1_row = field_1_row;
index 1cc6b7ae7950892b65c76ffdb9cc614a9d286fa7..4bbee79aecb13e9a2662918e7229348275b937e3 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.
 ==================================================================== */
-        
 
-/*
- * CellValueRecordInterface.java
- *
- * Created on October 2, 2001, 8:27 PM
- */
 package org.apache.poi.hssf.record;
 
 /**
@@ -36,73 +29,29 @@ package org.apache.poi.hssf.record;
  * @see org.apache.poi.hssf.record.Record
  * @see org.apache.poi.hssf.record.RecordFactory
  */
-
-public interface CellValueRecordInterface
-{
+public interface CellValueRecordInterface {
 
     /**
-     * get the row this cell occurs on
-     *
-     * @return the row
+     * @return the row this cell occurs on
      */
-
-    //public short getRow();
-    public int getRow();
+    int getRow();
 
     /**
-     * get the column this cell defines within the row
-     *
-     * @return the column
+     * @return the column this cell defines within the row
      */
-
-    public short getColumn();
+    short getColumn();
 
     /**
-     * set the row this cell occurs on
      * @param row the row this cell occurs within
      */
-
-    //public void setRow(short row);
-    public void setRow(int row);
+    void setRow(int row);
 
     /**
-     * set the column this cell defines within the row
-     *
      * @param col the column this cell defines
      */
+    void setColumn(short col);
 
-    public void setColumn(short col);
-
-    public void setXFIndex(short xf);
-
-    public short getXFIndex();
-
-    /**
-     * returns whether this cell is before the passed in cell
-     *
-     * @param i  another cell interface record to compare
-     * @return true if the cells is before, or false if not
-     */
-
-    public boolean isBefore(CellValueRecordInterface i);
-
-    /**
-     * returns whether this cell is after the passed in cell
-     *
-     * @param i  record to compare
-     * @return true if the cell is after, false if not
-     */
-
-    public boolean isAfter(CellValueRecordInterface i);
-
-    /**
-     * returns whether this cell represents the same cell (NOT VALUE)
-     *
-     * @param i  record to compare
-     * @return true if the cells are the same cell (positionally), false if not.
-     */
-
-    public boolean isEqual(CellValueRecordInterface i);
+    void setXFIndex(short xf);
 
-    public Object clone();
+    short getXFIndex();
 }
index 2b0744a91e3e7be67a728aaa24d12579fe7b60a5..c4f00581b2e13eb5be9373a2555a8da8ea42d3c7 100644 (file)
@@ -29,212 +29,212 @@ import org.apache.poi.util.LittleEndian;
  * @author Libin Roman (Vista Portal LDT. Developer)
  */
 public class ExternSheetRecord extends Record {
-    public final static short sid = 0x0017;
-    private List         _list;
-    
-    private final class RefSubRecord {
-       public static final int ENCODED_SIZE = 6;
+       public final static short sid = 0x0017;
+       private List _list;
+       
+       private final class RefSubRecord {
+               public static final int ENCODED_SIZE = 6;
 
-       /** index to External Book Block (which starts with a EXTERNALBOOK record) */
-        private int _extBookIndex;
-        private int _firstSheetIndex; // may be -1 (0xFFFF)
-        private int _lastSheetIndex;  // may be -1 (0xFFFF)
-        
-        
-        /** a Constructor for making new sub record
-         */
-        public RefSubRecord(int extBookIndex, int firstSheetIndex, int lastSheetIndex) {
-               _extBookIndex = extBookIndex;
-               _firstSheetIndex = firstSheetIndex;
-               _lastSheetIndex = lastSheetIndex;
-        }
-        
-        /**
-         * @param in the RecordInputstream to read the record from
-         */
-        public RefSubRecord(RecordInputStream in) {
-            this(in.readShort(), in.readShort(), in.readShort());
-        }
-        public int getExtBookIndex(){
-            return _extBookIndex;
-        }
-        public int getFirstSheetIndex(){
-            return _firstSheetIndex;
-        }
-        public int getLastSheetIndex(){
-            return _lastSheetIndex;
-        }
-        
-        public String toString() {
-            StringBuffer buffer = new StringBuffer();
-            buffer.append("extBook=").append(_extBookIndex);
-            buffer.append(" firstSheet=").append(_firstSheetIndex);
-            buffer.append(" lastSheet=").append(_lastSheetIndex);
-            return buffer.toString();
-        }
-        
-        /**
-         * called by the class that is responsible for writing this sucker.
-         * Subclasses should implement this so that their data is passed back in a
-         * byte array.
-         *
-         * @param offset to begin writing at
-         * @param data byte array containing instance data
-         * @return number of bytes written
-         */
-        public void serialize(int offset, byte [] data) {
-            LittleEndian.putUShort(data, 0 + offset, _extBookIndex);
-            LittleEndian.putUShort(data, 2 + offset, _firstSheetIndex);
-            LittleEndian.putUShort(data, 4 + offset, _lastSheetIndex);
-        }
-    }    
-    
-    
-    
-    public ExternSheetRecord() {
-        _list = new ArrayList();
-    }
-    
-    /**
-     * Constructs a Extern Sheet record and sets its fields appropriately.
-     * @param in the RecordInputstream to read the record from
-     */
-    
-    public ExternSheetRecord(RecordInputStream in) {
-        super(in);
-    }
-    
-    /**
-     * called by constructor, should throw runtime exception in the event of a
-     * record passed with a differing ID.
-     *
-     * @param id alleged id for this record
-     */
-    protected void validateSid(short id) {
-        if (id != sid) {
-            throw new RecordFormatException("NOT An ExternSheet RECORD");
-        }
-    }
-    
-    /**
-     * 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) {
-        _list           = new ArrayList();
-        
-        int nItems  = in.readShort();
-        
-        for (int i = 0 ; i < nItems ; ++i) {
-            RefSubRecord rec = new RefSubRecord(in);
-            
-            _list.add( rec);
-        }
-    }
-    
+               /** index to External Book Block (which starts with a EXTERNALBOOK record) */
+               private int _extBookIndex;
+               private int _firstSheetIndex; // may be -1 (0xFFFF)
+               private int _lastSheetIndex;  // may be -1 (0xFFFF)
+               
+               
+               /** a Constructor for making new sub record
+                */
+               public RefSubRecord(int extBookIndex, int firstSheetIndex, int lastSheetIndex) {
+                       _extBookIndex = extBookIndex;
+                       _firstSheetIndex = firstSheetIndex;
+                       _lastSheetIndex = lastSheetIndex;
+               }
+               
+               /**
+                * @param in the RecordInputstream to read the record from
+                */
+               public RefSubRecord(RecordInputStream in) {
+                       this(in.readShort(), in.readShort(), in.readShort());
+               }
+               public int getExtBookIndex(){
+                       return _extBookIndex;
+               }
+               public int getFirstSheetIndex(){
+                       return _firstSheetIndex;
+               }
+               public int getLastSheetIndex(){
+                       return _lastSheetIndex;
+               }
+               
+               public String toString() {
+                       StringBuffer buffer = new StringBuffer();
+                       buffer.append("extBook=").append(_extBookIndex);
+                       buffer.append(" firstSheet=").append(_firstSheetIndex);
+                       buffer.append(" lastSheet=").append(_lastSheetIndex);
+                       return buffer.toString();
+               }
+               
+               /**
+                * called by the class that is responsible for writing this sucker.
+                * Subclasses should implement this so that their data is passed back in a
+                * byte array.
+                *
+                * @param offset to begin writing at
+                * @param data byte array containing instance data
+                * @return number of bytes written
+                */
+               public void serialize(int offset, byte [] data) {
+                       LittleEndian.putUShort(data, 0 + offset, _extBookIndex);
+                       LittleEndian.putUShort(data, 2 + offset, _firstSheetIndex);
+                       LittleEndian.putUShort(data, 4 + offset, _lastSheetIndex);
+               }
+       }       
+       
+       
+       
+       public ExternSheetRecord() {
+               _list = new ArrayList();
+       }
+       
+       /**
+        * Constructs a Extern Sheet record and sets its fields appropriately.
+        * @param in the RecordInputstream to read the record from
+        */
+       
+       public ExternSheetRecord(RecordInputStream in) {
+               super(in);
+       }
+       
+       /**
+        * called by constructor, should throw runtime exception in the event of a
+        * record passed with a differing ID.
+        *
+        * @param id alleged id for this record
+        */
+       protected void validateSid(short id) {
+               if (id != sid) {
+                       throw new RecordFormatException("NOT An ExternSheet RECORD");
+               }
+       }
+       
+       /**
+        * 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) {
+               _list              = new ArrayList();
+               
+               int nItems  = in.readShort();
+               
+               for (int i = 0 ; i < nItems ; ++i) {
+                       RefSubRecord rec = new RefSubRecord(in);
+                       
+                       _list.add( rec);
+               }
+       }
+       
 
-    /**  
-     * @return number of REF structures
-     */
-    public int getNumOfRefs() {
-        return _list.size();
-    }
-    
-    /** 
-     * adds REF struct (ExternSheetSubRecord)
-     * @param rec REF struct
-     */
-    public void addREFRecord(RefSubRecord rec) {
-        _list.add(rec);
-    }
-    
-    /** returns the number of REF Records, which is in model
-     * @return number of REF records
-     */
-    public int getNumOfREFRecords() {
-        return _list.size();
-    }
-    
-    
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        int nItems = _list.size();
-        sb.append("[EXTERNSHEET]\n");
-        sb.append("   numOfRefs     = ").append(nItems).append("\n");
-        for (int i=0; i < nItems; i++) {
-            sb.append("refrec         #").append(i).append(": ");
-            sb.append(getRef(i).toString());
-            sb.append('\n');
-        }
-        sb.append("[/EXTERNSHEET]\n");
-        
-        
-        return sb.toString();
-    }
-    
-    
-    private int getDataSize() {
-       return 2 + _list.size() * RefSubRecord.ENCODED_SIZE;
-    }
-    
-    /**
-     * called by the class that is responsible for writing this sucker.
-     * Subclasses should implement this so that their data is passed back in a
-     * byte array.
-     *
-     * @param offset to begin writing at
-     * @param data byte array containing instance data
-     * @return number of bytes written
-     */
-    public int serialize(int offset, byte [] data) {
-        int dataSize = getDataSize();
-        
-        int nItems = _list.size();
+       /**  
+        * @return number of REF structures
+        */
+       public int getNumOfRefs() {
+               return _list.size();
+       }
+       
+       /** 
+        * adds REF struct (ExternSheetSubRecord)
+        * @param rec REF struct
+        */
+       public void addREFRecord(RefSubRecord rec) {
+               _list.add(rec);
+       }
+       
+       /** returns the number of REF Records, which is in model
+        * @return number of REF records
+        */
+       public int getNumOfREFRecords() {
+               return _list.size();
+       }
+       
+       
+       public String toString() {
+               StringBuffer sb = new StringBuffer();
+               int nItems = _list.size();
+               sb.append("[EXTERNSHEET]\n");
+               sb.append("   numOfRefs     = ").append(nItems).append("\n");
+               for (int i=0; i < nItems; i++) {
+                       sb.append("refrec         #").append(i).append(": ");
+                       sb.append(getRef(i).toString());
+                       sb.append('\n');
+               }
+               sb.append("[/EXTERNSHEET]\n");
+               
+               
+               return sb.toString();
+       }
+       
+       
+       private int getDataSize() {
+               return 2 + _list.size() * RefSubRecord.ENCODED_SIZE;
+       }
+       
+       /**
+        * called by the class that is responsible for writing this sucker.
+        * Subclasses should implement this so that their data is passed back in a
+        * byte array.
+        *
+        * @param offset to begin writing at
+        * @param data byte array containing instance data
+        * @return number of bytes written
+        */
+       public int serialize(int offset, byte [] data) {
+               int dataSize = getDataSize();
+               
+               int nItems = _list.size();
 
-        LittleEndian.putShort(data, 0 + offset, sid);
+               LittleEndian.putShort(data, 0 + offset, sid);
                LittleEndian.putUShort(data, 2 + offset, dataSize);
-        LittleEndian.putUShort(data, 4 + offset, nItems);
-        
-        int pos = 6 ;
-        
-        for (int i = 0; i < nItems; i++) {
-            getRef(i).serialize(offset + pos, data);
-            pos +=6;
-        }
-        return dataSize + 4;
-    }
+               LittleEndian.putUShort(data, 4 + offset, nItems);
+               
+               int pos = 6 ;
+               
+               for (int i = 0; i < nItems; i++) {
+                       getRef(i).serialize(offset + pos, data);
+                       pos +=6;
+               }
+               return dataSize + 4;
+       }
 
        private RefSubRecord getRef(int i) {
                return (RefSubRecord) _list.get(i);
        }
-    
-    public int getRecordSize() {
-        return 4 + getDataSize();
-    }
-    
-    /**
-     * return the non static version of the id for this record.
-     */
-    public short getSid() {
-        return sid;
-    }
+       
+       public int getRecordSize() {
+               return 4 + getDataSize();
+       }
+       
+       /**
+        * return the non static version of the id for this record.
+        */
+       public short getSid() {
+               return sid;
+       }
 
        public int getExtbookIndexFromRefIndex(int refIndex) {
-        return getRef(refIndex).getExtBookIndex();
+               return getRef(refIndex).getExtBookIndex();
        }
 
        /**
         * @return -1 if not found
         */
        public int findRefIndexFromExtBookIndex(int extBookIndex) {
-        int nItems = _list.size();
-        for (int i = 0; i < nItems; i++) {
-            if (getRef(i).getExtBookIndex() == extBookIndex) {
-               return i;
-            }
-        }
+               int nItems = _list.size();
+               for (int i = 0; i < nItems; i++) {
+                       if (getRef(i).getExtBookIndex() == extBookIndex) {
+                               return i;
+                       }
+               }
                return -1;
        }
 
@@ -251,13 +251,25 @@ public class ExternSheetRecord extends Record {
        }
 
        public int getRefIxForSheet(int sheetIndex) {
-        int nItems = _list.size();
-        for (int i = 0; i < nItems; i++) {
-            RefSubRecord ref = getRef(i);
+               int nItems = _list.size();
+               for (int i = 0; i < nItems; i++) {
+                       RefSubRecord ref = getRef(i);
                        if (ref.getFirstSheetIndex() == sheetIndex && ref.getLastSheetIndex() == sheetIndex) {
-               return i;
-            }
-        }
+                               return i;
+                       }
+               }
                return -1;
        }
+
+       public static ExternSheetRecord combine(ExternSheetRecord[] esrs) {
+               ExternSheetRecord result = new ExternSheetRecord();
+               for (int i = 0; i < esrs.length; i++) {
+                       ExternSheetRecord esr = esrs[i];
+                       int nRefs = esr.getNumOfREFRecords();
+                       for (int j=0; j<nRefs; j++) {
+                               result.addREFRecord(esr.getRef(j));
+                       }
+               }
+               return result;
+       }
 }
index 1aaa155a238efa340a77abacb1636ff2efa8dd19..9f6bb45866e3e53e6198bc1f961e81944f26642c 100644 (file)
@@ -32,10 +32,7 @@ import org.apache.poi.util.LittleEndian;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @version 2.0-pre
  */
-public final class FormulaRecord
-    extends Record
-    implements CellValueRecordInterface, Comparable
-{
+public final class FormulaRecord extends Record implements CellValueRecordInterface {
     
     public static final short sid = 0x0006;   // docs say 406...because of a bug Microsoft support site article #Q184647)
 
@@ -380,50 +377,6 @@ public final class FormulaRecord
         return retval;
     }
 
-    public boolean isBefore(CellValueRecordInterface i)
-    {
-        if (this.getRow() > i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() > i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isAfter(CellValueRecordInterface i)
-    {
-        if (this.getRow() < i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() < i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isEqual(CellValueRecordInterface i)
-    {
-        return ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()));
-    }
-
     public boolean isInValueSection()
     {
         return true;
@@ -433,51 +386,6 @@ public final class FormulaRecord
     {
         return true;
     }
-
-    public int compareTo(Object obj)
-    {
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return 0;
-        }
-        if (this.getRow() < loc.getRow())
-        {
-            return -1;
-        }
-        if (this.getRow() > loc.getRow())
-        {
-            return 1;
-        }
-        if (this.getColumn() < loc.getColumn())
-        {
-            return -1;
-        }
-        if (this.getColumn() > loc.getColumn())
-        {
-            return 1;
-        }
-        return -1;
-    }
-
-    public boolean equals(Object obj)
-    {
-        if (!(obj instanceof CellValueRecordInterface))
-        {
-            return false;
-        }
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return true;
-        }
-        return false;
-    }
-    
     
     public String toString()
     {
index c3fd5fb3dd8e51defc95ddbd457a9b90a643f89b..ae3b82f36fc8f8f641d3a41e72973a633e320ae5 100644 (file)
@@ -180,51 +180,6 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac
         return buffer.toString();
     }
 
-
-    public boolean isBefore(CellValueRecordInterface i)
-    {
-        if (this.getRow() > i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() > i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isAfter(CellValueRecordInterface i)
-    {
-        if (this.getRow() < i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() < i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isEqual(CellValueRecordInterface i)
-    {
-        return ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()));
-    }
-
     public boolean isInValueSection()
     {
         return true;
index 610f85522d611bb136089d3bbd8a5fb5a4472cac..a8d68bac2c4714562b26f000ba92f47da5d49e0f 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
@@ -15,7 +14,6 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
@@ -30,13 +28,8 @@ import org.apache.poi.util.LittleEndian;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @version 2.0-pre
  */
-
-public class LabelSSTRecord
-    extends Record
-    implements CellValueRecordInterface, Comparable
-{
+public final class LabelSSTRecord extends Record implements CellValueRecordInterface {
     public final static short sid = 0xfd;
-    //private short             field_1_row;
     private int             field_1_row;
     private short             field_2_column;
     private short             field_3_xf_index;
@@ -183,50 +176,6 @@ public class LabelSSTRecord
         return sid;
     }
 
-    public boolean isBefore(CellValueRecordInterface i)
-    {
-        if (this.getRow() > i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() > i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isAfter(CellValueRecordInterface i)
-    {
-        if (this.getRow() < i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() < i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isEqual(CellValueRecordInterface i)
-    {
-        return ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()));
-    }
-
     public boolean isInValueSection()
     {
         return true;
@@ -237,50 +186,6 @@ public class LabelSSTRecord
         return true;
     }
 
-    public int compareTo(Object obj)
-    {
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return 0;
-        }
-        if (this.getRow() < loc.getRow())
-        {
-            return -1;
-        }
-        if (this.getRow() > loc.getRow())
-        {
-            return 1;
-        }
-        if (this.getColumn() < loc.getColumn())
-        {
-            return -1;
-        }
-        if (this.getColumn() > loc.getColumn())
-        {
-            return 1;
-        }
-        return -1;
-    }
-
-    public boolean equals(Object obj)
-    {
-        if (!(obj instanceof CellValueRecordInterface))
-        {
-            return false;
-        }
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return true;
-        }
-        return false;
-    }
-
     public Object clone() {
       LabelSSTRecord rec = new LabelSSTRecord();
       rec.field_1_row = field_1_row;
index b21e488ed73c30417dc1809adf86ca2f1cb23a4c..eeb5cf62ad024b7c089d8b9d1bd9737aa64a058b 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.
 ==================================================================== */
-        
 
-/*
- * NumberRecord.java
- *
- * Created on October 1, 2001, 8:01 PM
- */
 package org.apache.poi.hssf.record;
 
 import org.apache.poi.util.LittleEndian;
@@ -34,13 +27,8 @@ import org.apache.poi.hssf.record.Record;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @version 2.0-pre
  */
-
-public class NumberRecord
-    extends Record
-    implements CellValueRecordInterface, Comparable
-{
+public final class NumberRecord extends Record implements CellValueRecordInterface {
     public static final short sid = 0x203;
-    //private short             field_1_row;
     private int             field_1_row;
     private short             field_2_col;
     private short             field_3_xf;
@@ -203,50 +191,6 @@ public class NumberRecord
         return sid;
     }
 
-    public boolean isBefore(CellValueRecordInterface i)
-    {
-        if (this.getRow() > i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() > i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isAfter(CellValueRecordInterface i)
-    {
-        if (this.getRow() < i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() < i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isEqual(CellValueRecordInterface i)
-    {
-        return ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()));
-    }
-
     public boolean isInValueSection()
     {
         return true;
@@ -257,50 +201,6 @@ public class NumberRecord
         return true;
     }
 
-    public int compareTo(Object obj)
-    {
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return 0;
-        }
-        if (this.getRow() < loc.getRow())
-        {
-            return -1;
-        }
-        if (this.getRow() > loc.getRow())
-        {
-            return 1;
-        }
-        if (this.getColumn() < loc.getColumn())
-        {
-            return -1;
-        }
-        if (this.getColumn() > loc.getColumn())
-        {
-            return 1;
-        }
-        return -1;
-    }
-
-    public boolean equals(Object obj)
-    {
-        if (!(obj instanceof CellValueRecordInterface))
-        {
-            return false;
-        }
-        CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
-
-        if ((this.getRow() == loc.getRow())
-                && (this.getColumn() == loc.getColumn()))
-        {
-            return true;
-        }
-        return false;
-    }
-
     public Object clone() {
       NumberRecord rec = new NumberRecord();
       rec.field_1_row = field_1_row;
index 4d30ddf4c9a62b744b8127b92a40dc8c5accdb16..2a99e16047c0aeb1fb1f7c8c09ade5ad91c8dd60 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
@@ -15,7 +14,6 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
@@ -38,17 +36,12 @@ import org.apache.poi.hssf.util.RKUtil;
  * @version 2.0-pre
  * @see org.apache.poi.hssf.record.NumberRecord
  */
-
-public class RKRecord
-    extends Record
-    implements CellValueRecordInterface
-{
+public final class RKRecord extends Record implements CellValueRecordInterface {
     public final static short sid                      = 0x27e;
     public final static short RK_IEEE_NUMBER           = 0;
     public final static short RK_IEEE_NUMBER_TIMES_100 = 1;
     public final static short RK_INTEGER               = 2;
     public final static short RK_INTEGER_TIMES_100     = 3;
-    //private short             field_1_row;
     private int             field_1_row;
     private short             field_2_col;
     private short             field_3_xf_index;
@@ -216,50 +209,6 @@ public class RKRecord
         return sid;
     }
 
-    public boolean isBefore(CellValueRecordInterface i)
-    {
-        if (this.getRow() > i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() > i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isAfter(CellValueRecordInterface i)
-    {
-        if (this.getRow() < i.getRow())
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() < i.getColumn()))
-        {
-            return false;
-        }
-        if ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public boolean isEqual(CellValueRecordInterface i)
-    {
-        return ((this.getRow() == i.getRow())
-                && (this.getColumn() == i.getColumn()));
-    }
-
     public boolean isInValueSection()
     {
         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 7840d32562c4ac730e0cb86389f014076343434a..3359ca55a41c68917cd0864a03ef8efcc186ecab 100644 (file)
    limitations under the License.
 ==================================================================== */
 
-
 package org.apache.poi.hssf.record.aggregates;
 
-import org.apache.poi.hssf.record.*;
+import org.apache.poi.hssf.record.CellValueRecordInterface;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.StringRecord;
 
 /**
  * The formula record aggregate is used to join together the formula record and it's
@@ -26,171 +27,81 @@ import org.apache.poi.hssf.record.*;
  *
  * @author Glen Stampoultzis (glens at apache.org)
  */
-public class FormulaRecordAggregate
-        extends Record
-        implements CellValueRecordInterface, Comparable
-{
-    public final static short sid       = -2000;
+public final class FormulaRecordAggregate extends RecordAggregate implements CellValueRecordInterface {
 
-    private FormulaRecord formulaRecord;
-    private StringRecord stringRecord;
+    private FormulaRecord _formulaRecord;
+    private StringRecord _stringRecord;
     
     public FormulaRecordAggregate( FormulaRecord formulaRecord, StringRecord stringRecord )
     {
-        this.formulaRecord = formulaRecord;
-        this.stringRecord = stringRecord;
-    }
-
-    protected void validateSid( short id )
-    {
-    }
-
-    protected void fillFields( RecordInputStream in )
-    {
-    }
-
-    /**
-     * called by the class that is responsible for writing this sucker.
-     * Subclasses should implement this so that their data is passed back in a
-     * byte array.
-     *
-     * @param offset to begin writing at
-     * @param data byte array containing instance data
-     * @return number of bytes written
-     */
-
-    public int serialize( int offset, byte[] data )
-    {
-        int pos = offset;
-        pos += formulaRecord.serialize(pos, data);
-
-         if (stringRecord != null)
-        {
-            pos += stringRecord.serialize(pos, data);
-        }
-        return pos - offset;
-        
+        _formulaRecord = formulaRecord;
+        _stringRecord = stringRecord;
     }
 
-    /**
-     * gives the current serialized size of the record. Should include the sid and reclength (4 bytes).
-     */
-    public int getRecordSize()
-    {
-        int size = formulaRecord.getRecordSize() + (stringRecord == null ? 0 : stringRecord.getRecordSize());
-        return size;
-    }
-
-
-    /**
-     * return the non static version of the id for this record.
-     */
-    public short getSid()
-    {
-        return sid;
-    }
-
-    public void setStringRecord( StringRecord stringRecord )
-    {
-        this.stringRecord = stringRecord;
+    public void setStringRecord( StringRecord stringRecord ) {
+        _stringRecord = stringRecord;
     }
 
     public void setFormulaRecord( FormulaRecord formulaRecord )
     {
-        this.formulaRecord = formulaRecord;
+        _formulaRecord = formulaRecord;
     }
     
     public FormulaRecord getFormulaRecord()
     {
-        return formulaRecord;
+        return _formulaRecord;
     }
 
     public StringRecord getStringRecord()
     {
-        return stringRecord;
+        return _stringRecord;
     }
     
-    public boolean isEqual(CellValueRecordInterface i)
-    {
-        return formulaRecord.isEqual( i );
-    }
-
-    public boolean isAfter(CellValueRecordInterface i)
-    {
-        return formulaRecord.isAfter( i );
-    }
-
-    public boolean isBefore(CellValueRecordInterface i)
-    {
-        return formulaRecord.isBefore( i );
-    }
-
     public short getXFIndex()
     {
-        return formulaRecord.getXFIndex();
+        return _formulaRecord.getXFIndex();
     }
 
     public void setXFIndex(short xf)
     {
-        formulaRecord.setXFIndex( xf );
+        _formulaRecord.setXFIndex( xf );
     }
 
     public void setColumn(short col)
     {
-        formulaRecord.setColumn( col );
+        _formulaRecord.setColumn( col );
     }
 
     public void setRow(int row)
     {
-        formulaRecord.setRow( row );
+        _formulaRecord.setRow( row );
     }
 
     public short getColumn()
     {
-        return formulaRecord.getColumn();
+        return _formulaRecord.getColumn();
     }
 
     public int getRow()
     {
-        return formulaRecord.getRow();
+        return _formulaRecord.getRow();
     }
 
-    public int compareTo(Object o)
-    {
-        return formulaRecord.compareTo( o );
+    public String toString() {
+        return _formulaRecord.toString();
     }
-
-    public boolean equals(Object obj)
-    {
-        return formulaRecord.equals( obj );
-    }
-
-    public String toString()
-    {
-        return formulaRecord.toString();
-    }
-    
-    /**
-     * @see java.lang.Object#clone()
-     */
-    public Object clone() {
-                       StringRecord clonedString = (stringRecord == null) ? null : (StringRecord)stringRecord.clone();
-               
-        return new FormulaRecordAggregate((FormulaRecord) this.formulaRecord.clone(), clonedString);
+   
+    public void visitContainedRecords(RecordVisitor rv) {
+         rv.visitRecord(_formulaRecord);
+         if (_stringRecord != null) {
+              rv.visitRecord(_stringRecord);
+         }
     }
-
-   /* 
-    * Setting to true so that this value does not abort the whole ValueAggregation
-    * (non-Javadoc)
-    * @see org.apache.poi.hssf.record.Record#isInValueSection()
-    */
-   public boolean isInValueSection() {
-
-      return true;
-   }
    
-   public String getStringValue() {
-        if(stringRecord==null) return null;
-        return stringRecord.getString();
-   }
+    public String getStringValue() {
+        if(_stringRecord==null) {
+            return null;
+        }
+        return _stringRecord.getString();
+    }
 }
index b7384a01948e9eba3793bfdf6c79c72882f9ea25..6a457fe48e4ee98fc722d4e4240b338b61ea97c4 100644 (file)
@@ -41,8 +41,12 @@ public final class MergedCellsTable extends RecordAggregate {
                _mergedRegions = new ArrayList();
        }
 
-       public MergedCellsTable(RecordStream rs) {
-               List temp = new ArrayList();
+       /**
+        * reads zero or more consecutive {@link MergeCellsRecord}s
+        * @param rs
+        */
+       public void read(RecordStream rs) {
+               List temp = _mergedRegions;
                while (rs.peekNextClass() == MergeCellsRecord.class) {
                        MergeCellsRecord mcr = (MergeCellsRecord) rs.getNext();
                        int nRegions = mcr.getNumAreas();
@@ -50,7 +54,6 @@ public final class MergedCellsTable extends RecordAggregate {
                                temp.add(mcr.getAreaAt(i));
                        }
                }
-               _mergedRegions = temp;
        }
 
        public int getRecordSize() {
@@ -92,7 +95,10 @@ public final class MergedCellsTable extends RecordAggregate {
        }
 
        public void add(MergeCellsRecord mcr) {
-               _mergedRegions.add(mcr);
+               int nRegions = mcr.getNumAreas();
+               for (int i = 0; i < nRegions; i++) {
+                       _mergedRegions.add(mcr.getAreaAt(i));
+               }
        }
 
        public CellRangeAddress get(int index) {
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;
index c9a302b614b3a851a97915d95e8c13ce12dcfaf2..d839ecfab623ea5f1d42fa40eade43c483213733 100644 (file)
@@ -26,8 +26,10 @@ import java.util.TreeMap;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.DBCellRecord;
 import org.apache.poi.hssf.record.IndexRecord;
+import org.apache.poi.hssf.record.MergeCellsRecord;
 import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.UnknownRecord;
 
 /**
  *
@@ -39,6 +41,7 @@ public final class RowRecordsAggregate extends RecordAggregate {
     private int _lastrow  = -1;
     private final Map _rowRecords;
     private final ValueRecordsAggregate _valuesAgg;
+    private final List _unknownRecords;
 
     /** Creates a new instance of ValueRecordsAggregate */
 
@@ -48,8 +51,54 @@ public final class RowRecordsAggregate extends RecordAggregate {
     private RowRecordsAggregate(TreeMap rowRecords, ValueRecordsAggregate valuesAgg) {
         _rowRecords = rowRecords;
         _valuesAgg = valuesAgg;
+        _unknownRecords = new ArrayList();
     }
 
+    public RowRecordsAggregate(List recs, int startIx, int endIx) {
+        this();
+        // First up, locate all the shared formulas for this sheet
+        SharedFormulaHolder sfh = SharedFormulaHolder.create(recs, startIx, endIx);
+        for(int i=startIx; i<endIx; i++) {
+            Record rec = (Record) recs.get(i);
+            switch (rec.getSid()) {
+                case MergeCellsRecord.sid:
+                    // Some apps scatter these records between the rows/cells but they are supposed to
+                    // be well after the row/cell records.  It is assumed such rogue MergeCellRecords 
+                    // have already been collected by the caller, and can safely be ignored here. 
+                    // see bug 45699
+                    continue;
+                case RowRecord.sid:
+                    insertRow((RowRecord) rec);
+                    continue;
+                case DBCellRecord.sid:
+                    // end of 'Row Block'.  Should only occur after cell records
+                    continue;
+            }
+            if (rec instanceof UnknownRecord) {
+                addUnknownRecord((UnknownRecord)rec);
+                // might need to keep track of where exactly these belong
+                continue;
+            }
+            if (!rec.isValue()) {
+                throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
+            }
+            i += _valuesAgg.construct(recs, i, endIx, sfh);
+        }
+        "".length();
+    }
+    /**
+     * Handles UnknownRecords which appear within the row/cell records
+     */
+    private void addUnknownRecord(UnknownRecord rec) {
+        // ony a few distinct record IDs are encountered by the existing POI test cases:
+        // 0x1065 // many
+        // 0x01C2 // several
+        // 0x0034 // few
+        // No documentation could be found for these
+        
+        // keep the unknown records for re-serialization
+        _unknownRecords.add(rec);
+    }
     public void insertRow(RowRecord row) {
         // Integer integer = new Integer(row.getRowNumber());
         _rowRecords.put(new Integer(row.getRowNumber()), row);
@@ -215,6 +264,10 @@ public final class RowRecordsAggregate extends RecordAggregate {
             cellRecord.setRowOffset(pos);
             rv.visitRecord(cellRecord);
         }
+        for (int i=0; i< _unknownRecords.size(); i++) {
+            // Potentially breaking the file here since we don't know exactly where to write these records
+            rv.visitRecord((Record) _unknownRecords.get(i));
+        }
     }
 
     public Iterator getIterator() {
@@ -439,9 +492,6 @@ public final class RowRecordsAggregate extends RecordAggregate {
         }
         return result;
     }
-    public void constructCellValues(int offset, List records) {
-        _valuesAgg.construct(offset, records);
-    }
     public void insertCell(CellValueRecordInterface cvRec) {
         _valuesAgg.insertCell(cvRec);
     }
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/SharedFormulaHolder.java b/src/java/org/apache/poi/hssf/record/aggregates/SharedFormulaHolder.java
new file mode 100644 (file)
index 0000000..2b39371
--- /dev/null
@@ -0,0 +1,96 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record.aggregates;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
+
+/**
+ * Temporarily holds SharedFormulaRecords while constructing a <tt>RowRecordsAggregate</tt>
+ * 
+ * @author Josh Micich
+ */
+final class SharedFormulaHolder {
+
+       private static final SharedFormulaHolder EMPTY = new SharedFormulaHolder(new SharedFormulaRecord[0]);
+       private final SharedFormulaRecord[] _sfrs;
+
+       /**
+        * @param recs list of sheet records (possibly contains records for other parts of the Excel file)
+        * @param startIx index of first row/cell record for current sheet
+        * @param endIx one past index of last row/cell record for current sheet.  It is important 
+        * that this code does not inadvertently collect <tt>SharedFormulaRecord</tt>s from any other
+        * sheet (which could happen if endIx is chosen poorly).  (see bug 44449) 
+        */
+       public static SharedFormulaHolder create(List recs, int startIx, int endIx) {
+               List temp = new ArrayList();
+        for (int k = startIx; k < endIx; k++)
+        {
+            Record rec = ( Record ) recs.get(k);
+            if (rec instanceof SharedFormulaRecord) {
+                temp.add(rec);
+            }
+        }
+        if (temp.size() < 1) {
+               return EMPTY;
+        }
+        SharedFormulaRecord[] sfrs = new SharedFormulaRecord[temp.size()];
+        temp.toArray(sfrs);
+        return new SharedFormulaHolder(sfrs);
+        
+       }
+       private SharedFormulaHolder(SharedFormulaRecord[] sfrs) {
+               _sfrs = sfrs;
+       }
+       public void convertSharedFormulaRecord(FormulaRecord formula) {
+        // Traverse the list of shared formulas in
+        //  reverse order, and try to find the correct one
+        //  for us
+        for (int i=0; i<_sfrs.length; i++) {
+            SharedFormulaRecord shrd = _sfrs[i];
+            if (shrd.isFormulaInShared(formula)) {
+                shrd.convertSharedFormulaRecord(formula);
+                return;
+            }
+        }
+        // not found
+        handleMissingSharedFormulaRecord(formula);
+       }
+
+    /**
+     * Sometimes the shared formula flag "seems" to be erroneously set, in which case there is no 
+     * call to <tt>SharedFormulaRecord.convertSharedFormulaRecord</tt> and hence the 
+     * <tt>parsedExpression</tt> field of this <tt>FormulaRecord</tt> will not get updated.<br/>
+     * As it turns out, this is not a problem, because in these circumstances, the existing value
+     * for <tt>parsedExpression</tt> is perfectly OK.<p/>
+     * 
+     * This method may also be used for setting breakpoints to help diagnose issues regarding the
+     * abnormally-set 'shared formula' flags. 
+     * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
+     * 
+     * The method currently does nothing but do not delete it without finding a nice home for this 
+     * comment.
+     */
+    private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
+        // could log an info message here since this is a fairly unusual occurrence.
+    }
+}
index 8d5764187f7c44816cfdeef7bed6e7ef50ac2275..0db1201432e647e3485845c84da08d4b0626db5c 100644 (file)
@@ -22,11 +22,15 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.apache.poi.hssf.record.CellValueRecordInterface;
-import org.apache.poi.hssf.record.EOFRecord;
+import org.apache.poi.hssf.record.DBCellRecord;
 import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.MergeCellsRecord;
 import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordBase;
+import org.apache.poi.hssf.record.RowRecord;
 import org.apache.poi.hssf.record.SharedFormulaRecord;
 import org.apache.poi.hssf.record.StringRecord;
+import org.apache.poi.hssf.record.TableRecord;
 import org.apache.poi.hssf.record.UnknownRecord;
 import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
 
@@ -39,8 +43,8 @@ import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class ValueRecordsAggregate {
-    private int                       firstcell = -1;
-    private int                       lastcell  = -1;
+    private int firstcell = -1;
+    private int lastcell  = -1;
     private CellValueRecordInterface[][] records;
 
     /** Creates a new instance of ValueRecordsAggregate */
@@ -137,92 +141,81 @@ public final class ValueRecordsAggregate {
         return lastcell;
     }
 
-    public int construct(int offset, List records)
-    {
+    /**
+     * Processes a sequential group of cell value records.  Stops at endIx or the first 
+     * non-value record encountered.
+     * @param sfh used to resolve any shared formulas for the current sheet
+     * @return the number of records consumed
+     */
+    public int construct(List records, int offset, int endIx, SharedFormulaHolder sfh) {
         int k = 0;
 
         FormulaRecordAggregate lastFormulaAggregate = null;
         
-        // First up, locate all the shared formulas for this sheet
-        List sharedFormulas = new java.util.ArrayList();
-        for (k = offset; k < records.size(); k++)
-        {
+        // Now do the main processing sweep
+        for (k = offset; k < endIx; k++) {
             Record rec = ( Record ) records.get(k);
+
+            if (rec instanceof StringRecord) {
+                if (lastFormulaAggregate == null) {
+                    throw new RuntimeException("StringRecord found without preceding FormulaRecord");
+                }
+                if (lastFormulaAggregate.getStringRecord() != null) {
+                    throw new RuntimeException("Multiple StringRecords found after FormulaRecord");
+                }
+                lastFormulaAggregate.setStringRecord((StringRecord)rec);
+                lastFormulaAggregate = null;
+                continue;
+            }
+            
+            if (rec instanceof TableRecord) {
+                // TODO - don't loose this record
+                // DATATABLE probably belongs in formula record aggregate
+                if (lastFormulaAggregate == null) {
+                    throw new RuntimeException("No preceding formula record found");
+                }
+                lastFormulaAggregate = null;
+                continue; 
+            }
+            
             if (rec instanceof SharedFormulaRecord) {
-                sharedFormulas.add(rec);
+                // Already handled, not to worry
+                continue;
             }
-            if(rec instanceof EOFRecord) {
-                // End of current sheet. Ignore all subsequent shared formula records (Bugzilla 44449)
+
+            if (rec instanceof UnknownRecord) {
                 break;
             }
-        }
-
-        // Now do the main processing sweep
-        for (k = offset; k < records.size(); k++)
-        {
-            Record rec = ( Record ) records.get(k);
-
-            if (rec instanceof StringRecord == false && !rec.isInValueSection() && !(rec instanceof UnknownRecord))
-            {
+            if (rec instanceof RowRecord) {
+                break; 
+            }
+            if (rec instanceof DBCellRecord) {
+                // end of 'Row Block'.  This record is ignored by POI
                 break;
-            } else if (rec instanceof SharedFormulaRecord) {
-                // Already handled, not to worry
-            } else if (rec instanceof FormulaRecord)
-            {
-              FormulaRecord formula = (FormulaRecord)rec;
-              if (formula.isSharedFormula()) {
-                // Traverse the list of shared formulas in
-                //  reverse order, and try to find the correct one
-                //  for us
-                boolean found = false;
-                for (int i=sharedFormulas.size()-1;i>=0;i--) {
-                    // TODO - there is no junit test case to justify this reversed loop
-                    // perhaps it could just run in the normal direction?
-                    SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i);
-                    if (shrd.isFormulaInShared(formula)) {
-                        shrd.convertSharedFormulaRecord(formula);
-                        found = true;
-                        break;
-                    }
-                }
-                if (!found) {
-                    handleMissingSharedFormulaRecord(formula);
-                }
-              }
-                
-              lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null);
-              insertCell( lastFormulaAggregate );
             }
-            else if (rec instanceof StringRecord)
-            {
-                lastFormulaAggregate.setStringRecord((StringRecord)rec);
+            if (rec instanceof MergeCellsRecord) {
+                // doesn't really belong here
+                // can safely be ignored, because it has been processed in a higher method
+                continue;
+            }
+            if (!rec.isValue()) {
+                throw new RuntimeException("bad record type");
             }
-            else if (rec.isValue())
-            {
-                insertCell(( CellValueRecordInterface ) rec);
+            if (rec instanceof FormulaRecord) {
+                FormulaRecord formula = (FormulaRecord)rec;
+                if (formula.isSharedFormula()) {
+                    sfh.convertSharedFormulaRecord(formula);
+                }
+                
+                lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null);
+                insertCell( lastFormulaAggregate );
+                continue;
             }
+            insertCell(( CellValueRecordInterface ) rec);
         }
-        return k;
+        return k - offset - 1;
     }
 
-    /**
-     * Sometimes the shared formula flag "seems" to be erroneously set, in which case there is no 
-     * call to <tt>SharedFormulaRecord.convertSharedFormulaRecord</tt> and hence the 
-     * <tt>parsedExpression</tt> field of this <tt>FormulaRecord</tt> will not get updated.<br/>
-     * As it turns out, this is not a problem, because in these circumstances, the existing value
-     * for <tt>parsedExpression</tt> is perfectly OK.<p/>
-     * 
-     * This method may also be used for setting breakpoints to help diagnose issues regarding the
-     * abnormally-set 'shared formula' flags. 
-     * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
-     * 
-     * The method currently does nothing but do not delete it without finding a nice home for this 
-     * comment.
-     */
-    private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
-        // could log an info message here since this is a fairly unusual occurrence.
-    }
-    
     /** Tallies a count of the size of the cell records
      *  that are attached to the rows in the range specified.
      */
@@ -235,7 +228,7 @@ public final class ValueRecordsAggregate {
         if (row > endRow)
           break;
         if ((row >=startRow) && (row <= endRow))
-          size += ((Record)cell).getRecordSize();
+          size += ((RecordBase)cell).getRecordSize();
       }
       return size;
     }
@@ -263,7 +256,7 @@ public final class ValueRecordsAggregate {
             CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
             if (cell.getRow() != row)
               break;
-            pos += (( Record ) cell).serialize(pos, data);
+            pos += (( RecordBase ) cell).serialize(pos, data);
         }
         return pos - offset;
     }
@@ -321,16 +314,6 @@ public final class ValueRecordsAggregate {
     {
     return new MyIterator();
     }
-
-    /** Performs a deep clone of the record*/
-    public Object clone() {
-      ValueRecordsAggregate rec = new ValueRecordsAggregate();
-      for (Iterator valIter = getIterator(); valIter.hasNext();) {
-        CellValueRecordInterface val = (CellValueRecordInterface)((CellValueRecordInterface)valIter.next()).clone();
-        rec.insertCell(val);
-      }
-      return rec;
-    }
   
   private final class MyIterator implements Iterator {
     short nextColumn=-1;
index 05d8391b29f7520ea5f80ef70e49fef2ee2abb11..9cc7334605a6ed916dc8a8121cff90ab562b67ad 100644 (file)
@@ -25,63 +25,59 @@ import org.apache.poi.util.LittleEndian;
 
 /**
  * This ptg indicates a data table.
- * It only occurs in a FORMULA record, never in an 
- *  ARRAY or NAME record.  When ptgTbl occurs in a 
- *  formula, it is the only token in the formula.  
- * (TODO - check this when processing)
- * This indicates that the cell containing the 
- *  formula is an interior cell in a data table; 
+ * It only occurs in a FORMULA record, never in an
+ *  ARRAY or NAME record.  When ptgTbl occurs in a
+ *  formula, it is the only token in the formula.
+ *
+ * This indicates that the cell containing the
+ *  formula is an interior cell in a data table;
  *  the table description is found in a TABLE
- *  record. Rows and columns which contain input 
- *  values to be substituted in the table do 
+ *  record. Rows and columns which contain input
+ *  values to be substituted in the table do
  *  not contain ptgTbl.
  * See page 811 of the june 08 binary docs.
  */
 public final class TblPtg extends ControlPtg {
-    private final static int  SIZE = 4;
-    public final static short sid  = 0x2;
+    private final static int  SIZE = 5;
+    public final static short sid  = 0x02;
     /** The row number of the upper left corner */
-    private final short     field_1_first_row;
+    private final int field_1_first_row;
     /** The column number of the upper left corner */
-    private final short     field_2_first_col;
+    private final int field_2_first_col;
 
-    public TblPtg(RecordInputStream in)
-    {
-      field_1_first_row = in.readShort();
-      field_2_first_col = in.readUByte();
+    public TblPtg(RecordInputStream in) {
+      field_1_first_row = in.readUShort();
+      field_2_first_col = in.readUShort();
     }
-    
-    public void writeBytes(byte [] array, int offset)
-    {
-      array[offset+0]= (byte) (sid);
-      LittleEndian.putShort(array,offset+1,field_1_first_row);
-      LittleEndian.putByte(array,offset+3,field_2_first_col);
+
+    public void writeBytes(byte [] array, int offset) {
+      LittleEndian.putByte(array, offset+0, sid);
+      LittleEndian.putUShort(array, offset+1, field_1_first_row);
+      LittleEndian.putUShort(array, offset+3, field_2_first_col);
     }
 
-    public int getSize()
-    {
+    public int getSize() {
         return SIZE;
     }
-    
-    public short getRow() {
+
+    public int getRow() {
       return field_1_first_row;
     }
 
-    public short getColumn() {
+    public int getColumn() {
       return field_2_first_col;
-    }    
+    }
 
     public String toFormulaString(Workbook book)
     {
-       // table(....)[][]
+        // table(....)[][]
         throw new RecordFormatException("Table and Arrays are not yet supported");
     }
-    
-    public String toString()
-    {
+
+    public String toString() {
         StringBuffer buffer = new StringBuffer("[Data Table - Parent cell is an interior cell in a data table]\n");
         buffer.append("top left row = ").append(getRow()).append("\n");
         buffer.append("top left col = ").append(getColumn()).append("\n");
         return buffer.toString();
-    }    
+    }
 }
index f66baf3024599a0180246d71b679acf7aa608df2..7f8f7aa3b90d1d762fa285ed66a494159fbda638 100644 (file)
@@ -189,40 +189,25 @@ public class HSSFCell implements Cell {
     /**
      * used internally -- given a cell value record, figure out its type
      */
-    private int determineType(CellValueRecordInterface cval)
-    {
+    private static int determineType(CellValueRecordInterface cval) {
+       if (cval instanceof FormulaRecordAggregate) {
+               return HSSFCell.CELL_TYPE_FORMULA;
+       }
+       // all others are plain BIFF records
         Record record = ( Record ) cval;
-        int    sid    = record.getSid();
-        int    retval = 0;
-
-        switch (sid)
-        {
-
-            case NumberRecord.sid :
-                retval = HSSFCell.CELL_TYPE_NUMERIC;
-                break;
-
-            case BlankRecord.sid :
-                retval = HSSFCell.CELL_TYPE_BLANK;
-                break;
-
-            case LabelSSTRecord.sid :
-                retval = HSSFCell.CELL_TYPE_STRING;
-                break;
-
-            case FormulaRecordAggregate.sid :
-                retval = HSSFCell.CELL_TYPE_FORMULA;
-                break;
+        switch (record.getSid()) {
 
+            case NumberRecord.sid :   return HSSFCell.CELL_TYPE_NUMERIC;
+            case BlankRecord.sid :    return HSSFCell.CELL_TYPE_BLANK;
+            case LabelSSTRecord.sid : return HSSFCell.CELL_TYPE_STRING;
             case BoolErrRecord.sid :
                 BoolErrRecord boolErrRecord = ( BoolErrRecord ) record;
 
-                retval = (boolErrRecord.isBoolean())
+                return boolErrRecord.isBoolean()
                          ? HSSFCell.CELL_TYPE_BOOLEAN
                          : HSSFCell.CELL_TYPE_ERROR;
-                break;
         }
-        return retval;
+        throw new RuntimeException("Bad cell value rec (" + cval.getClass().getName() + ")");
     }
     
     /**
diff --git a/src/testcases/org/apache/poi/hssf/data/ex45698-22488.xls b/src/testcases/org/apache/poi/hssf/data/ex45698-22488.xls
new file mode 100644 (file)
index 0000000..615e6c5
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/ex45698-22488.xls differ
index 6c6dd9fb25c1178988129075faa043643a3bbe31..97635e53627a1747720e0c8067f1a011e153cd93 100644 (file)
@@ -24,6 +24,7 @@ import java.util.List;
 import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
+import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.hssf.eventmodel.ERFListener;
 import org.apache.poi.hssf.eventmodel.EventRecordFactory;
 import org.apache.poi.hssf.record.BOFRecord;
@@ -32,6 +33,7 @@ import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.ColumnInfoRecord;
 import org.apache.poi.hssf.record.DimensionsRecord;
 import org.apache.poi.hssf.record.EOFRecord;
+import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.GutsRecord;
 import org.apache.poi.hssf.record.IndexRecord;
 import org.apache.poi.hssf.record.MergeCellsRecord;
@@ -39,9 +41,13 @@ import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RowRecord;
 import org.apache.poi.hssf.record.StringRecord;
 import org.apache.poi.hssf.record.UncalcedRecord;
+import org.apache.poi.hssf.record.WindowTwoRecord;
 import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
+import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
 import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
 import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.hssf.util.CellRangeAddress;
@@ -57,6 +63,7 @@ public final class TestSheet extends TestCase {
         List records = new ArrayList();
         records.add( new BOFRecord() );
         records.add( new DimensionsRecord() );
+        records.add(createWindow2Record());
         records.add(EOFRecord.instance);
         Sheet sheet = Sheet.createSheet( records, 0, 0 );
 
@@ -65,9 +72,22 @@ public final class TestSheet extends TestCase {
         assertTrue( sheet.records.get(pos++) instanceof ColumnInfoRecordsAggregate );
         assertTrue( sheet.records.get(pos++) instanceof DimensionsRecord );
         assertTrue( sheet.records.get(pos++) instanceof RowRecordsAggregate );
+        assertTrue( sheet.records.get(pos++) instanceof WindowTwoRecord );
+        assertTrue( sheet.records.get(pos++) instanceof MergedCellsTable );
         assertTrue( sheet.records.get(pos++) instanceof EOFRecord );
     }
 
+    private static Record createWindow2Record() {
+        WindowTwoRecord result = new WindowTwoRecord();
+        result.setOptions(( short ) 0x6b6);
+        result.setTopRow(( short ) 0);
+        result.setLeftCol(( short ) 0);
+        result.setHeaderColor(0x40);
+        result.setPageBreakZoom(( short ) 0);
+        result.setNormalZoom(( short ) 0);
+        return result;
+    }
+
     private static final class MergedCellListener implements ERFListener {
 
         private int _count;
@@ -168,6 +188,8 @@ public final class TestSheet extends TestCase {
         records.add(new RowRecord(0));
         records.add(new RowRecord(1));
         records.add(new RowRecord(2));
+        records.add(createWindow2Record());
+        records.add(EOFRecord.instance);
         records.add(merged);
 
         Sheet sheet = Sheet.createSheet(records, 0);
@@ -193,11 +215,15 @@ public final class TestSheet extends TestCase {
     public void testRowAggregation() {
         List records = new ArrayList();
 
+        records.add(Sheet.createBOF());
         records.add(new DimensionsRecord());
         records.add(new RowRecord(0));
         records.add(new RowRecord(1));
+        records.add(new FormulaRecord());
         records.add(new StringRecord());
         records.add(new RowRecord(2));
+        records.add(createWindow2Record());
+        records.add(EOFRecord.instance);
 
         Sheet sheet = Sheet.createSheet(records, 0);
         assertNotNull("Row [2] was skipped", sheet.getRow(2));
@@ -400,6 +426,7 @@ public final class TestSheet extends TestCase {
         records.add(new BOFRecord());
         records.add(new UncalcedRecord());
         records.add(new DimensionsRecord());
+        records.add(createWindow2Record());
         records.add(EOFRecord.instance);
         Sheet sheet = Sheet.createSheet(records, 0, 0);
 
@@ -408,7 +435,7 @@ public final class TestSheet extends TestCase {
         if (serializedSize != estimatedSize) {
             throw new AssertionFailedError("Identified bug 45066 b");
         }
-        assertEquals(68, serializedSize);
+        assertEquals(90, serializedSize);
     }
 
     /**
@@ -502,5 +529,17 @@ public final class TestSheet extends TestCase {
         }
         assertEquals(1, count);
     }
+    
+    public void testMisplacedMergedCellsRecords_bug45699() {
+        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex45698-22488.xls");
+        
+        HSSFSheet sheet = wb.getSheetAt(0);
+        HSSFRow row = sheet.getRow(3);
+        HSSFCell cell = row.getCell(4);
+        if (cell == null) {
+            throw new AssertionFailedError("Identified bug 45699");
+        }
+        assertEquals("Informations", cell.getRichStringCellValue().getString());
+    }
 }
 
index cdf74cabb2b896727be120b9c33acbf38a42f49c..88b5477783c9a6e5bc470cc2f754306de63b508c 100644 (file)
@@ -29,23 +29,13 @@ import org.apache.poi.hssf.record.StringRecord;
  *
  * @author  avik
  */
-public class TestFormulaRecordAggregate extends junit.framework.TestCase {
+public final class TestFormulaRecordAggregate extends junit.framework.TestCase {
     
-    /** Creates a new instance of TestFormulaRecordAggregate */
-    public TestFormulaRecordAggregate(String arg) {
-        super(arg);
-    }
-    
-    public void testClone() {
+    public void testBasic() throws Exception {
         FormulaRecord f = new FormulaRecord();
         StringRecord s = new StringRecord();
+        s.setString("abc");
         FormulaRecordAggregate fagg = new FormulaRecordAggregate(f,s);
-        FormulaRecordAggregate newFagg = (FormulaRecordAggregate) fagg.clone();
-        assertTrue("objects are different", fagg!=newFagg);
-        assertTrue("deep clone", fagg.getFormulaRecord() != newFagg.getFormulaRecord());
-        assertTrue("deep clone",  fagg.getStringRecord() != newFagg.getStringRecord());
-
-        
+        assertEquals("abc", fagg.getStringValue());
     }
-    
 }
index 3464c407d01e7784b4f4d4a22b1f8a4866218eab..7ea2e85f436114f2951c25b97030b40d631ee017 100755 (executable)
@@ -17,8 +17,6 @@
 
 package org.apache.poi.hssf.record.aggregates;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -32,31 +30,27 @@ import junit.framework.TestCase;
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.hssf.record.BlankRecord;
 import org.apache.poi.hssf.record.FormulaRecord;
-import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordBase;
 import org.apache.poi.hssf.record.SharedFormulaRecord;
-import org.apache.poi.hssf.record.UnknownRecord;
-import org.apache.poi.hssf.record.WindowOneRecord;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 
-public class TestValueRecordsAggregate extends TestCase
-{
+public final class TestValueRecordsAggregate extends TestCase {
     private static final String ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE = "AbnormalSharedFormulaFlag.xls";
-    ValueRecordsAggregate valueRecord = new ValueRecordsAggregate();
+    private final ValueRecordsAggregate valueRecord = new ValueRecordsAggregate();
 
     /**
      * Make sure the shared formula DOESNT makes it to the FormulaRecordAggregate when being parsed
      * as part of the value records
      */
-    public void testSharedFormula()
-    {
+    public void testSharedFormula() {
         List records = new ArrayList();
         records.add( new FormulaRecord() );
         records.add( new SharedFormulaRecord() );
 
-        valueRecord.construct( 0, records );
+        constructValueRecord(records);
         Iterator iterator = valueRecord.getIterator();
-        Record record = (Record) iterator.next();
+        RecordBase record = (RecordBase) iterator.next();
         assertNotNull( "Row contains a value", record );
         assertTrue( "First record is a FormulaRecordsAggregate", ( record instanceof FormulaRecordAggregate ) );
         //Ensure that the SharedFormulaRecord has been converted
@@ -64,39 +58,25 @@ public class TestValueRecordsAggregate extends TestCase
 
     }
 
-    public void testUnknownRecordsIgnored()
-    {
-        List records = testData();
-        valueRecord.construct( 0, records );
-        Iterator iterator = valueRecord.getIterator();
-        Record record1 = (Record) iterator.next();
-        Record record2 = (Record) iterator.next();
-        assertNotNull( "No record found", record1 );
-        assertNotNull( "No record found", record2 );
-        assertFalse( iterator.hasNext() );
-
+    private void constructValueRecord(List records) {
+        SharedFormulaHolder sfrh = SharedFormulaHolder.create(records, 0, records.size());
+        valueRecord.construct(records, 0, records.size(), sfrh );
     }
 
-    private List testData(){
+    private static List testData() {
         List records = new ArrayList();
         FormulaRecord formulaRecord = new FormulaRecord();
-        UnknownRecord unknownRecord = new UnknownRecord();
         BlankRecord blankRecord = new BlankRecord();
-        WindowOneRecord windowOneRecord = new WindowOneRecord();
         formulaRecord.setRow( 1 );
         formulaRecord.setColumn( (short) 1 );
         blankRecord.setRow( 2 );
         blankRecord.setColumn( (short) 2 );
         records.add( formulaRecord );
-        records.add( unknownRecord );
         records.add( blankRecord );
-        records.add( windowOneRecord );
         return records;
     }
 
-    public void testInsertCell()
-            throws Exception
-    {
+    public void testInsertCell() {
         Iterator iterator = valueRecord.getIterator();
         assertFalse( iterator.hasNext() );
 
@@ -118,8 +98,7 @@ public class TestValueRecordsAggregate extends TestCase
         valueRecord.removeCell( blankRecord2 );
     }
 
-    public void testGetPhysicalNumberOfCells() throws Exception
-    {
+    public void testGetPhysicalNumberOfCells() {
         assertEquals(0, valueRecord.getPhysicalNumberOfCells());
         BlankRecord blankRecord1 = newBlankRecord();
         valueRecord.insertCell( blankRecord1 );
@@ -128,8 +107,7 @@ public class TestValueRecordsAggregate extends TestCase
         assertEquals(0, valueRecord.getPhysicalNumberOfCells());
     }
 
-    public void testGetFirstCellNum() throws Exception
-    {
+    public void testGetFirstCellNum() {
         assertEquals( -1, valueRecord.getFirstCellNum() );
         valueRecord.insertCell( newBlankRecord( 2, 2 ) );
         assertEquals( 2, valueRecord.getFirstCellNum() );
@@ -141,8 +119,7 @@ public class TestValueRecordsAggregate extends TestCase
         assertEquals( 2, valueRecord.getFirstCellNum() );
     }
 
-    public void testGetLastCellNum() throws Exception
-    {
+    public void testGetLastCellNum() {
         assertEquals( -1, valueRecord.getLastCellNum() );
         valueRecord.insertCell( newBlankRecord( 2, 2 ) );
         assertEquals( 2, valueRecord.getLastCellNum() );
@@ -155,8 +132,7 @@ public class TestValueRecordsAggregate extends TestCase
 
     }
 
-    public void testSerialize() throws Exception
-    {
+    public void testSerialize() {
         byte[] actualArray = new byte[36];
         byte[] expectedArray = new byte[]
         {
@@ -171,7 +147,7 @@ public class TestValueRecordsAggregate extends TestCase
             (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00,
         };
         List records = testData();
-        valueRecord.construct( 0, records );
+        constructValueRecord(records);
         int bytesWritten = valueRecord.serializeCellRow(1, 0, actualArray );
         bytesWritten += valueRecord.serializeCellRow(2, bytesWritten, actualArray );
         assertEquals( 36, bytesWritten );
@@ -179,18 +155,12 @@ public class TestValueRecordsAggregate extends TestCase
             assertEquals( expectedArray[i], actualArray[i] );
     }
 
-    public static void main( String[] args )
-    {
-        System.out.println( "Testing org.apache.poi.hssf.record.aggregates.TestValueRecordAggregate" );
-        junit.textui.TestRunner.run( TestValueRecordsAggregate.class );
-    }
-
-    private BlankRecord newBlankRecord()
+    private static BlankRecord newBlankRecord()
     {
         return newBlankRecord( 2, 2 );
     }
 
-    private BlankRecord newBlankRecord( int col, int row)
+    private static BlankRecord newBlankRecord( int col, int row)
     {
         BlankRecord blankRecord = new BlankRecord();
         blankRecord.setRow( row );
@@ -300,5 +270,4 @@ public class TestValueRecordsAggregate extends TestCase
         
         return crc.getValue();
     }
-
 }
index 7d1082e86156b73fb829da0df9b8a030eaed8aa9..d8b4e95212c46de5d95328ed0a4415cee8c712ad 100644 (file)
@@ -41,4 +41,19 @@ public final class TestLinkTable extends TestCase {
                
                assertEquals("ipcSummenproduktIntern($C5,N$2,$A$9,N$1)", formula);
        }
+       
+       public void testMultipleExternSheetRecords_bug45698() {
+               HSSFWorkbook wb;
+
+               try {
+                       wb = HSSFTestDataSamples.openSampleWorkbook("ex45698-22488.xls");
+               } catch (RuntimeException e) {
+                       if ("Extern sheet is part of LinkTable".equals(e.getMessage())) {
+                               throw new AssertionFailedError("Identified bug 45698");
+                       }
+                       throw e;
+               }
+               // some other sanity checks
+               assertEquals(7, wb.getNumberOfSheets());
+       }
 }