fix error message

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1828364 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2018-04-04 16:55:46 +00:00
parent 16d25b62af
commit af19295590
2 changed files with 182 additions and 182 deletions

View File

@ -41,203 +41,203 @@ import org.apache.poi.ss.formula.eval.ValueEval;
* @author Josh Micich * @author Josh Micich
*/ */
public final class Offset implements Function { public final class Offset implements Function {
// These values are specific to BIFF8 // These values are specific to BIFF8
private static final int LAST_VALID_ROW_INDEX = 0xFFFF; private static final int LAST_VALID_ROW_INDEX = 0xFFFF;
private static final int LAST_VALID_COLUMN_INDEX = 0xFF; private static final int LAST_VALID_COLUMN_INDEX = 0xFF;
/** /**
* A one dimensional base + offset. Represents either a row range or a column range. * A one dimensional base + offset. Represents either a row range or a column range.
* Two instances of this class together specify an area range. * Two instances of this class together specify an area range.
*/ */
/* package */ static final class LinearOffsetRange { /* package */ static final class LinearOffsetRange {
private final int _offset; private final int _offset;
private final int _length; private final int _length;
public LinearOffsetRange(int offset, int length) { public LinearOffsetRange(int offset, int length) {
if(length == 0) { if(length == 0) {
// handled that condition much earlier // handled that condition much earlier
throw new RuntimeException("length may not be zero"); throw new RuntimeException("length may not be zero");
} }
_offset = offset; _offset = offset;
_length = length; _length = length;
} }
public short getFirstIndex() { public short getFirstIndex() {
return (short) _offset; return (short) _offset;
} }
public short getLastIndex() { public short getLastIndex() {
return (short) (_offset + _length - 1); return (short) (_offset + _length - 1);
} }
/** /**
* Moves the range by the specified translation amount.<p> * Moves the range by the specified translation amount.<p>
* *
* This method also 'normalises' the range: Excel specifies that the width and height * This method also 'normalises' the range: Excel specifies that the width and height
* parameters (length field here) cannot be negative. However, OFFSET() does produce * parameters (length field here) cannot be negative. However, OFFSET() does produce
* sensible results in these cases. That behavior is replicated here. <p> * sensible results in these cases. That behavior is replicated here. <p>
* *
* @param translationAmount may be zero negative or positive * @param translationAmount may be zero negative or positive
* *
* @return the equivalent <tt>LinearOffsetRange</tt> with a positive length, moved by the * @return the equivalent <tt>LinearOffsetRange</tt> with a positive length, moved by the
* specified translationAmount. * specified translationAmount.
*/ */
public LinearOffsetRange normaliseAndTranslate(int translationAmount) { public LinearOffsetRange normaliseAndTranslate(int translationAmount) {
if (_length > 0) { if (_length > 0) {
if(translationAmount == 0) { if(translationAmount == 0) {
return this; return this;
} }
return new LinearOffsetRange(translationAmount + _offset, _length); return new LinearOffsetRange(translationAmount + _offset, _length);
} }
return new LinearOffsetRange(translationAmount + _offset + _length + 1, -_length); return new LinearOffsetRange(translationAmount + _offset + _length + 1, -_length);
} }
public boolean isOutOfBounds(int lowValidIx, int highValidIx) { public boolean isOutOfBounds(int lowValidIx, int highValidIx) {
if(_offset < lowValidIx) { if(_offset < lowValidIx) {
return true; return true;
} }
if(getLastIndex() > highValidIx) { if(getLastIndex() > highValidIx) {
return true; return true;
} }
return false; return false;
} }
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer(64); StringBuilder sb = new StringBuilder(64);
sb.append(getClass().getName()).append(" ["); sb.append(getClass().getName()).append(" [");
sb.append(_offset).append("...").append(getLastIndex()); sb.append(_offset).append("...").append(getLastIndex());
sb.append("]"); sb.append("]");
return sb.toString(); return sb.toString();
} }
} }
/** /**
* Encapsulates either an area or cell reference which may be 2d or 3d. * Encapsulates either an area or cell reference which may be 2d or 3d.
*/ */
private static final class BaseRef { private static final class BaseRef {
private final int _firstRowIndex; private final int _firstRowIndex;
private final int _firstColumnIndex; private final int _firstColumnIndex;
private final int _width; private final int _width;
private final int _height; private final int _height;
private final RefEval _refEval; private final RefEval _refEval;
private final AreaEval _areaEval; private final AreaEval _areaEval;
public BaseRef(RefEval re) { public BaseRef(RefEval re) {
_refEval = re; _refEval = re;
_areaEval = null; _areaEval = null;
_firstRowIndex = re.getRow(); _firstRowIndex = re.getRow();
_firstColumnIndex = re.getColumn(); _firstColumnIndex = re.getColumn();
_height = 1; _height = 1;
_width = 1; _width = 1;
} }
public BaseRef(AreaEval ae) { public BaseRef(AreaEval ae) {
_refEval = null; _refEval = null;
_areaEval = ae; _areaEval = ae;
_firstRowIndex = ae.getFirstRow(); _firstRowIndex = ae.getFirstRow();
_firstColumnIndex = ae.getFirstColumn(); _firstColumnIndex = ae.getFirstColumn();
_height = ae.getLastRow() - ae.getFirstRow() + 1; _height = ae.getLastRow() - ae.getFirstRow() + 1;
_width = ae.getLastColumn() - ae.getFirstColumn() + 1; _width = ae.getLastColumn() - ae.getFirstColumn() + 1;
} }
public int getWidth() { public int getWidth() {
return _width; return _width;
} }
public int getHeight() { public int getHeight() {
return _height; return _height;
} }
public int getFirstRowIndex() { public int getFirstRowIndex() {
return _firstRowIndex; return _firstRowIndex;
} }
public int getFirstColumnIndex() { public int getFirstColumnIndex() {
return _firstColumnIndex; return _firstColumnIndex;
} }
public AreaEval offset(int relFirstRowIx, int relLastRowIx, public AreaEval offset(int relFirstRowIx, int relLastRowIx,
int relFirstColIx, int relLastColIx) { int relFirstColIx, int relLastColIx) {
if (_refEval == null) { if (_refEval == null) {
return _areaEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); return _areaEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
} }
return _refEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx); return _refEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
} }
} }
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) { public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
if(args.length < 1 || args.length > 5) { if(args.length < 1 || args.length > 5) {
return ErrorEval.VALUE_INVALID; return ErrorEval.VALUE_INVALID;
} }
try { try {
BaseRef baseRef = evaluateBaseRef(args[0]); BaseRef baseRef = evaluateBaseRef(args[0]);
// optional arguments // optional arguments
// If offsets are omitted, it is assumed to be 0. // If offsets are omitted, it is assumed to be 0.
int rowOffset = (args[1] instanceof MissingArgEval) ? 0 : evaluateIntArg(args[1], srcCellRow, srcCellCol); int rowOffset = (args[1] instanceof MissingArgEval) ? 0 : evaluateIntArg(args[1], srcCellRow, srcCellCol);
int columnOffset = (args[2] instanceof MissingArgEval) ? 0 : evaluateIntArg(args[2], srcCellRow, srcCellCol); int columnOffset = (args[2] instanceof MissingArgEval) ? 0 : evaluateIntArg(args[2], srcCellRow, srcCellCol);
int height = baseRef.getHeight(); int height = baseRef.getHeight();
int width = baseRef.getWidth(); int width = baseRef.getWidth();
// optional arguments // optional arguments
// If height or width are omitted, it is assumed to be the same height or width as reference. // If height or width are omitted, it is assumed to be the same height or width as reference.
switch(args.length) { switch(args.length) {
case 5: case 5:
if(!(args[4] instanceof MissingArgEval)) { if(!(args[4] instanceof MissingArgEval)) {
width = evaluateIntArg(args[4], srcCellRow, srcCellCol); width = evaluateIntArg(args[4], srcCellRow, srcCellCol);
} }
// fall-through to pick up height // fall-through to pick up height
case 4: case 4:
if(!(args[3] instanceof MissingArgEval)) { if(!(args[3] instanceof MissingArgEval)) {
height = evaluateIntArg(args[3], srcCellRow, srcCellCol); height = evaluateIntArg(args[3], srcCellRow, srcCellCol);
} }
break; break;
//case 3: //case 3:
// nothing to do // nothing to do
default: default:
break; break;
} }
// Zero height or width raises #REF! error // Zero height or width raises #REF! error
if(height == 0 || width == 0) { if(height == 0 || width == 0) {
return ErrorEval.REF_INVALID; return ErrorEval.REF_INVALID;
} }
LinearOffsetRange rowOffsetRange = new LinearOffsetRange(rowOffset, height); LinearOffsetRange rowOffsetRange = new LinearOffsetRange(rowOffset, height);
LinearOffsetRange colOffsetRange = new LinearOffsetRange(columnOffset, width); LinearOffsetRange colOffsetRange = new LinearOffsetRange(columnOffset, width);
return createOffset(baseRef, rowOffsetRange, colOffsetRange); return createOffset(baseRef, rowOffsetRange, colOffsetRange);
} catch (EvaluationException e) { } catch (EvaluationException e) {
return e.getErrorEval(); return e.getErrorEval();
} }
} }
private static AreaEval createOffset(BaseRef baseRef, private static AreaEval createOffset(BaseRef baseRef,
LinearOffsetRange orRow, LinearOffsetRange orCol) throws EvaluationException { LinearOffsetRange orRow, LinearOffsetRange orCol) throws EvaluationException {
LinearOffsetRange absRows = orRow.normaliseAndTranslate(baseRef.getFirstRowIndex()); LinearOffsetRange absRows = orRow.normaliseAndTranslate(baseRef.getFirstRowIndex());
LinearOffsetRange absCols = orCol.normaliseAndTranslate(baseRef.getFirstColumnIndex()); LinearOffsetRange absCols = orCol.normaliseAndTranslate(baseRef.getFirstColumnIndex());
if(absRows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) { if(absRows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
throw new EvaluationException(ErrorEval.REF_INVALID); throw new EvaluationException(ErrorEval.REF_INVALID);
} }
if(absCols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) { if(absCols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
throw new EvaluationException(ErrorEval.REF_INVALID); throw new EvaluationException(ErrorEval.REF_INVALID);
} }
return baseRef.offset(orRow.getFirstIndex(), orRow.getLastIndex(), orCol.getFirstIndex(), orCol.getLastIndex()); return baseRef.offset(orRow.getFirstIndex(), orRow.getLastIndex(), orCol.getFirstIndex(), orCol.getLastIndex());
} }
private static BaseRef evaluateBaseRef(ValueEval eval) throws EvaluationException { private static BaseRef evaluateBaseRef(ValueEval eval) throws EvaluationException {
if(eval instanceof RefEval) { if(eval instanceof RefEval) {
return new BaseRef((RefEval)eval); return new BaseRef((RefEval)eval);
} }
if(eval instanceof AreaEval) { if(eval instanceof AreaEval) {
return new BaseRef((AreaEval)eval); return new BaseRef((AreaEval)eval);
} }
if (eval instanceof ErrorEval) { if (eval instanceof ErrorEval) {
throw new EvaluationException((ErrorEval) eval); throw new EvaluationException((ErrorEval) eval);
} }
throw new EvaluationException(ErrorEval.VALUE_INVALID); throw new EvaluationException(ErrorEval.VALUE_INVALID);
} }
/** /**
* OFFSET's numeric arguments (2..5) have similar processing rules * OFFSET's numeric arguments (2..5) have similar processing rules
*/ */
static int evaluateIntArg(ValueEval eval, int srcCellRow, int srcCellCol) throws EvaluationException { static int evaluateIntArg(ValueEval eval, int srcCellRow, int srcCellCol) throws EvaluationException {
ValueEval ve = OperandResolver.getSingleValue(eval, srcCellRow, srcCellCol); ValueEval ve = OperandResolver.getSingleValue(eval, srcCellRow, srcCellCol);
return OperandResolver.coerceValueToInt(ve); return OperandResolver.coerceValueToInt(ve);
} }
} }

View File

@ -156,7 +156,7 @@ public class TestCellFormatPart extends CellFormatTestBase {
Matcher m = NUMBER_EXTRACT_FMT.matcher(str); Matcher m = NUMBER_EXTRACT_FMT.matcher(str);
if (!m.find()) if (!m.find())
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Cannot find numer in \"" + str + "\""); "Cannot find number in \"" + str + "\"");
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
// The groups in the pattern are the parts of the number // The groups in the pattern are the parts of the number