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_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) {
|
||||
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(int row)
|
||||
{
|
||||
@ -330,7 +316,7 @@ public class FormulaRecord
|
||||
//Microsoft Excel Developer's Kit Page 318
|
||||
LittleEndian.putInt(data, 20 + offset, 0);
|
||||
LittleEndian.putShort(data, 24 + offset, getExpressionLength());
|
||||
serializePtgs(data, 26+offset);
|
||||
Ptg.serializePtgStack(field_8_parsed_expr, data, 26+offset);
|
||||
} else {
|
||||
System.arraycopy(all_data,0,data,offset,all_data.length);
|
||||
}
|
||||
@ -368,19 +354,6 @@ public class FormulaRecord
|
||||
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)
|
||||
{
|
||||
if (this.getRow() > i.getRow())
|
||||
|
@ -49,7 +49,7 @@ public class LinkedDataFormulaField
|
||||
public int fillField( RecordInputStream in )
|
||||
{
|
||||
short tokenSize = in.readShort();
|
||||
formulaTokens = getParsedExpressionTokens(tokenSize, in);
|
||||
formulaTokens = Ptg.createParsedExpressionTokens(tokenSize, in);
|
||||
|
||||
return tokenSize + 2;
|
||||
}
|
||||
@ -80,12 +80,7 @@ public class LinkedDataFormulaField
|
||||
int size = getSize();
|
||||
LittleEndian.putShort(data, offset, (short)(size - 2));
|
||||
int pos = offset + 2;
|
||||
for ( Iterator iterator = formulaTokens.iterator(); iterator.hasNext(); )
|
||||
{
|
||||
Ptg ptg = (Ptg) iterator.next();
|
||||
ptg.writeBytes(data, pos);
|
||||
pos += ptg.getSize();
|
||||
}
|
||||
pos += Ptg.serializePtgStack(formulaTokens, data, pos);
|
||||
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 )
|
||||
{
|
||||
this.formulaTokens = (Stack) formulaTokens.clone();
|
||||
|
@ -331,7 +331,7 @@ public class NameRecord extends Record {
|
||||
/** get the definition length
|
||||
* @return definition length
|
||||
*/
|
||||
public short getDefinitionTextLength(){
|
||||
public short getDefinitionLength(){
|
||||
return field_4_length_name_definition;
|
||||
}
|
||||
|
||||
@ -501,11 +501,13 @@ public class NameRecord extends Record {
|
||||
public int serialize( int offset, byte[] data )
|
||||
{
|
||||
LittleEndian.putShort( data, 0 + offset, sid );
|
||||
short size = (short)( 15 + getTextsLength() + getNameDefinitionSize());
|
||||
LittleEndian.putShort( data, 2 + offset, size );
|
||||
// size defined below
|
||||
LittleEndian.putShort( data, 4 + offset, getOptionFlag() );
|
||||
data[6 + offset] = getKeyboardShortcut();
|
||||
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, 12 + offset, getEqualsToIndexToSheet() );
|
||||
data[14 + offset] = getCustomMenuLength();
|
||||
@ -526,7 +528,6 @@ public class NameRecord extends Record {
|
||||
}
|
||||
else
|
||||
{ */
|
||||
LittleEndian.putShort( data, 2 + offset, (short) ( 15 + getTextsLength() ) );
|
||||
|
||||
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;
|
||||
@ -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
|
||||
* @return total length
|
||||
*/
|
||||
public int getTextsLength(){
|
||||
int result;
|
||||
|
||||
result = getNameTextLength() + getDefinitionTextLength() + getDescriptionTextLength() +
|
||||
result = getNameTextLength() + getDescriptionTextLength() +
|
||||
getHelpTopicLength() + getStatusBarLength();
|
||||
|
||||
|
||||
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
|
||||
*/
|
||||
public int getRecordSize(){
|
||||
int result;
|
||||
|
||||
result = 19 + getTextsLength();
|
||||
result = 19 + getTextsLength() + getNameDefinitionSize();
|
||||
|
||||
|
||||
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???
|
||||
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.
|
||||
*/
|
||||
|
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.ArrayList;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.poi.hssf.model.Workbook;
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
@ -86,7 +87,32 @@ public abstract class Ptg
|
||||
}
|
||||
*/
|
||||
|
||||
public static Ptg createPtg(RecordInputStream in)
|
||||
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;
|
||||
}
|
||||
|
||||
private static Ptg createPtg(RecordInputStream in)
|
||||
{
|
||||
byte id = in.readByte();
|
||||
Ptg retval = null;
|
||||
@ -158,6 +184,16 @@ public abstract class Ptg
|
||||
retval = new ConcatPtg(in);
|
||||
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 :
|
||||
retval = new AreaPtg(in);
|
||||
break;
|
||||
@ -305,6 +341,34 @@ public abstract class Ptg
|
||||
|
||||
}
|
||||
|
||||
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 final byte [] getBytes()
|
||||
|
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.
@ -523,6 +523,22 @@ extends TestCase {
|
||||
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