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! -->
|
<!-- 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>
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
* 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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user