diff --git a/src/java/org/apache/poi/hssf/record/formula/AddPtg.java b/src/java/org/apache/poi/hssf/record/formula/AddPtg.java index f25f2b075..aa68f96d9 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AddPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AddPtg.java @@ -124,5 +124,7 @@ public class AddPtg buffer.append(operands[ 1 ]); return buffer.toString(); } + + public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} } diff --git a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java index 9aa124aed..33e0be384 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java @@ -70,7 +70,7 @@ public class Area3DPtg extends Ptg { public final static short sid = 0x3b; private final static int SIZE = 11; // 10 + 1 for Ptg - private short field_1_index_extern_sheet; + private short field_1_index_extern_sheet; private short field_2_first_row; private short field_3_last_row; private short field_4_first_column; @@ -116,20 +116,20 @@ public class Area3DPtg extends Ptg array[ 0 + offset ] = sid; LittleEndian.putShort(array, 1 + offset , getExternSheetIndex()); LittleEndian.putShort(array, 3 + offset , getFirstRow()); - LittleEndian.putShort(array, 5 + offset , getLastRow()); - LittleEndian.putShort(array, 7 + offset , getFirstColumnRaw()); - LittleEndian.putShort(array, 9 + offset , getLastColumnRaw()); + LittleEndian.putShort(array, 5 + offset , getLastRow()); + LittleEndian.putShort(array, 7 + offset , getFirstColumnRaw()); + LittleEndian.putShort(array, 9 + offset , getLastColumnRaw()); } public int getSize() { return SIZE; } - + public short getExternSheetIndex(){ return field_1_index_extern_sheet; } - + public void setExternSheetIndex(short index){ field_1_index_extern_sheet = index; } @@ -177,17 +177,17 @@ public class Area3DPtg extends Ptg public void setFirstColumn(short column) { field_4_first_column &= 0xFF00; - field_4_first_column |= column & 0xFF; + field_4_first_column |= column & 0xFF; } public void setFirstColumnRaw(short column) { - field_4_first_column = column; + field_4_first_column = column; } public short getLastColumn() { - return ( short ) (field_5_last_column & 0xFF); + return ( short ) (field_5_last_column & 0xFF); } public short getLastColumnRaw() @@ -208,32 +208,32 @@ public class Area3DPtg extends Ptg public void setLastColumn(short column) { field_5_last_column &= 0xFF00; - field_5_last_column |= column & 0xFF; + field_5_last_column |= column & 0xFF; } public void setLastColumnRaw(short column) { field_5_last_column = column; } - + public String getArea(){ - RangeAddress ra = new RangeAddress( getFirstColumn(),getFirstRow() + 1, getLastColumn(), getLastRow() + 1); + RangeAddress ra = new RangeAddress( getFirstColumn(),getFirstRow() + 1, getLastColumn(), getLastRow() + 1); String result = ra.getAddress(); - + return result; } - + public void setArea(String ref){ RangeAddress ra = new RangeAddress(ref); - + String from = ra.getFromCell(); String to = ra.getToCell(); - + setFirstColumn((short) (ra.getXPosition(from) -1)); setFirstRow((short) (ra.getYPosition(from) -1)); setLastColumn((short) (ra.getXPosition(to) -1)); setLastRow((short) (ra.getYPosition(to) -1)); - + } public String toFormulaString() @@ -243,5 +243,8 @@ public class Area3DPtg extends Ptg return result; } - + public byte getDefaultOperandClass() { + return Ptg.CLASS_VALUE; + } + } diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java index afbd0464c..5e22c1cea 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java @@ -131,7 +131,7 @@ public class AreaPtg } public void writeBytes(byte [] array, int offset) { - array[offset] = sid; + array[offset] = (byte) (sid + ptgClass); LittleEndian.putShort(array,offset+1,field_1_first_row); LittleEndian.putShort(array,offset+3,field_2_last_row); LittleEndian.putShort(array,offset+5,field_3_first_column); @@ -309,4 +309,8 @@ public class AreaPtg (new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative())).toString(); } + public byte getDefaultOperandClass() { + return Ptg.CLASS_REF; + } + } diff --git a/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java b/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java index 27fd4a0bd..c5db837b3 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java @@ -211,5 +211,5 @@ public class AttrPtg } - + public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} } diff --git a/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java b/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java index 6ec0916c3..dc8b4b354 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java @@ -96,4 +96,7 @@ public class ExpPtg { return "NO IDEA SHARED FORMULA EXP PTG"; } + + public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} + } diff --git a/src/java/org/apache/poi/hssf/record/formula/FormulaParser.java b/src/java/org/apache/poi/hssf/record/formula/FormulaParser.java index 6498ae9ee..823f6fa9c 100644 --- a/src/java/org/apache/poi/hssf/record/formula/FormulaParser.java +++ b/src/java/org/apache/poi/hssf/record/formula/FormulaParser.java @@ -79,6 +79,12 @@ import java.io.File; */ public class FormulaParser { + public static int FORMULA_TYPE_CELL = 0; + public static int FORMULA_TYPE_SHARED = 1; + public static int FORMULA_TYPE_ARRAY =2; + public static int FORMULA_TYPE_CONDFOMRAT = 3; + public static int FORMULA_TYPE_NAMEDRANGE = 4; + private String formulaString; private int pointer=0; @@ -193,18 +199,16 @@ public class FormulaParser { /** Get an Identifier */ private String GetName() { - String Token; - Token = ""; + StringBuffer Token = new StringBuffer(); if (!IsAlpha(Look)) { Expected("Name"); } while (IsAlNum(Look)) { - Token = Token + Character.toUpperCase(Look); + Token = Token.append(Character.toUpperCase(Look)); GetChar(); } - SkipWhite(); - return Token; + return Token.toString(); } @@ -304,7 +308,10 @@ public class FormulaParser { return; } else if (IsAlpha(Look)){ Ident(); - }else{ + } else if(Look == '"') { + StringLiteral(); + } else { + String number = GetNum(); if (Look=='.') { Match('.'); @@ -316,7 +323,13 @@ public class FormulaParser { } } } - + + private void StringLiteral() { + Match('"'); + String name= GetName(); + Match('"'); + tokens.add(new StringPtg(name)); + } /** Recognize and Translate a Multiply */ private void Multiply(){ @@ -429,13 +442,89 @@ end; * a result of the parsing */ public Ptg[] getRPNPtg() { - synchronized (tokens) { - if (tokens == null) throw new IllegalStateException("Please parse a string before trying to access the parse result"); - Ptg[] retval = new Ptg[tokens.size()]; - return (Ptg[]) tokens.toArray(retval); - } + return getRPNPtg(FORMULA_TYPE_CELL); } - + + public Ptg[] getRPNPtg(int formulaType) { + Node node = createTree(); + setRootLevelRVA(node, formulaType); + setParameterRVA(node,formulaType); + return (Ptg[]) tokens.toArray(new Ptg[0]); + } + + private void setRootLevelRVA(Node n, int formulaType) { + //Pg 16, excelfileformat.pdf @ openoffice.org + Ptg p = (Ptg) n.getValue(); + if (formulaType == this.FORMULA_TYPE_NAMEDRANGE) { + if (p.getDefaultOperandClass() == Ptg.CLASS_REF) { + setClass(n,Ptg.CLASS_REF); + } else { + setClass(n,Ptg.CLASS_ARRAY); + } + } else { + setClass(n,Ptg.CLASS_VALUE); + } + + } + + private void setParameterRVA(Node n, int formulaType) { + Ptg p = (Ptg) n.getValue(); + if (p instanceof FunctionPtg) { + int numOperands = n.getNumChildren(); + for (int i =0;i 0) { @@ -478,6 +568,31 @@ end; } return (String) stack.pop(); //TODO: catch stack underflow and throw parse exception. } + + private Node createTree() { + java.util.Stack stack = new java.util.Stack(); + int numPtgs = tokens.size(); + OperationPtg o; + int numOperands; + Node[] operands; + for (int i=0;i 0x60) { + retval.setClass(CLASS_ARRAY); + } else if (id > 0x40) { + retval.setClass(CLASS_VALUE); + } else + retval.setClass(CLASS_REF); + return retval; + } public abstract int getSize(); @@ -310,5 +285,19 @@ public abstract class Ptg return retval; } + public static final byte CLASS_REF = 0x00; + public static final byte CLASS_VALUE = 0x20; + public static final byte CLASS_ARRAY = 0x40; + + protected byte ptgClass = CLASS_REF; //base ptg + + public void setClass(byte thePtgClass) { + ptgClass = thePtgClass; + } + + + public abstract byte getDefaultOperandClass(); + + } diff --git a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java index 885a8bac1..3df425ae1 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java @@ -1,4 +1,5 @@ + /* ==================================================================== * The Apache Software License, Version 1.1 * @@ -72,22 +73,22 @@ public class Ref3DPtg extends Ptg { private short field_1_index_extern_sheet; private short field_2_row; private short field_3_column; - + /** Creates new AreaPtg */ - + public Ref3DPtg() { } - + public Ref3DPtg(byte[] data, int offset) { offset++; field_1_index_extern_sheet = LittleEndian.getShort(data, 0 + offset); field_2_row = LittleEndian.getShort(data, 2 + offset); field_3_column = LittleEndian.getShort(data, 4 + offset); } - + public String toString() { StringBuffer buffer = new StringBuffer(); - + buffer.append("Ref3dPrg\n"); buffer.append("Index to Extern Sheet = " + getExternSheetIndex()).append("\n"); buffer.append("Row = " + getRow()).append("\n"); @@ -97,81 +98,83 @@ public class Ref3DPtg extends Ptg { buffer.append("ColRel = " + isColRelative()).append("\n"); return buffer.toString(); } - + public void writeBytes(byte [] array, int offset) { array[ 0 + offset ] = sid; LittleEndian.putShort(array, 1 + offset , getExternSheetIndex()); LittleEndian.putShort(array, 3 + offset , getRow()); - LittleEndian.putShort(array, 5 + offset , getColumnRaw()); + LittleEndian.putShort(array, 5 + offset , getColumnRaw()); } - + public int getSize() { return SIZE; } - + public short getExternSheetIndex(){ return field_1_index_extern_sheet; } - + public void setExternSheetIndex(short index){ field_1_index_extern_sheet = index; } - + public short getRow() { return field_2_row; } - + public void setRow(short row) { field_2_row = row; } - + public short getColumn() { return ( short ) (field_3_column & 0xFF); } - + public short getColumnRaw() { return field_3_column; } - + public boolean isColRowRelative() { return (((getColumnRaw()) & 0x8000) == 0x8000); } - + public boolean isColRelative() { return (((getColumnRaw()) & 0x4000) == 0x4000); } - + public void setColumn(short column) { field_3_column &= 0xFF00; field_3_column |= column & 0xFF; } - + public void setColumnRaw(short column) { field_3_column = column; } - + public String getArea(){ RangeAddress ra = new RangeAddress(""); - + String result = (ra.numTo26Sys(getColumn()) + (getRow() + 1)); - + return result; } public void setArea(String ref){ RangeAddress ra = new RangeAddress(ref); - + String from = ra.getFromCell(); - + setColumn((short) (ra.getXPosition(from) -1)); setRow((short) (ra.getYPosition(from) -1)); - + } public String toFormulaString() { String result = getArea(); - + return result; } - + + public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} + } diff --git a/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java b/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java index 17b54dd06..201f9ea47 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java @@ -66,18 +66,15 @@ import org.apache.poi.util.BitField; import org.apache.poi.hssf.util.CellReference; /** - * ValueReferencePtg - handles references (such as A1, A2, IA4) - Should also - * be made to handle relative versus absolute references but I don't know enough - * about using them in excel to know if its correct. Seems inverted to me. - * FIXME = correct abs vs relative references + * ReferencePtg - handles references (such as A1, A2, IA4) * @author Andrew C. Oliver (acoliver@apache.org) */ public class ReferencePtg extends Ptg { private final static int SIZE = 5; - //public final static byte sid = 0x24; - public final static byte sid = 0x44; + public final static byte sid = 0x24; + //public final static byte sid = 0x44; private short field_1_row; private short field_2_col; private BitField rowRelative = new BitField(0x8000); @@ -120,7 +117,7 @@ public class ReferencePtg extends Ptg public void writeBytes(byte [] array, int offset) { - array[offset] = sid; + array[offset] = (byte) (sid + ptgClass); LittleEndian.putShort(array,offset+1,field_1_row); LittleEndian.putShort(array,offset+3,field_2_col); } @@ -183,4 +180,9 @@ public class ReferencePtg extends Ptg //TODO -- should we store a cellreference instance in this ptg?? but .. memory is an issue, i believe! return (new CellReference(getRow(),getColumn(),!isRowRelative(),!isColRelative())).toString(); } + + public byte getDefaultOperandClass() { + return Ptg.CLASS_REF; + } + } diff --git a/src/java/org/apache/poi/hssf/record/formula/StringPtg.java b/src/java/org/apache/poi/hssf/record/formula/StringPtg.java index 8e6555ef4..ba28f1883 100644 --- a/src/java/org/apache/poi/hssf/record/formula/StringPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/StringPtg.java @@ -69,29 +69,29 @@ public class StringPtg public final static byte sid = 0x17; private String field_1_value; - + /** Create a StringPtg from a byte array read from disk */ public StringPtg(byte [] data, int offset) { setValue(new String(data, offset+3, data[offset+1] + 256*data[offset+2])); } - + /** Create a StringPtg from a string representation of the number * Number format is not checked, it is expected to be validated in the parser - * that calls this method. + * that calls this method. * @param value : String representation of a floating point number */ protected StringPtg(String value) { setValue(value); } - - + + public void setValue(String value) { field_1_value = value; } - - + + public String getValue() { return field_1_value; @@ -114,6 +114,9 @@ public class StringPtg { return getValue(); } - + public byte getDefaultOperandClass() { + return Ptg.CLASS_VALUE; + } + } diff --git a/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java b/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java index b6d49a9e1..7bc89dda9 100644 --- a/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java @@ -95,4 +95,7 @@ public class UnknownPtg { return "UNKNOWN"; } + public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} + + } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java index e31a023c0..bd3784cc6 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java @@ -768,6 +768,8 @@ extends TestCase { c.setCellFormula("AVERAGE(A2:A3)"); c=r.createCell( (short) 4); c.setCellFormula("POWER(A2,A3)"); + c=r.createCell( (short) 5); + c.setCellFormula("SIN(A2)"); r = s.createRow((short) 1);c=r.createCell( (short) 0); c.setCellValue(2.0); r = s.createRow((short) 2);c=r.createCell( (short) 0); c.setCellValue(3.0);