diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml
index bfc44a828f..3d49ffca0c 100644
--- a/src/documentation/content/xdocs/changes.xml
+++ b/src/documentation/content/xdocs/changes.xml
@@ -64,6 +64,8 @@
Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx
+ 45699 - Fix RowRecordsAggregate to tolerate intervening MERGEDCELLS records
+ 45698 - Fix LinkTable to tolerate multiple EXTERNSHEET records
45682 - Fix for cloning of CFRecordsAggregate
Initial support for evaluating external add-in functions like YEARFRAC
45672 - Fix for MissingRecordAwareHSSFListener to prevent multiple LastCellOfRowDummyRecords when shared formulas are present
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index 5ed54a515b..05475a52ee 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -61,6 +61,8 @@
Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx
+ 45699 - Fix RowRecordsAggregate to tolerate intervening MERGEDCELLS records
+ 45698 - Fix LinkTable to tolerate multiple EXTERNSHEET records
45682 - Fix for cloning of CFRecordsAggregate
Initial support for evaluating external add-in functions like YEARFRAC
45672 - Fix for MissingRecordAwareHSSFListener to prevent multiple LastCellOfRowDummyRecords when shared formulas are present
diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java
index 9d1707558d..a64f134fed 100755
--- a/src/java/org/apache/poi/hssf/model/LinkTable.java
+++ b/src/java/org/apache/poi/hssf/model/LinkTable.java
@@ -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();
diff --git a/src/java/org/apache/poi/hssf/model/RecordOrderer.java b/src/java/org/apache/poi/hssf/model/RecordOrderer.java
index 887497a911..291bd07715 100644
--- a/src/java/org/apache/poi/hssf/model/RecordOrderer.java
+++ b/src/java/org/apache/poi/hssf/model/RecordOrderer.java
@@ -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 true
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);
+ }
}
diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java
index 336b1dbd46..b5db343d8e 100644
--- a/src/java/org/apache/poi/hssf/model/Sheet.java
+++ b/src/java/org/apache/poi/hssf/model/Sheet.java
@@ -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 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;
diff --git a/src/java/org/apache/poi/hssf/record/BoolErrRecord.java b/src/java/org/apache/poi/hssf/record/BoolErrRecord.java
index f2b9d928ab..43bdda900c 100644
--- a/src/java/org/apache/poi/hssf/record/BoolErrRecord.java
+++ b/src/java/org/apache/poi/hssf/record/BoolErrRecord.java
@@ -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;
diff --git a/src/java/org/apache/poi/hssf/record/CellValueRecordInterface.java b/src/java/org/apache/poi/hssf/record/CellValueRecordInterface.java
index 1cc6b7ae79..4bbee79aec 100644
--- a/src/java/org/apache/poi/hssf/record/CellValueRecordInterface.java
+++ b/src/java/org/apache/poi/hssf/record/CellValueRecordInterface.java
@@ -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,13 +14,7 @@
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);
+ void setXFIndex(short xf);
- 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);
-
- public Object clone();
+ short getXFIndex();
}
diff --git a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
index 2b0744a91e..c4f00581b2 100644
--- a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
+++ b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
@@ -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 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()
{
diff --git a/src/java/org/apache/poi/hssf/record/LabelRecord.java b/src/java/org/apache/poi/hssf/record/LabelRecord.java
index c3fd5fb3dd..ae3b82f36f 100644
--- a/src/java/org/apache/poi/hssf/record/LabelRecord.java
+++ b/src/java/org/apache/poi/hssf/record/LabelRecord.java
@@ -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;
diff --git a/src/java/org/apache/poi/hssf/record/LabelSSTRecord.java b/src/java/org/apache/poi/hssf/record/LabelSSTRecord.java
index 610f85522d..a8d68bac2c 100644
--- a/src/java/org/apache/poi/hssf/record/LabelSSTRecord.java
+++ b/src/java/org/apache/poi/hssf/record/LabelSSTRecord.java
@@ -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;
diff --git a/src/java/org/apache/poi/hssf/record/NumberRecord.java b/src/java/org/apache/poi/hssf/record/NumberRecord.java
index b21e488ed7..eeb5cf62ad 100644
--- a/src/java/org/apache/poi/hssf/record/NumberRecord.java
+++ b/src/java/org/apache/poi/hssf/record/NumberRecord.java
@@ -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,13 +14,7 @@
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;
diff --git a/src/java/org/apache/poi/hssf/record/RKRecord.java b/src/java/org/apache/poi/hssf/record/RKRecord.java
index 4d30ddf4c9..2a99e16047 100644
--- a/src/java/org/apache/poi/hssf/record/RKRecord.java
+++ b/src/java/org/apache/poi/hssf/record/RKRecord.java
@@ -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;
diff --git a/src/java/org/apache/poi/hssf/record/UnknownRecord.java b/src/java/org/apache/poi/hssf/record/UnknownRecord.java
index d3e76a020f..851dbfbf55 100644
--- a/src/java/org/apache/poi/hssf/record/UnknownRecord.java
+++ b/src/java/org/apache/poi/hssf/record/UnknownRecord.java
@@ -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,10 +14,10 @@
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 {
-public class UnknownRecord
- extends Record
-{
- private short sid = 0;
- private byte[] thedata = null;
+ /*
+ * 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;
- 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;
- }
+ /**
+ * @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 interperated and the record will
- * be serialized in its original form more or less
- * @param in the RecordInputstream to read the record from
- */
+ /**
+ * 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());
+ }
+ }
- 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 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;
+ }
- /**
- * 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 final int getRecordSize() {
+ return 4 + _rawData.length;
+ }
- public int getRecordSize()
- {
- int retval = 4;
+ /**
+ * 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?
+ }
- if (thedata != null)
- {
- retval += thedata.length;
- }
- return retval;
- }
+ /**
+ * 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();
- protected void fillFields(byte [] data, short sid)
- {
- this.sid = sid;
- thedata = data;
- }
+ 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();
+ }
- /**
- * NO OP!
- */
+ public final short getSid() {
+ return (short) _sid;
+ }
- protected void validateSid(short id)
- {
+ /**
+ * 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";
- // if we had a valid sid we wouldn't be using the "Unknown Record" record now would we?
- }
+ 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";
- /**
- * print a sort of string representation ([UNKNOWN RECORD] id = x [/UNKNOWN RECORD])
- */
+ case 0x01C0: return "EXCEL9FILE";
- public String toString()
- {
- StringBuffer buffer = new StringBuffer();
+ case 0x0802: return "QSISXTAG";
+ case 0x0803: return "DBQUERYEXT";
+ case 0x0805: return "TXTQUERY";
- 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();
- }
+ 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";
- public short getSid()
- {
- return sid;
- }
+ case 0x08C8: return "PLV{Mac Excel}";
- /**
- * 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
- */
+ case 0x1051: return "SHAPEPROPSSTREAM";
- protected void fillFields(RecordInputStream in)
- {
- throw new RecordFormatException(
- "Unknown record cannot be constructed via offset -- we need a copy of the data");
- }
+ }
+ if (isObservedButUnknown(sid)) {
+ return "UNKNOWN-" + Integer.toHexString(sid).toUpperCase();
+ }
- /** 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;
- }
+ return null;
+ }
+
+ /**
+ *
+ * @return true
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 final Object clone() {
+ // immutable - ok to return this
+ return this;
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
index 7840d32562..3359ca55a4 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
@@ -15,10 +15,11 @@
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;
+ _formulaRecord = formulaRecord;
+ _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;
-
- }
-
- /**
- * 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);
- }
-
- /*
- * 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 void visitContainedRecords(RecordVisitor rv) {
+ rv.visitRecord(_formulaRecord);
+ if (_stringRecord != null) {
+ rv.visitRecord(_stringRecord);
+ }
+ }
+
+ public String getStringValue() {
+ if(_stringRecord==null) {
+ return null;
+ }
+ return _stringRecord.getString();
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java b/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
index b7384a0194..6a457fe48e 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
@@ -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) {
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java b/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
index cc8be41791..819940e12e 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
@@ -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;
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
index c9a302b614..d839ecfab6 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
@@ -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; iRowRecordsAggregate
+ *
+ * @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 SharedFormulaRecords 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 SharedFormulaRecord.convertSharedFormulaRecord and hence the
+ * parsedExpression field of this FormulaRecord will not get updated.
+ * As it turns out, this is not a problem, because in these circumstances, the existing value
+ * for parsedExpression is perfectly OK.
+ *
+ * This method may also be used for setting breakpoints to help diagnose issues regarding the
+ * abnormally-set 'shared formula' flags.
+ * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).
+ *
+ * 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.
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
index 8d5764187f..0db1201432 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
@@ -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++)
- {
- Record rec = ( Record ) records.get(k);
- if (rec instanceof SharedFormulaRecord) {
- sharedFormulas.add(rec);
- }
- if(rec instanceof EOFRecord) {
- // End of current sheet. Ignore all subsequent shared formula records (Bugzilla 44449)
- break;
- }
- }
-
// Now do the main processing sweep
- for (k = offset; k < records.size(); k++)
- {
+ for (k = offset; k < endIx; k++) {
Record rec = ( Record ) records.get(k);
- if (rec instanceof StringRecord == false && !rec.isInValueSection() && !(rec instanceof UnknownRecord))
- {
- 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 (rec instanceof StringRecord) {
+ if (lastFormulaAggregate == null) {
+ throw new RuntimeException("StringRecord found without preceding FormulaRecord");
}
- if (!found) {
- handleMissingSharedFormulaRecord(formula);
+ if (lastFormulaAggregate.getStringRecord() != null) {
+ throw new RuntimeException("Multiple StringRecords found after FormulaRecord");
}
- }
-
- lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null);
- insertCell( lastFormulaAggregate );
- }
- else if (rec instanceof StringRecord)
- {
lastFormulaAggregate.setStringRecord((StringRecord)rec);
+ lastFormulaAggregate = null;
+ continue;
}
- else if (rec.isValue())
- {
- insertCell(( CellValueRecordInterface ) rec);
+
+ 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) {
+ // Already handled, not to worry
+ continue;
+ }
+
+ if (rec instanceof UnknownRecord) {
+ break;
+ }
+ if (rec instanceof RowRecord) {
+ break;
+ }
+ if (rec instanceof DBCellRecord) {
+ // end of 'Row Block'. This record is ignored by POI
+ break;
+ }
+ 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");
+ }
+ 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 SharedFormulaRecord.convertSharedFormulaRecord and hence the
- * parsedExpression field of this FormulaRecord will not get updated.
- * As it turns out, this is not a problem, because in these circumstances, the existing value
- * for parsedExpression is perfectly OK.
- *
- * This method may also be used for setting breakpoints to help diagnose issues regarding the
- * abnormally-set 'shared formula' flags.
- * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).
- *
- * 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;
diff --git a/src/java/org/apache/poi/hssf/record/formula/TblPtg.java b/src/java/org/apache/poi/hssf/record/formula/TblPtg.java
index 05d8391b29..9cc7334605 100644
--- a/src/java/org/apache/poi/hssf/record/formula/TblPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/TblPtg.java
@@ -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 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 TblPtg(RecordInputStream in) {
+ field_1_first_row = in.readUShort();
+ field_2_first_col = in.readUShort();
}
- public int getSize()
- {
+ 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() {
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();
- }
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
index f66baf3024..7f8f7aa3b9 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
@@ -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
index 0000000000..615e6c5d8c
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/ex45698-22488.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
index 6c6dd9fb25..97635e5362 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
@@ -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());
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
index cdf74cabb2..88b5477783 100644
--- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
+++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
@@ -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());
}
-
}
diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java
index 3464c407d0..7ea2e85f43 100755
--- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java
+++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java
@@ -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();
}
-
}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java b/src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java
index 7d1082e861..d8b4e95212 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java
@@ -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());
+ }
}