aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/poi
diff options
context:
space:
mode:
authorJosh Micich <josh@apache.org>2008-10-30 22:06:10 +0000
committerJosh Micich <josh@apache.org>2008-10-30 22:06:10 +0000
commit0f60f5eba5bfff80c34df7db0a42d9a457dbbc35 (patch)
tree07a92110d7ff8a321d777fb133c16df981da0fe1 /src/java/org/apache/poi
parent2b9938194aeb72c5ec3e4f0c98488f99b713a39a (diff)
downloadpoi-0f60f5eba5bfff80c34df7db0a42d9a457dbbc35.tar.gz
poi-0f60f5eba5bfff80c34df7db0a42d9a457dbbc35.zip
Merged revisions 708385,708996,709054,709217,709221,709235 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r708385 | josh | 2008-10-27 16:44:44 -0700 (Mon, 27 Oct 2008) | 1 line Small fix for bug in RecordInputStream.readAllContinuedRemainder() introduced in r707778. It seems like only BiffViewer was affected. ........ r708996 | josh | 2008-10-29 13:13:58 -0700 (Wed, 29 Oct 2008) | 1 line Allowed for quad-byte padding alignment on ObjRecord ........ r709054 | josh | 2008-10-29 17:21:24 -0700 (Wed, 29 Oct 2008) | 1 line removed obsolete methods ........ r709217 | josh | 2008-10-30 10:56:34 -0700 (Thu, 30 Oct 2008) | 1 line Fixed compiler warnings / simplified code ........ r709221 | josh | 2008-10-30 11:33:35 -0700 (Thu, 30 Oct 2008) | 1 line Optimised slow test case (after reviewing original purpose) ........ r709235 | josh | 2008-10-30 13:17:04 -0700 (Thu, 30 Oct 2008) | 1 line Fix for bug 15716 - - converted Ptg arrays into Formula objects to optimise memory usage ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@709262 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/poi')
-rw-r--r--src/java/org/apache/poi/hssf/record/ArrayRecord.java31
-rw-r--r--src/java/org/apache/poi/hssf/record/CFRuleRecord.java158
-rw-r--r--src/java/org/apache/poi/hssf/record/DVRecord.java117
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/ExternalNameRecord.java58
-rw-r--r--src/java/org/apache/poi/hssf/record/FormulaRecord.java113
-rw-r--r--src/java/org/apache/poi/hssf/record/NameRecord.java142
-rw-r--r--src/java/org/apache/poi/hssf/record/ObjRecord.java61
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/RecordInputStream.java8
-rwxr-xr-xsrc/java/org/apache/poi/hssf/record/SharedFormulaRecord.java66
-rw-r--r--src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java26
-rw-r--r--src/java/org/apache/poi/hssf/record/TableRecord.java16
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java285
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java11
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java48
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java131
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java3
-rw-r--r--src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java313
-rw-r--r--src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java107
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java20
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFCell.java30
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java5
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java6
-rw-r--r--src/java/org/apache/poi/hssf/util/CellRangeAddress8Bit.java25
-rw-r--r--src/java/org/apache/poi/hssf/util/CellRangeAddressList.java4
-rw-r--r--src/java/org/apache/poi/ss/formula/Formula.java133
-rw-r--r--src/java/org/apache/poi/ss/util/CellRangeAddress.java18
-rw-r--r--src/java/org/apache/poi/ss/util/CellRangeAddressList.java16
-rw-r--r--src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java5
-rw-r--r--src/java/org/apache/poi/util/LittleEndianOutput.java3
-rw-r--r--src/java/org/apache/poi/util/LittleEndianOutputStream.java8
30 files changed, 1061 insertions, 906 deletions
diff --git a/src/java/org/apache/poi/hssf/record/ArrayRecord.java b/src/java/org/apache/poi/hssf/record/ArrayRecord.java
index 7a04bdf99f..35239bb238 100644
--- a/src/java/org/apache/poi/hssf/record/ArrayRecord.java
+++ b/src/java/org/apache/poi/hssf/record/ArrayRecord.java
@@ -18,8 +18,9 @@
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.ss.formula.Formula;
import org.apache.poi.util.HexDump;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianOutput;
/**
* ARRAY (0x0221)<p/>
@@ -36,14 +37,15 @@ public final class ArrayRecord extends SharedValueRecordBase {
private int _options;
private int _field3notUsed;
- private Ptg[] _formulaTokens;
+ private Formula _formula;
public ArrayRecord(RecordInputStream in) {
super(in);
_options = in.readUShort();
_field3notUsed = in.readInt();
- int formulaLen = in.readUShort();
- _formulaTokens = Ptg.readTokens(formulaLen, in);
+ int formulaTokenLen = in.readUShort();
+ int totalFormulaLen = in.available();
+ _formula = Formula.read(formulaTokenLen, in, totalFormulaLen);
}
public boolean isAlwaysRecalculate() {
@@ -55,18 +57,12 @@ public final class ArrayRecord extends SharedValueRecordBase {
protected int getExtraDataSize() {
return 2 + 4
- + 2 + Ptg.getEncodedSize(_formulaTokens);
+ + _formula.getEncodedSize();
}
- protected void serializeExtraData(int offset, byte[] data) {
- int pos = offset;
- LittleEndian.putUShort(data, pos, _options);
- pos+=2;
- LittleEndian.putInt(data, pos, _field3notUsed);
- pos+=4;
- int tokenSize = Ptg.getEncodedSizeWithoutArrayData(_formulaTokens);
- LittleEndian.putUShort(data, pos, tokenSize);
- pos+=2;
- Ptg.serializePtgs(_formulaTokens, data, pos);
+ protected void serializeExtraData(LittleEndianOutput out) {
+ out.writeShort(_options);
+ out.writeInt(_field3notUsed);
+ _formula.serialize(out);
}
public short getSid() {
@@ -80,8 +76,9 @@ public final class ArrayRecord extends SharedValueRecordBase {
sb.append(" options=").append(HexDump.shortToHex(_options)).append("\n");
sb.append(" notUsed=").append(HexDump.intToHex(_field3notUsed)).append("\n");
sb.append(" formula:").append("\n");
- for (int i = 0; i < _formulaTokens.length; i++) {
- Ptg ptg = _formulaTokens[i];
+ Ptg[] ptgs = _formula.getTokens();
+ for (int i = 0; i < ptgs.length; i++) {
+ Ptg ptg = ptgs[i];
sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
}
sb.append("]");
diff --git a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java
index ef8e05c29d..214ebaa299 100644
--- a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java
+++ b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java
@@ -23,9 +23,10 @@ import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.Formula;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
/**
* Conditional Formatting Rule Record.
@@ -94,18 +95,12 @@ public final class CFRuleRecord extends Record {
private FontFormatting fontFormatting;
- private byte field_8_align_text_break;
- private byte field_9_align_text_rotation_angle;
- private short field_10_align_indentation;
- private short field_11_relative_indentation;
- private short field_12_not_used;
-
private BorderFormatting borderFormatting;
private PatternFormatting patternFormatting;
- private Ptg[] field_17_formula1;
- private Ptg[] field_18_formula2;
+ private Formula field_17_formula1;
+ private Formula field_18_formula2;
/** Creates new CFRuleRecord */
private CFRuleRecord(byte conditionType, byte comparisonOperation)
@@ -121,23 +116,18 @@ public final class CFRuleRecord extends Record {
field_6_not_used = (short)0x8002; // Excel seems to write this value, but it doesn't seem to care what it reads
fontFormatting=null;
- field_8_align_text_break = 0;
- field_9_align_text_rotation_angle = 0;
- field_10_align_indentation = 0;
- field_11_relative_indentation = 0;
- field_12_not_used = 0;
borderFormatting=null;
patternFormatting=null;
- field_17_formula1=null;
- field_18_formula2=null;
+ field_17_formula1=Formula.create(Ptg.EMPTY_PTG_ARRAY);
+ field_18_formula2=Formula.create(Ptg.EMPTY_PTG_ARRAY);
}
private CFRuleRecord(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] formula2) {
this(conditionType, comparisonOperation);
field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS;
field_2_comparison_operator = comparisonOperation;
- field_17_formula1 = formula1;
- field_18_formula2 = formula2;
+ field_17_formula1 = Formula.create(formula1);
+ field_18_formula2 = Formula.create(formula2);
}
/**
@@ -178,12 +168,9 @@ public final class CFRuleRecord extends Record {
patternFormatting = new PatternFormatting(in);
}
- if (field_3_formula1_len > 0) {
- field_17_formula1 = Ptg.readTokens(field_3_formula1_len, in);
- }
- if (field_4_formula2_len > 0) {
- field_18_formula2 = Ptg.readTokens(field_4_formula2_len, in);
- }
+ // "You may not use unions, intersections or array constants in Conditional Formatting criteria"
+ field_17_formula1 = Formula.read(field_3_formula1_len, in);
+ field_18_formula2 = Formula.read(field_4_formula2_len, in);
}
public byte getConditionType()
@@ -414,33 +401,22 @@ public final class CFRuleRecord extends Record {
public Ptg[] getParsedExpression1()
{
- return field_17_formula1;
+ return field_17_formula1.getTokens();
}
public void setParsedExpression1(Ptg[] ptgs) {
- field_17_formula1 = safeClone(ptgs);
- }
- private static Ptg[] safeClone(Ptg[] ptgs) {
- if (ptgs == null) {
- return null;
- }
- return (Ptg[]) ptgs.clone();
+ field_17_formula1 = Formula.create(ptgs);
}
/**
* get the stack of the 2nd expression as a list
*
- * @return list of tokens (casts stack to a list and returns it!)
- * this method can return null is we are unable to create Ptgs from
- * existing excel file
- * callers should check for null!
+ * @return array of {@link Ptg}s, possibly <code>null</code>
*/
-
- public Ptg[] getParsedExpression2()
- {
- return field_18_formula2;
+ public Ptg[] getParsedExpression2() {
+ return Formula.getTokens(field_18_formula2);
}
public void setParsedExpression2(Ptg[] ptgs) {
- field_18_formula2 = safeClone(ptgs);
+ field_18_formula2 = Formula.create(ptgs);
}
public short getSid()
@@ -449,14 +425,11 @@ public final class CFRuleRecord extends Record {
}
/**
- * @param ptgs may be <code>null</code>
- * @return encoded size of the formula
+ * @param ptgs must not be <code>null</code>
+ * @return encoded size of the formula tokens (does not include 2 bytes for ushort length)
*/
- private static int getFormulaSize(Ptg[] ptgs) {
- if (ptgs == null) {
- return 0;
- }
- return Ptg.getEncodedSize(ptgs);
+ private static int getFormulaSize(Formula formula) {
+ return formula.getEncodedTokenSize();
}
/**
@@ -468,51 +441,43 @@ public final class CFRuleRecord extends Record {
* @param data byte array containing instance data
* @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 recordsize = getRecordSize();
- LittleEndian.putShort(data, 0 + offset, sid);
- LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4));
- data[4 + offset] = field_1_condition_type;
- data[5 + offset] = field_2_comparison_operator;
- LittleEndian.putUShort(data, 6 + offset, formula1Len);
- LittleEndian.putUShort(data, 8 + offset, formula2Len);
- LittleEndian.putInt(data, 10 + offset, field_5_options);
- LittleEndian.putShort(data,14 + offset, field_6_not_used);
- offset += 16;
+ LittleEndianByteArrayOutputStream out = new LittleEndianByteArrayOutputStream(data, pOffset, recordsize);
- if( containsFontFormattingBlock() )
- {
+ out.writeShort(sid);
+ out.writeShort(recordsize-4);
+ out.writeByte(field_1_condition_type);
+ out.writeByte(field_2_comparison_operator);
+ out.writeShort(formula1Len);
+ out.writeShort(formula2Len);
+ out.writeInt(field_5_options);
+ out.writeShort(field_6_not_used);
+
+ if (containsFontFormattingBlock()) {
byte[] fontFormattingRawRecord = fontFormatting.getRawRecord();
- System.arraycopy(fontFormattingRawRecord, 0, data, offset, fontFormattingRawRecord.length);
- offset += fontFormattingRawRecord.length;
+ out.write(fontFormattingRawRecord);
}
- if( containsBorderFormattingBlock())
- {
- offset += borderFormatting.serialize(offset, data);
+ if (containsBorderFormattingBlock()) {
+ borderFormatting.serialize(out);
}
- if( containsPatternFormattingBlock() )
- {
- offset += patternFormatting.serialize(offset, data);
+ if (containsPatternFormattingBlock()) {
+ patternFormatting.serialize(out);
}
- if (field_17_formula1 != null) {
- offset += Ptg.serializePtgs(field_17_formula1, data, offset);
- }
-
- if (field_18_formula2 != null) {
- offset += Ptg.serializePtgs(field_18_formula2, data, offset);
- }
- if(offset - pOffset != recordsize) {
- throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")");
+ field_17_formula1.serializeTokens(out);
+ field_18_formula2.serializeTokens(out);
+
+ if(out.getWriteIndex() - pOffset != recordsize) {
+ throw new IllegalStateException("write mismatch ("
+ + (out.getWriteIndex() - pOffset) + "!=" + recordsize + ")");
}
return recordsize;
}
@@ -531,25 +496,22 @@ public final class CFRuleRecord extends Record {
}
- public String toString()
- {
+ public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[CFRULE]\n");
buffer.append(" OPTION FLAGS=0x"+Integer.toHexString(getOptions()));
- /*
- if( containsFontFormattingBlock())
- {
- buffer.append(fontFormatting.toString());
+ if (false) {
+ if (containsFontFormattingBlock()) {
+ buffer.append(fontFormatting.toString());
+ }
+ if (containsBorderFormattingBlock()) {
+ buffer.append(borderFormatting.toString());
+ }
+ if (containsPatternFormattingBlock()) {
+ buffer.append(patternFormatting.toString());
+ }
+ buffer.append("[/CFRULE]\n");
}
- if( containsBorderFormattingBlock())
- {
- buffer.append(borderFormatting.toString());
- }
- if( containsPatternFormattingBlock())
- {
- buffer.append(patternFormatting.toString());
- }
- buffer.append("[/CFRULE]\n");*/
return buffer.toString();
}
@@ -566,12 +528,8 @@ public final class CFRuleRecord extends Record {
if (containsPatternFormattingBlock()) {
rec.patternFormatting = (PatternFormatting) patternFormatting.clone();
}
- if (field_17_formula1 != null) {
- rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone();
- }
- if (field_18_formula2 != null) {
- rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone();
- }
+ rec.field_17_formula1 = field_17_formula1.copy();
+ rec.field_18_formula2 = field_17_formula1.copy();
return rec;
}
diff --git a/src/java/org/apache/poi/hssf/record/DVRecord.java b/src/java/org/apache/poi/hssf/record/DVRecord.java
index da34e5425a..c2c0c1f6e9 100644
--- a/src/java/org/apache/poi/hssf/record/DVRecord.java
+++ b/src/java/org/apache/poi/hssf/record/DVRecord.java
@@ -16,14 +16,16 @@
package org.apache.poi.hssf.record;
-import org.apache.poi.hssf.record.UnicodeString.UnicodeRecordStats;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.usermodel.DVConstraint;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.ss.formula.Formula;
import org.apache.poi.util.BitField;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianOutput;
+import org.apache.poi.util.StringUtil;
/**
* Title: DATAVALIDATION Record (0x01BE)<p/>
@@ -53,11 +55,11 @@ public final class DVRecord extends Record {
/** Not used - Excel seems to always write 0x3FE0 */
private short _not_used_1 = 0x3FE0;
/** Formula data for first condition (RPN token array without size field) */
- private Ptg[] _formula1;
+ private Formula _formula1;
/** Not used - Excel seems to always write 0x0000 */
private short _not_used_2 = 0x0000;
/** Formula data for second condition (RPN token array without size field) */
- private Ptg[] _formula2;
+ private Formula _formula2;
/** Cell range address list with all affected ranges */
private CellRangeAddressList _regions;
@@ -96,34 +98,36 @@ public final class DVRecord extends Record {
_promptText = resolveTitleText(promptText);
_errorTitle = resolveTitleText(errorTitle);
_errorText = resolveTitleText(errorText);
- _formula1 = formula1;
- _formula2 = formula2;
+ _formula1 = Formula.create(formula1);
+ _formula2 = Formula.create(formula2);
_regions = regions;
}
public DVRecord(RecordInputStream in) {
-
- _option_flags = in.readInt();
-
- _promptTitle = readUnicodeString(in);
- _errorTitle = readUnicodeString(in);
- _promptText = readUnicodeString(in);
- _errorText = readUnicodeString(in);
- int field_size_first_formula = in.readUShort();
- _not_used_1 = in.readShort();
+ _option_flags = in.readInt();
+
+ _promptTitle = readUnicodeString(in);
+ _errorTitle = readUnicodeString(in);
+ _promptText = readUnicodeString(in);
+ _errorText = readUnicodeString(in);
+
+ int field_size_first_formula = in.readUShort();
+ _not_used_1 = in.readShort();
- //read first formula data condition
- _formula1 = Ptg.readTokens(field_size_first_formula, in);
+ // "You may not use unions, intersections or array constants in Data Validation criteria"
- int field_size_sec_formula = in.readUShort();
- _not_used_2 = in.readShort();
+ // read first formula data condition
+ _formula1 = Formula.read(field_size_first_formula, in);
- //read sec formula data condition
- _formula2 = Ptg.readTokens(field_size_sec_formula, in);
+ int field_size_sec_formula = in.readUShort();
+ _not_used_2 = in.readShort();
- //read cell range address list with all affected ranges
- _regions = new org.apache.poi.hssf.util.CellRangeAddressList(in);
+ // read sec formula data condition
+ _formula2 = Formula.read(field_size_sec_formula, in);
+
+ // read cell range address list with all affected ranges
+ _regions = new CellRangeAddressList(in);
}
// --> start option flags
@@ -235,45 +239,43 @@ public final class DVRecord extends Record {
return str;
}
- private void appendFormula(StringBuffer sb, String label, Ptg[] ptgs) {
+ private static void appendFormula(StringBuffer sb, String label, Formula f) {
sb.append(label);
- if (ptgs.length < 1) {
+
+ if (f == null) {
sb.append("<empty>\n");
return;
}
- sb.append("\n");
+ Ptg[] ptgs = f.getTokens();
+ sb.append('\n');
for (int i = 0; i < ptgs.length; i++) {
sb.append('\t').append(ptgs[i].toString()).append('\n');
}
}
public int serialize(int offset, byte [] data) {
- int size = this.getRecordSize();
- LittleEndian.putShort(data, 0 + offset, sid);
- LittleEndian.putShort(data, 2 + offset, ( short ) (size-4));
+ int recSize = getRecordSize();
+ LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
+
+ out.writeShort(sid);
+ out.writeShort(recSize-4);
- int pos = 4;
- LittleEndian.putInt(data, pos + offset, _option_flags);
- pos += 4;
+ out.writeInt(_option_flags);
- pos += serializeUnicodeString(_promptTitle, pos+offset, data);
- pos += serializeUnicodeString(_errorTitle, pos+offset, data);
- pos += serializeUnicodeString(_promptText, pos+offset, data);
- pos += serializeUnicodeString(_errorText, pos+offset, data);
- LittleEndian.putUShort(data, offset+pos, Ptg.getEncodedSize(_formula1));
- pos += 2;
- LittleEndian.putUShort(data, offset+pos, _not_used_1);
- pos += 2;
-
- pos += Ptg.serializePtgs(_formula1, data, pos+offset);
-
- LittleEndian.putUShort(data, offset+pos, Ptg.getEncodedSize(_formula2));
- pos += 2;
- LittleEndian.putShort(data, offset+pos, _not_used_2);
- pos += 2;
- pos += Ptg.serializePtgs(_formula2, data, pos+offset);
- _regions.serialize(pos+offset, data);
- return size;
+ serializeUnicodeString(_promptTitle, out);
+ serializeUnicodeString(_errorTitle, out);
+ serializeUnicodeString(_promptText, out);
+ serializeUnicodeString(_errorText, out);
+ out.writeShort(_formula1.getEncodedTokenSize());
+ out.writeShort(_not_used_1);
+ _formula1.serializeTokens(out);
+
+ out.writeShort(_formula2.getEncodedTokenSize());
+ out.writeShort(_not_used_2);
+ _formula2.serializeTokens(out);
+
+ _regions.serialize(out);
+ return recSize;
}
/**
@@ -293,13 +295,12 @@ public final class DVRecord extends Record {
return new UnicodeString(in);
}
- private static int serializeUnicodeString(UnicodeString us, int offset, byte[] data) {
- UnicodeRecordStats urs = new UnicodeRecordStats();
- us.serialize(urs, offset, data);
- return urs.recordSize;
+ private static void serializeUnicodeString(UnicodeString us, LittleEndianOutput out) {
+ StringUtil.writeUnicodeString(out, us.getString());
}
- private static int getUnicodeStringSize(UnicodeString str) {
- return 3 + str.getString().length();
+ private static int getUnicodeStringSize(UnicodeString us) {
+ String str = us.getString();
+ return 3 + str.length() * (StringUtil.hasMultibyte(str) ? 2 : 1);
}
public int getRecordSize() {
@@ -308,8 +309,8 @@ public final class DVRecord extends Record {
size += getUnicodeStringSize(_errorTitle);
size += getUnicodeStringSize(_promptText);
size += getUnicodeStringSize(_errorText);
- size += Ptg.getEncodedSize(_formula1);
- size += Ptg.getEncodedSize(_formula2);
+ size += _formula1.getEncodedTokenSize();
+ size += _formula2.getEncodedTokenSize();
size += _regions.getSize();
return size;
}
diff --git a/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java b/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
index 4d7f312bd5..a3dfe575c1 100755
--- a/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
+++ b/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
@@ -17,20 +17,19 @@
package org.apache.poi.hssf.record;
-import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.Formula;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;
/**
- * EXTERNALNAME<p/>
+ * EXTERNALNAME (0x0023)<p/>
*
* @author Josh Micich
*/
public final class ExternalNameRecord extends Record {
- private static final Ptg[] EMPTY_PTG_ARRAY = { };
-
- public final static short sid = 0x23; // as per BIFF8. (some old versions used 0x223)
+ public final static short sid = 0x0023; // as per BIFF8. (some old versions used 0x223)
private static final int OPT_BUILTIN_NAME = 0x0001;
private static final int OPT_AUTOMATIC_LINK = 0x0002; // m$ doc calls this fWantAdvise
@@ -45,7 +44,7 @@ public final class ExternalNameRecord extends Record {
private short field_2_index;
private short field_3_not_used;
private String field_4_name;
- private Ptg[] field_5_name_definition;
+ private Formula field_5_name_definition;
/**
* Convenience Function to determine if the name is a built-in name
@@ -88,7 +87,7 @@ public final class ExternalNameRecord extends Record {
int result = 3 * 2 // 3 short fields
+ 2 + field_4_name.length(); // nameLen and name
if(hasFormula()) {
- result += 2 + getNameDefinitionSize(); // nameDefLen and nameDef
+ result += field_5_name_definition.getEncodedSize();
}
return result;
}
@@ -104,28 +103,23 @@ public final class ExternalNameRecord extends Record {
*/
public int serialize( int offset, byte[] data ) {
int dataSize = getDataSize();
-
- LittleEndian.putShort( data, 0 + offset, sid );
- LittleEndian.putShort( data, 2 + offset, (short) dataSize );
- LittleEndian.putShort( data, 4 + offset, field_1_option_flag );
- LittleEndian.putShort( data, 6 + offset, field_2_index );
- LittleEndian.putShort( data, 8 + offset, field_3_not_used );
+ int recSize = dataSize + 4;
+ LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
+
+ out.writeShort(sid);
+ out.writeShort(dataSize);
+ out.writeShort(field_1_option_flag);
+ out.writeShort(field_2_index);
+ out.writeShort(field_3_not_used);
int nameLen = field_4_name.length();
- LittleEndian.putUShort( data, 10 + offset, nameLen );
- StringUtil.putCompressedUnicode( field_4_name, data, 12 + offset );
- if(hasFormula()) {
- int defLen = getNameDefinitionSize();
- LittleEndian.putUShort( data, 12 + nameLen + offset, defLen );
- Ptg.serializePtgs(field_5_name_definition, data, 14 + nameLen + offset );
+ out.writeShort(nameLen);
+ StringUtil.putCompressedUnicode(field_4_name, out);
+ if (hasFormula()) {
+ field_5_name_definition.serialize(out);
}
- return dataSize + 4;
+ return recSize;
}
- private int getNameDefinitionSize() {
- return Ptg.getEncodedSize(field_5_name_definition);
- }
-
-
public int getRecordSize(){
return 4 + getDataSize();
}
@@ -141,14 +135,16 @@ public final class ExternalNameRecord extends Record {
if(in.remaining() > 0) {
throw readFail("Some unread data (is formula present?)");
}
- field_5_name_definition = EMPTY_PTG_ARRAY;
+ field_5_name_definition = null;
return;
}
- if(in.remaining() <= 0) {
+ int nBytesRemaining = in.available();
+ if(nBytesRemaining <= 0) {
throw readFail("Ran out of record data trying to read formula.");
}
- short formulaLen = in.readShort();
- field_5_name_definition = Ptg.readTokens(formulaLen, in);
+ int formulaLen = in.readUShort();
+ nBytesRemaining -=2;
+ field_5_name_definition = Formula.read(formulaLen, in, nBytesRemaining);
}
/*
* Makes better error messages (while hasFormula() is not reliable)
@@ -157,7 +153,7 @@ public final class ExternalNameRecord extends Record {
private RuntimeException readFail(String msg) {
String fullMsg = msg + " fields: (option=" + field_1_option_flag + " index=" + field_2_index
+ " not_used=" + field_3_not_used + " name='" + field_4_name + "')";
- return new RuntimeException(fullMsg);
+ return new RecordFormatException(fullMsg);
}
private boolean hasFormula() {
diff --git a/src/java/org/apache/poi/hssf/record/FormulaRecord.java b/src/java/org/apache/poi/hssf/record/FormulaRecord.java
index a6c97d46ef..e51ed77a96 100644
--- a/src/java/org/apache/poi/hssf/record/FormulaRecord.java
+++ b/src/java/org/apache/poi/hssf/record/FormulaRecord.java
@@ -20,10 +20,13 @@ package org.apache.poi.hssf.record;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.ss.formula.Formula;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Formula Record (0x0006).
@@ -35,7 +38,7 @@ import org.apache.poi.util.LittleEndian;
public final class FormulaRecord extends Record implements CellValueRecordInterface {
public static final short sid = 0x0006; // docs say 406...because of a bug Microsoft support site article #Q184647)
- private static int FIXED_SIZE = 22;
+ private static int FIXED_SIZE = 20;
private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
private static final BitField calcOnLoad = BitFieldFactory.getInstance(0x0002);
@@ -92,9 +95,9 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf
}
return new SpecialCachedValue(result);
}
- public void serialize(byte[] data, int offset) {
- System.arraycopy(_variableData, 0, data, offset, VARIABLE_DATA_LENGTH);
- LittleEndian.putUShort(data, offset+VARIABLE_DATA_LENGTH, 0xFFFF);
+ public void serialize(LittleEndianOutput out) {
+ out.write(_variableData);
+ out.writeShort(0xFFFF);
}
public String formatDebugString() {
return formatValue() + ' ' + HexDump.toHex(_variableData);
@@ -172,8 +175,13 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf
private short field_3_xf;
private double field_4_value;
private short field_5_options;
- private int field_6_zero;
- private Ptg[] field_8_parsed_expr;
+ /**
+ * Unused field. As it turns out this field is often not zero..
+ * According to Microsoft Excel Developer's Kit Page 318:
+ * when writing the chn field (offset 20), it's supposed to be 0 but ignored on read
+ */
+ private int field_6_zero;
+ private Formula field_8_parsed_expr;
/**
* Since the NaN support seems sketchy (different constants) we'll store and spit it out directly
@@ -183,13 +191,14 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf
/** Creates new FormulaRecord */
public FormulaRecord() {
- field_8_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
+ field_8_parsed_expr = Formula.create(Ptg.EMPTY_PTG_ARRAY);
}
- public FormulaRecord(RecordInputStream in) {
- field_1_row = in.readUShort();
- field_2_column = in.readShort();
- field_3_xf = in.readShort();
+ public FormulaRecord(RecordInputStream ris) {
+ LittleEndianInput in = ris;
+ field_1_row = in.readUShort();
+ field_2_column = in.readShort();
+ field_3_xf = in.readShort();
long valueLongBits = in.readLong();
field_5_options = in.readShort();
specialCachedValue = SpecialCachedValue.create(valueLongBits);
@@ -197,14 +206,11 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf
field_4_value = Double.longBitsToDouble(valueLongBits);
}
- field_6_zero = in.readInt();
+ field_6_zero = in.readInt();
+
int field_7_expression_len = in.readShort(); // this length does not include any extra array data
- field_8_parsed_expr = Ptg.readTokens(field_7_expression_len, in);
- if (in.remaining() == 10) {
- // TODO - this seems to occur when IntersectionPtg is present
- // 10 extra bytes are just 0x01 and 0x00
- // This causes POI stderr: "WARN. Unread 10 bytes of record 0x6"
- }
+ int nBytesAvailable = in.available();
+ field_8_parsed_expr = Formula.read(field_7_expression_len, in, nBytesAvailable);
}
@@ -336,11 +342,11 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf
* @return the formula tokens. never <code>null</code>
*/
public Ptg[] getParsedExpression() {
- return (Ptg[]) field_8_parsed_expr.clone();
+ return field_8_parsed_expr.getTokens();
}
public void setParsedExpression(Ptg[] ptgs) {
- field_8_parsed_expr = ptgs;
+ field_8_parsed_expr = Formula.create(ptgs);
}
public short getSid() {
@@ -348,33 +354,30 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf
}
private int getDataSize() {
- return FIXED_SIZE + Ptg.getEncodedSize(field_8_parsed_expr);
+ return FIXED_SIZE + field_8_parsed_expr.getEncodedSize();
}
public int serialize(int offset, byte [] data) {
int dataSize = getDataSize();
-
- LittleEndian.putShort(data, 0 + offset, sid);
- LittleEndian.putUShort(data, 2 + offset, dataSize);
- LittleEndian.putUShort(data, 4 + offset, getRow());
- LittleEndian.putShort(data, 6 + offset, getColumn());
- LittleEndian.putShort(data, 8 + offset, getXFIndex());
+ int recSize = 4 + dataSize;
+ LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
+ out.writeShort(sid);
+ out.writeShort(dataSize);
+ out.writeShort(getRow());
+ out.writeShort(getColumn());
+ out.writeShort(getXFIndex());
if (specialCachedValue == null) {
- LittleEndian.putDouble(data, 10 + offset, field_4_value);
+ out.writeDouble(field_4_value);
} else {
- specialCachedValue.serialize(data, 10+offset);
+ specialCachedValue.serialize(out);
}
- LittleEndian.putShort(data, 18 + offset, getOptions());
+ out.writeShort(getOptions());
- //when writing the chn field (offset 20), it's supposed to be 0 but ignored on read
- //Microsoft Excel Developer's Kit Page 318
- LittleEndian.putInt(data, 20 + offset, 0);
- int formulaTokensSize = Ptg.getEncodedSizeWithoutArrayData(field_8_parsed_expr);
- LittleEndian.putUShort(data, 24 + offset, formulaTokensSize);
- Ptg.serializePtgs(field_8_parsed_expr, data, 26+offset);
- return 4 + dataSize;
+ out.writeInt(field_6_zero); // may as well write original data back so as to minimise differences from original
+ field_8_parsed_expr.serialize(out);
+ return recSize;
}
public int getRecordSize() {
@@ -385,24 +388,25 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf
StringBuffer sb = new StringBuffer();
sb.append("[FORMULA]\n");
- sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n");
- sb.append(" .column = ").append(HexDump.shortToHex(getColumn())).append("\n");
- sb.append(" .xf = ").append(HexDump.shortToHex(getXFIndex())).append("\n");
- sb.append(" .value = ");
+ sb.append(" .row = ").append(HexDump.shortToHex(getRow())).append("\n");
+ sb.append(" .column = ").append(HexDump.shortToHex(getColumn())).append("\n");
+ sb.append(" .xf = ").append(HexDump.shortToHex(getXFIndex())).append("\n");
+ sb.append(" .value = ");
if (specialCachedValue == null) {
sb.append(field_4_value).append("\n");
} else {
sb.append(specialCachedValue.formatDebugString()).append("\n");
}
- sb.append(" .options = ").append(HexDump.shortToHex(getOptions())).append("\n");
- sb.append(" .alwaysCalc= ").append(alwaysCalc.isSet(getOptions())).append("\n");
- sb.append(" .calcOnLoad= ").append(calcOnLoad.isSet(getOptions())).append("\n");
- sb.append(" .shared = ").append(sharedFormula.isSet(getOptions())).append("\n");
- sb.append(" .zero = ").append(HexDump.intToHex(field_6_zero)).append("\n");
-
- for (int k = 0; k < field_8_parsed_expr.length; k++ ) {
- sb.append(" Ptg[").append(k).append("]=");
- Ptg ptg = field_8_parsed_expr[k];
+ sb.append(" .options = ").append(HexDump.shortToHex(getOptions())).append("\n");
+ sb.append(" .alwaysCalc= ").append(isAlwaysCalc()).append("\n");
+ sb.append(" .calcOnLoad= ").append(isCalcOnLoad()).append("\n");
+ sb.append(" .shared = ").append(isSharedFormula()).append("\n");
+ sb.append(" .zero = ").append(HexDump.intToHex(field_6_zero)).append("\n");
+
+ Ptg[] ptgs = field_8_parsed_expr.getTokens();
+ for (int k = 0; k < ptgs.length; k++ ) {
+ sb.append(" Ptg[").append(k).append("]=");
+ Ptg ptg = ptgs[k];
sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
}
sb.append("[/FORMULA]\n");
@@ -417,12 +421,7 @@ public final class FormulaRecord extends Record implements CellValueRecordInterf
rec.field_4_value = field_4_value;
rec.field_5_options = field_5_options;
rec.field_6_zero = field_6_zero;
- int nTokens = field_8_parsed_expr.length;
- Ptg[] ptgs = new Ptg[nTokens];
- for (int i = 0; i < nTokens; i++) {
- ptgs[i] = field_8_parsed_expr[i].copy();
- }
- rec.field_8_parsed_expr = ptgs;
+ rec.field_8_parsed_expr = field_8_parsed_expr;
rec.specialCachedValue = specialCachedValue;
return rec;
}
diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java
index 0c2d17b496..99e2cddd70 100644
--- a/src/java/org/apache/poi/hssf/record/NameRecord.java
+++ b/src/java/org/apache/poi/hssf/record/NameRecord.java
@@ -27,9 +27,11 @@ import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.RangeAddress;
+import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.util.HexDump;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.StringUtil;
/**
@@ -89,7 +91,7 @@ public final class NameRecord extends Record {
private boolean field_11_nameIsMultibyte;
private byte field_12_built_in_code;
private String field_12_name_text;
- private Ptg[] field_13_name_definition;
+ private Formula field_13_name_definition;
private String field_14_custom_menu_text;
private String field_15_description_text;
private String field_16_help_topic_text;
@@ -98,7 +100,7 @@ public final class NameRecord extends Record {
/** Creates new NameRecord */
public NameRecord() {
- field_13_name_definition = Ptg.EMPTY_PTG_ARRAY;
+ field_13_name_definition = Formula.create(Ptg.EMPTY_PTG_ARRAY);
field_12_name_text = "";
field_14_custom_menu_text = "";
@@ -245,7 +247,7 @@ public final class NameRecord extends Record {
* @return <code>true</code> if name has a formula (named range or defined value)
*/
public boolean hasFormula() {
- return field_1_option_flag == 0 && field_13_name_definition.length > 0;
+ return field_1_option_flag == 0 && field_13_name_definition.getEncodedTokenSize() > 0;
}
/**
@@ -296,11 +298,11 @@ public final class NameRecord extends Record {
* @return the name formula. never <code>null</code>
*/
public Ptg[] getNameDefinition() {
- return (Ptg[]) field_13_name_definition.clone();
+ return field_13_name_definition.getTokens();
}
public void setNameDefinition(Ptg[] ptgs) {
- field_13_name_definition = (Ptg[]) ptgs.clone();
+ field_13_name_definition = Formula.create(ptgs);
}
/** get the custom menu text
@@ -346,9 +348,9 @@ public final class NameRecord extends Record {
int field_9_length_help_topic_text = field_16_help_topic_text.length();
int field_10_length_status_bar_text = field_17_status_bar_text.length();
int rawNameSize = getNameRawSize();
-
- int formulaTotalSize = Ptg.getEncodedSize(field_13_name_definition);
- int dataSize = 15 // 4 shorts + 7 bytes
+
+ int formulaTotalSize = field_13_name_definition.getEncodedSize();
+ int dataSize = 13 // 3 shorts + 7 bytes
+ rawNameSize
+ field_7_length_custom_menu
+ field_8_length_description_text
@@ -356,48 +358,45 @@ public final class NameRecord extends Record {
+ field_10_length_status_bar_text
+ formulaTotalSize;
- LittleEndian.putShort(data, 0 + offset, sid);
- LittleEndian.putUShort(data, 2 + offset, dataSize);
+ int recSize = 4 + dataSize;
+ LittleEndianByteArrayOutputStream out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
+
+ out.writeShort(sid);
+ out.writeShort(dataSize);
// size defined below
- LittleEndian.putShort(data, 4 + offset, getOptionFlag());
- LittleEndian.putByte(data, 6 + offset, getKeyboardShortcut());
- LittleEndian.putByte(data, 7 + offset, getNameTextLength());
- // Note -
- LittleEndian.putUShort(data, 8 + offset, Ptg.getEncodedSizeWithoutArrayData(field_13_name_definition));
- LittleEndian.putUShort(data, 10 + offset, field_5_externSheetIndex_plus1);
- LittleEndian.putUShort(data, 12 + offset, field_6_sheetNumber);
- LittleEndian.putByte(data, 14 + offset, field_7_length_custom_menu);
- LittleEndian.putByte(data, 15 + offset, field_8_length_description_text);
- LittleEndian.putByte(data, 16 + offset, field_9_length_help_topic_text);
- LittleEndian.putByte(data, 17 + offset, field_10_length_status_bar_text);
- LittleEndian.putByte(data, 18 + offset, field_11_nameIsMultibyte ? 1 : 0);
- int pos = 19 + offset;
+ out.writeShort(getOptionFlag());
+ out.writeByte(getKeyboardShortcut());
+ out.writeByte(getNameTextLength());
+ // Note - formula size is not immediately before encoded formula, and does not include any array constant data
+ out.writeShort(field_13_name_definition.getEncodedTokenSize());
+ out.writeShort(field_5_externSheetIndex_plus1);
+ out.writeShort(field_6_sheetNumber);
+ out.writeByte(field_7_length_custom_menu);
+ out.writeByte(field_8_length_description_text);
+ out.writeByte(field_9_length_help_topic_text);
+ out.writeByte(field_10_length_status_bar_text);
+ out.writeByte(field_11_nameIsMultibyte ? 1 : 0);
if (isBuiltInName()) {
//can send the builtin name directly in
- LittleEndian.putByte(data, pos, field_12_built_in_code);
+ out.writeByte(field_12_built_in_code);
} else {
String nameText = field_12_name_text;
if (field_11_nameIsMultibyte) {
- StringUtil.putUnicodeLE(nameText, data, pos);
- } else {
- StringUtil.putCompressedUnicode(nameText, data, pos);
- }
+ StringUtil.putUnicodeLE(nameText, out);
+ } else {
+ StringUtil.putCompressedUnicode(nameText, out);
+ }
}
- pos += rawNameSize;
-
- Ptg.serializePtgs(field_13_name_definition, data, pos);
- pos += formulaTotalSize;
+ field_13_name_definition.serializeTokens(out);
+ field_13_name_definition.serializeArrayConstantData(out);
- StringUtil.putCompressedUnicode( getCustomMenuText(), data, pos);
- pos += field_7_length_custom_menu;
- StringUtil.putCompressedUnicode( getDescriptionText(), data, pos);
- pos += field_8_length_description_text;
- StringUtil.putCompressedUnicode( getHelpTopicText(), data, pos);
- pos += field_9_length_help_topic_text;
- StringUtil.putCompressedUnicode( getStatusBarText(), data, pos);
+ StringUtil.putCompressedUnicode( getCustomMenuText(), out);
+ StringUtil.putCompressedUnicode( getDescriptionText(), out);
+ StringUtil.putCompressedUnicode( getHelpTopicText(), out);
+ StringUtil.putCompressedUnicode( getStatusBarText(), out);
- return 4 + dataSize;
+ return recSize;
}
private int getNameRawSize() {
if (isBuiltInName()) {
@@ -412,23 +411,23 @@ public final class NameRecord extends Record {
public int getRecordSize(){
return 4 // sid + size
- + 15 // 4 shorts + 7 bytes
+ + 13 // 3 shorts + 7 bytes
+ getNameRawSize()
+ field_14_custom_menu_text.length()
+ field_15_description_text.length()
+ field_16_help_topic_text.length()
+ field_17_status_bar_text.length()
- + Ptg.getEncodedSize(field_13_name_definition);
+ + field_13_name_definition.getEncodedSize();
}
/** gets the extern sheet number
* @return extern sheet index
*/
public int getExternSheetNumber(){
- if (field_13_name_definition.length < 1) {
+ if (field_13_name_definition.getEncodedSize() < 1) {
return 0;
}
- Ptg ptg = field_13_name_definition[0];
+ Ptg ptg = field_13_name_definition.getTokens()[0];
if (ptg.getClass() == Area3DPtg.class){
return ((Area3DPtg) ptg).getExternSheetIndex();
@@ -444,15 +443,14 @@ public final class NameRecord extends Record {
* @param externSheetNumber extern sheet number
*/
public void setExternSheetNumber(short externSheetNumber){
+ Ptg[] ptgs = field_13_name_definition.getTokens();
Ptg ptg;
- if (field_13_name_definition.length < 1){
+ if (ptgs.length < 1){
ptg = createNewPtg();
- field_13_name_definition = new Ptg[] {
- ptg,
- };
+ ptgs = new Ptg[] { ptg, };
} else {
- ptg = field_13_name_definition[0];
+ ptg = ptgs[0];
}
if (ptg.getClass() == Area3DPtg.class){
@@ -461,7 +459,7 @@ public final class NameRecord extends Record {
} else if (ptg.getClass() == Ref3DPtg.class){
((Ref3DPtg) ptg).setExternSheetIndex(externSheetNumber);
}
-
+ field_13_name_definition = Formula.create(ptgs);
}
private static Ptg createNewPtg(){
@@ -472,7 +470,7 @@ public final class NameRecord extends Record {
* @return area reference
*/
public String getAreaReference(HSSFWorkbook book){
- return HSSFFormulaParser.toFormulaString(book, field_13_name_definition);
+ return HSSFFormulaParser.toFormulaString(book, field_13_name_definition.getTokens());
}
/** sets the reference , the area only (range)
@@ -483,11 +481,11 @@ public final class NameRecord extends Record {
RangeAddress ra = new RangeAddress(ref);
Ptg oldPtg;
- if (field_13_name_definition.length < 1){
+ if (field_13_name_definition.getEncodedTokenSize() < 1){
oldPtg = createNewPtg();
} else {
//Trying to find extern sheet index
- oldPtg = field_13_name_definition[0];
+ oldPtg = field_13_name_definition.getTokens()[0];
}
List temp = new ArrayList();
int externSheetIndex = 0;
@@ -519,7 +517,7 @@ public final class NameRecord extends Record {
}
Ptg[] ptgs = new Ptg[temp.size()];
temp.toArray(ptgs);
- field_13_name_definition = ptgs;
+ field_13_name_definition = Formula.create(ptgs);
}
/**
@@ -528,17 +526,18 @@ public final class NameRecord extends Record {
*
* @param in the RecordInputstream to read the record from
*/
- public NameRecord(RecordInputStream in) {
+ public NameRecord(RecordInputStream ris) {
+ LittleEndianInput in = ris;
field_1_option_flag = in.readShort();
field_2_keyboard_shortcut = in.readByte();
int field_3_length_name_text = in.readByte();
int field_4_length_name_definition = in.readShort();
field_5_externSheetIndex_plus1 = in.readShort();
field_6_sheetNumber = in.readUShort();
- int field_7_length_custom_menu = in.readUByte();
- int field_8_length_description_text = in.readUByte();
- int field_9_length_help_topic_text = in.readUByte();
- int field_10_length_status_bar_text = in.readUByte();
+ int f7_customMenuLen = in.readUByte();
+ int f8_descriptionTextLen = in.readUByte();
+ int f9_helpTopicTextLen = in.readUByte();
+ int f10_statusBarTextLen = in.readUByte();
//store the name in byte form if it's a built-in name
field_11_nameIsMultibyte = (in.readByte() != 0);
@@ -546,19 +545,21 @@ public final class NameRecord extends Record {
field_12_built_in_code = in.readByte();
} else {
if (field_11_nameIsMultibyte) {
- field_12_name_text = in.readUnicodeLEString(field_3_length_name_text);
+ field_12_name_text = StringUtil.readUnicodeLE(in, field_3_length_name_text);
} else {
- field_12_name_text = in.readCompressedUnicode(field_3_length_name_text);
+ field_12_name_text = StringUtil.readCompressedUnicode(in, field_3_length_name_text);
}
}
- field_13_name_definition = Ptg.readTokens(field_4_length_name_definition, in);
+ int nBytesAvailable = in.available() - (f7_customMenuLen
+ + f8_descriptionTextLen + f9_helpTopicTextLen + f10_statusBarTextLen);
+ field_13_name_definition = Formula.read(field_4_length_name_definition, in, nBytesAvailable);
//Who says that this can only ever be compressed unicode???
- field_14_custom_menu_text = in.readCompressedUnicode(field_7_length_custom_menu);
- field_15_description_text = in.readCompressedUnicode(field_8_length_description_text);
- field_16_help_topic_text = in.readCompressedUnicode(field_9_length_help_topic_text);
- field_17_status_bar_text = in.readCompressedUnicode(field_10_length_status_bar_text);
+ field_14_custom_menu_text = StringUtil.readCompressedUnicode(in, f7_customMenuLen);
+ field_15_description_text = StringUtil.readCompressedUnicode(in, f8_descriptionTextLen);
+ field_16_help_topic_text = StringUtil.readCompressedUnicode(in, f9_helpTopicTextLen);
+ field_17_status_bar_text = StringUtil.readCompressedUnicode(in, f10_statusBarTextLen);
}
/**
@@ -633,9 +634,10 @@ public final class NameRecord extends Record {
sb.append(" .Status bar text length = ").append(field_17_status_bar_text.length()).append("\n");
sb.append(" .NameIsMultibyte = ").append(field_11_nameIsMultibyte).append("\n");
sb.append(" .Name (Unicode text) = ").append( getNameText() ).append("\n");
- sb.append(" .Formula (nTokens=").append(field_13_name_definition.length).append("):") .append("\n");
- for (int i = 0; i < field_13_name_definition.length; i++) {
- Ptg ptg = field_13_name_definition[i];
+ Ptg[] ptgs = field_13_name_definition.getTokens();
+ sb.append(" .Formula (nTokens=").append(ptgs.length).append("):") .append("\n");
+ for (int i = 0; i < ptgs.length; i++) {
+ Ptg ptg = ptgs[i];
sb.append(" " + ptg.toString()).append(ptg.getRVAType()).append("\n");
}
diff --git a/src/java/org/apache/poi/hssf/record/ObjRecord.java b/src/java/org/apache/poi/hssf/record/ObjRecord.java
index c50f65b61e..538b1ae9f1 100644
--- a/src/java/org/apache/poi/hssf/record/ObjRecord.java
+++ b/src/java/org/apache/poi/hssf/record/ObjRecord.java
@@ -18,15 +18,13 @@
package org.apache.poi.hssf.record;
import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianInputStream;
-import org.apache.poi.util.LittleEndianOutput;
-import org.apache.poi.util.LittleEndianOutputStream;
/**
* OBJRECORD (0x005D)<p/>
@@ -37,10 +35,17 @@ import org.apache.poi.util.LittleEndianOutputStream;
*/
public final class ObjRecord extends Record {
public final static short sid = 0x005D;
+
+ private static final int NORMAL_PAD_ALIGNMENT = 2;
+ private static int MAX_PAD_ALIGNMENT = 4;
private List subrecords;
/** used when POI has no idea what is going on */
private byte[] _uninterpretedData;
+ /**
+ * Excel seems to tolerate padding to quad or double byte length
+ */
+ private boolean _isPaddedToQuadByteMultiple;
//00000000 15 00 12 00 01 00 01 00 11 60 00 00 00 00 00 0D .........`......
//00000010 26 01 00 00 00 00 00 00 00 00 &.........
@@ -71,6 +76,10 @@ public final class ObjRecord extends Record {
_uninterpretedData = subRecordData;
return;
}
+ if (subRecordData.length % 2 != 0) {
+ String msg = "Unexpected length of subRecordData : " + HexDump.toHex(subRecordData);
+ throw new RecordFormatException(msg);
+ }
// System.out.println(HexDump.toHex(subRecordData));
@@ -84,12 +93,17 @@ public final class ObjRecord extends Record {
break;
}
}
- if (bais.available() > 0) {
- // earlier versions of the code had allowances for padding
- // At present (Oct-2008), no unit test samples exhibit such padding
- String msg = "Leftover " + bais.available()
+ int nRemainingBytes = bais.available();
+ if (nRemainingBytes > 0) {
+ // At present (Oct-2008), most unit test samples have (subRecordData.length % 2 == 0)
+ _isPaddedToQuadByteMultiple = subRecordData.length % MAX_PAD_ALIGNMENT == 0;
+ if (nRemainingBytes >= (_isPaddedToQuadByteMultiple ? MAX_PAD_ALIGNMENT : NORMAL_PAD_ALIGNMENT)) {
+ String msg = "Leftover " + nRemainingBytes
+ " bytes in subrecord data " + HexDump.toHex(subRecordData);
- throw new RecordFormatException(msg);
+ throw new RecordFormatException(msg);
+ }
+ } else {
+ _isPaddedToQuadByteMultiple = false;
}
}
@@ -114,34 +128,41 @@ public final class ObjRecord extends Record {
SubRecord record = (SubRecord) subrecords.get(i);
size += record.getDataSize()+4;
}
+ if (_isPaddedToQuadByteMultiple) {
+ while (size % MAX_PAD_ALIGNMENT != 0) {
+ size++;
+ }
+ } else {
+ while (size % NORMAL_PAD_ALIGNMENT != 0) {
+ size++;
+ }
+ }
return size;
}
public int serialize(int offset, byte[] data) {
int dataSize = getDataSize();
+ int recSize = 4 + dataSize;
+ LittleEndianByteArrayOutputStream out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
- LittleEndian.putUShort(data, 0 + offset, sid);
- LittleEndian.putUShort(data, 2 + offset, dataSize);
+ out.writeShort(sid);
+ out.writeShort(dataSize);
- byte[] subRecordBytes;
if (_uninterpretedData == null) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream(dataSize);
- LittleEndianOutput leo = new LittleEndianOutputStream(baos);
for (int i = 0; i < subrecords.size(); i++) {
SubRecord record = (SubRecord) subrecords.get(i);
- record.serialize(leo);
+ record.serialize(out);
}
+ int expectedEndIx = offset+dataSize;
// padding
- while (baos.size() < dataSize) {
- baos.write(0);
+ while (out.getWriteIndex() < expectedEndIx) {
+ out.writeByte(0);
}
- subRecordBytes = baos.toByteArray();
} else {
- subRecordBytes = _uninterpretedData;
+ out.write(_uninterpretedData);
}
- System.arraycopy(subRecordBytes, 0, data, offset + 4, dataSize);
- return 4 + dataSize;
+ return recSize;
}
public int getRecordSize() {
diff --git a/src/java/org/apache/poi/hssf/record/RecordInputStream.java b/src/java/org/apache/poi/hssf/record/RecordInputStream.java
index f9dd2c76c7..b66bf0e96d 100755
--- a/src/java/org/apache/poi/hssf/record/RecordInputStream.java
+++ b/src/java/org/apache/poi/hssf/record/RecordInputStream.java
@@ -355,14 +355,14 @@ public final class RecordInputStream extends InputStream implements LittleEndian
//growable array of the data.
ByteArrayOutputStream out = new ByteArrayOutputStream(2*MAX_RECORD_DATA_SIZE);
- while (isContinueNext()) {
+ while (true) {
byte[] b = readRemainder();
out.write(b, 0, b.length);
+ if (!isContinueNext()) {
+ break;
+ }
nextRecord();
}
- byte[] b = readRemainder();
- out.write(b, 0, b.length);
-
return out.toByteArray();
}
diff --git a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
index 9ede66d957..52b14d3db9 100755
--- a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
+++ b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
@@ -22,7 +22,10 @@ import org.apache.poi.hssf.record.formula.AreaPtg;
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.util.CellRangeAddress8Bit;
+import org.apache.poi.ss.formula.Formula;
import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Title: SHAREDFMLA (0x04BC) SharedFormulaRecord
@@ -39,10 +42,15 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
public final static short sid = 0x04BC;
private int field_5_reserved;
- private Ptg[] field_7_parsed_expr;
+ private Formula field_7_parsed_expr;
+ // for testing only
public SharedFormulaRecord() {
- field_7_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
+ this(new CellRangeAddress8Bit(0,0,0,0));
+ }
+ private SharedFormulaRecord(CellRangeAddress8Bit range) {
+ super(range);
+ field_7_parsed_expr = Formula.create(Ptg.EMPTY_PTG_ARRAY);
}
/**
@@ -52,17 +60,17 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
super(in);
field_5_reserved = in.readShort();
int field_6_expression_len = in.readShort();
- field_7_parsed_expr = Ptg.readTokens(field_6_expression_len, in);
+ int nAvailableBytes = in.available();
+ field_7_parsed_expr = Formula.read(field_6_expression_len, in, nAvailableBytes);
}
- protected void serializeExtraData(int offset, byte[] data) {
- //Because this record is converted to individual Formula records, this method is not required.
- throw new UnsupportedOperationException("Cannot serialize a SharedFormulaRecord");
+
+ protected void serializeExtraData(LittleEndianOutput out) {
+ out.writeShort(field_5_reserved);
+ field_7_parsed_expr.serialize(out);
}
protected int getExtraDataSize() {
- //Because this record is converted to individual Formula records, this method is not required.
- throw new UnsupportedOperationException("Cannot get the size for a SharedFormulaRecord");
-
+ return 2 + field_7_parsed_expr.getEncodedSize();
}
/**
@@ -77,9 +85,10 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
buffer.append(" .range = ").append(getRange().toString()).append("\n");
buffer.append(" .reserved = ").append(HexDump.shortToHex(field_5_reserved)).append("\n");
- for (int k = 0; k < field_7_parsed_expr.length; k++ ) {
+ Ptg[] ptgs = field_7_parsed_expr.getTokens();
+ for (int k = 0; k < ptgs.length; k++ ) {
buffer.append("Formula[").append(k).append("]");
- Ptg ptg = field_7_parsed_expr[k];
+ Ptg ptg = ptgs[k];
buffer.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
}
@@ -92,20 +101,13 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
}
/**
- * Creates a non shared formula from the shared formula
- * counter part
+ * Creates a non shared formula from the shared formula counterpart<br/>
+ *
+ * Perhaps this functionality could be implemented in terms of the raw
+ * byte array inside {@link Formula}.
*/
- protected static Ptg[] convertSharedFormulas(Ptg[] ptgs, int formulaRow, int formulaColumn) {
- if(false) {
- /*
- * TODO - (May-2008) Stop converting relative ref Ptgs in shared formula records.
- * If/when POI writes out the workbook, this conversion makes an unnecessary diff in the BIFF records.
- * Disabling this code breaks one existing junit.
- * Some fix-up will be required to make Ptg.toFormulaString(HSSFWorkbook) work properly.
- * That method will need 2 extra params: rowIx and colIx.
- */
- return ptgs;
- }
+ static Ptg[] convertSharedFormulas(Ptg[] ptgs, int formulaRow, int formulaColumn) {
+
Ptg[] newPtgStack = new Ptg[ptgs.length];
for (int k = 0; k < ptgs.length; k++) {
@@ -145,10 +147,9 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
}
/**
- * Creates a non shared formula from the shared formula
- * counter part
+ * @return the equivalent {@link Ptg} array that the formula would have, were it not shared.
*/
- public void convertSharedFormulaRecord(FormulaRecord formula) {
+ public Ptg[] getFormulaTokens(FormulaRecord formula) {
int formulaRow = formula.getRow();
int formulaColumn = formula.getColumn();
//Sanity checks
@@ -156,10 +157,7 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
throw new RuntimeException("Shared Formula Conversion: Coding Error");
}
- Ptg[] ptgs = convertSharedFormulas(field_7_parsed_expr, formulaRow, formulaColumn);
- formula.setParsedExpression(ptgs);
- //Now its not shared!
- formula.setSharedFormula(false);
+ return convertSharedFormulas(field_7_parsed_expr.getTokens(), formulaRow, formulaColumn);
}
private static int fixupRelativeColumn(int currentcolumn, int column, boolean relative) {
@@ -179,7 +177,9 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
}
public Object clone() {
- //Because this record is converted to individual Formula records, this method is not required.
- throw new UnsupportedOperationException("Cannot clone a SharedFormulaRecord");
+ SharedFormulaRecord result = new SharedFormulaRecord(getRange());
+ result.field_5_reserved = field_5_reserved;
+ result.field_7_parsed_expr = field_7_parsed_expr.copy();
+ return result;
}
}
diff --git a/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java b/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java
index fc51de8465..3672b881a2 100644
--- a/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java
+++ b/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java
@@ -18,7 +18,9 @@
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.util.CellRangeAddress8Bit;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Common base class for {@link SharedFormulaRecord}, {@link ArrayRecord} and
@@ -41,7 +43,7 @@ public abstract class SharedValueRecordBase extends Record {
/**
* reads only the range (1 {@link CellRangeAddress8Bit}) from the stream
*/
- public SharedValueRecordBase(RecordInputStream in) {
+ public SharedValueRecordBase(LittleEndianInput in) {
_range = new CellRangeAddress8Bit(in);
}
@@ -71,19 +73,19 @@ public abstract class SharedValueRecordBase extends Record {
protected abstract int getExtraDataSize();
- protected abstract void serializeExtraData(int offset, byte[] data);
+ protected abstract void serializeExtraData(LittleEndianOutput out);
public final int serialize(int offset, byte[] data) {
int dataSize = CellRangeAddress8Bit.ENCODED_SIZE + getExtraDataSize();
-
- LittleEndian.putShort(data, 0 + offset, getSid());
- LittleEndian.putUShort(data, 2 + offset, dataSize);
-
- int pos = offset + 4;
- _range.serialize(pos, data);
- pos += CellRangeAddress8Bit.ENCODED_SIZE;
- serializeExtraData(pos, data);
- return dataSize + 4;
+
+ int totalRecSize = dataSize + 4;
+ LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, totalRecSize);
+ out.writeShort(getSid());
+ out.writeShort(dataSize);
+
+ _range.serialize(out);
+ serializeExtraData(out);
+ return totalRecSize;
}
/**
diff --git a/src/java/org/apache/poi/hssf/record/TableRecord.java b/src/java/org/apache/poi/hssf/record/TableRecord.java
index 0d4934620e..0a3921cbbe 100644
--- a/src/java/org/apache/poi/hssf/record/TableRecord.java
+++ b/src/java/org/apache/poi/hssf/record/TableRecord.java
@@ -23,7 +23,7 @@ import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianOutput;
/**
* DATATABLE (0x0236)<p/>
*
@@ -146,13 +146,13 @@ public final class TableRecord extends SharedValueRecordBase {
2 // 2 byte fields
+ 8; // 4 short fields
}
- protected void serializeExtraData(int offset, byte[] data) {
- LittleEndian.putByte(data, 0 + offset, field_5_flags);
- LittleEndian.putByte(data, 1 + offset, field_6_res);
- LittleEndian.putUShort(data, 2 + offset, field_7_rowInputRow);
- LittleEndian.putUShort(data, 4 + offset, field_8_colInputRow);
- LittleEndian.putUShort(data, 6 + offset, field_9_rowInputCol);
- LittleEndian.putUShort(data, 8 + offset, field_10_colInputCol);
+ protected void serializeExtraData(LittleEndianOutput out) {
+ out.writeByte(field_5_flags);
+ out.writeByte(field_6_res);
+ out.writeShort(field_7_rowInputRow);
+ out.writeShort(field_8_colInputRow);
+ out.writeShort(field_9_rowInputCol);
+ out.writeShort(field_10_colInputCol);
}
public String toString() {
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
index 2e86b13821..282afc427c 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
@@ -21,7 +21,10 @@ import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFormatException;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
import org.apache.poi.hssf.record.StringRecord;
+import org.apache.poi.hssf.record.formula.ExpPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
/**
* The formula record aggregate is used to join together the formula record and it's
@@ -31,113 +34,177 @@ import org.apache.poi.hssf.record.StringRecord;
*/
public final class FormulaRecordAggregate extends RecordAggregate implements CellValueRecordInterface {
- private final FormulaRecord _formulaRecord;
- private SharedValueManager _sharedValueManager;
- /** caches the calculated result of the formula */
- private StringRecord _stringRecord;
-
- /**
- * @param stringRec may be <code>null</code> if this formula does not have a cached text
- * value.
- * @param svm the {@link SharedValueManager} for the current sheet
- */
- public FormulaRecordAggregate(FormulaRecord formulaRec, StringRecord stringRec, SharedValueManager svm) {
- if (svm == null) {
- throw new IllegalArgumentException("sfm must not be null");
- }
- boolean hasStringRec = stringRec != null;
- boolean hasCachedStringFlag = formulaRec.hasCachedResultString();
- if (hasStringRec != hasCachedStringFlag) {
- throw new RecordFormatException("String record was "
- + (hasStringRec ? "": "not ") + " supplied but formula record flag is "
- + (hasCachedStringFlag ? "" : "not ") + " set");
- }
-
- if (formulaRec.isSharedFormula()) {
- svm.convertSharedFormulaRecord(formulaRec);
- }
- _formulaRecord = formulaRec;
- _sharedValueManager = svm;
- _stringRecord = stringRec;
- }
-
- public FormulaRecord getFormulaRecord() {
- return _formulaRecord;
- }
-
- /**
- * debug only
- * TODO - encapsulate
- */
- public StringRecord getStringRecord() {
- return _stringRecord;
- }
-
- public short getXFIndex() {
- return _formulaRecord.getXFIndex();
- }
-
- public void setXFIndex(short xf) {
- _formulaRecord.setXFIndex(xf);
- }
-
- public void setColumn(short col) {
- _formulaRecord.setColumn(col);
- }
-
- public void setRow(int row) {
- _formulaRecord.setRow(row);
- }
-
- public short getColumn() {
- return _formulaRecord.getColumn();
- }
-
- public int getRow() {
- return _formulaRecord.getRow();
- }
-
- public String toString() {
- return _formulaRecord.toString();
- }
-
- public void visitContainedRecords(RecordVisitor rv) {
- rv.visitRecord(_formulaRecord);
- Record sharedFormulaRecord = _sharedValueManager.getRecordForFirstCell(_formulaRecord);
- if (sharedFormulaRecord != null) {
- rv.visitRecord(sharedFormulaRecord);
- }
- if (_stringRecord != null) {
- rv.visitRecord(_stringRecord);
- }
- }
-
- public String getStringValue() {
- if(_stringRecord==null) {
- return null;
- }
- return _stringRecord.getString();
- }
-
- public void setCachedStringResult(String value) {
-
- // Save the string into a String Record, creating one if required
- if(_stringRecord == null) {
- _stringRecord = new StringRecord();
- }
- _stringRecord.setString(value);
- if (value.length() < 1) {
- _formulaRecord.setCachedResultTypeEmptyString();
- } else {
- _formulaRecord.setCachedResultTypeString();
- }
- }
- public void setCachedBooleanResult(boolean value) {
- _stringRecord = null;
- _formulaRecord.setCachedResultBoolean(value);
- }
- public void setCachedErrorResult(int errorCode) {
- _stringRecord = null;
- _formulaRecord.setCachedResultErrorCode(errorCode);
- }
+ private final FormulaRecord _formulaRecord;
+ private SharedValueManager _sharedValueManager;
+ /** caches the calculated result of the formula */
+ private StringRecord _stringRecord;
+ private SharedFormulaRecord _sharedFormulaRecord;
+
+ /**
+ * @param stringRec may be <code>null</code> if this formula does not have a cached text
+ * value.
+ * @param svm the {@link SharedValueManager} for the current sheet
+ */
+ public FormulaRecordAggregate(FormulaRecord formulaRec, StringRecord stringRec, SharedValueManager svm) {
+ if (svm == null) {
+ throw new IllegalArgumentException("sfm must not be null");
+ }
+ boolean hasStringRec = stringRec != null;
+ boolean hasCachedStringFlag = formulaRec.hasCachedResultString();
+ if (hasStringRec != hasCachedStringFlag) {
+ throw new RecordFormatException("String record was "
+ + (hasStringRec ? "": "not ") + " supplied but formula record flag is "
+ + (hasCachedStringFlag ? "" : "not ") + " set");
+ }
+
+ _formulaRecord = formulaRec;
+ _sharedValueManager = svm;
+ _stringRecord = stringRec;
+ if (formulaRec.isSharedFormula()) {
+ _sharedFormulaRecord = svm.linkSharedFormulaRecord(this);
+ if (_sharedFormulaRecord == null) {
+ handleMissingSharedFormulaRecord(formulaRec);
+ }
+ }
+ }
+ /**
+ * Sometimes the shared formula flag "seems" to be erroneously set (because the corresponding
+ * {@link SharedFormulaRecord} does not exist). Normally this would leave no way of determining
+ * the {@link Ptg} tokens for the formula. However as it turns out in these
+ * cases, Excel encodes the unshared {@link Ptg} tokens in the right place (inside the {@link
+ * FormulaRecord}). So the the only thing that needs to be done is to ignore the erroneous
+ * shared formula flag.<br/>
+ *
+ * This method may also be used for setting breakpoints to help diagnose issues regarding the
+ * abnormally-set 'shared formula' flags.
+ * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
+ */
+ private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
+ // make sure 'unshared' formula is actually available
+ Ptg firstToken = formula.getParsedExpression()[0];
+ if (firstToken instanceof ExpPtg) {
+ throw new RecordFormatException(
+ "SharedFormulaRecord not found for FormulaRecord with (isSharedFormula=true)");
+ }
+ // could log an info message here since this is a fairly unusual occurrence.
+ formula.setSharedFormula(false); // no point leaving the flag erroneously set
+ }
+
+ public FormulaRecord getFormulaRecord() {
+ return _formulaRecord;
+ }
+
+ /**
+ * debug only
+ * TODO - encapsulate
+ */
+ public StringRecord getStringRecord() {
+ return _stringRecord;
+ }
+
+ public short getXFIndex() {
+ return _formulaRecord.getXFIndex();
+ }
+
+ public void setXFIndex(short xf) {
+ _formulaRecord.setXFIndex(xf);
+ }
+
+ public void setColumn(short col) {
+ _formulaRecord.setColumn(col);
+ }
+
+ public void setRow(int row) {
+ _formulaRecord.setRow(row);
+ }
+
+ public short getColumn() {
+ return _formulaRecord.getColumn();
+ }
+
+ public int getRow() {
+ return _formulaRecord.getRow();
+ }
+
+ public String toString() {
+ return _formulaRecord.toString();
+ }
+
+ public void visitContainedRecords(RecordVisitor rv) {
+ rv.visitRecord(_formulaRecord);
+ // TODO - only bother with this if array or table formula
+ Record sharedFormulaRecord = _sharedValueManager.getRecordForFirstCell(_formulaRecord);
+ if (sharedFormulaRecord != null) {
+ rv.visitRecord(sharedFormulaRecord);
+ }
+ if (_stringRecord != null) {
+ rv.visitRecord(_stringRecord);
+ }
+ }
+
+ public String getStringValue() {
+ if(_stringRecord==null) {
+ return null;
+ }
+ return _stringRecord.getString();
+ }
+
+ public void setCachedStringResult(String value) {
+
+ // Save the string into a String Record, creating one if required
+ if(_stringRecord == null) {
+ _stringRecord = new StringRecord();
+ }
+ _stringRecord.setString(value);
+ if (value.length() < 1) {
+ _formulaRecord.setCachedResultTypeEmptyString();
+ } else {
+ _formulaRecord.setCachedResultTypeString();
+ }
+ }
+ public void setCachedBooleanResult(boolean value) {
+ _stringRecord = null;
+ _formulaRecord.setCachedResultBoolean(value);
+ }
+ public void setCachedErrorResult(int errorCode) {
+ _stringRecord = null;
+ _formulaRecord.setCachedResultErrorCode(errorCode);
+ }
+
+ public Ptg[] getFormulaTokens() {
+ if (_sharedFormulaRecord == null) {
+ return _formulaRecord.getParsedExpression();
+ }
+ return _sharedFormulaRecord.getFormulaTokens(_formulaRecord);
+ }
+
+ /**
+ * Also checks for a related shared formula and unlinks it if found
+ */
+ public void setParsedExpression(Ptg[] ptgs) {
+ notifyFormulaChanging();
+ _formulaRecord.setParsedExpression(ptgs);
+ }
+
+ public void unlinkSharedFormula() {
+ SharedFormulaRecord sfr = _sharedFormulaRecord;
+ if (sfr == null) {
+ throw new IllegalStateException("Formula not linked to shared formula");
+ }
+ Ptg[] ptgs = sfr.getFormulaTokens(_formulaRecord);
+ _formulaRecord.setParsedExpression(ptgs);
+ //Now its not shared!
+ _formulaRecord.setSharedFormula(false);
+ _sharedFormulaRecord = null;
+ }
+ /**
+ * Should be called by any code which is either deleting this formula cell, or changing
+ * its type. This method gives the aggregate a chance to unlink any shared formula
+ * that may be involved with this cell formula.
+ */
+ public void notifyFormulaChanging() {
+ if (_sharedFormulaRecord != null) {
+ _sharedValueManager.unlink(_sharedFormulaRecord);
+ }
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java
index 9ea9d61e99..6eefb30e1c 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/RecordAggregate.java
@@ -19,7 +19,6 @@ package org.apache.poi.hssf.record.aggregates;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordBase;
-import org.apache.poi.hssf.record.RecordInputStream;
/**
* <tt>RecordAggregate</tt>s are groups of of BIFF <tt>Record</tt>s that are typically stored
@@ -29,16 +28,6 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Josh Micich
*/
public abstract class RecordAggregate extends RecordBase {
- // TODO - delete these methods when all subclasses have been converted
- protected final void validateSid(short id) {
- throw new RuntimeException("Should not be called");
- }
- protected final void fillFields(RecordInputStream in) {
- throw new RuntimeException("Should not be called");
- }
- public final short getSid() {
- throw new RuntimeException("Should not be called");
- }
/**
* Visit each of the atomic BIFF records contained in this {@link RecordAggregate} in the order
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
index cfa6afc77e..2a2497f363 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
@@ -321,39 +321,38 @@ public final class RowRecordsAggregate extends RecordAggregate {
return currentRow-1;
}
- public int writeHidden( RowRecord rowRecord, int row, boolean hidden )
- {
+ /**
+ * Hide all rows at or below the current outline level
+ * @return index of the <em>next<em> row after the last row that gets hidden
+ */
+ private int writeHidden(RowRecord pRowRecord, int row) {
+ int rowIx = row;
+ RowRecord rowRecord = pRowRecord;
int level = rowRecord.getOutlineLevel();
- while (rowRecord != null && this.getRow(row).getOutlineLevel() >= level)
- {
- rowRecord.setZeroHeight( hidden );
- row++;
- rowRecord = this.getRow( row );
+ while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) {
+ rowRecord.setZeroHeight(true);
+ rowIx++;
+ rowRecord = getRow(rowIx);
}
- return row - 1;
+ return rowIx;
}
- public void collapseRow( int rowNumber )
- {
+ public void collapseRow(int rowNumber) {
// Find the start of the group.
- int startRow = findStartOfRowOutlineGroup( rowNumber );
- RowRecord rowRecord = getRow( startRow );
+ int startRow = findStartOfRowOutlineGroup(rowNumber);
+ RowRecord rowRecord = getRow(startRow);
// Hide all the columns until the end of the group
- int lastRow = writeHidden( rowRecord, startRow, true );
+ int nextRowIx = writeHidden(rowRecord, startRow);
- // Write collapse field
- if (getRow(lastRow + 1) != null)
- {
- getRow(lastRow + 1).setColapsed( true );
- }
- else
- {
- RowRecord row = createRow( lastRow + 1);
- row.setColapsed( true );
- insertRow( row );
+ RowRecord row = getRow(nextRowIx);
+ if (row == null) {
+ row = createRow(nextRowIx);
+ insertRow(row);
}
+ // Write collapse field
+ row.setColapsed(true);
}
/**
@@ -500,6 +499,9 @@ public final class RowRecordsAggregate extends RecordAggregate {
_valuesAgg.insertCell(cvRec);
}
public void removeCell(CellValueRecordInterface cvRec) {
+ if (cvRec instanceof FormulaRecordAggregate) {
+ ((FormulaRecordAggregate)cvRec).notifyFormulaChanging();
+ }
_valuesAgg.removeCell(cvRec);
}
public FormulaRecordAggregate createFormula(int row, int col) {
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java b/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
index d5cf1b6ac8..98eebe0880 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
@@ -17,6 +17,9 @@
package org.apache.poi.hssf.record.aggregates;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.poi.hssf.record.ArrayRecord;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.SharedFormulaRecord;
@@ -35,18 +38,72 @@ import org.apache.poi.hssf.record.TableRecord;
* @author Josh Micich
*/
public final class SharedValueManager {
+
+ // This class should probably be generalised to handle array and table groups too
+ private static final class SharedValueGroup {
+ private final SharedValueRecordBase _svr;
+ private final FormulaRecordAggregate[] _frAggs;
+ private int _numberOfFormulas;
+
+ public SharedValueGroup(SharedValueRecordBase svr) {
+ _svr = svr;
+ int width = svr.getLastColumn() - svr.getFirstColumn() + 1;
+ int height = svr.getLastRow() - svr.getFirstRow() + 1;
+ _frAggs = new FormulaRecordAggregate[width * height];
+ _numberOfFormulas = 0;
+ }
+
+ public void add(FormulaRecordAggregate agg) {
+ _frAggs[_numberOfFormulas++] = agg;
+ }
+
+ public void unlinkSharedFormulas() {
+ for (int i = 0; i < _numberOfFormulas; i++) {
+ _frAggs[i].unlinkSharedFormula();
+ }
+ }
+
+ public boolean isInRange(int rowIx, int columnIx) {
+ return _svr.isInRange(rowIx, columnIx);
+ }
+
+ public SharedValueRecordBase getSVR() {
+ return _svr;
+ }
+
+ /**
+ * Note - Sometimes the first formula in a group is not present (because the range
+ * is sparsely populated), so this method can return <code>true</code> for a cell
+ * that is not the top-left corner of the range.
+ * @return <code>true</code> if this is the first formula cell in the group
+ */
+ public boolean isFirstCell(int row, int column) {
+ // hack for the moment, just check against the first formula that
+ // came in through the add() method.
+ FormulaRecordAggregate fra = _frAggs[0];
+ return fra.getRow() == row && fra.getColumn() == column;
+ }
+
+ }
public static final SharedValueManager EMPTY = new SharedValueManager(
new SharedFormulaRecord[0], new ArrayRecord[0], new TableRecord[0]);
- private final SharedFormulaRecord[] _sfrs;
private final ArrayRecord[] _arrayRecords;
private final TableRecord[] _tableRecords;
+ private final Map _groupsBySharedFormulaRecord;
+ /** cached for optimization purposes */
+ private SharedValueGroup[] _groups;
private SharedValueManager(SharedFormulaRecord[] sharedFormulaRecords,
ArrayRecord[] arrayRecords, TableRecord[] tableRecords) {
- _sfrs = sharedFormulaRecords;
_arrayRecords = arrayRecords;
_tableRecords = tableRecords;
+ Map m = new HashMap(sharedFormulaRecords.length * 3 / 2);
+ for (int i = 0; i < sharedFormulaRecords.length; i++) {
+ SharedFormulaRecord sfr = sharedFormulaRecords[i];
+ m.put(sfr, new SharedValueGroup(sfr));
+ }
+ _groupsBySharedFormulaRecord = m;
}
/**
@@ -64,42 +121,42 @@ public final class SharedValueManager {
return new SharedValueManager(sharedFormulaRecords, arrayRecords, tableRecords);
}
- public void convertSharedFormulaRecord(FormulaRecord formula) {
+
+ /**
+ * @return <code>null</code> if the specified formula does not have any corresponding
+ * {@link SharedFormulaRecord}
+ */
+ public SharedFormulaRecord linkSharedFormulaRecord(FormulaRecordAggregate agg) {
+ FormulaRecord formula = agg.getFormulaRecord();
int row = formula.getRow();
int column = formula.getColumn();
// Traverse the list of shared formulas in
// reverse order, and try to find the correct one
// for us
- for (int i = 0; i < _sfrs.length; i++) {
- SharedFormulaRecord shrd = _sfrs[i];
- if (shrd.isInRange(row, column)) {
- shrd.convertSharedFormulaRecord(formula);
- return;
+
+ SharedValueGroup[] groups = getGroups();
+ for (int i = 0; i < groups.length; i++) {
+ SharedValueGroup svr = groups[i];
+ if (svr.isInRange(row, column)) {
+ svr.add(agg);
+ return (SharedFormulaRecord) svr.getSVR();
}
}
- // not found
- handleMissingSharedFormulaRecord(formula);
+ return null;
}
- /**
- * Sometimes the shared formula flag "seems" to be erroneously set, in which case there is no
- * call to <tt>SharedFormulaRecord.convertSharedFormulaRecord</tt> and hence the
- * <tt>parsedExpression</tt> field of this <tt>FormulaRecord</tt> will not get updated.<br/>
- * As it turns out, this is not a problem, because in these circumstances, the existing value
- * for <tt>parsedExpression</tt> is perfectly OK.<p/>
- *
- * This method may also be used for setting breakpoints to help diagnose issues regarding the
- * abnormally-set 'shared formula' flags.
- * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
- *
- * The method currently does nothing but do not delete it without finding a nice home for this
- * comment.
- */
- private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
- // could log an info message here since this is a fairly unusual occurrence.
- formula.setSharedFormula(false); // no point leaving the flag erroneously set
+ private SharedValueGroup[] getGroups() {
+ if (_groups == null) {
+ SharedValueGroup[] groups = new SharedValueGroup[_groupsBySharedFormulaRecord.size()];
+ _groupsBySharedFormulaRecord.values().toArray(groups);
+ _groups = groups;
+
+ }
+ return _groups;
}
+
+
/**
* Note - does not return SharedFormulaRecords currently, because the corresponding formula
* records have been converted to 'unshared'. POI does not attempt to re-share formulas. On
@@ -125,6 +182,26 @@ public final class SharedValueManager {
return ar;
}
}
+ SharedValueGroup[] groups = getGroups();
+ for (int i = 0; i < groups.length; i++) {
+ SharedValueGroup svg = groups[i];
+ if (svg.isFirstCell(row, column)) {
+ return svg.getSVR();
+ }
+ }
return null;
}
+
+ /**
+ * Converts all {@link FormulaRecord}s handled by <tt>sharedFormulaRecord</tt>
+ * to plain unshared formulas
+ */
+ public void unlink(SharedFormulaRecord sharedFormulaRecord) {
+ SharedValueGroup svg = (SharedValueGroup) _groupsBySharedFormulaRecord.remove(sharedFormulaRecord);
+ _groups = null; // be sure to reset cached value
+ if (svg == null) {
+ throw new IllegalStateException("Failed to find formulas for shared formula");
+ }
+ svg.unlinkSharedFormulas();
+ }
}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
index a9b1de2531..27000811ce 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
@@ -145,9 +145,6 @@ public final class ValueRecordsAggregate {
public void construct(CellValueRecordInterface rec, RecordStream rs, SharedValueManager sfh) {
if (rec instanceof FormulaRecord) {
FormulaRecord formulaRec = (FormulaRecord)rec;
- if (formulaRec.isSharedFormula()) {
- sfh.convertSharedFormulaRecord(formulaRec);
- }
// read optional cached text value
StringRecord cachedText;
Class nextClass = rs.peekNextClass();
diff --git a/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java b/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java
index 4343760ddd..4698c5c310 100644
--- a/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.java
+++ b/src/java/org/apache/poi/hssf/record/cf/BorderFormatting.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
@@ -15,129 +14,54 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
-/*
- * FontFormatting.java
- *
- * Created on January 22, 2008, 10:05 PM
- */
package org.apache.poi.hssf.record.cf;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Border Formatting Block of the Conditional Formatting Rule Record.
- *
+ *
* @author Dmitriy Kumshayev
*/
+public final class BorderFormatting {
-public class BorderFormatting
-{
-
- /**
- * No border
- */
-
+ /** No border */
public final static short BORDER_NONE = 0x0;
-
- /**
- * Thin border
- */
-
+ /** Thin border */
public final static short BORDER_THIN = 0x1;
-
- /**
- * Medium border
- */
-
+ /** Medium border */
public final static short BORDER_MEDIUM = 0x2;
-
- /**
- * dash border
- */
-
+ /** dash border */
public final static short BORDER_DASHED = 0x3;
-
- /**
- * dot border
- */
-
- public final static short BORDER_HAIR = 0x4;
-
- /**
- * Thick border
- */
-
+ /** dot border */
+ public final static short BORDER_HAIR = 0x4;
+ /** Thick border */
public final static short BORDER_THICK = 0x5;
-
- /**
- * double-line border
- */
-
+ /** double-line border */
public final static short BORDER_DOUBLE = 0x6;
-
- /**
- * hair-line border
- */
-
- public final static short BORDER_DOTTED = 0x7;
-
- /**
- * Medium dashed border
- */
-
+ /** hair-line border */
+ public final static short BORDER_DOTTED = 0x7;
+ /** Medium dashed border */
public final static short BORDER_MEDIUM_DASHED = 0x8;
-
- /**
- * dash-dot border
- */
-
+ /** dash-dot border */
public final static short BORDER_DASH_DOT = 0x9;
-
- /**
- * medium dash-dot border
- */
-
+ /** medium dash-dot border */
public final static short BORDER_MEDIUM_DASH_DOT = 0xA;
-
- /**
- * dash-dot-dot border
- */
-
+ /** dash-dot-dot border */
public final static short BORDER_DASH_DOT_DOT = 0xB;
-
- /**
- * medium dash-dot-dot border
- */
-
+ /** medium dash-dot-dot border */
public final static short BORDER_MEDIUM_DASH_DOT_DOT = 0xC;
-
- /**
- * slanted dash-dot border
- */
-
+ /** slanted dash-dot border */
public final static short BORDER_SLANTED_DASH_DOT = 0xD;
-
- public BorderFormatting()
- {
- field_13_border_styles1 = (short)0;
- field_14_border_styles2 = (short)0;
- }
-
- /** Creates new FontFormatting */
- public BorderFormatting(RecordInputStream in)
- {
- field_13_border_styles1 = in.readInt();
- field_14_border_styles2 = in.readInt();
- }
-
+
// BORDER FORMATTING BLOCK
// For Border Line Style codes see HSSFCellStyle.BORDER_XXXXXX
- private int field_13_border_styles1;
+ private int field_13_border_styles1;
private static final BitField bordLeftLineStyle = BitFieldFactory.getInstance(0x0000000F);
private static final BitField bordRightLineStyle = BitFieldFactory.getInstance(0x000000F0);
private static final BitField bordTopLineStyle = BitFieldFactory.getInstance(0x00000F00);
@@ -147,12 +71,25 @@ public class BorderFormatting
private static final BitField bordTlBrLineOnOff = BitFieldFactory.getInstance(0x40000000);
private static final BitField bordBlTrtLineOnOff = BitFieldFactory.getInstance(0x80000000);
- private int field_14_border_styles2;
+ private int field_14_border_styles2;
private static final BitField bordTopLineColor = BitFieldFactory.getInstance(0x0000007F);
private static final BitField bordBottomLineColor= BitFieldFactory.getInstance(0x00003f80);
private static final BitField bordDiagLineColor = BitFieldFactory.getInstance(0x001FC000);
private static final BitField bordDiagLineStyle = BitFieldFactory.getInstance(0x01E00000);
+
+ public BorderFormatting() {
+ field_13_border_styles1 = 0;
+ field_14_border_styles2 = 0;
+ }
+
+ /** Creates new FontFormatting */
+ public BorderFormatting(LittleEndianInput in) {
+ field_13_border_styles1 = in.readInt();
+ field_14_border_styles2 = in.readInt();
+ }
+
+
/**
* set the type of border to use for the left border of the cell
* @param border type
@@ -171,10 +108,8 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
-
- public void setBorderLeft(short border)
- {
- field_13_border_styles1 = bordLeftLineStyle.setValue(field_13_border_styles1, border);
+ public void setBorderLeft(int border) {
+ field_13_border_styles1 = bordLeftLineStyle.setValue(field_13_border_styles1, border);
}
/**
@@ -195,10 +130,8 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
-
- public short getBorderLeft()
- {
- return (short)bordLeftLineStyle.getValue(field_13_border_styles1);
+ public int getBorderLeft() {
+ return bordLeftLineStyle.getValue(field_13_border_styles1);
}
/**
@@ -219,10 +152,8 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
-
- public void setBorderRight(short border)
- {
- field_13_border_styles1 = bordRightLineStyle.setValue(field_13_border_styles1, border);
+ public void setBorderRight(int border) {
+ field_13_border_styles1 = bordRightLineStyle.setValue(field_13_border_styles1, border);
}
/**
@@ -243,10 +174,8 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
-
- public short getBorderRight()
- {
- return (short)bordRightLineStyle.getValue(field_13_border_styles1);
+ public int getBorderRight() {
+ return bordRightLineStyle.getValue(field_13_border_styles1);
}
/**
@@ -267,10 +196,8 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
-
- public void setBorderTop(short border)
- {
- field_13_border_styles1 = bordTopLineStyle.setValue(field_13_border_styles1, border);
+ public void setBorderTop(int border) {
+ field_13_border_styles1 = bordTopLineStyle.setValue(field_13_border_styles1, border);
}
/**
@@ -291,10 +218,8 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
-
- public short getBorderTop()
- {
- return (short)bordTopLineStyle.getValue(field_13_border_styles1);
+ public int getBorderTop() {
+ return bordTopLineStyle.getValue(field_13_border_styles1);
}
/**
@@ -315,10 +240,8 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
-
- public void setBorderBottom(short border)
- {
- field_13_border_styles1 = bordBottomLineStyle.setValue(field_13_border_styles1, border);
+ public void setBorderBottom(int border) {
+ field_13_border_styles1 = bordBottomLineStyle.setValue(field_13_border_styles1, border);
}
/**
@@ -339,11 +262,10 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
- public short getBorderBottom()
- {
- return (short)bordBottomLineStyle.getValue(field_13_border_styles1);
+ public int getBorderBottom() {
+ return bordBottomLineStyle.getValue(field_13_border_styles1);
}
-
+
/**
* set the type of border to use for the diagonal border of the cell
* @param border type
@@ -362,10 +284,8 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
-
- public void setBorderDiagonal(short border)
- {
- field_14_border_styles2 = bordDiagLineStyle.setValue(field_14_border_styles2, border);
+ public void setBorderDiagonal(int border) {
+ field_14_border_styles2 = bordDiagLineStyle.setValue(field_14_border_styles2, border);
}
/**
@@ -386,18 +306,16 @@ public class BorderFormatting
* @see #BORDER_MEDIUM_DASH_DOT_DOT
* @see #BORDER_SLANTED_DASH_DOT
*/
- public short getBorderDiagonal()
- {
- return (short)bordDiagLineStyle.getValue(field_14_border_styles2);
+ public int getBorderDiagonal() {
+ return bordDiagLineStyle.getValue(field_14_border_styles2);
}
/**
* set the color to use for the left border
* @param color The index of the color definition
*/
- public void setLeftBorderColor(short color)
- {
- field_13_border_styles1 = bordLeftLineColor.setValue(field_13_border_styles1, color);
+ public void setLeftBorderColor(int color) {
+ field_13_border_styles1 = bordLeftLineColor.setValue(field_13_border_styles1, color);
}
/**
@@ -405,18 +323,16 @@ public class BorderFormatting
* @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
* @param color The index of the color definition
*/
- public short getLeftBorderColor()
- {
- return (short)bordLeftLineColor.getValue(field_13_border_styles1);
+ public int getLeftBorderColor() {
+ return bordLeftLineColor.getValue(field_13_border_styles1);
}
/**
* set the color to use for the right border
* @param color The index of the color definition
*/
- public void setRightBorderColor(short color)
- {
- field_13_border_styles1 = bordRightLineColor.setValue(field_13_border_styles1, color);
+ public void setRightBorderColor(int color) {
+ field_13_border_styles1 = bordRightLineColor.setValue(field_13_border_styles1, color);
}
/**
@@ -424,18 +340,16 @@ public class BorderFormatting
* @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
* @param color The index of the color definition
*/
- public short getRightBorderColor()
- {
- return (short)bordRightLineColor.getValue(field_13_border_styles1);
+ public int getRightBorderColor() {
+ return bordRightLineColor.getValue(field_13_border_styles1);
}
/**
* set the color to use for the top border
* @param color The index of the color definition
*/
- public void setTopBorderColor(short color)
- {
- field_14_border_styles2 = bordTopLineColor.setValue(field_14_border_styles2, color);
+ public void setTopBorderColor(int color) {
+ field_14_border_styles2 = bordTopLineColor.setValue(field_14_border_styles2, color);
}
/**
@@ -443,18 +357,17 @@ public class BorderFormatting
* @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
* @param color The index of the color definition
*/
- public short getTopBorderColor()
- {
- return (short)bordTopLineColor.getValue(field_14_border_styles2);
+ public int getTopBorderColor() {
+ return bordTopLineColor.getValue(field_14_border_styles2);
}
/**
* set the color to use for the bottom border
* @param color The index of the color definition
*/
- public void setBottomBorderColor(short color)
+ public void setBottomBorderColor(int color)
{
- field_14_border_styles2 = bordBottomLineColor.setValue(field_14_border_styles2, color);
+ field_14_border_styles2 = bordBottomLineColor.setValue(field_14_border_styles2, color);
}
/**
@@ -462,18 +375,16 @@ public class BorderFormatting
* @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
* @param color The index of the color definition
*/
- public short getBottomBorderColor()
- {
- return (short)bordBottomLineColor.getValue(field_14_border_styles2);
+ public int getBottomBorderColor() {
+ return bordBottomLineColor.getValue(field_14_border_styles2);
}
-
+
/**
* set the color to use for the diagonal borders
* @param color The index of the color definition
*/
- public void setDiagonalBorderColor(short color)
- {
- field_14_border_styles2 = bordDiagLineColor.setValue(field_14_border_styles2, color);
+ public void setDiagonalBorderColor(int color) {
+ field_14_border_styles2 = bordDiagLineColor.setValue(field_14_border_styles2, color);
}
/**
@@ -481,50 +392,44 @@ public class BorderFormatting
* @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
* @param color The index of the color definition
*/
- public short getDiagonalBorderColor()
- {
- return (short)bordDiagLineColor.getValue(field_14_border_styles2);
+ public int getDiagonalBorderColor() {
+ return bordDiagLineColor.getValue(field_14_border_styles2);
}
/**
* Of/off bottom left to top right line
- *
- * @param on - if true - on, otherwise off
+ *
+ * @param on - if <code>true</code> - on, otherwise off
*/
- public void setForwardDiagonalOn(boolean on)
- {
- field_13_border_styles1 = bordBlTrtLineOnOff.setBoolean(field_13_border_styles1, on);
+ public void setForwardDiagonalOn(boolean on) {
+ field_13_border_styles1 = bordBlTrtLineOnOff.setBoolean(field_13_border_styles1, on);
}
/**
* Of/off top left to bottom right line
- *
- * @param on - if true - on, otherwise off
+ *
+ * @param on - if <code>true</code> - on, otherwise off
*/
- public void setBackwardDiagonalOn(boolean on)
- {
- field_13_border_styles1 = bordTlBrLineOnOff.setBoolean(field_13_border_styles1, on);
+ public void setBackwardDiagonalOn(boolean on) {
+ field_13_border_styles1 = bordTlBrLineOnOff.setBoolean(field_13_border_styles1, on);
}
-
+
/**
- * @return true if forward diagonal is on
+ * @return <code>true</code> if forward diagonal is on
*/
- public boolean isForwardDiagonalOn()
- {
- return bordBlTrtLineOnOff.isSet(field_13_border_styles1);
+ public boolean isForwardDiagonalOn() {
+ return bordBlTrtLineOnOff.isSet(field_13_border_styles1);
}
/**
- * @return true if backward diagonal is on
+ * @return <code>true</code> if backward diagonal is on
*/
- public boolean isBackwardDiagonalOn()
- {
- return bordTlBrLineOnOff.isSet(field_13_border_styles1);
+ public boolean isBackwardDiagonalOn() {
+ return bordTlBrLineOnOff.isSet(field_13_border_styles1);
}
-
-
- public String toString()
- {
+
+
+ public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(" [Border Formatting]\n");
buffer.append(" .lftln = ").append(Integer.toHexString(getBorderLeft())).append("\n");
@@ -540,21 +445,21 @@ public class BorderFormatting
buffer.append(" [/Border Formatting]\n");
return buffer.toString();
}
-
- public Object clone()
- {
+
+ public Object clone() {
BorderFormatting rec = new BorderFormatting();
- rec.field_13_border_styles1 = field_13_border_styles1;
- rec.field_14_border_styles2 = field_14_border_styles2;
+ rec.field_13_border_styles1 = field_13_border_styles1;
+ rec.field_14_border_styles2 = field_14_border_styles2;
return rec;
}
-
- public int serialize(int offset, byte [] data)
- {
- LittleEndian.putInt(data, offset, field_13_border_styles1);
- offset += 4;
- LittleEndian.putInt(data, offset, field_14_border_styles2);
- offset += 4;
- return 8;
+
+ public int serialize(int offset, byte [] data) {
+ LittleEndian.putInt(data, offset+0, field_13_border_styles1);
+ LittleEndian.putInt(data, offset+4, field_14_border_styles2);
+ return 8;
+ }
+ public void serialize(LittleEndianOutput out) {
+ out.writeInt(field_13_border_styles1);
+ out.writeInt(field_14_border_styles2);
}
}
diff --git a/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java b/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java
index 3157bf46c8..2587157f78 100644
--- a/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.java
+++ b/src/java/org/apache/poi/hssf/record/cf/PatternFormatting.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
@@ -15,28 +14,20 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
-/*
- * FontFormatting.java
- *
- * Created on January 22, 2008, 10:05 PM
- */
package org.apache.poi.hssf.record.cf;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Pattern Formatting Block of the Conditional Formatting Rule Record.
*
* @author Dmitriy Kumshayev
*/
-
-public class PatternFormatting implements Cloneable
-{
+public final class PatternFormatting implements Cloneable {
/** No background */
public final static short NO_FILL = 0 ;
/** Solidly filled */
@@ -75,29 +66,29 @@ public class PatternFormatting implements Cloneable
public final static short LESS_DOTS = 17 ;
/** Least Dots */
public final static short LEAST_DOTS = 18 ;
-
- public PatternFormatting()
- {
- field_15_pattern_style = (short)0;
- field_16_pattern_color_indexes = (short)0;
- }
- /** Creates new FontFormatting */
- public PatternFormatting(RecordInputStream in)
- {
- field_15_pattern_style = in.readShort();
- field_16_pattern_color_indexes = in.readShort();
- }
// PATTERN FORMATING BLOCK
// For Pattern Styles see constants at HSSFCellStyle (from NO_FILL to LEAST_DOTS)
- private short field_15_pattern_style;
+ private int field_15_pattern_style;
private static final BitField fillPatternStyle = BitFieldFactory.getInstance(0xFC00);
- private short field_16_pattern_color_indexes;
- private static final BitField patternColorIndex = BitFieldFactory.getInstance(0x007F);
- private static final BitField patternBackgroundColorIndex = BitFieldFactory.getInstance(0x3F80);
+ private int field_16_pattern_color_indexes;
+ private static final BitField patternColorIndex = BitFieldFactory.getInstance(0x007F);
+ private static final BitField patternBackgroundColorIndex = BitFieldFactory.getInstance(0x3F80);
+
+ public PatternFormatting() {
+ field_15_pattern_style = 0;
+ field_16_pattern_color_indexes = 0;
+ }
+
+ /** Creates new FontFormatting */
+ public PatternFormatting(LittleEndianInput in) {
+ field_15_pattern_style = in.readUShort();
+ field_16_pattern_color_indexes = in.readUShort();
+ }
+
/**
* setting fill pattern
*
@@ -121,63 +112,48 @@ public class PatternFormatting implements Cloneable
*
* @param fp fill pattern
*/
- public void setFillPattern(short fp)
- {
- field_15_pattern_style = fillPatternStyle.setShortValue(field_15_pattern_style, fp);
+ public void setFillPattern(int fp) {
+ field_15_pattern_style = fillPatternStyle.setValue(field_15_pattern_style, fp);
}
/**
- * get the fill pattern
* @return fill pattern
*/
-
- public short getFillPattern()
- {
- return fillPatternStyle.getShortValue(field_15_pattern_style);
+ public int getFillPattern() {
+ return fillPatternStyle.getValue(field_15_pattern_style);
}
/**
* set the background fill color.
- *
- * @param bg color
*/
-
- public void setFillBackgroundColor(short bg)
- {
- field_16_pattern_color_indexes = patternBackgroundColorIndex.setShortValue(field_16_pattern_color_indexes,bg);
+ public void setFillBackgroundColor(int bg) {
+ field_16_pattern_color_indexes = patternBackgroundColorIndex.setValue(field_16_pattern_color_indexes,bg);
}
/**
- * get the background fill color
* @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
- * @return fill color
+ * @return get the background fill color
*/
- public short getFillBackgroundColor()
- {
- return patternBackgroundColorIndex.getShortValue(field_16_pattern_color_indexes);
+ public int getFillBackgroundColor() {
+ return patternBackgroundColorIndex.getValue(field_16_pattern_color_indexes);
}
/**
* set the foreground fill color
- * @param bg color
*/
- public void setFillForegroundColor(short fg)
- {
- field_16_pattern_color_indexes = patternColorIndex.setShortValue(field_16_pattern_color_indexes,fg);
+ public void setFillForegroundColor(int fg) {
+ field_16_pattern_color_indexes = patternColorIndex.setValue(field_16_pattern_color_indexes,fg);
}
/**
- * get the foreground fill color
* @see org.apache.poi.hssf.usermodel.HSSFPalette#getColor(short)
- * @return fill color
+ * @return get the foreground fill color
*/
- public short getFillForegroundColor()
- {
- return patternColorIndex.getShortValue(field_16_pattern_color_indexes);
+ public int getFillForegroundColor() {
+ return patternColorIndex.getValue(field_16_pattern_color_indexes);
}
- public String toString()
- {
+ public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(" [Pattern Formatting]\n");
buffer.append(" .fillpattern= ").append(Integer.toHexString(getFillPattern())).append("\n");
@@ -187,20 +163,15 @@ public class PatternFormatting implements Cloneable
return buffer.toString();
}
- public Object clone()
- {
+ public Object clone() {
PatternFormatting rec = new PatternFormatting();
rec.field_15_pattern_style = field_15_pattern_style;
rec.field_16_pattern_color_indexes = field_16_pattern_color_indexes;
return rec;
}
-
- public int serialize(int offset, byte [] data)
- {
- LittleEndian.putShort(data, offset, field_15_pattern_style);
- offset += 2;
- LittleEndian.putShort(data, offset, field_16_pattern_color_indexes);
- offset += 2;
- return 4;
+
+ public void serialize(LittleEndianOutput out) {
+ out.writeShort(field_15_pattern_style);
+ out.writeShort(field_16_pattern_color_indexes);
}
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java
index 33e1d3a850..178e1675ef 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFBorderFormatting.java
@@ -75,52 +75,52 @@ public final class HSSFBorderFormatting
public short getBorderBottom()
{
- return borderFormatting.getBorderBottom();
+ return (short)borderFormatting.getBorderBottom();
}
public short getBorderDiagonal()
{
- return borderFormatting.getBorderDiagonal();
+ return (short)borderFormatting.getBorderDiagonal();
}
public short getBorderLeft()
{
- return borderFormatting.getBorderLeft();
+ return (short)borderFormatting.getBorderLeft();
}
public short getBorderRight()
{
- return borderFormatting.getBorderRight();
+ return (short)borderFormatting.getBorderRight();
}
public short getBorderTop()
{
- return borderFormatting.getBorderTop();
+ return (short)borderFormatting.getBorderTop();
}
public short getBottomBorderColor()
{
- return borderFormatting.getBottomBorderColor();
+ return (short)borderFormatting.getBottomBorderColor();
}
public short getDiagonalBorderColor()
{
- return borderFormatting.getDiagonalBorderColor();
+ return (short)borderFormatting.getDiagonalBorderColor();
}
public short getLeftBorderColor()
{
- return borderFormatting.getLeftBorderColor();
+ return (short)borderFormatting.getLeftBorderColor();
}
public short getRightBorderColor()
{
- return borderFormatting.getRightBorderColor();
+ return (short)borderFormatting.getRightBorderColor();
}
public short getTopBorderColor()
{
- return borderFormatting.getTopBorderColor();
+ return (short)borderFormatting.getTopBorderColor();
}
public boolean isBackwardDiagonalOn()
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
index 2554f539f9..5707356221 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
@@ -269,9 +269,8 @@ public class HSSFCell implements Cell {
* @see #CELL_TYPE_BOOLEAN
* @see #CELL_TYPE_ERROR
*/
-
- public void setCellType(int cellType)
- {
+ public void setCellType(int cellType) {
+ notifyFormulaChanging();
int row=record.getRow();
short col=record.getColumn();
short styleIndex=record.getXFIndex();
@@ -533,7 +532,7 @@ public class HSSFCell implements Cell {
* @param value value to set the cell to. For formulas we'll set the formula
* string, for String cells we'll set its value. For other types we will
* change the cell to a string cell and set its value.
- * If value is null then we will change the cell to a Blank cell.
+ * If value is <code>null</code> then we will change the cell to a Blank cell.
*/
public void setCellValue(RichTextString value)
@@ -544,6 +543,7 @@ public class HSSFCell implements Cell {
short styleIndex=record.getXFIndex();
if (hvalue == null)
{
+ notifyFormulaChanging();
setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex);
return;
}
@@ -581,25 +581,35 @@ public class HSSFCell implements Cell {
short styleIndex=record.getXFIndex();
if (formula==null) {
+ notifyFormulaChanging();
setCellType(CELL_TYPE_BLANK, false, row, col, styleIndex);
return;
}
setCellType(CELL_TYPE_FORMULA, false, row, col, styleIndex);
- FormulaRecordAggregate rec = (FormulaRecordAggregate) record;
- FormulaRecord frec = rec.getFormulaRecord();
+ FormulaRecordAggregate agg = (FormulaRecordAggregate) record;
+ FormulaRecord frec = agg.getFormulaRecord();
frec.setOptions((short) 2);
frec.setValue(0);
//only set to default if there is no extended format index already set
- if (rec.getXFIndex() == (short)0) {
- rec.setXFIndex((short) 0x0f);
+ if (agg.getXFIndex() == (short)0) {
+ agg.setXFIndex((short) 0x0f);
}
Ptg[] ptgs = HSSFFormulaParser.parse(formula, book);
- frec.setParsedExpression(ptgs);
+ agg.setParsedExpression(ptgs);
+ }
+ /**
+ * Should be called any time that a formula could potentially be deleted.
+ * Does nothing if this cell currently does not hold a formula
+ */
+ private void notifyFormulaChanging() {
+ if (record instanceof FormulaRecordAggregate) {
+ ((FormulaRecordAggregate)record).notifyFormulaChanging();
+ }
}
public String getCellFormula() {
- return HSSFFormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression());
+ return HSSFFormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaTokens());
}
/**
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
index 359862e477..9830b9f27b 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
@@ -19,7 +19,6 @@ package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.model.Workbook;
-import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.formula.NamePtg;
@@ -121,8 +120,8 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
// to make sure that all formulas POI can evaluate can also be parsed.
return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook);
}
- FormulaRecord fr = ((FormulaRecordAggregate) cell.getCellValueRecord()).getFormulaRecord();
- return fr.getParsedExpression();
+ FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();
+ return fra.getFormulaTokens();
}
private static final class Name implements EvaluationName {
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java
index cb1ae9365e..1ec1dfa9c6 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPatternFormatting.java
@@ -87,7 +87,7 @@ public class HSSFPatternFormatting
*/
public short getFillBackgroundColor()
{
- return patternFormatting.getFillBackgroundColor();
+ return (short)patternFormatting.getFillBackgroundColor();
}
/**
@@ -96,7 +96,7 @@ public class HSSFPatternFormatting
*/
public short getFillForegroundColor()
{
- return patternFormatting.getFillForegroundColor();
+ return (short)patternFormatting.getFillForegroundColor();
}
/**
@@ -105,7 +105,7 @@ public class HSSFPatternFormatting
*/
public short getFillPattern()
{
- return patternFormatting.getFillPattern();
+ return (short)patternFormatting.getFillPattern();
}
/**
diff --git a/src/java/org/apache/poi/hssf/util/CellRangeAddress8Bit.java b/src/java/org/apache/poi/hssf/util/CellRangeAddress8Bit.java
index 3b0c83fe98..ac5f540412 100644
--- a/src/java/org/apache/poi/hssf/util/CellRangeAddress8Bit.java
+++ b/src/java/org/apache/poi/hssf/util/CellRangeAddress8Bit.java
@@ -16,9 +16,10 @@
package org.apache.poi.hssf.util;
-import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.ss.util.CellRangeAddressBase;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
/**
* See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>
@@ -35,25 +36,31 @@ public final class CellRangeAddress8Bit extends CellRangeAddressBase {
super(firstRow, lastRow, firstCol, lastCol);
}
- public CellRangeAddress8Bit(RecordInputStream in) {
+ public CellRangeAddress8Bit(LittleEndianInput in) {
super(readUShortAndCheck(in), in.readUShort(), in.readUByte(), in.readUByte());
}
- private static int readUShortAndCheck(RecordInputStream in) {
- if (in.remaining() < ENCODED_SIZE) {
+ private static int readUShortAndCheck(LittleEndianInput in) {
+ if (in.available() < ENCODED_SIZE) {
// Ran out of data
throw new RuntimeException("Ran out of data reading CellRangeAddress");
}
return in.readUShort();
}
+ /**
+ * @deprecated use {@link #serialize(LittleEndianOutput)}
+ */
public int serialize(int offset, byte[] data) {
- LittleEndian.putUShort(data, offset + 0, getFirstRow());
- LittleEndian.putUShort(data, offset + 2, getLastRow());
- LittleEndian.putByte(data, offset + 4, getFirstColumn());
- LittleEndian.putByte(data, offset + 5, getLastColumn());
+ serialize(new LittleEndianByteArrayOutputStream(data, offset, ENCODED_SIZE));
return ENCODED_SIZE;
}
+ public void serialize(LittleEndianOutput out) {
+ out.writeShort(getFirstRow());
+ out.writeShort(getLastRow());
+ out.writeByte(getFirstColumn());
+ out.writeByte(getLastColumn());
+ }
public CellRangeAddress8Bit copy() {
return new CellRangeAddress8Bit(getFirstRow(), getLastRow(), getFirstColumn(), getLastColumn());
diff --git a/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java b/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
index 5f22fb7336..7f01e3d0f4 100644
--- a/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
+++ b/src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
@@ -16,11 +16,7 @@
package org.apache.poi.hssf.util;
-import java.util.ArrayList;
-import java.util.List;
-
import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
/**
* Implementation of the cell range address lists,like is described
diff --git a/src/java/org/apache/poi/ss/formula/Formula.java b/src/java/org/apache/poi/ss/formula/Formula.java
new file mode 100644
index 0000000000..55314452a2
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/Formula.java
@@ -0,0 +1,133 @@
+package org.apache.poi.ss.formula;
+
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.util.LittleEndianByteArrayInputStream;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
+
+public class Formula {
+
+ private static final byte[] EMPTY_BYTE_ARRAY = { };
+ private final byte[] _byteEncoding;
+ private final int _encodedTokenLen;
+
+ private Formula(byte[] byteEncoding, int encodedTokenLen) {
+ _byteEncoding = byteEncoding;
+ _encodedTokenLen = encodedTokenLen;
+ if (false) { // set to true to eagerly check Ptg decoding
+ LittleEndianByteArrayInputStream in = new LittleEndianByteArrayInputStream(byteEncoding);
+ Ptg.readTokens(encodedTokenLen, in);
+ int nUnusedBytes = _byteEncoding.length - in.getReadIndex();
+ if (nUnusedBytes > 0) {
+ // TODO - this seems to occur when IntersectionPtg is present
+ // This example file "IntersectionPtg.xls"
+ // used by test: TestIntersectionPtg.testReading()
+ // has 10 bytes unused at the end of the formula
+ // 10 extra bytes are just 0x01 and 0x00
+ System.out.println(nUnusedBytes + " unused bytes at end of formula");
+ }
+ }
+ }
+ /**
+ * Convenience method for {@link #read(int, LittleEndianInput, int)}
+ */
+ public static Formula read(int encodedTokenLen, LittleEndianInput in) {
+ return read(encodedTokenLen, in, encodedTokenLen);
+ }
+ /**
+ * When there are no array constants present, <tt>encodedTokenLen</tt>==<tt>totalEncodedLen</tt>
+ * @param encodedTokenLen number of bytes in the stream taken by the plain formula tokens
+ * @param totalEncodedLen the total number of bytes in the formula (includes trailing encoding
+ * for array constants, but does not include 2 bytes for initial <tt>ushort encodedTokenLen</tt> field.
+ * @return A new formula object as read from the stream. Possibly empty, never <code>null</code>.
+ */
+ public static Formula read(int encodedTokenLen, LittleEndianInput in, int totalEncodedLen) {
+ byte[] byteEncoding = new byte[totalEncodedLen];
+ in.readFully(byteEncoding);
+ return new Formula(byteEncoding, encodedTokenLen);
+ }
+
+ public Ptg[] getTokens() {
+ LittleEndianInput in = new LittleEndianByteArrayInputStream(_byteEncoding);
+ return Ptg.readTokens(_encodedTokenLen, in);
+ }
+ /**
+ * Writes The formula encoding is includes:
+ * <ul>
+ * <li>ushort tokenDataLen</li>
+ * <li>tokenData</li>
+ * <li>arrayConstantData (if present)</li>
+ * </ul>
+ */
+ public void serialize(LittleEndianOutput out) {
+ out.writeShort(_encodedTokenLen);
+ out.write(_byteEncoding);
+ }
+
+ public void serializeTokens(LittleEndianOutput out) {
+ out.write(_byteEncoding, 0, _encodedTokenLen);
+ }
+ public void serializeArrayConstantData(LittleEndianOutput out) {
+ int len = _byteEncoding.length-_encodedTokenLen;
+ out.write(_byteEncoding, _encodedTokenLen, len);
+ }
+
+
+ /**
+ * @return total formula encoding length. The formula encoding includes:
+ * <ul>
+ * <li>ushort tokenDataLen</li>
+ * <li>tokenData</li>
+ * <li>arrayConstantData (optional)</li>
+ * </ul>
+ * Note - this value is different to <tt>tokenDataLength</tt>
+ */
+ public int getEncodedSize() {
+ return 2 + _byteEncoding.length;
+ }
+ /**
+ * This method is often used when the formula length does not appear immediately before
+ * the encoded token data.
+ *
+ * @return the encoded length of the plain formula tokens. This does <em>not</em> include
+ * the leading ushort field, nor any trailing array constant data.
+ */
+ public int getEncodedTokenSize() {
+ return _encodedTokenLen;
+ }
+
+ /**
+ * Creates a {@link Formula} object from a supplied {@link Ptg} array.
+ * Handles <code>null</code>s OK.
+ * @param ptgs may be <code>null</code>
+ * @return Never <code>null</code> (Possibly empty if the supplied <tt>ptgs</tt> is <code>null</code>)
+ */
+ public static Formula create(Ptg[] ptgs) {
+ if (ptgs == null) {
+ return new Formula(EMPTY_BYTE_ARRAY, 0);
+ }
+ int totalSize = Ptg.getEncodedSize(ptgs);
+ byte[] encodedData = new byte[totalSize];
+ Ptg.serializePtgs(ptgs, encodedData, 0);
+ int encodedTokenLen = Ptg.getEncodedSizeWithoutArrayData(ptgs);
+ return new Formula(encodedData, encodedTokenLen);
+ }
+ /**
+ * Gets the {@link Ptg} array from the supplied {@link Formula}.
+ * Handles <code>null</code>s OK.
+ *
+ * @param formula may be <code>null</code>
+ * @return possibly <code>null</code> (if the supplied <tt>formula</tt> is <code>null</code>)
+ */
+ public static Ptg[] getTokens(Formula formula) {
+ if (formula == null) {
+ return null;
+ }
+ return formula.getTokens();
+ }
+
+ public Formula copy() {
+ // OK to return this for the moment because currently immutable
+ return this;
+ }
+}
diff --git a/src/java/org/apache/poi/ss/util/CellRangeAddress.java b/src/java/org/apache/poi/ss/util/CellRangeAddress.java
index 3cc70cf483..fe3c922979 100644
--- a/src/java/org/apache/poi/ss/util/CellRangeAddress.java
+++ b/src/java/org/apache/poi/ss/util/CellRangeAddress.java
@@ -18,7 +18,8 @@ package org.apache.poi.ss.util;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.SelectionRecord;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianOutput;
/**
* See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>
@@ -36,13 +37,20 @@ public class CellRangeAddress extends CellRangeAddressBase {
super(firstRow, lastRow, firstCol, lastCol);
}
+ /**
+ * @deprecated use {@link #serialize(LittleEndianOutput)}
+ */
public int serialize(int offset, byte[] data) {
- LittleEndian.putUShort(data, offset + 0, getFirstRow());
- LittleEndian.putUShort(data, offset + 2, getLastRow());
- LittleEndian.putUShort(data, offset + 4, getFirstColumn());
- LittleEndian.putUShort(data, offset + 6, getLastColumn());
+ serialize(new LittleEndianByteArrayOutputStream(data, offset, ENCODED_SIZE));
return ENCODED_SIZE;
}
+ public void serialize(LittleEndianOutput out) {
+ out.writeShort(getFirstRow());
+ out.writeShort(getLastRow());
+ out.writeShort(getFirstColumn());
+ out.writeShort(getLastColumn());
+ }
+
public CellRangeAddress(RecordInputStream in) {
super(readUShortAndCheck(in), in.readUShort(), in.readUShort(), in.readUShort());
}
diff --git a/src/java/org/apache/poi/ss/util/CellRangeAddressList.java b/src/java/org/apache/poi/ss/util/CellRangeAddressList.java
index 65474ef980..f5dd8ab7ce 100644
--- a/src/java/org/apache/poi/ss/util/CellRangeAddressList.java
+++ b/src/java/org/apache/poi/ss/util/CellRangeAddressList.java
@@ -20,7 +20,8 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianOutput;
/**
* Implementation of the cell range address lists,like is described
@@ -122,16 +123,19 @@ public class CellRangeAddressList {
}
public int serialize(int offset, byte[] data) {
- int pos = 2;
-
+ int totalSize = getSize();
+ serialize(new LittleEndianByteArrayOutputStream(data, offset, totalSize));
+ return totalSize;
+ }
+ public void serialize(LittleEndianOutput out) {
int nItems = _list.size();
- LittleEndian.putUShort(data, offset, nItems);
+ out.writeShort(nItems);
for (int k = 0; k < nItems; k++) {
CellRangeAddress region = (CellRangeAddress) _list.get(k);
- pos += region.serialize(offset + pos, data);
+ region.serialize(out);
}
- return getSize();
}
+
public CellRangeAddressList copy() {
CellRangeAddressList result = new CellRangeAddressList();
diff --git a/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java b/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java
index b77407c7a9..1b68a348be 100644
--- a/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java
+++ b/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java
@@ -81,6 +81,11 @@ public final class LittleEndianByteArrayOutputStream implements LittleEndianOutp
System.arraycopy(b, 0, _buf, _writeIndex, len);
_writeIndex += len;
}
+ public void write(byte[] b, int offset, int len) {
+ checkPosition(len);
+ System.arraycopy(b, offset, _buf, _writeIndex, len);
+ _writeIndex += len;
+ }
public int getWriteIndex() {
return _writeIndex;
}
diff --git a/src/java/org/apache/poi/util/LittleEndianOutput.java b/src/java/org/apache/poi/util/LittleEndianOutput.java
index ccea11a17d..450b337bdb 100644
--- a/src/java/org/apache/poi/util/LittleEndianOutput.java
+++ b/src/java/org/apache/poi/util/LittleEndianOutput.java
@@ -26,5 +26,6 @@ public interface LittleEndianOutput {
void writeInt(int v);
void writeLong(long v);
void writeDouble(double v);
- void write(byte[] data);
+ void write(byte[] b);
+ void write(byte[] b, int offset, int len);
}
diff --git a/src/java/org/apache/poi/util/LittleEndianOutputStream.java b/src/java/org/apache/poi/util/LittleEndianOutputStream.java
index 45f2d9e3dd..249211d049 100644
--- a/src/java/org/apache/poi/util/LittleEndianOutputStream.java
+++ b/src/java/org/apache/poi/util/LittleEndianOutputStream.java
@@ -80,4 +80,12 @@ public final class LittleEndianOutputStream extends FilterOutputStream implement
throw new RuntimeException(e);
}
}
+ public void write(byte[] b, int off, int len) {
+ // suppress IOException for interface method
+ try {
+ super.write(b, off, len);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
}