Patch largely from Josh from bug #44539 - Support for area references in formulas of rows >= 32768

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@634630 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-03-07 12:06:18 +00:00
parent 96198ae3d1
commit ff78b7ac71
27 changed files with 443 additions and 376 deletions

View File

@ -36,6 +36,7 @@
<!-- Don't forget to update status.xml too! --> <!-- Don't forget to update status.xml too! -->
<release version="3.1-beta1" date="2008-??-??"> <release version="3.1-beta1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">44539 - Support for area references in formulas of rows >= 32768</action>
<action dev="POI-DEVELOPERS" type="add">44536 - Improved support for detecting read-only recommended files</action> <action dev="POI-DEVELOPERS" type="add">44536 - Improved support for detecting read-only recommended files</action>
<action dev="POI-DEVELOPERS" type="fix">43901 - Correctly update the internal last cell number when adding and removing cells (previously sometimes off-by-one)</action> <action dev="POI-DEVELOPERS" type="fix">43901 - Correctly update the internal last cell number when adding and removing cells (previously sometimes off-by-one)</action>
<action dev="POI-DEVELOPERS" type="fix">28231 - For apparently truncated files, which are somehow still valid, now issue a truncation warning but carry on, rather than giving an exception as before</action> <action dev="POI-DEVELOPERS" type="fix">28231 - For apparently truncated files, which are somehow still valid, now issue a truncation warning but carry on, rather than giving an exception as before</action>

View File

@ -33,6 +33,7 @@
<!-- Don't forget to update changes.xml too! --> <!-- Don't forget to update changes.xml too! -->
<changes> <changes>
<release version="3.1-beta1" date="2008-??-??"> <release version="3.1-beta1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">44539 - Support for area references in formulas of rows >= 32768</action>
<action dev="POI-DEVELOPERS" type="add">44536 - Improved support for detecting read-only recommended files</action> <action dev="POI-DEVELOPERS" type="add">44536 - Improved support for detecting read-only recommended files</action>
<action dev="POI-DEVELOPERS" type="fix">43901 - Correctly update the internal last cell number when adding and removing cells (previously sometimes off-by-one)</action> <action dev="POI-DEVELOPERS" type="fix">43901 - Correctly update the internal last cell number when adding and removing cells (previously sometimes off-by-one)</action>
<action dev="POI-DEVELOPERS" type="fix">44504 - Added initial support for recognising external functions like YEARFRAC and ISEVEN (using NameXPtg), via LinkTable support</action> <action dev="POI-DEVELOPERS" type="fix">44504 - Added initial support for recognising external functions like YEARFRAC and ISEVEN (using NameXPtg), via LinkTable support</action>

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -15,8 +14,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import java.util.Stack; import java.util.Stack;
@ -34,10 +32,7 @@ import org.apache.poi.hssf.record.formula.*;
* record types. * record types.
* @author Danny Mui at apache dot org * @author Danny Mui at apache dot org
*/ */
public final class SharedFormulaRecord extends Record {
public class SharedFormulaRecord
extends Record
{
public final static short sid = 0x4BC; public final static short sid = 0x4BC;
private int field_1_first_row; private int field_1_first_row;
@ -58,15 +53,15 @@ public class SharedFormulaRecord
public SharedFormulaRecord(RecordInputStream in) public SharedFormulaRecord(RecordInputStream in)
{ {
super(in); super(in);
} }
protected void validateSid(short id) protected void validateSid(short id)
{ {
if (id != this.sid) if (id != this.sid)
{ {
throw new RecordFormatException("Not a valid SharedFormula"); throw new RecordFormatException("Not a valid SharedFormula");
} }
} }
public int getFirstRow() { public int getFirstRow() {
@ -96,14 +91,14 @@ public class SharedFormulaRecord
public int serialize(int offset, byte [] data) public int serialize(int offset, byte [] data)
{ {
//Because this record is converted to individual Formula records, this method is not required. //Because this record is converted to individual Formula records, this method is not required.
throw new UnsupportedOperationException("Cannot serialize a SharedFormulaRecord"); throw new UnsupportedOperationException("Cannot serialize a SharedFormulaRecord");
} }
public int getRecordSize() public int getRecordSize()
{ {
//Because this record is converted to individual Formula records, this method is not required. //Because this record is converted to individual Formula records, this method is not required.
throw new UnsupportedOperationException("Cannot get the size for a SharedFormulaRecord"); throw new UnsupportedOperationException("Cannot get the size for a SharedFormulaRecord");
} }
@ -257,39 +252,40 @@ public class SharedFormulaRecord
} }
} }
private short fixupRelativeColumn(int currentcolumn, short column, boolean relative) { private int fixupRelativeColumn(int currentcolumn, int column, boolean relative) {
if(relative) { if(relative) {
if((column&128)!=0) column=(short)(column-256); // mask out upper bits to produce 'wrapping' at column 256 ("IV")
column+=currentcolumn; return (column + currentcolumn) & 0x00FF;
} }
return column; return column;
} }
private short fixupRelativeRow(int currentrow, short row, boolean relative) { private int fixupRelativeRow(int currentrow, int row, boolean relative) {
if(relative) { if(relative) {
row+=currentrow; // mask out upper bits to produce 'wrapping' at row 65536
} return (row+currentrow) & 0x00FFFF;
return row; }
} return row;
}
/** /**
* Mirroring formula records so it is registered in the ValueRecordsAggregate * Mirroring formula records so it is registered in the ValueRecordsAggregate
*/ */
public boolean isInValueSection() public boolean isInValueSection()
{ {
return true; return true;
} }
/** /**
* Register it in the ValueRecordsAggregate so it can go into the FormulaRecordAggregate * Register it in the ValueRecordsAggregate so it can go into the FormulaRecordAggregate
*/ */
public boolean isValue() { public boolean isValue() {
return true; return true;
} }
public Object clone() { public Object clone() {
//Because this record is converted to individual Formula records, this method is not required. //Because this record is converted to individual Formula records, this method is not required.
throw new UnsupportedOperationException("Cannot clone a SharedFormulaRecord"); throw new UnsupportedOperationException("Cannot clone a SharedFormulaRecord");
} }
} }

View File

@ -41,10 +41,10 @@ public class Area3DPtg extends Ptg implements AreaI
public final static byte sid = 0x3b; public final static byte sid = 0x3b;
private final static int SIZE = 11; // 10 + 1 for Ptg private final static int SIZE = 11; // 10 + 1 for Ptg
private short field_1_index_extern_sheet; private short field_1_index_extern_sheet;
private short field_2_first_row; private int field_2_first_row;
private short field_3_last_row; private int field_3_last_row;
private short field_4_first_column; private int field_4_first_column;
private short field_5_last_column; private int field_5_last_column;
private BitField rowRelative = BitFieldFactory.getInstance( 0x8000 ); private BitField rowRelative = BitFieldFactory.getInstance( 0x8000 );
private BitField colRelative = BitFieldFactory.getInstance( 0x4000 ); private BitField colRelative = BitFieldFactory.getInstance( 0x4000 );
@ -64,27 +64,27 @@ public class Area3DPtg extends Ptg implements AreaI
public Area3DPtg(RecordInputStream in) public Area3DPtg(RecordInputStream in)
{ {
field_1_index_extern_sheet = in.readShort(); field_1_index_extern_sheet = in.readShort();
field_2_first_row = in.readShort(); field_2_first_row = in.readUShort();
field_3_last_row = in.readShort(); field_3_last_row = in.readUShort();
field_4_first_column = in.readShort(); field_4_first_column = in.readUShort();
field_5_last_column = in.readShort(); field_5_last_column = in.readUShort();
} }
public Area3DPtg(short firstRow, short lastRow, short firstColumn, short lastColumn, public Area3DPtg(short firstRow, short lastRow, short firstColumn, short lastColumn,
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative,
short externalSheetIndex) { short externalSheetIndex) {
setFirstRow(firstRow); setFirstRow(firstRow);
setLastRow(lastRow); setLastRow(lastRow);
setFirstColumn(firstColumn); setFirstColumn(firstColumn);
setLastColumn(lastColumn); setLastColumn(lastColumn);
setFirstRowRelative(firstRowRelative); setFirstRowRelative(firstRowRelative);
setLastRowRelative(lastRowRelative); setLastRowRelative(lastRowRelative);
setFirstColRelative(firstColRelative); setFirstColRelative(firstColRelative);
setLastColRelative(lastColRelative); setLastColRelative(lastColRelative);
setExternSheetIndex(externalSheetIndex); setExternSheetIndex(externalSheetIndex);
} }
public String toString() public String toString()
{ {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
@ -99,7 +99,7 @@ public class Area3DPtg extends Ptg implements AreaI
buffer.append( "lastColRowRel = " buffer.append( "lastColRowRel = "
+ isLastRowRelative() ).append( "\n" ); + isLastRowRelative() ).append( "\n" );
buffer.append( "firstColRel = " + isFirstColRelative() ).append( "\n" ); buffer.append( "firstColRel = " + isFirstColRelative() ).append( "\n" );
buffer.append( "lastColRel = " + isLastColRelative() ).append( "\n" ); buffer.append( "lastColRel = " + isLastColRelative() ).append( "\n" );
return buffer.toString(); return buffer.toString();
} }
@ -107,10 +107,10 @@ public class Area3DPtg extends Ptg implements AreaI
{ {
array[0 + offset] = (byte) ( sid + ptgClass ); array[0 + offset] = (byte) ( sid + ptgClass );
LittleEndian.putShort( array, 1 + offset, getExternSheetIndex() ); LittleEndian.putShort( array, 1 + offset, getExternSheetIndex() );
LittleEndian.putShort( array, 3 + offset, getFirstRow() ); LittleEndian.putShort( array, 3 + offset, (short)getFirstRow() );
LittleEndian.putShort( array, 5 + offset, getLastRow() ); LittleEndian.putShort( array, 5 + offset, (short)getLastRow() );
LittleEndian.putShort( array, 7 + offset, getFirstColumnRaw() ); LittleEndian.putShort( array, 7 + offset, (short)getFirstColumnRaw() );
LittleEndian.putShort( array, 9 + offset, getLastColumnRaw() ); LittleEndian.putShort( array, 9 + offset, (short)getLastColumnRaw() );
} }
public int getSize() public int getSize()
@ -128,32 +128,32 @@ public class Area3DPtg extends Ptg implements AreaI
field_1_index_extern_sheet = index; field_1_index_extern_sheet = index;
} }
public short getFirstRow() public int getFirstRow()
{ {
return field_2_first_row; return field_2_first_row;
} }
public void setFirstRow( short row ) public void setFirstRow( int row )
{ {
field_2_first_row = row; field_2_first_row = row;
} }
public short getLastRow() public int getLastRow()
{ {
return field_3_last_row; return field_3_last_row;
} }
public void setLastRow( short row ) public void setLastRow( int row )
{ {
field_3_last_row = row; field_3_last_row = row;
} }
public short getFirstColumn() public int getFirstColumn()
{ {
return (short) ( field_4_first_column & 0xFF ); return field_4_first_column & 0xFF;
} }
public short getFirstColumnRaw() public int getFirstColumnRaw()
{ {
return field_4_first_column; return field_4_first_column;
} }
@ -179,12 +179,12 @@ public class Area3DPtg extends Ptg implements AreaI
field_4_first_column = column; field_4_first_column = column;
} }
public short getLastColumn() public int getLastColumn()
{ {
return (short) ( field_5_last_column & 0xFF ); return field_5_last_column & 0xFF;
} }
public short getLastColumnRaw() public int getLastColumnRaw()
{ {
return field_5_last_column; return field_5_last_column;
} }
@ -216,7 +216,7 @@ public class Area3DPtg extends Ptg implements AreaI
*/ */
public void setFirstRowRelative( boolean rel ) public void setFirstRowRelative( boolean rel )
{ {
field_4_first_column = rowRelative.setShortBoolean( field_4_first_column, rel ); field_4_first_column = rowRelative.setBoolean( field_4_first_column, rel );
} }
/** /**
@ -224,7 +224,7 @@ public class Area3DPtg extends Ptg implements AreaI
*/ */
public void setFirstColRelative( boolean rel ) public void setFirstColRelative( boolean rel )
{ {
field_4_first_column = colRelative.setShortBoolean( field_4_first_column, rel ); field_4_first_column = colRelative.setBoolean( field_4_first_column, rel );
} }
/** /**
@ -233,7 +233,7 @@ public class Area3DPtg extends Ptg implements AreaI
*/ */
public void setLastRowRelative( boolean rel ) public void setLastRowRelative( boolean rel )
{ {
field_5_last_column = rowRelative.setShortBoolean( field_5_last_column, rel ); field_5_last_column = rowRelative.setBoolean( field_5_last_column, rel );
} }
/** /**
@ -241,7 +241,7 @@ public class Area3DPtg extends Ptg implements AreaI
*/ */
public void setLastColRelative( boolean rel ) public void setLastColRelative( boolean rel )
{ {
field_5_last_column = colRelative.setShortBoolean( field_5_last_column, rel ); field_5_last_column = colRelative.setBoolean( field_5_last_column, rel );
} }
@ -259,20 +259,20 @@ public class Area3DPtg extends Ptg implements AreaI
CellReference frstCell = ar.getFirstCell(); CellReference frstCell = ar.getFirstCell();
CellReference lastCell = ar.getLastCell(); CellReference lastCell = ar.getLastCell();
setFirstRow( (short) frstCell.getRow() ); setFirstRow( (short) frstCell.getRow() );
setFirstColumn( frstCell.getCol() ); setFirstColumn( frstCell.getCol() );
setLastRow( (short) lastCell.getRow() ); setLastRow( (short) lastCell.getRow() );
setLastColumn( lastCell.getCol() ); setLastColumn( lastCell.getCol() );
setFirstColRelative( !frstCell.isColAbsolute() ); setFirstColRelative( !frstCell.isColAbsolute() );
setLastColRelative( !lastCell.isColAbsolute() ); setLastColRelative( !lastCell.isColAbsolute() );
setFirstRowRelative( !frstCell.isRowAbsolute() ); setFirstRowRelative( !frstCell.isRowAbsolute() );
setLastRowRelative( !lastCell.isRowAbsolute() ); setLastRowRelative( !lastCell.isRowAbsolute() );
} }
/** /**
* @return text representation of this area reference that can be used in text * @return text representation of this area reference that can be used in text
* formulas. The sheet name will get properly delimited if required. * formulas. The sheet name will get properly delimited if required.
*/ */
public String toFormulaString(Workbook book) public String toFormulaString(Workbook book)
{ {
// First do the sheet name // First do the sheet name
@ -303,7 +303,7 @@ public class Area3DPtg extends Ptg implements AreaI
ptg.field_3_last_row = field_3_last_row; ptg.field_3_last_row = field_3_last_row;
ptg.field_4_first_column = field_4_first_column; ptg.field_4_first_column = field_4_first_column;
ptg.field_5_last_column = field_5_last_column; ptg.field_5_last_column = field_5_last_column;
ptg.setClass(ptgClass); ptg.setClass(ptgClass);
return ptg; return ptg;
} }

View File

@ -36,16 +36,14 @@ import org.apache.poi.hssf.model.Workbook;
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public class AreaAPtg public final class AreaAPtg extends AreaPtg {
extends AreaPtg
{
public final static short sid = 0x65; public final static short sid = 0x65;
protected AreaAPtg() { protected AreaAPtg() {
//Required for clone methods //Required for clone methods
} }
public AreaAPtg(short firstRow, short lastRow, short firstColumn, short lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) { public AreaAPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative); super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
} }

View File

@ -24,22 +24,22 @@ public interface AreaI {
/** /**
* @return the first row in the area * @return the first row in the area
*/ */
public short getFirstRow(); public int getFirstRow();
/** /**
* @return last row in the range (x2 in x1,y1-x2,y2) * @return last row in the range (x2 in x1,y1-x2,y2)
*/ */
public short getLastRow(); public int getLastRow();
/** /**
* @return the first column number in the area. * @return the first column number in the area.
*/ */
public short getFirstColumn(); public int getFirstColumn();
/** /**
* @return lastcolumn in the area * @return lastcolumn in the area
*/ */
public short getLastColumn(); public int getLastColumn();
/** /**
* @return isrelative first column to relative or not * @return isrelative first column to relative or not

View File

@ -38,10 +38,14 @@ public class AreaPtg
{ {
public final static short sid = 0x25; public final static short sid = 0x25;
private final static int SIZE = 9; private final static int SIZE = 9;
private short field_1_first_row; /** zero based, unsigned 16 bit */
private short field_2_last_row; private int field_1_first_row;
private short field_3_first_column; /** zero based, unsigned 16 bit */
private short field_4_last_column; private int field_2_last_row;
/** zero based, unsigned 8 bit */
private int field_3_first_column;
/** zero based, unsigned 8 bit */
private int field_4_last_column;
private final static BitField rowRelative = BitFieldFactory.getInstance(0x8000); private final static BitField rowRelative = BitFieldFactory.getInstance(0x8000);
private final static BitField colRelative = BitFieldFactory.getInstance(0x4000); private final static BitField colRelative = BitFieldFactory.getInstance(0x4000);
@ -55,9 +59,9 @@ public class AreaPtg
AreaReference ar = new AreaReference(arearef); AreaReference ar = new AreaReference(arearef);
CellReference firstCell = ar.getFirstCell(); CellReference firstCell = ar.getFirstCell();
CellReference lastCell = ar.getLastCell(); CellReference lastCell = ar.getLastCell();
setFirstRow((short)firstCell.getRow()); setFirstRow(firstCell.getRow());
setFirstColumn(firstCell.getCol()); setFirstColumn(firstCell.getCol());
setLastRow((short)lastCell.getRow()); setLastRow(lastCell.getRow());
setLastColumn(lastCell.getCol()); setLastColumn(lastCell.getCol());
setFirstColRelative(!firstCell.isColAbsolute()); setFirstColRelative(!firstCell.isColAbsolute());
setLastColRelative(!lastCell.isColAbsolute()); setLastColRelative(!lastCell.isColAbsolute());
@ -65,7 +69,13 @@ public class AreaPtg
setLastRowRelative(!lastCell.isRowAbsolute()); setLastRowRelative(!lastCell.isRowAbsolute());
} }
public AreaPtg(short firstRow, short lastRow, short firstColumn, short lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) { public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn,
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
checkColumnBounds(firstColumn);
checkColumnBounds(lastColumn);
checkRowBounds(firstRow);
checkRowBounds(lastRow);
setFirstRow(firstRow); setFirstRow(firstRow);
setLastRow(lastRow); setLastRow(lastRow);
setFirstColumn(firstColumn); setFirstColumn(firstColumn);
@ -76,12 +86,23 @@ public class AreaPtg
setLastColRelative(lastColRelative); setLastColRelative(lastColRelative);
} }
private static void checkColumnBounds(int colIx) {
if((colIx & 0x0FF) != colIx) {
throw new IllegalArgumentException("colIx (" + colIx + ") is out of range");
}
}
private static void checkRowBounds(int rowIx) {
if((rowIx & 0x0FFFF) != rowIx) {
throw new IllegalArgumentException("rowIx (" + rowIx + ") is out of range");
}
}
public AreaPtg(RecordInputStream in) public AreaPtg(RecordInputStream in)
{ {
field_1_first_row = in.readShort(); field_1_first_row = in.readUShort();
field_2_last_row = in.readShort(); field_2_last_row = in.readUShort();
field_3_first_column = in.readShort(); field_3_first_column = in.readUShort();
field_4_last_column = in.readShort(); field_4_last_column = in.readUShort();
//System.out.println(toString()); //System.out.println(toString());
} }
@ -110,10 +131,10 @@ public class AreaPtg
public void writeBytes(byte [] array, int offset) { public void writeBytes(byte [] array, int offset) {
array[offset] = (byte) (sid + ptgClass); array[offset] = (byte) (sid + ptgClass);
LittleEndian.putShort(array,offset+1,field_1_first_row); LittleEndian.putShort(array,offset+1,(short)field_1_first_row);
LittleEndian.putShort(array,offset+3,field_2_last_row); LittleEndian.putShort(array,offset+3,(short)field_2_last_row);
LittleEndian.putShort(array,offset+5,field_3_first_column); LittleEndian.putShort(array,offset+5,(short)field_3_first_column);
LittleEndian.putShort(array,offset+7,field_4_last_column); LittleEndian.putShort(array,offset+7,(short)field_4_last_column);
} }
public int getSize() public int getSize()
@ -124,42 +145,42 @@ public class AreaPtg
/** /**
* @return the first row in the area * @return the first row in the area
*/ */
public short getFirstRow() public int getFirstRow()
{ {
return field_1_first_row; return field_1_first_row;
} }
/** /**
* sets the first row * sets the first row
* @param row number (0-based) * @param rowIx number (0-based)
*/ */
public void setFirstRow(short row) public void setFirstRow(int rowIx) {
{ checkRowBounds(rowIx);
field_1_first_row = row; field_1_first_row = rowIx;
} }
/** /**
* @return last row in the range (x2 in x1,y1-x2,y2) * @return last row in the range (x2 in x1,y1-x2,y2)
*/ */
public short getLastRow() public int getLastRow()
{ {
return field_2_last_row; return field_2_last_row;
} }
/** /**
* @param row last row number in the area * @param rowIx last row number in the area
*/ */
public void setLastRow(short row) public void setLastRow(int rowIx) {
{ checkRowBounds(rowIx);
field_2_last_row = row; field_2_last_row = rowIx;
} }
/** /**
* @return the first column number in the area. * @return the first column number in the area.
*/ */
public short getFirstColumn() public int getFirstColumn()
{ {
return columnMask.getShortValue(field_3_first_column); return columnMask.getValue(field_3_first_column);
} }
/** /**
@ -167,7 +188,7 @@ public class AreaPtg
*/ */
public short getFirstColumnRaw() public short getFirstColumnRaw()
{ {
return field_3_first_column; return (short) field_3_first_column; // TODO
} }
/** /**
@ -183,7 +204,7 @@ public class AreaPtg
* @param rel is relative or not. * @param rel is relative or not.
*/ */
public void setFirstRowRelative(boolean rel) { public void setFirstRowRelative(boolean rel) {
field_3_first_column=rowRelative.setShortBoolean(field_3_first_column,rel); field_3_first_column=rowRelative.setBoolean(field_3_first_column,rel);
} }
/** /**
@ -198,21 +219,21 @@ public class AreaPtg
* set whether the first column is relative * set whether the first column is relative
*/ */
public void setFirstColRelative(boolean rel) { public void setFirstColRelative(boolean rel) {
field_3_first_column=colRelative.setShortBoolean(field_3_first_column,rel); field_3_first_column=colRelative.setBoolean(field_3_first_column,rel);
} }
/** /**
* set the first column in the area * set the first column in the area
*/ */
public void setFirstColumn(short column) public void setFirstColumn(int colIx) {
{ checkColumnBounds(colIx);
field_3_first_column=columnMask.setShortValue(field_3_first_column, column); field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
} }
/** /**
* set the first column irespective of the bitmasks * set the first column irespective of the bitmasks
*/ */
public void setFirstColumnRaw(short column) public void setFirstColumnRaw(int column)
{ {
field_3_first_column = column; field_3_first_column = column;
} }
@ -220,9 +241,9 @@ public class AreaPtg
/** /**
* @return lastcolumn in the area * @return lastcolumn in the area
*/ */
public short getLastColumn() public int getLastColumn()
{ {
return columnMask.getShortValue(field_4_last_column); return columnMask.getValue(field_4_last_column);
} }
/** /**
@ -230,7 +251,7 @@ public class AreaPtg
*/ */
public short getLastColumnRaw() public short getLastColumnRaw()
{ {
return field_4_last_column; return (short) field_4_last_column;
} }
/** /**
@ -247,7 +268,7 @@ public class AreaPtg
* <code>false</code> * <code>false</code>
*/ */
public void setLastRowRelative(boolean rel) { public void setLastRowRelative(boolean rel) {
field_4_last_column=rowRelative.setShortBoolean(field_4_last_column,rel); field_4_last_column=rowRelative.setBoolean(field_4_last_column,rel);
} }
/** /**
@ -262,16 +283,16 @@ public class AreaPtg
* set whether the last column should be relative or not * set whether the last column should be relative or not
*/ */
public void setLastColRelative(boolean rel) { public void setLastColRelative(boolean rel) {
field_4_last_column=colRelative.setShortBoolean(field_4_last_column,rel); field_4_last_column=colRelative.setBoolean(field_4_last_column,rel);
} }
/** /**
* set the last column in the area * set the last column in the area
*/ */
public void setLastColumn(short column) public void setLastColumn(int colIx) {
{ checkColumnBounds(colIx);
field_4_last_column=columnMask.setShortValue(field_4_last_column, column); field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
} }
/** /**

View File

@ -36,7 +36,7 @@ import org.apache.poi.hssf.model.Workbook;
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public class AreaVPtg public final class AreaVPtg
extends AreaPtg extends AreaPtg
{ {
public final static short sid = 0x45; public final static short sid = 0x45;
@ -45,7 +45,7 @@ public class AreaVPtg
//Required for clone methods //Required for clone methods
} }
public AreaVPtg(short firstRow, short lastRow, short firstColumn, short lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) { public AreaVPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative); super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
} }

View File

@ -18,16 +18,14 @@
package org.apache.poi.hssf.record.formula; package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hssf.util.RangeAddress;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.util.SheetReferences;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.util.RangeAddress;
import org.apache.poi.hssf.util.SheetReferences;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian;
/** /**
* Title: Reference 3D Ptg <P> * Title: Reference 3D Ptg <P>
@ -42,8 +40,14 @@ public class Ref3DPtg extends Ptg {
public final static byte sid = 0x3a; public final static byte sid = 0x3a;
private final static int SIZE = 7; // 6 + 1 for Ptg private final static int SIZE = 7; // 6 + 1 for Ptg
private short field_1_index_extern_sheet; private short field_1_index_extern_sheet;
private short field_2_row; /** The row index - zero based unsigned 16 bit value */
private short field_3_column; private int field_2_row;
/** Field 2
* - lower 8 bits is the zero based unsigned byte column index
* - bit 16 - isRowRelative
* - bit 15 - isColumnRelative
*/
private int field_3_column;
private BitField rowRelative = BitFieldFactory.getInstance(0x8000); private BitField rowRelative = BitFieldFactory.getInstance(0x8000);
private BitField colRelative = BitFieldFactory.getInstance(0x4000); private BitField colRelative = BitFieldFactory.getInstance(0x4000);
@ -58,8 +62,8 @@ public class Ref3DPtg extends Ptg {
public Ref3DPtg(String cellref, short externIdx ) { public Ref3DPtg(String cellref, short externIdx ) {
CellReference c= new CellReference(cellref); CellReference c= new CellReference(cellref);
setRow((short) c.getRow()); setRow(c.getRow());
setColumn((short) c.getCol()); setColumn(c.getCol());
setColRelative(!c.isColAbsolute()); setColRelative(!c.isColAbsolute());
setRowRelative(!c.isRowAbsolute()); setRowRelative(!c.isRowAbsolute());
setExternSheetIndex(externIdx); setExternSheetIndex(externIdx);
@ -81,8 +85,8 @@ public class Ref3DPtg extends Ptg {
public void writeBytes(byte [] array, int offset) { public void writeBytes(byte [] array, int offset) {
array[ 0 + offset ] = (byte) (sid + ptgClass); array[ 0 + offset ] = (byte) (sid + ptgClass);
LittleEndian.putShort(array, 1 + offset , getExternSheetIndex()); LittleEndian.putShort(array, 1 + offset , getExternSheetIndex());
LittleEndian.putShort(array, 3 + offset , getRow()); LittleEndian.putShort(array, 3 + offset , (short)getRow());
LittleEndian.putShort(array, 5 + offset , getColumnRaw()); LittleEndian.putShort(array, 5 + offset , (short)getColumnRaw());
} }
public int getSize() { public int getSize() {
@ -97,19 +101,19 @@ public class Ref3DPtg extends Ptg {
field_1_index_extern_sheet = index; field_1_index_extern_sheet = index;
} }
public short getRow() { public int getRow() {
return field_2_row; return field_2_row;
} }
public void setRow(short row) { public void setRow(int row) {
field_2_row = row; field_2_row = row;
} }
public short getColumn() { public int getColumn() {
return ( short ) (field_3_column & 0xFF); return field_3_column & 0xFF;
} }
public short getColumnRaw() { public int getColumnRaw() {
return field_3_column; return field_3_column;
} }
@ -119,7 +123,7 @@ public class Ref3DPtg extends Ptg {
} }
public void setRowRelative(boolean rel) { public void setRowRelative(boolean rel) {
field_3_column=rowRelative.setShortBoolean(field_3_column,rel); field_3_column=rowRelative.setBoolean(field_3_column,rel);
} }
public boolean isColRelative() public boolean isColRelative()
@ -128,7 +132,7 @@ public class Ref3DPtg extends Ptg {
} }
public void setColRelative(boolean rel) { public void setColRelative(boolean rel) {
field_3_column=colRelative.setShortBoolean(field_3_column,rel); field_3_column=colRelative.setBoolean(field_3_column,rel);
} }
public void setColumn(short column) { public void setColumn(short column) {
field_3_column &= 0xFF00; field_3_column &= 0xFF00;
@ -197,5 +201,4 @@ public class Ref3DPtg extends Ptg {
ptg.setClass(ptgClass); ptg.setClass(ptgClass);
return ptg; return ptg;
} }
} }

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -16,34 +15,23 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
/*
* ValueReferencePtg.java
*
* Created on November 21, 2001, 5:27 PM
*/
package org.apache.poi.hssf.record.formula; package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.model.Workbook;
/** /**
* RefNAPtg * RefNAPtg
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public class RefAPtg extends ReferencePtg public final class RefAPtg extends ReferencePtg {
{
public final static byte sid = 0x64; public final static byte sid = 0x64;
protected RefAPtg() { protected RefAPtg() {
super(); super();
} }
public RefAPtg(short row, short column, boolean isRowRelative, boolean isColumnRelative) { public RefAPtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
super(row, column, isRowRelative, isColumnRelative); super(row, column, isRowRelative, isColumnRelative);
} }

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -18,27 +17,20 @@
package org.apache.poi.hssf.record.formula; package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.model.Workbook;
/** /**
* RefVPtg * RefVPtg
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public final class RefVPtg extends ReferencePtg {
public class RefVPtg extends ReferencePtg
{
public final static byte sid = 0x44; public final static byte sid = 0x44;
protected RefVPtg() { protected RefVPtg() {
super(); super();
} }
public RefVPtg(short row, short column, boolean isRowRelative, boolean isColumnRelative) { public RefVPtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
super(row, column, isRowRelative, isColumnRelative); super(row, column, isRowRelative, isColumnRelative);
} }

View File

@ -31,26 +31,22 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public class ReferencePtg extends Ptg public class ReferencePtg extends Ptg {
{
private final static int SIZE = 5; private final static int SIZE = 5;
public final static byte sid = 0x24; public final static byte sid = 0x24;
private final static int MAX_ROW_NUMBER = 65536; private final static int MAX_ROW_NUMBER = 65536;
//public final static byte sid = 0x44;
/** /** The row index - zero based unsigned 16 bit value */
* The row number, between 0 and 65535, but stored as a signed private int field_1_row;
* short between -32767 and 32768. /** Field 2
* Take care about which version you fetch back! * - lower 8 bits is the zero based unsigned byte column index
* - bit 16 - isRowRelative
* - bit 15 - isColumnRelative
*/ */
private short field_1_row; private int field_2_col;
/** private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
* The column number, between 0 and ?? private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
*/ private static final BitField column = BitFieldFactory.getInstance(0x00FF);
private short field_2_col;
private BitField rowRelative = BitFieldFactory.getInstance(0x8000);
private BitField colRelative = BitFieldFactory.getInstance(0x4000);
private BitField column = BitFieldFactory.getInstance(0x3FFF);
protected ReferencePtg() { protected ReferencePtg() {
//Required for clone methods //Required for clone methods
@ -62,13 +58,13 @@ public class ReferencePtg extends Ptg
*/ */
public ReferencePtg(String cellref) { public ReferencePtg(String cellref) {
CellReference c= new CellReference(cellref); CellReference c= new CellReference(cellref);
setRow((short) c.getRow()); setRow(c.getRow());
setColumn((short) c.getCol()); setColumn(c.getCol());
setColRelative(!c.isColAbsolute()); setColRelative(!c.isColAbsolute());
setRowRelative(!c.isRowAbsolute()); setRowRelative(!c.isRowAbsolute());
} }
public ReferencePtg(short row, short column, boolean isRowRelative, boolean isColumnRelative) { public ReferencePtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
setRow(row); setRow(row);
setColumn(column); setColumn(column);
setRowRelative(isRowRelative); setRowRelative(isRowRelative);
@ -79,8 +75,8 @@ public class ReferencePtg extends Ptg
public ReferencePtg(RecordInputStream in) public ReferencePtg(RecordInputStream in)
{ {
field_1_row = in.readShort(); field_1_row = in.readUShort();
field_2_col = in.readShort(); field_2_col = in.readUShort();
} }
public String getRefPtgName() { public String getRefPtgName() {
@ -104,33 +100,23 @@ public class ReferencePtg extends Ptg
{ {
array[offset] = (byte) (sid + ptgClass); array[offset] = (byte) (sid + ptgClass);
LittleEndian.putShort(array,offset+1,field_1_row); LittleEndian.putShort(array, offset+1, (short)field_1_row);
LittleEndian.putShort(array,offset+3,field_2_col); LittleEndian.putShort(array, offset+3, (short)field_2_col);
} }
public void setRow(short row)
{
field_1_row = row;
}
public void setRow(int row) public void setRow(int row)
{ {
if(row < 0 || row >= MAX_ROW_NUMBER) { if(row < 0 || row >= MAX_ROW_NUMBER) {
throw new IllegalArgumentException("The row number, when specified as an integer, must be between 0 and " + MAX_ROW_NUMBER); throw new IllegalArgumentException("The row number, when specified as an integer, must be between 0 and " + MAX_ROW_NUMBER);
} }
field_1_row = row;
// Save, wrapping as needed
if(row > Short.MAX_VALUE) {
field_1_row = (short)(row - MAX_ROW_NUMBER);
} else {
field_1_row = (short)row;
}
} }
/** /**
* Returns the row number as a short, which will be * Returns the row number as a short, which will be
* wrapped (negative) for values between 32769 and 65535 * wrapped (negative) for values between 32769 and 65535
*/ */
public short getRow() public int getRow()
{ {
return field_1_row; return field_1_row;
} }
@ -151,7 +137,7 @@ public class ReferencePtg extends Ptg
} }
public void setRowRelative(boolean rel) { public void setRowRelative(boolean rel) {
field_2_col=rowRelative.setShortBoolean(field_2_col,rel); field_2_col=rowRelative.setBoolean(field_2_col,rel);
} }
public boolean isColRelative() public boolean isColRelative()
@ -160,27 +146,29 @@ public class ReferencePtg extends Ptg
} }
public void setColRelative(boolean rel) { public void setColRelative(boolean rel) {
field_2_col=colRelative.setShortBoolean(field_2_col,rel); field_2_col=colRelative.setBoolean(field_2_col,rel);
} }
public void setColumnRaw(short col) public void setColumnRaw(int col)
{ {
field_2_col = col; field_2_col = col;
} }
public short getColumnRaw() public int getColumnRaw()
{ {
return field_2_col; return field_2_col;
} }
public void setColumn(short col) public void setColumn(int col)
{ {
field_2_col = column.setShortValue(field_2_col, col); if(col < 0 || col > 0x100) {
throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
}
field_2_col = column.setValue(field_2_col, col);
} }
public short getColumn() public int getColumn() {
{ return column.getValue(field_2_col);
return column.getShortValue(field_2_col);
} }
public int getSize() public int getSize()

View File

@ -287,17 +287,30 @@ public final class HSSFRow implements Comparable {
} }
/** /**
* get the hssfcell representing a given column (logical cell) 0-based. If you * Get the hssfcell representing a given column (logical cell)
* ask for a cell that is not defined....you get a null. * 0-based. If you ask for a cell that is not defined....
* you get a null.
* Short method signature provided to retain binary
* compatibility.
* *
* @param cellnum 0 based column number * @param cellnum 0 based column number
* @return HSSFCell representing that column or null if undefined. * @return HSSFCell representing that column or null if undefined.
*/ */
public HSSFCell getCell(short cellnum) public HSSFCell getCell(short cellnum)
{ {
if(cellnum<0||cellnum>=cells.length) return null; return getCell((int)cellnum);
return cells[cellnum]; }
/**
* Get the hssfcell representing a given column (logical cell)
* 0-based. If you ask for a cell that is not defined....
* you get a null.
*
* @param cellnum 0 based column number
* @return HSSFCell representing that column or null if undefined.
*/
public HSSFCell getCell(int cellnum) {
if(cellnum<0||cellnum>=cells.length) return null;
return cells[cellnum];
} }
/** /**

View File

@ -53,9 +53,10 @@ public final class AreaReference {
parts[1].length() == 1 && parts[1].length() == 1 &&
parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' && parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') { parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
// Represented internally as x$1 to x$0 // Represented internally as x$1 to x$65536
// which is the maximum range of rows
parts[0] = parts[0] + "$1"; parts[0] = parts[0] + "$1";
parts[1] = parts[1] + "$0"; parts[1] = parts[1] + "$65536";
} }
_firstCell = new CellReference(parts[0]); _firstCell = new CellReference(parts[0]);
@ -98,10 +99,10 @@ public final class AreaReference {
*/ */
public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) { public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
// These are represented as something like // These are represented as something like
// C$1:C$0 or D$1:F$0 // C$1:C$65535 or D$1:F$0
// i.e. absolute from 1st row to 0th one // i.e. absolute from 1st row to 0th one
if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() && if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
botRight.getRow() == -1 && botRight.isRowAbsolute()) { botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
return true; return true;
} }
return false; return false;

View File

@ -71,6 +71,14 @@ public final class CellReference {
this(null, pRow, pCol, pAbsRow, pAbsCol); this(null, pRow, pCol, pAbsRow, pAbsCol);
} }
public CellReference(String pSheetName, int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) { public CellReference(String pSheetName, int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
// TODO - "-1" is a special value being temporarily used for whole row and whole column area references.
// so these checks are currently N.Q.R.
if(pRow < -1) {
throw new IllegalArgumentException("row index may not be negative");
}
if(pCol < -1) {
throw new IllegalArgumentException("column index may not be negative");
}
_sheetName = pSheetName; _sheetName = pSheetName;
_rowIndex=pRow; _rowIndex=pRow;
_colIndex=pCol; _colIndex=pCol;

View File

@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on May 8, 2005
*
*/
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.AreaPtg; import org.apache.poi.hssf.record.formula.AreaPtg;
@ -27,48 +24,60 @@ import org.apache.poi.hssf.record.formula.Ptg;
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
* *
*/ */
public class Area2DEval implements AreaEval { public final class Area2DEval implements AreaEval {
// TODO -refactor with Area3DEval
private final AreaPtg _delegate;
private AreaPtg delegate; private final ValueEval[] _values;
private ValueEval[] values;
public Area2DEval(Ptg ptg, ValueEval[] values) { public Area2DEval(Ptg ptg, ValueEval[] values) {
this.delegate = (AreaPtg) ptg; if(ptg == null) {
this.values = values; throw new IllegalArgumentException("ptg must not be null");
}
if(values == null) {
throw new IllegalArgumentException("values must not be null");
}
for(int i=values.length-1; i>=0; i--) {
if(values[i] == null) {
throw new IllegalArgumentException("value array elements must not be null");
}
}
// TODO - check size of array vs size of AreaPtg
_delegate = (AreaPtg) ptg;
_values = values;
} }
public short getFirstColumn() { public int getFirstColumn() {
return delegate.getFirstColumn(); return _delegate.getFirstColumn();
} }
public int getFirstRow() { public int getFirstRow() {
return delegate.getFirstRow(); return _delegate.getFirstRow();
} }
public short getLastColumn() { public int getLastColumn() {
return delegate.getLastColumn(); return _delegate.getLastColumn();
} }
public int getLastRow() { public int getLastRow() {
return delegate.getLastRow(); return _delegate.getLastRow();
} }
public ValueEval[] getValues() { public ValueEval[] getValues() {
return values; return _values;
} }
public ValueEval getValueAt(int row, short col) { public ValueEval getValueAt(int row, int col) {
ValueEval retval; ValueEval retval;
int index = ((row-getFirstRow())*(getLastColumn()-getFirstColumn()+1))+(col-getFirstColumn()); int index = ((row-getFirstRow())*(getLastColumn()-getFirstColumn()+1))+(col-getFirstColumn());
if (index <0 || index >= values.length) if (index <0 || index >= _values.length)
retval = ErrorEval.VALUE_INVALID; retval = ErrorEval.VALUE_INVALID;
else else
retval = values[index]; retval = _values[index];
return retval; return retval;
} }
public boolean contains(int row, short col) { public boolean contains(int row, int col) {
return (getFirstRow() <= row) && (getLastRow() >= row) return (getFirstRow() <= row) && (getLastRow() >= row)
&& (getFirstColumn() <= col) && (getLastColumn() >= col); && (getFirstColumn() <= col) && (getLastColumn() >= col);
} }
@ -82,10 +91,10 @@ public class Area2DEval implements AreaEval {
} }
public boolean isColumn() { public boolean isColumn() {
return delegate.getFirstColumn() == delegate.getLastColumn(); return _delegate.getFirstColumn() == _delegate.getLastColumn();
} }
public boolean isRow() { public boolean isRow() {
return delegate.getFirstRow() == delegate.getLastRow(); return _delegate.getFirstRow() == _delegate.getLastRow();
} }
} }

View File

@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on May 8, 2005
*
*/
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.Area3DPtg; import org.apache.poi.hssf.record.formula.Area3DPtg;
@ -28,47 +25,59 @@ import org.apache.poi.hssf.record.formula.Ptg;
* *
*/ */
public final class Area3DEval implements AreaEval { public final class Area3DEval implements AreaEval {
// TODO -refactor with Area3DEval
private final Area3DPtg _delegate;
private Area3DPtg delegate; private final ValueEval[] _values;
private ValueEval[] values;
public Area3DEval(Ptg ptg, ValueEval[] values) { public Area3DEval(Ptg ptg, ValueEval[] values) {
this.values = values; if(ptg == null) {
this.delegate = (Area3DPtg) ptg; throw new IllegalArgumentException("ptg must not be null");
}
if(values == null) {
throw new IllegalArgumentException("values must not be null");
}
for(int i=values.length-1; i>=0; i--) {
if(values[i] == null) {
throw new IllegalArgumentException("value array elements must not be null");
}
}
// TODO - check size of array vs size of AreaPtg
_values = values;
_delegate = (Area3DPtg) ptg;
} }
public short getFirstColumn() { public int getFirstColumn() {
return delegate.getFirstColumn(); return _delegate.getFirstColumn();
} }
public int getFirstRow() { public int getFirstRow() {
return delegate.getFirstRow(); return _delegate.getFirstRow();
} }
public short getLastColumn() { public int getLastColumn() {
return delegate.getLastColumn(); return (short) _delegate.getLastColumn();
} }
public int getLastRow() { public int getLastRow() {
return delegate.getLastRow(); return _delegate.getLastRow();
} }
public ValueEval[] getValues() { public ValueEval[] getValues() {
return values; return _values;
} }
public ValueEval getValueAt(int row, short col) { public ValueEval getValueAt(int row, int col) {
ValueEval retval; ValueEval retval;
int index = (row-getFirstRow())*(col-getFirstColumn()); int index = (row-getFirstRow())*(col-getFirstColumn());
if (index <0 || index >= values.length) if (index <0 || index >= _values.length)
retval = ErrorEval.VALUE_INVALID; retval = ErrorEval.VALUE_INVALID;
else else
retval = values[index]; retval = _values[index];
return retval; return retval;
} }
public boolean contains(int row, short col) { public boolean contains(int row, int col) {
return (getFirstRow() <= row) && (getLastRow() >= row) return (getFirstRow() <= row) && (getLastRow() >= row)
&& (getFirstColumn() <= col) && (getLastColumn() >= col); && (getFirstColumn() <= col) && (getLastColumn() >= col);
} }
@ -83,15 +92,14 @@ public final class Area3DEval implements AreaEval {
public boolean isColumn() { public boolean isColumn() {
return delegate.getFirstColumn() == delegate.getLastColumn(); return _delegate.getFirstColumn() == _delegate.getLastColumn();
} }
public boolean isRow() { public boolean isRow() {
return delegate.getFirstRow() == delegate.getLastRow(); return _delegate.getFirstRow() == _delegate.getLastRow();
} }
public int getExternSheetIndex() { public int getExternSheetIndex() {
return delegate.getExternSheetIndex(); return _delegate.getExternSheetIndex();
} }
} }

View File

@ -42,13 +42,13 @@ public interface AreaEval extends ValueEval {
* returns the 0-based index of the first col in * returns the 0-based index of the first col in
* this area. * this area.
*/ */
public short getFirstColumn(); public int getFirstColumn();
/** /**
* returns the 0-based index of the last col in * returns the 0-based index of the last col in
* this area. * this area.
*/ */
public short getLastColumn(); public int getLastColumn();
/** /**
* returns true if the Area's start and end row indexes * returns true if the Area's start and end row indexes
@ -80,7 +80,7 @@ public interface AreaEval extends ValueEval {
* @param row * @param row
* @param col * @param col
*/ */
public ValueEval getValueAt(int row, short col); public ValueEval getValueAt(int row, int col);
/** /**
* returns true if the cell at row and col specified * returns true if the cell at row and col specified
@ -89,7 +89,7 @@ public interface AreaEval extends ValueEval {
* @param row * @param row
* @param col * @param col
*/ */
public boolean contains(int row, short col); public boolean contains(int row, int col);
/** /**
* returns true if the specified col is in range * returns true if the specified col is in range

View File

@ -29,16 +29,22 @@ public final class Ref2DEval implements RefEval {
private final ReferencePtg delegate; private final ReferencePtg delegate;
public Ref2DEval(ReferencePtg ptg, ValueEval ve) { public Ref2DEval(ReferencePtg ptg, ValueEval ve) {
if(ve == null) {
throw new IllegalArgumentException("ve must not be null");
}
if(false && ptg == null) { // TODO - fix dodgy code in MultiOperandNumericFunction
throw new IllegalArgumentException("ptg must not be null");
}
value = ve; value = ve;
delegate = ptg; delegate = ptg;
} }
public ValueEval getInnerValueEval() { public ValueEval getInnerValueEval() {
return value; return value;
} }
public short getRow() { public int getRow() {
return delegate.getRow(); return delegate.getRow();
} }
public short getColumn() { public int getColumn() {
return delegate.getColumn(); return delegate.getColumn();
} }
} }

View File

@ -29,16 +29,22 @@ public final class Ref3DEval implements RefEval {
private final Ref3DPtg delegate; private final Ref3DPtg delegate;
public Ref3DEval(Ref3DPtg ptg, ValueEval ve) { public Ref3DEval(Ref3DPtg ptg, ValueEval ve) {
if(ve == null) {
throw new IllegalArgumentException("ve must not be null");
}
if(ptg == null) {
throw new IllegalArgumentException("ptg must not be null");
}
value = ve; value = ve;
delegate = ptg; delegate = ptg;
} }
public ValueEval getInnerValueEval() { public ValueEval getInnerValueEval() {
return value; return value;
} }
public short getRow() { public int getRow() {
return delegate.getRow(); return delegate.getRow();
} }
public short getColumn() { public int getColumn() {
return delegate.getColumn(); return delegate.getColumn();
} }
public int getExternSheetIndex() { public int getExternSheetIndex() {

View File

@ -40,12 +40,12 @@ public interface RefEval extends ValueEval {
public ValueEval getInnerValueEval(); public ValueEval getInnerValueEval();
/** /**
* returns the column index. * returns the zero based column index.
*/ */
public short getColumn(); public int getColumn();
/** /**
* returns the row index. * returns the zero based row index.
*/ */
public short getRow(); public int getRow();
} }

View File

@ -287,8 +287,8 @@ final class LookupUtils {
// It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval. // It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval.
// This code only requires the value array item. // This code only requires the value array item.
// anything would be ok for rowIx and colIx, but may as well get it right. // anything would be ok for rowIx and colIx, but may as well get it right.
short rowIx = refEval.getRow(); int rowIx = refEval.getRow();
short colIx = refEval.getColumn(); int colIx = refEval.getColumn();
AreaPtg ap = new AreaPtg(rowIx, rowIx, colIx, colIx, false, false, false, false); AreaPtg ap = new AreaPtg(rowIx, rowIx, colIx, colIx, false, false, false, false);
ValueEval value = refEval.getInnerValueEval(); ValueEval value = refEval.getInnerValueEval();
return new Area2DEval(ap, new ValueEval[] { value, }); return new Area2DEval(ap, new ValueEval[] { value, });

View File

@ -14,10 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on May 5, 2005
*
*/
package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -420,20 +417,20 @@ public class HSSFFormulaEvaluator {
} }
else if (ptg instanceof ReferencePtg) { else if (ptg instanceof ReferencePtg) {
ReferencePtg refPtg = (ReferencePtg) ptg; ReferencePtg refPtg = (ReferencePtg) ptg;
short colnum = refPtg.getColumn(); int colIx = refPtg.getColumn();
short rownum = refPtg.getRow(); int rowIx = refPtg.getRow();
HSSFRow row = sheet.getRow(rownum); HSSFRow row = sheet.getRow(rowIx);
HSSFCell cell = (row != null) ? row.getCell(colnum) : null; HSSFCell cell = (row != null) ? row.getCell(colIx) : null;
stack.push(createRef2DEval(refPtg, cell, row, sheet, workbook)); stack.push(createRef2DEval(refPtg, cell, row, sheet, workbook));
} }
else if (ptg instanceof Ref3DPtg) { else if (ptg instanceof Ref3DPtg) {
Ref3DPtg refPtg = (Ref3DPtg) ptg; Ref3DPtg refPtg = (Ref3DPtg) ptg;
short colnum = refPtg.getColumn(); int colIx = refPtg.getColumn();
short rownum = refPtg.getRow(); int rowIx = refPtg.getRow();
Workbook wb = workbook.getWorkbook(); Workbook wb = workbook.getWorkbook();
HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex())); HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()));
HSSFRow row = xsheet.getRow(rownum); HSSFRow row = xsheet.getRow(rowIx);
HSSFCell cell = (row != null) ? row.getCell(colnum) : null; HSSFCell cell = (row != null) ? row.getCell(colIx) : null;
stack.push(createRef3DEval(refPtg, cell, row, xsheet, workbook)); stack.push(createRef3DEval(refPtg, cell, row, xsheet, workbook));
} }
else if (ptg instanceof AreaPtg) { else if (ptg instanceof AreaPtg) {
@ -506,10 +503,10 @@ public class HSSFFormulaEvaluator {
} }
public static AreaEval evaluateAreaPtg(HSSFSheet sheet, HSSFWorkbook workbook, AreaPtg ap) { public static AreaEval evaluateAreaPtg(HSSFSheet sheet, HSSFWorkbook workbook, AreaPtg ap) {
short row0 = ap.getFirstRow(); int row0 = ap.getFirstRow();
short col0 = ap.getFirstColumn(); int col0 = ap.getFirstColumn();
short row1 = ap.getLastRow(); int row1 = ap.getLastRow();
short col1 = ap.getLastColumn(); int col1 = ap.getLastColumn();
// If the last row is -1, then the // If the last row is -1, then the
// reference is for the rest of the column // reference is for the rest of the column
@ -518,24 +515,15 @@ public class HSSFFormulaEvaluator {
if(row1 == -1 && row0 >= 0) { if(row1 == -1 && row0 >= 0) {
row1 = (short)sheet.getLastRowNum(); row1 = (short)sheet.getLastRowNum();
} }
ValueEval[] values = evalArea(workbook, sheet, row0, col0, row1, col1);
ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)]; return new Area2DEval(ap, values);
for (short x = row0; sheet != null && x < row1 + 1; x++) {
HSSFRow row = sheet.getRow(x);
for (short y = col0; row != null && y < col1 + 1; y++) {
values[(x - row0) * (col1 - col0 + 1) + (y - col0)] =
getEvalForCell(row.getCell(y), row, sheet, workbook);
}
}
AreaEval ae = new Area2DEval(ap, values);
return ae;
} }
public static AreaEval evaluateArea3dPtg(HSSFWorkbook workbook, Area3DPtg a3dp) { public static AreaEval evaluateArea3dPtg(HSSFWorkbook workbook, Area3DPtg a3dp) {
short row0 = a3dp.getFirstRow(); int row0 = a3dp.getFirstRow();
short col0 = a3dp.getFirstColumn(); int col0 = a3dp.getFirstColumn();
short row1 = a3dp.getLastRow(); int row1 = a3dp.getLastRow();
short col1 = a3dp.getLastColumn(); int col1 = a3dp.getLastColumn();
Workbook wb = workbook.getWorkbook(); Workbook wb = workbook.getWorkbook();
HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex())); HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()));
@ -547,19 +535,28 @@ public class HSSFFormulaEvaluator {
row1 = (short)xsheet.getLastRowNum(); row1 = (short)xsheet.getLastRowNum();
} }
ValueEval[] values = evalArea(workbook, xsheet, row0, col0, row1, col1);
return new Area3DEval(a3dp, values);
}
private static ValueEval[] evalArea(HSSFWorkbook workbook, HSSFSheet sheet,
int row0, int col0, int row1, int col1) {
ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)]; ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)];
for (short x = row0; xsheet != null && x < row1 + 1; x++) { for (int x = row0; sheet != null && x < row1 + 1; x++) {
HSSFRow row = xsheet.getRow(x); HSSFRow row = sheet.getRow(x);
for (short y = col0; row != null && y < col1 + 1; y++) { for (int y = col0; y < col1 + 1; y++) {
values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = ValueEval cellEval;
getEvalForCell(row.getCell(y), row, xsheet, workbook); if(row == null) {
cellEval = BlankEval.INSTANCE;
} else {
cellEval = getEvalForCell(row.getCell(y), row, sheet, workbook);
}
values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = cellEval;
} }
} }
AreaEval ae = new Area3DEval(a3dp, values); return values;
return ae;
} }
/** /**
* returns the OperationEval concrete impl instance corresponding * returns the OperationEval concrete impl instance corresponding
* to the suplied operationPtg * to the suplied operationPtg

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -15,30 +14,30 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.model; package org.apache.poi.hssf.model;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
import org.apache.poi.hssf.record.formula.FuncVarPtg; import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.NamePtg; import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFName; import org.apache.poi.hssf.usermodel.HSSFName;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
/** /**
* Test the low level formula parser functionality, * Test the low level formula parser functionality,
* but using parts which need to use the * but using parts which need to use the
* HSSFFormulaEvaluator, which is in scratchpad * HSSFFormulaEvaluator, which is in scratchpad
*/ */
public class TestFormulaParserSP extends TestCase { public final class TestFormulaParserSP extends TestCase {
public TestFormulaParserSP(String name) {
super(name);
}
public void testWithNamedRange() throws Exception { public void testWithNamedRange() throws Exception {
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
FormulaParser fp; FormulaParser fp;
@ -80,4 +79,32 @@ public class TestFormulaParserSP extends TestCase {
assertEquals(FuncVarPtg.class, ptgs[1].getClass()); assertEquals(FuncVarPtg.class, ptgs[1].getClass());
} }
public void testEvaluateFormulaWithRowBeyond32768_Bug44539() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
wb.setSheetName(0, "Sheet1");
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short)0);
cell.setCellFormula("SUM(A32769:A32770)");
// put some values in the cells to make the evaluation more interesting
sheet.createRow(32768).createCell((short)0).setCellValue(31);
sheet.createRow(32769).createCell((short)0).setCellValue(11);
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
fe.setCurrentRow(row);
CellValue result;
try {
result = fe.evaluate(cell);
} catch (FormulaParseException e) {
if(e.getMessage().equals("Found reference to named range \"A\", but that named range wasn't defined!")) {
fail("Identifed bug 44539");
}
throw new RuntimeException(e);
}
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, result.getCellType());
assertEquals(42.0, result.getNumberValue(), 0.0);
}
} }

View File

@ -63,12 +63,13 @@ public class TestBug44410 extends TestCase {
assertEquals(AreaPtg.class, ops.get(0).getClass()); assertEquals(AreaPtg.class, ops.get(0).getClass());
assertEquals(FuncVarPtg.class, ops.get(1).getClass()); assertEquals(FuncVarPtg.class, ops.get(1).getClass());
// Actually stored as C1 to C0 (last row is -1) // Actually stored as C1 to C65536
// (last row is -1 === 65535)
AreaPtg ptg = (AreaPtg)ops.get(0); AreaPtg ptg = (AreaPtg)ops.get(0);
assertEquals(2, ptg.getFirstColumn()); assertEquals(2, ptg.getFirstColumn());
assertEquals(2, ptg.getLastColumn()); assertEquals(2, ptg.getLastColumn());
assertEquals(0, ptg.getFirstRow()); assertEquals(0, ptg.getFirstRow());
assertEquals(-1, ptg.getLastRow()); assertEquals(65535, ptg.getLastRow());
assertEquals("C:C", ptg.toFormulaString(wb.getWorkbook())); assertEquals("C:C", ptg.toFormulaString(wb.getWorkbook()));
// Will show as C:C, but won't know how many // Will show as C:C, but won't know how many

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -21,6 +20,7 @@ package org.apache.poi.hssf.model;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg; import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.AddPtg; import org.apache.poi.hssf.record.formula.AddPtg;
import org.apache.poi.hssf.record.formula.AreaPtg; import org.apache.poi.hssf.record.formula.AreaPtg;
@ -59,18 +59,8 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
* Some tests are also done in scratchpad, if they need * Some tests are also done in scratchpad, if they need
* HSSFFormulaEvaluator, which is there * HSSFFormulaEvaluator, which is there
*/ */
public class TestFormulaParser extends TestCase { public final class TestFormulaParser extends TestCase {
public TestFormulaParser(String name) {
super(name);
}
public void setUp(){
}
public void tearDown() {
}
/** /**
* @return parsed token array already confirmed not <code>null</code> * @return parsed token array already confirmed not <code>null</code>
*/ */
@ -831,10 +821,27 @@ public class TestFormulaParser extends TestCase {
try { try {
parseFormula(formula); parseFormula(formula);
throw new AssertionFailedError("expected parse exception"); throw new AssertionFailedError("expected parse exception");
} catch (RuntimeException e) { } catch (FormulaParseException e) {
// TODO - catch more specific exception
// expected during successful test // expected during successful test
return; assertNotNull(e.getMessage());
} catch (RuntimeException e) {
e.printStackTrace();
fail("Wrong exception:" + e.getMessage());
} }
} }
public void testSetFormulaWithRowBeyond32768_Bug44539() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
wb.setSheetName(0, "Sheet1");
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short)0);
cell.setCellFormula("SUM(A32769:A32770)");
if("SUM(A-32767:A-32766)".equals(cell.getCellFormula())) {
fail("Identified bug 44539");
}
assertEquals("SUM(A32769:A32770)", cell.getCellFormula());
}
} }

View File

@ -27,15 +27,12 @@ import org.apache.poi.hssf.model.FormulaParser;
* *
* @author Dmitriy Kumshayev * @author Dmitriy Kumshayev
*/ */
public class TestAreaPtg extends TestCase public final class TestAreaPtg extends TestCase {
{
AreaPtg relative; AreaPtg relative;
AreaPtg absolute; AreaPtg absolute;
protected void setUp() throws Exception protected void setUp() {
{
super.setUp();
short firstRow=5; short firstRow=5;
short lastRow=13; short lastRow=13;
short firstCol=7; short firstCol=7;
@ -64,10 +61,9 @@ public class TestAreaPtg extends TestCase
} }
public void resetColumns(AreaPtg aptg) private static void resetColumns(AreaPtg aptg) {
{ int fc = aptg.getFirstColumn();
short fc = aptg.getFirstColumn(); int lc = aptg.getLastColumn();
short lc = aptg.getLastColumn();
aptg.setFirstColumn(fc); aptg.setFirstColumn(fc);
aptg.setLastColumn(lc); aptg.setLastColumn(lc);
assertEquals(fc , aptg.getFirstColumn() ); assertEquals(fc , aptg.getFirstColumn() );