diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/hssf/model/FormulaParser.java index 94cf9978a..82f54f0ac 100644 --- a/src/java/org/apache/poi/hssf/model/FormulaParser.java +++ b/src/java/org/apache/poi/hssf/model/FormulaParser.java @@ -931,6 +931,10 @@ end; private void setClass(Node n, byte theClass) { Ptg p = n.getValue(); + if (p.isBaseToken()) { + return; + } + if (p instanceof AbstractFunctionPtg || !(p instanceof OperationPtg)) { p.setClass(theClass); } else { @@ -988,11 +992,11 @@ end; // TODO - put comment and throw exception in toFormulaString() of these classes continue; } - if (! (ptg instanceof OperationPtg)) { - stack.push(ptg.toFormulaString(book)); + if (ptg instanceof ParenthesisPtg) { + String contents = (String)stack.pop(); + stack.push ("(" + contents + ")"); continue; } - if (ptg instanceof AttrPtg) { AttrPtg attrPtg = ((AttrPtg) ptg); if (attrPtg.isOptimizedIf() || attrPtg.isOptimizedChoose() || attrPtg.isGoto()) { @@ -1009,9 +1013,17 @@ end; // similar to tAttrSpace - RPN is violated continue; } - if (!attrPtg.isSum()) { - throw new RuntimeException("Unexpected tAttr: " + attrPtg.toString()); + if (attrPtg.isSum()) { + String[] operands = getOperands(stack, attrPtg.getNumberOfOperands()); + stack.push(attrPtg.toFormulaString(operands)); + continue; } + throw new RuntimeException("Unexpected tAttr: " + attrPtg.toString()); + } + + if (! (ptg instanceof OperationPtg)) { + stack.push(ptg.toFormulaString(book)); + continue; } OperationPtg o = (OperationPtg) ptg; diff --git a/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java b/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java index 48d7d4cc5..3c1293807 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java @@ -44,6 +44,10 @@ public abstract class AbstractFunctionPtg extends OperationPtg { protected byte field_1_num_args; protected short field_2_fnc_index; + public final boolean isBaseToken() { + return false; + } + public String toString() { StringBuffer sb = new StringBuffer(64); sb.append(getClass().getName()).append(" ["); 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 4f79d7602..c6acbaeb8 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AddPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AddPtg.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,11 +15,6 @@ limitations under the License. ==================================================================== */ -/* - * AddPtg.java - * - * Created on October 29, 2001, 7:48 PM - */ package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.usermodel.HSSFWorkbook; @@ -32,10 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Andrew C. Oliver (acoliver@apache.org) * @author Jason Height (jheight at chariot dot net dot au) */ - -public class AddPtg - extends OperationPtg -{ +public final class AddPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x03; @@ -89,8 +80,6 @@ public class AddPtg buffer.append(operands[ 1 ]); return buffer.toString(); } - - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} public Object clone() { return new AddPtg(); 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 f2b801f69..4ee0bef15 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java @@ -35,8 +35,7 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @version 1.0-pre */ -public class Area3DPtg extends Ptg implements AreaI -{ +public class Area3DPtg extends OperandPtg implements AreaI { public final static byte sid = 0x3b; private final static int SIZE = 11; // 10 + 1 for Ptg private short field_1_index_extern_sheet; 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 969ab5f75..29d5782e0 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java @@ -31,7 +31,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author andy * @author Jason Height (jheight at chariot dot net dot au) */ -public class AreaPtg extends Ptg implements AreaI { +public class AreaPtg extends OperandPtg implements AreaI { /** * TODO - (May-2008) fix subclasses of AreaPtg 'AreaN~' which are used in shared formulas. * see similar comment in ReferencePtg diff --git a/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java b/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java index 49c66e072..99495a5d2 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java @@ -47,7 +47,7 @@ public class ArrayPtg extends Ptg { protected Object[] token_3_arrayValues; protected ArrayPtg() { - //Required for clone methods + //Required for clone methods } public ArrayPtg(RecordInputStream in) @@ -59,6 +59,10 @@ public class ArrayPtg extends Ptg { } } + public boolean isBaseToken() { + return false; + } + /** * Read in the actual token (array) values. This occurs * AFTER the last Ptg in the expression. @@ -89,7 +93,7 @@ public class ArrayPtg extends Ptg { for (int x=0;x 0) { + for (int x=0;x 0) { b.append(";"); } - for (int y = 0; y < getRowCount(); y++) { + for (int y=0;y 0) { b.append(","); } - Object o = token_3_arrayValues[getValueIndex(x, y)]; - b.append(getConstantText(o)); - } - } + Object o = token_3_arrayValues[getValueIndex(x, y)]; + b.append(getConstantText(o)); + } + } b.append("}"); return b.toString(); } @@ -169,7 +174,6 @@ public class ArrayPtg extends Ptg { return "\"" + ((UnicodeString)o).getString() + "\""; } if (o instanceof Double) { - // TODO - numeric array elements need default Excel number formatting return ((Double)o).toString(); } if (o instanceof Boolean) { @@ -186,13 +190,13 @@ public class ArrayPtg extends Ptg { } public Object clone() { - ArrayPtg ptg = new ArrayPtg(); - ptg.field_1_reserved = (byte[]) field_1_reserved.clone(); - - ptg.token_1_columns = token_1_columns; - ptg.token_2_rows = token_2_rows; - ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone(); - ptg.setClass(ptgClass); - return ptg; + ArrayPtg ptg = new ArrayPtg(); + ptg.field_1_reserved = (byte[]) field_1_reserved.clone(); + + ptg.token_1_columns = token_1_columns; + ptg.token_2_rows = token_2_rows; + ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone(); + ptg.setClass(ptgClass); + return ptg; } } 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 4aee71fbd..0da20a99e 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java @@ -15,7 +15,6 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.usermodel.HSSFWorkbook; @@ -32,8 +31,7 @@ import org.apache.poi.util.BitFieldFactory; * @author andy * @author Jason Height (jheight at chariot dot net dot au) */ - -public final class AttrPtg extends OperationPtg { +public final class AttrPtg extends ControlPtg { public final static byte sid = 0x19; private final static int SIZE = 4; private byte field_1_options; @@ -289,12 +287,6 @@ public final class AttrPtg extends OperationPtg { } return "UNKNOWN ATTRIBUTE"; } - - - - public byte getDefaultOperandClass() { - return Ptg.CLASS_VALUE; - } public Object clone() { int[] jt; diff --git a/src/java/org/apache/poi/hssf/record/formula/BoolPtg.java b/src/java/org/apache/poi/hssf/record/formula/BoolPtg.java index 80c9f39d7..e3342a033 100644 --- a/src/java/org/apache/poi/hssf/record/formula/BoolPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/BoolPtg.java @@ -27,10 +27,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at chariot dot net dot au) */ - -public class BoolPtg - extends Ptg -{ +public final class BoolPtg extends ScalarConstantPtg { public final static int SIZE = 2; public final static byte sid = 0x1d; private boolean field_1_value; @@ -75,8 +72,6 @@ public class BoolPtg return field_1_value ? "TRUE" : "FALSE"; } - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} - public Object clone() { BoolPtg ptg = new BoolPtg(); ptg.field_1_value = field_1_value; diff --git a/src/java/org/apache/poi/hssf/record/formula/ConcatPtg.java b/src/java/org/apache/poi/hssf/record/formula/ConcatPtg.java index 951872f43..e77382a34 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ConcatPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ConcatPtg.java @@ -15,7 +15,6 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.usermodel.HSSFWorkbook; @@ -26,10 +25,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author andy * @author Jason Height (jheight at chariot dot net dot au) */ - -public class ConcatPtg - extends OperationPtg -{ +public final class ConcatPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x08; diff --git a/src/java/org/apache/poi/hssf/record/formula/ControlPtg.java b/src/java/org/apache/poi/hssf/record/formula/ControlPtg.java index 52c683619..90c196590 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ControlPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ControlPtg.java @@ -15,11 +15,25 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.formula; -public abstract class ControlPtg - extends Ptg -{ - +/** + * Common superclass for + * tExp + * tTbl + * tParen + * tNlr + * tAttr + * tSheet + * tEndSheet + */ +public abstract class ControlPtg extends Ptg { + + public boolean isBaseToken() { + return true; + } + public final byte getDefaultOperandClass() { +// TODO throw new IllegalStateException("Control tokens are not classified"); + return Ptg.CLASS_VALUE; + } } diff --git a/src/java/org/apache/poi/hssf/record/formula/DividePtg.java b/src/java/org/apache/poi/hssf/record/formula/DividePtg.java index 70fa62e58..60efad4f6 100644 --- a/src/java/org/apache/poi/hssf/record/formula/DividePtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/DividePtg.java @@ -15,7 +15,6 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.usermodel.HSSFWorkbook; @@ -26,10 +25,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Andrew C. Oliver acoliver at apache dot org * @author Jason Height (jheight at chariot dot net dot au) */ - -public class DividePtg - extends OperationPtg -{ +public final class DividePtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x06; diff --git a/src/java/org/apache/poi/hssf/record/formula/EqualPtg.java b/src/java/org/apache/poi/hssf/record/formula/EqualPtg.java index a08a863d1..b8023d845 100644 --- a/src/java/org/apache/poi/hssf/record/formula/EqualPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/EqualPtg.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -25,10 +24,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * * @author andy */ - -public class EqualPtg - extends OperationPtg -{ +public final class EqualPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x0b; diff --git a/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java b/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java index a16992f94..650ba054f 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ErrPtg.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,7 +15,6 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.usermodel.HSSFWorkbook; @@ -26,7 +24,7 @@ import org.apache.poi.hssf.usermodel.HSSFErrorConstants; /** * @author Daniel Noll (daniel at nuix dot com dot au) */ -public final class ErrPtg extends Ptg { +public final class ErrPtg extends ScalarConstantPtg { // convenient access to namespace private static final HSSFErrorConstants EC = null; @@ -78,10 +76,6 @@ public final class ErrPtg extends Ptg { return SIZE; } - public byte getDefaultOperandClass() { - return Ptg.CLASS_VALUE; - } - public Object clone() { return new ErrPtg(field_1_error_code); } 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 0cd54e5f5..c4a0c33fe 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java @@ -31,9 +31,7 @@ import org.apache.poi.util.LittleEndian; * @author dmui (save existing implementation) */ -public class ExpPtg - extends Ptg -{ +public final class ExpPtg extends ControlPtg { private final static int SIZE = 5; public final static short sid = 0x1; private short field_1_first_row; @@ -52,7 +50,7 @@ public class ExpPtg field_1_first_row = in.readShort(); field_2_first_col = in.readShort(); } - + public void writeBytes(byte [] array, int offset) { array[offset+0]= (byte) (sid); @@ -86,8 +84,6 @@ public class ExpPtg return buffer.toString(); } - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} - public Object clone() { ExpPtg result = new ExpPtg(); result.field_1_first_row = field_1_first_row; diff --git a/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java b/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java index 364ddf5a0..cea44ed43 100644 --- a/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java @@ -44,6 +44,8 @@ public final class FuncPtg extends AbstractFunctionPtg { throw new RuntimeException("Invalid built-in function index (" + field_2_fnc_index + ")"); } numParams = fm.getMinParams(); + returnClass = fm.getReturnClassCode(); + paramClass = fm.getParameterClassCodes(); } public FuncPtg(int functionIndex) { field_2_fnc_index = (short) functionIndex; diff --git a/src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java b/src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java index 431dc5717..e3d2e7731 100644 --- a/src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java @@ -40,6 +40,15 @@ public final class FuncVarPtg extends AbstractFunctionPtg{ public FuncVarPtg(RecordInputStream in) { field_1_num_args = in.readByte(); field_2_fnc_index = in.readShort(); + FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(field_2_fnc_index); + if(fm == null) { + // Happens only as a result of a call to FormulaParser.parse(), with a non-built-in function name + returnClass = Ptg.CLASS_VALUE; + paramClass = new byte[] {Ptg.CLASS_VALUE}; + } else { + returnClass = fm.getReturnClassCode(); + paramClass = fm.getParameterClassCodes(); + } } /** diff --git a/src/java/org/apache/poi/hssf/record/formula/GreaterEqualPtg.java b/src/java/org/apache/poi/hssf/record/formula/GreaterEqualPtg.java index 677d78c3e..652c454ec 100755 --- a/src/java/org/apache/poi/hssf/record/formula/GreaterEqualPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/GreaterEqualPtg.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,22 +15,17 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.record.RecordInputStream; - /** * PTG class to implement greater or equal to * * @author fred at stsci dot edu */ - -public class GreaterEqualPtg - extends OperationPtg -{ +public final class GreaterEqualPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x0c; diff --git a/src/java/org/apache/poi/hssf/record/formula/GreaterThanPtg.java b/src/java/org/apache/poi/hssf/record/formula/GreaterThanPtg.java index 6501203ed..44a1d0e8e 100644 --- a/src/java/org/apache/poi/hssf/record/formula/GreaterThanPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/GreaterThanPtg.java @@ -15,26 +15,16 @@ limitations under the License. ==================================================================== */ - -/* - * GreaterThanPtg.java - * - * Created on January 23, 2003, 9:47 AM - */ package org.apache.poi.hssf.record.formula; -import java.util.List; - -import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; /** * Greater than operator PTG ">" * @author Cameron Riley (criley at ekmail.com) */ -public class GreaterThanPtg - extends OperationPtg -{ +public final class GreaterThanPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x0D; private final static String GREATERTHAN = ">"; @@ -117,15 +107,6 @@ public class GreaterThanPtg return buffer.toString(); } - /** - * Get the default operands class value - * @return byte the Ptg Class Value as a byte from the Ptg Parent object - */ - public byte getDefaultOperandClass() - { - return Ptg.CLASS_VALUE; - } - /** * Implementation of clone method from Object * @return Object a clone of this class as an Object diff --git a/src/java/org/apache/poi/hssf/record/formula/IntPtg.java b/src/java/org/apache/poi/hssf/record/formula/IntPtg.java index f3dd16f06..89c806dd2 100644 --- a/src/java/org/apache/poi/hssf/record/formula/IntPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/IntPtg.java @@ -27,7 +27,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at chariot dot net dot au) */ -public final class IntPtg extends Ptg { +public final class IntPtg extends ScalarConstantPtg { // 16 bit unsigned integer private static final int MIN_VALUE = 0x0000; private static final int MAX_VALUE = 0xFFFF; @@ -75,9 +75,6 @@ public final class IntPtg extends Ptg { public String toFormulaString(HSSFWorkbook book) { return String.valueOf(getValue()); } - public byte getDefaultOperandClass() { - return Ptg.CLASS_VALUE; - } public Object clone() { return new IntPtg(field_1_value); diff --git a/src/java/org/apache/poi/hssf/record/formula/IntersectionPtg.java b/src/java/org/apache/poi/hssf/record/formula/IntersectionPtg.java index 8f5bddc19..27e7ec4f9 100644 --- a/src/java/org/apache/poi/hssf/record/formula/IntersectionPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/IntersectionPtg.java @@ -23,8 +23,7 @@ import org.apache.poi.hssf.record.RecordInputStream; /** * @author Daniel Noll (daniel at nuix dot com dot au) */ -public class IntersectionPtg extends OperationPtg -{ +public final class IntersectionPtg extends OperationPtg { public final static byte sid = 0x0f; @@ -37,6 +36,9 @@ public class IntersectionPtg extends OperationPtg // doesn't need anything } + public final boolean isBaseToken() { + return true; + } public int getSize() { diff --git a/src/java/org/apache/poi/hssf/record/formula/LessEqualPtg.java b/src/java/org/apache/poi/hssf/record/formula/LessEqualPtg.java index f42966394..fad0b90f5 100755 --- a/src/java/org/apache/poi/hssf/record/formula/LessEqualPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/LessEqualPtg.java @@ -16,7 +16,6 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.formula; @@ -29,9 +28,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * * @author fred at stsci dot edu */ -public class LessEqualPtg - extends OperationPtg -{ +public final class LessEqualPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x0a; diff --git a/src/java/org/apache/poi/hssf/record/formula/LessThanPtg.java b/src/java/org/apache/poi/hssf/record/formula/LessThanPtg.java index c23658d2d..d1c6c5581 100644 --- a/src/java/org/apache/poi/hssf/record/formula/LessThanPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/LessThanPtg.java @@ -15,18 +15,8 @@ limitations under the License. ==================================================================== */ - -/* - * LessThanPtg.java - * - * Created on January 23, 2003, 9:47 AM - */ package org.apache.poi.hssf.record.formula; -//JDK -import java.util.List; - -//POI import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.record.RecordInputStream; @@ -36,9 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * Table 3.5.7 * @author Cameron Riley (criley at ekmail.com) */ -public class LessThanPtg - extends OperationPtg -{ +public final class LessThanPtg extends ValueOperatorPtg { /** the size of the Ptg */ public final static int SIZE = 1; @@ -125,15 +113,6 @@ public class LessThanPtg return buffer.toString(); } - /** - * Get the default operands class value - * @return byte the Ptg Class Value as a byte from the Ptg Parent object - */ - public byte getDefaultOperandClass() - { - return Ptg.CLASS_VALUE; - } - /** * Implementation of clone method from Object * @return Object a clone of this class as an Object diff --git a/src/java/org/apache/poi/hssf/record/formula/MemAreaPtg.java b/src/java/org/apache/poi/hssf/record/formula/MemAreaPtg.java index ec33d1092..98e217289 100644 --- a/src/java/org/apache/poi/hssf/record/formula/MemAreaPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/MemAreaPtg.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,12 +15,6 @@ limitations under the License. ==================================================================== */ - -/* - * MemAreaPtg.java - * - * Created on November 21, 2001, 8:46 AM - */ package org.apache.poi.hssf.record.formula; import org.apache.poi.util.LittleEndian; @@ -31,9 +24,7 @@ import org.apache.poi.hssf.record.RecordInputStream; /** * @author Daniel Noll (daniel at nuix dot com dot au) */ -public class MemAreaPtg - extends Ptg -{ +public class MemAreaPtg extends OperandPtg { public final static short sid = 0x26; private final static int SIZE = 7; private int field_1_reserved; diff --git a/src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java b/src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java index 63c07a79e..020b90fc5 100644 --- a/src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java @@ -30,8 +30,7 @@ import org.apache.poi.hssf.record.RecordInputStream; /** * @author Glen Stampoultzis (glens at apache.org) */ -public class MemFuncPtg extends ControlPtg -{ +public class MemFuncPtg extends OperandPtg { public final static byte sid = 0x29; private short field_1_len_ref_subexpression = 0; diff --git a/src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java b/src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java index d539405cd..a08090c85 100644 --- a/src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java @@ -26,9 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * Avik Sengupta <avik at apache.org> * @author Jason Height (jheight at chariot dot net dot au) */ -public class MissingArgPtg - extends Ptg -{ +public final class MissingArgPtg extends ScalarConstantPtg { private final static int SIZE = 1; public final static byte sid = 0x16; @@ -59,8 +57,6 @@ public class MissingArgPtg { return " "; } - - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} public Object clone() { return new MissingArgPtg(); diff --git a/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java b/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java index cbc0b6700..1960dc907 100644 --- a/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java @@ -25,9 +25,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Jason Height (jheight at chariot dot net dot au) */ -public class MultiplyPtg - extends OperationPtg -{ +public final class MultiplyPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x05; diff --git a/src/java/org/apache/poi/hssf/record/formula/NamePtg.java b/src/java/org/apache/poi/hssf/record/formula/NamePtg.java index 9d93f1e98..f3bfd8ba2 100644 --- a/src/java/org/apache/poi/hssf/record/formula/NamePtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/NamePtg.java @@ -28,10 +28,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author andy * @author Jason Height (jheight at chariot dot net dot au) */ - -public class NamePtg - extends Ptg -{ +public final class NamePtg extends OperandPtg { public final static short sid = 0x23; private final static int SIZE = 5; /** one-based index to defined name record */ diff --git a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java index 3036800b1..2c95ba3af 100644 --- a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java @@ -25,7 +25,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * * @author aviks */ -public final class NameXPtg extends Ptg { +public final class NameXPtg extends OperandPtg { public final static short sid = 0x39; private final static int SIZE = 7; private short field_1_ixals; // index to REF entry in externsheet record diff --git a/src/java/org/apache/poi/hssf/record/formula/NotEqualPtg.java b/src/java/org/apache/poi/hssf/record/formula/NotEqualPtg.java index 5dbbec875..273edc01d 100755 --- a/src/java/org/apache/poi/hssf/record/formula/NotEqualPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/NotEqualPtg.java @@ -26,9 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * * @author fred at stsci dot edu */ -public class NotEqualPtg - extends OperationPtg -{ +public final class NotEqualPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x0e; diff --git a/src/java/org/apache/poi/hssf/record/formula/NumberPtg.java b/src/java/org/apache/poi/hssf/record/formula/NumberPtg.java index 8ec67345b..f5e4305cc 100644 --- a/src/java/org/apache/poi/hssf/record/formula/NumberPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/NumberPtg.java @@ -28,10 +28,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Avik Sengupta * @author Jason Height (jheight at chariot dot net dot au) */ - -public class NumberPtg - extends Ptg -{ +public final class NumberPtg extends ScalarConstantPtg { public final static int SIZE = 9; public final static byte sid = 0x1f; private double field_1_value; @@ -82,7 +79,6 @@ public class NumberPtg { return "" + getValue(); } - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} public Object clone() { NumberPtg ptg = new NumberPtg(); diff --git a/src/java/org/apache/poi/hssf/record/formula/OperandPtg.java b/src/java/org/apache/poi/hssf/record/formula/OperandPtg.java new file mode 100644 index 000000000..02a708f64 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/OperandPtg.java @@ -0,0 +1,31 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.formula; + +/** + * @author Josh Micich + */ +public abstract class OperandPtg extends Ptg { + + /** + * All Operand Ptgs are classifed ('relative', 'value', 'array') + */ + public final boolean isBaseToken() { + return false; + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java b/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java index 402dbd377..4cd5b5727 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java @@ -32,9 +32,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at chariot dot net dot au) */ -public class ParenthesisPtg - extends OperationPtg -{ +public final class ParenthesisPtg extends ControlPtg { private final static int SIZE = 1; public final static byte sid = 0x15; @@ -61,16 +59,6 @@ public class ParenthesisPtg return SIZE; } - public int getType() - { - return TYPE_BINARY; - } - - public int getNumberOfOperands() - { - return 1; - } - public String toFormulaString(HSSFWorkbook book) { return "()"; @@ -80,8 +68,6 @@ public class ParenthesisPtg public String toFormulaString(String[] operands) { return "("+operands[0]+")"; } - - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} public Object clone() { return new ParenthesisPtg(); diff --git a/src/java/org/apache/poi/hssf/record/formula/PercentPtg.java b/src/java/org/apache/poi/hssf/record/formula/PercentPtg.java index 0c59bb7ac..aa1e87765 100644 --- a/src/java/org/apache/poi/hssf/record/formula/PercentPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/PercentPtg.java @@ -32,9 +32,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Daniel Noll (daniel at nuix.com.au) */ -public class PercentPtg - extends OperationPtg -{ +public final class PercentPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x14; @@ -88,8 +86,6 @@ public class PercentPtg return buffer.toString(); } - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} - public Object clone() { return new PercentPtg(); } diff --git a/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java b/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java index 0dbb3ba28..8d849fba2 100644 --- a/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java @@ -17,8 +17,6 @@ package org.apache.poi.hssf.record.formula; -import java.util.List; - import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.record.RecordInputStream; @@ -27,10 +25,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author andy * @author Jason Height (jheight at chariot dot net dot au) */ - -public class PowerPtg - extends OperationPtg -{ +public final class PowerPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x07; diff --git a/src/java/org/apache/poi/hssf/record/formula/Ptg.java b/src/java/org/apache/poi/hssf/record/formula/Ptg.java index fe8702c4a..28d5d13b4 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ptg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ptg.java @@ -119,254 +119,14 @@ public abstract class Ptg return stack; } - public static Ptg createPtg(RecordInputStream in) - { - byte id = in.readByte(); - Ptg retval = null; - - switch (id) - { - case ExpPtg.sid : // 0x01 - retval = new ExpPtg(in); - break; - - case AddPtg.sid : // 0x03 - retval = new AddPtg(in); - break; - - case SubtractPtg.sid : // 0x04 - retval = new SubtractPtg(in); - break; - - case MultiplyPtg.sid : // 0x05 - retval = new MultiplyPtg(in); - break; - - case DividePtg.sid : // 0x06 - retval = new DividePtg(in); - break; - - case PowerPtg.sid : // 0x07 - retval = new PowerPtg(in); - break; - - case ConcatPtg.sid : // 0x08 - retval = new ConcatPtg(in); - break; - - case LessThanPtg.sid: // 0x09 - retval = new LessThanPtg(in); - break; - - case LessEqualPtg.sid : // 0x0a - retval = new LessEqualPtg(in); - break; - - case EqualPtg.sid : // 0x0b - retval = new EqualPtg(in); - break; - - case GreaterEqualPtg.sid : // 0x0c - retval = new GreaterEqualPtg(in); - break; - - case GreaterThanPtg.sid : // 0x0d - retval = new GreaterThanPtg(in); - break; - - case NotEqualPtg.sid : // 0x0e - retval = new NotEqualPtg(in); - break; - - case IntersectionPtg.sid : // 0x0f - retval = new IntersectionPtg(in); - break; - case UnionPtg.sid : // 0x10 - retval = new UnionPtg(in); - break; - - case RangePtg.sid : // 0x11 - retval = new RangePtg(in); - break; - - case UnaryPlusPtg.sid : // 0x12 - retval = new UnaryPlusPtg(in); - break; - - case UnaryMinusPtg.sid : // 0x13 - retval = new UnaryMinusPtg(in); - break; - - case PercentPtg.sid : // 0x14 - retval = new PercentPtg(in); - break; - - case ParenthesisPtg.sid : // 0x15 - retval = new ParenthesisPtg(in); - break; - - case MissingArgPtg.sid : // 0x16 - retval = new MissingArgPtg(in); - break; - - case StringPtg.sid : // 0x17 - retval = new StringPtg(in); - break; - - case AttrPtg.sid : // 0x19 - case 0x1a : - retval = new AttrPtg(in); - break; - - case ErrPtg.sid : // 0x1c - retval = new ErrPtg(in); - break; - - case BoolPtg.sid : // 0x1d - retval = new BoolPtg(in); - break; - - case IntPtg.sid : // 0x1e - retval = new IntPtg(in); - break; - - case NumberPtg.sid : // 0x1f - retval = new NumberPtg(in); - break; - - case ArrayPtg.sid : // 0x20 - retval = new ArrayPtg(in); - break; - case ArrayPtgV.sid : // 0x40 - retval = new ArrayPtgV(in); - break; - case ArrayPtgA.sid : // 0x60 - retval = new ArrayPtgA(in); - break; - - case FuncPtg.sid : // 0x21 - case FuncPtg.sid + 0x20 : // 0x41 - case FuncPtg.sid + 0x40 : // 0x61 - retval = new FuncPtg(in); - break; - - case FuncVarPtg.sid : // 0x22 - case FuncVarPtg.sid + 0x20 : // 0x42 - case FuncVarPtg.sid + 0x40 : // 0x62 - retval = new FuncVarPtg(in); - break; - - case ReferencePtg.sid : // 0x24 - retval = new ReferencePtg(in); - break; - case RefAPtg.sid : // 0x64 - retval = new RefAPtg(in); - break; - case RefVPtg.sid : // 0x44 - retval = new RefVPtg(in); - break; - case RefNAPtg.sid : // 0x6C - retval = new RefNAPtg(in); - break; - case RefNPtg.sid : // 0x2C - retval = new RefNPtg(in); - break; - case RefNVPtg.sid : // 0x4C - retval = new RefNVPtg(in); - break; - - case AreaPtg.sid : // 0x25 - retval = new AreaPtg(in); - break; - case AreaVPtg.sid: // 0x45 - retval = new AreaVPtg(in); - break; - case AreaAPtg.sid: // 0x65 - retval = new AreaAPtg(in); - break; - case AreaNAPtg.sid : // 0x6D - retval = new AreaNAPtg(in); - break; - case AreaNPtg.sid : // 0x2D - retval = new AreaNPtg(in); - break; - case AreaNVPtg.sid : // 0x4D - retval = new AreaNVPtg(in); - break; - - case MemAreaPtg.sid : // 0x26 - case MemAreaPtg.sid + 0x40 : // 0x46 - case MemAreaPtg.sid + 0x20 : // 0x66 - retval = new MemAreaPtg(in); - break; - - case MemErrPtg.sid : // 0x27 - case MemErrPtg.sid + 0x20 : // 0x47 - case MemErrPtg.sid + 0x40 : // 0x67 - retval = new MemErrPtg(in); - break; - - case MemFuncPtg.sid : // 0x29 - retval = new MemFuncPtg(in); - break; - - case RefErrorPtg.sid : // 0x2a - case RefErrorPtg.sid + 0x20 : // 0x4a - case RefErrorPtg.sid + 0x40 : // 0x6a - retval = new RefErrorPtg(in); - break; - - case AreaErrPtg.sid : // 0x2b - case AreaErrPtg.sid + 0x20 : // 0x4b - case AreaErrPtg.sid + 0x40 : // 0x6b - retval = new AreaErrPtg(in); - break; - - case NamePtg.sid : // 0x23 - case NamePtg.sid + 0x20 : // 0x43 - case NamePtg.sid + 0x40 : // 0x63 - retval = new NamePtg(in); - break; - - case NameXPtg.sid : // 0x39 - case NameXPtg.sid + 0x20 : // 0x45 - case NameXPtg.sid + 0x40 : // 0x79 - retval = new NameXPtg(in); - break; - - case Area3DPtg.sid : // 0x3b - case Area3DPtg.sid + 0x20 : // 0x5b - case Area3DPtg.sid + 0x40 : // 0x7b - retval = new Area3DPtg(in); - break; - - case Ref3DPtg.sid : // 0x3a - case Ref3DPtg.sid + 0x20: // 0x5a - case Ref3DPtg.sid + 0x40: // 0x7a - retval = new Ref3DPtg(in); - break; - - case DeletedRef3DPtg.sid: // 0x3c - case DeletedRef3DPtg.sid + 0x20: // 0x5c - case DeletedRef3DPtg.sid + 0x40: // 0x7c - retval = new DeletedRef3DPtg(in); - break; - - case DeletedArea3DPtg.sid : // 0x3d - case DeletedArea3DPtg.sid + 0x20 : // 0x5d - case DeletedArea3DPtg.sid + 0x40 : // 0x7d - retval = new DeletedArea3DPtg(in); - break; - - case 0x00: - retval = new UnknownPtg(); - break; - - default : - //retval = new UnknownPtg(); - throw new java.lang.UnsupportedOperationException(" Unknown Ptg in Formula: 0x"+ - Integer.toHexString(( int ) id) + " (" + ( int ) id + ")"); + public static Ptg createPtg(RecordInputStream in) { + byte id = in.readByte(); + + if (id < 0x20) { + return createBasePtg(id, in); } + + Ptg retval = createClassifiedPtg(id, in); if (id > 0x60) { retval.setClass(CLASS_ARRAY); @@ -380,6 +140,118 @@ public abstract class Ptg } + private static Ptg createClassifiedPtg(byte id, RecordInputStream in) { + + int baseId = id & 0x1F | 0x20; + + switch (baseId) { + case FuncPtg.sid: return new FuncPtg(in); // 0x21, 0x41, 0x61 + case FuncVarPtg.sid: return new FuncVarPtg(in); // 0x22, 0x42, 0x62 + case NamePtg.sid: return new NamePtg(in); // 0x23, 0x43, 0x63 + + case MemAreaPtg.sid: return new MemAreaPtg(in); // 0x26, 0x46, 0x66 + case MemErrPtg.sid: return new MemErrPtg(in); // 0x27, 0x47, 0x67 + case MemFuncPtg.sid: return new MemFuncPtg(in); // 0x29, 0x49, 0x69 + case RefErrorPtg.sid: return new RefErrorPtg(in);// 0x2a, 0x4a, 0x6a + case AreaErrPtg.sid: return new AreaErrPtg(in); // 0x2b, 0x4b, 0x6b + + case NameXPtg.sid: return new NameXPtg(in); // 0x39, 0x49, 0x79 + case Ref3DPtg.sid: return new Ref3DPtg(in); // 0x3a, 0x5a, 0x7a + case Area3DPtg.sid: return new Area3DPtg(in); // 0x3b, 0x5b, 0x7b + case DeletedRef3DPtg.sid: return new DeletedRef3DPtg(in); // 0x3c, 0x5c, 0x7c + case DeletedArea3DPtg.sid: return new DeletedArea3DPtg(in); // 0x3d, 0x5d, 0x7d + } + + + switch (id) { + // TODO - why are specific subclasses needed for these Ptgs? + case ArrayPtg.sid: return new ArrayPtg(in); // 0x20 + case ArrayPtgV.sid: return new ArrayPtgV(in); // 0x40 + case ArrayPtgA.sid: return new ArrayPtgA(in); // 0x60 + + case ReferencePtg.sid: return new ReferencePtg(in);// 0x24 + case RefAPtg.sid: return new RefAPtg(in); // 0x64 + case RefVPtg.sid: return new RefVPtg(in); // 0x44 + + case RefNAPtg.sid: return new RefNAPtg(in); // 0x6C + case RefNPtg.sid: return new RefNPtg(in); // 0x2C + case RefNVPtg.sid: return new RefNVPtg(in); // 0x4C + + case AreaPtg.sid: return new AreaPtg(in); // 0x25 + case AreaVPtg.sid: return new AreaVPtg(in); // 0x45 + case AreaAPtg.sid: return new AreaAPtg(in); // 0x65 + + case AreaNAPtg.sid: return new AreaNAPtg(in); // 0x6D + case AreaNPtg.sid: return new AreaNPtg(in); // 0x2D + case AreaNVPtg.sid: return new AreaNVPtg(in); // 0x4D + + } + throw new UnsupportedOperationException(" Unknown Ptg in Formula: 0x"+ + Integer.toHexString(id) + " (" + ( int ) id + ")"); + } + + private static Ptg createBasePtg(byte id, RecordInputStream in) { + switch(id) { + case 0x00: return new UnknownPtg(); // TODO - not a real Ptg + case ExpPtg.sid: return new ExpPtg(in); // 0x01 + case AddPtg.sid: return new AddPtg(in); // 0x03 + case SubtractPtg.sid: return new SubtractPtg(in); // 0x04 + case MultiplyPtg.sid: return new MultiplyPtg(in); // 0x05 + case DividePtg.sid: return new DividePtg(in); // 0x06 + case PowerPtg.sid: return new PowerPtg(in); // 0x07 + case ConcatPtg.sid: return new ConcatPtg(in); // 0x08 + case LessThanPtg.sid: return new LessThanPtg(in); // 0x09 + case LessEqualPtg.sid: return new LessEqualPtg(in); // 0x0a + case EqualPtg.sid: return new EqualPtg(in); // 0x0b + case GreaterEqualPtg.sid: return new GreaterEqualPtg(in);// 0x0c + case GreaterThanPtg.sid: return new GreaterThanPtg(in); // 0x0d + case NotEqualPtg.sid: return new NotEqualPtg(in); // 0x0e + case IntersectionPtg.sid: return new IntersectionPtg(in);// 0x0f + case UnionPtg.sid: return new UnionPtg(in); // 0x10 + case RangePtg.sid: return new RangePtg(in); // 0x11 + case UnaryPlusPtg.sid: return new UnaryPlusPtg(in); // 0x12 + case UnaryMinusPtg.sid: return new UnaryMinusPtg(in); // 0x13 + case PercentPtg.sid: return new PercentPtg(in); // 0x14 + case ParenthesisPtg.sid: return new ParenthesisPtg(in); // 0x15 + case MissingArgPtg.sid: return new MissingArgPtg(in); // 0x16 + case StringPtg.sid: return new StringPtg(in); // 0x17 + case AttrPtg.sid: + case 0x1a: return new AttrPtg(in); // 0x19 + case ErrPtg.sid: return new ErrPtg(in); // 0x1c + case BoolPtg.sid: return new BoolPtg(in); // 0x1d + case IntPtg.sid: return new IntPtg(in); // 0x1e + case NumberPtg.sid: return new NumberPtg(in); // 0x1f + } + throw new RuntimeException("Unexpected base token id (" + id + ")"); + } + /** + * + * + */ + public static int getEncodedSize(Stack ptgs) { + return getEncodedSize(toPtgArray(ptgs)); + } + private static Ptg[] toPtgArray(List l) { + Ptg[] result = new Ptg[l.size()]; + l.toArray(result); + return result; + } + private static Stack createStack(Ptg[] formulaTokens) { + Stack result = new Stack(); + for (int i = 0; i < formulaTokens.length; i++) { + result.add(formulaTokens[i]); + } + return result; + } + // TODO - several duplicates of this code should be refactored here + public static int getEncodedSize(Ptg[] ptgs) { + int result = 0; + for (int i = 0; i < ptgs.length; i++) { + result += ptgs[i].getSize(); + } + return result; + } + public static int serializePtgStack(Stack expression, byte[] array, int offset) { int pos = 0; int size = 0; @@ -408,7 +280,15 @@ public abstract class Ptg return pos; } + /** + * @return the encoded length of this Ptg, including the initial Ptg type identifier byte. + */ public abstract int getSize(); + + /** + * @return the encoded length of this Ptg, not including the initial Ptg type identifier byte. + */ +// public abstract int getDataSize(); public final byte [] getBytes() { @@ -455,6 +335,9 @@ public abstract class Ptg protected byte ptgClass = CLASS_REF; //base ptg public void setClass(byte thePtgClass) { + if (isBaseToken()) { + throw new RuntimeException("setClass should not be called on a base token"); + } ptgClass = thePtgClass; } @@ -468,5 +351,8 @@ public abstract class Ptg public abstract Object clone(); - + /** + * @return false if this token is classified as 'reference', 'value', or 'array' + */ + public abstract boolean isBaseToken(); } diff --git a/src/java/org/apache/poi/hssf/record/formula/RangePtg.java b/src/java/org/apache/poi/hssf/record/formula/RangePtg.java index 4726a70c1..37ae53716 100644 --- a/src/java/org/apache/poi/hssf/record/formula/RangePtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/RangePtg.java @@ -23,8 +23,7 @@ import org.apache.poi.hssf.record.RecordInputStream; /** * @author Daniel Noll (daniel at nuix dot com dot au) */ -public class RangePtg extends OperationPtg -{ +public final class RangePtg extends OperationPtg { public final static int SIZE = 1; public final static byte sid = 0x11; @@ -37,6 +36,10 @@ public class RangePtg extends OperationPtg // No contents } + public final boolean isBaseToken() { + return true; + } + public int getSize() { 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 3b4749c85..1731f658e 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java @@ -35,8 +35,7 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @version 1.0-pre */ - -public class Ref3DPtg extends Ptg { +public class Ref3DPtg extends OperandPtg { public final static byte sid = 0x3a; private final static int SIZE = 7; // 6 + 1 for Ptg private short field_1_index_extern_sheet; diff --git a/src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java b/src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java index c29b55bf9..309744d78 100755 --- a/src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java @@ -28,9 +28,8 @@ import org.apache.poi.hssf.record.RecordInputStream; * RefError - handles deleted cell reference * @author Jason Height (jheight at chariot dot net dot au) */ +public final class RefErrorPtg extends OperandPtg { -public class RefErrorPtg extends Ptg -{ private final static int SIZE = 5; public final static byte sid = 0x2a; private int field_1_reserved; 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 5fc7eaf8a..1af278a9b 100644 --- a/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java @@ -30,14 +30,14 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Andrew C. Oliver (acoliver@apache.org) * @author Jason Height (jheight at chariot dot net dot au) */ -public class ReferencePtg extends Ptg { +public class ReferencePtg extends OperandPtg { /** * TODO - (May-2008) fix subclasses of ReferencePtg 'RefN~' which are used in shared formulas. * (See bugzilla 44921) - * The 'RefN~' instances do not work properly, and are expected to be converted by - * SharedFormulaRecord.convertSharedFormulas(). - * This conversion currently does not take place for formulas of named ranges, conditional - * format rules and data validation rules. + * The 'RefN~' instances do not work properly, and are expected to be converted by + * SharedFormulaRecord.convertSharedFormulas(). + * This conversion currently does not take place for formulas of named ranges, conditional + * format rules and data validation rules. * Furthermore, conversion is probably not appropriate in those instances. */ protected final RuntimeException notImplemented() { @@ -46,14 +46,14 @@ public class ReferencePtg extends Ptg { private final static int SIZE = 5; public final static byte sid = 0x24; - private final static int MAX_ROW_NUMBER = 65536; + private final static int MAX_ROW_NUMBER = 65536; /** The row index - zero based unsigned 16 bit value */ private int field_1_row; - /** Field 2 - * - lower 8 bits is the zero based unsigned byte column index + /** Field 2 + * - lower 8 bits is the zero based unsigned byte column index * - bit 16 - isRowRelative - * - bit 15 - isColumnRelative + * - bit 15 - isColumnRelative */ private int field_2_col; private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000); @@ -63,9 +63,9 @@ public class ReferencePtg extends Ptg { protected ReferencePtg() { //Required for clone methods } - + /** - * Takes in a String represnetation of a cell reference and fills out the + * Takes in a String represnetation of a cell reference and fills out the * numeric fields. */ public ReferencePtg(String cellref) { @@ -75,13 +75,13 @@ public class ReferencePtg extends Ptg { setColRelative(!c.isColAbsolute()); setRowRelative(!c.isRowAbsolute()); } - + public ReferencePtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) { setRow(row); setColumn(column); setRowRelative(isRowRelative); setColRelative(isColumnRelative); - } + } /** Creates new ValueReferencePtg */ @@ -90,22 +90,19 @@ public class ReferencePtg extends Ptg { field_1_row = in.readUShort(); field_2_col = in.readUShort(); } - + public String getRefPtgName() { return "ReferencePtg"; - } + } - public String toString() - { - StringBuffer buffer = new StringBuffer("["); - buffer.append(getRefPtgName()); - buffer.append("]\n"); - - buffer.append("row = ").append(getRow()).append("\n"); - buffer.append("col = ").append(getColumn()).append("\n"); - buffer.append("rowrelative = ").append(isRowRelative()).append("\n"); - buffer.append("colrelative = ").append(isColRelative()).append("\n"); - return buffer.toString(); + public String toString() { + CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(),!isColRelative()); + StringBuffer sb = new StringBuffer(); + sb.append(getClass().getName()); + sb.append(" ["); + sb.append(cr.formatAsString()); + sb.append("]"); + return sb.toString(); } public void writeBytes(byte [] array, int offset) @@ -147,16 +144,16 @@ public class ReferencePtg extends Ptg { { return rowRelative.isSet(field_2_col); } - + public void setRowRelative(boolean rel) { field_2_col=rowRelative.setBoolean(field_2_col,rel); } - + public boolean isColRelative() { return colRelative.isSet(field_2_col); } - + public void setColRelative(boolean rel) { field_2_col=colRelative.setBoolean(field_2_col,rel); } @@ -193,11 +190,11 @@ 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(getRowAsInt(),getColumn(),!isRowRelative(),!isColRelative())).formatAsString(); } - + public byte getDefaultOperandClass() { return Ptg.CLASS_REF; } - + public Object clone() { ReferencePtg ptg = new ReferencePtg(); ptg.field_1_row = field_1_row; diff --git a/src/java/org/apache/poi/hssf/record/formula/ScalarConstantPtg.java b/src/java/org/apache/poi/hssf/record/formula/ScalarConstantPtg.java new file mode 100644 index 000000000..43b8c1392 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/ScalarConstantPtg.java @@ -0,0 +1,31 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.formula; + +/** + * @author Josh Micich + */ +abstract class ScalarConstantPtg extends Ptg { + public boolean isBaseToken() { + return true; + } + public final byte getDefaultOperandClass() { + return Ptg.CLASS_VALUE; + } + +} 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 47bd6ab6e..14ed38203 100644 --- a/src/java/org/apache/poi/hssf/record/formula/StringPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/StringPtg.java @@ -31,7 +31,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Jason Height (jheight at chariot dot net dot au) * @author Bernard Chesnoy */ -public final class StringPtg extends Ptg { +public final class StringPtg extends ScalarConstantPtg { public final static int SIZE = 9; public final static byte sid = 0x17; private static final BitField fHighByte = BitFieldFactory.getInstance(0x01); @@ -124,10 +124,6 @@ public final class StringPtg extends Ptg { return sb.toString(); } - public byte getDefaultOperandClass() { - return Ptg.CLASS_VALUE; - } - public Object clone() { StringPtg ptg = new StringPtg(); ptg.field_1_length = field_1_length; diff --git a/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java b/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java index 37af74ba9..3d04a9f45 100644 --- a/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java @@ -26,10 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author andy * @author Jason Height (jheight at chariot dot net dot au) */ - -public class SubtractPtg - extends OperationPtg -{ +public final class SubtractPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x04; diff --git a/src/java/org/apache/poi/hssf/record/formula/UnaryMinusPtg.java b/src/java/org/apache/poi/hssf/record/formula/UnaryMinusPtg.java index 7c134b97d..51cb7018d 100644 --- a/src/java/org/apache/poi/hssf/record/formula/UnaryMinusPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/UnaryMinusPtg.java @@ -28,8 +28,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Avik Sengupta */ -public class UnaryMinusPtg extends OperationPtg -{ +public final class UnaryMinusPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x13; @@ -82,8 +81,6 @@ public class UnaryMinusPtg extends OperationPtg return buffer.toString(); } - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} - public Object clone() { return new UnaryPlusPtg(); } diff --git a/src/java/org/apache/poi/hssf/record/formula/UnaryPlusPtg.java b/src/java/org/apache/poi/hssf/record/formula/UnaryPlusPtg.java index 148c83fa4..70cdbf2ca 100644 --- a/src/java/org/apache/poi/hssf/record/formula/UnaryPlusPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/UnaryPlusPtg.java @@ -28,8 +28,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Avik Sengupta */ -public class UnaryPlusPtg extends OperationPtg -{ +public final class UnaryPlusPtg extends ValueOperatorPtg { public final static int SIZE = 1; public final static byte sid = 0x12; @@ -82,8 +81,6 @@ public class UnaryPlusPtg extends OperationPtg return buffer.toString(); } - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} - public Object clone() { return new UnaryPlusPtg(); } diff --git a/src/java/org/apache/poi/hssf/record/formula/UnionPtg.java b/src/java/org/apache/poi/hssf/record/formula/UnionPtg.java index 8d00ec34d..c1fe011b5 100644 --- a/src/java/org/apache/poi/hssf/record/formula/UnionPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/UnionPtg.java @@ -23,8 +23,7 @@ import org.apache.poi.hssf.record.RecordInputStream; /** * @author Glen Stampoultzis (glens at apache.org) */ -public class UnionPtg extends OperationPtg -{ +public final class UnionPtg extends OperationPtg { public final static byte sid = 0x10; @@ -37,6 +36,9 @@ public class UnionPtg extends OperationPtg // doesn't need anything } + public final boolean isBaseToken() { + return true; + } public int getSize() { 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 56493d906..c68671590 100644 --- a/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java @@ -24,10 +24,7 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author andy * @author Jason Height (jheight at chariot dot net dot au) */ - -public class UnknownPtg - extends Ptg -{ +public class UnknownPtg extends Ptg { private short size = 1; /** Creates new UnknownPtg */ @@ -36,12 +33,13 @@ public class UnknownPtg { } - public UnknownPtg(RecordInputStream in) - { - + public UnknownPtg(RecordInputStream in) { // doesn't need anything } + public boolean isBaseToken() { + return true; + } public void writeBytes(byte [] array, int offset) { } diff --git a/src/java/org/apache/poi/hssf/record/formula/ValueOperatorPtg.java b/src/java/org/apache/poi/hssf/record/formula/ValueOperatorPtg.java new file mode 100644 index 000000000..4ef6ab595 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/ValueOperatorPtg.java @@ -0,0 +1,37 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.formula; + +/** + * Common superclass of all value operators. + * Subclasses include all unary and binary operators except for the reference operators (IntersectionPtg, RangePtg, UnionPtg) + * + * @author Josh Micich + */ +public abstract class ValueOperatorPtg extends OperationPtg { + + /** + * All Operator Ptgs are base tokens (i.e. are not RVA classifed) + */ + public final boolean isBaseToken() { + return true; + } + public final byte getDefaultOperandClass() { + return Ptg.CLASS_VALUE; + } +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java index cf4f83b31..e23a58c59 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java @@ -342,28 +342,28 @@ public class HSSFFormulaEvaluator { } private static ValueEval evaluateCell(HSSFWorkbook workbook, HSSFSheet sheet, int srcRowNum, short srcColNum, String cellFormulaText) { - FormulaParser parser = new FormulaParser(cellFormulaText, workbook); - parser.parse(); - Ptg[] ptgs = parser.getRPNPtg(); - // -- parsing over -- - + + Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook); Stack stack = new Stack(); for (int i = 0, iSize = ptgs.length; i < iSize; i++) { // since we don't know how to handle these yet :( Ptg ptg = ptgs[i]; - if (ptg instanceof ControlPtg) { continue; } + if (ptg instanceof ControlPtg) { + // skip Parentheses, Attr, etc + continue; + } if (ptg instanceof MemErrPtg) { continue; } if (ptg instanceof MissingArgPtg) { continue; } if (ptg instanceof NamePtg) { - // named ranges, macro functions + // named ranges, macro functions NamePtg namePtg = (NamePtg) ptg; stack.push(new NameEval(namePtg.getIndex())); continue; } if (ptg instanceof NameXPtg) { - // TODO - external functions + // TODO - external functions continue; } if (ptg instanceof UnknownPtg) { continue; } @@ -371,9 +371,6 @@ public class HSSFFormulaEvaluator { if (ptg instanceof OperationPtg) { OperationPtg optg = (OperationPtg) ptg; - // parens can be ignored since we have RPN tokens - if (optg instanceof ParenthesisPtg) { continue; } - if (optg instanceof AttrPtg) { continue; } if (optg instanceof UnionPtg) { continue; } OperationEval operation = OperationEvaluatorFactory.create(optg);