]> source.dussan.org Git - poi.git/commitdiff
Bug37630: SQUASHED! Array Ptgs now implemented (at least the read and write functiona...
authorJason Height <jheight@apache.org>
Sat, 21 Jan 2006 05:40:07 +0000 (05:40 +0000)
committerJason Height <jheight@apache.org>
Sat, 21 Jan 2006 05:40:07 +0000 (05:40 +0000)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@370987 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/FormulaRecord.java
src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java
src/java/org/apache/poi/hssf/record/NameRecord.java
src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/ArrayPtgA.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/ArrayPtgV.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/Ptg.java
src/testcases/org/apache/poi/hssf/data/37630.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java

index 11c7165562d4087108bb0fba562748bbfb64b5b1..a3b189d47f8f4fed3156de775a1d3126f7f8db5a 100644 (file)
@@ -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())
index c16f25458651c45911aadf1ef45f7c103b26cbb4..45921f86ce8a92abb09177a8f8242b31062052be 100644 (file)
@@ -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();
index 576385cfb8ae121f1dfb08f3b9f6aa15eb010546..9217a71b672b5edce28810dbf0f9e9ba8495018c 100644 (file)
@@ -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 (file)
index 0000000..568b3a3
--- /dev/null
@@ -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;
+    }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/ArrayPtgA.java b/src/java/org/apache/poi/hssf/record/formula/ArrayPtgA.java
new file mode 100644 (file)
index 0000000..2fdd210
--- /dev/null
@@ -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;
+    }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/ArrayPtgV.java b/src/java/org/apache/poi/hssf/record/formula/ArrayPtgV.java
new file mode 100644 (file)
index 0000000..68cf317
--- /dev/null
@@ -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;
+    }
+}
index 92a7a628192ce5df4675e5fe13863c295e808528..4e7df5b8695a9ee60470595dfe5ef9e0341f2ae6 100644 (file)
@@ -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;
@@ -85,8 +86,33 @@ public abstract class Ptg
         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();
         Ptg  retval = null;
@@ -157,6 +183,16 @@ public abstract class Ptg
             case ConcatPtg.sid :
                 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);
@@ -304,6 +340,34 @@ public abstract class Ptg
        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();
 
diff --git a/src/testcases/org/apache/poi/hssf/data/37630.xls b/src/testcases/org/apache/poi/hssf/data/37630.xls
new file mode 100644 (file)
index 0000000..ad2b0ef
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/37630.xls differ
index 5b102733d89aad3d793f8de8f599c66977044a86..4d610d8d9a808e60ee1586ef707b399c94287386 100644 (file)
@@ -522,6 +522,22 @@ extends TestCase {
               HSSFWorkbook wb = new HSSFWorkbook(in);
               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);
+       }
+       
+       
+       
 
 }