diff --git a/src/java/org/apache/poi/hssf/record/FormulaRecord.java b/src/java/org/apache/poi/hssf/record/FormulaRecord.java index 11c7165562..a3b189d47f 100644 --- a/src/java/org/apache/poi/hssf/record/FormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/FormulaRecord.java @@ -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()) diff --git a/src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java b/src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java index c16f254586..45921f86ce 100644 --- a/src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java +++ b/src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java @@ -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(); diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java index 576385cfb8..9217a71b67 100644 --- a/src/java/org/apache/poi/hssf/record/NameRecord.java +++ b/src/java/org/apache/poi/hssf/record/NameRecord.java @@ -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; } @@ -488,7 +488,7 @@ public class NameRecord extends Record { throw new RecordFormatException("NOT A valid Name RECORD"); } } - + /** * called by the class that is responsible for writing this sucker. * 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 ) { 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(); @@ -525,8 +527,7 @@ public class NameRecord extends Record { return 20 + field_13_raw_name_definition.length; } 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. */ diff --git a/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java b/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java new file mode 100644 index 0000000000..568b3a3cb4 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java @@ -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