git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352651 13f79535-47bb-0310-9956-ffa450edef68tags/REL_1_10
@@ -124,5 +124,7 @@ public class AddPtg | |||
buffer.append(operands[ 1 ]); | |||
return buffer.toString(); | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -211,5 +211,5 @@ public class AttrPtg | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} |
@@ -96,4 +96,7 @@ public class ExpPtg | |||
{ | |||
return "NO IDEA SHARED FORMULA EXP PTG"; | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} |
@@ -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<n.getNumChildren();i++) { | |||
setParameterRVA(n.getChild(i),((FunctionPtg)p).getParameterClass(i),formulaType); | |||
if (n.getChild(i).getValue() instanceof FunctionPtg) { | |||
setParameterRVA(n.getChild(i),formulaType); | |||
} | |||
} | |||
} else { | |||
for (int i =0;i<n.getNumChildren();i++) { | |||
setParameterRVA(n.getChild(i),formulaType); | |||
} | |||
} | |||
} | |||
private void setParameterRVA(Node n, int expectedClass,int formulaType) { | |||
Ptg p = (Ptg) n.getValue(); | |||
if (expectedClass == Ptg.CLASS_REF) { //pg 15, table 1 | |||
if (p.getDefaultOperandClass() == Ptg.CLASS_REF ) { | |||
setClass(n, Ptg.CLASS_REF); | |||
} | |||
if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE) { | |||
if (formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED) { | |||
setClass(n,Ptg.CLASS_VALUE); | |||
} else { | |||
setClass(n,Ptg.CLASS_ARRAY); | |||
} | |||
} | |||
if (p.getDefaultOperandClass() == Ptg.CLASS_ARRAY ) { | |||
setClass(n, Ptg.CLASS_ARRAY); | |||
} | |||
} else if (expectedClass == Ptg.CLASS_VALUE) { //pg 15, table 2 | |||
if (formulaType == FORMULA_TYPE_NAMEDRANGE) { | |||
setClass(n,Ptg.CLASS_ARRAY) ; | |||
} else { | |||
setClass(n,Ptg.CLASS_VALUE); | |||
} | |||
} else { //Array class, pg 16. | |||
if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE && | |||
(formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED)) { | |||
setClass(n,Ptg.CLASS_VALUE); | |||
} else { | |||
setClass(n,Ptg.CLASS_ARRAY); | |||
} | |||
} | |||
} | |||
private void setClass(Node n, byte theClass) { | |||
Ptg p = (Ptg) n.getValue(); | |||
if (p instanceof FunctionPtg || !(p instanceof OperationPtg)) { | |||
p.setClass(theClass); | |||
} else { | |||
for (int i =0;i<n.getNumChildren();i++) { | |||
setClass(n.getChild(i),theClass); | |||
} | |||
} | |||
} | |||
/** | |||
* Convience method which takes in a list then passes it to the other toFormulaString | |||
* signature | |||
@@ -459,6 +548,7 @@ end; | |||
String[] operands; | |||
for (int i=0;i<numPtgs;i++) { | |||
if (ptgs[i] instanceof OperationPtg) { | |||
// Excel allows to have AttrPtg at position 0 (such as Blanks) which | |||
// do not have any operands. Skip them. | |||
if(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<numPtgs;i++) { | |||
if (tokens.get(i) instanceof OperationPtg) { | |||
o = (OperationPtg) tokens.get(i); | |||
numOperands = o.getNumberOfOperands(); | |||
operands = new Node[numOperands]; | |||
for (int j=0;j<numOperands;j++) { | |||
operands[numOperands-j-1] = (Node) stack.pop(); | |||
} | |||
Node result = new Node(o); | |||
result.setChildren(operands); | |||
stack.push(result); | |||
} else { | |||
stack.push(new Node((Ptg)tokens.get(i))); | |||
} | |||
} | |||
return (Node) stack.pop(); | |||
} | |||
/** toString on the parser instance returns the RPN ordered list of tokens | |||
* Useful for testing | |||
@@ -491,5 +606,17 @@ end; | |||
return buf.toString(); | |||
} | |||
} | |||
class Node { | |||
private Ptg value=null; | |||
private Node[] children=new Node[0]; | |||
private int numChild=0; | |||
public Node(Ptg val) { | |||
value = val; | |||
} | |||
public void setChildren(Node[] child) {children = child;numChild=child.length;} | |||
public int getNumChildren() {return numChild;} | |||
public Node getChild(int number) {return children[number];} | |||
public Ptg getValue() {return value;} | |||
} | |||
} |
@@ -9,15 +9,15 @@ import org.apache.poi.util.BinaryTree; | |||
* This class provides functions with variable arguments. | |||
* @author Avik Sengupta | |||
* @author Andrew C. Oliver (acoliver at apache dot org) | |||
* @version | |||
*/ | |||
public class FunctionPtg extends OperationPtg { | |||
public final static short sid = 0x22; | |||
private final static int SIZE = 4; | |||
private static BinaryTree map = produceHash(); | |||
static { map=produceHash();} | |||
private static Object[][] functionData = produceFunctionData(); | |||
private byte returnClass; | |||
private byte[] paramClass; | |||
private byte field_1_num_args; | |||
private short field_2_fnc_index; | |||
@@ -30,7 +30,6 @@ public class FunctionPtg extends OperationPtg { | |||
offset++; | |||
field_1_num_args = data[ offset + 0 ]; | |||
field_2_fnc_index = LittleEndian.getShort(data,offset + 1 ); | |||
} | |||
/** | |||
@@ -39,7 +38,13 @@ public class FunctionPtg extends OperationPtg { | |||
protected FunctionPtg(String pName, byte pNumOperands) { | |||
field_1_num_args = pNumOperands; | |||
field_2_fnc_index = lookupIndex(pName); | |||
try{ | |||
returnClass = ( (Byte) functionData[field_2_fnc_index][0]).byteValue(); | |||
paramClass = (byte[]) functionData[field_2_fnc_index][1]; | |||
} catch (NullPointerException npe ) { | |||
returnClass = Ptg.CLASS_VALUE; | |||
paramClass = new byte[] {Ptg.CLASS_VALUE}; | |||
} | |||
} | |||
public String toString() { | |||
@@ -89,7 +94,7 @@ public class FunctionPtg extends OperationPtg { | |||
public void writeBytes(byte[] array, int offset) { | |||
array[offset+0]=sid; | |||
array[offset+0]=(byte) (sid + ptgClass); | |||
array[offset+1]=field_1_num_args; | |||
LittleEndian.putShort(array,offset+2,field_2_fnc_index); | |||
} | |||
@@ -99,11 +104,11 @@ public class FunctionPtg extends OperationPtg { | |||
} | |||
private String lookupName(short index) { | |||
return ((String)map.get(new Integer(index))); //for now always return "SUM" | |||
return ((String)map.get(new Integer(index))); | |||
} | |||
private short lookupIndex(String name) { | |||
return (short)((Integer)map.getKeyForValue(name)).intValue(); //for now just return SUM everytime... | |||
return (short)((Integer)map.getKeyForValue(name)).intValue(); | |||
} | |||
/** | |||
@@ -465,4 +470,50 @@ public class FunctionPtg extends OperationPtg { | |||
return dmap; | |||
} | |||
private static Object[][] produceFunctionData() { | |||
Object [][] functionData = new Object[368][2]; | |||
functionData[0][0]=new Byte(Ptg.CLASS_VALUE);functionData[0][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[2][0]=new Byte(Ptg.CLASS_VALUE);functionData[2][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[3][0]=new Byte(Ptg.CLASS_VALUE);functionData[3][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[4][0]=new Byte(Ptg.CLASS_VALUE);functionData[4][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[5][0]=new Byte(Ptg.CLASS_VALUE);functionData[5][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[6][0]=new Byte(Ptg.CLASS_VALUE);functionData[6][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[7][0]=new Byte(Ptg.CLASS_VALUE);functionData[7][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[8][0]=new Byte(Ptg.CLASS_VALUE);functionData[8][1]=new byte[] {Ptg.CLASS_REF}; | |||
functionData[9][0]=new Byte(Ptg.CLASS_VALUE);functionData[9][1]=new byte[] {Ptg.CLASS_REF}; | |||
functionData[10][0]=new Byte(Ptg.CLASS_VALUE);functionData[10][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[11][0]=new Byte(Ptg.CLASS_VALUE);functionData[11][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[12][0]=new Byte(Ptg.CLASS_VALUE);functionData[12][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[13][0]=new Byte(Ptg.CLASS_VALUE);functionData[13][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[14][0]=new Byte(Ptg.CLASS_VALUE);functionData[14][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[15][0]=new Byte(Ptg.CLASS_VALUE);functionData[15][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[16][0]=new Byte(Ptg.CLASS_VALUE);functionData[16][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[17][0]=new Byte(Ptg.CLASS_VALUE);functionData[17][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[18][0]=new Byte(Ptg.CLASS_VALUE);functionData[18][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[19][0]=new Byte(Ptg.CLASS_VALUE);functionData[19][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[20][0]=new Byte(Ptg.CLASS_VALUE);functionData[20][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[21][0]=new Byte(Ptg.CLASS_VALUE);functionData[21][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[22][0]=new Byte(Ptg.CLASS_VALUE);functionData[22][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[23][0]=new Byte(Ptg.CLASS_VALUE);functionData[23][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[24][0]=new Byte(Ptg.CLASS_VALUE);functionData[24][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[25][0]=new Byte(Ptg.CLASS_VALUE);functionData[25][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[26][0]=new Byte(Ptg.CLASS_VALUE);functionData[26][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
functionData[27][0]=new Byte(Ptg.CLASS_VALUE);functionData[27][1]=new byte[] {Ptg.CLASS_VALUE}; | |||
return functionData; | |||
} | |||
public byte getDefaultOperandClass() { | |||
return returnClass; | |||
} | |||
protected byte getParameterClass(int index) { | |||
try { | |||
return paramClass[index]; | |||
} catch (ArrayIndexOutOfBoundsException aioobe) { | |||
return paramClass[paramClass.length - 1]; | |||
} | |||
} | |||
} |
@@ -114,5 +114,5 @@ public class IntPtg | |||
{ | |||
return "" + getValue(); | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} |
@@ -120,4 +120,5 @@ public class MemErrPtg | |||
{ | |||
return "ERR#"; | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} |
@@ -106,4 +106,6 @@ public class NamePtg | |||
{ | |||
return "NO IDEA - NAME"; | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} |
@@ -113,6 +113,6 @@ public class NumberPtg | |||
{ | |||
return "" + getValue(); | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} | |||
@@ -88,4 +88,6 @@ public abstract class OperationPtg extends Ptg | |||
*/ | |||
public abstract int getNumberOfOperands(); | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} |
@@ -112,7 +112,9 @@ public class ParenthesisPtg | |||
public String toFormulaString(String[] operands) { | |||
return "("+operands[0]+")"; | |||
} | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} | |||
@@ -109,9 +109,7 @@ public class PowerPtg | |||
{ | |||
return "^"; | |||
} | |||
public String toFormulaString(String[] operands) { | |||
StringBuffer buffer = new StringBuffer(); | |||
@@ -66,6 +66,7 @@ import java.util.ArrayList; | |||
/** | |||
* | |||
* @author andy | |||
* @author avik | |||
*/ | |||
public abstract class Ptg | |||
@@ -124,54 +125,18 @@ public abstract class Ptg | |||
return retval; | |||
} | |||
*/ | |||
/* | |||
private static List ptgsToList(Class [] ptgs) | |||
{ | |||
List result = new ArrayList(); | |||
Constructor constructor; | |||
for (int i = 0; i < ptgs.length; i++) | |||
{ | |||
Class ptg = null; | |||
ptg = ptgs[ i ]; | |||
try | |||
{ | |||
constructor = ptg.getConstructor(new Class[] | |||
{ | |||
byte [].class, int.class | |||
}); | |||
} | |||
catch (Exception illegalArgumentException) | |||
{ | |||
throw new RuntimeException( | |||
"Now that didn't work nicely at all (couldn't do that there list of ptgs)"); | |||
} | |||
result.add(constructor); | |||
} | |||
return result; | |||
}*/ | |||
public static Ptg createPtg(byte [] data, int offset) | |||
{ | |||
byte id = data[ offset + 0 ]; | |||
Ptg retval = null; | |||
final int refRef = ReferencePtg.sid - 0x20; | |||
final int arrayRef = ReferencePtg.sid + 0x20; | |||
final int valueFunc = FunctionPtg.sid + 0x20; | |||
final int arrayFunc = FunctionPtg.sid + 0x40; | |||
final int refArea = AreaPtg.sid-0x20; | |||
final int arrayArea = AreaPtg.sid+0x20; | |||
final byte valueRef = ReferencePtg.sid + 0x20; | |||
final byte arrayRef = ReferencePtg.sid + 0x40; | |||
final byte valueFunc = FunctionPtg.sid + 0x20; | |||
final byte arrayFunc = FunctionPtg.sid + 0x40; | |||
final byte valueArea = AreaPtg.sid + 0x20; | |||
final byte arrayArea = AreaPtg.sid + 0x40; | |||
switch (id) | |||
{ | |||
@@ -207,7 +172,12 @@ public abstract class Ptg | |||
case AreaPtg.sid : | |||
retval = new AreaPtg(data, offset); | |||
break; | |||
case valueArea: | |||
retval = new AreaPtg(data, offset); | |||
break; | |||
case arrayArea: | |||
retval = new AreaPtg(data, offset); | |||
break; | |||
case MemErrPtg.sid : | |||
retval = new MemErrPtg(data, offset); | |||
break; | |||
@@ -215,18 +185,16 @@ public abstract class Ptg | |||
case AttrPtg.sid : | |||
retval = new AttrPtg(data, offset); | |||
break; | |||
case ReferencePtg.sid : | |||
retval = new ReferencePtg(data, offset); | |||
break; | |||
case refRef : | |||
break; | |||
case valueRef : | |||
retval = new ReferencePtg(data, offset); | |||
break; | |||
break; | |||
case arrayRef : | |||
retval = new ReferencePtg(data, offset); | |||
break; | |||
break; | |||
case ParenthesisPtg.sid : | |||
retval = new ParenthesisPtg(data, offset); | |||
@@ -239,7 +207,6 @@ public abstract class Ptg | |||
case valueFunc : | |||
retval = new FunctionPtg(data, offset); | |||
break; | |||
case arrayFunc : | |||
retval = new FunctionPtg(data, offset); | |||
break; | |||
@@ -275,7 +242,15 @@ public abstract class Ptg | |||
+ Integer.toHexString(( int ) id) | |||
+ " (" + ( int ) id + ")"); | |||
} | |||
return retval; | |||
if (id > 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(); | |||
} |
@@ -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;} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
@@ -95,4 +95,7 @@ public class UnknownPtg | |||
{ | |||
return "UNKNOWN"; | |||
} | |||
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} | |||
} |
@@ -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); |