Fix for bug 45234 - Removed incorrect shared formula conversion in CFRuleRecord
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@669658 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
501c3b258a
commit
c02655d884
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.1-final" date="2008-06-??">
|
<release version="3.1-final" date="2008-06-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">45234 - Removed incorrect shared formula conversion in CFRuleRecord</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
|
<action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
|
<action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
|
<action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.1-final" date="2008-06-??">
|
<release version="3.1-final" date="2008-06-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">45234 - Removed incorrect shared formula conversion in CFRuleRecord</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
|
<action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
|
<action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
|
<action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
|
||||||
|
@ -15,13 +15,9 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.model.FormulaParser;
|
import org.apache.poi.hssf.model.FormulaParser;
|
||||||
import org.apache.poi.hssf.model.Workbook;
|
|
||||||
import org.apache.poi.hssf.record.cf.BorderFormatting;
|
import org.apache.poi.hssf.record.cf.BorderFormatting;
|
||||||
import org.apache.poi.hssf.record.cf.FontFormatting;
|
import org.apache.poi.hssf.record.cf.FontFormatting;
|
||||||
import org.apache.poi.hssf.record.cf.PatternFormatting;
|
import org.apache.poi.hssf.record.cf.PatternFormatting;
|
||||||
@ -30,7 +26,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|||||||
import org.apache.poi.util.BitField;
|
import org.apache.poi.util.BitField;
|
||||||
import org.apache.poi.util.BitFieldFactory;
|
import org.apache.poi.util.BitFieldFactory;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.StringUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conditional Formatting Rule Record.
|
* Conditional Formatting Rule Record.
|
||||||
@ -59,9 +54,6 @@ public final class CFRuleRecord extends Record
|
|||||||
|
|
||||||
private byte field_2_comparison_operator;
|
private byte field_2_comparison_operator;
|
||||||
|
|
||||||
private short field_3_formula1_len;
|
|
||||||
private short field_4_formula2_len;
|
|
||||||
|
|
||||||
private int field_5_options;
|
private int field_5_options;
|
||||||
|
|
||||||
private static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
|
private static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
|
||||||
@ -121,8 +113,6 @@ public final class CFRuleRecord extends Record
|
|||||||
{
|
{
|
||||||
field_1_condition_type=conditionType;
|
field_1_condition_type=conditionType;
|
||||||
field_2_comparison_operator=comparisonOperation;
|
field_2_comparison_operator=comparisonOperation;
|
||||||
field_3_formula1_len = (short)0;
|
|
||||||
field_4_formula2_len = (short)0;
|
|
||||||
|
|
||||||
// Set modification flags to 1: by default options are not modified
|
// Set modification flags to 1: by default options are not modified
|
||||||
field_5_options = modificationBits.setValue(field_5_options, -1);
|
field_5_options = modificationBits.setValue(field_5_options, -1);
|
||||||
@ -147,8 +137,8 @@ public final class CFRuleRecord extends Record
|
|||||||
this(conditionType, comparisonOperation);
|
this(conditionType, comparisonOperation);
|
||||||
field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS;
|
field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS;
|
||||||
field_2_comparison_operator = comparisonOperation;
|
field_2_comparison_operator = comparisonOperation;
|
||||||
setParsedExpression1(formula1);
|
field_17_formula1 = formula1;
|
||||||
setParsedExpression2(formula2);
|
field_18_formula2 = formula2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,31 +157,17 @@ public final class CFRuleRecord extends Record
|
|||||||
Ptg[] formula1 = parseFormula(formulaText1, workbook);
|
Ptg[] formula1 = parseFormula(formulaText1, workbook);
|
||||||
Ptg[] formula2 = parseFormula(formulaText2, workbook);
|
Ptg[] formula2 = parseFormula(formulaText2, workbook);
|
||||||
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
|
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public CFRuleRecord(RecordInputStream in) {
|
||||||
* Constructs a Formula record and sets its fields appropriately.
|
|
||||||
* Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an
|
|
||||||
* "explanation of this bug in the documentation) or an exception
|
|
||||||
* will be throw upon validation
|
|
||||||
*
|
|
||||||
* @param in the RecordInputstream to read the record from
|
|
||||||
*/
|
|
||||||
|
|
||||||
public CFRuleRecord(RecordInputStream in)
|
|
||||||
{
|
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected void fillFields(RecordInputStream in) {
|
protected void fillFields(RecordInputStream in) {
|
||||||
try {
|
|
||||||
field_1_condition_type = in.readByte();
|
field_1_condition_type = in.readByte();
|
||||||
field_2_comparison_operator = in.readByte();
|
field_2_comparison_operator = in.readByte();
|
||||||
field_3_formula1_len = in.readShort();
|
int field_3_formula1_len = in.readUShort();
|
||||||
field_4_formula2_len = in.readShort();
|
int field_4_formula2_len = in.readUShort();
|
||||||
field_5_options = in.readInt();
|
field_5_options = in.readInt();
|
||||||
field_6_not_used = in.readShort();
|
field_6_not_used = in.readShort();
|
||||||
|
|
||||||
@ -208,22 +184,11 @@ public final class CFRuleRecord extends Record
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (field_3_formula1_len > 0) {
|
if (field_3_formula1_len > 0) {
|
||||||
Stack ptgs = Ptg.createParsedExpressionTokens(field_3_formula1_len, in);
|
field_17_formula1 = Ptg.readTokens(field_3_formula1_len, in);
|
||||||
// Now convert any fields as required
|
|
||||||
ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
|
|
||||||
field_17_formula1 = toArray(ptgs);
|
|
||||||
}
|
}
|
||||||
if (field_4_formula2_len > 0) {
|
if (field_4_formula2_len > 0) {
|
||||||
Stack ptgs = Ptg.createParsedExpressionTokens(field_4_formula2_len, in);
|
field_18_formula2 = Ptg.readTokens(field_4_formula2_len, in);
|
||||||
|
|
||||||
// Now convert any fields as required
|
|
||||||
ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
|
|
||||||
field_18_formula2 = toArray(ptgs);
|
|
||||||
}
|
}
|
||||||
} catch (java.lang.UnsupportedOperationException uoe) {
|
|
||||||
throw new RecordFormatException(uoe);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getConditionType()
|
public byte getConditionType()
|
||||||
@ -323,24 +288,6 @@ public final class CFRuleRecord extends Record
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the length (in number of tokens) of the expression 1
|
|
||||||
* @return expression length
|
|
||||||
*/
|
|
||||||
private short getExpression1Length()
|
|
||||||
{
|
|
||||||
return field_3_formula1_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the length (in number of tokens) of the expression 2
|
|
||||||
* @return expression length
|
|
||||||
*/
|
|
||||||
private short getExpression2Length()
|
|
||||||
{
|
|
||||||
return field_4_formula2_len;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* get the option flags
|
* get the option flags
|
||||||
*
|
*
|
||||||
@ -489,16 +436,6 @@ public final class CFRuleRecord extends Record
|
|||||||
return field_18_formula2;
|
return field_18_formula2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setParsedExpression1(Ptg[] ptgs) {
|
|
||||||
short len = getTotalPtgSize(field_17_formula1 = ptgs);
|
|
||||||
field_3_formula1_len = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setParsedExpression2(Ptg[] ptgs) {
|
|
||||||
short len = getTotalPtgSize(field_18_formula2 = ptgs);
|
|
||||||
field_4_formula2_len = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called by constructor, should throw runtime exception in the event of a
|
* called by constructor, should throw runtime exception in the event of a
|
||||||
* record passed with a differing ID.
|
* record passed with a differing ID.
|
||||||
@ -519,6 +456,17 @@ public final class CFRuleRecord extends Record
|
|||||||
return sid;
|
return sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ptgs may be <code>null</code>
|
||||||
|
* @return encoded size of the formula
|
||||||
|
*/
|
||||||
|
private static int getFormulaSize(Ptg[] ptgs) {
|
||||||
|
if (ptgs == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Ptg.getEncodedSize(ptgs);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called by the class that is responsible for writing this sucker.
|
* called by the class that is responsible for writing this sucker.
|
||||||
* Subclasses should implement this so that their data is passed back in a
|
* Subclasses should implement this so that their data is passed back in a
|
||||||
@ -528,18 +476,20 @@ public final class CFRuleRecord extends Record
|
|||||||
* @param data byte array containing instance data
|
* @param data byte array containing instance data
|
||||||
* @return number of bytes written
|
* @return number of bytes written
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public int serialize(int pOffset, byte [] data)
|
public int serialize(int pOffset, byte [] data)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
int formula1Len=getFormulaSize(field_17_formula1);
|
||||||
|
int formula2Len=getFormulaSize(field_18_formula2);
|
||||||
|
|
||||||
int offset = pOffset;
|
int offset = pOffset;
|
||||||
int recordsize = getRecordSize();
|
int recordsize = getRecordSize();
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4));
|
LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4));
|
||||||
data[4 + offset] = field_1_condition_type;
|
data[4 + offset] = field_1_condition_type;
|
||||||
data[5 + offset] = field_2_comparison_operator;
|
data[5 + offset] = field_2_comparison_operator;
|
||||||
LittleEndian.putShort(data, 6 + offset, field_3_formula1_len);
|
LittleEndian.putUShort(data, 6 + offset, formula1Len);
|
||||||
LittleEndian.putShort(data, 8 + offset, field_4_formula2_len);
|
LittleEndian.putUShort(data, 8 + offset, formula2Len);
|
||||||
LittleEndian.putInt(data, 10 + offset, field_5_options);
|
LittleEndian.putInt(data, 10 + offset, field_5_options);
|
||||||
LittleEndian.putShort(data,14 + offset, field_6_not_used);
|
LittleEndian.putShort(data,14 + offset, field_6_not_used);
|
||||||
|
|
||||||
@ -562,16 +512,12 @@ public final class CFRuleRecord extends Record
|
|||||||
offset += patternFormatting.serialize(offset, data);
|
offset += patternFormatting.serialize(offset, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getExpression1Length()>0)
|
if (field_17_formula1 != null) {
|
||||||
{
|
offset += Ptg.serializePtgs(field_17_formula1, data, offset);
|
||||||
Ptg.serializePtgStack(convertToTokenStack(field_17_formula1), data, offset);
|
|
||||||
offset += getExpression1Length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getExpression2Length()>0)
|
if (field_18_formula2 != null) {
|
||||||
{
|
offset += Ptg.serializePtgs(field_18_formula2, data, offset);
|
||||||
Ptg.serializePtgStack(convertToTokenStack(field_18_formula2), data, offset);
|
|
||||||
offset += getExpression2Length();
|
|
||||||
}
|
}
|
||||||
if(offset - pOffset != recordsize) {
|
if(offset - pOffset != recordsize) {
|
||||||
throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")");
|
throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")");
|
||||||
@ -586,24 +532,12 @@ public final class CFRuleRecord extends Record
|
|||||||
(containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+
|
(containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+
|
||||||
(containsBorderFormattingBlock()?8:0)+
|
(containsBorderFormattingBlock()?8:0)+
|
||||||
(containsPatternFormattingBlock()?4:0)+
|
(containsPatternFormattingBlock()?4:0)+
|
||||||
getExpression1Length()+
|
getFormulaSize(field_17_formula1)+
|
||||||
getExpression2Length()
|
getFormulaSize(field_18_formula2)
|
||||||
;
|
;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private short getTotalPtgSize(Ptg[] ptgs)
|
|
||||||
{
|
|
||||||
if( ptgs == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
short retval = 0;
|
|
||||||
for (int i = 0; i < ptgs.length; i++)
|
|
||||||
{
|
|
||||||
retval += ptgs[i].getSize();
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
@ -629,8 +563,6 @@ public final class CFRuleRecord extends Record
|
|||||||
|
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator);
|
CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator);
|
||||||
rec.field_3_formula1_len = field_3_formula1_len;
|
|
||||||
rec.field_4_formula2_len = field_4_formula2_len;
|
|
||||||
rec.field_5_options = field_5_options;
|
rec.field_5_options = field_5_options;
|
||||||
rec.field_6_not_used = field_6_not_used;
|
rec.field_6_not_used = field_6_not_used;
|
||||||
if (containsFontFormattingBlock()) {
|
if (containsFontFormattingBlock()) {
|
||||||
@ -642,10 +574,10 @@ public final class CFRuleRecord extends Record
|
|||||||
if (containsPatternFormattingBlock()) {
|
if (containsPatternFormattingBlock()) {
|
||||||
rec.patternFormatting = (PatternFormatting) patternFormatting.clone();
|
rec.patternFormatting = (PatternFormatting) patternFormatting.clone();
|
||||||
}
|
}
|
||||||
if (field_3_formula1_len > 0) {
|
if (field_17_formula1 != null) {
|
||||||
rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone();
|
rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone();
|
||||||
}
|
}
|
||||||
if (field_4_formula2_len > 0) {
|
if (field_18_formula2 != null) {
|
||||||
rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone();
|
rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,30 +585,17 @@ public final class CFRuleRecord extends Record
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* TODO - parse conditional format formulas properly i.e. produce tRefN and tAreaN instead of tRef and tArea
|
||||||
|
* this call will produce the wrong results if the formula contains any cell references
|
||||||
|
* One approach might be to apply the inverse of SharedFormulaRecord.convertSharedFormulas(Stack, int, int)
|
||||||
|
* Note - two extra parameters (rowIx & colIx) will be required. They probably come from one of the Region objects.
|
||||||
|
*
|
||||||
* @return <code>null</code> if <tt>formula</tt> was null.
|
* @return <code>null</code> if <tt>formula</tt> was null.
|
||||||
*/
|
*/
|
||||||
private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook)
|
private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) {
|
||||||
{
|
|
||||||
if(formula == null) {
|
if(formula == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return FormulaParser.parse(formula, workbook);
|
return FormulaParser.parse(formula, workbook);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - treat formulas as token arrays instead of Stacks throughout the rest of POI
|
|
||||||
private static Stack convertToTokenStack(Ptg[] ptgs)
|
|
||||||
{
|
|
||||||
Stack parsedExpression = new Stack();
|
|
||||||
// fill the Ptg Stack with Ptgs of new formula
|
|
||||||
for (int k = 0; k < ptgs.length; k++)
|
|
||||||
{
|
|
||||||
parsedExpression.push(ptgs[ k ]);
|
|
||||||
}
|
|
||||||
return parsedExpression;
|
|
||||||
}
|
|
||||||
private static Ptg[] toArray(Stack ptgs) {
|
|
||||||
Ptg[] result = new Ptg[ptgs.size()];
|
|
||||||
ptgs.toArray(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,8 @@ public final class HSSFSheetConditionalFormatting {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory method allowing to create a conditional formatting rule
|
* A factory method allowing to create a conditional formatting rule
|
||||||
* with a cell comparison operator
|
* with a cell comparison operator<p/>
|
||||||
|
* TODO - formulas containing cell references are currently not parsed properly
|
||||||
*
|
*
|
||||||
* @param comparisonOperation - a constant value from
|
* @param comparisonOperation - a constant value from
|
||||||
* <tt>{@link HSSFConditionalFormattingRule.ComparisonOperator}</tt>: <p>
|
* <tt>{@link HSSFConditionalFormattingRule.ComparisonOperator}</tt>: <p>
|
||||||
@ -72,8 +73,8 @@ public final class HSSFSheetConditionalFormatting {
|
|||||||
/**
|
/**
|
||||||
* A factory method allowing to create a conditional formatting rule with a formula.<br>
|
* A factory method allowing to create a conditional formatting rule with a formula.<br>
|
||||||
*
|
*
|
||||||
* The formatting rules are applied by Excel when the value of the formula not equal to 0.
|
* The formatting rules are applied by Excel when the value of the formula not equal to 0.<p/>
|
||||||
*
|
* TODO - formulas containing cell references are currently not parsed properly
|
||||||
* @param formula - formula for the valued, compared with the cell
|
* @param formula - formula for the valued, compared with the cell
|
||||||
*/
|
*/
|
||||||
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {
|
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {
|
||||||
|
@ -17,12 +17,16 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
|
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
|
||||||
import org.apache.poi.hssf.record.cf.BorderFormatting;
|
import org.apache.poi.hssf.record.cf.BorderFormatting;
|
||||||
import org.apache.poi.hssf.record.cf.FontFormatting;
|
import org.apache.poi.hssf.record.cf.FontFormatting;
|
||||||
import org.apache.poi.hssf.record.cf.PatternFormatting;
|
import org.apache.poi.hssf.record.cf.PatternFormatting;
|
||||||
|
import org.apache.poi.hssf.record.formula.Ptg;
|
||||||
|
import org.apache.poi.hssf.record.formula.RefNPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.RefPtg;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
import org.apache.poi.hssf.util.HSSFColor;
|
import org.apache.poi.hssf.util.HSSFColor;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
@ -297,6 +301,56 @@ public final class TestCFRuleRecord extends TestCase
|
|||||||
assertEquals(0x203FFFFF, flags);
|
assertEquals(0x203FFFFF, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final byte[] DATA_REFN = {
|
||||||
|
// formula extracted from bugzilla 45234 att 22141
|
||||||
|
1, 3,
|
||||||
|
9, // formula 1 length
|
||||||
|
0, 0, 0, -1, -1, 63, 32, 2, -128, 0, 0, 0, 5,
|
||||||
|
// formula 1: "=B3=1" (formula is relative to B4)
|
||||||
|
76, -1, -1, 0, -64, // tRefN(B1)
|
||||||
|
30, 1, 0,
|
||||||
|
11,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tRefN and tAreaN tokens must be preserved when re-serializing conditional format formulas
|
||||||
|
*/
|
||||||
|
public void testReserializeRefNTokens() {
|
||||||
|
|
||||||
|
RecordInputStream is = new TestcaseRecordInputStream(CFRuleRecord.sid, DATA_REFN);
|
||||||
|
CFRuleRecord rr = new CFRuleRecord(is);
|
||||||
|
Ptg[] ptgs = rr.getParsedExpression1();
|
||||||
|
assertEquals(3, ptgs.length);
|
||||||
|
if (ptgs[0] instanceof RefPtg) {
|
||||||
|
throw new AssertionFailedError("Identified bug 45234");
|
||||||
|
}
|
||||||
|
assertEquals(RefNPtg.class, ptgs[0].getClass());
|
||||||
|
RefNPtg refNPtg = (RefNPtg) ptgs[0];
|
||||||
|
assertTrue(refNPtg.isColRelative());
|
||||||
|
assertTrue(refNPtg.isRowRelative());
|
||||||
|
|
||||||
|
byte[] data = rr.serialize();
|
||||||
|
|
||||||
|
if (!compareArrays(DATA_REFN, 0, data, 4, DATA_REFN.length)) {
|
||||||
|
fail("Did not re-serialize correctly");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean compareArrays(byte[] arrayA, int offsetA, byte[] arrayB, int offsetB, int length) {
|
||||||
|
|
||||||
|
if (offsetA + length > arrayA.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (offsetB + length > arrayB.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
if (arrayA[i+offsetA] != arrayB[i+offsetB]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] ignored_args)
|
public static void main(String[] ignored_args)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user