diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 9eb163fc8..c355afd44 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -36,6 +36,7 @@ + 44539 - Support for area references in formulas of rows >= 32768 44536 - Improved support for detecting read-only recommended files 43901 - Correctly update the internal last cell number when adding and removing cells (previously sometimes off-by-one) 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 diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 201c4936d..c59cae1a3 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -33,6 +33,7 @@ + 44539 - Support for area references in formulas of rows >= 32768 44536 - Improved support for detecting read-only recommended files 43901 - Correctly update the internal last cell number when adding and removing cells (previously sometimes off-by-one) 44504 - Added initial support for recognising external functions like YEARFRAC and ISEVEN (using NameXPtg), via LinkTable support diff --git a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java index ae250246d..b2fd9ae4f 100755 --- a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - - + package org.apache.poi.hssf.record; import java.util.Stack; @@ -34,10 +32,7 @@ import org.apache.poi.hssf.record.formula.*; * record types. * @author Danny Mui at apache dot org */ - -public class SharedFormulaRecord - extends Record -{ +public final class SharedFormulaRecord extends Record { public final static short sid = 0x4BC; private int field_1_first_row; @@ -58,15 +53,15 @@ public class SharedFormulaRecord public SharedFormulaRecord(RecordInputStream in) { - super(in); + super(in); } protected void validateSid(short id) { - if (id != this.sid) - { - throw new RecordFormatException("Not a valid SharedFormula"); - } + if (id != this.sid) + { + throw new RecordFormatException("Not a valid SharedFormula"); + } } public int getFirstRow() { @@ -96,14 +91,14 @@ public class SharedFormulaRecord public int serialize(int offset, byte [] data) { - //Because this record is converted to individual Formula records, this method is not required. - throw new UnsupportedOperationException("Cannot serialize a SharedFormulaRecord"); + //Because this record is converted to individual Formula records, this method is not required. + throw new UnsupportedOperationException("Cannot serialize a SharedFormulaRecord"); } public int getRecordSize() { - //Because this record is converted to individual Formula records, this method is not required. - throw new UnsupportedOperationException("Cannot get the size for a SharedFormulaRecord"); + //Because this record is converted to individual Formula records, this method is not required. + 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) { - if(relative) { - if((column&128)!=0) column=(short)(column-256); - column+=currentcolumn; - } - return column; - } + private int fixupRelativeColumn(int currentcolumn, int column, boolean relative) { + if(relative) { + // mask out upper bits to produce 'wrapping' at column 256 ("IV") + return (column + currentcolumn) & 0x00FF; + } + return column; + } - private short fixupRelativeRow(int currentrow, short row, boolean relative) { - if(relative) { - row+=currentrow; - } - return row; - } + private int fixupRelativeRow(int currentrow, int row, boolean relative) { + if(relative) { + // mask out upper bits to produce 'wrapping' at row 65536 + return (row+currentrow) & 0x00FFFF; + } + return row; + } - /** - * Mirroring formula records so it is registered in the ValueRecordsAggregate - */ - public boolean isInValueSection() - { - return true; - } + /** + * Mirroring formula records so it is registered in the ValueRecordsAggregate + */ + public boolean isInValueSection() + { + return true; + } - /** - * Register it in the ValueRecordsAggregate so it can go into the FormulaRecordAggregate - */ - public boolean isValue() { - return true; - } + /** + * Register it in the ValueRecordsAggregate so it can go into the FormulaRecordAggregate + */ + public boolean isValue() { + return true; + } public Object clone() { - //Because this record is converted to individual Formula records, this method is not required. - throw new UnsupportedOperationException("Cannot clone a SharedFormulaRecord"); + //Because this record is converted to individual Formula records, this method is not required. + throw new UnsupportedOperationException("Cannot clone a SharedFormulaRecord"); } } diff --git a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java index c3de3758f..33278e25e 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java @@ -41,10 +41,10 @@ public class Area3DPtg extends Ptg implements AreaI public final static byte sid = 0x3b; private final static int SIZE = 11; // 10 + 1 for Ptg private short field_1_index_extern_sheet; - private short field_2_first_row; - private short field_3_last_row; - private short field_4_first_column; - private short field_5_last_column; + private int field_2_first_row; + private int field_3_last_row; + private int field_4_first_column; + private int field_5_last_column; private BitField rowRelative = BitFieldFactory.getInstance( 0x8000 ); private BitField colRelative = BitFieldFactory.getInstance( 0x4000 ); @@ -64,27 +64,27 @@ public class Area3DPtg extends Ptg implements AreaI public Area3DPtg(RecordInputStream in) { field_1_index_extern_sheet = in.readShort(); - field_2_first_row = in.readShort(); - field_3_last_row = in.readShort(); - field_4_first_column = in.readShort(); - field_5_last_column = in.readShort(); + field_2_first_row = in.readUShort(); + field_3_last_row = in.readUShort(); + field_4_first_column = in.readUShort(); + field_5_last_column = in.readUShort(); } public Area3DPtg(short firstRow, short lastRow, short firstColumn, short lastColumn, - boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative, - short externalSheetIndex) { - setFirstRow(firstRow); - setLastRow(lastRow); - setFirstColumn(firstColumn); - setLastColumn(lastColumn); - setFirstRowRelative(firstRowRelative); - setLastRowRelative(lastRowRelative); - setFirstColRelative(firstColRelative); - setLastColRelative(lastColRelative); - setExternSheetIndex(externalSheetIndex); - } + boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative, + short externalSheetIndex) { + setFirstRow(firstRow); + setLastRow(lastRow); + setFirstColumn(firstColumn); + setLastColumn(lastColumn); + setFirstRowRelative(firstRowRelative); + setLastRowRelative(lastRowRelative); + setFirstColRelative(firstColRelative); + setLastColRelative(lastColRelative); + setExternSheetIndex(externalSheetIndex); + } - public String toString() + public String toString() { StringBuffer buffer = new StringBuffer(); @@ -99,7 +99,7 @@ public class Area3DPtg extends Ptg implements AreaI buffer.append( "lastColRowRel = " + isLastRowRelative() ).append( "\n" ); buffer.append( "firstColRel = " + isFirstColRelative() ).append( "\n" ); - buffer.append( "lastColRel = " + isLastColRelative() ).append( "\n" ); + buffer.append( "lastColRel = " + isLastColRelative() ).append( "\n" ); return buffer.toString(); } @@ -107,10 +107,10 @@ public class Area3DPtg extends Ptg implements AreaI { array[0 + offset] = (byte) ( sid + ptgClass ); LittleEndian.putShort( array, 1 + offset, getExternSheetIndex() ); - LittleEndian.putShort( array, 3 + offset, getFirstRow() ); - LittleEndian.putShort( array, 5 + offset, getLastRow() ); - LittleEndian.putShort( array, 7 + offset, getFirstColumnRaw() ); - LittleEndian.putShort( array, 9 + offset, getLastColumnRaw() ); + LittleEndian.putShort( array, 3 + offset, (short)getFirstRow() ); + LittleEndian.putShort( array, 5 + offset, (short)getLastRow() ); + LittleEndian.putShort( array, 7 + offset, (short)getFirstColumnRaw() ); + LittleEndian.putShort( array, 9 + offset, (short)getLastColumnRaw() ); } public int getSize() @@ -128,32 +128,32 @@ public class Area3DPtg extends Ptg implements AreaI field_1_index_extern_sheet = index; } - public short getFirstRow() + public int getFirstRow() { return field_2_first_row; } - public void setFirstRow( short row ) + public void setFirstRow( int row ) { field_2_first_row = row; } - public short getLastRow() + public int getLastRow() { return field_3_last_row; } - public void setLastRow( short row ) + public void setLastRow( int 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; } @@ -179,12 +179,12 @@ public class Area3DPtg extends Ptg implements AreaI 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; } @@ -216,7 +216,7 @@ public class Area3DPtg extends Ptg implements AreaI */ 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 ) { - 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 ) { - 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 ) { - 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 lastCell = ar.getLastCell(); - setFirstRow( (short) frstCell.getRow() ); - setFirstColumn( frstCell.getCol() ); - setLastRow( (short) lastCell.getRow() ); - setLastColumn( lastCell.getCol() ); + setFirstRow( (short) frstCell.getRow() ); + setFirstColumn( frstCell.getCol() ); + setLastRow( (short) lastCell.getRow() ); + setLastColumn( lastCell.getCol() ); setFirstColRelative( !frstCell.isColAbsolute() ); setLastColRelative( !lastCell.isColAbsolute() ); setFirstRowRelative( !frstCell.isRowAbsolute() ); setLastRowRelative( !lastCell.isRowAbsolute() ); } - /** - * @return text representation of this area reference that can be used in text - * formulas. The sheet name will get properly delimited if required. - */ + /** + * @return text representation of this area reference that can be used in text + * formulas. The sheet name will get properly delimited if required. + */ public String toFormulaString(Workbook book) { // 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_4_first_column = field_4_first_column; ptg.field_5_last_column = field_5_last_column; - ptg.setClass(ptgClass); + ptg.setClass(ptgClass); return ptg; } diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaAPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaAPtg.java index 57628f19b..515d07dd4 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AreaAPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AreaAPtg.java @@ -36,16 +36,14 @@ import org.apache.poi.hssf.model.Workbook; * @author Jason Height (jheight at chariot dot net dot au) */ -public class AreaAPtg - extends AreaPtg -{ +public final class AreaAPtg extends AreaPtg { public final static short sid = 0x65; protected AreaAPtg() { //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); } diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaI.java b/src/java/org/apache/poi/hssf/record/formula/AreaI.java index 974ff95f0..5a0a21e86 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AreaI.java +++ b/src/java/org/apache/poi/hssf/record/formula/AreaI.java @@ -24,22 +24,22 @@ public interface AreaI { /** * @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) */ - public short getLastRow(); + public int getLastRow(); /** * @return the first column number in the area. */ - public short getFirstColumn(); + public int getFirstColumn(); /** * @return lastcolumn in the area */ - public short getLastColumn(); + public int getLastColumn(); /** * @return isrelative first column to relative or not diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java index ae408c34c..be34e0074 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java @@ -38,10 +38,14 @@ public class AreaPtg { public final static short sid = 0x25; private final static int SIZE = 9; - private short field_1_first_row; - private short field_2_last_row; - private short field_3_first_column; - private short field_4_last_column; + /** zero based, unsigned 16 bit */ + private int field_1_first_row; + /** zero based, unsigned 16 bit */ + 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 colRelative = BitFieldFactory.getInstance(0x4000); @@ -55,9 +59,9 @@ public class AreaPtg AreaReference ar = new AreaReference(arearef); CellReference firstCell = ar.getFirstCell(); CellReference lastCell = ar.getLastCell(); - setFirstRow((short)firstCell.getRow()); + setFirstRow(firstCell.getRow()); setFirstColumn(firstCell.getCol()); - setLastRow((short)lastCell.getRow()); + setLastRow(lastCell.getRow()); setLastColumn(lastCell.getCol()); setFirstColRelative(!firstCell.isColAbsolute()); setLastColRelative(!lastCell.isColAbsolute()); @@ -65,7 +69,13 @@ public class AreaPtg 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); setLastRow(lastRow); setFirstColumn(firstColumn); @@ -76,12 +86,23 @@ public class AreaPtg 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) { - field_1_first_row = in.readShort(); - field_2_last_row = in.readShort(); - field_3_first_column = in.readShort(); - field_4_last_column = in.readShort(); + field_1_first_row = in.readUShort(); + field_2_last_row = in.readUShort(); + field_3_first_column = in.readUShort(); + field_4_last_column = in.readUShort(); //System.out.println(toString()); } @@ -110,10 +131,10 @@ public class AreaPtg public void writeBytes(byte [] array, int offset) { array[offset] = (byte) (sid + ptgClass); - LittleEndian.putShort(array,offset+1,field_1_first_row); - LittleEndian.putShort(array,offset+3,field_2_last_row); - LittleEndian.putShort(array,offset+5,field_3_first_column); - LittleEndian.putShort(array,offset+7,field_4_last_column); + LittleEndian.putShort(array,offset+1,(short)field_1_first_row); + LittleEndian.putShort(array,offset+3,(short)field_2_last_row); + LittleEndian.putShort(array,offset+5,(short)field_3_first_column); + LittleEndian.putShort(array,offset+7,(short)field_4_last_column); } public int getSize() @@ -124,42 +145,42 @@ public class AreaPtg /** * @return the first row in the area */ - public short getFirstRow() + public int getFirstRow() { return field_1_first_row; } /** * sets the first row - * @param row number (0-based) + * @param rowIx number (0-based) */ - public void setFirstRow(short row) - { - field_1_first_row = row; + public void setFirstRow(int rowIx) { + checkRowBounds(rowIx); + field_1_first_row = rowIx; } /** * @return last row in the range (x2 in x1,y1-x2,y2) */ - public short getLastRow() + public int getLastRow() { 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) - { - field_2_last_row = row; + public void setLastRow(int rowIx) { + checkRowBounds(rowIx); + field_2_last_row = rowIx; } /** * @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() { - 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. */ 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 */ 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 */ - public void setFirstColumn(short column) - { - field_3_first_column=columnMask.setShortValue(field_3_first_column, column); + public void setFirstColumn(int colIx) { + checkColumnBounds(colIx); + field_3_first_column=columnMask.setValue(field_3_first_column, colIx); } /** * set the first column irespective of the bitmasks */ - public void setFirstColumnRaw(short column) + public void setFirstColumnRaw(int column) { field_3_first_column = column; } @@ -220,9 +241,9 @@ public class AreaPtg /** * @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() { - return field_4_last_column; + return (short) field_4_last_column; } /** @@ -247,7 +268,7 @@ public class AreaPtg * false */ 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 */ 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 */ - public void setLastColumn(short column) - { - field_4_last_column=columnMask.setShortValue(field_4_last_column, column); + public void setLastColumn(int colIx) { + checkColumnBounds(colIx); + field_4_last_column=columnMask.setValue(field_4_last_column, colIx); } /** diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaVPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaVPtg.java index 2974eec64..42dc11fa3 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AreaVPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AreaVPtg.java @@ -36,7 +36,7 @@ import org.apache.poi.hssf.model.Workbook; * @author Jason Height (jheight at chariot dot net dot au) */ -public class AreaVPtg +public final class AreaVPtg extends AreaPtg { public final static short sid = 0x45; @@ -45,7 +45,7 @@ public class AreaVPtg //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); } diff --git a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java index ea4c742e2..84ff659b3 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java @@ -18,16 +18,14 @@ 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.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

@@ -42,8 +40,14 @@ public class Ref3DPtg extends Ptg { public final static byte sid = 0x3a; private final static int SIZE = 7; // 6 + 1 for Ptg private short field_1_index_extern_sheet; - private short field_2_row; - private short field_3_column; + /** The row index - zero based unsigned 16 bit value */ + 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 colRelative = BitFieldFactory.getInstance(0x4000); @@ -58,8 +62,8 @@ public class Ref3DPtg extends Ptg { public Ref3DPtg(String cellref, short externIdx ) { CellReference c= new CellReference(cellref); - setRow((short) c.getRow()); - setColumn((short) c.getCol()); + setRow(c.getRow()); + setColumn(c.getCol()); setColRelative(!c.isColAbsolute()); setRowRelative(!c.isRowAbsolute()); setExternSheetIndex(externIdx); @@ -81,8 +85,8 @@ public class Ref3DPtg extends Ptg { public void writeBytes(byte [] array, int offset) { array[ 0 + offset ] = (byte) (sid + ptgClass); LittleEndian.putShort(array, 1 + offset , getExternSheetIndex()); - LittleEndian.putShort(array, 3 + offset , getRow()); - LittleEndian.putShort(array, 5 + offset , getColumnRaw()); + LittleEndian.putShort(array, 3 + offset , (short)getRow()); + LittleEndian.putShort(array, 5 + offset , (short)getColumnRaw()); } public int getSize() { @@ -97,19 +101,19 @@ public class Ref3DPtg extends Ptg { field_1_index_extern_sheet = index; } - public short getRow() { + public int getRow() { return field_2_row; } - public void setRow(short row) { + public void setRow(int row) { field_2_row = row; } - public short getColumn() { - return ( short ) (field_3_column & 0xFF); + public int getColumn() { + return field_3_column & 0xFF; } - public short getColumnRaw() { + public int getColumnRaw() { return field_3_column; } @@ -119,7 +123,7 @@ public class Ref3DPtg extends Ptg { } 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() @@ -128,7 +132,7 @@ public class Ref3DPtg extends Ptg { } 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) { field_3_column &= 0xFF00; @@ -197,5 +201,4 @@ public class Ref3DPtg extends Ptg { ptg.setClass(ptgClass); return ptg; } - } diff --git a/src/java/org/apache/poi/hssf/record/formula/RefAPtg.java b/src/java/org/apache/poi/hssf/record/formula/RefAPtg.java index 996f40e39..596b38623 100644 --- a/src/java/org/apache/poi/hssf/record/formula/RefAPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/RefAPtg.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,34 +15,23 @@ limitations under the License. ==================================================================== */ -/* - * ValueReferencePtg.java - * - * Created on November 21, 2001, 5:27 PM - */ 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.util.CellReference; -import org.apache.poi.hssf.model.Workbook; /** * RefNAPtg * @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; protected RefAPtg() { 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); } diff --git a/src/java/org/apache/poi/hssf/record/formula/RefVPtg.java b/src/java/org/apache/poi/hssf/record/formula/RefVPtg.java index b9d55a09e..8a6b2c03b 100644 --- a/src/java/org/apache/poi/hssf/record/formula/RefVPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/RefVPtg.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -18,27 +17,20 @@ 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.util.CellReference; -import org.apache.poi.hssf.model.Workbook; /** * RefVPtg * @author Jason Height (jheight at chariot dot net dot au) */ - -public class RefVPtg extends ReferencePtg -{ +public final class RefVPtg extends ReferencePtg { public final static byte sid = 0x44; protected RefVPtg() { 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); } diff --git a/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java b/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java index 3afd64192..4983c9d07 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java @@ -31,26 +31,22 @@ import org.apache.poi.hssf.record.RecordInputStream; * @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; public final static byte sid = 0x24; private final static int MAX_ROW_NUMBER = 65536; - //public final static byte sid = 0x44; - /** - * The row number, between 0 and 65535, but stored as a signed - * short between -32767 and 32768. - * Take care about which version you fetch back! + /** The row index - zero based unsigned 16 bit value */ + private int field_1_row; + /** Field 2 + * - lower 8 bits is the zero based unsigned byte column index + * - bit 16 - isRowRelative + * - bit 15 - isColumnRelative */ - private short field_1_row; - /** - * The column number, between 0 and ?? - */ - private short field_2_col; - private BitField rowRelative = BitFieldFactory.getInstance(0x8000); - private BitField colRelative = BitFieldFactory.getInstance(0x4000); - private BitField column = BitFieldFactory.getInstance(0x3FFF); + private int field_2_col; + private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000); + private static final BitField colRelative = BitFieldFactory.getInstance(0x4000); + private static final BitField column = BitFieldFactory.getInstance(0x00FF); protected ReferencePtg() { //Required for clone methods @@ -62,13 +58,13 @@ public class ReferencePtg extends Ptg */ public ReferencePtg(String cellref) { CellReference c= new CellReference(cellref); - setRow((short) c.getRow()); - setColumn((short) c.getCol()); + setRow(c.getRow()); + setColumn(c.getCol()); setColRelative(!c.isColAbsolute()); 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); setColumn(column); setRowRelative(isRowRelative); @@ -79,8 +75,8 @@ public class ReferencePtg extends Ptg public ReferencePtg(RecordInputStream in) { - field_1_row = in.readShort(); - field_2_col = in.readShort(); + field_1_row = in.readUShort(); + field_2_col = in.readUShort(); } public String getRefPtgName() { @@ -104,33 +100,23 @@ public class ReferencePtg extends Ptg { array[offset] = (byte) (sid + ptgClass); - LittleEndian.putShort(array,offset+1,field_1_row); - LittleEndian.putShort(array,offset+3,field_2_col); + LittleEndian.putShort(array, offset+1, (short)field_1_row); + LittleEndian.putShort(array, offset+3, (short)field_2_col); } - public void setRow(short row) - { - field_1_row = row; - } public void setRow(int row) { 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); } - - // Save, wrapping as needed - if(row > Short.MAX_VALUE) { - field_1_row = (short)(row - MAX_ROW_NUMBER); - } else { - field_1_row = (short)row; - } + field_1_row = row; } /** * Returns the row number as a short, which will be * wrapped (negative) for values between 32769 and 65535 */ - public short getRow() + public int getRow() { return field_1_row; } @@ -151,7 +137,7 @@ public class ReferencePtg extends Ptg } 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() @@ -160,27 +146,29 @@ public class ReferencePtg extends Ptg } 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; } - public short getColumnRaw() + public int getColumnRaw() { 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() - { - return column.getShortValue(field_2_col); + public int getColumn() { + return column.getValue(field_2_col); } public int getSize() diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java index 30bdc01f5..66f79ffd8 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java @@ -287,17 +287,30 @@ public final class HSSFRow implements Comparable { } /** - * 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. + * 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. + * Short method signature provided to retain binary + * compatibility. * * @param cellnum 0 based column number * @return HSSFCell representing that column or null if undefined. */ - public HSSFCell getCell(short cellnum) { - if(cellnum<0||cellnum>=cells.length) return null; - return cells[cellnum]; + return getCell((int)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]; } /** diff --git a/src/java/org/apache/poi/hssf/util/AreaReference.java b/src/java/org/apache/poi/hssf/util/AreaReference.java index fbd128842..3f6b321a6 100644 --- a/src/java/org/apache/poi/hssf/util/AreaReference.java +++ b/src/java/org/apache/poi/hssf/util/AreaReference.java @@ -53,9 +53,10 @@ public final class AreaReference { parts[1].length() == 1 && parts[0].charAt(0) >= 'A' && parts[0].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[1] = parts[1] + "$0"; + parts[1] = parts[1] + "$65536"; } _firstCell = new CellReference(parts[0]); @@ -98,10 +99,10 @@ public final class AreaReference { */ public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) { // 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 if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() && - botRight.getRow() == -1 && botRight.isRowAbsolute()) { + botRight.getRow() == 65535 && botRight.isRowAbsolute()) { return true; } return false; diff --git a/src/java/org/apache/poi/hssf/util/CellReference.java b/src/java/org/apache/poi/hssf/util/CellReference.java index cb8368772..47d579d94 100644 --- a/src/java/org/apache/poi/hssf/util/CellReference.java +++ b/src/java/org/apache/poi/hssf/util/CellReference.java @@ -71,6 +71,14 @@ public final class CellReference { this(null, pRow, pCol, pAbsRow, 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; _rowIndex=pRow; _colIndex=pCol; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Area2DEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Area2DEval.java index 179698dc8..4b9a64c1c 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Area2DEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Area2DEval.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Created on May 8, 2005 - * - */ + package org.apache.poi.hssf.record.formula.eval; import org.apache.poi.hssf.record.formula.AreaPtg; @@ -27,48 +24,60 @@ import org.apache.poi.hssf.record.formula.Ptg; * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class Area2DEval implements AreaEval { +public final class Area2DEval implements AreaEval { +// TODO -refactor with Area3DEval + private final AreaPtg _delegate; - private AreaPtg delegate; - - private ValueEval[] values; + private final ValueEval[] _values; public Area2DEval(Ptg ptg, ValueEval[] values) { - this.delegate = (AreaPtg) ptg; - this.values = values; + if(ptg == null) { + 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() { - return delegate.getFirstColumn(); + public int getFirstColumn() { + return _delegate.getFirstColumn(); } public int getFirstRow() { - return delegate.getFirstRow(); + return _delegate.getFirstRow(); } - public short getLastColumn() { - return delegate.getLastColumn(); + public int getLastColumn() { + return _delegate.getLastColumn(); } public int getLastRow() { - return delegate.getLastRow(); + return _delegate.getLastRow(); } public ValueEval[] getValues() { - return values; + return _values; } - public ValueEval getValueAt(int row, short col) { + public ValueEval getValueAt(int row, int col) { ValueEval retval; 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; else - retval = values[index]; + retval = _values[index]; return retval; } - public boolean contains(int row, short col) { + public boolean contains(int row, int col) { return (getFirstRow() <= row) && (getLastRow() >= row) && (getFirstColumn() <= col) && (getLastColumn() >= col); } @@ -82,10 +91,10 @@ public class Area2DEval implements AreaEval { } public boolean isColumn() { - return delegate.getFirstColumn() == delegate.getLastColumn(); + return _delegate.getFirstColumn() == _delegate.getLastColumn(); } public boolean isRow() { - return delegate.getFirstRow() == delegate.getLastRow(); + return _delegate.getFirstRow() == _delegate.getLastRow(); } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Area3DEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Area3DEval.java index b997b95c6..2f539142d 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Area3DEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Area3DEval.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Created on May 8, 2005 - * - */ + package org.apache.poi.hssf.record.formula.eval; 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 { + // TODO -refactor with Area3DEval + private final Area3DPtg _delegate; - private Area3DPtg delegate; - - private ValueEval[] values; + private final ValueEval[] _values; public Area3DEval(Ptg ptg, ValueEval[] values) { - this.values = values; - this.delegate = (Area3DPtg) ptg; + if(ptg == null) { + 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() { - return delegate.getFirstColumn(); + public int getFirstColumn() { + return _delegate.getFirstColumn(); } public int getFirstRow() { - return delegate.getFirstRow(); + return _delegate.getFirstRow(); } - public short getLastColumn() { - return delegate.getLastColumn(); + public int getLastColumn() { + return (short) _delegate.getLastColumn(); } public int getLastRow() { - return delegate.getLastRow(); + return _delegate.getLastRow(); } public ValueEval[] getValues() { - return values; + return _values; } - public ValueEval getValueAt(int row, short col) { + public ValueEval getValueAt(int row, int col) { ValueEval retval; int index = (row-getFirstRow())*(col-getFirstColumn()); - if (index <0 || index >= values.length) + if (index <0 || index >= _values.length) retval = ErrorEval.VALUE_INVALID; else - retval = values[index]; + retval = _values[index]; return retval; } - public boolean contains(int row, short col) { + public boolean contains(int row, int col) { return (getFirstRow() <= row) && (getLastRow() >= row) && (getFirstColumn() <= col) && (getLastColumn() >= col); } @@ -83,15 +92,14 @@ public final class Area3DEval implements AreaEval { public boolean isColumn() { - return delegate.getFirstColumn() == delegate.getLastColumn(); + return _delegate.getFirstColumn() == _delegate.getLastColumn(); } public boolean isRow() { - return delegate.getFirstRow() == delegate.getLastRow(); + return _delegate.getFirstRow() == _delegate.getLastRow(); } public int getExternSheetIndex() { - return delegate.getExternSheetIndex(); + return _delegate.getExternSheetIndex(); } - } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AreaEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AreaEval.java index f60d63c13..82cc8a9b4 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AreaEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AreaEval.java @@ -42,13 +42,13 @@ public interface AreaEval extends ValueEval { * returns the 0-based index of the first col in * this area. */ - public short getFirstColumn(); + public int getFirstColumn(); /** * returns the 0-based index of the last col in * this area. */ - public short getLastColumn(); + public int getLastColumn(); /** * returns true if the Area's start and end row indexes @@ -80,7 +80,7 @@ public interface AreaEval extends ValueEval { * @param row * @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 @@ -89,7 +89,7 @@ public interface AreaEval extends ValueEval { * @param row * @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 diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java index 4dd055c6c..898d7a861 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java @@ -29,16 +29,22 @@ public final class Ref2DEval implements RefEval { private final ReferencePtg delegate; 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; delegate = ptg; } public ValueEval getInnerValueEval() { return value; } - public short getRow() { + public int getRow() { return delegate.getRow(); } - public short getColumn() { + public int getColumn() { return delegate.getColumn(); } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java index 7ecca2678..622d68632 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java @@ -29,16 +29,22 @@ public final class Ref3DEval implements RefEval { private final Ref3DPtg delegate; 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; delegate = ptg; } public ValueEval getInnerValueEval() { return value; } - public short getRow() { + public int getRow() { return delegate.getRow(); } - public short getColumn() { + public int getColumn() { return delegate.getColumn(); } public int getExternSheetIndex() { diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/RefEval.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/RefEval.java index 48a94b024..e462586d7 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/RefEval.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/RefEval.java @@ -40,12 +40,12 @@ public interface RefEval extends ValueEval { 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(); } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/LookupUtils.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/LookupUtils.java index 66123b298..d6a848962 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/LookupUtils.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/LookupUtils.java @@ -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. // This code only requires the value array item. // anything would be ok for rowIx and colIx, but may as well get it right. - short rowIx = refEval.getRow(); - short colIx = refEval.getColumn(); + int rowIx = refEval.getRow(); + int colIx = refEval.getColumn(); AreaPtg ap = new AreaPtg(rowIx, rowIx, colIx, colIx, false, false, false, false); ValueEval value = refEval.getInnerValueEval(); return new Area2DEval(ap, new ValueEval[] { value, }); diff --git a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java index 3cbec2e6d..3fce30655 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java +++ b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java @@ -14,10 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Created on May 5, 2005 - * - */ + package org.apache.poi.hssf.usermodel; import java.lang.reflect.Constructor; @@ -420,20 +417,20 @@ public class HSSFFormulaEvaluator { } else if (ptg instanceof ReferencePtg) { ReferencePtg refPtg = (ReferencePtg) ptg; - short colnum = refPtg.getColumn(); - short rownum = refPtg.getRow(); - HSSFRow row = sheet.getRow(rownum); - HSSFCell cell = (row != null) ? row.getCell(colnum) : null; + int colIx = refPtg.getColumn(); + int rowIx = refPtg.getRow(); + HSSFRow row = sheet.getRow(rowIx); + HSSFCell cell = (row != null) ? row.getCell(colIx) : null; stack.push(createRef2DEval(refPtg, cell, row, sheet, workbook)); } else if (ptg instanceof Ref3DPtg) { Ref3DPtg refPtg = (Ref3DPtg) ptg; - short colnum = refPtg.getColumn(); - short rownum = refPtg.getRow(); + int colIx = refPtg.getColumn(); + int rowIx = refPtg.getRow(); Workbook wb = workbook.getWorkbook(); HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex())); - HSSFRow row = xsheet.getRow(rownum); - HSSFCell cell = (row != null) ? row.getCell(colnum) : null; + HSSFRow row = xsheet.getRow(rowIx); + HSSFCell cell = (row != null) ? row.getCell(colIx) : null; stack.push(createRef3DEval(refPtg, cell, row, xsheet, workbook)); } else if (ptg instanceof AreaPtg) { @@ -506,10 +503,10 @@ public class HSSFFormulaEvaluator { } public static AreaEval evaluateAreaPtg(HSSFSheet sheet, HSSFWorkbook workbook, AreaPtg ap) { - short row0 = ap.getFirstRow(); - short col0 = ap.getFirstColumn(); - short row1 = ap.getLastRow(); - short col1 = ap.getLastColumn(); + int row0 = ap.getFirstRow(); + int col0 = ap.getFirstColumn(); + int row1 = ap.getLastRow(); + int col1 = ap.getLastColumn(); // If the last row is -1, then the // reference is for the rest of the column @@ -518,24 +515,15 @@ public class HSSFFormulaEvaluator { if(row1 == -1 && row0 >= 0) { row1 = (short)sheet.getLastRowNum(); } - - ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)]; - 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; + ValueEval[] values = evalArea(workbook, sheet, row0, col0, row1, col1); + return new Area2DEval(ap, values); } public static AreaEval evaluateArea3dPtg(HSSFWorkbook workbook, Area3DPtg a3dp) { - short row0 = a3dp.getFirstRow(); - short col0 = a3dp.getFirstColumn(); - short row1 = a3dp.getLastRow(); - short col1 = a3dp.getLastColumn(); + int row0 = a3dp.getFirstRow(); + int col0 = a3dp.getFirstColumn(); + int row1 = a3dp.getLastRow(); + int col1 = a3dp.getLastColumn(); Workbook wb = workbook.getWorkbook(); HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex())); @@ -547,19 +535,28 @@ public class HSSFFormulaEvaluator { 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)]; - for (short x = row0; xsheet != null && x < row1 + 1; x++) { - HSSFRow row = xsheet.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, xsheet, workbook); + for (int x = row0; sheet != null && x < row1 + 1; x++) { + HSSFRow row = sheet.getRow(x); + for (int y = col0; y < col1 + 1; y++) { + ValueEval cellEval; + 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 ae; + return values; } - /** * returns the OperationEval concrete impl instance corresponding * to the suplied operationPtg diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/model/TestFormulaParserSP.java b/src/scratchpad/testcases/org/apache/poi/hssf/model/TestFormulaParserSP.java index aa73714a0..0141e1b2a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/model/TestFormulaParserSP.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/model/TestFormulaParserSP.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,30 +14,30 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.model; 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.NamePtg; 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.HSSFName; +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.usermodel.HSSFFormulaEvaluator.CellValue; /** * Test the low level formula parser functionality, * but using parts which need to use the * 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 { HSSFWorkbook workbook = new HSSFWorkbook(); FormulaParser fp; @@ -80,4 +79,32 @@ public class TestFormulaParserSP extends TestCase { 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); + } } diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44410.java b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44410.java index 03e35e6af..27c3bdc38 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44410.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/usermodel/TestBug44410.java @@ -63,12 +63,13 @@ public class TestBug44410 extends TestCase { assertEquals(AreaPtg.class, ops.get(0).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); assertEquals(2, ptg.getFirstColumn()); assertEquals(2, ptg.getLastColumn()); assertEquals(0, ptg.getFirstRow()); - assertEquals(-1, ptg.getLastRow()); + assertEquals(65535, ptg.getLastRow()); assertEquals("C:C", ptg.toFormulaString(wb.getWorkbook())); // Will show as C:C, but won't know how many diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java index 7b42bf333..f922e75d8 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java +++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -21,6 +20,7 @@ package org.apache.poi.hssf.model; import junit.framework.AssertionFailedError; 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.AddPtg; 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 * 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 null */ @@ -831,10 +821,27 @@ public class TestFormulaParser extends TestCase { try { parseFormula(formula); throw new AssertionFailedError("expected parse exception"); - } catch (RuntimeException e) { - // TODO - catch more specific exception + } catch (FormulaParseException e) { // 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()); + } } diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestAreaPtg.java b/src/testcases/org/apache/poi/hssf/record/formula/TestAreaPtg.java index 522a5bcf2..3a7f2f29a 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestAreaPtg.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/TestAreaPtg.java @@ -27,15 +27,12 @@ import org.apache.poi.hssf.model.FormulaParser; * * @author Dmitriy Kumshayev */ -public class TestAreaPtg extends TestCase -{ +public final class TestAreaPtg extends TestCase { AreaPtg relative; AreaPtg absolute; - protected void setUp() throws Exception - { - super.setUp(); + protected void setUp() { short firstRow=5; short lastRow=13; short firstCol=7; @@ -64,10 +61,9 @@ public class TestAreaPtg extends TestCase } - public void resetColumns(AreaPtg aptg) - { - short fc = aptg.getFirstColumn(); - short lc = aptg.getLastColumn(); + private static void resetColumns(AreaPtg aptg) { + int fc = aptg.getFirstColumn(); + int lc = aptg.getLastColumn(); aptg.setFirstColumn(fc); aptg.setLastColumn(lc); assertEquals(fc , aptg.getFirstColumn() );