Skip to content

Commit

Permalink
SHARED FORMULA SUPPORT:
Browse files Browse the repository at this point in the history
Implemented my long standing (but incomplete) patch attached to Bug 26502.

Now shared formula conversion is working. Tested against file attached to Bug 26502 and Bug 18311.

TestValueRecordAggregate fails with the patch at the moment, too tired to look at. Will do tomorrow.

Jason

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@425402 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
Jason Height committed Jul 25, 2006
1 parent 79d49c2 commit 94429dd
Show file tree
Hide file tree
Showing 17 changed files with 1,349 additions and 67 deletions.
25 changes: 22 additions & 3 deletions src/java/org/apache/poi/hssf/record/FormulaRecord.java
Expand Up @@ -27,6 +27,8 @@
import java.util.Stack;

import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian;

/**
Expand All @@ -53,6 +55,9 @@ public class FormulaRecord
private short field_3_xf;
private double field_4_value;
private short field_5_options;
private BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
private BitField calcOnLoad = BitFieldFactory.getInstance(0x0002);
private BitField sharedFormula = BitFieldFactory.getInstance(0x0008);
private int field_6_zero;
private short field_7_expression_len;
private Stack field_8_parsed_expr;
Expand Down Expand Up @@ -191,7 +196,11 @@ public short getOptions()
{
return field_5_options;
}


public boolean isSharedFormula() {
return sharedFormula.isSet(field_5_options);
}

/**
* get the length (in number of tokens) of the expression
* @return expression length
Expand Down Expand Up @@ -262,6 +271,10 @@ public List getParsedExpression()
{
return field_8_parsed_expr;
}

public void setParsedExpression(Stack ptgs) {
field_8_parsed_expr = ptgs;
}

/**
* called by constructor, should throw runtime exception in the event of a
Expand Down Expand Up @@ -474,6 +487,12 @@ public String toString()
.append("\n");
buffer.append(" .options = ").append(getOptions())
.append("\n");
buffer.append(" .alwaysCalc = ").append(alwaysCalc.isSet(getOptions()))
.append("\n");
buffer.append(" .calcOnLoad = ").append(calcOnLoad.isSet(getOptions()))
.append("\n");
buffer.append(" .sharedFormula = ").append(sharedFormula.isSet(getOptions()))
.append("\n");
buffer.append(" .zero = ").append(field_6_zero)
.append("\n");
buffer.append(" .expressionlength= ").append(getExpressionLength())
Expand All @@ -485,9 +504,9 @@ public String toString()


for (int k = 0; k < field_8_parsed_expr.size(); k++ ) {
buffer.append("Formula ")
buffer.append(" Ptg(")
.append(k)
.append("=")
.append(")=")
.append(field_8_parsed_expr.get(k).toString())
.append("\n")
.append(((Ptg)field_8_parsed_expr.get(k)).toDebugString())
Expand Down
203 changes: 167 additions & 36 deletions src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
Expand Up @@ -18,6 +18,10 @@

package org.apache.poi.hssf.record;

import java.util.Stack;
import java.util.List;

import org.apache.poi.hssf.record.formula.*;
import org.apache.poi.util.LittleEndian;

/**
Expand All @@ -36,9 +40,14 @@ public class SharedFormulaRecord
extends Record
{
public final static short sid = 0x4BC;
private short size = 0;
private byte[] thedata = null;
int offset = 0;

private int field_1_first_row;
private int field_2_last_row;
private short field_3_first_column;
private short field_4_last_column;
private int field_5_reserved;
private short field_6_expression_len;
private Stack field_7_parsed_expr;

public SharedFormulaRecord()
{
Expand All @@ -55,45 +64,51 @@ public SharedFormulaRecord(RecordInputStream in)
{
super(in);
}

protected void validateSid(short id)
{
if (id != this.sid)
{
throw new RecordFormatException("Not a valid SharedFormula");
}
}

public int getFirstRow() {
return field_1_first_row;
}

public int getLastRow() {
return field_2_last_row;
}

public short getFirstColumn() {
return field_3_first_column;
}

public short getLastColumn() {
return field_4_last_column;
}

public short getExpressionLength()
{
return field_6_expression_len;
}

/**
* spit the record out AS IS. no interperatation or identification
*/

public int serialize(int offset, byte [] data)
{
if (thedata == null)
{
thedata = new byte[ 0 ];
}
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, ( short ) (thedata.length));
if (thedata.length > 0)
{
System.arraycopy(thedata, 0, data, 4 + offset, thedata.length);
}
return getRecordSize();
//Because this record is converted to individual Formula records, this method is not required.
throw new UnsupportedOperationException("Cannot serialize a SharedFormulaRecord");
}

public int getRecordSize()
{
int retval = 4;
//Because this record is converted to individual Formula records, this method is not required.
throw new UnsupportedOperationException("Cannot get the size for a SharedFormulaRecord");

if (thedata != null)
{
retval += thedata.length;
}
return retval;
}


protected void validateSid(short id)
{
if (id != this.sid)
{
throw new RecordFormatException("Not a valid SharedFormula");
}

}

/**
Expand All @@ -107,6 +122,33 @@ public String toString()
buffer.append("[SHARED FORMULA RECORD:" + Integer.toHexString(sid) + "]\n");
buffer.append(" .id = ").append(Integer.toHexString(sid))
.append("\n");
buffer.append(" .first_row = ")
.append(Integer.toHexString(getFirstRow())).append("\n");
buffer.append(" .last_row = ")
.append(Integer.toHexString(getLastRow()))
.append("\n");
buffer.append(" .first_column = ")
.append(Integer.toHexString(getFirstColumn())).append("\n");
buffer.append(" .last_column = ")
.append(Integer.toHexString(getLastColumn()))
.append("\n");
buffer.append(" .reserved = ")
.append(Integer.toHexString(field_5_reserved))
.append("\n");
buffer.append(" .expressionlength= ").append(getExpressionLength())
.append("\n");

buffer.append(" .numptgsinarray = ").append(field_7_parsed_expr.size())
.append("\n");

for (int k = 0; k < field_7_parsed_expr.size(); k++ ) {
buffer.append("Formula ")
.append(k)
.append("\n")
.append(field_7_parsed_expr.get(k).toString())
.append("\n");
}

buffer.append("[/SHARED FORMULA RECORD]\n");
return buffer.toString();
}
Expand All @@ -121,7 +163,99 @@ public short getSid()
*/
protected void fillFields(RecordInputStream in)
{
thedata = in.readRemainder();
field_1_first_row = in.readShort();
field_2_last_row = in.readShort();
field_3_first_column = in.readByte();
field_4_last_column = in.readByte();
field_5_reserved = in.readShort();
field_6_expression_len = in.readShort();
field_7_parsed_expr = getParsedExpressionTokens(in);
}

private Stack getParsedExpressionTokens(RecordInputStream in)
{
Stack stack = new Stack();

while (in.remaining() != 0) {
Ptg ptg = Ptg.createPtg(in);
stack.push(ptg);
}
return stack;
}

public boolean isFormulaInShared(FormulaRecord formula) {
final int formulaRow = formula.getRow();
final int formulaColumn = formula.getColumn();
return ((getFirstRow() <= formulaRow) && (getLastRow() >= formulaRow) &&
(getFirstColumn() <= formulaColumn) && (getLastColumn() >= formulaColumn));
}

/** Creates a non shared formula from the shared formula counter part*/
public void convertSharedFormulaRecord(FormulaRecord formula) {
//Sanity checks
final int formulaRow = formula.getRow();
final int formulaColumn = formula.getColumn();
if (isFormulaInShared(formula)) {
formula.setExpressionLength(getExpressionLength());
Stack newPtgStack = new Stack();

for (int k = 0; k < field_7_parsed_expr.size(); k++) {
Ptg ptg = (Ptg) field_7_parsed_expr.get(k);
if (ptg instanceof RefNPtg) {
RefNPtg refNPtg = (RefNPtg)ptg;
ptg = new ReferencePtg( (short)(formulaRow + refNPtg.getRow()),
(byte)(formulaColumn + refNPtg.getColumn()),
refNPtg.isRowRelative(),
refNPtg.isColRelative());
} else if (ptg instanceof RefNVPtg) {
RefNVPtg refNVPtg = (RefNVPtg)ptg;
ptg = new RefVPtg( (short)(formulaRow + refNVPtg.getRow()),
(byte)(formulaColumn + refNVPtg.getColumn()),
refNVPtg.isRowRelative(),
refNVPtg.isColRelative());
} else if (ptg instanceof RefNAPtg) {
RefNAPtg refNAPtg = (RefNAPtg)ptg;
ptg = new RefAPtg( (short)(formulaRow + refNAPtg.getRow()),
(byte)(formulaColumn + refNAPtg.getColumn()),
refNAPtg.isRowRelative(),
refNAPtg.isColRelative());
} else if (ptg instanceof AreaNPtg) {
AreaNPtg areaNPtg = (AreaNPtg)ptg;
ptg = new AreaPtg((short)(formulaRow + areaNPtg.getFirstRow()),
(short)(formulaRow + areaNPtg.getLastRow()),
(short)(formulaColumn + areaNPtg.getFirstColumn()),
(short)(formulaColumn + areaNPtg.getLastColumn()),
areaNPtg.isFirstRowRelative(),
areaNPtg.isLastRowRelative(),
areaNPtg.isFirstColRelative(),
areaNPtg.isLastColRelative());
} else if (ptg instanceof AreaNVPtg) {
AreaNVPtg areaNVPtg = (AreaNVPtg)ptg;
ptg = new AreaVPtg((short)(formulaRow + areaNVPtg.getFirstRow()),
(short)(formulaRow + areaNVPtg.getLastRow()),
(short)(formulaColumn + areaNVPtg.getFirstColumn()),
(short)(formulaColumn + areaNVPtg.getLastColumn()),
areaNVPtg.isFirstRowRelative(),
areaNVPtg.isLastRowRelative(),
areaNVPtg.isFirstColRelative(),
areaNVPtg.isLastColRelative());
} else if (ptg instanceof AreaNAPtg) {
AreaNAPtg areaNAPtg = (AreaNAPtg)ptg;
ptg = new AreaAPtg((short)(formulaRow + areaNAPtg.getFirstRow()),
(short)(formulaRow + areaNAPtg.getLastRow()),
(short)(formulaColumn + areaNAPtg.getFirstColumn()),
(short)(formulaColumn + areaNAPtg.getLastColumn()),
areaNAPtg.isFirstRowRelative(),
areaNAPtg.isLastRowRelative(),
areaNAPtg.isFirstColRelative(),
areaNAPtg.isLastColRelative());
}
newPtgStack.add(ptg);
}
formula.setParsedExpression(newPtgStack);
} else {
throw new RuntimeException("Shared Formula Conversion: Coding Error");
}
}

/**
Expand All @@ -141,10 +275,7 @@ public boolean isValue() {
}

public Object clone() {
SharedFormulaRecord rec = new SharedFormulaRecord();
rec.offset = offset;
rec.size = size;
rec.thedata = thedata;
return rec;
//Because this record is converted to individual Formula records, this method is not required.
throw new UnsupportedOperationException("Cannot clone a SharedFormulaRecord");
}
}
Expand Up @@ -125,6 +125,7 @@ public int construct(int offset, List records)
int k = 0;

FormulaRecordAggregate lastFormulaAggregate = null;
SharedFormulaRecord lastSharedFormula = null;

for (k = offset; k < records.size(); k++)
{
Expand All @@ -136,18 +137,38 @@ public int construct(int offset, List records)
}
if (rec instanceof FormulaRecord)
{
FormulaRecord formula = (FormulaRecord)rec;
if (formula.isSharedFormula()) {
if ((lastSharedFormula != null) && (lastSharedFormula.isFormulaInShared(formula))) {
//Convert this Formula Record from a shared formula to a real formula
lastSharedFormula.convertSharedFormulaRecord(formula);
} else {
Record nextRecord = (Record) records.get(k + 1);
if (nextRecord instanceof SharedFormulaRecord) {
k++;
lastSharedFormula = (SharedFormulaRecord) nextRecord;

//Convert this Formula Record from a shared formula to a real formula
lastSharedFormula.convertSharedFormulaRecord(formula);
}
else
throw new RuntimeException(
"Shared formula bit set but next record is not a Shared Formula??");
}
}

lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null);
insertCell( lastFormulaAggregate );
}
else if (rec instanceof StringRecord)
{
lastFormulaAggregate.setStringRecord((StringRecord)rec);
}
else if (rec instanceof SharedFormulaRecord)
{
//these follow the first formula in a group
lastFormulaAggregate.setSharedFormulaRecord((SharedFormulaRecord)rec);
}
//else if (rec instanceof SharedFormulaRecord)
//{
// //these follow the first formula in a group
// lastFormulaAggregate.setSharedFormulaRecord((SharedFormulaRecord)rec);
//}
else if (rec.isValue())
{
insertCell(( CellValueRecordInterface ) rec);
Expand Down

0 comments on commit 94429dd

Please sign in to comment.