Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-659571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675726,675728-675733,675735-675775,675777-675782,675784,675786-675791,675794-675852,675854-676200,676202,676204,676206-676220,676222-676309,676311-676456,676458-676994,676996-677027,677030-677040,677042-677056,677058-677375,677377-677968,677970-677971,677973,677975-677994,677996-678286,678288-678538,678540-680393,680395-680469,680471-680529,680531-680852,680854-681529,681531-681571,681573-682224,682226,682228,682231-682281,682283-682335,682337-682507,682509,682512-682517,682519-682532,682534-682619,682622-682777,682779-682998,683000-683019,683021-683022,683024-683080,683082-683092,683094-683095,683097-683127,683129-683131,683133-683166,683168-683698,683700-683705,683707-683757,683759-683787,683789-683870,683872-683879,683881-683900,683902-684066,684068-684074,684076-684222,684224-684254,684257-684281,684283-684286,684288-684292,684294-684298,684300-684301,684303-684308,684310-684317,684320,684323-684335,684337-684348,684350-684354,684356-684361,684363-684369,684371-684453,684455-684883,684885-684937,684940-684958,684960-684970,684972-684985,684987-685053,685055-685063,685065-685259,685261-685262,685264-685266,685268-685282,685285-686035,686037-686045,686047-686052,686054-686206,686208-686215,686217-686277,686279-686289,686291-686620,686622-686623,686626-686627,686629-686639,686641-686843,686845-686976,686978-687402,687404-687422,687424-687428,687430-687442,687444-688425,688427-688641,688643-688649,688651-688654,688656-688824,688826-688909,688911-689779 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r689544 | josh | 2008-08-27 19:13:46 +0100 (Wed, 27 Aug 2008) | 1 line Fixed size of TblPtg ........ r689559 | josh | 2008-08-27 19:51:03 +0100 (Wed, 27 Aug 2008) | 1 line added names of known but uniterpreted BIFF records ........ r689636 | josh | 2008-08-27 22:54:20 +0100 (Wed, 27 Aug 2008) | 1 line should have been submitted with c689559 ........ r689704 | josh | 2008-08-28 03:54:47 +0100 (Thu, 28 Aug 2008) | 1 line Fix for bug 45698 - allow LinkTable to read EXTERNSHEET records ........ r689716 | josh | 2008-08-28 05:27:41 +0100 (Thu, 28 Aug 2008) | 1 line Fix for bug 45699 - RowRecordsAggregate needs to tolerate MergeCellsRecords between row/cell records ........ r689719 | josh | 2008-08-28 06:13:31 +0100 (Thu, 28 Aug 2008) | 1 line Should have been submitted with c689716 (bug 45699) ........ r689721 | josh | 2008-08-28 06:25:24 +0100 (Thu, 28 Aug 2008) | 1 line Removed unused methods from CellValueRecordInterface. Converted FormulaRecordAggregate to RecordAggregate subclass ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@689811 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7df799556d
commit
0f9e14a4b0
@ -64,6 +64,8 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">45699 - Fix RowRecordsAggregate to tolerate intervening MERGEDCELLS records</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45698 - Fix LinkTable to tolerate multiple EXTERNSHEET records</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45682 - Fix for cloning of CFRecordsAggregate</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Initial support for evaluating external add-in functions like YEARFRAC</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45672 - Fix for MissingRecordAwareHSSFListener to prevent multiple LastCellOfRowDummyRecords when shared formulas are present</action>
|
||||
|
@ -61,6 +61,8 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.1.1-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">45699 - Fix RowRecordsAggregate to tolerate intervening MERGEDCELLS records</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45698 - Fix LinkTable to tolerate multiple EXTERNSHEET records</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45682 - Fix for cloning of CFRecordsAggregate</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Initial support for evaluating external add-in functions like YEARFRAC</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45672 - Fix for MissingRecordAwareHSSFListener to prevent multiple LastCellOfRowDummyRecords when shared formulas are present</action>
|
||||
|
@ -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();
|
||||
|
@ -22,16 +22,20 @@ import java.util.List;
|
||||
import org.apache.poi.hssf.record.BOFRecord;
|
||||
import org.apache.poi.hssf.record.CalcCountRecord;
|
||||
import org.apache.poi.hssf.record.CalcModeRecord;
|
||||
import org.apache.poi.hssf.record.DVALRecord;
|
||||
import org.apache.poi.hssf.record.DateWindow1904Record;
|
||||
import org.apache.poi.hssf.record.DefaultRowHeightRecord;
|
||||
import org.apache.poi.hssf.record.DeltaRecord;
|
||||
import org.apache.poi.hssf.record.DimensionsRecord;
|
||||
import org.apache.poi.hssf.record.DrawingRecord;
|
||||
import org.apache.poi.hssf.record.DrawingSelectionRecord;
|
||||
import org.apache.poi.hssf.record.EOFRecord;
|
||||
import org.apache.poi.hssf.record.GridsetRecord;
|
||||
import org.apache.poi.hssf.record.GutsRecord;
|
||||
import org.apache.poi.hssf.record.HyperlinkRecord;
|
||||
import org.apache.poi.hssf.record.IndexRecord;
|
||||
import org.apache.poi.hssf.record.IterationRecord;
|
||||
import org.apache.poi.hssf.record.ObjRecord;
|
||||
import org.apache.poi.hssf.record.PaneRecord;
|
||||
import org.apache.poi.hssf.record.PrecisionRecord;
|
||||
import org.apache.poi.hssf.record.PrintGridlinesRecord;
|
||||
@ -42,7 +46,10 @@ import org.apache.poi.hssf.record.RefModeRecord;
|
||||
import org.apache.poi.hssf.record.SCLRecord;
|
||||
import org.apache.poi.hssf.record.SaveRecalcRecord;
|
||||
import org.apache.poi.hssf.record.SelectionRecord;
|
||||
import org.apache.poi.hssf.record.TextObjectRecord;
|
||||
import org.apache.poi.hssf.record.UncalcedRecord;
|
||||
import org.apache.poi.hssf.record.UnknownRecord;
|
||||
import org.apache.poi.hssf.record.WindowOneRecord;
|
||||
import org.apache.poi.hssf.record.WindowTwoRecord;
|
||||
import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
|
||||
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
|
||||
@ -57,8 +64,6 @@ import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
||||
* @author Josh Micich
|
||||
*/
|
||||
final class RecordOrderer {
|
||||
// TODO - add UninterpretedRecord as base class for many of these
|
||||
// unimplemented sids
|
||||
|
||||
// TODO - simplify logic using a generalised record ordering
|
||||
|
||||
@ -126,7 +131,7 @@ final class RecordOrderer {
|
||||
case PrintGridlinesRecord.sid:
|
||||
case GridsetRecord.sid:
|
||||
case DefaultRowHeightRecord.sid:
|
||||
case 0x0081: // SHEETPR
|
||||
case UnknownRecord.SHEETPR_0081:
|
||||
return true;
|
||||
// next is the 'Worksheet Protection Block'
|
||||
}
|
||||
@ -149,10 +154,10 @@ final class RecordOrderer {
|
||||
case SCLRecord.sid:
|
||||
case PaneRecord.sid:
|
||||
case SelectionRecord.sid:
|
||||
case 0x0099:// STANDARDWIDTH
|
||||
case UnknownRecord.STANDARDWIDTH_0099:
|
||||
// MergedCellsTable usually here
|
||||
case 0x015f:// LABELRANGES
|
||||
case 0x00ef:// PHONETICPR
|
||||
case UnknownRecord.LABELRANGES_015F:
|
||||
case UnknownRecord.PHONETICPR_00EF:
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
@ -162,13 +167,20 @@ final class RecordOrderer {
|
||||
private static int findInsertPosForNewMergedRecordTable(List records) {
|
||||
for (int i = records.size() - 2; i >= 0; i--) { // -2 to skip EOF record
|
||||
Object rb = records.get(i);
|
||||
if (!(rb instanceof Record)) {
|
||||
// DataValidityTable, ConditionalFormattingTable,
|
||||
// even PageSettingsBlock (which doesn't normally appear after 'View Settings')
|
||||
continue;
|
||||
}
|
||||
Record rec = (Record) rb;
|
||||
switch (rec.getSid()) {
|
||||
// 'View Settings' (4 records)
|
||||
case WindowTwoRecord.sid:
|
||||
case SCLRecord.sid:
|
||||
case PaneRecord.sid:
|
||||
case SelectionRecord.sid:
|
||||
case 0x0099:// STANDARDWIDTH
|
||||
|
||||
case UnknownRecord.STANDARDWIDTH_0099:
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
@ -229,16 +241,16 @@ final class RecordOrderer {
|
||||
short sid = ((Record)rb).getSid();
|
||||
switch(sid) {
|
||||
case WindowTwoRecord.sid:
|
||||
case 0x00A0: // SCL
|
||||
case UnknownRecord.SCL_00A0:
|
||||
case PaneRecord.sid:
|
||||
case SelectionRecord.sid:
|
||||
case 0x0099: // STANDARDWIDTH
|
||||
case UnknownRecord.STANDARDWIDTH_0099:
|
||||
// MergedCellsTable
|
||||
case 0x015F: // LABELRANGES
|
||||
case 0x00EF: // PHONETICPR
|
||||
case UnknownRecord.LABELRANGES_015F:
|
||||
case UnknownRecord.PHONETICPR_00EF:
|
||||
// ConditionalFormattingTable
|
||||
case HyperlinkRecord.sid:
|
||||
case 0x0800: // QUICKTIP
|
||||
case UnknownRecord.QUICKTIP_0800:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -246,9 +258,9 @@ final class RecordOrderer {
|
||||
|
||||
private static boolean isDVTSubsequentRecord(short sid) {
|
||||
switch(sid) {
|
||||
case 0x0862: // SHEETLAYOUT
|
||||
case 0x0867: // SHEETPROTECTION
|
||||
case 0x0868: // RANGEPROTECTION
|
||||
case UnknownRecord.SHEETEXT_0862:
|
||||
case UnknownRecord.SHEETPROTECTION_0867:
|
||||
case UnknownRecord.RANGEPROTECTION_0868:
|
||||
case EOFRecord.sid:
|
||||
return true;
|
||||
}
|
||||
@ -307,4 +319,29 @@ final class RecordOrderer {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @return <code>true</code> if the specified record ID terminates a sequence of Row block records
|
||||
* It is assumed that at least one row or cell value record has been found prior to the current
|
||||
* record
|
||||
*/
|
||||
public static boolean isEndOfRowBlock(short sid) {
|
||||
switch(sid) {
|
||||
case DrawingRecord.sid:
|
||||
case DrawingSelectionRecord.sid:
|
||||
case ObjRecord.sid:
|
||||
case TextObjectRecord.sid:
|
||||
|
||||
case WindowOneRecord.sid:
|
||||
// should really be part of workbook stream, but some apps seem to put this before WINDOW2
|
||||
case WindowTwoRecord.sid:
|
||||
return true;
|
||||
|
||||
case DVALRecord.sid:
|
||||
return true;
|
||||
case EOFRecord.sid:
|
||||
// WINDOW2 should always be present, so shouldn't have got this far
|
||||
throw new RuntimeException("Found EOFRecord before WindowTwoRecord was encountered");
|
||||
}
|
||||
return PageSettingsBlock.isComponentRecord(sid);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
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");
|
||||
}
|
||||
int lastRowCellRec = findEndOfRowBlock(inRecs, k, retval._mergedCellsTable);
|
||||
retval._rowsAggregate = new RowRecordsAggregate(inRecs, k, lastRowCellRec);
|
||||
records.add(retval._rowsAggregate); //only add the aggregate once
|
||||
}
|
||||
retval._rowsAggregate.insertRow(row);
|
||||
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 );
|
||||
}
|
||||
k = lastRowCellRec -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PageSettingsBlock.isComponentRecord(rec.getSid())) {
|
||||
RecordStream rs = new RecordStream(recs, k);
|
||||
RecordStream rs = new RecordStream(inRecs, k);
|
||||
PageSettingsBlock psb = new PageSettingsBlock(rs);
|
||||
if (bofEofNestingLevel == 1) {
|
||||
if (retval._psBlock == null) {
|
||||
@ -253,9 +245,10 @@ public final class Sheet implements Model {
|
||||
}
|
||||
|
||||
if (rec.getSid() == MergeCellsRecord.sid) {
|
||||
RecordStream rs = new RecordStream(recs, k);
|
||||
retval._mergedCellsTable = new MergedCellsTable(rs);
|
||||
records.add(retval._mergedCellsTable);
|
||||
// when the MergedCellsTable is found in the right place, we expect those records to be contiguous
|
||||
RecordStream rs = new RecordStream(inRecs, k);
|
||||
retval._mergedCellsTable.read(rs);
|
||||
k += rs.getCountRead()-1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -337,6 +330,11 @@ public final class Sheet implements Model {
|
||||
if (retval._dimensions == null) {
|
||||
throw new RuntimeException("DimensionsRecord was not found");
|
||||
}
|
||||
if (retval.windowTwo == null) {
|
||||
throw new RuntimeException("WINDOW2 was not found");
|
||||
}
|
||||
// put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */
|
||||
RecordOrderer.addNewSheetRecord(records, retval._mergedCellsTable);
|
||||
retval.records = records;
|
||||
retval.checkRows();
|
||||
if (log.check( POILogger.DEBUG ))
|
||||
@ -344,6 +342,26 @@ public final class Sheet implements Model {
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Also collects any rogue MergeCellRecords
|
||||
* @return the index one after the last row/cell record
|
||||
*/
|
||||
private static int findEndOfRowBlock(List recs, int startIx, MergedCellsTable mergedCellsTable) {
|
||||
for(int i=startIx; i<recs.size(); i++) {
|
||||
Record rec = (Record) recs.get(i);
|
||||
if (RecordOrderer.isEndOfRowBlock(rec.getSid())) {
|
||||
return i;
|
||||
}
|
||||
if (rec.getSid() == MergeCellsRecord.sid) {
|
||||
// Some apps scatter these records between the rows/cells but they are supposed to
|
||||
// be well after the row/cell records. We collect them here
|
||||
// see bug 45699
|
||||
mergedCellsTable.add((MergeCellsRecord) rec);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Failed to find end of row/cell records");
|
||||
}
|
||||
|
||||
private static final class RecordCloner implements RecordVisitor {
|
||||
|
||||
private final List _destList;
|
||||
@ -447,9 +465,12 @@ public final class Sheet implements Model {
|
||||
retval._dimensions = createDimensions();
|
||||
records.add(retval._dimensions);
|
||||
retval.dimsloc = records.size()-1;
|
||||
// 'Sheet View Settings'
|
||||
records.add(retval.windowTwo = retval.createWindowTwo());
|
||||
retval.selection = createSelection();
|
||||
records.add(retval.selection);
|
||||
|
||||
records.add(retval._mergedCellsTable); // MCT comes after 'Sheet View Settings'
|
||||
records.add(EOFRecord.instance);
|
||||
|
||||
|
||||
@ -468,11 +489,7 @@ public final class Sheet implements Model {
|
||||
}
|
||||
}
|
||||
private MergedCellsTable getMergedRecords() {
|
||||
if (_mergedCellsTable == null) {
|
||||
MergedCellsTable mct = new MergedCellsTable();
|
||||
RecordOrderer.addNewSheetRecord(records, mct);
|
||||
_mergedCellsTable = mct;
|
||||
}
|
||||
// always present
|
||||
return _mergedCellsTable;
|
||||
}
|
||||
|
||||
@ -872,7 +889,7 @@ public final class Sheet implements Model {
|
||||
/**
|
||||
* creates the BOF record
|
||||
*/
|
||||
private static BOFRecord createBOF() {
|
||||
/* package */ static BOFRecord createBOF() {
|
||||
BOFRecord retval = new BOFRecord();
|
||||
|
||||
retval.setVersion(( short ) 0x600);
|
||||
|
@ -34,13 +34,8 @@ import org.apache.poi.util.LittleEndian;
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
|
||||
public class BlankRecord
|
||||
extends Record
|
||||
implements CellValueRecordInterface, Comparable
|
||||
{
|
||||
public final class BlankRecord extends Record implements CellValueRecordInterface {
|
||||
public final static short sid = 0x201;
|
||||
//private short field_1_row;
|
||||
private int field_1_row;
|
||||
private short field_2_col;
|
||||
private short field_3_xf;
|
||||
@ -152,50 +147,6 @@ public class BlankRecord
|
||||
field_2_col = col;
|
||||
}
|
||||
|
||||
public boolean isBefore(CellValueRecordInterface i)
|
||||
{
|
||||
if (this.getRow() > i.getRow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() > i.getColumn()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() == i.getColumn()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAfter(CellValueRecordInterface i)
|
||||
{
|
||||
if (this.getRow() < i.getRow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() < i.getColumn()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() == i.getColumn()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isEqual(CellValueRecordInterface i)
|
||||
{
|
||||
return ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() == i.getColumn()));
|
||||
}
|
||||
|
||||
public boolean isInValueSection()
|
||||
{
|
||||
return true;
|
||||
@ -254,50 +205,6 @@ public class BlankRecord
|
||||
return 10;
|
||||
}
|
||||
|
||||
public int compareTo(Object obj)
|
||||
{
|
||||
CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
|
||||
|
||||
if ((this.getRow() == loc.getRow())
|
||||
&& (this.getColumn() == loc.getColumn()))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (this.getRow() < loc.getRow())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (this.getRow() > loc.getRow())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (this.getColumn() < loc.getColumn())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (this.getColumn() > loc.getColumn())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (!(obj instanceof CellValueRecordInterface))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
CellValueRecordInterface loc = ( CellValueRecordInterface ) obj;
|
||||
|
||||
if ((this.getRow() == loc.getRow())
|
||||
&& (this.getColumn() == loc.getColumn()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
BlankRecord rec = new BlankRecord();
|
||||
rec.field_1_row = field_1_row;
|
||||
|
@ -33,13 +33,8 @@ 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 short field_2_column;
|
||||
private short field_3_xf_index;
|
||||
@ -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;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,12 +15,6 @@
|
||||
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();
|
||||
}
|
||||
|
@ -260,4 +260,16 @@ public class ExternSheetRecord extends Record {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static ExternSheetRecord combine(ExternSheetRecord[] esrs) {
|
||||
ExternSheetRecord result = new ExternSheetRecord();
|
||||
for (int i = 0; i < esrs.length; i++) {
|
||||
ExternSheetRecord esr = esrs[i];
|
||||
int nRefs = esr.getNumOfREFRecords();
|
||||
for (int j=0; j<nRefs; j++) {
|
||||
result.addREFRecord(esr.getRef(j));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -32,10 +32,7 @@ import org.apache.poi.util.LittleEndian;
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
* @version 2.0-pre
|
||||
*/
|
||||
public final class FormulaRecord
|
||||
extends Record
|
||||
implements CellValueRecordInterface, Comparable
|
||||
{
|
||||
public final class FormulaRecord extends Record implements CellValueRecordInterface {
|
||||
|
||||
public static final short sid = 0x0006; // docs say 406...because of a bug Microsoft support site article #Q184647)
|
||||
|
||||
@ -380,50 +377,6 @@ public final class FormulaRecord
|
||||
return retval;
|
||||
}
|
||||
|
||||
public boolean isBefore(CellValueRecordInterface i)
|
||||
{
|
||||
if (this.getRow() > i.getRow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() > i.getColumn()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() == i.getColumn()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAfter(CellValueRecordInterface i)
|
||||
{
|
||||
if (this.getRow() < i.getRow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() < i.getColumn()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() == i.getColumn()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isEqual(CellValueRecordInterface i)
|
||||
{
|
||||
return ((this.getRow() == i.getRow())
|
||||
&& (this.getColumn() == i.getColumn()));
|
||||
}
|
||||
|
||||
public boolean isInValueSection()
|
||||
{
|
||||
return true;
|
||||
@ -434,51 +387,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()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
@ -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;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,7 +15,6 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
@ -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;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,12 +15,6 @@
|
||||
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;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,7 +15,6 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.hssf.util.RKUtil;
|
||||
@ -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;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
@ -16,9 +15,9 @@
|
||||
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;
|
||||
|
||||
public UnknownRecord()
|
||||
{
|
||||
}
|
||||
private int _sid;
|
||||
private byte[] _rawData;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
public UnknownRecord(int id, byte[] data) {
|
||||
_sid = id & 0xFFFF;
|
||||
_rawData = data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* construct an unknown record. No fields are interperated and the record will
|
||||
* construct an unknown record. No fields are interpreted and the record will
|
||||
* be serialized in its original form more or less
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
|
||||
public UnknownRecord(RecordInputStream in)
|
||||
{
|
||||
sid = in.getSid();
|
||||
thedata = in.readRemainder();
|
||||
|
||||
//System.out.println("UnknownRecord: 0x"+Integer.toHexString(sid));
|
||||
public UnknownRecord(RecordInputStream in) {
|
||||
_sid = in.getSid();
|
||||
_rawData = in.readRemainder();
|
||||
if (false && getBiffName(_sid) == null) {
|
||||
// unknown sids in the range 0x0004-0x0013 are probably 'sub-records' of ObjectRecord
|
||||
// those sids are in a different number space.
|
||||
// TODO - put unknown OBJ sub-records in a different class
|
||||
System.out.println("Unknown record 0x" + Integer.toHexString(_sid).toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* spit the record out AS IS. no interpretation or identification
|
||||
*/
|
||||
public 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 serialize(int offset, byte[] data) {
|
||||
LittleEndian.putUShort(data, 0 + offset, _sid);
|
||||
int dataSize = _rawData.length;
|
||||
LittleEndian.putUShort(data, 2 + offset, dataSize);
|
||||
System.arraycopy(_rawData, 0, data, 4 + offset, dataSize);
|
||||
return 4 + dataSize;
|
||||
}
|
||||
|
||||
public int getRecordSize()
|
||||
{
|
||||
int retval = 4;
|
||||
|
||||
if (thedata != null)
|
||||
{
|
||||
retval += thedata.length;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
protected void fillFields(byte [] data, short sid)
|
||||
{
|
||||
this.sid = sid;
|
||||
thedata = data;
|
||||
public final int getRecordSize() {
|
||||
return 4 + _rawData.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* NO OP!
|
||||
*/
|
||||
|
||||
protected void validateSid(short id)
|
||||
{
|
||||
|
||||
protected void validateSid(short id) {
|
||||
// if we had a valid sid we wouldn't be using the "Unknown Record" record now would we?
|
||||
}
|
||||
|
||||
/**
|
||||
* print a sort of string representation ([UNKNOWN RECORD] id = x [/UNKNOWN RECORD])
|
||||
*/
|
||||
public final String toString() {
|
||||
String biffName = getBiffName(_sid);
|
||||
if (biffName == null) {
|
||||
biffName = "UNKNOWNRECORD";
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[UNKNOWN RECORD:" + Integer.toHexString(sid) + "]\n");
|
||||
buffer.append(" .id = ").append(Integer.toHexString(sid))
|
||||
.append("\n");
|
||||
buffer.append("[/UNKNOWN RECORD]\n");
|
||||
return buffer.toString();
|
||||
sb.append("[").append(biffName).append("] (0x");
|
||||
sb.append(Integer.toHexString(_sid).toUpperCase() + ")\n");
|
||||
if (_rawData.length > 0) {
|
||||
sb.append(" rawData=").append(HexDump.toHex(_rawData)).append("\n");
|
||||
}
|
||||
sb.append("[/").append(biffName).append("]\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public short getSid()
|
||||
{
|
||||
return sid;
|
||||
public final short getSid() {
|
||||
return (short) _sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* called by the constructor, should set class level fields. Should throw
|
||||
* runtime exception for bad/icomplete data.
|
||||
* These BIFF record types are known but still uninterpreted by POI
|
||||
*
|
||||
* @param in the RecordInputstream to read the record from
|
||||
* @return the documented name of this BIFF record type
|
||||
*/
|
||||
private static String getBiffName(int sid) {
|
||||
// Note to POI developers:
|
||||
// Make sure you delete the corresponding entry from
|
||||
// this method any time a new Record subclass is created.
|
||||
switch (sid) {
|
||||
case PLS_004D: return "PLS";
|
||||
case 0x0050: return "DCON";
|
||||
case 0x007F: return "IMDATA";
|
||||
case SHEETPR_0081: return "SHEETPR";
|
||||
case 0x0090: return "SORT";
|
||||
case 0x0094: return "LHRECORD";
|
||||
case STANDARDWIDTH_0099: return "STANDARDWIDTH";
|
||||
case 0x009D: return "AUTOFILTERINFO";
|
||||
case SCL_00A0: return "SCL";
|
||||
case 0x00AE: return "SCENMAN";
|
||||
case 0x00D3: return "OBPROJ";
|
||||
case 0x00DC: return "PARAMQRY";
|
||||
case 0x00DE: return "OLESIZE";
|
||||
case BITMAP_00E9: return "BITMAP";
|
||||
case PHONETICPR_00EF: return "PHONETICPR";
|
||||
|
||||
protected void fillFields(RecordInputStream in)
|
||||
{
|
||||
case LABELRANGES_015F: return "LABELRANGES";
|
||||
case 0x01BA: return "CODENAME";
|
||||
case 0x01A9: return "USERBVIEW";
|
||||
case 0x01AA: return "USERSVIEWBEGIN";
|
||||
case 0x01AB: return "USERSVIEWEND";
|
||||
case 0x01AD: return "QSI";
|
||||
|
||||
case 0x01C0: return "EXCEL9FILE";
|
||||
|
||||
case 0x0802: return "QSISXTAG";
|
||||
case 0x0803: return "DBQUERYEXT";
|
||||
case 0x0805: return "TXTQUERY";
|
||||
|
||||
case QUICKTIP_0800: return "QUICKTIP";
|
||||
case 0x0850: return "CHARTFRTINFO";
|
||||
case 0x0852: return "STARTBLOCK";
|
||||
case 0x0853: return "ENDBLOCK";
|
||||
case 0x0856: return "CATLAB";
|
||||
case SHEETEXT_0862: return "SHEETEXT";
|
||||
case 0x0863: return "BOOKEXT";
|
||||
case SHEETPROTECTION_0867: return "SHEETPROTECTION";
|
||||
case RANGEPROTECTION_0868: return "RANGEPROTECTION";
|
||||
case 0x086B: return "DATALABEXTCONTENTS";
|
||||
case 0x086C: return "CELLWATCH";
|
||||
case 0x0874: return "DROPDOWNOBJIDS";
|
||||
case 0x0876: return "DCONN";
|
||||
case 0x087B: return "CFEX";
|
||||
case 0x087C: return "XFCRC";
|
||||
case 0x087D: return "XFEXT";
|
||||
case 0x088B: return "PLV";
|
||||
case 0x088C: return "COMPAT12";
|
||||
case 0x088D: return "DXF";
|
||||
case 0x088E: return "TABLESTYLES";
|
||||
case 0x0892: return "STYLEEXT";
|
||||
case 0x0896: return "THEME";
|
||||
case 0x0897: return "GUIDTYPELIB";
|
||||
case 0x089A: return "MTRSETTINGS";
|
||||
case 0x089B: return "COMPRESSPICTURES";
|
||||
case 0x089C: return "HEADERFOOTER";
|
||||
case 0x08A3: return "FORCEFULLCALCULATION";
|
||||
case 0x08A4: return "SHAPEPROPSSTREAM";
|
||||
case 0x08A5: return "TEXTPROPSSTREAM";
|
||||
case 0x08A6: return "RICHTEXTSTREAM";
|
||||
|
||||
case 0x08C8: return "PLV{Mac Excel}";
|
||||
|
||||
case 0x1051: return "SHAPEPROPSSTREAM";
|
||||
|
||||
}
|
||||
if (isObservedButUnknown(sid)) {
|
||||
return "UNKNOWN-" + Integer.toHexString(sid).toUpperCase();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <code>true</code> if the unknown record id has been observed in POI unit tests
|
||||
*/
|
||||
private static boolean isObservedButUnknown(int sid) {
|
||||
switch (sid) {
|
||||
case 0x0033:
|
||||
// contains 2 bytes of data: 0x0001 or 0x0003
|
||||
case 0x0034:
|
||||
// Seems to be written by MSAccess
|
||||
// contains text "[Microsoft JET Created Table]0021010"
|
||||
// appears after last cell value record and before WINDOW2
|
||||
case 0x01BD:
|
||||
case 0x01C2:
|
||||
// Written by Excel 2007
|
||||
// rawData is multiple of 12 bytes long
|
||||
// appears after last cell value record and before WINDOW2 or drawing records
|
||||
case 0x089D:
|
||||
case 0x089E:
|
||||
case 0x08A7:
|
||||
|
||||
case 0x1001:
|
||||
case 0x1006:
|
||||
case 0x1007:
|
||||
case 0x1009:
|
||||
case 0x100A:
|
||||
case 0x100B:
|
||||
case 0x100C:
|
||||
case 0x1014:
|
||||
case 0x1017:
|
||||
case 0x1018:
|
||||
case 0x1019:
|
||||
case 0x101A:
|
||||
case 0x101B:
|
||||
case 0x101D:
|
||||
case 0x101E:
|
||||
case 0x101F:
|
||||
case 0x1020:
|
||||
case 0x1021:
|
||||
case 0x1022:
|
||||
case 0x1024:
|
||||
case 0x1025:
|
||||
case 0x1026:
|
||||
case 0x1027:
|
||||
case 0x1032:
|
||||
case 0x1033:
|
||||
case 0x1034:
|
||||
case 0x1035:
|
||||
case 0x103A:
|
||||
case 0x1041:
|
||||
case 0x1043:
|
||||
case 0x1044:
|
||||
case 0x1045:
|
||||
case 0x1046:
|
||||
case 0x104A:
|
||||
case 0x104B:
|
||||
case 0x104E:
|
||||
case 0x104F:
|
||||
case 0x1051:
|
||||
case 0x105C:
|
||||
case 0x105D:
|
||||
case 0x105F:
|
||||
case 0x1060:
|
||||
case 0x1062:
|
||||
case 0x1063:
|
||||
case 0x1064:
|
||||
case 0x1065:
|
||||
case 0x1066:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected final void fillFields(RecordInputStream in) {
|
||||
throw new RecordFormatException(
|
||||
"Unknown record cannot be constructed via offset -- we need a copy of the data");
|
||||
}
|
||||
|
||||
/** Unlike the other Record.clone methods this is a shallow clone*/
|
||||
public Object clone() {
|
||||
UnknownRecord rec = new UnknownRecord();
|
||||
rec.sid = sid;
|
||||
rec.thedata = thedata;
|
||||
return rec;
|
||||
public final Object clone() {
|
||||
// immutable - ok to return this
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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 );
|
||||
return _stringRecord;
|
||||
}
|
||||
|
||||
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 void visitContainedRecords(RecordVisitor rv) {
|
||||
rv.visitRecord(_formulaRecord);
|
||||
if (_stringRecord != null) {
|
||||
rv.visitRecord(_stringRecord);
|
||||
}
|
||||
|
||||
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();
|
||||
if(_stringRecord==null) {
|
||||
return null;
|
||||
}
|
||||
return _stringRecord.getString();
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -26,8 +26,10 @@ import java.util.TreeMap;
|
||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||
import org.apache.poi.hssf.record.DBCellRecord;
|
||||
import org.apache.poi.hssf.record.IndexRecord;
|
||||
import org.apache.poi.hssf.record.MergeCellsRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.RowRecord;
|
||||
import org.apache.poi.hssf.record.UnknownRecord;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -39,6 +41,7 @@ public final class RowRecordsAggregate extends RecordAggregate {
|
||||
private int _lastrow = -1;
|
||||
private final Map _rowRecords;
|
||||
private final ValueRecordsAggregate _valuesAgg;
|
||||
private final List _unknownRecords;
|
||||
|
||||
/** Creates a new instance of ValueRecordsAggregate */
|
||||
|
||||
@ -48,8 +51,54 @@ public final class RowRecordsAggregate extends RecordAggregate {
|
||||
private RowRecordsAggregate(TreeMap rowRecords, ValueRecordsAggregate valuesAgg) {
|
||||
_rowRecords = rowRecords;
|
||||
_valuesAgg = valuesAgg;
|
||||
_unknownRecords = new ArrayList();
|
||||
}
|
||||
|
||||
public RowRecordsAggregate(List recs, int startIx, int endIx) {
|
||||
this();
|
||||
// First up, locate all the shared formulas for this sheet
|
||||
SharedFormulaHolder sfh = SharedFormulaHolder.create(recs, startIx, endIx);
|
||||
for(int i=startIx; i<endIx; i++) {
|
||||
Record rec = (Record) recs.get(i);
|
||||
switch (rec.getSid()) {
|
||||
case MergeCellsRecord.sid:
|
||||
// Some apps scatter these records between the rows/cells but they are supposed to
|
||||
// be well after the row/cell records. It is assumed such rogue MergeCellRecords
|
||||
// have already been collected by the caller, and can safely be ignored here.
|
||||
// see bug 45699
|
||||
continue;
|
||||
case RowRecord.sid:
|
||||
insertRow((RowRecord) rec);
|
||||
continue;
|
||||
case DBCellRecord.sid:
|
||||
// end of 'Row Block'. Should only occur after cell records
|
||||
continue;
|
||||
}
|
||||
if (rec instanceof UnknownRecord) {
|
||||
addUnknownRecord((UnknownRecord)rec);
|
||||
// might need to keep track of where exactly these belong
|
||||
continue;
|
||||
}
|
||||
if (!rec.isValue()) {
|
||||
throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
|
||||
}
|
||||
i += _valuesAgg.construct(recs, i, endIx, sfh);
|
||||
}
|
||||
"".length();
|
||||
}
|
||||
/**
|
||||
* Handles UnknownRecords which appear within the row/cell records
|
||||
*/
|
||||
private void addUnknownRecord(UnknownRecord rec) {
|
||||
// ony a few distinct record IDs are encountered by the existing POI test cases:
|
||||
// 0x1065 // many
|
||||
// 0x01C2 // several
|
||||
// 0x0034 // few
|
||||
// No documentation could be found for these
|
||||
|
||||
// keep the unknown records for re-serialization
|
||||
_unknownRecords.add(rec);
|
||||
}
|
||||
public void insertRow(RowRecord row) {
|
||||
// Integer integer = new Integer(row.getRowNumber());
|
||||
_rowRecords.put(new Integer(row.getRowNumber()), row);
|
||||
@ -215,6 +264,10 @@ public final class RowRecordsAggregate extends RecordAggregate {
|
||||
cellRecord.setRowOffset(pos);
|
||||
rv.visitRecord(cellRecord);
|
||||
}
|
||||
for (int i=0; i< _unknownRecords.size(); i++) {
|
||||
// Potentially breaking the file here since we don't know exactly where to write these records
|
||||
rv.visitRecord((Record) _unknownRecords.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator getIterator() {
|
||||
@ -439,9 +492,6 @@ public final class RowRecordsAggregate extends RecordAggregate {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public void constructCellValues(int offset, List records) {
|
||||
_valuesAgg.construct(offset, records);
|
||||
}
|
||||
public void insertCell(CellValueRecordInterface cvRec) {
|
||||
_valuesAgg.insertCell(cvRec);
|
||||
}
|
||||
|
@ -0,0 +1,96 @@
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.record.aggregates;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.record.FormulaRecord;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.SharedFormulaRecord;
|
||||
|
||||
/**
|
||||
* Temporarily holds SharedFormulaRecords while constructing a <tt>RowRecordsAggregate</tt>
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
final class SharedFormulaHolder {
|
||||
|
||||
private static final SharedFormulaHolder EMPTY = new SharedFormulaHolder(new SharedFormulaRecord[0]);
|
||||
private final SharedFormulaRecord[] _sfrs;
|
||||
|
||||
/**
|
||||
* @param recs list of sheet records (possibly contains records for other parts of the Excel file)
|
||||
* @param startIx index of first row/cell record for current sheet
|
||||
* @param endIx one past index of last row/cell record for current sheet. It is important
|
||||
* that this code does not inadvertently collect <tt>SharedFormulaRecord</tt>s from any other
|
||||
* sheet (which could happen if endIx is chosen poorly). (see bug 44449)
|
||||
*/
|
||||
public static SharedFormulaHolder create(List recs, int startIx, int endIx) {
|
||||
List temp = new ArrayList();
|
||||
for (int k = startIx; k < endIx; k++)
|
||||
{
|
||||
Record rec = ( Record ) recs.get(k);
|
||||
if (rec instanceof SharedFormulaRecord) {
|
||||
temp.add(rec);
|
||||
}
|
||||
}
|
||||
if (temp.size() < 1) {
|
||||
return EMPTY;
|
||||
}
|
||||
SharedFormulaRecord[] sfrs = new SharedFormulaRecord[temp.size()];
|
||||
temp.toArray(sfrs);
|
||||
return new SharedFormulaHolder(sfrs);
|
||||
|
||||
}
|
||||
private SharedFormulaHolder(SharedFormulaRecord[] sfrs) {
|
||||
_sfrs = sfrs;
|
||||
}
|
||||
public void convertSharedFormulaRecord(FormulaRecord formula) {
|
||||
// Traverse the list of shared formulas in
|
||||
// reverse order, and try to find the correct one
|
||||
// for us
|
||||
for (int i=0; i<_sfrs.length; i++) {
|
||||
SharedFormulaRecord shrd = _sfrs[i];
|
||||
if (shrd.isFormulaInShared(formula)) {
|
||||
shrd.convertSharedFormulaRecord(formula);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// not found
|
||||
handleMissingSharedFormulaRecord(formula);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes the shared formula flag "seems" to be erroneously set, in which case there is no
|
||||
* call to <tt>SharedFormulaRecord.convertSharedFormulaRecord</tt> and hence the
|
||||
* <tt>parsedExpression</tt> field of this <tt>FormulaRecord</tt> will not get updated.<br/>
|
||||
* As it turns out, this is not a problem, because in these circumstances, the existing value
|
||||
* for <tt>parsedExpression</tt> is perfectly OK.<p/>
|
||||
*
|
||||
* This method may also be used for setting breakpoints to help diagnose issues regarding the
|
||||
* abnormally-set 'shared formula' flags.
|
||||
* (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
|
||||
*
|
||||
* The method currently does nothing but do not delete it without finding a nice home for this
|
||||
* comment.
|
||||
*/
|
||||
private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
|
||||
// could log an info message here since this is a fairly unusual occurrence.
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
@ -137,90 +141,79 @@ 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) {
|
||||
if (rec instanceof StringRecord) {
|
||||
if (lastFormulaAggregate == null) {
|
||||
throw new RuntimeException("StringRecord found without preceding FormulaRecord");
|
||||
}
|
||||
if (lastFormulaAggregate.getStringRecord() != null) {
|
||||
throw new RuntimeException("Multiple StringRecords found after FormulaRecord");
|
||||
}
|
||||
lastFormulaAggregate.setStringRecord((StringRecord)rec);
|
||||
lastFormulaAggregate = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rec instanceof TableRecord) {
|
||||
// TODO - don't loose this record
|
||||
// DATATABLE probably belongs in formula record aggregate
|
||||
if (lastFormulaAggregate == null) {
|
||||
throw new RuntimeException("No preceding formula record found");
|
||||
}
|
||||
lastFormulaAggregate = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rec instanceof SharedFormulaRecord) {
|
||||
// Already handled, not to worry
|
||||
} else if (rec instanceof FormulaRecord)
|
||||
{
|
||||
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()) {
|
||||
// Traverse the list of shared formulas in
|
||||
// reverse order, and try to find the correct one
|
||||
// for us
|
||||
boolean found = false;
|
||||
for (int i=sharedFormulas.size()-1;i>=0;i--) {
|
||||
// TODO - there is no junit test case to justify this reversed loop
|
||||
// perhaps it could just run in the normal direction?
|
||||
SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i);
|
||||
if (shrd.isFormulaInShared(formula)) {
|
||||
shrd.convertSharedFormulaRecord(formula);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
handleMissingSharedFormulaRecord(formula);
|
||||
}
|
||||
sfh.convertSharedFormulaRecord(formula);
|
||||
}
|
||||
|
||||
lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null);
|
||||
insertCell( lastFormulaAggregate );
|
||||
continue;
|
||||
}
|
||||
else if (rec instanceof StringRecord)
|
||||
{
|
||||
lastFormulaAggregate.setStringRecord((StringRecord)rec);
|
||||
}
|
||||
else if (rec.isValue())
|
||||
{
|
||||
insertCell(( CellValueRecordInterface ) rec);
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes the shared formula flag "seems" to be erroneously set, in which case there is no
|
||||
* call to <tt>SharedFormulaRecord.convertSharedFormulaRecord</tt> and hence the
|
||||
* <tt>parsedExpression</tt> field of this <tt>FormulaRecord</tt> will not get updated.<br/>
|
||||
* As it turns out, this is not a problem, because in these circumstances, the existing value
|
||||
* for <tt>parsedExpression</tt> is perfectly OK.<p/>
|
||||
*
|
||||
* This method may also be used for setting breakpoints to help diagnose issues regarding the
|
||||
* abnormally-set 'shared formula' flags.
|
||||
* (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
|
||||
*
|
||||
* The method currently does nothing but do not delete it without finding a nice home for this
|
||||
* comment.
|
||||
*/
|
||||
private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
|
||||
// could log an info message here since this is a fairly unusual occurrence.
|
||||
return k - offset - 1;
|
||||
}
|
||||
|
||||
/** Tallies a count of the size of the cell records
|
||||
@ -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;
|
||||
}
|
||||
@ -322,16 +315,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;
|
||||
int nextRow,lastRow;
|
||||
|
@ -28,7 +28,7 @@ import org.apache.poi.util.LittleEndian;
|
||||
* 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;
|
||||
* the table description is found in a TABLE
|
||||
@ -38,36 +38,33 @@ import org.apache.poi.util.LittleEndian;
|
||||
* See page 811 of the june 08 binary docs.
|
||||
*/
|
||||
public final class TblPtg extends ControlPtg {
|
||||
private final static int SIZE = 4;
|
||||
public final static short sid = 0x2;
|
||||
private final static int SIZE = 5;
|
||||
public final static short sid = 0x02;
|
||||
/** The row number of the upper left corner */
|
||||
private final short field_1_first_row;
|
||||
private final int field_1_first_row;
|
||||
/** The column number of the upper left corner */
|
||||
private final short field_2_first_col;
|
||||
private final int field_2_first_col;
|
||||
|
||||
public TblPtg(RecordInputStream in)
|
||||
{
|
||||
field_1_first_row = in.readShort();
|
||||
field_2_first_col = in.readUByte();
|
||||
public TblPtg(RecordInputStream in) {
|
||||
field_1_first_row = in.readUShort();
|
||||
field_2_first_col = in.readUShort();
|
||||
}
|
||||
|
||||
public void writeBytes(byte [] array, int offset)
|
||||
{
|
||||
array[offset+0]= (byte) (sid);
|
||||
LittleEndian.putShort(array,offset+1,field_1_first_row);
|
||||
LittleEndian.putByte(array,offset+3,field_2_first_col);
|
||||
public void writeBytes(byte [] array, int offset) {
|
||||
LittleEndian.putByte(array, offset+0, sid);
|
||||
LittleEndian.putUShort(array, offset+1, field_1_first_row);
|
||||
LittleEndian.putUShort(array, offset+3, field_2_first_col);
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
public int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
public short getRow() {
|
||||
public int getRow() {
|
||||
return field_1_first_row;
|
||||
}
|
||||
|
||||
public short getColumn() {
|
||||
public int getColumn() {
|
||||
return field_2_first_col;
|
||||
}
|
||||
|
||||
@ -77,8 +74,7 @@ public final class TblPtg extends ControlPtg {
|
||||
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");
|
||||
|
@ -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() + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
|
BIN
src/testcases/org/apache/poi/hssf/data/ex45698-22488.xls
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/ex45698-22488.xls
Normal file
Binary file not shown.
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user