Bug37630: SQUASHED! Array Ptgs now implemented (at least the read and write functionality. No means to modify (yet!))
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@370987 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1d00be095e
commit
84e47bd7bb
@ -100,26 +100,12 @@ public class FormulaRecord
|
|||||||
|
|
||||||
field_6_zero = in.readInt();
|
field_6_zero = in.readInt();
|
||||||
field_7_expression_len = in.readShort();
|
field_7_expression_len = in.readShort();
|
||||||
field_8_parsed_expr = getParsedExpressionTokens(in, field_7_expression_len);
|
field_8_parsed_expr = Ptg.createParsedExpressionTokens(field_7_expression_len, in);
|
||||||
} catch (java.lang.UnsupportedOperationException uoe) {
|
} catch (java.lang.UnsupportedOperationException uoe) {
|
||||||
throw new RecordFormatException(uoe.toString());
|
throw new RecordFormatException(uoe.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stack getParsedExpressionTokens(RecordInputStream in, short size)
|
|
||||||
{
|
|
||||||
Stack stack = new Stack();
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
while (pos < size)
|
|
||||||
{
|
|
||||||
Ptg ptg = Ptg.createPtg(in);
|
|
||||||
pos += ptg.getSize();
|
|
||||||
stack.push(ptg);
|
|
||||||
}
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
//public void setRow(short row)
|
//public void setRow(short row)
|
||||||
public void setRow(int row)
|
public void setRow(int row)
|
||||||
{
|
{
|
||||||
@ -330,7 +316,7 @@ public class FormulaRecord
|
|||||||
//Microsoft Excel Developer's Kit Page 318
|
//Microsoft Excel Developer's Kit Page 318
|
||||||
LittleEndian.putInt(data, 20 + offset, 0);
|
LittleEndian.putInt(data, 20 + offset, 0);
|
||||||
LittleEndian.putShort(data, 24 + offset, getExpressionLength());
|
LittleEndian.putShort(data, 24 + offset, getExpressionLength());
|
||||||
serializePtgs(data, 26+offset);
|
Ptg.serializePtgStack(field_8_parsed_expr, data, 26+offset);
|
||||||
} else {
|
} else {
|
||||||
System.arraycopy(all_data,0,data,offset,all_data.length);
|
System.arraycopy(all_data,0,data,offset,all_data.length);
|
||||||
}
|
}
|
||||||
@ -368,19 +354,6 @@ public class FormulaRecord
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serializePtgs(byte [] data, int offset)
|
|
||||||
{
|
|
||||||
int pos = offset;
|
|
||||||
|
|
||||||
for (int k = 0; k < field_8_parsed_expr.size(); k++)
|
|
||||||
{
|
|
||||||
Ptg ptg = ( Ptg ) field_8_parsed_expr.get(k);
|
|
||||||
|
|
||||||
ptg.writeBytes(data, pos);
|
|
||||||
pos += ptg.getSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBefore(CellValueRecordInterface i)
|
public boolean isBefore(CellValueRecordInterface i)
|
||||||
{
|
{
|
||||||
if (this.getRow() > i.getRow())
|
if (this.getRow() > i.getRow())
|
||||||
|
@ -49,7 +49,7 @@ public class LinkedDataFormulaField
|
|||||||
public int fillField( RecordInputStream in )
|
public int fillField( RecordInputStream in )
|
||||||
{
|
{
|
||||||
short tokenSize = in.readShort();
|
short tokenSize = in.readShort();
|
||||||
formulaTokens = getParsedExpressionTokens(tokenSize, in);
|
formulaTokens = Ptg.createParsedExpressionTokens(tokenSize, in);
|
||||||
|
|
||||||
return tokenSize + 2;
|
return tokenSize + 2;
|
||||||
}
|
}
|
||||||
@ -80,12 +80,7 @@ public class LinkedDataFormulaField
|
|||||||
int size = getSize();
|
int size = getSize();
|
||||||
LittleEndian.putShort(data, offset, (short)(size - 2));
|
LittleEndian.putShort(data, offset, (short)(size - 2));
|
||||||
int pos = offset + 2;
|
int pos = offset + 2;
|
||||||
for ( Iterator iterator = formulaTokens.iterator(); iterator.hasNext(); )
|
pos += Ptg.serializePtgStack(formulaTokens, data, pos);
|
||||||
{
|
|
||||||
Ptg ptg = (Ptg) iterator.next();
|
|
||||||
ptg.writeBytes(data, pos);
|
|
||||||
pos += ptg.getSize();
|
|
||||||
}
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,19 +98,6 @@ public class LinkedDataFormulaField
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stack getParsedExpressionTokens(short size, RecordInputStream in )
|
|
||||||
{
|
|
||||||
Stack stack = new Stack();
|
|
||||||
int pos = 0;
|
|
||||||
while ( pos < size )
|
|
||||||
{
|
|
||||||
Ptg ptg = Ptg.createPtg( in );
|
|
||||||
pos += ptg.getSize();
|
|
||||||
stack.push( ptg );
|
|
||||||
}
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFormulaTokens( Stack formulaTokens )
|
public void setFormulaTokens( Stack formulaTokens )
|
||||||
{
|
{
|
||||||
this.formulaTokens = (Stack) formulaTokens.clone();
|
this.formulaTokens = (Stack) formulaTokens.clone();
|
||||||
|
@ -331,7 +331,7 @@ public class NameRecord extends Record {
|
|||||||
/** get the definition length
|
/** get the definition length
|
||||||
* @return definition length
|
* @return definition length
|
||||||
*/
|
*/
|
||||||
public short getDefinitionTextLength(){
|
public short getDefinitionLength(){
|
||||||
return field_4_length_name_definition;
|
return field_4_length_name_definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,7 +488,7 @@ public class NameRecord extends Record {
|
|||||||
throw new RecordFormatException("NOT A valid Name RECORD");
|
throw new RecordFormatException("NOT A valid Name RECORD");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called by the class that is responsible for writing this sucker.
|
* called by the class that is responsible for writing this sucker.
|
||||||
* Subclasses should implement this so that their data is passed back in a
|
* Subclasses should implement this so that their data is passed back in a
|
||||||
@ -501,11 +501,13 @@ public class NameRecord extends Record {
|
|||||||
public int serialize( int offset, byte[] data )
|
public int serialize( int offset, byte[] data )
|
||||||
{
|
{
|
||||||
LittleEndian.putShort( data, 0 + offset, sid );
|
LittleEndian.putShort( data, 0 + offset, sid );
|
||||||
|
short size = (short)( 15 + getTextsLength() + getNameDefinitionSize());
|
||||||
|
LittleEndian.putShort( data, 2 + offset, size );
|
||||||
// size defined below
|
// size defined below
|
||||||
LittleEndian.putShort( data, 4 + offset, getOptionFlag() );
|
LittleEndian.putShort( data, 4 + offset, getOptionFlag() );
|
||||||
data[6 + offset] = getKeyboardShortcut();
|
data[6 + offset] = getKeyboardShortcut();
|
||||||
data[7 + offset] = getNameTextLength();
|
data[7 + offset] = getNameTextLength();
|
||||||
LittleEndian.putShort( data, 8 + offset, getDefinitionTextLength() );
|
LittleEndian.putShort( data, 8 + offset, getDefinitionLength() );
|
||||||
LittleEndian.putShort( data, 10 + offset, getUnused() );
|
LittleEndian.putShort( data, 10 + offset, getUnused() );
|
||||||
LittleEndian.putShort( data, 12 + offset, getEqualsToIndexToSheet() );
|
LittleEndian.putShort( data, 12 + offset, getEqualsToIndexToSheet() );
|
||||||
data[14 + offset] = getCustomMenuLength();
|
data[14 + offset] = getCustomMenuLength();
|
||||||
@ -525,8 +527,7 @@ public class NameRecord extends Record {
|
|||||||
return 20 + field_13_raw_name_definition.length;
|
return 20 + field_13_raw_name_definition.length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ */
|
{ */
|
||||||
LittleEndian.putShort( data, 2 + offset, (short) ( 15 + getTextsLength() ) );
|
|
||||||
|
|
||||||
int start_of_name_definition = 19 + field_3_length_name_text;
|
int start_of_name_definition = 19 + field_3_length_name_text;
|
||||||
|
|
||||||
@ -539,7 +540,7 @@ public class NameRecord extends Record {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
serializePtgs( data, start_of_name_definition + offset );
|
Ptg.serializePtgStack(field_13_name_definition, data, start_of_name_definition + offset );
|
||||||
|
|
||||||
|
|
||||||
int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition;
|
int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition;
|
||||||
@ -558,37 +559,39 @@ public class NameRecord extends Record {
|
|||||||
/* } */
|
/* } */
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serializePtgs(byte [] data, int offset) {
|
|
||||||
int pos = offset;
|
|
||||||
|
|
||||||
for (int k = 0; k < field_13_name_definition.size(); k++) {
|
|
||||||
Ptg ptg = ( Ptg ) field_13_name_definition.get(k);
|
|
||||||
|
|
||||||
ptg.writeBytes(data, pos);
|
|
||||||
pos += ptg.getSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** gets the length of all texts
|
/** gets the length of all texts
|
||||||
* @return total length
|
* @return total length
|
||||||
*/
|
*/
|
||||||
public int getTextsLength(){
|
public int getTextsLength(){
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = getNameTextLength() + getDefinitionTextLength() + getDescriptionTextLength() +
|
result = getNameTextLength() + getDescriptionTextLength() +
|
||||||
getHelpTopicLength() + getStatusBarLength();
|
getHelpTopicLength() + getStatusBarLength();
|
||||||
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getNameDefinitionSize() {
|
||||||
|
int result = 0;
|
||||||
|
List list = field_13_name_definition;
|
||||||
|
|
||||||
|
for (int k = 0; k < list.size(); k++)
|
||||||
|
{
|
||||||
|
Ptg ptg = ( Ptg ) list.get(k);
|
||||||
|
|
||||||
|
result += ptg.getSize();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/** returns the record size
|
/** returns the record size
|
||||||
*/
|
*/
|
||||||
public int getRecordSize(){
|
public int getRecordSize(){
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = 19 + getTextsLength();
|
result = 19 + getTextsLength() + getNameDefinitionSize();
|
||||||
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -733,7 +736,7 @@ public class NameRecord extends Record {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field_13_name_definition = getParsedExpressionTokens(in, field_4_length_name_definition);
|
field_13_name_definition = Ptg.createParsedExpressionTokens(field_4_length_name_definition, in);
|
||||||
|
|
||||||
//Who says that this can only ever be compressed unicode???
|
//Who says that this can only ever be compressed unicode???
|
||||||
field_14_custom_menu_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_7_length_custom_menu));
|
field_14_custom_menu_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_7_length_custom_menu));
|
||||||
@ -746,23 +749,6 @@ public class NameRecord extends Record {
|
|||||||
/*} */
|
/*} */
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stack getParsedExpressionTokens(RecordInputStream in, short size) {
|
|
||||||
Stack stack = new Stack();
|
|
||||||
int sizeCounter = 0;
|
|
||||||
try {
|
|
||||||
while (sizeCounter < size) {
|
|
||||||
Ptg ptg = Ptg.createPtg(in);
|
|
||||||
|
|
||||||
sizeCounter += ptg.getSize();
|
|
||||||
stack.push(ptg);
|
|
||||||
}
|
|
||||||
} catch (java.lang.UnsupportedOperationException uoe) {
|
|
||||||
throw new RecordFormatException(uoe.toString());
|
|
||||||
}
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the non static version of the id for this record.
|
* return the non static version of the id for this record.
|
||||||
*/
|
*/
|
||||||
|
246
src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java
Normal file
246
src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2003-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
Licensed 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 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.model.Workbook;
|
||||||
|
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
|
||||||
|
* 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
|
||||||
|
* ArrayPtg elements and need to parse the data upto the FORMULA record size.
|
||||||
|
*
|
||||||
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
protected short token_1_columns;
|
||||||
|
protected short token_2_rows;
|
||||||
|
protected Object[][] token_3_arrayValues;
|
||||||
|
|
||||||
|
protected ArrayPtg() {
|
||||||
|
//Required for clone methods
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read in the actual token (array) values. This occurs AFTER the last
|
||||||
|
* Ptg in the expression.
|
||||||
|
*/
|
||||||
|
public void readTokenValues(RecordInputStream in) {
|
||||||
|
token_1_columns = (short)(0x00ff & in.readByte());
|
||||||
|
token_2_rows = 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.
|
||||||
|
token_1_columns++;
|
||||||
|
token_2_rows++;
|
||||||
|
|
||||||
|
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] = Double.valueOf(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+"'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
|
||||||
|
|
||||||
|
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 [] 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
token_2_rows = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRowCount()
|
||||||
|
{
|
||||||
|
return token_2_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColumnCount(short col)
|
||||||
|
{
|
||||||
|
token_1_columns = (byte)col;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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(Workbook 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getDefaultOperandClass() {
|
||||||
|
return Ptg.CLASS_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
72
src/java/org/apache/poi/hssf/record/formula/ArrayPtgA.java
Normal file
72
src/java/org/apache/poi/hssf/record/formula/ArrayPtgA.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2003-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
Licensed 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 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.model.Workbook;
|
||||||
|
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 static byte sid = 0x60;
|
||||||
|
|
||||||
|
protected ArrayPtgA() {
|
||||||
|
super();
|
||||||
|
//Required for clone methods
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
}
|
||||||
|
}
|
77
src/java/org/apache/poi/hssf/record/formula/ArrayPtgV.java
Normal file
77
src/java/org/apache/poi/hssf/record/formula/ArrayPtgV.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2003-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
Licensed 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 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.model.Workbook;
|
||||||
|
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
|
||||||
|
* 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
|
||||||
|
* ArrayPtg elements and need to parse the data upto the FORMULA record size.
|
||||||
|
*
|
||||||
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ArrayPtgV extends ArrayPtg
|
||||||
|
{
|
||||||
|
public final static byte sid = 0x40;
|
||||||
|
|
||||||
|
protected ArrayPtgV() {
|
||||||
|
//Required for clone methods
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ package org.apache.poi.hssf.record.formula;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
import org.apache.poi.hssf.model.Workbook;
|
import org.apache.poi.hssf.model.Workbook;
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
@ -85,8 +86,33 @@ public abstract class Ptg
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
public static Stack createParsedExpressionTokens(short size, RecordInputStream in )
|
||||||
|
{
|
||||||
|
Stack stack = new Stack();
|
||||||
|
int pos = 0;
|
||||||
|
List arrayPtgs = null;
|
||||||
|
while ( pos < size )
|
||||||
|
{
|
||||||
|
Ptg ptg = Ptg.createPtg( in );
|
||||||
|
if (ptg instanceof ArrayPtg) {
|
||||||
|
if (arrayPtgs == null)
|
||||||
|
arrayPtgs = new ArrayList(5);
|
||||||
|
arrayPtgs.add(ptg);
|
||||||
|
pos += 8;
|
||||||
|
} else pos += ptg.getSize();
|
||||||
|
stack.push( ptg );
|
||||||
|
}
|
||||||
|
if (arrayPtgs != null) {
|
||||||
|
for (int i=0;i<arrayPtgs.size();i++) {
|
||||||
|
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
|
||||||
|
p.readTokenValues(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
public static Ptg createPtg(RecordInputStream in)
|
private static Ptg createPtg(RecordInputStream in)
|
||||||
{
|
{
|
||||||
byte id = in.readByte();
|
byte id = in.readByte();
|
||||||
Ptg retval = null;
|
Ptg retval = null;
|
||||||
@ -157,6 +183,16 @@ public abstract class Ptg
|
|||||||
case ConcatPtg.sid :
|
case ConcatPtg.sid :
|
||||||
retval = new ConcatPtg(in);
|
retval = new ConcatPtg(in);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ArrayPtg.sid:
|
||||||
|
retval = new ArrayPtg(in);
|
||||||
|
break;
|
||||||
|
case ArrayPtgV.sid:
|
||||||
|
retval = new ArrayPtgV(in);
|
||||||
|
break;
|
||||||
|
case ArrayPtgA.sid:
|
||||||
|
retval = new ArrayPtgA(in);
|
||||||
|
break;
|
||||||
|
|
||||||
case AreaPtg.sid :
|
case AreaPtg.sid :
|
||||||
retval = new AreaPtg(in);
|
retval = new AreaPtg(in);
|
||||||
@ -304,6 +340,34 @@ public abstract class Ptg
|
|||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int serializePtgStack(Stack expression, byte[] array, int offset) {
|
||||||
|
int pos = 0;
|
||||||
|
int size = 0;
|
||||||
|
if (expression != null)
|
||||||
|
size = expression.size();
|
||||||
|
|
||||||
|
List arrayPtgs = null;
|
||||||
|
|
||||||
|
for (int k = 0; k < size; k++) {
|
||||||
|
Ptg ptg = ( Ptg ) expression.get(k);
|
||||||
|
|
||||||
|
ptg.writeBytes(array, pos + offset);
|
||||||
|
if (ptg instanceof ArrayPtg) {
|
||||||
|
if (arrayPtgs == null)
|
||||||
|
arrayPtgs = new ArrayList(5);
|
||||||
|
arrayPtgs.add(ptg);
|
||||||
|
pos += 8;
|
||||||
|
} else pos += ptg.getSize();
|
||||||
|
}
|
||||||
|
if (arrayPtgs != null) {
|
||||||
|
for (int i=0;i<arrayPtgs.size();i++) {
|
||||||
|
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
|
||||||
|
pos += p.writeTokenValueBytes(array, pos + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract int getSize();
|
public abstract int getSize();
|
||||||
|
|
||||||
|
BIN
src/testcases/org/apache/poi/hssf/data/37630.xls
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/37630.xls
Normal file
Binary file not shown.
@ -522,6 +522,22 @@ extends TestCase {
|
|||||||
HSSFWorkbook wb = new HSSFWorkbook(in);
|
HSSFWorkbook wb = new HSSFWorkbook(in);
|
||||||
assertTrue("Read book fine!" , true);
|
assertTrue("Read book fine!" , true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Error when reading then writing ArrayValues in NameRecord's*/
|
||||||
|
public void test37630() throws java.io.IOException {
|
||||||
|
String filename = System.getProperty("HSSF.testdata.path");
|
||||||
|
filename=filename+"/37630.xls";
|
||||||
|
FileInputStream in = new FileInputStream(filename);
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook(in);
|
||||||
|
File file = TempFile.createTempFile("test37630",".xls");
|
||||||
|
FileOutputStream out = new FileOutputStream(file);
|
||||||
|
wb.write(out);
|
||||||
|
|
||||||
|
assertTrue("Read book fine!" , true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user