first commit

This commit is contained in:
2025-07-28 13:56:49 +05:30
commit e9eb805edb
3438 changed files with 520990 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class Add extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "+";
}
Token getToken() {
return Token.ADD;
}
int getPrecedence() {
return 4;
}
}

View File

@@ -0,0 +1,161 @@
package jxl.biff.formula;
import common.Assert;
import common.Logger;
import jxl.biff.CellReferenceHelper;
import jxl.biff.IntegerHelper;
class Area extends Operand implements ParsedThing {
private static Logger logger = Logger.getLogger(Area.class);
private int columnFirst;
private int rowFirst;
private int columnLast;
private int rowLast;
private boolean columnFirstRelative;
private boolean rowFirstRelative;
private boolean columnLastRelative;
private boolean rowLastRelative;
Area() {}
Area(String s) {
int seppos = s.indexOf(":");
Assert.verify((seppos != -1));
String startcell = s.substring(0, seppos);
String endcell = s.substring(seppos + 1);
this.columnFirst = CellReferenceHelper.getColumn(startcell);
this.rowFirst = CellReferenceHelper.getRow(startcell);
this.columnLast = CellReferenceHelper.getColumn(endcell);
this.rowLast = CellReferenceHelper.getRow(endcell);
this.columnFirstRelative = CellReferenceHelper.isColumnRelative(startcell);
this.rowFirstRelative = CellReferenceHelper.isRowRelative(startcell);
this.columnLastRelative = CellReferenceHelper.isColumnRelative(endcell);
this.rowLastRelative = CellReferenceHelper.isRowRelative(endcell);
}
int getFirstColumn() {
return this.columnFirst;
}
int getFirstRow() {
return this.rowFirst;
}
int getLastColumn() {
return this.columnLast;
}
int getLastRow() {
return this.rowLast;
}
public int read(byte[] data, int pos) {
this.rowFirst = IntegerHelper.getInt(data[pos], data[pos + 1]);
this.rowLast = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
int columnMask = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
this.columnFirst = columnMask & 0xFF;
this.columnFirstRelative = ((columnMask & 0x4000) != 0);
this.rowFirstRelative = ((columnMask & 0x8000) != 0);
columnMask = IntegerHelper.getInt(data[pos + 6], data[pos + 7]);
this.columnLast = columnMask & 0xFF;
this.columnLastRelative = ((columnMask & 0x4000) != 0);
this.rowLastRelative = ((columnMask & 0x8000) != 0);
return 8;
}
public void getString(StringBuffer buf) {
CellReferenceHelper.getCellReference(this.columnFirst, this.rowFirst, buf);
buf.append(':');
CellReferenceHelper.getCellReference(this.columnLast, this.rowLast, buf);
}
byte[] getBytes() {
byte[] data = new byte[9];
data[0] = !useAlternateCode() ? Token.AREA.getCode() : Token.AREA.getCode2();
IntegerHelper.getTwoBytes(this.rowFirst, data, 1);
IntegerHelper.getTwoBytes(this.rowLast, data, 3);
int grcol = this.columnFirst;
if (this.rowFirstRelative)
grcol |= 0x8000;
if (this.columnFirstRelative)
grcol |= 0x4000;
IntegerHelper.getTwoBytes(grcol, data, 5);
grcol = this.columnLast;
if (this.rowLastRelative)
grcol |= 0x8000;
if (this.columnLastRelative)
grcol |= 0x4000;
IntegerHelper.getTwoBytes(grcol, data, 7);
return data;
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
if (this.columnFirstRelative)
this.columnFirst += colAdjust;
if (this.columnLastRelative)
this.columnLast += colAdjust;
if (this.rowFirstRelative)
this.rowFirst += rowAdjust;
if (this.rowLastRelative)
this.rowLast += rowAdjust;
}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {
if (!currentSheet)
return;
if (col <= this.columnFirst)
this.columnFirst++;
if (col <= this.columnLast)
this.columnLast++;
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
if (!currentSheet)
return;
if (col < this.columnFirst)
this.columnFirst--;
if (col <= this.columnLast)
this.columnLast--;
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
if (!currentSheet)
return;
if (this.rowLast == 65535)
return;
if (row <= this.rowFirst)
this.rowFirst++;
if (row <= this.rowLast)
this.rowLast++;
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
if (!currentSheet)
return;
if (this.rowLast == 65535)
return;
if (row < this.rowFirst)
this.rowFirst--;
if (row <= this.rowLast)
this.rowLast--;
}
protected void setRangeData(int colFirst, int colLast, int rwFirst, int rwLast, boolean colFirstRel, boolean colLastRel, boolean rowFirstRel, boolean rowLastRel) {
this.columnFirst = colFirst;
this.columnLast = colLast;
this.rowFirst = rwFirst;
this.rowLast = rwLast;
this.columnFirstRelative = colFirstRel;
this.columnLastRelative = colLastRel;
this.rowFirstRelative = rowFirstRel;
this.rowLastRelative = rowLastRel;
}
}

View File

@@ -0,0 +1,178 @@
package jxl.biff.formula;
import common.Assert;
import common.Logger;
import jxl.biff.CellReferenceHelper;
import jxl.biff.IntegerHelper;
class Area3d extends Operand implements ParsedThing {
private static Logger logger = Logger.getLogger(Area3d.class);
private int sheet;
private int columnFirst;
private int rowFirst;
private int columnLast;
private int rowLast;
private boolean columnFirstRelative;
private boolean rowFirstRelative;
private boolean columnLastRelative;
private boolean rowLastRelative;
private ExternalSheet workbook;
Area3d(ExternalSheet es) {
this.workbook = es;
}
Area3d(String s, ExternalSheet es) throws FormulaException {
this.workbook = es;
int seppos = s.lastIndexOf(":");
Assert.verify((seppos != -1));
String endcell = s.substring(seppos + 1);
int sep = s.indexOf('!');
String cellString = s.substring(sep + 1, seppos);
this.columnFirst = CellReferenceHelper.getColumn(cellString);
this.rowFirst = CellReferenceHelper.getRow(cellString);
String sheetName = s.substring(0, sep);
if (sheetName.charAt(0) == '\'' && sheetName.charAt(sheetName.length() - 1) == '\'')
sheetName = sheetName.substring(1, sheetName.length() - 1);
this.sheet = es.getExternalSheetIndex(sheetName);
if (this.sheet < 0)
throw new FormulaException(FormulaException.sheetRefNotFound, sheetName);
this.columnLast = CellReferenceHelper.getColumn(endcell);
this.rowLast = CellReferenceHelper.getRow(endcell);
this.columnFirstRelative = true;
this.rowFirstRelative = true;
this.columnLastRelative = true;
this.rowLastRelative = true;
}
int getFirstColumn() {
return this.columnFirst;
}
int getFirstRow() {
return this.rowFirst;
}
int getLastColumn() {
return this.columnLast;
}
int getLastRow() {
return this.rowLast;
}
public int read(byte[] data, int pos) {
this.sheet = IntegerHelper.getInt(data[pos], data[pos + 1]);
this.rowFirst = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
this.rowLast = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
int columnMask = IntegerHelper.getInt(data[pos + 6], data[pos + 7]);
this.columnFirst = columnMask & 0xFF;
this.columnFirstRelative = ((columnMask & 0x4000) != 0);
this.rowFirstRelative = ((columnMask & 0x8000) != 0);
columnMask = IntegerHelper.getInt(data[pos + 8], data[pos + 9]);
this.columnLast = columnMask & 0xFF;
this.columnLastRelative = ((columnMask & 0x4000) != 0);
this.rowLastRelative = ((columnMask & 0x8000) != 0);
return 10;
}
public void getString(StringBuffer buf) {
CellReferenceHelper.getCellReference(this.sheet, this.columnFirst, this.rowFirst, this.workbook, buf);
buf.append(':');
CellReferenceHelper.getCellReference(this.columnLast, this.rowLast, buf);
}
byte[] getBytes() {
byte[] data = new byte[11];
data[0] = Token.AREA3D.getCode();
IntegerHelper.getTwoBytes(this.sheet, data, 1);
IntegerHelper.getTwoBytes(this.rowFirst, data, 3);
IntegerHelper.getTwoBytes(this.rowLast, data, 5);
int grcol = this.columnFirst;
if (this.rowFirstRelative)
grcol |= 0x8000;
if (this.columnFirstRelative)
grcol |= 0x4000;
IntegerHelper.getTwoBytes(grcol, data, 7);
grcol = this.columnLast;
if (this.rowLastRelative)
grcol |= 0x8000;
if (this.columnLastRelative)
grcol |= 0x4000;
IntegerHelper.getTwoBytes(grcol, data, 9);
return data;
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
if (this.columnFirstRelative)
this.columnFirst += colAdjust;
if (this.columnLastRelative)
this.columnLast += colAdjust;
if (this.rowFirstRelative)
this.rowFirst += rowAdjust;
if (this.rowLastRelative)
this.rowLast += rowAdjust;
}
public void columnInserted(int sheetIndex, int col, boolean currentSheet) {
if (sheetIndex != this.sheet)
return;
if (this.columnFirst >= col)
this.columnFirst++;
if (this.columnLast >= col)
this.columnLast++;
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
if (sheetIndex != this.sheet)
return;
if (col < this.columnFirst)
this.columnFirst--;
if (col <= this.columnLast)
this.columnLast--;
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
if (sheetIndex != this.sheet)
return;
if (this.rowLast == 65535)
return;
if (row <= this.rowFirst)
this.rowFirst++;
if (row <= this.rowLast)
this.rowLast++;
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
if (sheetIndex != this.sheet)
return;
if (this.rowLast == 65535)
return;
if (row < this.rowFirst)
this.rowFirst--;
if (row <= this.rowLast)
this.rowLast--;
}
protected void setRangeData(int sht, int colFirst, int colLast, int rwFirst, int rwLast, boolean colFirstRel, boolean colLastRel, boolean rowFirstRel, boolean rowLastRel) {
this.sheet = sht;
this.columnFirst = colFirst;
this.columnLast = colLast;
this.rowFirst = rwFirst;
this.rowLast = rwLast;
this.columnFirstRelative = colFirstRel;
this.columnLastRelative = colLastRel;
this.rowFirstRelative = rowFirstRel;
this.rowLastRelative = rowLastRel;
}
}

View File

@@ -0,0 +1,3 @@
package jxl.biff.formula;
class ArgumentSeparator extends StringParseItem {}

View File

@@ -0,0 +1,230 @@
package jxl.biff.formula;
import common.Logger;
import java.util.Stack;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
class Attribute extends Operator implements ParsedThing {
private static Logger logger = Logger.getLogger(Attribute.class);
private int options;
private int word;
private WorkbookSettings settings;
private static final int sumMask = 16;
private static final int ifMask = 2;
private static final int gotoMask = 8;
private VariableArgFunction ifConditions;
public Attribute(WorkbookSettings ws) {
this.settings = ws;
}
public Attribute(StringFunction sf, WorkbookSettings ws) {
this.settings = ws;
if (sf.getFunction(this.settings) == Function.SUM) {
this.options |= 0x10;
} else if (sf.getFunction(this.settings) == Function.IF) {
this.options |= 0x2;
}
}
void setIfConditions(VariableArgFunction vaf) {
this.ifConditions = vaf;
this.options |= 0x2;
}
public int read(byte[] data, int pos) {
this.options = data[pos];
this.word = IntegerHelper.getInt(data[pos + 1], data[pos + 2]);
return 3;
}
public boolean isFunction() {
return ((this.options & 0x12) != 0);
}
public boolean isSum() {
return ((this.options & 0x10) != 0);
}
public boolean isIf() {
return ((this.options & 0x2) != 0);
}
public boolean isGoto() {
return ((this.options & 0x8) != 0);
}
public void getOperands(Stack s) {
if ((this.options & 0x10) != 0) {
ParseItem o1 = s.pop();
add(o1);
} else if ((this.options & 0x2) != 0) {
ParseItem o1 = s.pop();
add(o1);
}
}
public void getString(StringBuffer buf) {
if ((this.options & 0x10) != 0) {
ParseItem[] operands = getOperands();
buf.append(Function.SUM.getName(this.settings));
buf.append('(');
operands[0].getString(buf);
buf.append(')');
} else if ((this.options & 0x2) != 0) {
buf.append(Function.IF.getName(this.settings));
buf.append('(');
ParseItem[] operands = this.ifConditions.getOperands();
for (int i = 0; i < operands.length - 1; i++) {
operands[i].getString(buf);
buf.append(',');
}
operands[operands.length - 1].getString(buf);
buf.append(')');
}
}
byte[] getBytes() {
byte[] data = new byte[0];
if (isSum()) {
ParseItem[] operands = getOperands();
for (int i = operands.length - 1; i >= 0; i--) {
byte[] opdata = operands[i].getBytes();
byte[] arrayOfByte1 = new byte[data.length + opdata.length];
System.arraycopy(data, 0, arrayOfByte1, 0, data.length);
System.arraycopy(opdata, 0, arrayOfByte1, data.length, opdata.length);
data = arrayOfByte1;
}
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, data.length);
newdata[data.length] = Token.ATTRIBUTE.getCode();
newdata[data.length + 1] = 16;
data = newdata;
} else if (isIf()) {
return getIf();
}
return data;
}
private byte[] getIf() {
ParseItem[] operands = this.ifConditions.getOperands();
int falseOffsetPos = 0;
int gotoEndPos = 0;
int numArgs = operands.length;
byte[] data = operands[0].getBytes();
int pos = data.length;
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, data.length);
data = newdata;
data[pos] = Token.ATTRIBUTE.getCode();
data[pos + 1] = 2;
falseOffsetPos = pos + 2;
byte[] truedata = operands[1].getBytes();
newdata = new byte[data.length + truedata.length];
System.arraycopy(data, 0, newdata, 0, data.length);
System.arraycopy(truedata, 0, newdata, data.length, truedata.length);
data = newdata;
pos = data.length;
newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, data.length);
data = newdata;
data[pos] = Token.ATTRIBUTE.getCode();
data[pos + 1] = 8;
gotoEndPos = pos + 2;
if (numArgs > 2) {
IntegerHelper.getTwoBytes(data.length - falseOffsetPos - 2, data, falseOffsetPos);
byte[] falsedata = operands[numArgs - 1].getBytes();
newdata = new byte[data.length + falsedata.length];
System.arraycopy(data, 0, newdata, 0, data.length);
System.arraycopy(falsedata, 0, newdata, data.length, falsedata.length);
data = newdata;
pos = data.length;
newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, data.length);
data = newdata;
data[pos] = Token.ATTRIBUTE.getCode();
data[pos + 1] = 8;
data[pos + 2] = 3;
}
pos = data.length;
newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, data.length);
data = newdata;
data[pos] = Token.FUNCTIONVARARG.getCode();
data[pos + 1] = (byte)numArgs;
data[pos + 2] = 1;
data[pos + 3] = 0;
int endPos = data.length - 1;
if (numArgs < 3)
IntegerHelper.getTwoBytes(endPos - falseOffsetPos - 5, data, falseOffsetPos);
IntegerHelper.getTwoBytes(endPos - gotoEndPos - 2, data, gotoEndPos);
return data;
}
int getPrecedence() {
return 3;
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
ParseItem[] operands = null;
if (isIf()) {
operands = this.ifConditions.getOperands();
} else {
operands = getOperands();
}
for (int i = 0; i < operands.length; i++)
operands[i].adjustRelativeCellReferences(colAdjust, rowAdjust);
}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = null;
if (isIf()) {
operands = this.ifConditions.getOperands();
} else {
operands = getOperands();
}
for (int i = 0; i < operands.length; i++)
operands[i].columnInserted(sheetIndex, col, currentSheet);
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = null;
if (isIf()) {
operands = this.ifConditions.getOperands();
} else {
operands = getOperands();
}
for (int i = 0; i < operands.length; i++)
operands[i].columnRemoved(sheetIndex, col, currentSheet);
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = null;
if (isIf()) {
operands = this.ifConditions.getOperands();
} else {
operands = getOperands();
}
for (int i = 0; i < operands.length; i++)
operands[i].rowInserted(sheetIndex, row, currentSheet);
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = null;
if (isIf()) {
operands = this.ifConditions.getOperands();
} else {
operands = getOperands();
}
for (int i = 0; i < operands.length; i++)
operands[i].rowRemoved(sheetIndex, row, currentSheet);
}
}

View File

@@ -0,0 +1,73 @@
package jxl.biff.formula;
import java.util.Stack;
abstract class BinaryOperator extends Operator implements ParsedThing {
public int read(byte[] data, int pos) {
return 0;
}
public void getOperands(Stack s) {
ParseItem o1 = s.pop();
ParseItem o2 = s.pop();
add(o1);
add(o2);
}
public void getString(StringBuffer buf) {
ParseItem[] operands = getOperands();
operands[1].getString(buf);
buf.append(getSymbol());
operands[0].getString(buf);
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
ParseItem[] operands = getOperands();
operands[1].adjustRelativeCellReferences(colAdjust, rowAdjust);
operands[0].adjustRelativeCellReferences(colAdjust, rowAdjust);
}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[1].columnInserted(sheetIndex, col, currentSheet);
operands[0].columnInserted(sheetIndex, col, currentSheet);
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[1].columnRemoved(sheetIndex, col, currentSheet);
operands[0].columnRemoved(sheetIndex, col, currentSheet);
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[1].rowInserted(sheetIndex, row, currentSheet);
operands[0].rowInserted(sheetIndex, row, currentSheet);
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[1].rowRemoved(sheetIndex, row, currentSheet);
operands[0].rowRemoved(sheetIndex, row, currentSheet);
}
byte[] getBytes() {
ParseItem[] operands = getOperands();
byte[] data = new byte[0];
for (int i = operands.length - 1; i >= 0; i--) {
byte[] opdata = operands[i].getBytes();
byte[] arrayOfByte1 = new byte[data.length + opdata.length];
System.arraycopy(data, 0, arrayOfByte1, 0, data.length);
System.arraycopy(opdata, 0, arrayOfByte1, data.length, opdata.length);
data = arrayOfByte1;
}
byte[] newdata = new byte[data.length + 1];
System.arraycopy(data, 0, newdata, 0, data.length);
newdata[data.length] = getToken().getCode();
return newdata;
}
abstract String getSymbol();
abstract Token getToken();
}

View File

@@ -0,0 +1,27 @@
package jxl.biff.formula;
class BooleanValue extends Operand implements ParsedThing {
private boolean value;
public BooleanValue() {}
public BooleanValue(String s) {
this.value = Boolean.valueOf(s).booleanValue();
}
public int read(byte[] data, int pos) {
this.value = (data[pos] == 1);
return 1;
}
byte[] getBytes() {
byte[] data = new byte[2];
data[0] = Token.BOOL.getCode();
data[1] = (byte)((this.value == true) ? 1 : 0);
return data;
}
public void getString(StringBuffer buf) {
buf.append((new Boolean(this.value)).toString());
}
}

View File

@@ -0,0 +1,108 @@
package jxl.biff.formula;
import common.Assert;
import common.Logger;
import java.util.Stack;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
class BuiltInFunction extends Operator implements ParsedThing {
private static Logger logger = Logger.getLogger(BuiltInFunction.class);
private Function function;
private WorkbookSettings settings;
public BuiltInFunction(WorkbookSettings ws) {
this.settings = ws;
}
public BuiltInFunction(Function f, WorkbookSettings ws) {
this.function = f;
this.settings = ws;
}
public int read(byte[] data, int pos) {
int index = IntegerHelper.getInt(data[pos], data[pos + 1]);
this.function = Function.getFunction(index);
Assert.verify((this.function != Function.UNKNOWN), "function code " + index);
return 2;
}
public void getOperands(Stack s) {
ParseItem[] items = new ParseItem[this.function.getNumArgs()];
int i;
for (i = this.function.getNumArgs() - 1; i >= 0; i--) {
ParseItem pi = s.pop();
items[i] = pi;
}
for (i = 0; i < this.function.getNumArgs(); i++)
add(items[i]);
}
public void getString(StringBuffer buf) {
buf.append(this.function.getName(this.settings));
buf.append('(');
int numArgs = this.function.getNumArgs();
if (numArgs > 0) {
ParseItem[] operands = getOperands();
operands[0].getString(buf);
for (int i = 1; i < numArgs; i++) {
buf.append(',');
operands[i].getString(buf);
}
}
buf.append(')');
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].adjustRelativeCellReferences(colAdjust, rowAdjust);
}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].columnInserted(sheetIndex, col, currentSheet);
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].columnRemoved(sheetIndex, col, currentSheet);
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].rowInserted(sheetIndex, row, currentSheet);
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].rowRemoved(sheetIndex, row, currentSheet);
}
byte[] getBytes() {
ParseItem[] operands = getOperands();
byte[] data = new byte[0];
for (int i = 0; i < operands.length; i++) {
byte[] opdata = operands[i].getBytes();
byte[] arrayOfByte1 = new byte[data.length + opdata.length];
System.arraycopy(data, 0, arrayOfByte1, 0, data.length);
System.arraycopy(opdata, 0, arrayOfByte1, data.length, opdata.length);
data = arrayOfByte1;
}
byte[] newdata = new byte[data.length + 3];
System.arraycopy(data, 0, newdata, 0, data.length);
newdata[data.length] = !useAlternateCode() ? Token.FUNCTION.getCode() : Token.FUNCTION.getCode2();
IntegerHelper.getTwoBytes(this.function.getCode(), newdata, data.length + 1);
return newdata;
}
int getPrecedence() {
return 3;
}
}

View File

@@ -0,0 +1,102 @@
package jxl.biff.formula;
import common.Logger;
import jxl.Cell;
import jxl.biff.CellReferenceHelper;
import jxl.biff.IntegerHelper;
class CellReference extends Operand implements ParsedThing {
private static Logger logger = Logger.getLogger(CellReference.class);
private boolean columnRelative;
private boolean rowRelative;
private int column;
private int row;
private Cell relativeTo;
public CellReference(Cell rt) {
this.relativeTo = rt;
}
public CellReference() {}
public CellReference(String s) {
this.column = CellReferenceHelper.getColumn(s);
this.row = CellReferenceHelper.getRow(s);
this.columnRelative = CellReferenceHelper.isColumnRelative(s);
this.rowRelative = CellReferenceHelper.isRowRelative(s);
}
public int read(byte[] data, int pos) {
this.row = IntegerHelper.getInt(data[pos], data[pos + 1]);
int columnMask = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
this.column = columnMask & 0xFF;
this.columnRelative = ((columnMask & 0x4000) != 0);
this.rowRelative = ((columnMask & 0x8000) != 0);
return 4;
}
public int getColumn() {
return this.column;
}
public int getRow() {
return this.row;
}
public void getString(StringBuffer buf) {
CellReferenceHelper.getCellReference(this.column, !this.columnRelative, this.row, !this.rowRelative, buf);
}
byte[] getBytes() {
byte[] data = new byte[5];
data[0] = !useAlternateCode() ? Token.REF.getCode() : Token.REF.getCode2();
IntegerHelper.getTwoBytes(this.row, data, 1);
int grcol = this.column;
if (this.rowRelative)
grcol |= 0x8000;
if (this.columnRelative)
grcol |= 0x4000;
IntegerHelper.getTwoBytes(grcol, data, 3);
return data;
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
if (this.columnRelative)
this.column += colAdjust;
if (this.rowRelative)
this.row += rowAdjust;
}
public void columnInserted(int sheetIndex, int col, boolean currentSheet) {
if (!currentSheet)
return;
if (this.column >= col)
this.column++;
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
if (!currentSheet)
return;
if (this.column >= col)
this.column--;
}
void rowInserted(int sheetIndex, int r, boolean currentSheet) {
if (!currentSheet)
return;
if (this.row >= r)
this.row++;
}
void rowRemoved(int sheetIndex, int r, boolean currentSheet) {
if (!currentSheet)
return;
if (this.row >= r)
this.row--;
}
}

View File

@@ -0,0 +1,116 @@
package jxl.biff.formula;
import common.Logger;
import jxl.Cell;
import jxl.biff.CellReferenceHelper;
import jxl.biff.IntegerHelper;
class CellReference3d extends Operand implements ParsedThing {
private static Logger logger = Logger.getLogger(CellReference3d.class);
private boolean columnRelative;
private boolean rowRelative;
private int column;
private int row;
private Cell relativeTo;
private int sheet;
private ExternalSheet workbook;
public CellReference3d(Cell rt, ExternalSheet w) {
this.relativeTo = rt;
this.workbook = w;
}
public CellReference3d(String s, ExternalSheet w) throws FormulaException {
this.workbook = w;
this.columnRelative = true;
this.rowRelative = true;
int sep = s.indexOf('!');
String cellString = s.substring(sep + 1);
this.column = CellReferenceHelper.getColumn(cellString);
this.row = CellReferenceHelper.getRow(cellString);
String sheetName = s.substring(0, sep);
if (sheetName.charAt(0) == '\'' && sheetName.charAt(sheetName.length() - 1) == '\'')
sheetName = sheetName.substring(1, sheetName.length() - 1);
this.sheet = w.getExternalSheetIndex(sheetName);
if (this.sheet < 0)
throw new FormulaException(FormulaException.sheetRefNotFound, sheetName);
}
public int read(byte[] data, int pos) {
this.sheet = IntegerHelper.getInt(data[pos], data[pos + 1]);
this.row = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
int columnMask = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
this.column = columnMask & 0xFF;
this.columnRelative = ((columnMask & 0x4000) != 0);
this.rowRelative = ((columnMask & 0x8000) != 0);
return 6;
}
public int getColumn() {
return this.column;
}
public int getRow() {
return this.row;
}
public void getString(StringBuffer buf) {
CellReferenceHelper.getCellReference(this.sheet, this.column, !this.columnRelative, this.row, !this.rowRelative, this.workbook, buf);
}
byte[] getBytes() {
byte[] data = new byte[7];
data[0] = Token.REF3D.getCode();
IntegerHelper.getTwoBytes(this.sheet, data, 1);
IntegerHelper.getTwoBytes(this.row, data, 3);
int grcol = this.column;
if (this.rowRelative)
grcol |= 0x8000;
if (this.columnRelative)
grcol |= 0x4000;
IntegerHelper.getTwoBytes(grcol, data, 5);
return data;
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
if (this.columnRelative)
this.column += colAdjust;
if (this.rowRelative)
this.row += rowAdjust;
}
public void columnInserted(int sheetIndex, int col, boolean currentSheet) {
if (sheetIndex != this.sheet)
return;
if (this.column >= col)
this.column++;
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
if (sheetIndex != this.sheet)
return;
if (this.column >= col)
this.column--;
}
void rowInserted(int sheetIndex, int r, boolean currentSheet) {
if (sheetIndex != this.sheet)
return;
if (this.row >= r)
this.row++;
}
void rowRemoved(int sheetIndex, int r, boolean currentSheet) {
if (sheetIndex != this.sheet)
return;
if (this.row >= r)
this.row--;
}
}

View File

@@ -0,0 +1,21 @@
package jxl.biff.formula;
import common.Logger;
class CellReferenceError extends Operand implements ParsedThing {
private static Logger logger = Logger.getLogger(CellReferenceError.class);
public int read(byte[] data, int pos) {
return 4;
}
public void getString(StringBuffer buf) {
buf.append(FormulaErrorCode.REF.getDescription());
}
byte[] getBytes() {
byte[] data = new byte[5];
data[0] = Token.REFERR.getCode();
return data;
}
}

View File

@@ -0,0 +1,3 @@
package jxl.biff.formula;
class CloseParentheses extends StringParseItem {}

View File

@@ -0,0 +1,33 @@
package jxl.biff.formula;
import common.Assert;
import common.Logger;
import jxl.biff.CellReferenceHelper;
class ColumnRange extends Area {
private static Logger logger = Logger.getLogger(ColumnRange.class);
ColumnRange() {}
ColumnRange(String s) {
int seppos = s.indexOf(":");
Assert.verify((seppos != -1));
String startcell = s.substring(0, seppos);
String endcell = s.substring(seppos + 1);
int columnFirst = CellReferenceHelper.getColumn(startcell);
int rowFirst = 0;
int columnLast = CellReferenceHelper.getColumn(endcell);
int rowLast = 65535;
boolean columnFirstRelative = CellReferenceHelper.isColumnRelative(startcell);
boolean rowFirstRelative = false;
boolean columnLastRelative = CellReferenceHelper.isColumnRelative(endcell);
boolean rowLastRelative = false;
setRangeData(columnFirst, columnLast, rowFirst, rowLast, columnFirstRelative, columnLastRelative, rowFirstRelative, rowLastRelative);
}
public void getString(StringBuffer buf) {
CellReferenceHelper.getColumnReference(getFirstColumn(), buf);
buf.append(':');
CellReferenceHelper.getColumnReference(getLastColumn(), buf);
}
}

View File

@@ -0,0 +1,55 @@
package jxl.biff.formula;
import common.Assert;
import common.Logger;
import jxl.biff.CellReferenceHelper;
class ColumnRange3d extends Area3d {
private static Logger logger = Logger.getLogger(ColumnRange3d.class);
private ExternalSheet workbook;
private int sheet;
ColumnRange3d(ExternalSheet es) {
super(es);
this.workbook = es;
}
ColumnRange3d(String s, ExternalSheet es) throws FormulaException {
super(es);
this.workbook = es;
int seppos = s.lastIndexOf(":");
Assert.verify((seppos != -1));
String startcell = s.substring(0, seppos);
String endcell = s.substring(seppos + 1);
int sep = s.indexOf('!');
String cellString = s.substring(sep + 1, seppos);
int columnFirst = CellReferenceHelper.getColumn(cellString);
int rowFirst = 0;
String sheetName = s.substring(0, sep);
int sheetNamePos = sheetName.lastIndexOf(']');
if (sheetName.charAt(0) == '\'' && sheetName.charAt(sheetName.length() - 1) == '\'')
sheetName = sheetName.substring(1, sheetName.length() - 1);
this.sheet = es.getExternalSheetIndex(sheetName);
if (this.sheet < 0)
throw new FormulaException(FormulaException.sheetRefNotFound, sheetName);
int columnLast = CellReferenceHelper.getColumn(endcell);
int rowLast = 65535;
boolean columnFirstRelative = true;
boolean rowFirstRelative = true;
boolean columnLastRelative = true;
boolean rowLastRelative = true;
setRangeData(this.sheet, columnFirst, columnLast, rowFirst, rowLast, columnFirstRelative, rowFirstRelative, columnLastRelative, rowLastRelative);
}
public void getString(StringBuffer buf) {
buf.append('\'');
buf.append(this.workbook.getExternalSheetName(this.sheet));
buf.append('\'');
buf.append('!');
CellReferenceHelper.getColumnReference(getFirstColumn(), buf);
buf.append(':');
CellReferenceHelper.getColumnReference(getLastColumn(), buf);
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class Concatenate extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "&";
}
Token getToken() {
return Token.CONCAT;
}
int getPrecedence() {
return 3;
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class Divide extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "/";
}
Token getToken() {
return Token.DIVIDE;
}
int getPrecedence() {
return 3;
}
}

View File

@@ -0,0 +1,41 @@
package jxl.biff.formula;
import common.Logger;
import jxl.biff.DoubleHelper;
class DoubleValue extends NumberValue implements ParsedThing {
private static Logger logger = Logger.getLogger(DoubleValue.class);
private double value;
public DoubleValue() {}
DoubleValue(double v) {
this.value = v;
}
public DoubleValue(String s) {
try {
this.value = Double.parseDouble(s);
} catch (NumberFormatException e) {
logger.warn(e, e);
this.value = 0.0D;
}
}
public int read(byte[] data, int pos) {
this.value = DoubleHelper.getIEEEDouble(data, pos);
return 8;
}
byte[] getBytes() {
byte[] data = new byte[9];
data[0] = Token.DOUBLE.getCode();
DoubleHelper.getIEEEBytes(this.value, data, 1);
return data;
}
public double getValue() {
return this.value;
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class Equal extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "=";
}
Token getToken() {
return Token.EQUAL;
}
int getPrecedence() {
return 5;
}
}

View File

@@ -0,0 +1,17 @@
package jxl.biff.formula;
import jxl.read.biff.BOFRecord;
public interface ExternalSheet {
String getExternalSheetName(int paramInt);
int getExternalSheetIndex(String paramString);
int getExternalSheetIndex(int paramInt);
int getLastExternalSheetIndex(String paramString);
int getLastExternalSheetIndex(int paramInt);
BOFRecord getWorkbookBof();
}

View File

@@ -0,0 +1,54 @@
package jxl.biff.formula;
public class FormulaErrorCode {
private int errorCode;
private String description;
private static FormulaErrorCode[] codes = new FormulaErrorCode[0];
FormulaErrorCode(int code, String desc) {
this.errorCode = code;
this.description = desc;
FormulaErrorCode[] newcodes = new FormulaErrorCode[codes.length + 1];
System.arraycopy(codes, 0, newcodes, 0, codes.length);
newcodes[codes.length] = this;
codes = newcodes;
}
public int getCode() {
return this.errorCode;
}
public String getDescription() {
return this.description;
}
public static FormulaErrorCode getErrorCode(int code) {
boolean found = false;
FormulaErrorCode ec = UNKNOWN;
for (int i = 0; i < codes.length && !found; i++) {
if ((codes[i]).errorCode == code) {
found = true;
ec = codes[i];
}
}
return ec;
}
public static FormulaErrorCode UNKNOWN = new FormulaErrorCode(255, "?");
public static FormulaErrorCode NULL = new FormulaErrorCode(0, "#NULL");
public static FormulaErrorCode DIV0 = new FormulaErrorCode(7, "#DIV/0");
public static FormulaErrorCode VALUE = new FormulaErrorCode(15, "#VALUE");
public static FormulaErrorCode REF = new FormulaErrorCode(23, "#REF");
public static FormulaErrorCode NAME = new FormulaErrorCode(29, "#NAME");
public static FormulaErrorCode NUM = new FormulaErrorCode(36, "#NUM");
public static FormulaErrorCode NA = new FormulaErrorCode(42, "#N/A");
}

View File

@@ -0,0 +1,39 @@
package jxl.biff.formula;
import jxl.JXLException;
public class FormulaException extends JXLException {
private static class FormulaMessage {
public String message;
FormulaMessage(String m) {
this.message = m;
}
}
static FormulaMessage unrecognizedToken = new FormulaMessage("Unrecognized token");
static FormulaMessage unrecognizedFunction = new FormulaMessage("Unrecognized function");
public static FormulaMessage biff8Supported = new FormulaMessage("Only biff8 formulas are supported");
static FormulaMessage lexicalError = new FormulaMessage("Lexical error: ");
static FormulaMessage incorrectArguments = new FormulaMessage("Incorrect arguments supplied to function");
static FormulaMessage sheetRefNotFound = new FormulaMessage("Could not find sheet");
static FormulaMessage cellNameNotFound = new FormulaMessage("Could not find named cell");
public FormulaException(FormulaMessage m) {
super(m.message);
}
public FormulaException(FormulaMessage m, int val) {
super(m.message + " " + val);
}
public FormulaException(FormulaMessage m, String val) {
super(m.message + " " + val);
}
}

View File

@@ -0,0 +1,51 @@
package jxl.biff.formula;
import jxl.Cell;
import jxl.WorkbookSettings;
import jxl.biff.WorkbookMethods;
public class FormulaParser {
private Parser parser;
public FormulaParser(byte[] tokens, Cell rt, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) throws FormulaException {
if (es.getWorkbookBof() != null && !es.getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
this.parser = new TokenFormulaParser(tokens, rt, es, nt, ws);
}
public FormulaParser(String form, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) {
this.parser = new StringFormulaParser(form, es, nt, ws);
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
this.parser.adjustRelativeCellReferences(colAdjust, rowAdjust);
}
public void parse() throws FormulaException {
this.parser.parse();
}
public String getFormula() throws FormulaException {
return this.parser.getFormula();
}
public byte[] getBytes() {
return this.parser.getBytes();
}
public void columnInserted(int sheetIndex, int col, boolean currentSheet) {
this.parser.columnInserted(sheetIndex, col, currentSheet);
}
public void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
this.parser.columnRemoved(sheetIndex, col, currentSheet);
}
public void rowInserted(int sheetIndex, int row, boolean currentSheet) {
this.parser.rowInserted(sheetIndex, row, currentSheet);
}
public void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
this.parser.rowRemoved(sheetIndex, row, currentSheet);
}
}

View File

@@ -0,0 +1,530 @@
package jxl.biff.formula;
import common.Logger;
import jxl.WorkbookSettings;
class Function {
private static Logger logger = Logger.getLogger(Function.class);
private final int code;
private final String name;
private final int numArgs;
static Function[] functions = new Function[0];
private Function(int v, String s, int a) {
this.code = v;
this.name = s;
this.numArgs = a;
Function[] newarray = new Function[functions.length + 1];
System.arraycopy(functions, 0, newarray, 0, functions.length);
newarray[functions.length] = this;
functions = newarray;
}
public int hashCode() {
return this.code;
}
int getCode() {
return this.code;
}
String getPropertyName() {
return this.name;
}
String getName(WorkbookSettings ws) {
FunctionNames fn = ws.getFunctionNames();
return fn.getName(this);
}
int getNumArgs() {
return this.numArgs;
}
public static Function getFunction(int v) {
Function f = null;
for (int i = 0; i < functions.length; i++) {
if ((functions[i]).code == v) {
f = functions[i];
break;
}
}
return (f != null) ? f : UNKNOWN;
}
public static Function getFunction(String v, WorkbookSettings ws) {
FunctionNames fn = ws.getFunctionNames();
Function f = fn.getFunction(v);
return (f != null) ? f : UNKNOWN;
}
public static final Function COUNT = new Function(0, "count", 255);
public static final Function ATTRIBUTE = new Function(1, "", 255);
public static final Function ISNA = new Function(2, "isna", 1);
public static final Function ISERROR = new Function(3, "iserror", 1);
public static final Function SUM = new Function(4, "sum", 255);
public static final Function AVERAGE = new Function(5, "average", 255);
public static final Function MIN = new Function(6, "min", 255);
public static final Function MAX = new Function(7, "max", 255);
public static final Function ROW = new Function(8, "row", 255);
public static final Function COLUMN = new Function(9, "column", 255);
public static final Function NA = new Function(10, "na", 0);
public static final Function NPV = new Function(11, "npv", 255);
public static final Function STDEV = new Function(12, "stdev", 255);
public static final Function DOLLAR = new Function(13, "dollar", 2);
public static final Function FIXED = new Function(14, "fixed", 255);
public static final Function SIN = new Function(15, "sin", 1);
public static final Function COS = new Function(16, "cos", 1);
public static final Function TAN = new Function(17, "tan", 1);
public static final Function ATAN = new Function(18, "atan", 1);
public static final Function PI = new Function(19, "pi", 0);
public static final Function SQRT = new Function(20, "sqrt", 1);
public static final Function EXP = new Function(21, "exp", 1);
public static final Function LN = new Function(22, "ln", 1);
public static final Function LOG10 = new Function(23, "log10", 1);
public static final Function ABS = new Function(24, "abs", 1);
public static final Function INT = new Function(25, "int", 1);
public static final Function SIGN = new Function(26, "sign", 1);
public static final Function ROUND = new Function(27, "round", 2);
public static final Function LOOKUP = new Function(28, "lookup", 2);
public static final Function INDEX = new Function(29, "index", 3);
public static final Function REPT = new Function(30, "rept", 2);
public static final Function MID = new Function(31, "mid", 3);
public static final Function LEN = new Function(32, "len", 1);
public static final Function VALUE = new Function(33, "value", 1);
public static final Function TRUE = new Function(34, "true", 0);
public static final Function FALSE = new Function(35, "false", 0);
public static final Function AND = new Function(36, "and", 255);
public static final Function OR = new Function(37, "or", 255);
public static final Function NOT = new Function(38, "not", 1);
public static final Function MOD = new Function(39, "mod", 2);
public static final Function DCOUNT = new Function(40, "dcount", 3);
public static final Function DSUM = new Function(41, "dsum", 3);
public static final Function DAVERAGE = new Function(42, "daverage", 3);
public static final Function DMIN = new Function(43, "dmin", 3);
public static final Function DMAX = new Function(44, "dmax", 3);
public static final Function DSTDEV = new Function(45, "dstdev", 3);
public static final Function VAR = new Function(46, "var", 255);
public static final Function DVAR = new Function(47, "dvar", 3);
public static final Function TEXT = new Function(48, "text", 2);
public static final Function LINEST = new Function(49, "linest", 255);
public static final Function TREND = new Function(50, "trend", 255);
public static final Function LOGEST = new Function(51, "logest", 255);
public static final Function GROWTH = new Function(52, "growth", 255);
public static final Function PV = new Function(56, "pv", 255);
public static final Function FV = new Function(57, "fv", 255);
public static final Function NPER = new Function(58, "nper", 255);
public static final Function PMT = new Function(59, "pmt", 255);
public static final Function RATE = new Function(60, "rate", 255);
public static final Function RAND = new Function(63, "rand", 0);
public static final Function MATCH = new Function(64, "match", 3);
public static final Function DATE = new Function(65, "date", 3);
public static final Function TIME = new Function(66, "time", 3);
public static final Function DAY = new Function(67, "day", 1);
public static final Function MONTH = new Function(68, "month", 1);
public static final Function YEAR = new Function(69, "year", 1);
public static final Function WEEKDAY = new Function(70, "weekday", 2);
public static final Function HOUR = new Function(71, "hour", 1);
public static final Function MINUTE = new Function(72, "minute", 1);
public static final Function SECOND = new Function(73, "second", 1);
public static final Function NOW = new Function(74, "now", 0);
public static final Function AREAS = new Function(75, "areas", 255);
public static final Function ROWS = new Function(76, "rows", 1);
public static final Function COLUMNS = new Function(77, "columns", 255);
public static final Function OFFSET = new Function(78, "offset", 255);
public static final Function TRANSPOSE = new Function(83, "transpose", 255);
public static final Function ERROR = new Function(84, "error", 1);
public static final Function TYPE = new Function(86, "type", 1);
public static final Function ATAN2 = new Function(97, "atan2", 1);
public static final Function ASIN = new Function(98, "asin", 1);
public static final Function ACOS = new Function(99, "acos", 1);
public static final Function CHOOSE = new Function(100, "choose", 255);
public static final Function HLOOKUP = new Function(101, "hlookup", 255);
public static final Function VLOOKUP = new Function(102, "vlookup", 255);
public static final Function ISREF = new Function(105, "isref", 1);
public static final Function LOG = new Function(109, "log", 255);
public static final Function CHAR = new Function(111, "char", 1);
public static final Function LOWER = new Function(112, "lower", 1);
public static final Function UPPER = new Function(113, "upper", 1);
public static final Function PROPER = new Function(114, "proper", 1);
public static final Function LEFT = new Function(115, "left", 255);
public static final Function RIGHT = new Function(116, "right", 255);
public static final Function EXACT = new Function(117, "exact", 2);
public static final Function TRIM = new Function(118, "trim", 1);
public static final Function REPLACE = new Function(119, "replace", 4);
public static final Function SUBSTITUTE = new Function(120, "substitute", 255);
public static final Function CODE = new Function(121, "code", 1);
public static final Function FIND = new Function(124, "find", 255);
public static final Function CELL = new Function(125, "cell", 2);
public static final Function ISERR = new Function(126, "iserr", 1);
public static final Function ISTEXT = new Function(127, "istext", 1);
public static final Function ISNUMBER = new Function(128, "isnumber", 1);
public static final Function ISBLANK = new Function(129, "isblank", 1);
public static final Function T = new Function(130, "t", 1);
public static final Function N = new Function(131, "n", 1);
public static final Function DATEVALUE = new Function(140, "datevalue", 1);
public static final Function TIMEVALUE = new Function(141, "timevalue", 1);
public static final Function SLN = new Function(142, "sln", 3);
public static final Function SYD = new Function(143, "syd", 3);
public static final Function DDB = new Function(144, "ddb", 255);
public static final Function INDIRECT = new Function(148, "indirect", 255);
public static final Function CLEAN = new Function(162, "clean", 1);
public static final Function MDETERM = new Function(163, "mdeterm", 255);
public static final Function MINVERSE = new Function(164, "minverse", 255);
public static final Function MMULT = new Function(165, "mmult", 255);
public static final Function IPMT = new Function(167, "ipmt", 255);
public static final Function PPMT = new Function(168, "ppmt", 255);
public static final Function COUNTA = new Function(169, "counta", 255);
public static final Function PRODUCT = new Function(183, "product", 255);
public static final Function FACT = new Function(184, "fact", 1);
public static final Function DPRODUCT = new Function(189, "dproduct", 3);
public static final Function ISNONTEXT = new Function(190, "isnontext", 1);
public static final Function STDEVP = new Function(193, "stdevp", 255);
public static final Function VARP = new Function(194, "varp", 255);
public static final Function DSTDEVP = new Function(195, "dstdevp", 255);
public static final Function DVARP = new Function(196, "dvarp", 255);
public static final Function TRUNC = new Function(197, "trunc", 255);
public static final Function ISLOGICAL = new Function(198, "islogical", 1);
public static final Function DCOUNTA = new Function(199, "dcounta", 255);
public static final Function FINDB = new Function(205, "findb", 255);
public static final Function SEARCHB = new Function(206, "searchb", 3);
public static final Function REPLACEB = new Function(207, "replaceb", 4);
public static final Function LEFTB = new Function(208, "leftb", 255);
public static final Function RIGHTB = new Function(209, "rightb", 255);
public static final Function MIDB = new Function(210, "midb", 3);
public static final Function LENB = new Function(211, "lenb", 1);
public static final Function ROUNDUP = new Function(212, "roundup", 2);
public static final Function ROUNDDOWN = new Function(213, "rounddown", 2);
public static final Function RANK = new Function(216, "rank", 255);
public static final Function ADDRESS = new Function(219, "address", 255);
public static final Function AYS360 = new Function(220, "days360", 255);
public static final Function ODAY = new Function(221, "today", 0);
public static final Function VDB = new Function(222, "vdb", 255);
public static final Function MEDIAN = new Function(227, "median", 255);
public static final Function SUMPRODUCT = new Function(228, "sumproduct", 255);
public static final Function SINH = new Function(229, "sinh", 1);
public static final Function COSH = new Function(230, "cosh", 1);
public static final Function TANH = new Function(231, "tanh", 1);
public static final Function ASINH = new Function(232, "asinh", 1);
public static final Function ACOSH = new Function(233, "acosh", 1);
public static final Function ATANH = new Function(234, "atanh", 1);
public static final Function INFO = new Function(244, "info", 1);
public static final Function AVEDEV = new Function(269, "avedev", 255);
public static final Function BETADIST = new Function(270, "betadist", 255);
public static final Function GAMMALN = new Function(271, "gammaln", 1);
public static final Function BETAINV = new Function(272, "betainv", 255);
public static final Function BINOMDIST = new Function(273, "binomdist", 4);
public static final Function CHIDIST = new Function(274, "chidist", 2);
public static final Function CHIINV = new Function(275, "chiinv", 2);
public static final Function COMBIN = new Function(276, "combin", 2);
public static final Function CONFIDENCE = new Function(277, "confidence", 3);
public static final Function CRITBINOM = new Function(278, "critbinom", 3);
public static final Function EVEN = new Function(279, "even", 1);
public static final Function EXPONDIST = new Function(280, "expondist", 3);
public static final Function FDIST = new Function(281, "fdist", 3);
public static final Function FINV = new Function(282, "finv", 3);
public static final Function FISHER = new Function(283, "fisher", 1);
public static final Function FISHERINV = new Function(284, "fisherinv", 1);
public static final Function FLOOR = new Function(285, "floor", 2);
public static final Function GAMMADIST = new Function(286, "gammadist", 4);
public static final Function GAMMAINV = new Function(287, "gammainv", 3);
public static final Function CEILING = new Function(288, "ceiling", 2);
public static final Function HYPGEOMDIST = new Function(289, "hypgeomdist", 4);
public static final Function LOGNORMDIST = new Function(290, "lognormdist", 3);
public static final Function LOGINV = new Function(291, "loginv", 3);
public static final Function NEGBINOMDIST = new Function(292, "negbinomdist", 3);
public static final Function NORMDIST = new Function(293, "normdist", 4);
public static final Function NORMSDIST = new Function(294, "normsdist", 1);
public static final Function NORMINV = new Function(295, "norminv", 3);
public static final Function NORMSINV = new Function(296, "normsinv", 1);
public static final Function STANDARDIZE = new Function(297, "standardize", 3);
public static final Function ODD = new Function(298, "odd", 1);
public static final Function PERMUT = new Function(299, "permut", 2);
public static final Function POISSON = new Function(300, "poisson", 3);
public static final Function TDIST = new Function(301, "tdist", 3);
public static final Function WEIBULL = new Function(302, "weibull", 4);
public static final Function SUMXMY2 = new Function(303, "sumxmy2", 255);
public static final Function SUMX2MY2 = new Function(304, "sumx2my2", 255);
public static final Function SUMX2PY2 = new Function(305, "sumx2py2", 255);
public static final Function CHITEST = new Function(306, "chitest", 255);
public static final Function CORREL = new Function(307, "correl", 255);
public static final Function COVAR = new Function(308, "covar", 255);
public static final Function FORECAST = new Function(309, "forecast", 255);
public static final Function FTEST = new Function(310, "ftest", 255);
public static final Function INTERCEPT = new Function(311, "intercept", 255);
public static final Function PEARSON = new Function(312, "pearson", 255);
public static final Function RSQ = new Function(313, "rsq", 255);
public static final Function STEYX = new Function(314, "steyx", 255);
public static final Function SLOPE = new Function(315, "slope", 2);
public static final Function TTEST = new Function(316, "ttest", 255);
public static final Function PROB = new Function(317, "prob", 255);
public static final Function DEVSQ = new Function(318, "devsq", 255);
public static final Function GEOMEAN = new Function(319, "geomean", 255);
public static final Function HARMEAN = new Function(320, "harmean", 255);
public static final Function SUMSQ = new Function(321, "sumsq", 255);
public static final Function KURT = new Function(322, "kurt", 255);
public static final Function SKEW = new Function(323, "skew", 255);
public static final Function ZTEST = new Function(324, "ztest", 255);
public static final Function LARGE = new Function(325, "large", 255);
public static final Function SMALL = new Function(326, "small", 255);
public static final Function QUARTILE = new Function(327, "quartile", 255);
public static final Function PERCENTILE = new Function(328, "percentile", 255);
public static final Function PERCENTRANK = new Function(329, "percentrank", 255);
public static final Function MODE = new Function(330, "mode", 255);
public static final Function TRIMMEAN = new Function(331, "trimmean", 255);
public static final Function TINV = new Function(332, "tinv", 2);
public static final Function CONCATENATE = new Function(336, "concatenate", 255);
public static final Function POWER = new Function(337, "power", 2);
public static final Function RADIANS = new Function(342, "radians", 1);
public static final Function DEGREES = new Function(343, "degrees", 1);
public static final Function SUBTOTAL = new Function(344, "subtotal", 255);
public static final Function SUMIF = new Function(345, "sumif", 255);
public static final Function COUNTIF = new Function(346, "countif", 2);
public static final Function COUNTBLANK = new Function(347, "countblank", 1);
public static final Function HYPERLINK = new Function(359, "hyperlink", 2);
public static final Function AVERAGEA = new Function(361, "averagea", 255);
public static final Function MAXA = new Function(362, "maxa", 255);
public static final Function MINA = new Function(363, "mina", 255);
public static final Function STDEVPA = new Function(364, "stdevpa", 255);
public static final Function VARPA = new Function(365, "varpa", 255);
public static final Function STDEVA = new Function(366, "stdeva", 255);
public static final Function VARA = new Function(367, "vara", 255);
public static final Function IF = new Function(65534, "if", 255);
public static final Function UNKNOWN = new Function(65535, "", 0);
}

View File

@@ -0,0 +1,40 @@
package jxl.biff.formula;
import common.Logger;
import java.util.HashMap;
import java.util.Locale;
import java.util.ResourceBundle;
public class FunctionNames {
private static Logger logger = Logger.getLogger(FunctionNames.class);
private HashMap names;
private HashMap functions;
public FunctionNames(Locale l) {
ResourceBundle rb = ResourceBundle.getBundle("functions", l);
this.names = new HashMap(Function.functions.length);
this.functions = new HashMap(Function.functions.length);
Function f = null;
String n = null;
String propname = null;
for (int i = 0; i < Function.functions.length; i++) {
f = Function.functions[i];
propname = f.getPropertyName();
n = (propname.length() != 0) ? rb.getString(propname) : null;
if (n != null) {
this.names.put(f, n);
this.functions.put(n, f);
}
}
}
Function getFunction(String s) {
return (Function)this.functions.get(s);
}
String getName(Function f) {
return (String)this.names.get(f);
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class GreaterEqual extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return ">=";
}
Token getToken() {
return Token.GREATER_EQUAL;
}
int getPrecedence() {
return 5;
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class GreaterThan extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return ">";
}
Token getToken() {
return Token.GREATER_THAN;
}
int getPrecedence() {
return 5;
}
}

View File

@@ -0,0 +1,47 @@
package jxl.biff.formula;
import common.Logger;
import jxl.biff.IntegerHelper;
class IntegerValue extends NumberValue implements ParsedThing {
private static Logger logger = Logger.getLogger(IntegerValue.class);
private double value;
private boolean outOfRange;
public IntegerValue() {
this.outOfRange = false;
}
public IntegerValue(String s) {
try {
this.value = Integer.parseInt(s);
} catch (NumberFormatException e) {
logger.warn(e, e);
this.value = 0.0D;
}
short v = (short)(int)this.value;
this.outOfRange = (this.value != v);
}
public int read(byte[] data, int pos) {
this.value = IntegerHelper.getInt(data[pos], data[pos + 1]);
return 2;
}
byte[] getBytes() {
byte[] data = new byte[3];
data[0] = Token.INTEGER.getCode();
IntegerHelper.getTwoBytes((int)this.value, data, 1);
return data;
}
public double getValue() {
return this.value;
}
boolean isOutOfRange() {
return this.outOfRange;
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class LessEqual extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "<=";
}
Token getToken() {
return Token.LESS_EQUAL;
}
int getPrecedence() {
return 5;
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class LessThan extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "<";
}
Token getToken() {
return Token.LESS_THAN;
}
int getPrecedence() {
return 5;
}
}

View File

@@ -0,0 +1,43 @@
package jxl.biff.formula;
import java.util.Stack;
import jxl.biff.IntegerHelper;
class MemFunc extends Operand implements ParsedThing {
private int length;
private ParseItem[] subExpression;
public int read(byte[] data, int pos) {
this.length = IntegerHelper.getInt(data[pos], data[pos + 1]);
return 2;
}
public void getOperands(Stack s) {}
public void getString(StringBuffer buf) {
if (this.subExpression.length == 1) {
this.subExpression[0].getString(buf);
} else if (this.subExpression.length == 2) {
this.subExpression[1].getString(buf);
buf.append(':');
this.subExpression[0].getString(buf);
}
}
byte[] getBytes() {
return null;
}
int getPrecedence() {
return 5;
}
public int getLength() {
return this.length;
}
public void setSubExpression(ParseItem[] pi) {
this.subExpression = pi;
}
}

View File

@@ -0,0 +1,11 @@
package jxl.biff.formula;
class Minus extends StringOperator {
Operator getBinaryOperator() {
return new Subtract();
}
Operator getUnaryOperator() {
return new UnaryMinus();
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class MissingArg extends Operand implements ParsedThing {
public int read(byte[] data, int pos) {
return 0;
}
byte[] getBytes() {
byte[] data = new byte[1];
data[0] = Token.MISSING_ARG.getCode();
return data;
}
public void getString(StringBuffer buf) {}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class Multiply extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "*";
}
Token getToken() {
return Token.MULTIPLY;
}
int getPrecedence() {
return 3;
}
}

View File

@@ -0,0 +1,16 @@
package jxl.biff.formula;
class Name extends Operand implements ParsedThing {
public int read(byte[] data, int pos) {
return 6;
}
byte[] getBytes() {
byte[] data = new byte[6];
return data;
}
public void getString(StringBuffer buf) {
buf.append("[Name record not implemented]");
}
}

View File

@@ -0,0 +1,42 @@
package jxl.biff.formula;
import jxl.biff.IntegerHelper;
import jxl.biff.WorkbookMethods;
class NameRange extends Operand implements ParsedThing {
private WorkbookMethods nameTable;
private String name;
private int index;
public NameRange(WorkbookMethods nt) {
this.nameTable = nt;
}
public NameRange(String nm, WorkbookMethods nt) throws FormulaException {
this.name = nm;
this.nameTable = nt;
this.index = this.nameTable.getNameIndex(this.name);
if (this.index < 0)
throw new FormulaException(FormulaException.cellNameNotFound, this.name);
this.index++;
}
public int read(byte[] data, int pos) {
this.index = IntegerHelper.getInt(data[pos], data[pos + 1]);
this.name = this.nameTable.getName(this.index - 1);
return 4;
}
byte[] getBytes() {
byte[] data = new byte[5];
data[0] = Token.NAMED_RANGE.getCode();
IntegerHelper.getTwoBytes(this.index, data, 1);
return data;
}
public void getString(StringBuffer buf) {
buf.append(this.name);
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class NotEqual extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "<>";
}
Token getToken() {
return Token.NOT_EQUAL;
}
int getPrecedence() {
return 5;
}
}

View File

@@ -0,0 +1,9 @@
package jxl.biff.formula;
abstract class NumberValue extends Operand implements ParsedThing {
public abstract double getValue();
public void getString(StringBuffer buf) {
buf.append(Double.toString(getValue()));
}
}

View File

@@ -0,0 +1,3 @@
package jxl.biff.formula;
class OpenParentheses extends StringParseItem {}

View File

@@ -0,0 +1,13 @@
package jxl.biff.formula;
abstract class Operand extends ParseItem {
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {}
}

View File

@@ -0,0 +1,28 @@
package jxl.biff.formula;
import java.util.Stack;
abstract class Operator extends ParseItem {
private ParseItem[] operands = new ParseItem[0];
protected void setOperandAlternateCode() {
for (int i = 0; i < this.operands.length; i++)
this.operands[i].setAlternateCode();
}
protected void add(ParseItem n) {
n.setParent(this);
ParseItem[] newOperands = new ParseItem[this.operands.length + 1];
System.arraycopy(this.operands, 0, newOperands, 0, this.operands.length);
newOperands[this.operands.length] = n;
this.operands = newOperands;
}
public abstract void getOperands(Stack paramStack);
protected ParseItem[] getOperands() {
return this.operands;
}
abstract int getPrecedence();
}

View File

@@ -0,0 +1,63 @@
package jxl.biff.formula;
import java.util.Stack;
class Parenthesis extends Operator implements ParsedThing {
public int read(byte[] data, int pos) {
return 0;
}
public void getOperands(Stack s) {
ParseItem pi = s.pop();
add(pi);
}
public void getString(StringBuffer buf) {
ParseItem[] operands = getOperands();
buf.append('(');
operands[0].getString(buf);
buf.append(')');
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
ParseItem[] operands = getOperands();
operands[0].adjustRelativeCellReferences(colAdjust, rowAdjust);
}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[0].columnInserted(sheetIndex, col, currentSheet);
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[0].columnRemoved(sheetIndex, col, currentSheet);
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[0].rowInserted(sheetIndex, row, currentSheet);
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[0].rowRemoved(sheetIndex, row, currentSheet);
}
Token getToken() {
return Token.PARENTHESIS;
}
byte[] getBytes() {
ParseItem[] operands = getOperands();
byte[] data = operands[0].getBytes();
byte[] newdata = new byte[data.length + 1];
System.arraycopy(data, 0, newdata, 0, data.length);
newdata[data.length] = getToken().getCode();
return newdata;
}
int getPrecedence() {
return 4;
}
}

View File

@@ -0,0 +1,45 @@
package jxl.biff.formula;
abstract class ParseItem {
private ParseItem parent;
private boolean volatileFunction = false;
private boolean alternateCode = false;
protected void setParent(ParseItem p) {
this.parent = p;
}
protected void setVolatile() {
this.volatileFunction = true;
if (this.parent != null && !this.parent.isVolatile())
this.parent.setVolatile();
}
final boolean isVolatile() {
return this.volatileFunction;
}
abstract void getString(StringBuffer paramStringBuffer);
abstract byte[] getBytes();
abstract void adjustRelativeCellReferences(int paramInt1, int paramInt2);
abstract void columnInserted(int paramInt1, int paramInt2, boolean paramBoolean);
abstract void columnRemoved(int paramInt1, int paramInt2, boolean paramBoolean);
abstract void rowInserted(int paramInt1, int paramInt2, boolean paramBoolean);
abstract void rowRemoved(int paramInt1, int paramInt2, boolean paramBoolean);
protected void setAlternateCode() {
this.alternateCode = true;
}
protected final boolean useAlternateCode() {
return this.alternateCode;
}
}

View File

@@ -0,0 +1,5 @@
package jxl.biff.formula;
interface ParsedThing {
int read(byte[] paramArrayOfbyte, int paramInt) throws FormulaException;
}

View File

@@ -0,0 +1,19 @@
package jxl.biff.formula;
interface Parser {
void parse() throws FormulaException;
String getFormula();
byte[] getBytes();
void adjustRelativeCellReferences(int paramInt1, int paramInt2);
void columnInserted(int paramInt1, int paramInt2, boolean paramBoolean);
void columnRemoved(int paramInt1, int paramInt2, boolean paramBoolean);
void rowInserted(int paramInt1, int paramInt2, boolean paramBoolean);
void rowRemoved(int paramInt1, int paramInt2, boolean paramBoolean);
}

View File

@@ -0,0 +1,21 @@
package jxl.biff.formula;
class Percent extends UnaryOperator implements ParsedThing {
public String getSymbol() {
return "%";
}
public void getString(StringBuffer buf) {
ParseItem[] operands = getOperands();
operands[0].getString(buf);
buf.append(getSymbol());
}
Token getToken() {
return Token.PERCENT;
}
int getPrecedence() {
return 5;
}
}

View File

@@ -0,0 +1,11 @@
package jxl.biff.formula;
class Plus extends StringOperator {
Operator getBinaryOperator() {
return new Add();
}
Operator getUnaryOperator() {
return new UnaryPlus();
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class Power extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "^";
}
Token getToken() {
return Token.POWER;
}
int getPrecedence() {
return 1;
}
}

View File

@@ -0,0 +1,28 @@
package jxl.biff.formula;
import jxl.biff.IntegerHelper;
class RangeSeparator extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return ":";
}
Token getToken() {
return Token.RANGE;
}
int getPrecedence() {
return 1;
}
byte[] getBytes() {
setVolatile();
setOperandAlternateCode();
byte[] funcBytes = super.getBytes();
byte[] bytes = new byte[funcBytes.length + 3];
System.arraycopy(funcBytes, 0, bytes, 3, funcBytes.length);
bytes[0] = Token.MEM_FUNC.getCode();
IntegerHelper.getTwoBytes(funcBytes.length, bytes, 1);
return bytes;
}
}

View File

@@ -0,0 +1,83 @@
package jxl.biff.formula;
import jxl.Cell;
import jxl.biff.CellReferenceHelper;
import jxl.biff.IntegerHelper;
class SharedFormulaArea extends Operand implements ParsedThing {
private int columnFirst;
private int rowFirst;
private int columnLast;
private int rowLast;
private boolean columnFirstRelative;
private boolean rowFirstRelative;
private boolean columnLastRelative;
private boolean rowLastRelative;
private Cell relativeTo;
public SharedFormulaArea(Cell rt) {
this.relativeTo = rt;
}
int getFirstColumn() {
return this.columnFirst;
}
int getFirstRow() {
return this.rowFirst;
}
int getLastColumn() {
return this.columnLast;
}
int getLastRow() {
return this.rowLast;
}
public int read(byte[] data, int pos) {
this.rowFirst = IntegerHelper.getShort(data[pos], data[pos + 1]);
this.rowLast = IntegerHelper.getShort(data[pos + 2], data[pos + 3]);
int columnMask = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
this.columnFirst = columnMask & 0xFF;
this.columnFirstRelative = ((columnMask & 0x4000) != 0);
this.rowFirstRelative = ((columnMask & 0x8000) != 0);
if (this.columnFirstRelative)
this.columnFirst = this.relativeTo.getColumn() + this.columnFirst;
if (this.rowFirstRelative)
this.rowFirst = this.relativeTo.getRow() + this.rowFirst;
columnMask = IntegerHelper.getInt(data[pos + 6], data[pos + 7]);
this.columnLast = columnMask & 0xFF;
this.columnLastRelative = ((columnMask & 0x4000) != 0);
this.rowLastRelative = ((columnMask & 0x8000) != 0);
if (this.columnLastRelative)
this.columnLast = this.relativeTo.getColumn() + this.columnLast;
if (this.rowLastRelative)
this.rowLast = this.relativeTo.getRow() + this.rowLast;
return 8;
}
public void getString(StringBuffer buf) {
CellReferenceHelper.getCellReference(this.columnFirst, this.rowFirst, buf);
buf.append(':');
CellReferenceHelper.getCellReference(this.columnLast, this.rowLast, buf);
}
byte[] getBytes() {
byte[] data = new byte[9];
data[0] = Token.AREA.getCode();
IntegerHelper.getTwoBytes(this.rowFirst, data, 1);
IntegerHelper.getTwoBytes(this.rowLast, data, 3);
IntegerHelper.getTwoBytes(this.columnFirst, data, 5);
IntegerHelper.getTwoBytes(this.columnLast, data, 7);
return data;
}
}

View File

@@ -0,0 +1,59 @@
package jxl.biff.formula;
import jxl.Cell;
import jxl.biff.CellReferenceHelper;
import jxl.biff.IntegerHelper;
class SharedFormulaCellReference extends Operand implements ParsedThing {
private boolean columnRelative;
private boolean rowRelative;
private int column;
private int row;
private Cell relativeTo;
public SharedFormulaCellReference(Cell rt) {
this.relativeTo = rt;
}
public int read(byte[] data, int pos) {
this.row = IntegerHelper.getShort(data[pos], data[pos + 1]);
int columnMask = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
this.column = (byte)(columnMask & 0xFF);
this.columnRelative = ((columnMask & 0x4000) != 0);
this.rowRelative = ((columnMask & 0x8000) != 0);
if (this.columnRelative)
this.column = this.relativeTo.getColumn() + this.column;
if (this.rowRelative)
this.row = this.relativeTo.getRow() + this.row;
return 4;
}
public int getColumn() {
return this.column;
}
public int getRow() {
return this.row;
}
public void getString(StringBuffer buf) {
CellReferenceHelper.getCellReference(this.column, this.row, buf);
}
byte[] getBytes() {
byte[] data = new byte[5];
data[0] = Token.REF.getCode();
IntegerHelper.getTwoBytes(this.row, data, 1);
int columnMask = this.column;
if (this.columnRelative)
columnMask |= 0x4000;
if (this.rowRelative)
columnMask |= 0x8000;
IntegerHelper.getTwoBytes(columnMask, data, 3);
return data;
}
}

View File

@@ -0,0 +1,249 @@
package jxl.biff.formula;
import common.Logger;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Stack;
import jxl.WorkbookSettings;
import jxl.biff.WorkbookMethods;
class StringFormulaParser implements Parser {
private static Logger logger = Logger.getLogger(StringFormulaParser.class);
private String formula;
private String parsedFormula;
private ParseItem root;
private Stack arguments;
private WorkbookSettings settings;
private ExternalSheet externalSheet;
private WorkbookMethods nameTable;
public StringFormulaParser(String f, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) {
this.formula = f;
this.settings = ws;
this.externalSheet = es;
this.nameTable = nt;
}
public void parse() throws FormulaException {
ArrayList tokens = getTokens();
Iterator i = tokens.iterator();
this.root = parseCurrent(i);
}
private ParseItem parseCurrent(Iterator i) throws FormulaException {
Stack stack = new Stack();
Stack operators = new Stack();
Stack args = null;
boolean parenthesesClosed = false;
ParseItem lastParseItem = null;
while (i.hasNext() && !parenthesesClosed) {
ParseItem pi = i.next();
if (pi instanceof Operand) {
handleOperand((Operand)pi, stack);
} else if (pi instanceof StringFunction) {
handleFunction((StringFunction)pi, i, stack);
} else if (pi instanceof Operator) {
Operator op = (Operator)pi;
if (op instanceof StringOperator) {
StringOperator sop = (StringOperator)op;
if (stack.isEmpty() || lastParseItem instanceof Operator) {
op = sop.getUnaryOperator();
} else {
op = sop.getBinaryOperator();
}
}
if (operators.empty()) {
operators.push(op);
} else {
Operator operator = operators.peek();
if (op.getPrecedence() < operator.getPrecedence()) {
operators.push(op);
} else {
operators.pop();
operator.getOperands(stack);
stack.push(operator);
operators.push(op);
}
}
} else if (pi instanceof ArgumentSeparator) {
while (!operators.isEmpty()) {
Operator o = operators.pop();
o.getOperands(stack);
stack.push(o);
}
if (args == null)
args = new Stack();
args.push(stack.pop());
stack.clear();
} else if (pi instanceof OpenParentheses) {
ParseItem pi2 = parseCurrent(i);
Parenthesis p = new Parenthesis();
pi2.setParent(p);
p.add(pi2);
stack.push(p);
} else if (pi instanceof CloseParentheses) {
parenthesesClosed = true;
}
lastParseItem = pi;
}
while (!operators.isEmpty()) {
Operator o = operators.pop();
o.getOperands(stack);
stack.push(o);
}
ParseItem rt = !stack.empty() ? stack.pop() : null;
if (args != null && rt != null)
args.push(rt);
this.arguments = args;
if (!stack.empty() || !operators.empty())
logger.warn("Formula " + this.formula + " has a non-empty parse stack");
return rt;
}
private ArrayList getTokens() throws FormulaException {
ArrayList tokens = new ArrayList();
StringReader sr = new StringReader(this.formula);
Yylex lex = new Yylex(sr);
lex.setExternalSheet(this.externalSheet);
lex.setNameTable(this.nameTable);
try {
ParseItem pi = lex.yylex();
while (pi != null) {
tokens.add(pi);
pi = lex.yylex();
}
} catch (IOException e) {
logger.warn(e.toString());
} catch (Error e) {
throw new FormulaException(FormulaException.lexicalError, this.formula + " at char " + lex.getPos());
}
return tokens;
}
public String getFormula() {
if (this.parsedFormula == null) {
StringBuffer sb = new StringBuffer();
this.root.getString(sb);
this.parsedFormula = sb.toString();
}
return this.parsedFormula;
}
public byte[] getBytes() {
byte[] bytes = this.root.getBytes();
if (this.root.isVolatile()) {
byte[] newBytes = new byte[bytes.length + 4];
System.arraycopy(bytes, 0, newBytes, 4, bytes.length);
newBytes[0] = Token.ATTRIBUTE.getCode();
newBytes[1] = 1;
bytes = newBytes;
}
return bytes;
}
private void handleFunction(StringFunction sf, Iterator i, Stack stack) throws FormulaException {
ParseItem pi2 = parseCurrent(i);
if (sf.getFunction(this.settings) == Function.UNKNOWN)
throw new FormulaException(FormulaException.unrecognizedFunction);
if (sf.getFunction(this.settings) == Function.SUM && this.arguments == null) {
Attribute a = new Attribute(sf, this.settings);
a.add(pi2);
stack.push(a);
return;
}
if (sf.getFunction(this.settings) == Function.IF) {
Attribute a = new Attribute(sf, this.settings);
VariableArgFunction vaf = new VariableArgFunction(this.settings);
int k = this.arguments.size();
for (int j = 0; j < k; j++) {
ParseItem pi3 = this.arguments.get(j);
vaf.add(pi3);
}
a.setIfConditions(vaf);
stack.push(a);
return;
}
if (sf.getFunction(this.settings).getNumArgs() == 255) {
if (this.arguments == null) {
int numArgs = (pi2 != null) ? 1 : 0;
VariableArgFunction vaf = new VariableArgFunction(sf.getFunction(this.settings), numArgs, this.settings);
if (pi2 != null)
vaf.add(pi2);
stack.push(vaf);
} else {
int k = this.arguments.size();
VariableArgFunction vaf = new VariableArgFunction(sf.getFunction(this.settings), k, this.settings);
ParseItem[] args = new ParseItem[k];
int j;
for (j = 0; j < k; j++) {
ParseItem pi3 = this.arguments.pop();
args[k - j - 1] = pi3;
}
for (j = 0; j < args.length; j++)
vaf.add(args[j]);
stack.push(vaf);
this.arguments.clear();
this.arguments = null;
}
return;
}
BuiltInFunction bif = new BuiltInFunction(sf.getFunction(this.settings), this.settings);
int numargs = sf.getFunction(this.settings).getNumArgs();
if (numargs == 1) {
bif.add(pi2);
} else {
if ((this.arguments == null && numargs != 0) || (this.arguments != null && numargs != this.arguments.size()))
throw new FormulaException(FormulaException.incorrectArguments);
for (int j = 0; j < numargs; j++) {
ParseItem pi3 = this.arguments.get(j);
bif.add(pi3);
}
}
stack.push(bif);
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
this.root.adjustRelativeCellReferences(colAdjust, rowAdjust);
}
public void columnInserted(int sheetIndex, int col, boolean currentSheet) {
this.root.columnInserted(sheetIndex, col, currentSheet);
}
public void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
this.root.columnRemoved(sheetIndex, col, currentSheet);
}
public void rowInserted(int sheetIndex, int row, boolean currentSheet) {
this.root.rowInserted(sheetIndex, row, currentSheet);
}
public void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
this.root.rowRemoved(sheetIndex, row, currentSheet);
}
private void handleOperand(Operand o, Stack stack) {
if (!(o instanceof IntegerValue)) {
stack.push(o);
return;
}
if (o instanceof IntegerValue) {
IntegerValue iv = (IntegerValue)o;
if (!iv.isOutOfRange()) {
stack.push(iv);
} else {
DoubleValue dv = new DoubleValue(iv.getValue());
stack.push(dv);
}
}
}
}

View File

@@ -0,0 +1,22 @@
package jxl.biff.formula;
import common.Logger;
import jxl.WorkbookSettings;
class StringFunction extends StringParseItem {
private static Logger logger = Logger.getLogger(StringFunction.class);
private Function function;
private String functionString;
StringFunction(String s) {
this.functionString = s.substring(0, s.length() - 1);
}
Function getFunction(WorkbookSettings ws) {
if (this.function == null)
this.function = Function.getFunction(this.functionString, ws);
return this.function;
}
}

View File

@@ -0,0 +1,48 @@
package jxl.biff.formula;
import common.Assert;
import java.util.Stack;
abstract class StringOperator extends Operator {
public void getOperands(Stack s) {
Assert.verify(false);
}
int getPrecedence() {
Assert.verify(false);
return 0;
}
byte[] getBytes() {
Assert.verify(false);
return null;
}
void getString(StringBuffer buf) {
Assert.verify(false);
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
Assert.verify(false);
}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {
Assert.verify(false);
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
Assert.verify(false);
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
Assert.verify(false);
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
Assert.verify(false);
}
abstract Operator getBinaryOperator();
abstract Operator getUnaryOperator();
}

View File

@@ -0,0 +1,19 @@
package jxl.biff.formula;
class StringParseItem extends ParseItem {
void getString(StringBuffer buf) {}
byte[] getBytes() {
return new byte[0];
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {}
}

View File

@@ -0,0 +1,50 @@
package jxl.biff.formula;
import common.Logger;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.StringHelper;
class StringValue extends Operand implements ParsedThing {
private static final Logger logger = Logger.getLogger(StringValue.class);
private String value;
private WorkbookSettings settings;
public StringValue(WorkbookSettings ws) {
this.settings = ws;
}
public StringValue(String s) {
this.value = s;
}
public int read(byte[] data, int pos) {
int length = IntegerHelper.getInt(data[pos], data[pos + 1]);
int consumed = 2;
if ((data[pos + 1] & 0x1) == 0) {
this.value = StringHelper.getString(data, length, pos + 2, this.settings);
consumed += length;
} else {
this.value = StringHelper.getUnicodeString(data, length, pos + 2);
consumed += length * 2;
}
return consumed;
}
byte[] getBytes() {
byte[] data = new byte[this.value.length() * 2 + 3];
data[0] = Token.STRING.getCode();
data[1] = (byte)this.value.length();
data[2] = 1;
StringHelper.getUnicodeBytes(this.value, data, 3);
return data;
}
public void getString(StringBuffer buf) {
buf.append("\"");
buf.append(this.value);
buf.append("\"");
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class Subtract extends BinaryOperator implements ParsedThing {
public String getSymbol() {
return "-";
}
Token getToken() {
return Token.SUBTRACT;
}
int getPrecedence() {
return 4;
}
}

View File

@@ -0,0 +1,131 @@
package jxl.biff.formula;
import java.util.HashMap;
class Token {
public final int[] value;
private static HashMap tokens = new HashMap(20);
private Token(int v) {
this.value = new int[] { v };
tokens.put(new Integer(v), this);
}
private Token(int v1, int v2) {
this.value = new int[] { v1, v2 };
tokens.put(new Integer(v1), this);
tokens.put(new Integer(v2), this);
}
private Token(int v1, int v2, int v3) {
this.value = new int[] { v1, v2, v3 };
tokens.put(new Integer(v1), this);
tokens.put(new Integer(v2), this);
tokens.put(new Integer(v3), this);
}
private Token(int v1, int v2, int v3, int v4) {
this.value = new int[] { v1, v2, v3, v4 };
tokens.put(new Integer(v1), this);
tokens.put(new Integer(v2), this);
tokens.put(new Integer(v3), this);
tokens.put(new Integer(v4), this);
}
private Token(int v1, int v2, int v3, int v4, int v5) {
this.value = new int[] { v1, v2, v3, v4, v5 };
tokens.put(new Integer(v1), this);
tokens.put(new Integer(v2), this);
tokens.put(new Integer(v3), this);
tokens.put(new Integer(v4), this);
tokens.put(new Integer(v5), this);
}
public byte getCode() {
return (byte)this.value[0];
}
public byte getCode2() {
return (byte)((this.value.length > 0) ? this.value[1] : this.value[0]);
}
public static Token getToken(int v) {
Token t = (Token)tokens.get(new Integer(v));
return (t != null) ? t : UNKNOWN;
}
public static final Token REF = new Token(68, 36, 100);
public static final Token REF3D = new Token(90, 58, 122);
public static final Token MISSING_ARG = new Token(22);
public static final Token STRING = new Token(23);
public static final Token BOOL = new Token(29);
public static final Token INTEGER = new Token(30);
public static final Token DOUBLE = new Token(31);
public static final Token REFERR = new Token(42, 74, 106);
public static final Token REFV = new Token(44, 76, 108);
public static final Token AREAV = new Token(45, 77, 109);
public static final Token AREA = new Token(37, 101, 69);
public static final Token NAMED_RANGE = new Token(67, 35, 99);
public static final Token NAME = new Token(57);
public static final Token AREA3D = new Token(59, 91);
public static final Token UNARY_PLUS = new Token(18);
public static final Token UNARY_MINUS = new Token(19);
public static final Token PERCENT = new Token(20);
public static final Token PARENTHESIS = new Token(21);
public static final Token ADD = new Token(3);
public static final Token SUBTRACT = new Token(4);
public static final Token MULTIPLY = new Token(5);
public static final Token DIVIDE = new Token(6);
public static final Token POWER = new Token(7);
public static final Token CONCAT = new Token(8);
public static final Token LESS_THAN = new Token(9);
public static final Token LESS_EQUAL = new Token(10);
public static final Token EQUAL = new Token(11);
public static final Token GREATER_EQUAL = new Token(12);
public static final Token GREATER_THAN = new Token(13);
public static final Token NOT_EQUAL = new Token(14);
public static final Token UNION = new Token(16);
public static final Token RANGE = new Token(17);
public static final Token FUNCTION = new Token(65, 33, 97);
public static final Token FUNCTIONVARARG = new Token(66, 34, 98);
public static final Token ATTRIBUTE = new Token(25);
public static final Token MEM_FUNC = new Token(41, 73, 105);
public static final Token UNKNOWN = new Token(65535);
}

View File

@@ -0,0 +1,325 @@
package jxl.biff.formula;
import common.Assert;
import common.Logger;
import java.util.Stack;
import jxl.Cell;
import jxl.WorkbookSettings;
import jxl.biff.WorkbookMethods;
class TokenFormulaParser implements Parser {
private static Logger logger = Logger.getLogger(TokenFormulaParser.class);
private byte[] tokenData;
private Cell relativeTo;
private int pos;
private ParseItem root;
private Stack tokenStack;
private ExternalSheet workbook;
private WorkbookMethods nameTable;
private WorkbookSettings settings;
public TokenFormulaParser(byte[] data, Cell c, ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) {
this.tokenData = data;
this.pos = 0;
this.relativeTo = c;
this.workbook = es;
this.nameTable = nt;
this.tokenStack = new Stack();
this.settings = ws;
}
public void parse() throws FormulaException {
parseSubExpression(this.tokenData.length);
this.root = this.tokenStack.pop();
Assert.verify(this.tokenStack.empty());
}
private void parseSubExpression(int len) throws FormulaException {
int tokenVal = 0;
Token t = null;
Stack ifStack = new Stack();
int endpos = this.pos + len;
while (this.pos < endpos) {
tokenVal = this.tokenData[this.pos];
this.pos++;
t = Token.getToken(tokenVal);
if (t == Token.UNKNOWN)
throw new FormulaException(FormulaException.unrecognizedToken, tokenVal);
Assert.verify((t != Token.UNKNOWN));
if (t == Token.REF) {
CellReference cr = new CellReference(this.relativeTo);
this.pos += cr.read(this.tokenData, this.pos);
this.tokenStack.push(cr);
continue;
}
if (t == Token.REF) {
CellReferenceError cr = new CellReferenceError();
this.pos += cr.read(this.tokenData, this.pos);
this.tokenStack.push(cr);
continue;
}
if (t == Token.REFV) {
SharedFormulaCellReference cr = new SharedFormulaCellReference(this.relativeTo);
this.pos += cr.read(this.tokenData, this.pos);
this.tokenStack.push(cr);
continue;
}
if (t == Token.REF3D) {
CellReference3d cr = new CellReference3d(this.relativeTo, this.workbook);
this.pos += cr.read(this.tokenData, this.pos);
this.tokenStack.push(cr);
continue;
}
if (t == Token.AREA) {
Area a = new Area();
this.pos += a.read(this.tokenData, this.pos);
this.tokenStack.push(a);
continue;
}
if (t == Token.AREAV) {
SharedFormulaArea a = new SharedFormulaArea(this.relativeTo);
this.pos += a.read(this.tokenData, this.pos);
this.tokenStack.push(a);
continue;
}
if (t == Token.AREA3D) {
Area3d a = new Area3d(this.workbook);
this.pos += a.read(this.tokenData, this.pos);
this.tokenStack.push(a);
continue;
}
if (t == Token.NAME) {
Name n = new Name();
this.pos += n.read(this.tokenData, this.pos);
this.tokenStack.push(n);
continue;
}
if (t == Token.NAMED_RANGE) {
NameRange nr = new NameRange(this.nameTable);
this.pos += nr.read(this.tokenData, this.pos);
this.tokenStack.push(nr);
continue;
}
if (t == Token.INTEGER) {
IntegerValue i = new IntegerValue();
this.pos += i.read(this.tokenData, this.pos);
this.tokenStack.push(i);
continue;
}
if (t == Token.DOUBLE) {
DoubleValue d = new DoubleValue();
this.pos += d.read(this.tokenData, this.pos);
this.tokenStack.push(d);
continue;
}
if (t == Token.BOOL) {
BooleanValue bv = new BooleanValue();
this.pos += bv.read(this.tokenData, this.pos);
this.tokenStack.push(bv);
continue;
}
if (t == Token.STRING) {
StringValue sv = new StringValue(this.settings);
this.pos += sv.read(this.tokenData, this.pos);
this.tokenStack.push(sv);
continue;
}
if (t == Token.MISSING_ARG) {
MissingArg ma = new MissingArg();
this.pos += ma.read(this.tokenData, this.pos);
this.tokenStack.push(ma);
continue;
}
if (t == Token.UNARY_PLUS) {
UnaryPlus up = new UnaryPlus();
this.pos += up.read(this.tokenData, this.pos);
addOperator(up);
continue;
}
if (t == Token.UNARY_MINUS) {
UnaryMinus um = new UnaryMinus();
this.pos += um.read(this.tokenData, this.pos);
addOperator(um);
continue;
}
if (t == Token.PERCENT) {
Percent p = new Percent();
this.pos += p.read(this.tokenData, this.pos);
addOperator(p);
continue;
}
if (t == Token.SUBTRACT) {
Subtract s = new Subtract();
this.pos += s.read(this.tokenData, this.pos);
addOperator(s);
continue;
}
if (t == Token.ADD) {
Add s = new Add();
this.pos += s.read(this.tokenData, this.pos);
addOperator(s);
continue;
}
if (t == Token.MULTIPLY) {
Multiply s = new Multiply();
this.pos += s.read(this.tokenData, this.pos);
addOperator(s);
continue;
}
if (t == Token.DIVIDE) {
Divide s = new Divide();
this.pos += s.read(this.tokenData, this.pos);
addOperator(s);
continue;
}
if (t == Token.CONCAT) {
Concatenate c = new Concatenate();
this.pos += c.read(this.tokenData, this.pos);
addOperator(c);
continue;
}
if (t == Token.POWER) {
Power p = new Power();
this.pos += p.read(this.tokenData, this.pos);
addOperator(p);
continue;
}
if (t == Token.LESS_THAN) {
LessThan lt = new LessThan();
this.pos += lt.read(this.tokenData, this.pos);
addOperator(lt);
continue;
}
if (t == Token.LESS_EQUAL) {
LessEqual lte = new LessEqual();
this.pos += lte.read(this.tokenData, this.pos);
addOperator(lte);
continue;
}
if (t == Token.GREATER_THAN) {
GreaterThan gt = new GreaterThan();
this.pos += gt.read(this.tokenData, this.pos);
addOperator(gt);
continue;
}
if (t == Token.GREATER_EQUAL) {
GreaterEqual gte = new GreaterEqual();
this.pos += gte.read(this.tokenData, this.pos);
addOperator(gte);
continue;
}
if (t == Token.NOT_EQUAL) {
NotEqual ne = new NotEqual();
this.pos += ne.read(this.tokenData, this.pos);
addOperator(ne);
continue;
}
if (t == Token.EQUAL) {
Equal e = new Equal();
this.pos += e.read(this.tokenData, this.pos);
addOperator(e);
continue;
}
if (t == Token.PARENTHESIS) {
Parenthesis p = new Parenthesis();
this.pos += p.read(this.tokenData, this.pos);
addOperator(p);
continue;
}
if (t == Token.ATTRIBUTE) {
Attribute a = new Attribute(this.settings);
this.pos += a.read(this.tokenData, this.pos);
if (a.isSum()) {
addOperator(a);
continue;
}
if (a.isIf())
ifStack.push(a);
continue;
}
if (t == Token.FUNCTION) {
BuiltInFunction bif = new BuiltInFunction(this.settings);
this.pos += bif.read(this.tokenData, this.pos);
addOperator(bif);
continue;
}
if (t == Token.FUNCTIONVARARG) {
VariableArgFunction vaf = new VariableArgFunction(this.settings);
this.pos += vaf.read(this.tokenData, this.pos);
if (vaf.getFunction() != Function.ATTRIBUTE) {
addOperator(vaf);
continue;
}
vaf.getOperands(this.tokenStack);
Attribute ifattr = null;
if (ifStack.empty()) {
ifattr = new Attribute(this.settings);
} else {
ifattr = ifStack.pop();
}
ifattr.setIfConditions(vaf);
this.tokenStack.push(ifattr);
continue;
}
if (t == Token.MEM_FUNC) {
MemFunc memFunc = new MemFunc();
this.pos += memFunc.read(this.tokenData, this.pos);
Stack oldStack = this.tokenStack;
this.tokenStack = new Stack();
parseSubExpression(memFunc.getLength());
ParseItem[] subexpr = new ParseItem[this.tokenStack.size()];
int i = 0;
while (!this.tokenStack.isEmpty()) {
subexpr[i] = this.tokenStack.pop();
i++;
}
memFunc.setSubExpression(subexpr);
this.tokenStack = oldStack;
this.tokenStack.push(memFunc);
}
}
}
private void addOperator(Operator o) {
o.getOperands(this.tokenStack);
this.tokenStack.push(o);
}
public String getFormula() {
StringBuffer sb = new StringBuffer();
this.root.getString(sb);
return sb.toString();
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
this.root.adjustRelativeCellReferences(colAdjust, rowAdjust);
}
public byte[] getBytes() {
return this.root.getBytes();
}
public void columnInserted(int sheetIndex, int col, boolean currentSheet) {
this.root.columnInserted(sheetIndex, col, currentSheet);
}
public void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
this.root.columnRemoved(sheetIndex, col, currentSheet);
}
public void rowInserted(int sheetIndex, int row, boolean currentSheet) {
this.root.rowInserted(sheetIndex, row, currentSheet);
}
public void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
this.root.rowRemoved(sheetIndex, row, currentSheet);
}
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class UnaryMinus extends UnaryOperator implements ParsedThing {
public String getSymbol() {
return "-";
}
Token getToken() {
return Token.UNARY_MINUS;
}
int getPrecedence() {
return 2;
}
}

View File

@@ -0,0 +1,58 @@
package jxl.biff.formula;
import java.util.Stack;
abstract class UnaryOperator extends Operator implements ParsedThing {
public int read(byte[] data, int pos) {
return 0;
}
public void getOperands(Stack s) {
ParseItem o1 = s.pop();
add(o1);
}
public void getString(StringBuffer buf) {
ParseItem[] operands = getOperands();
buf.append(getSymbol());
operands[0].getString(buf);
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
ParseItem[] operands = getOperands();
operands[0].adjustRelativeCellReferences(colAdjust, rowAdjust);
}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[0].columnInserted(sheetIndex, col, currentSheet);
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[0].columnRemoved(sheetIndex, col, currentSheet);
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[0].rowInserted(sheetIndex, row, currentSheet);
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
operands[0].rowRemoved(sheetIndex, row, currentSheet);
}
byte[] getBytes() {
ParseItem[] operands = getOperands();
byte[] data = operands[0].getBytes();
byte[] newdata = new byte[data.length + 1];
System.arraycopy(data, 0, newdata, 0, data.length);
newdata[data.length] = getToken().getCode();
return newdata;
}
abstract String getSymbol();
abstract Token getToken();
}

View File

@@ -0,0 +1,15 @@
package jxl.biff.formula;
class UnaryPlus extends UnaryOperator implements ParsedThing {
public String getSymbol() {
return "+";
}
Token getToken() {
return Token.UNARY_PLUS;
}
int getPrecedence() {
return 2;
}
}

View File

@@ -0,0 +1,139 @@
package jxl.biff.formula;
import common.Logger;
import java.util.Stack;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
class VariableArgFunction extends Operator implements ParsedThing {
private static Logger logger = Logger.getLogger(VariableArgFunction.class);
private Function function;
private int arguments;
private boolean readFromSheet;
private WorkbookSettings settings;
public VariableArgFunction(WorkbookSettings ws) {
this.readFromSheet = true;
this.settings = ws;
}
public VariableArgFunction(Function f, int a, WorkbookSettings ws) {
this.function = f;
this.arguments = a;
this.readFromSheet = false;
this.settings = ws;
}
public int read(byte[] data, int pos) throws FormulaException {
this.arguments = data[pos];
int index = IntegerHelper.getInt(data[pos + 1], data[pos + 2]);
this.function = Function.getFunction(index);
if (this.function == Function.UNKNOWN)
throw new FormulaException(FormulaException.unrecognizedFunction, index);
return 3;
}
public void getOperands(Stack s) {
ParseItem[] items = new ParseItem[this.arguments];
int i;
for (i = this.arguments - 1; i >= 0; i--) {
ParseItem pi = s.pop();
items[i] = pi;
}
for (i = 0; i < this.arguments; i++)
add(items[i]);
}
public void getString(StringBuffer buf) {
buf.append(this.function.getName(this.settings));
buf.append('(');
if (this.arguments > 0) {
ParseItem[] operands = getOperands();
if (this.readFromSheet) {
operands[0].getString(buf);
for (int i = 1; i < this.arguments; i++) {
buf.append(',');
operands[i].getString(buf);
}
} else {
operands[this.arguments - 1].getString(buf);
for (int i = this.arguments - 2; i >= 0; i--) {
buf.append(',');
operands[i].getString(buf);
}
}
}
buf.append(')');
}
public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].adjustRelativeCellReferences(colAdjust, rowAdjust);
}
void columnInserted(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].columnInserted(sheetIndex, col, currentSheet);
}
void columnRemoved(int sheetIndex, int col, boolean currentSheet) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].columnRemoved(sheetIndex, col, currentSheet);
}
void rowInserted(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].rowInserted(sheetIndex, row, currentSheet);
}
void rowRemoved(int sheetIndex, int row, boolean currentSheet) {
ParseItem[] operands = getOperands();
for (int i = 0; i < operands.length; i++)
operands[i].rowRemoved(sheetIndex, row, currentSheet);
}
Function getFunction() {
return this.function;
}
byte[] getBytes() {
handleSpecialCases();
ParseItem[] operands = getOperands();
byte[] data = new byte[0];
for (int i = 0; i < operands.length; i++) {
byte[] opdata = operands[i].getBytes();
byte[] arrayOfByte1 = new byte[data.length + opdata.length];
System.arraycopy(data, 0, arrayOfByte1, 0, data.length);
System.arraycopy(opdata, 0, arrayOfByte1, data.length, opdata.length);
data = arrayOfByte1;
}
byte[] newdata = new byte[data.length + 4];
System.arraycopy(data, 0, newdata, 0, data.length);
newdata[data.length] = !useAlternateCode() ? Token.FUNCTIONVARARG.getCode() : Token.FUNCTIONVARARG.getCode2();
newdata[data.length + 1] = (byte)this.arguments;
IntegerHelper.getTwoBytes(this.function.getCode(), newdata, data.length + 2);
return newdata;
}
int getPrecedence() {
return 3;
}
private void handleSpecialCases() {
if (this.function == Function.SUMPRODUCT) {
ParseItem[] operands = getOperands();
for (int i = operands.length - 1; i >= 0; i--) {
if (operands[i] instanceof Area)
operands[i].setAlternateCode();
}
}
}
}

View File

@@ -0,0 +1,503 @@
package jxl.biff.formula;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import jxl.biff.WorkbookMethods;
class Yylex {
private final int YY_BUFFER_SIZE = 512;
private final int YY_F = -1;
private final int YY_NO_STATE = -1;
private final int YY_NOT_ACCEPT = 0;
private final int YY_START = 1;
private final int YY_END = 2;
private final int YY_NO_ANCHOR = 4;
private final int YY_BOL = 65536;
private final int YY_EOF = 65537;
private boolean emptyString;
private ExternalSheet externalSheet;
private WorkbookMethods nameTable;
private BufferedReader yy_reader;
private int yy_buffer_index;
private int yy_buffer_read;
private int yy_buffer_start;
private int yy_buffer_end;
private char[] yy_buffer;
private int yychar;
private int yyline;
private boolean yy_at_bol;
private int yy_lexical_state;
private boolean yy_eof_done;
private final int YYSTRING = 1;
private final int YYINITIAL = 0;
private final int[] yy_state_dtrans;
private boolean yy_last_was_cr;
private final int YY_E_INTERNAL = 0;
private final int YY_E_MATCH = 1;
private String[] yy_error_string;
private int[] yy_acpt;
private int[] yy_cmap;
private int[] yy_rmap;
private int[][] yy_nxt;
int getPos() {
return this.yychar;
}
void setExternalSheet(ExternalSheet es) {
this.externalSheet = es;
}
void setNameTable(WorkbookMethods nt) {
this.nameTable = nt;
}
Yylex(Reader reader) {
this();
if (null == reader)
throw new Error("Error: Bad input stream initializer.");
this.yy_reader = new BufferedReader(reader);
}
Yylex(InputStream instream) {
this();
if (null == instream)
throw new Error("Error: Bad input stream initializer.");
this.yy_reader = new BufferedReader(new InputStreamReader(instream));
}
private Yylex() {
this.yy_eof_done = false;
this.YYSTRING = 1;
this.YYINITIAL = 0;
this.yy_state_dtrans = new int[] { 0, 30 };
this.yy_last_was_cr = false;
this.YY_E_INTERNAL = 0;
this.YY_E_MATCH = 1;
this.yy_error_string = new String[] { "Error: Internal error.\n", "Error: Unmatched input.\n" };
this.yy_acpt = new int[] {
0, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 0, 4, 4, 4, 4, 4, 4, 4,
0, 4, 4, 0, 4, 4, 0, 4, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 4, 0, 4, 0, 0, 4, 0 };
this.yy_cmap = unpackFromString(1, 65538, "29:8,14:3,29:21,14,16,28,15,11,15:2,13,26,27,3,1,8,2,10,4,9:10,17,15,7,6,5,15:2,23,12:3,21,22,12:5,24,12:5,19,25,18,20,12:5,15:5,29,12:26,29,15,29,15,29:65409,0:2")[0];
this.yy_rmap = unpackFromString(1, 89, "0,1,2,1,2:2,3,2,4,2,5,2:2,1:3,2:3,6,7,1,8,9,10,11,12,13,11,14,15,1,16,17,11,2,18,19,20,21,22,23,2,24,25,1,26,27,8,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,13,50,51,52,53,54,55,56,14,57,20,58,59,60,2,61,62,63")[0];
this.yy_nxt = unpackFromString(64, 30, "1,2,3,4,5,6,7,8,9,10,32,40,32,43,11,85:2,12,83,32:3,88,32:3,13,14,15,-1:32,85,-1,85:10,46,85:2,86,85:9,-1:5,85,-1,85:3,16,85:6,46,85:2,86,85:9,-1:5,85,-1,85:2,17,18,85:6,46,85:2,86,85:9,-1:5,85,-1,85:6,10,48,85:2,46,85:2,86,85:9,-1:5,85,-1,85:6,19,85:3,46,85:2,86,55,85:8,-1:5,85,-1,85:6,33,34,49,34,46,85:2,86,50,34:8,21,-1:4,85,-1,85:6,22,85:3,46,85:2,86,85:9,-1:5,85,-1,85:7,35,85,35,46,85:2,86,85,35:8,-1:5,85,-1,85:6,24,85:3,46,85:2,86,68,85:8,-1:5,85,-1,85:6,44,34,85,34,46,85:2,86,85,34:8,21,-1:4,85,-1,85:7,42,85,42,46,85:2,86,85,42:8,-1:5,85,-1,85:6,27,85:3,46,85:2,86,85:9,-1:5,85,-1,85:6,29,85:3,46,85:2,86,85:9,-1:4,1,39:27,31,39,-1,85,-1,85:6,19,20,49,20,46,85:2,86,50,20:8,21,-1:4,85,-1,85:6,33,44,85,44,46,85:2,86,55,44:8,-1:13,36,-1:7,72,-1:22,45,-1,45,-1:5,45:8,-1:13,38,-1:21,39:27,-1,39,-1,85,-1,85:7,51,85,51,46,85:2,86,85,51:8,-1:5,85,-1,85:6,44,34,85,34,46,85:2,86,85,34:3,25,34:4,21,-1:4,85,-1,85:10,-1,85:12,-1:5,85,-1,85:6,44:2,85,44,46,85:2,86,85,44:8,-1:20,52,-1:14,85,-1,85:6,44,34,85,34,46,85:2,86,85,34:3,28,34:4,21,-1:4,85,-1,85:6,19,85:3,46,85:2,86,85:9,-1:5,85,-1,85:7,23,56,23,46,85:2,86,85,23:8,-1:5,85,-1,85:6,19,57,49,57,46,85:2,86,50,57:8,-1:14,58,59,58,-1:5,58:8,-1:5,85,-1,85:6,24,60,61,60,46,85:2,86,62,60:8,-1:5,85,-1,85:7,53,85,53,46,85:2,86,85,53:8,-1:5,85,-1,85:7,63,64,63,46,85:2,86,85,63:8,-1:5,85,-1,85:7,23,85,23,46,85:2,86,85,23:8,-1:5,85,-1,85:6,19,85,49,85,46,85:2,86,50,85:8,-1:13,36,65,66,65,-1:4,67,65:8,-1:14,58,-1,58,-1:5,58:8,-1:5,85,-1,85:6,24,85,61,85,46,85:2,86,62,85:8,-1:5,85,-1,85:6,24,85:3,46,85:2,86,85:9,-1:5,85,-1,85:7,26,69,26,46,85:2,86,85,26:8,-1:5,85,-1,85:6,27,70,71,70,46,85:2,86,85,70:8,-1:5,85,-1,85:7,63,85,63,46,85:2,86,85,63:8,-1:13,36,-1,66,-1:5,67,-1:21,36,-1:30,37,73,37,-1:5,37:8,-1:5,85,-1,85:7,74,75,74,46,85:2,86,85,74:8,-1:5,85,-1,85:7,26,85,26,46,85:2,86,85,26:8,-1:5,85,-1,85:6,27,85,71,85,46,85:2,86,85:9,-1:14,76,77,76,-1:5,76:8,-1:14,37,-1,37,-1:5,37:8,-1:5,85,-1,85:6,29,78,79,78,46,85:2,86,85,78:8,-1:5,85,-1,85:7,74,85,74,46,85:2,86,85,74:8,-1:13,38,80,81,80,-1:5,80:8,-1:14,76,-1,76,-1:5,76:8,-1:5,85,-1,85:6,29,85,79,85,46,85:2,86,85:9,-1:13,38,-1,81,-1:19,85,-1,85:6,33,34,49,34,46,85:2,86,50,34:2,41,34:5,21,-1:4,85,-1,85:6,19,20,49,20,46,85:2,86,50,20,82,20:6,21,-1:4,85,-1,85:6,44,34,85,34,46,85:2,86,85,34:7,47,21,-1:4,85,-1,85:7,53,54,53,46,85:2,86,85,53:8,-1:5,85,-1,85:6,33,34,49,34,46,85:2,86,50,34:6,84,34,21,-1:4,85,-1,85:6,19,20,49,20,46,85:2,86,50,20:5,87,20:2,21,-1:3");
this.yy_buffer = new char[512];
this.yy_buffer_read = 0;
this.yy_buffer_index = 0;
this.yy_buffer_start = 0;
this.yy_buffer_end = 0;
this.yychar = 0;
this.yyline = 0;
this.yy_at_bol = true;
this.yy_lexical_state = 0;
}
private void yybegin(int state) {
this.yy_lexical_state = state;
}
private int yy_advance() throws IOException {
if (this.yy_buffer_index < this.yy_buffer_read)
return this.yy_buffer[this.yy_buffer_index++];
if (0 != this.yy_buffer_start) {
int i = this.yy_buffer_start;
int j = 0;
while (i < this.yy_buffer_read) {
this.yy_buffer[j] = this.yy_buffer[i];
i++;
j++;
}
this.yy_buffer_end -= this.yy_buffer_start;
this.yy_buffer_start = 0;
this.yy_buffer_read = j;
this.yy_buffer_index = j;
int next_read = this.yy_reader.read(this.yy_buffer, this.yy_buffer_read, this.yy_buffer.length - this.yy_buffer_read);
if (-1 == next_read)
return 65537;
this.yy_buffer_read += next_read;
}
while (this.yy_buffer_index >= this.yy_buffer_read) {
if (this.yy_buffer_index >= this.yy_buffer.length)
this.yy_buffer = yy_double(this.yy_buffer);
int next_read = this.yy_reader.read(this.yy_buffer, this.yy_buffer_read, this.yy_buffer.length - this.yy_buffer_read);
if (-1 == next_read)
return 65537;
this.yy_buffer_read += next_read;
}
return this.yy_buffer[this.yy_buffer_index++];
}
private void yy_move_end() {
if (this.yy_buffer_end > this.yy_buffer_start && '\n' == this.yy_buffer[this.yy_buffer_end - 1])
this.yy_buffer_end--;
if (this.yy_buffer_end > this.yy_buffer_start && '\r' == this.yy_buffer[this.yy_buffer_end - 1])
this.yy_buffer_end--;
}
private void yy_mark_start() {
for (int i = this.yy_buffer_start; i < this.yy_buffer_index; i++) {
if ('\n' == this.yy_buffer[i] && !this.yy_last_was_cr)
this.yyline++;
if ('\r' == this.yy_buffer[i]) {
this.yyline++;
this.yy_last_was_cr = true;
} else {
this.yy_last_was_cr = false;
}
}
this.yychar = this.yychar + this.yy_buffer_index - this.yy_buffer_start;
this.yy_buffer_start = this.yy_buffer_index;
}
private void yy_mark_end() {
this.yy_buffer_end = this.yy_buffer_index;
}
private void yy_to_mark() {
this.yy_buffer_index = this.yy_buffer_end;
this.yy_at_bol = (this.yy_buffer_end > this.yy_buffer_start && ('\r' == this.yy_buffer[this.yy_buffer_end - 1] || '\n' == this.yy_buffer[this.yy_buffer_end - 1] || '߬' == this.yy_buffer[this.yy_buffer_end - 1] || '߭' == this.yy_buffer[this.yy_buffer_end - 1]));
}
private String yytext() {
return new String(this.yy_buffer, this.yy_buffer_start, this.yy_buffer_end - this.yy_buffer_start);
}
private int yylength() {
return this.yy_buffer_end - this.yy_buffer_start;
}
private char[] yy_double(char[] buf) {
char[] newbuf = new char[2 * buf.length];
for (int i = 0; i < buf.length; i++)
newbuf[i] = buf[i];
return newbuf;
}
private void yy_error(int code, boolean fatal) {
System.out.print(this.yy_error_string[code]);
System.out.flush();
if (fatal)
throw new Error("Fatal Error.\n");
}
private int[][] unpackFromString(int size1, int size2, String st) {
int colonIndex = -1;
int sequenceLength = 0;
int sequenceInteger = 0;
int[][] res = new int[size1][size2];
for (int i = 0; i < size1; i++) {
for (int j = 0; j < size2; j++) {
if (sequenceLength != 0) {
res[i][j] = sequenceInteger;
sequenceLength--;
} else {
int commaIndex = st.indexOf(',');
String workString = (commaIndex == -1) ? st : st.substring(0, commaIndex);
st = st.substring(commaIndex + 1);
colonIndex = workString.indexOf(':');
if (colonIndex == -1) {
res[i][j] = Integer.parseInt(workString);
} else {
String lengthString = workString.substring(colonIndex + 1);
sequenceLength = Integer.parseInt(lengthString);
workString = workString.substring(0, colonIndex);
sequenceInteger = Integer.parseInt(workString);
res[i][j] = sequenceInteger;
sequenceLength--;
}
}
}
}
return res;
}
public ParseItem yylex() throws IOException, FormulaException {
int yy_anchor = 4;
int yy_state = this.yy_state_dtrans[this.yy_lexical_state];
int yy_next_state = -1;
int yy_last_accept_state = -1;
boolean yy_initial = true;
yy_mark_start();
int yy_this_accept = this.yy_acpt[yy_state];
if (0 != yy_this_accept) {
yy_last_accept_state = yy_state;
yy_mark_end();
}
while (true) {
int yy_lookahead;
if (yy_initial && this.yy_at_bol) {
yy_lookahead = 65536;
} else {
yy_lookahead = yy_advance();
}
yy_next_state = -1;
yy_next_state = this.yy_nxt[this.yy_rmap[yy_state]][this.yy_cmap[yy_lookahead]];
if (65537 == yy_lookahead && true == yy_initial)
return null;
if (-1 != yy_next_state) {
yy_state = yy_next_state;
yy_initial = false;
yy_this_accept = this.yy_acpt[yy_state];
if (0 != yy_this_accept) {
yy_last_accept_state = yy_state;
yy_mark_end();
}
continue;
}
if (-1 == yy_last_accept_state)
throw new Error("Lexical Error: Unmatched Input.");
yy_anchor = this.yy_acpt[yy_last_accept_state];
if (0 != (0x2 & yy_anchor))
yy_move_end();
yy_to_mark();
switch (yy_last_accept_state) {
case -2:
case 1:
break;
case 2:
return new Plus();
case -3:
break;
case 3:
return new Minus();
case -4:
break;
case 4:
return new Multiply();
case -5:
break;
case 5:
return new Divide();
case -6:
break;
case 6:
return new GreaterThan();
case -7:
break;
case 7:
return new Equal();
case -8:
break;
case 8:
return new LessThan();
case -9:
break;
case 9:
return new ArgumentSeparator();
case -10:
break;
case 10:
return new IntegerValue(yytext());
case -11:
case -12:
case 11:
break;
case 12:
return new RangeSeparator();
case -13:
break;
case 13:
return new OpenParentheses();
case -14:
break;
case 14:
return new CloseParentheses();
case -15:
break;
case 15:
this.emptyString = true;
yybegin(1);
break;
case -16:
break;
case 16:
return new GreaterEqual();
case -17:
break;
case 17:
return new NotEqual();
case -18:
break;
case 18:
return new LessEqual();
case -19:
break;
case 19:
return new CellReference(yytext());
case -20:
break;
case 20:
return new NameRange(yytext(), this.nameTable);
case -21:
break;
case 21:
return new StringFunction(yytext());
case -22:
break;
case 22:
return new DoubleValue(yytext());
case -23:
break;
case 23:
return new ColumnRange(yytext());
case -24:
break;
case 24:
return new CellReference3d(yytext(), this.externalSheet);
case -25:
break;
case 25:
return new BooleanValue(yytext());
case -26:
break;
case 26:
return new ColumnRange3d(yytext(), this.externalSheet);
case -27:
break;
case 27:
return new Area(yytext());
case -28:
break;
case 28:
return new BooleanValue(yytext());
case -29:
break;
case 29:
return new Area3d(yytext(), this.externalSheet);
case -30:
break;
case 30:
this.emptyString = false;
return new StringValue(yytext());
case -31:
break;
case 31:
yybegin(0);
if (this.emptyString)
return new StringValue("");
break;
case -32:
break;
case 33:
return new CellReference(yytext());
case -33:
break;
case 34:
return new NameRange(yytext(), this.nameTable);
case -34:
break;
case 35:
return new ColumnRange(yytext());
case -35:
break;
case 36:
return new CellReference3d(yytext(), this.externalSheet);
case -36:
break;
case 37:
return new ColumnRange3d(yytext(), this.externalSheet);
case -37:
break;
case 38:
return new Area3d(yytext(), this.externalSheet);
case -38:
break;
case 39:
this.emptyString = false;
return new StringValue(yytext());
case -39:
break;
case 41:
return new NameRange(yytext(), this.nameTable);
case -40:
break;
case 42:
return new ColumnRange3d(yytext(), this.externalSheet);
case -41:
break;
case 44:
return new NameRange(yytext(), this.nameTable);
case -42:
break;
case 45:
return new ColumnRange3d(yytext(), this.externalSheet);
case -43:
break;
case 47:
return new NameRange(yytext(), this.nameTable);
case -44:
break;
case 82:
return new NameRange(yytext(), this.nameTable);
case -45:
break;
case 84:
return new NameRange(yytext(), this.nameTable);
case -46:
break;
case 87:
return new NameRange(yytext(), this.nameTable);
case -47:
break;
default:
yy_error(0, false);
break;
case -1:
break;
}
yy_initial = true;
yy_state = this.yy_state_dtrans[this.yy_lexical_state];
yy_next_state = -1;
yy_last_accept_state = -1;
yy_mark_start();
yy_this_accept = this.yy_acpt[yy_state];
if (0 != yy_this_accept) {
yy_last_accept_state = yy_state;
yy_mark_end();
}
}
}
}