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:
parent
31ccbe6fc9
commit
8264540df1
@ -37,6 +37,7 @@
|
||||
|
||||
<!-- Don't forget to update status.xml too! -->
|
||||
<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">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>
|
||||
|
@ -34,6 +34,7 @@
|
||||
<!-- Don't forget to update changes.xml too! -->
|
||||
<changes>
|
||||
<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">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>
|
||||
|
@ -24,9 +24,8 @@ import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* 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/>
|
||||
* TODO - code in ArrayPtg should be merged with this code. It currently supports only 2 of the constant types
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
|
@ -47,18 +47,31 @@ public class ErrorConstant {
|
||||
public int getErrorCode() {
|
||||
return _errorCode;
|
||||
}
|
||||
public String getText() {
|
||||
if(HSSFErrorConstants.isValidCode(_errorCode)) {
|
||||
return HSSFErrorConstants.getText(_errorCode);
|
||||
}
|
||||
return "unknown error code (" + _errorCode + ")";
|
||||
}
|
||||
|
||||
public static ErrorConstant valueOf(int errorCode) {
|
||||
switch (errorCode) {
|
||||
case HSSFErrorConstants.ERROR_NULL: return NULL;
|
||||
case HSSFErrorConstants.ERROR_DIV_0: return DIV_0;
|
||||
case HSSFErrorConstants.ERROR_VALUE: return VALUE;
|
||||
case HSSFErrorConstants.ERROR_REF: return REF;
|
||||
case HSSFErrorConstants.ERROR_NAME: return NAME;
|
||||
case HSSFErrorConstants.ERROR_NUM: return NUM;
|
||||
case HSSFErrorConstants.ERROR_NA: return NA;
|
||||
case HSSFErrorConstants.ERROR_NULL: return NULL;
|
||||
case HSSFErrorConstants.ERROR_DIV_0: return DIV_0;
|
||||
case HSSFErrorConstants.ERROR_VALUE: return VALUE;
|
||||
case HSSFErrorConstants.ERROR_REF: return REF;
|
||||
case HSSFErrorConstants.ERROR_NAME: return NAME;
|
||||
case HSSFErrorConstants.ERROR_NUM: return NUM;
|
||||
case HSSFErrorConstants.ERROR_NA: return NA;
|
||||
}
|
||||
System.err.println("Warning - unexpected error code (" + 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();
|
||||
}
|
||||
}
|
||||
|
@ -17,22 +17,17 @@
|
||||
|
||||
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.SSTRecord;
|
||||
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
|
||||
*
|
||||
* 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.
|
||||
* 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
|
||||
@ -40,209 +35,160 @@ import org.apache.poi.hssf.record.UnicodeString;
|
||||
*
|
||||
* @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
|
||||
{
|
||||
public final static byte sid = 0x20;
|
||||
protected byte field_1_reserved;
|
||||
protected byte field_2_reserved;
|
||||
protected byte field_3_reserved;
|
||||
protected byte field_4_reserved;
|
||||
protected byte field_5_reserved;
|
||||
protected byte field_6_reserved;
|
||||
protected byte field_7_reserved;
|
||||
private static final int RESERVED_FIELD_LEN = 7;
|
||||
// TODO - fix up field visibility and subclasses
|
||||
protected byte[] field_1_reserved;
|
||||
// data from these fields comes after the Ptg data of all tokens in current formula
|
||||
protected short token_1_columns;
|
||||
protected short token_2_rows;
|
||||
protected Object[] token_3_arrayValues;
|
||||
|
||||
protected ArrayPtg() {
|
||||
//Required for clone methods
|
||||
}
|
||||
|
||||
protected short token_1_columns;
|
||||
protected short token_2_rows;
|
||||
protected Object[][] token_3_arrayValues;
|
||||
public ArrayPtg(RecordInputStream in)
|
||||
{
|
||||
field_1_reserved = new byte[RESERVED_FIELD_LEN];
|
||||
// TODO - add readFully method to RecordInputStream
|
||||
for(int i=0; i< RESERVED_FIELD_LEN; i++) {
|
||||
field_1_reserved[i] = in.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
protected ArrayPtg() {
|
||||
//Required for clone methods
|
||||
}
|
||||
/**
|
||||
* Read in the actual token (array) values. This occurs
|
||||
* 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();
|
||||
short nRows = in.readShort();
|
||||
//The token_1_columns and token_2_rows do not follow the documentation.
|
||||
//The number of physical rows and columns is actually +1 of these values.
|
||||
//Which is not explicitly documented.
|
||||
nColumns++;
|
||||
nRows++;
|
||||
|
||||
public ArrayPtg(RecordInputStream in)
|
||||
{
|
||||
field_1_reserved = in.readByte();
|
||||
field_2_reserved = in.readByte();
|
||||
field_3_reserved = in.readByte();
|
||||
field_4_reserved = in.readByte();
|
||||
field_5_reserved = in.readByte();
|
||||
field_6_reserved = in.readByte();
|
||||
field_7_reserved = in.readByte();
|
||||
}
|
||||
token_1_columns = nColumns;
|
||||
token_2_rows = nRows;
|
||||
|
||||
/**
|
||||
* Read in the actual token (array) values. This occurs
|
||||
* AFTER the last Ptg in the expression.
|
||||
* See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf
|
||||
*/
|
||||
public void readTokenValues(RecordInputStream in) {
|
||||
token_1_columns = (short)(0x00ff & in.readByte());
|
||||
token_2_rows = in.readShort();
|
||||
int totalCount = nRows * nColumns;
|
||||
token_3_arrayValues = ConstantValueParser.parse(in, totalCount);
|
||||
}
|
||||
|
||||
//The token_1_columns and token_2_rows do not follow the documentation.
|
||||
//The number of physical rows and columns is actually +1 of these values.
|
||||
//Which is not explicitly documented.
|
||||
token_1_columns++;
|
||||
token_2_rows++;
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
|
||||
|
||||
token_3_arrayValues = new Object[token_1_columns][token_2_rows];
|
||||
|
||||
for (int x=0;x<token_1_columns;x++) {
|
||||
for (int y=0;y<token_2_rows;y++) {
|
||||
byte grbit = in.readByte();
|
||||
if (grbit == 0x01) {
|
||||
token_3_arrayValues[x][y] = new Double(in.readDouble());
|
||||
} else if (grbit == 0x02) {
|
||||
//Ignore the doco, it is actually a unicode string with all the
|
||||
//trimmings ie 16 bit size, option byte etc
|
||||
token_3_arrayValues[x][y] = in.readUnicodeString();
|
||||
} else throw new RecordFormatException("Unknown grbit '"+grbit+"' at " + x + "," + y + " with " + in.remaining() + " bytes left");
|
||||
buffer.append("columns = ").append(getColumnCount()).append("\n");
|
||||
buffer.append("rows = ").append(getRowCount()).append("\n");
|
||||
for (int x=0;x<getColumnCount();x++) {
|
||||
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()
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
|
||||
/* package */ int getValueIndex(int colIx, int rowIx) {
|
||||
if(colIx < 0 || colIx >= token_1_columns) {
|
||||
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");
|
||||
buffer.append("rows = ").append(getRowCount()).append("\n");
|
||||
for (int x=0;x<getColumnCount();x++) {
|
||||
for (int y=0;y<getRowCount();y++) {
|
||||
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[] data, int offset) {
|
||||
|
||||
public void writeBytes(byte [] array, 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;
|
||||
LittleEndian.putByte(data, offset + 0, sid + ptgClass);
|
||||
System.arraycopy(field_1_reserved, 0, data, offset+1, RESERVED_FIELD_LEN);
|
||||
}
|
||||
|
||||
}
|
||||
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 int writeTokenValueBytes(byte[] data, int offset) {
|
||||
|
||||
public void setRowCount(short row)
|
||||
{
|
||||
token_2_rows = row;
|
||||
}
|
||||
LittleEndian.putByte(data, offset + 0, token_1_columns-1);
|
||||
LittleEndian.putShort(data, offset + 1, (short)(token_2_rows-1));
|
||||
ConstantValueParser.encode(data, offset + 3, token_3_arrayValues);
|
||||
return 3 + ConstantValueParser.getEncodedSize(token_3_arrayValues);
|
||||
}
|
||||
|
||||
public short getRowCount()
|
||||
{
|
||||
return token_2_rows;
|
||||
}
|
||||
public short getRowCount() {
|
||||
return token_2_rows;
|
||||
}
|
||||
|
||||
public void setColumnCount(short col)
|
||||
{
|
||||
token_1_columns = (byte)col;
|
||||
}
|
||||
public short getColumnCount() {
|
||||
return token_1_columns;
|
||||
}
|
||||
|
||||
public short getColumnCount()
|
||||
{
|
||||
return token_1_columns;
|
||||
}
|
||||
/** This size includes the size of the array Ptg plus the Array Ptg Token value size*/
|
||||
public int getSize()
|
||||
{
|
||||
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 int getSize()
|
||||
{
|
||||
int size = 1+7+1+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 UnicodeString) {
|
||||
size++;
|
||||
UnicodeString.UnicodeRecordStats rs = new UnicodeString.UnicodeRecordStats();
|
||||
((UnicodeString)o).getRecordSize(rs);
|
||||
size += rs.recordSize;
|
||||
} else if (o instanceof Double) {
|
||||
size += 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
public String toFormulaString(HSSFWorkbook book)
|
||||
{
|
||||
StringBuffer b = new StringBuffer();
|
||||
b.append("{");
|
||||
for (int x=0;x<getColumnCount();x++) {
|
||||
if (x > 0) {
|
||||
b.append(";");
|
||||
}
|
||||
for (int y=0;y<getRowCount();y++) {
|
||||
if (y > 0) {
|
||||
b.append(",");
|
||||
}
|
||||
Object o = token_3_arrayValues[getValueIndex(x, y)];
|
||||
b.append(getConstantText(o));
|
||||
}
|
||||
}
|
||||
b.append("}");
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public String toFormulaString(HSSFWorkbook book)
|
||||
{
|
||||
StringBuffer b = new StringBuffer();
|
||||
b.append("{");
|
||||
for (int x=0;x<getColumnCount();x++) {
|
||||
for (int y=0;y<getRowCount();y++) {
|
||||
Object o = token_3_arrayValues[x][y];
|
||||
if (o instanceof String) {
|
||||
b.append((String)o);
|
||||
} else if (o instanceof Double) {
|
||||
b.append(((Double)o).doubleValue());
|
||||
}
|
||||
if (y != getRowCount())
|
||||
b.append(",");
|
||||
}
|
||||
if (x != getColumnCount())
|
||||
b.append(";");
|
||||
}
|
||||
b.append("}");
|
||||
return b.toString();
|
||||
}
|
||||
private static String getConstantText(Object o) {
|
||||
|
||||
public byte getDefaultOperandClass() {
|
||||
return Ptg.CLASS_ARRAY;
|
||||
}
|
||||
if (o == null) {
|
||||
return ""; // TODO - how is 'empty value' represented in formulas?
|
||||
}
|
||||
if (o instanceof UnicodeString) {
|
||||
return "\"" + ((UnicodeString)o).getString() + "\"";
|
||||
}
|
||||
if (o instanceof Double) {
|
||||
return ((Double)o).toString();
|
||||
}
|
||||
if (o instanceof Boolean) {
|
||||
((Boolean)o).toString();
|
||||
}
|
||||
if (o instanceof ErrorConstant) {
|
||||
return ((ErrorConstant)o).getText();
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected constant class (" + o.getClass().getName() + ")");
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
ArrayPtg ptg = new ArrayPtg();
|
||||
ptg.field_1_reserved = field_1_reserved;
|
||||
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;
|
||||
public byte getDefaultOperandClass() {
|
||||
return Ptg.CLASS_ARRAY;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
public Object clone() {
|
||||
ArrayPtg ptg = new ArrayPtg();
|
||||
ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
|
||||
|
||||
ptg.token_1_columns = token_1_columns;
|
||||
ptg.token_2_rows = token_2_rows;
|
||||
ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
|
||||
ptg.setClass(ptgClass);
|
||||
return ptg;
|
||||
}
|
||||
}
|
||||
|
@ -17,56 +17,31 @@
|
||||
|
||||
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.SSTRecord;
|
||||
import org.apache.poi.hssf.record.UnicodeString;
|
||||
|
||||
/**
|
||||
* ArrayPtgA - handles arrays
|
||||
*
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
|
||||
public class ArrayPtgA extends ArrayPtg
|
||||
{
|
||||
public final class ArrayPtgA extends ArrayPtg {
|
||||
public final static byte sid = 0x60;
|
||||
|
||||
protected ArrayPtgA() {
|
||||
super();
|
||||
private ArrayPtgA() {
|
||||
//Required for clone methods
|
||||
}
|
||||
|
||||
public ArrayPtgA(RecordInputStream in)
|
||||
{
|
||||
public ArrayPtgA(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
ArrayPtgA ptg = new ArrayPtgA();
|
||||
ptg.field_1_reserved = field_1_reserved;
|
||||
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.field_1_reserved = (byte[]) field_1_reserved.clone();
|
||||
|
||||
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.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
|
||||
ptg.setClass(ptgClass);
|
||||
return ptg;
|
||||
}
|
||||
|
@ -17,22 +17,12 @@
|
||||
|
||||
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.SSTRecord;
|
||||
import org.apache.poi.hssf.record.UnicodeString;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
@ -40,38 +30,24 @@ import org.apache.poi.hssf.record.UnicodeString;
|
||||
*
|
||||
* @author Jason Height (jheight at chariot dot net dot au)
|
||||
*/
|
||||
|
||||
public class ArrayPtgV extends ArrayPtg
|
||||
{
|
||||
public final class ArrayPtgV extends ArrayPtg {
|
||||
public final static byte sid = 0x40;
|
||||
|
||||
protected ArrayPtgV() {
|
||||
private ArrayPtgV() {
|
||||
//Required for clone methods
|
||||
}
|
||||
|
||||
public ArrayPtgV(RecordInputStream in)
|
||||
{
|
||||
public ArrayPtgV(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
ArrayPtgV ptg = new ArrayPtgV();
|
||||
ptg.field_1_reserved = field_1_reserved;
|
||||
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.field_1_reserved = (byte[]) field_1_reserved.clone();
|
||||
|
||||
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.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
|
||||
ptg.setClass(ptgClass);
|
||||
return ptg;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ public final class AllFormulaTests {
|
||||
result.addTestSuite(TestArea3DPtg.class);
|
||||
result.addTestSuite(TestAreaErrPtg.class);
|
||||
result.addTestSuite(TestAreaPtg.class);
|
||||
result.addTestSuite(TestArrayPtg.class);
|
||||
result.addTestSuite(TestErrPtg.class);
|
||||
result.addTestSuite(TestExternalFunctionFormulas.class);
|
||||
result.addTestSuite(TestFuncPtg.class);
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -732,7 +732,7 @@ public final class TestBugs extends TestCase {
|
||||
* with the NameRecord, once you get past the BOFRecord
|
||||
* issue.
|
||||
*/
|
||||
public void DISABLEDtest42564Alt() {
|
||||
public void test42564Alt() {
|
||||
HSSFWorkbook wb = openSample("42564-2.xls");
|
||||
writeOutAndReadBack(wb);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user