42564 - fixed ArrayPtg to use ConstantValueParser. Fixed a few other ArrayPtg encoding issues.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@653668 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-05-06 02:02:41 +00:00
parent 31ccbe6fc9
commit 8264540df1
10 changed files with 279 additions and 272 deletions

View File

@ -37,6 +37,7 @@
<!-- Don't forget to update status.xml too! --> <!-- Don't forget to update status.xml too! -->
<release version="3.1-beta2" date="2008-05-??"> <release version="3.1-beta2" date="2008-05-??">
<action dev="POI-DEVELOPERS" type="fix">42564 - fixed ArrayPtg to use ConstantValueParser. Fixed a few other ArrayPtg encoding issues.</action>
<action dev="POI-DEVELOPERS" type="fix">Follow-on from 28754 - StringPtg.toFormulaString() should escape double quotes</action> <action dev="POI-DEVELOPERS" type="fix">Follow-on from 28754 - StringPtg.toFormulaString() should escape double quotes</action>
<action dev="POI-DEVELOPERS" type="fix">44929 - Improved error handling in HSSFWorkbook when attempting to read a BIFF5 file</action> <action dev="POI-DEVELOPERS" type="fix">44929 - Improved error handling in HSSFWorkbook when attempting to read a BIFF5 file</action>
<action dev="POI-DEVELOPERS" type="fix">44675 - Parameter operand classes (function metadata) required to encode SUM() etc properly. Added parse validation for number of parameters</action> <action dev="POI-DEVELOPERS" type="fix">44675 - Parameter operand classes (function metadata) required to encode SUM() etc properly. Added parse validation for number of parameters</action>

View File

@ -34,6 +34,7 @@
<!-- Don't forget to update changes.xml too! --> <!-- Don't forget to update changes.xml too! -->
<changes> <changes>
<release version="3.1-beta2" date="2008-05-??"> <release version="3.1-beta2" date="2008-05-??">
<action dev="POI-DEVELOPERS" type="fix">42564 - fixed ArrayPtg to use ConstantValueParser. Fixed a few other ArrayPtg encoding issues.</action>
<action dev="POI-DEVELOPERS" type="fix">Follow-on from 28754 - StringPtg.toFormulaString() should escape double quotes</action> <action dev="POI-DEVELOPERS" type="fix">Follow-on from 28754 - StringPtg.toFormulaString() should escape double quotes</action>
<action dev="POI-DEVELOPERS" type="fix">44929 - Improved error handling in HSSFWorkbook when attempting to read a BIFF5 file</action> <action dev="POI-DEVELOPERS" type="fix">44929 - Improved error handling in HSSFWorkbook when attempting to read a BIFF5 file</action>
<action dev="POI-DEVELOPERS" type="fix">44675 - Parameter operand classes (function metadata) required to encode SUM() etc properly. Added parse validation for number of parameters</action> <action dev="POI-DEVELOPERS" type="fix">44675 - Parameter operand classes (function metadata) required to encode SUM() etc properly. Added parse validation for number of parameters</action>

View File

@ -24,9 +24,8 @@ import org.apache.poi.util.LittleEndian;
/** /**
* To support Constant Values (2.5.7) as required by the CRN record. * To support Constant Values (2.5.7) as required by the CRN record.
* This class should probably also be used for two dimensional arrays which are encoded by * This class is also used for two dimensional arrays which are encoded by
* EXTERNALNAME (5.39) records and Array tokens.<p/> * EXTERNALNAME (5.39) records and Array tokens.<p/>
* TODO - code in ArrayPtg should be merged with this code. It currently supports only 2 of the constant types
* *
* @author Josh Micich * @author Josh Micich
*/ */

View File

@ -47,18 +47,31 @@ public class ErrorConstant {
public int getErrorCode() { public int getErrorCode() {
return _errorCode; return _errorCode;
} }
public String getText() {
if(HSSFErrorConstants.isValidCode(_errorCode)) {
return HSSFErrorConstants.getText(_errorCode);
}
return "unknown error code (" + _errorCode + ")";
}
public static ErrorConstant valueOf(int errorCode) { public static ErrorConstant valueOf(int errorCode) {
switch (errorCode) { switch (errorCode) {
case HSSFErrorConstants.ERROR_NULL: return NULL; case HSSFErrorConstants.ERROR_NULL: return NULL;
case HSSFErrorConstants.ERROR_DIV_0: return DIV_0; case HSSFErrorConstants.ERROR_DIV_0: return DIV_0;
case HSSFErrorConstants.ERROR_VALUE: return VALUE; case HSSFErrorConstants.ERROR_VALUE: return VALUE;
case HSSFErrorConstants.ERROR_REF: return REF; case HSSFErrorConstants.ERROR_REF: return REF;
case HSSFErrorConstants.ERROR_NAME: return NAME; case HSSFErrorConstants.ERROR_NAME: return NAME;
case HSSFErrorConstants.ERROR_NUM: return NUM; case HSSFErrorConstants.ERROR_NUM: return NUM;
case HSSFErrorConstants.ERROR_NA: return NA; case HSSFErrorConstants.ERROR_NA: return NA;
} }
System.err.println("Warning - unexpected error code (" + errorCode + ")"); System.err.println("Warning - unexpected error code (" + errorCode + ")");
return new ErrorConstant(errorCode); return new ErrorConstant(errorCode);
} }
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");
sb.append(getText());
sb.append("]");
return sb.toString();
}
} }

View File

@ -17,22 +17,17 @@
package org.apache.poi.hssf.record.formula; package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.StringUtil;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.UnicodeString; import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.record.constant.ConstantValueParser;
import org.apache.poi.hssf.record.constant.ErrorConstant;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndian;
/** /**
* ArrayPtg - handles arrays * ArrayPtg - handles arrays
* *
* The ArrayPtg is a little wierd, the size of the Ptg when parsing initially only * The ArrayPtg is a little weird, the size of the Ptg when parsing initially only
* includes the Ptg sid and the reserved bytes. The next Ptg in the expression then follows. * includes the Ptg sid and the reserved bytes. The next Ptg in the expression then follows.
* It is only after the "size" of all the Ptgs is met, that the ArrayPtg data is actually * It is only after the "size" of all the Ptgs is met, that the ArrayPtg data is actually
* held after this. So Ptg.createParsedExpression keeps track of the number of * held after this. So Ptg.createParsedExpression keeps track of the number of
@ -40,209 +35,160 @@ import org.apache.poi.hssf.record.UnicodeString;
* *
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public class ArrayPtg extends Ptg {
public static final byte sid = 0x20;
public class ArrayPtg extends Ptg private static final int RESERVED_FIELD_LEN = 7;
{ // TODO - fix up field visibility and subclasses
public final static byte sid = 0x20; protected byte[] field_1_reserved;
protected byte field_1_reserved; // data from these fields comes after the Ptg data of all tokens in current formula
protected byte field_2_reserved; protected short token_1_columns;
protected byte field_3_reserved; protected short token_2_rows;
protected byte field_4_reserved; protected Object[] token_3_arrayValues;
protected byte field_5_reserved;
protected byte field_6_reserved;
protected byte field_7_reserved;
protected short token_1_columns;
protected short token_2_rows;
protected Object[][] token_3_arrayValues;
protected ArrayPtg() { protected ArrayPtg() {
//Required for clone methods //Required for clone methods
} }
public ArrayPtg(RecordInputStream in) public ArrayPtg(RecordInputStream in)
{ {
field_1_reserved = in.readByte(); field_1_reserved = new byte[RESERVED_FIELD_LEN];
field_2_reserved = in.readByte(); // TODO - add readFully method to RecordInputStream
field_3_reserved = in.readByte(); for(int i=0; i< RESERVED_FIELD_LEN; i++) {
field_4_reserved = in.readByte(); field_1_reserved[i] = in.readByte();
field_5_reserved = in.readByte(); }
field_6_reserved = in.readByte(); }
field_7_reserved = in.readByte();
} /**
* Read in the actual token (array) values. This occurs
/** * AFTER the last Ptg in the expression.
* Read in the actual token (array) values. This occurs * See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf
* AFTER the last Ptg in the expression. */
* See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf public void readTokenValues(RecordInputStream in) {
*/ short nColumns = in.readUByte();
public void readTokenValues(RecordInputStream in) { short nRows = in.readShort();
token_1_columns = (short)(0x00ff & in.readByte()); //The token_1_columns and token_2_rows do not follow the documentation.
token_2_rows = in.readShort(); //The number of physical rows and columns is actually +1 of these values.
//Which is not explicitly documented.
//The token_1_columns and token_2_rows do not follow the documentation. nColumns++;
//The number of physical rows and columns is actually +1 of these values. nRows++;
//Which is not explicitly documented.
token_1_columns++; token_1_columns = nColumns;
token_2_rows++; token_2_rows = nRows;
token_3_arrayValues = new Object[token_1_columns][token_2_rows]; int totalCount = nRows * nColumns;
token_3_arrayValues = ConstantValueParser.parse(in, totalCount);
for (int x=0;x<token_1_columns;x++) { }
for (int y=0;y<token_2_rows;y++) {
byte grbit = in.readByte(); public String toString()
if (grbit == 0x01) { {
token_3_arrayValues[x][y] = new Double(in.readDouble()); StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
} else if (grbit == 0x02) {
//Ignore the doco, it is actually a unicode string with all the buffer.append("columns = ").append(getColumnCount()).append("\n");
//trimmings ie 16 bit size, option byte etc buffer.append("rows = ").append(getRowCount()).append("\n");
token_3_arrayValues[x][y] = in.readUnicodeString(); for (int x=0;x<getColumnCount();x++) {
} else throw new RecordFormatException("Unknown grbit '"+grbit+"' at " + x + "," + y + " with " + in.remaining() + " bytes left"); for (int y=0;y<getRowCount();y++) {
Object o = token_3_arrayValues[getValueIndex(x, y)];
buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n");
} }
} }
} return buffer.toString();
}
public String toString() /* package */ int getValueIndex(int colIx, int rowIx) {
{ if(colIx < 0 || colIx >= token_1_columns) {
StringBuffer buffer = new StringBuffer("[ArrayPtg]\n"); throw new IllegalArgumentException("Specified colIx (" + colIx
+ ") is outside the allowed range (0.." + (token_1_columns-1) + ")");
}
if(rowIx < 0 || rowIx >= token_2_rows) {
throw new IllegalArgumentException("Specified rowIx (" + rowIx
+ ") is outside the allowed range (0.." + (token_2_rows-1) + ")");
}
return rowIx * token_1_columns + colIx;
}
buffer.append("columns = ").append(getColumnCount()).append("\n"); public void writeBytes(byte[] data, int offset) {
buffer.append("rows = ").append(getRowCount()).append("\n");
for (int x=0;x<getColumnCount();x++) { LittleEndian.putByte(data, offset + 0, sid + ptgClass);
for (int y=0;y<getRowCount();y++) { System.arraycopy(field_1_reserved, 0, data, offset+1, RESERVED_FIELD_LEN);
Object o = token_3_arrayValues[x][y]; }
buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n");
}
}
return buffer.toString();
}
public void writeBytes(byte [] array, int offset) public int writeTokenValueBytes(byte[] data, int offset) {
{
array[offset++] = (byte) (sid + ptgClass);
array[offset++] = field_1_reserved;
array[offset++] = field_2_reserved;
array[offset++] = field_3_reserved;
array[offset++] = field_4_reserved;
array[offset++] = field_5_reserved;
array[offset++] = field_6_reserved;
array[offset++] = field_7_reserved;
}
public int writeTokenValueBytes(byte [] array, int offset) {
int pos = 0;
array[pos + offset] = (byte)(token_1_columns-1);
pos++;
LittleEndian.putShort(array, pos+offset, (short)(token_2_rows-1));
pos += 2;
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
Object o = token_3_arrayValues[x][y];
if (o instanceof Double) {
array[pos+offset] = 0x01;
pos++;
LittleEndian.putDouble(array, pos+offset, ((Double)o).doubleValue());
pos+=8;
} else if (o instanceof UnicodeString) {
array[pos+offset] = 0x02;
pos++;
UnicodeString s = (UnicodeString)o;
//JMH TBD Handle string continuation. Id do it now but its 4am.
UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats();
s.serialize(stats, pos + offset, array);
pos += stats.recordSize;
} else throw new RuntimeException("Coding error");
}
}
return pos;
}
public void setRowCount(short row) LittleEndian.putByte(data, offset + 0, token_1_columns-1);
{ LittleEndian.putShort(data, offset + 1, (short)(token_2_rows-1));
token_2_rows = row; ConstantValueParser.encode(data, offset + 3, token_3_arrayValues);
} return 3 + ConstantValueParser.getEncodedSize(token_3_arrayValues);
}
public short getRowCount() public short getRowCount() {
{ return token_2_rows;
return token_2_rows; }
}
public void setColumnCount(short col) public short getColumnCount() {
{ return token_1_columns;
token_1_columns = (byte)col; }
}
public short getColumnCount() /** This size includes the size of the array Ptg plus the Array Ptg Token value size*/
{ public int getSize()
return token_1_columns; {
} int size = 1+7+1+2;
size += ConstantValueParser.getEncodedSize(token_3_arrayValues);
return size;
}
/** This size includes the size of the array Ptg plus the Array Ptg Token value size*/ public String toFormulaString(HSSFWorkbook book)
public int getSize() {
{ StringBuffer b = new StringBuffer();
int size = 1+7+1+2; b.append("{");
for (int x=0;x<getColumnCount();x++) { for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) { if (x > 0) {
Object o = token_3_arrayValues[x][y]; b.append(";");
if (o instanceof UnicodeString) { }
size++; for (int y=0;y<getRowCount();y++) {
UnicodeString.UnicodeRecordStats rs = new UnicodeString.UnicodeRecordStats(); if (y > 0) {
((UnicodeString)o).getRecordSize(rs); b.append(",");
size += rs.recordSize; }
} else if (o instanceof Double) { Object o = token_3_arrayValues[getValueIndex(x, y)];
size += 9; b.append(getConstantText(o));
} }
} }
} b.append("}");
return size; return b.toString();
} }
private static String getConstantText(Object o) {
public String toFormulaString(HSSFWorkbook book) if (o == null) {
{ return ""; // TODO - how is 'empty value' represented in formulas?
StringBuffer b = new StringBuffer(); }
b.append("{"); if (o instanceof UnicodeString) {
for (int x=0;x<getColumnCount();x++) { return "\"" + ((UnicodeString)o).getString() + "\"";
for (int y=0;y<getRowCount();y++) { }
Object o = token_3_arrayValues[x][y]; if (o instanceof Double) {
if (o instanceof String) { return ((Double)o).toString();
b.append((String)o); }
} else if (o instanceof Double) { if (o instanceof Boolean) {
b.append(((Double)o).doubleValue()); ((Boolean)o).toString();
} }
if (y != getRowCount()) if (o instanceof ErrorConstant) {
b.append(","); return ((ErrorConstant)o).getText();
} }
if (x != getColumnCount()) throw new IllegalArgumentException("Unexpected constant class (" + o.getClass().getName() + ")");
b.append(";"); }
}
b.append("}"); public byte getDefaultOperandClass() {
return b.toString(); return Ptg.CLASS_ARRAY;
} }
public byte getDefaultOperandClass() { public Object clone() {
return Ptg.CLASS_ARRAY; ArrayPtg ptg = new ArrayPtg();
} ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
public Object clone() { ptg.token_1_columns = token_1_columns;
ArrayPtg ptg = new ArrayPtg(); ptg.token_2_rows = token_2_rows;
ptg.field_1_reserved = field_1_reserved; ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
ptg.field_2_reserved = field_2_reserved; ptg.setClass(ptgClass);
ptg.field_3_reserved = field_3_reserved; return ptg;
ptg.field_4_reserved = field_4_reserved; }
ptg.field_5_reserved = field_5_reserved;
ptg.field_6_reserved = field_6_reserved;
ptg.field_7_reserved = field_7_reserved;
ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = new Object[getColumnCount()][getRowCount()];
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
ptg.token_3_arrayValues[x][y] = token_3_arrayValues[x][y];
}
}
ptg.setClass(ptgClass);
return ptg;
}
} }

View File

@ -17,56 +17,31 @@
package org.apache.poi.hssf.record.formula; package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.StringUtil;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.UnicodeString;
/** /**
* ArrayPtgA - handles arrays * ArrayPtgA - handles arrays
* *
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public final class ArrayPtgA extends ArrayPtg {
public class ArrayPtgA extends ArrayPtg
{
public final static byte sid = 0x60; public final static byte sid = 0x60;
protected ArrayPtgA() { private ArrayPtgA() {
super();
//Required for clone methods //Required for clone methods
} }
public ArrayPtgA(RecordInputStream in) public ArrayPtgA(RecordInputStream in) {
{
super(in); super(in);
} }
public Object clone() { public Object clone() {
ArrayPtgA ptg = new ArrayPtgA(); ArrayPtgA ptg = new ArrayPtgA();
ptg.field_1_reserved = field_1_reserved; ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
ptg.field_2_reserved = field_2_reserved;
ptg.field_3_reserved = field_3_reserved;
ptg.field_4_reserved = field_4_reserved;
ptg.field_5_reserved = field_5_reserved;
ptg.field_6_reserved = field_6_reserved;
ptg.field_7_reserved = field_7_reserved;
ptg.token_1_columns = token_1_columns; ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows; ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = new Object[getColumnCount()][getRowCount()]; ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
ptg.token_3_arrayValues[x][y] = token_3_arrayValues[x][y];
}
}
ptg.setClass(ptgClass); ptg.setClass(ptgClass);
return ptg; return ptg;
} }

View File

@ -17,22 +17,12 @@
package org.apache.poi.hssf.record.formula; package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.StringUtil;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.UnicodeString;
/** /**
* ArrayPtg - handles arrays * ArrayPtg - handles arrays
* *
* The ArrayPtg is a little wierd, the size of the Ptg when parsing initially only * The ArrayPtg is a little weird, the size of the Ptg when parsing initially only
* includes the Ptg sid and the reserved bytes. The next Ptg in the expression then follows. * includes the Ptg sid and the reserved bytes. The next Ptg in the expression then follows.
* It is only after the "size" of all the Ptgs is met, that the ArrayPtg data is actually * It is only after the "size" of all the Ptgs is met, that the ArrayPtg data is actually
* held after this. So Ptg.createParsedExpression keeps track of the number of * held after this. So Ptg.createParsedExpression keeps track of the number of
@ -40,38 +30,24 @@ import org.apache.poi.hssf.record.UnicodeString;
* *
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public final class ArrayPtgV extends ArrayPtg {
public class ArrayPtgV extends ArrayPtg
{
public final static byte sid = 0x40; public final static byte sid = 0x40;
protected ArrayPtgV() { private ArrayPtgV() {
//Required for clone methods //Required for clone methods
} }
public ArrayPtgV(RecordInputStream in) public ArrayPtgV(RecordInputStream in) {
{
super(in); super(in);
} }
public Object clone() { public Object clone() {
ArrayPtgV ptg = new ArrayPtgV(); ArrayPtgV ptg = new ArrayPtgV();
ptg.field_1_reserved = field_1_reserved; ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
ptg.field_2_reserved = field_2_reserved;
ptg.field_3_reserved = field_3_reserved;
ptg.field_4_reserved = field_4_reserved;
ptg.field_5_reserved = field_5_reserved;
ptg.field_6_reserved = field_6_reserved;
ptg.field_7_reserved = field_7_reserved;
ptg.token_1_columns = token_1_columns; ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows; ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = new Object[getColumnCount()][getRowCount()]; ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
ptg.token_3_arrayValues[x][y] = token_3_arrayValues[x][y];
}
}
ptg.setClass(ptgClass); ptg.setClass(ptgClass);
return ptg; return ptg;
} }

View File

@ -40,6 +40,7 @@ public final class AllFormulaTests {
result.addTestSuite(TestArea3DPtg.class); result.addTestSuite(TestArea3DPtg.class);
result.addTestSuite(TestAreaErrPtg.class); result.addTestSuite(TestAreaErrPtg.class);
result.addTestSuite(TestAreaPtg.class); result.addTestSuite(TestAreaPtg.class);
result.addTestSuite(TestArrayPtg.class);
result.addTestSuite(TestErrPtg.class); result.addTestSuite(TestErrPtg.class);
result.addTestSuite(TestExternalFunctionFormulas.class); result.addTestSuite(TestExternalFunctionFormulas.class);
result.addTestSuite(TestFuncPtg.class); result.addTestSuite(TestFuncPtg.class);

View File

@ -0,0 +1,95 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import java.util.Arrays;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
/**
* Tests for <tt>ArrayPtg</tt>
*
* @author Josh Micich
*/
public final class TestArrayPtg extends TestCase {
private static final byte[] ENCODED_PTG_DATA = {
0x40, 0x00,
0x08, 0x00,
0, 0, 0, 0, 0, 0, 0, 0,
};
private static final byte[] ENCODED_CONSTANT_DATA = {
2, // 3 columns
1, 0, // 2 rows
4, 1, 0, 0, 0, 0, 0, 0, 0, // TRUE
2, 4, 0, 0, 65, 66, 67, 68, // "ABCD"
2, 1, 0, 0, 69, // "E"
1, 0, 0, 0, 0, 0, 0, 0, 0, // 0
4, 0, 0, 0, 0, 0, 0, 0, 0, // FALSE
2, 2, 0, 0, 70, 71, // "FG"
};
/**
* Lots of problems with ArrayPtg's encoding of
*/
public void testReadWriteTokenValueBytes() {
ArrayPtg ptg = new ArrayPtgV(new TestcaseRecordInputStream(ArrayPtgV.sid, ENCODED_PTG_DATA));
ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
Object[] values = ptg.token_3_arrayValues;
assertEquals(6, values.length);
assertEquals(Boolean.TRUE, values[0]);
assertEquals(new UnicodeString("ABCD"), values[1]);
assertEquals(new Double(0), values[3]);
assertEquals(Boolean.FALSE, values[4]);
assertEquals(new UnicodeString("FG"), values[5]);
byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.length];
ptg.writeTokenValueBytes(outBuf, 0);
if(outBuf[0] == 4) {
throw new AssertionFailedError("Identified bug 42564b");
}
assertTrue(Arrays.equals(ENCODED_CONSTANT_DATA, outBuf));
}
/**
* make sure constant elements are stored row by row
*/
public void testElementOrdering() {
ArrayPtg ptg = new ArrayPtgV(new TestcaseRecordInputStream(ArrayPtgV.sid, ENCODED_PTG_DATA));
ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
assertEquals(0, ptg.getValueIndex(0, 0));
assertEquals(1, ptg.getValueIndex(1, 0));
assertEquals(2, ptg.getValueIndex(2, 0));
assertEquals(3, ptg.getValueIndex(0, 1));
assertEquals(4, ptg.getValueIndex(1, 1));
assertEquals(5, ptg.getValueIndex(2, 1));
}
}

View File

@ -732,7 +732,7 @@ public final class TestBugs extends TestCase {
* with the NameRecord, once you get past the BOFRecord * with the NameRecord, once you get past the BOFRecord
* issue. * issue.
*/ */
public void DISABLEDtest42564Alt() { public void test42564Alt() {
HSSFWorkbook wb = openSample("42564-2.xls"); HSSFWorkbook wb = openSample("42564-2.xls");
writeOutAndReadBack(wb); writeOutAndReadBack(wb);
} }