poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r690636 - in /poi/trunk/src: documentation/content/xdocs/ java/org/apache/poi/hssf/model/ java/org/apache/poi/hssf/record/ java/org/apache/poi/hssf/record/aggregates/ java/org/apache/poi/hssf/usermodel/ testcases/org/apache/poi/hssf/data/ t...
Date Sun, 31 Aug 2008 04:45:01 GMT
Author: josh
Date: Sat Aug 30 21:45:00 2008
New Revision: 690636

URL: http://svn.apache.org/viewvc?rev=690636&view=rev
Log:
Fix for bugs 26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records

Added:
    poi/trunk/src/java/org/apache/poi/hssf/model/RowBlocksReader.java
    poi/trunk/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java   (contents, props changed)
      - copied, changed from r690539, poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedFormulaHolder.java
    poi/trunk/src/testcases/org/apache/poi/hssf/data/testArraysAndTables.xls   (with props)
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/RecordInspector.java
Removed:
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedFormulaHolder.java
Modified:
    poi/trunk/src/documentation/content/xdocs/changes.xml
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java
    poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/FormulaRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java
    poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java

Modified: poi/trunk/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/changes.xml?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/changes.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/changes.xml Sat Aug 30 21:45:00 2008
@@ -37,6 +37,7 @@
 
 		<!-- Don't forget to update status.xml too! -->
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records</action>
            <action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
            <action dev="POI-DEVELOPERS" type="fix">Avoid NPE in hssf.usermodel.HeaderFooter when stripping fields out</action>
            <action dev="POI-DEVELOPERS" type="fix">Avoid NPE in EscherBSERecord on older escher records</action>

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Sat Aug 30 21:45:00 2008
@@ -34,6 +34,7 @@
 	<!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records</action>
            <action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
            <action dev="POI-DEVELOPERS" type="fix">Avoid NPE in hssf.usermodel.HeaderFooter when stripping fields out</action>
            <action dev="POI-DEVELOPERS" type="fix">Avoid NPE in EscherBSERecord on older escher records</action>

Added: poi/trunk/src/java/org/apache/poi/hssf/model/RowBlocksReader.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/model/RowBlocksReader.java?rev=690636&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/model/RowBlocksReader.java (added)
+++ poi/trunk/src/java/org/apache/poi/hssf/model/RowBlocksReader.java Sat Aug 30 21:45:00 2008
@@ -0,0 +1,116 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.record.ArrayRecord;
+import org.apache.poi.hssf.record.MergeCellsRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
+import org.apache.poi.hssf.record.TableRecord;
+import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
+import org.apache.poi.hssf.record.aggregates.SharedValueManager;
+
+/**
+ * Segregates the 'Row Blocks' section of a single sheet into plain row/cell records and 
+ * shared formula records.
+ * 
+ * @author Josh Micich
+ */
+public final class RowBlocksReader {
+
+	private final List _plainRecords;
+	private final SharedValueManager _sfm;
+	private final MergeCellsRecord[] _mergedCellsRecords;
+	private final int _totalNumberOfRecords;
+
+	/**
+	 * Also collects any loose MergeCellRecords and puts them in the supplied
+	 * mergedCellsTable
+	 */
+	public RowBlocksReader(List recs, int startIx) {
+		List plainRecords = new ArrayList();
+		List shFrmRecords = new ArrayList();
+		List arrayRecords = new ArrayList();
+		List tableRecords = new ArrayList();
+		List mergeCellRecords = new ArrayList();
+
+		int endIx = -1;
+		for (int i = startIx; i < recs.size(); i++) {
+			Record rec = (Record) recs.get(i);
+			if (RecordOrderer.isEndOfRowBlock(rec.getSid())) {
+				// End of row/cell records for the current sheet
+				// Note - It is important that this code does not inadvertently any sheet 
+				// records from a subsequent sheet.  For example, if SharedFormulaRecords 
+				// are taken from the wrong sheet, this could cause bug 44449. 
+				endIx = i;
+				break;
+			}
+			List dest;
+			switch (rec.getSid()) {
+				case MergeCellsRecord.sid:    dest = mergeCellRecords; break;
+				case SharedFormulaRecord.sid: dest = shFrmRecords;     break;
+				case ArrayRecord.sid:         dest = arrayRecords;     break;
+				case TableRecord.sid:         dest = tableRecords;     break;
+				default:                      dest = plainRecords;
+			}
+			dest.add(rec);
+		}
+		if (endIx < 0) {
+			throw new RuntimeException("Failed to find end of row/cell records");
+		}
+		SharedFormulaRecord[] sharedFormulaRecs = new SharedFormulaRecord[shFrmRecords.size()];
+		ArrayRecord[] arrayRecs = new ArrayRecord[arrayRecords.size()];
+		TableRecord[] tableRecs = new TableRecord[tableRecords.size()];
+		shFrmRecords.toArray(sharedFormulaRecs);
+		arrayRecords.toArray(arrayRecs);
+		tableRecords.toArray(tableRecs);
+		
+		_plainRecords = plainRecords;
+		_sfm = SharedValueManager.create(sharedFormulaRecs, arrayRecs, tableRecs);
+		_mergedCellsRecords = new MergeCellsRecord[mergeCellRecords.size()];
+		mergeCellRecords.toArray(_mergedCellsRecords);
+		_totalNumberOfRecords = endIx - startIx;
+	}
+	
+	/**
+	 * Some unconventional apps place {@link MergeCellsRecord}s within the row block.  They 
+	 * actually should be in the {@link MergedCellsTable} which is much later (see bug 45699).
+	 * @return any loose  <tt>MergeCellsRecord</tt>s found
+	 */
+	public MergeCellsRecord[] getLooseMergedCells() {
+		return _mergedCellsRecords;
+	}
+
+	public int getTotalNumberOfRecords() {
+		return _totalNumberOfRecords;
+	}
+
+	public SharedValueManager getSharedFormulaManager() {
+		return _sfm;
+	}
+	/**
+	 * @return a {@link RecordStream} containing all the non-{@link SharedFormulaRecord} 
+	 * non-{@link ArrayRecord} and non-{@link TableRecord} Records.
+	 */
+	public RecordStream getPlainRecordStream() {
+		return new RecordStream(_plainRecords, 0);
+	}
+}

Modified: poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/model/Sheet.java Sat Aug 30 21:45:00 2008
@@ -27,7 +27,6 @@
 import org.apache.poi.hssf.record.CalcModeRecord;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.ColumnInfoRecord;
-import org.apache.poi.hssf.record.DBCellRecord;
 import org.apache.poi.hssf.record.DVALRecord;
 import org.apache.poi.hssf.record.DefaultColWidthRecord;
 import org.apache.poi.hssf.record.DefaultRowHeightRecord;
@@ -56,7 +55,6 @@
 import org.apache.poi.hssf.record.SaveRecalcRecord;
 import org.apache.poi.hssf.record.ScenarioProtectRecord;
 import org.apache.poi.hssf.record.SelectionRecord;
-import org.apache.poi.hssf.record.StringRecord;
 import org.apache.poi.hssf.record.UncalcedRecord;
 import org.apache.poi.hssf.record.WSBoolRecord;
 import org.apache.poi.hssf.record.WindowTwoRecord;
@@ -64,6 +62,7 @@
 import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
 import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
 import org.apache.poi.hssf.record.aggregates.DataValidityTable;
+import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
 import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
 import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
 import org.apache.poi.hssf.record.aggregates.RecordAggregate;
@@ -181,18 +180,12 @@
 
         for (int k = offset; k < inRecs.size(); k++) {
             Record rec = ( Record ) inRecs.get(k);
-            if ( rec.getSid() == DBCellRecord.sid ) {
-                continue;
-            }
             if ( rec.getSid() == IndexRecord.sid ) {
                 // ignore INDEX record because it is only needed by Excel, 
                 // and POI always re-calculates its contents 
                 continue;
             }
-            if ( rec.getSid() == StringRecord.sid ) {
-                continue;
-            }
-            
+
             if ( rec.getSid() == CFHeaderRecord.sid ) {
                 RecordStream rs = new RecordStream(inRecs, k);
                 retval.condFormatting = new ConditionalFormattingTable(rs);
@@ -221,10 +214,11 @@
                 if (retval._rowsAggregate != null) {
                     throw new RuntimeException("row/cell records found in the wrong place");
                 }
-                int lastRowCellRec = findEndOfRowBlock(inRecs, k, retval._mergedCellsTable);
-                retval._rowsAggregate = new RowRecordsAggregate(inRecs, k, lastRowCellRec);
+                RowBlocksReader rbr = new RowBlocksReader(inRecs, k);
+                retval._mergedCellsTable.addRecords(rbr.getLooseMergedCells());
+                retval._rowsAggregate = new RowRecordsAggregate(rbr.getPlainRecordStream(), rbr.getSharedFormulaManager());
                 records.add(retval._rowsAggregate); //only add the aggregate once
-                k = lastRowCellRec -1;
+                k += rbr.getTotalNumberOfRecords() - 1;
                 continue;
             }
              
@@ -344,26 +338,6 @@
         return retval;
     }
 
-    /**
-     * Also collects any rogue MergeCellRecords
-     * @return the index one after the last row/cell record
-     */
-    private static int findEndOfRowBlock(List recs, int startIx, MergedCellsTable mergedCellsTable) {
-        for(int i=startIx; i<recs.size(); i++) {
-            Record rec = (Record) recs.get(i);
-            if (RecordOrderer.isEndOfRowBlock(rec.getSid())) {
-                return i;
-            }
-            if (rec.getSid() == MergeCellsRecord.sid) {
-                    // Some apps scatter these records between the rows/cells but they are supposed to
-                    // be well after the row/cell records.  We collect them here 
-                    // see bug 45699
-                    mergedCellsTable.add((MergeCellsRecord) rec);
-            }
-        }
-        throw new RuntimeException("Failed to find end of row/cell records");
-    }
-
     private static final class RecordCloner implements RecordVisitor {
 
         private final List _destList;
@@ -618,7 +592,7 @@
                 //Can there be more than one BOF for a sheet? If not then we can
                 //remove this guard. So be safe it is left here.
                 if (_rowsAggregate != null) {
-                	// find forward distance to first RowRecord
+                    // find forward distance to first RowRecord
                     int initRecsSize = getSizeOfInitialSheetRecords(k);
                     int currentPos = ptv.getPosition();
                     ptv.visitRecord(_rowsAggregate.createIndexRecord(currentPos, initRecsSize));
@@ -1867,4 +1841,8 @@
         }
         return _dataValidityTable;
     }
+
+    public FormulaRecordAggregate createFormula(int row, int col) {
+        return _rowsAggregate.createFormula(row, col);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java Sat Aug 30 21:45:00 2008
@@ -18,7 +18,6 @@
 package org.apache.poi.hssf.record;
 
 import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.util.CellRangeAddress8Bit;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
 
@@ -29,13 +28,11 @@
  * 
  * @author Josh Micich
  */		
-public final class ArrayRecord extends Record {
+public final class ArrayRecord extends SharedValueRecordBase {
 
 	public final static short sid = 0x0221;
 	private static final int OPT_ALWAYS_RECALCULATE = 0x0001;
 	private static final int OPT_CALCULATE_ON_OPEN  = 0x0002;
-
-	private CellRangeAddress8Bit _range;
 	
 	private int	_options;
 	private int _field3notUsed;
@@ -43,6 +40,10 @@
 
 	public ArrayRecord(RecordInputStream in) {
 		super(in);
+		_options = in.readUShort();
+		_field3notUsed = in.readInt();
+		int formulaLen = in.readUShort();
+		_formulaTokens = Ptg.readTokens(formulaLen, in);
 	}
 
 	public boolean isAlwaysRecalculate() {
@@ -52,27 +53,12 @@
 		return (_options & OPT_CALCULATE_ON_OPEN) != 0;
 	}
 
-	protected void validateSid(short id) {
-		if (id != sid) {
-			throw new RecordFormatException("NOT A valid Array RECORD");
-		}
+	protected int getExtraDataSize() {
+		return 2 + 4
+			+ 2 + Ptg.getEncodedSize(_formulaTokens);
 	}
-
-	private int getDataSize(){
-		return CellRangeAddress8Bit.ENCODED_SIZE 
-			+ 2 + 4
-			+ getFormulaSize();
-	}
-
-	public int serialize( int offset, byte[] data ) {
-		int dataSize = getDataSize();
-
-		LittleEndian.putShort(data, 0 + offset, sid);
-		LittleEndian.putUShort(data, 2 + offset, dataSize);
-
-		int pos = offset+4;
-		_range.serialize(pos, data);
-		pos += CellRangeAddress8Bit.ENCODED_SIZE;
+	protected void serializeExtraData(int offset, byte[] data) {
+		int pos = offset;
 		LittleEndian.putUShort(data, pos, _options);
 		pos+=2;
 		LittleEndian.putInt(data, pos, _field3notUsed);
@@ -81,29 +67,6 @@
 		LittleEndian.putUShort(data, pos, tokenSize);
 		pos+=2;
 		Ptg.serializePtgs(_formulaTokens, data, pos);
-		return dataSize + 4;
-	}
-
-	private int getFormulaSize() {
-		int result = 0;
-		for (int i = 0; i < _formulaTokens.length; i++) {
-			result += _formulaTokens[i].getSize();
-		}
-		return result;
-	}
-
-
-	public int getRecordSize(){
-		return 4 + getDataSize();
-	}
-
-
-	protected void fillFields(RecordInputStream in) {
-		_range = new CellRangeAddress8Bit(in);
-		_options = in.readUShort();
-		_field3notUsed = in.readInt();
-		int formulaLen = in.readUShort();
-		_formulaTokens = Ptg.readTokens(formulaLen, in);
 	}
 
 	public short getSid() {
@@ -113,12 +76,13 @@
 	public String toString() {
 		StringBuffer sb = new StringBuffer();
 		sb.append(getClass().getName()).append(" [ARRAY]\n");
-		sb.append(" range=").append(_range.toString()).append("\n");
+		sb.append(" range=").append(getRange().toString()).append("\n");
 		sb.append(" options=").append(HexDump.shortToHex(_options)).append("\n");
 		sb.append(" notUsed=").append(HexDump.intToHex(_field3notUsed)).append("\n");
 		sb.append(" formula:").append("\n");
 		for (int i = 0; i < _formulaTokens.length; i++) {
-			sb.append(_formulaTokens[i].toString());
+			Ptg ptg = _formulaTokens[i];
+			sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
 		}
 		sb.append("]");
 		return sb.toString();

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/FormulaRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/FormulaRecord.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/FormulaRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/FormulaRecord.java Sat Aug 30 21:45:00 2008
@@ -17,9 +17,6 @@
 
 package org.apache.poi.hssf.record;
 
-import java.util.Arrays;
-import java.util.List;
-
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
@@ -27,7 +24,7 @@
 import org.apache.poi.util.LittleEndian;
 
 /**
- * Formula Record.
+ * Formula Record (0x0006).
  * REFERENCE:  PG 317/444 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
  * @author Andrew C. Oliver (acoliver at apache dot org)
  * @author Jason Height (jheight at chariot dot net dot au)
@@ -270,7 +267,8 @@
 
         for (int k = 0; k < field_8_parsed_expr.length; k++ ) {
             sb.append("     Ptg[").append(k).append("]=");
-            sb.append(field_8_parsed_expr[k].toString()).append("\n");
+            Ptg ptg = field_8_parsed_expr[k];
+            sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
         }
         sb.append("[/FORMULA]\n");
         return sb.toString();

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java Sat Aug 30 21:45:00 2008
@@ -41,7 +41,7 @@
  * @author Csaba Nagy (ncsaba at yahoo dot com)
  */
 public final class RecordFactory {
-    private static final int NUM_RECORDS = 512;
+	private static final int NUM_RECORDS = 512;
 
 	private static final Class[] CONSTRUCTOR_ARGS = { RecordInputStream.class, };
 
@@ -50,6 +50,7 @@
 	 * Note - this most but not *every* subclass of Record.
 	 */
 	private static final Class[] records = {
+		ArrayRecord.class,
 		BackupRecord.class,
 		BlankRecord.class,
 		BOFRecord.class,

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java Sat Aug 30 21:45:00 2008
@@ -22,7 +22,6 @@
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.RefNPtg;
 import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.util.CellRangeAddress8Bit;
 import org.apache.poi.util.HexDump;
 
 /**
@@ -36,59 +35,31 @@
  * record types.
  * @author Danny Mui at apache dot org
  */
-public final class SharedFormulaRecord extends Record {
+public final class SharedFormulaRecord extends SharedValueRecordBase {
     public final static short   sid = 0x04BC;
 
-    private CellRangeAddress8Bit _range;
     private int field_5_reserved;
     private Ptg[] field_7_parsed_expr;
 
     public SharedFormulaRecord() {
-    	_range = new CellRangeAddress8Bit(0, 0, 0, 0);
-    	field_7_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
+        field_7_parsed_expr = Ptg.EMPTY_PTG_ARRAY;
     }
 
     /**
      * @param in the RecordInputstream to read the record from
      */
     public SharedFormulaRecord(RecordInputStream in) {
-          super(in);
-    }
-
-    protected void validateSid(short id) {
-        if (id != this.sid) {
-            throw new RecordFormatException("Not a valid SharedFormula");
-        }
-    }
-
-    public int getFirstRow() {
-      return _range.getFirstRow();
-    }
-
-    public int getLastRow() {
-      return _range.getLastRow();
-    }
-
-    public short getFirstColumn() {
-      return (short) _range.getFirstColumn();
-    }
-
-    public short getLastColumn() {
-      return (short) _range.getLastColumn();
+        super(in);
+        field_5_reserved        = in.readShort();
+        int field_6_expression_len = in.readShort();
+        field_7_parsed_expr = Ptg.readTokens(field_6_expression_len, in);
     }
-
-    /**
-     * spit the record out AS IS.  no interpretation or identification
-     */
-
-    public int serialize(int offset, byte [] data)
-    {
+    protected void serializeExtraData(int offset, byte[] data) {
         //Because this record is converted to individual Formula records, this method is not required.
         throw new UnsupportedOperationException("Cannot serialize a SharedFormulaRecord");
     }
-
-    public int getRecordSize()
-    {
+    
+    protected int getExtraDataSize() {
         //Because this record is converted to individual Formula records, this method is not required.
         throw new UnsupportedOperationException("Cannot get the size for a SharedFormulaRecord");
 
@@ -103,12 +74,13 @@
         StringBuffer buffer = new StringBuffer();
 
         buffer.append("[SHARED FORMULA (").append(HexDump.intToHex(sid)).append("]\n");
-        buffer.append("    .range      = ").append(_range.toString()).append("\n");
+        buffer.append("    .range      = ").append(getRange().toString()).append("\n");
         buffer.append("    .reserved    = ").append(HexDump.shortToHex(field_5_reserved)).append("\n");
 
         for (int k = 0; k < field_7_parsed_expr.length; k++ ) {
            buffer.append("Formula[").append(k).append("]");
-           buffer.append(field_7_parsed_expr[k].toString()).append("\n");
+           Ptg ptg = field_7_parsed_expr[k];
+           buffer.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
         }
 
         buffer.append("[/SHARED FORMULA]\n");
@@ -119,23 +91,6 @@
         return sid;
     }
 
-    protected void fillFields(RecordInputStream in) {
-        _range = new CellRangeAddress8Bit(in);
-        field_5_reserved        = in.readShort();
-        int field_6_expression_len = in.readShort();
-        field_7_parsed_expr = Ptg.readTokens(field_6_expression_len, in);
-    }
-
-    /**
-     * Are we shared by the supplied formula record?
-     */
-    public boolean isFormulaInShared(FormulaRecord formula) {
-      final int formulaRow = formula.getRow();
-      final int formulaColumn = formula.getColumn();
-      return ((getFirstRow() <= formulaRow) && (getLastRow() >= formulaRow) &&
-          (getFirstColumn() <= formulaColumn) && (getLastColumn() >= formulaColumn));
-    }
-
     /**
      * Creates a non shared formula from the shared formula
      * counter part
@@ -176,9 +131,9 @@
                                 areaNPtg.isFirstColRelative(),
                                 areaNPtg.isLastColRelative());
             } else {
-            	if (false) {// do we need a ptg clone here?
-            		ptg = ptg.copy();
-            	}
+                if (false) {// do we need a ptg clone here?
+                    ptg = ptg.copy();
+                }
             }
             if (!ptg.isBaseToken()) {
                 ptg.setClass(originalOperandClass);
@@ -194,12 +149,12 @@
      * counter part
      */
     public void convertSharedFormulaRecord(FormulaRecord formula) {
-      //Sanity checks
-        if (!isFormulaInShared(formula)) {
+        int formulaRow = formula.getRow();
+        int formulaColumn = formula.getColumn();
+        //Sanity checks
+        if (!isInRange(formulaRow, formulaColumn)) {
             throw new RuntimeException("Shared Formula Conversion: Coding Error");
         }
-        final int formulaRow = formula.getRow();
-        final int formulaColumn = formula.getColumn();
 
         Ptg[] ptgs = convertSharedFormulas(field_7_parsed_expr, formulaRow, formulaColumn);
         formula.setParsedExpression(ptgs);
@@ -223,22 +178,6 @@
         return row;
     }
 
-    /**
-     * Mirroring formula records so it is registered in the ValueRecordsAggregate
-     */
-    public boolean isInValueSection()
-    {
-         return true;
-    }
-
-
-     /**
-      * Register it in the ValueRecordsAggregate so it can go into the FormulaRecordAggregate
-      */
-     public boolean isValue() {
-         return true;
-     }
-
     public Object clone() {
         //Because this record is converted to individual Formula records, this method is not required.
         throw new UnsupportedOperationException("Cannot clone a SharedFormulaRecord");

Added: poi/trunk/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java?rev=690636&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java (added)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SharedValueRecordBase.java Sat Aug 30 21:45:00 2008
@@ -0,0 +1,134 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record;
+
+import org.apache.poi.hssf.util.CellRangeAddress8Bit;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * Common base class for {@link SharedFormulaRecord}, {@link ArrayRecord} and
+ * {@link TableRecord} which are have similarities.
+ * 
+ * @author Josh Micich
+ */
+public abstract class SharedValueRecordBase extends Record {
+
+	private CellRangeAddress8Bit _range;
+
+	protected SharedValueRecordBase(CellRangeAddress8Bit range) {
+		_range = range;
+	}
+
+	protected SharedValueRecordBase() {
+		this(new CellRangeAddress8Bit(0, 0, 0, 0));
+	}
+
+	/**
+	 * reads only the range (1 {@link CellRangeAddress8Bit}) from the stream
+	 */
+	public SharedValueRecordBase(RecordInputStream in) {
+		_range = new CellRangeAddress8Bit(in);
+	}
+
+	protected final void validateSid(short id) {
+		if (id != getSid()) {
+			throw new RecordFormatException("Not a valid SharedFormula");
+		}
+	}
+
+	public final CellRangeAddress8Bit getRange() {
+		return _range;
+	}
+
+	public final int getFirstRow() {
+		return _range.getFirstRow();
+	}
+
+	public final int getLastRow() {
+		return _range.getLastRow();
+	}
+
+	public final int getFirstColumn() {
+		return (short) _range.getFirstColumn();
+	}
+
+	public final int getLastColumn() {
+		return (short) _range.getLastColumn();
+	}
+
+	public final int getRecordSize() {
+		return 4 + CellRangeAddress8Bit.ENCODED_SIZE + getExtraDataSize();
+	}
+
+	protected abstract int getExtraDataSize();
+
+	protected abstract void serializeExtraData(int offset, byte[] data);
+
+	public final int serialize(int offset, byte[] data) {
+		int dataSize = CellRangeAddress8Bit.ENCODED_SIZE + getExtraDataSize();
+
+		LittleEndian.putShort(data, 0 + offset, getSid());
+		LittleEndian.putUShort(data, 2 + offset, dataSize);
+
+		int pos = offset + 4;
+		_range.serialize(pos, data);
+		pos += CellRangeAddress8Bit.ENCODED_SIZE;
+		serializeExtraData(pos, data);
+		return dataSize + 4;
+	}
+
+	protected final void fillFields(RecordInputStream in) {
+		throw new RuntimeException("Should not be called.  Fields are filled in constructor");
+	}
+
+	/**
+	 * @return <code>true</code> if (rowIx, colIx) is within the range ({@link #getRange()})
+	 * of this shared value object.
+	 */
+	public final boolean isInRange(int rowIx, int colIx) {
+		CellRangeAddress8Bit r = _range;
+		return r.getFirstRow() <= rowIx 
+			&& r.getLastRow() >= rowIx
+			&& r.getFirstColumn() <= colIx 
+			&& r.getLastColumn() >= colIx;
+	}
+	/**
+	 * @return <code>true</code> if (rowIx, colIx) describes the first cell in this shared value 
+	 * object's range ({@link #getRange()})
+	 */
+	public final boolean isFirstCell(int rowIx, int colIx) {
+		CellRangeAddress8Bit r = getRange();
+		return r.getFirstRow() == rowIx && r.getFirstColumn() == colIx;
+	}
+
+	/**
+	 * Mirroring formula records so it is registered in the
+	 * ValueRecordsAggregate
+	 */
+	public final boolean isInValueSection() {
+		return true;
+	}
+
+	/**
+	 * Register it in the ValueRecordsAggregate so it can go into the
+	 * FormulaRecordAggregate
+	 */
+	public final boolean isValue() {
+		return true;
+	}
+}

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/TableRecord.java Sat Aug 30 21:45:00 2008
@@ -34,19 +34,15 @@
  *
  * See p536 of the June 08 binary docs
  */
-public final class TableRecord extends Record {
+public final class TableRecord extends SharedValueRecordBase {
 	public static final short sid = 0x0236;
 
 	private static final BitField alwaysCalc      = BitFieldFactory.getInstance(0x0001);
-	private static final BitField reserved1       = BitFieldFactory.getInstance(0x0002);
+	private static final BitField calcOnOpen      = BitFieldFactory.getInstance(0x0002);
 	private static final BitField rowOrColInpCell = BitFieldFactory.getInstance(0x0004);
 	private static final BitField oneOrTwoVar     = BitFieldFactory.getInstance(0x0008);
 	private static final BitField rowDeleted      = BitFieldFactory.getInstance(0x0010);
 	private static final BitField colDeleted      = BitFieldFactory.getInstance(0x0020);
-	private static final BitField reserved2       = BitFieldFactory.getInstance(0x0040);
-	private static final BitField reserved3       = BitFieldFactory.getInstance(0x0080);
-
-	private CellRangeAddress8Bit _range;
 
 	private int field_5_flags;
 	private int field_6_res;
@@ -55,9 +51,8 @@
 	private int field_9_rowInputCol;
 	private int field_10_colInputCol;
 
-
-	protected void fillFields(RecordInputStream in) {
-		_range = new CellRangeAddress8Bit(in);
+	public TableRecord(RecordInputStream in) {
+		super(in);
 		field_5_flags        = in.readByte();
 		field_6_res          = in.readByte();
 		field_7_rowInputRow  = in.readShort();
@@ -66,18 +61,11 @@
 		field_10_colInputCol = in.readShort();
 	}
 
-	public TableRecord(RecordInputStream in) {
-		super(in);
-	}
 	public TableRecord(CellRangeAddress8Bit range) {
-		_range = range;
+		super(range);
 		field_6_res = 0;
 	}
 
-	public CellRangeAddress8Bit getRange() {
-		return _range;
-	}
-
 	public int getFlags() {
 		return field_5_flags;
 	}
@@ -153,43 +141,24 @@
 	public short getSid() {
 		return sid;
 	}
-
-	public int serialize(int offset, byte[] data) {
-		int dataSize = getDataSize();
-		LittleEndian.putShort(data, 0 + offset, sid);
-		LittleEndian.putUShort(data, 2 + offset, dataSize);
-
-		_range.serialize(4 + offset, data);
-		LittleEndian.putByte(data, 10 + offset, field_5_flags);
-		LittleEndian.putByte(data, 11 + offset, field_6_res);
-		LittleEndian.putUShort(data, 12 + offset, field_7_rowInputRow);
-		LittleEndian.putUShort(data, 14 + offset, field_8_colInputRow);
-		LittleEndian.putUShort(data, 16 + offset, field_9_rowInputCol);
-		LittleEndian.putUShort(data, 18 + offset, field_10_colInputCol);
-
-		return 4 + dataSize;
-	}
-	private int getDataSize() {
-		return CellRangeAddress8Bit.ENCODED_SIZE
-			+ 2 // 2 byte fields
-			+ 8; // 4 short fields
-	}
-
-	public int getRecordSize() {
-		return 4+getDataSize();
-	}
-
-	protected void validateSid(short id) {
-		if (id != sid)
-		{
-			throw new RecordFormatException("NOT A TABLE RECORD");
-		}
+	protected int getExtraDataSize() {
+		return 
+		2 // 2 byte fields
+		+ 8; // 4 short fields
+	}
+	protected void serializeExtraData(int offset, byte[] data) {
+		LittleEndian.putByte(data, 0 + offset, field_5_flags);
+		LittleEndian.putByte(data, 1 + offset, field_6_res);
+		LittleEndian.putUShort(data, 2 + offset, field_7_rowInputRow);
+		LittleEndian.putUShort(data, 4 + offset, field_8_colInputRow);
+		LittleEndian.putUShort(data, 6 + offset, field_9_rowInputCol);
+		LittleEndian.putUShort(data, 8 + offset, field_10_colInputCol);
 	}
 
 	public String toString() {
 		StringBuffer buffer = new StringBuffer();
 		buffer.append("[TABLE]\n");
-		buffer.append("    .range    = ").append(_range.toString()).append("\n");
+		buffer.append("    .range    = ").append(getRange().toString()).append("\n");
 		buffer.append("    .flags    = ") .append(HexDump.byteToHex(field_5_flags)).append("\n");
 		buffer.append("    .alwaysClc= ").append(isAlwaysCalc()).append("\n");
 		buffer.append("    .reserved = ").append(HexDump.intToHex(field_6_res)).append("\n");

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java Sat Aug 30 21:45:00 2008
@@ -17,12 +17,10 @@
 
 package org.apache.poi.hssf.record.aggregates;
 
-import org.apache.poi.hssf.model.RecordStream;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.FormulaRecord;
-import org.apache.poi.hssf.record.SharedFormulaRecord;
+import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.StringRecord;
-import org.apache.poi.hssf.record.TableRecord;
 
 /**
  * The formula record aggregate is used to join together the formula record and it's
@@ -33,35 +31,29 @@
 public final class FormulaRecordAggregate extends RecordAggregate implements CellValueRecordInterface {
 
     private final FormulaRecord _formulaRecord;
+    private SharedValueManager _sharedValueManager;
     /** caches the calculated result of the formula */
     private StringRecord _stringRecord;
-    private TableRecord _tableRecord;
     
-    public FormulaRecordAggregate(FormulaRecord formulaRecord) {
-        _formulaRecord = formulaRecord;
-        _stringRecord = null;
-    }
-    public FormulaRecordAggregate(FormulaRecord formulaRecord, RecordStream rs) {
-        _formulaRecord = formulaRecord;
-        Class nextClass = rs.peekNextClass();
-        if (nextClass == SharedFormulaRecord.class) {
-            // For (text) shared formulas, the SharedFormulaRecord comes before the StringRecord.
-            // In any case it is OK to skip SharedFormulaRecords because they were collected 
-            // before constructing the ValueRecordsAggregate.
-            rs.getNext(); // skip the shared formula record
-            nextClass = rs.peekNextClass();
+    /**
+     * @param stringRec may be <code>null</code> if this formula does not have a cached text 
+     * value.
+     * @param svm the {@link SharedValueManager} for the current sheet
+     */
+    public FormulaRecordAggregate(FormulaRecord formulaRec, StringRecord stringRec, SharedValueManager svm) {
+        if (svm == null) {
+            throw new IllegalArgumentException("sfm must not be null");
         }
-        if (nextClass == StringRecord.class) {
-            _stringRecord = (StringRecord) rs.getNext();
-        } else if (nextClass == TableRecord.class) {
-            _tableRecord = (TableRecord) rs.getNext();
+        if (formulaRec.isSharedFormula()) {
+            svm.convertSharedFormulaRecord(formulaRec);
         }
+        _formulaRecord = formulaRec;
+        _sharedValueManager = svm;
+        _stringRecord = stringRec;
     }
 
     public void setStringRecord(StringRecord stringRecord) {
         _stringRecord = stringRecord;
-        _tableRecord = null; // probably can't have both present at the same time
-        // TODO - establish rules governing when each of these sub records may exist
     }
     
     public FormulaRecord getFormulaRecord() {
@@ -102,12 +94,13 @@
    
     public void visitContainedRecords(RecordVisitor rv) {
          rv.visitRecord(_formulaRecord);
+         Record sharedFormulaRecord = _sharedValueManager.getRecordForFirstCell(_formulaRecord);
+         if (sharedFormulaRecord != null) {
+             rv.visitRecord(sharedFormulaRecord);
+         }
          if (_stringRecord != null) {
              rv.visitRecord(_stringRecord);
          }
-         if (_tableRecord != null) {
-             rv.visitRecord(_tableRecord);
-        }
     }
    
     public String getStringValue() {

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java Sat Aug 30 21:45:00 2008
@@ -93,8 +93,13 @@
 			rv.visitRecord(new MergeCellsRecord(cras, startIx, nLeftoverMergedRegions));
 		}
 	}
+	public void addRecords(MergeCellsRecord[] mcrs) {
+		for (int i = 0; i < mcrs.length; i++) {
+			addMergeCellsRecord(mcrs[i]);
+		}
+	}
 
-	public void add(MergeCellsRecord mcr) {
+	private void addMergeCellsRecord(MergeCellsRecord mcr) {
 		int nRegions = mcr.getNumAreas();
 		for (int i = 0; i < nRegions; i++) {
 			_mergedRegions.add(mcr.getAreaAt(i));
@@ -125,4 +130,5 @@
 	public int getNumberOfMergedRegions() {
 		return _mergedRegions.size();
 	}
+
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java Sat Aug 30 21:45:00 2008
@@ -23,12 +23,17 @@
 import java.util.Map;
 import java.util.TreeMap;
 
+import org.apache.poi.hssf.model.RecordStream;
+import org.apache.poi.hssf.record.ArrayRecord;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.DBCellRecord;
+import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.IndexRecord;
 import org.apache.poi.hssf.record.MergeCellsRecord;
 import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
+import org.apache.poi.hssf.record.TableRecord;
 import org.apache.poi.hssf.record.UnknownRecord;
 
 /**
@@ -42,36 +47,34 @@
     private final Map _rowRecords;
     private final ValueRecordsAggregate _valuesAgg;
     private final List _unknownRecords;
+    private final SharedValueManager _sharedValueManager;
 
     /** Creates a new instance of ValueRecordsAggregate */
-
     public RowRecordsAggregate() {
-        this(new TreeMap(), new ValueRecordsAggregate());
+        this(SharedValueManager.EMPTY);
     }
-    private RowRecordsAggregate(TreeMap rowRecords, ValueRecordsAggregate valuesAgg) {
-        _rowRecords = rowRecords;
-        _valuesAgg = valuesAgg;
+    private RowRecordsAggregate(SharedValueManager svm) {
+        _rowRecords = new TreeMap();
+        _valuesAgg = new ValueRecordsAggregate();
         _unknownRecords = new ArrayList();
+        _sharedValueManager = svm;
     }
 
-    public RowRecordsAggregate(List recs, int startIx, int endIx) {
-        this();
-        // First up, locate all the shared formulas for this sheet
-        SharedFormulaHolder sfh = SharedFormulaHolder.create(recs, startIx, endIx);
-        for(int i=startIx; i<endIx; i++) {
-            Record rec = (Record) recs.get(i);
+    /**
+     * @param rs record stream with all {@link SharedFormulaRecord}
+     * {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed
+     */
+    public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) {
+        this(svm);
+        while(rs.hasNext()) {
+            Record rec = rs.getNext();
             switch (rec.getSid()) {
-                case MergeCellsRecord.sid:
-                    // Some apps scatter these records between the rows/cells but they are supposed to
-                    // be well after the row/cell records.  It is assumed such rogue MergeCellRecords 
-                    // have already been collected by the caller, and can safely be ignored here. 
-                    // see bug 45699
-                    continue;
                 case RowRecord.sid:
                     insertRow((RowRecord) rec);
                     continue;
                 case DBCellRecord.sid:
                     // end of 'Row Block'.  Should only occur after cell records
+                    // ignore DBCELL records because POI generates them upon re-serialization
                     continue;
             }
             if (rec instanceof UnknownRecord) {
@@ -82,9 +85,8 @@
             if (!rec.isValue()) {
                 throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
             }
-            i += _valuesAgg.construct(recs, i, endIx, sfh)-1;
+            _valuesAgg.construct((CellValueRecordInterface)rec, rs, svm);
         }
-        "".length();
     }
     /**
      * Handles UnknownRecords which appear within the row/cell records
@@ -95,7 +97,7 @@
         // 0x01C2 // several
         // 0x0034 // few
         // No documentation could be found for these
-        
+
         // keep the unknown records for re-serialization
         _unknownRecords.add(rec);
     }
@@ -147,7 +149,7 @@
     {
         return _lastrow;
     }
-    
+
     /** Returns the number of row blocks.
      * <p/>The row blocks are goupings of rows that contain the DBCell record
      * after them
@@ -209,7 +211,7 @@
       }
       return row.getRowNumber();
     }
-    
+
     private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) {
         final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE;
         final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
@@ -230,11 +232,11 @@
           rv.visitRecord(rec);
         }
         return result;
-      }
-    
+    }
+
     public void visitContainedRecords(RecordVisitor rv) {
-        ValueRecordsAggregate cells = _valuesAgg;
-       
+
+        PositionTrackingVisitor stv = new PositionTrackingVisitor(rv, 0);
         //DBCells are serialized before row records.
         final int blockCount = getRowBlockCount();
         for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) {
@@ -251,8 +253,10 @@
             // Note: Cell references start from the second row...
             int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE);
             for (int row = startRowNumber; row <= endRowNumber; row++) {
-                if (cells.rowHasCells(row)) {
-                    final int rowCellSize = cells.visitCellsForRow(row, rv);
+                if (_valuesAgg.rowHasCells(row)) {
+                    stv.setPosition(0);
+                    _valuesAgg.visitCellsForRow(row, stv);
+                    int rowCellSize = stv.getPosition();
                     pos += rowCellSize;
                     // Add the offset to the first cell for the row into the
                     // DBCellRecord.
@@ -273,8 +277,7 @@
     public Iterator getIterator() {
         return _rowRecords.values().iterator();
     }
-    
-    
+
     public Iterator getAllRecordsIterator() {
         List result = new ArrayList(_rowRecords.size() * 2);
         result.addAll(_rowRecords.values());
@@ -498,5 +501,10 @@
     public void removeCell(CellValueRecordInterface cvRec) {
         _valuesAgg.removeCell(cvRec);
     }
+    public FormulaRecordAggregate createFormula(int row, int col) {
+        FormulaRecord fr = new FormulaRecord();
+        fr.setRow(row);
+        fr.setColumn((short) col);
+        return new FormulaRecordAggregate(fr, null, _sharedValueManager);
+    }
 }
-

Copied: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java (from r690539, poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedFormulaHolder.java)
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java?p2=poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java&p1=poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedFormulaHolder.java&r1=690539&r2=690636&rev=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedFormulaHolder.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java Sat Aug 30 21:45:00 2008
@@ -17,22 +17,37 @@
 
 package org.apache.poi.hssf.record.aggregates;
 
-import java.util.ArrayList;
-import java.util.List;
-
+import org.apache.poi.hssf.record.ArrayRecord;
 import org.apache.poi.hssf.record.FormulaRecord;
-import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.SharedFormulaRecord;
+import org.apache.poi.hssf.record.SharedValueRecordBase;
+import org.apache.poi.hssf.record.TableRecord;
 
 /**
- * Temporarily holds SharedFormulaRecords while constructing a <tt>RowRecordsAggregate</tt>
+ * Manages various auxiliary records while constructing a
+ * {@link RowRecordsAggregate}:
+ * <ul>
+ * <li>{@link SharedFormulaRecord}s</li>
+ * <li>{@link ArrayRecord}s</li>
+ * <li>{@link TableRecord}s</li>
+ * </ul>
  * 
  * @author Josh Micich
  */
-final class SharedFormulaHolder {
+public final class SharedValueManager {
 
-	private static final SharedFormulaHolder EMPTY = new SharedFormulaHolder(new SharedFormulaRecord[0]);
+	public static final SharedValueManager EMPTY = new SharedValueManager(
+			new SharedFormulaRecord[0], new ArrayRecord[0], new TableRecord[0]);
 	private final SharedFormulaRecord[] _sfrs;
+	private final ArrayRecord[] _arrayRecords;
+	private final TableRecord[] _tableRecords;
+
+	private SharedValueManager(SharedFormulaRecord[] sharedFormulaRecords,
+			ArrayRecord[] arrayRecords, TableRecord[] tableRecords) {
+		_sfrs = sharedFormulaRecords;
+		_arrayRecords = arrayRecords;
+		_tableRecords = tableRecords;
+	}
 
 	/**
 	 * @param recs list of sheet records (possibly contains records for other parts of the Excel file)
@@ -41,56 +56,75 @@
 	 * that this code does not inadvertently collect <tt>SharedFormulaRecord</tt>s from any other
 	 * sheet (which could happen if endIx is chosen poorly).  (see bug 44449) 
 	 */
-	public static SharedFormulaHolder create(List recs, int startIx, int endIx) {
-		List temp = new ArrayList();
-        for (int k = startIx; k < endIx; k++)
-        {
-            Record rec = ( Record ) recs.get(k);
-            if (rec instanceof SharedFormulaRecord) {
-                temp.add(rec);
-            }
-        }
-        if (temp.size() < 1) {
-        	return EMPTY;
-        }
-        SharedFormulaRecord[] sfrs = new SharedFormulaRecord[temp.size()];
-        temp.toArray(sfrs);
-        return new SharedFormulaHolder(sfrs);
-        
-	}
-	private SharedFormulaHolder(SharedFormulaRecord[] sfrs) {
-		_sfrs = sfrs;
+	public static SharedValueManager create(SharedFormulaRecord[] sharedFormulaRecords,
+			ArrayRecord[] arrayRecords, TableRecord[] tableRecords) {
+		if (sharedFormulaRecords.length + arrayRecords.length + tableRecords.length < 1) {
+			return EMPTY;
+		}
+		return new SharedValueManager(sharedFormulaRecords, arrayRecords, tableRecords);
 	}
+
 	public void convertSharedFormulaRecord(FormulaRecord formula) {
-        // Traverse the list of shared formulas in
-        //  reverse order, and try to find the correct one
-        //  for us
-        for (int i=0; i<_sfrs.length; i++) {
-            SharedFormulaRecord shrd = _sfrs[i];
-            if (shrd.isFormulaInShared(formula)) {
-                shrd.convertSharedFormulaRecord(formula);
-                return;
-            }
-        }
-        // not found
-        handleMissingSharedFormulaRecord(formula);
+		int row = formula.getRow();
+		int column = formula.getColumn();
+		// Traverse the list of shared formulas in
+		// reverse order, and try to find the correct one
+		// for us
+		for (int i = 0; i < _sfrs.length; i++) {
+			SharedFormulaRecord shrd = _sfrs[i];
+			if (shrd.isInRange(row, column)) {
+				shrd.convertSharedFormulaRecord(formula);
+				return;
+			}
+		}
+		// not found
+		handleMissingSharedFormulaRecord(formula);
+	}
+
+	/**
+	 * Sometimes the shared formula flag "seems" to be erroneously set, in which case there is no 
+	 * call to <tt>SharedFormulaRecord.convertSharedFormulaRecord</tt> and hence the 
+	 * <tt>parsedExpression</tt> field of this <tt>FormulaRecord</tt> will not get updated.<br/>
+	 * As it turns out, this is not a problem, because in these circumstances, the existing value
+	 * for <tt>parsedExpression</tt> is perfectly OK.<p/>
+	 * 
+	 * This method may also be used for setting breakpoints to help diagnose issues regarding the
+	 * abnormally-set 'shared formula' flags. 
+	 * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
+	 * 
+	 * The method currently does nothing but do not delete it without finding a nice home for this 
+	 * comment.
+	 */
+	private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
+		// could log an info message here since this is a fairly unusual occurrence.
+		formula.setSharedFormula(false); // no point leaving the flag erroneously set
 	}
 
-    /**
-     * Sometimes the shared formula flag "seems" to be erroneously set, in which case there is no 
-     * call to <tt>SharedFormulaRecord.convertSharedFormulaRecord</tt> and hence the 
-     * <tt>parsedExpression</tt> field of this <tt>FormulaRecord</tt> will not get updated.<br/>
-     * As it turns out, this is not a problem, because in these circumstances, the existing value
-     * for <tt>parsedExpression</tt> is perfectly OK.<p/>
-     * 
-     * This method may also be used for setting breakpoints to help diagnose issues regarding the
-     * abnormally-set 'shared formula' flags. 
-     * (see TestValueRecordsAggregate.testSpuriousSharedFormulaFlag()).<p/>
-     * 
-     * The method currently does nothing but do not delete it without finding a nice home for this 
-     * comment.
-     */
-    private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
-        // could log an info message here since this is a fairly unusual occurrence.
-    }
+	/**
+	 * Note - does not return SharedFormulaRecords currently, because the corresponding formula
+	 * records have been converted to 'unshared'. POI does not attempt to re-share formulas. On
+	 * the other hand, there is no such conversion for array or table formulas, so this method 
+	 * returns the TABLE or ARRAY record (if it should be written after the specified 
+	 * formulaRecord.
+	 * 
+	 * @return the TABLE or ARRAY record for this formula cell, if it is the first cell of a 
+	 * table or array region.
+	 */
+	public SharedValueRecordBase getRecordForFirstCell(FormulaRecord formulaRecord) {
+		int row = formulaRecord.getRow();
+		int column = formulaRecord.getColumn();
+		for (int i = 0; i < _tableRecords.length; i++) {
+			TableRecord tr = _tableRecords[i];
+			if (tr.isFirstCell(row, column)) {
+				return tr;
+			}
+		}
+		for (int i = 0; i < _arrayRecords.length; i++) {
+			ArrayRecord ar = _arrayRecords[i];
+			if (ar.isFirstCell(row, column)) {
+				return ar;
+			}
+		}
+		return null;
+	}
 }

Propchange: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
------------------------------------------------------------------------------
    svn:mergeinfo = 

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java Sat Aug 30 21:45:00 2008
@@ -23,16 +23,10 @@
 
 import org.apache.poi.hssf.model.RecordStream;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
-import org.apache.poi.hssf.record.DBCellRecord;
 import org.apache.poi.hssf.record.FormulaRecord;
-import org.apache.poi.hssf.record.MergeCellsRecord;
 import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RecordBase;
-import org.apache.poi.hssf.record.RowRecord;
-import org.apache.poi.hssf.record.SharedFormulaRecord;
 import org.apache.poi.hssf.record.StringRecord;
-import org.apache.poi.hssf.record.TableRecord;
-import org.apache.poi.hssf.record.UnknownRecord;
 import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
 
 /**
@@ -143,63 +137,27 @@
     }
 
     /**
-     * Processes a sequential group of cell value records.  Stops at endIx or the first
-     * non-value record encountered.
-     * @param sfh used to resolve any shared formulas for the current sheet
-     * @return the number of records consumed
+     * Processes a single cell value record
+     * @param sfh used to resolve any shared-formulas/arrays/tables for the current sheet
      */
-    public int construct(List records, int offset, int endIx, SharedFormulaHolder sfh) {
-        RecordStream rs = new RecordStream(records, offset, endIx);
-
-        // Now do the main processing sweep
-        while (rs.hasNext()) {
-            Class recClass = rs.peekNextClass();
-            if (recClass == StringRecord.class) {
-                throw new RuntimeException("Loose StringRecord found without preceding FormulaRecord");
-            }
-
-            if (recClass == TableRecord.class) {
-                throw new RuntimeException("Loose TableRecord found without preceding FormulaRecord");
-            }
-
-            if (recClass == UnknownRecord.class) {
-                break;
-            }
-            if (recClass == RowRecord.class) {
-                break;
-            }
-            if (recClass == DBCellRecord.class) {
-                // end of 'Row Block'.  This record is ignored by POI
-                break;
-            }
-
-            Record rec = rs.getNext();
-
-            if (recClass == SharedFormulaRecord.class) {
-                // Already handled, not to worry
-                continue;
-            }
-            if (recClass == MergeCellsRecord.class) {
-                // doesn't really belong here
-                // can safely be ignored, because it has been processed in a higher method
-                continue;
-            }
-
-            if (!rec.isValue()) {
-                throw new RuntimeException("bad record type");
-            }
-            if (rec instanceof FormulaRecord) {
-                FormulaRecord formula = (FormulaRecord)rec;
-                if (formula.isSharedFormula()) {
-                    sfh.convertSharedFormulaRecord(formula);
-                }
-
-                insertCell(new FormulaRecordAggregate((FormulaRecord)rec, rs));
-                continue;
-            }
-            insertCell(( CellValueRecordInterface ) rec);
+    public void construct(CellValueRecordInterface rec, RecordStream rs, SharedValueManager sfh) {
+        if (rec instanceof FormulaRecord) {
+            FormulaRecord formulaRec = (FormulaRecord)rec;
+            if (formulaRec.isSharedFormula()) {
+                sfh.convertSharedFormulaRecord(formulaRec);
+            }
+            // read optional cached text value
+            StringRecord cachedText;
+            Class nextClass = rs.peekNextClass();
+            if (nextClass == StringRecord.class) {
+                cachedText = (StringRecord) rs.getNext();
+            } else {
+                cachedText = null;
+            }
+            insertCell(new FormulaRecordAggregate(formulaRec, cachedText, sfh));
+        } else {
+            insertCell(rec);
         }
-        return rs.getCountRead();
     }
 
     /** Tallies a count of the size of the cell records
@@ -247,8 +205,8 @@
         return pos - offset;
     }
 
-    public int visitCellsForRow(int rowIndex, RecordVisitor rv) {
-        int result = 0;
+    public void visitCellsForRow(int rowIndex, RecordVisitor rv) {
+
         CellValueRecordInterface[] cellRecs = records[rowIndex];
         if (cellRecs != null) {
             for (int i = 0; i < cellRecs.length; i++) {
@@ -256,24 +214,15 @@
                 if (cvr == null) {
                     continue;
                 }
-                if (cvr instanceof FormulaRecordAggregate) {
-                    FormulaRecordAggregate fmAgg = (FormulaRecordAggregate) cvr;
-                    Record fmAggRec = fmAgg.getFormulaRecord();
-                    rv.visitRecord(fmAggRec);
-                    result += fmAggRec.getRecordSize();
-                    fmAggRec = fmAgg.getStringRecord();
-                    if (fmAggRec != null) {
-                        rv.visitRecord(fmAggRec);
-                        result += fmAggRec.getRecordSize();
-                    }
+                if (cvr instanceof RecordAggregate) {
+                    RecordAggregate agg = (RecordAggregate) cvr;
+                    agg.visitContainedRecords(rv);
                 } else {
                     Record rec = (Record) cvr;
                     rv.visitRecord(rec);
-                    result += rec.getRecordSize();
                 }
             }
         }
-        return result;
     }
 
     public CellValueRecordInterface[] getValueRecords() {

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java Sat Aug 30 21:45:00 2008
@@ -288,23 +288,20 @@
         {
 
             case CELL_TYPE_FORMULA :
-                FormulaRecordAggregate frec = null;
+                FormulaRecordAggregate frec;
 
-                if (cellType != this.cellType)
-                {
-                    frec = new FormulaRecordAggregate(new FormulaRecord());
-                }
-                else
-                {
-                    frec = ( FormulaRecordAggregate ) record;
+                if (cellType != this.cellType) {
+                    frec = sheet.createFormula(row, col);
+                } else {
+                    frec = (FormulaRecordAggregate) record;
+                    frec.setRow(row);
+                    frec.setColumn(col);
                 }
-                frec.setColumn(col);
                 if (setValue)
                 {
                     frec.getFormulaRecord().setValue(getNumericCellValue());
                 }
                 frec.setXFIndex(styleIndex);
-                frec.setRow(row);
                 record = frec;
                 break;
 

Added: poi/trunk/src/testcases/org/apache/poi/hssf/data/testArraysAndTables.xls
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/data/testArraysAndTables.xls?rev=690636&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/src/testcases/org/apache/poi/hssf/data/testArraysAndTables.xls
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java Sat Aug 30 21:45:00 2008
@@ -15,13 +15,10 @@
    limitations under the License.
 ==================================================================== */
 
-/*
- * TestFormulaRecordAggregate.java
- *
- * Created on March 21, 2003, 12:32 AM
- */
-
 package org.apache.poi.hssf.record.aggregates;
+
+import junit.framework.TestCase;
+
 import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.StringRecord;
 
@@ -29,14 +26,13 @@
  *
  * @author  avik
  */
-public final class TestFormulaRecordAggregate extends junit.framework.TestCase {
+public final class TestFormulaRecordAggregate extends TestCase {
     
     public void testBasic() throws Exception {
         FormulaRecord f = new FormulaRecord();
         StringRecord s = new StringRecord();
         s.setString("abc");
-        FormulaRecordAggregate fagg = new FormulaRecordAggregate(f);
-        fagg.setStringRecord(s);
+        FormulaRecordAggregate fagg = new FormulaRecordAggregate(f, s, SharedValueManager.EMPTY);
         assertEquals("abc", fagg.getStringValue());
     }
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java Sat Aug 30 21:45:00 2008
@@ -17,25 +17,100 @@
 
 package org.apache.poi.hssf.record.aggregates;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.record.ArrayRecord;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
+import org.apache.poi.hssf.record.SharedValueRecordBase;
+import org.apache.poi.hssf.record.TableRecord;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.usermodel.RecordInspector;
+import org.apache.poi.hssf.util.CellRangeAddress8Bit;
 
 /**
  * 
  */
 public final class TestRowRecordsAggregate extends TestCase {
-    
-    public void testRowGet() {
-        RowRecordsAggregate rra = new RowRecordsAggregate();
-        RowRecord rr = new RowRecord(4);
-        rra.insertRow(rr);
-        rra.insertRow(new RowRecord(1));
-        
-        RowRecord rr1 = rra.getRow(4);
-        
-        assertNotNull(rr1);
-        assertEquals("Row number is 1", 4, rr1.getRowNumber());
-        assertTrue("Row record retrieved is identical ", rr1 == rr);
-    }
+
+	public void testRowGet() {
+		RowRecordsAggregate rra = new RowRecordsAggregate();
+		RowRecord rr = new RowRecord(4);
+		rra.insertRow(rr);
+		rra.insertRow(new RowRecord(1));
+
+		RowRecord rr1 = rra.getRow(4);
+
+		assertNotNull(rr1);
+		assertEquals("Row number is 1", 4, rr1.getRowNumber());
+		assertTrue("Row record retrieved is identical ", rr1 == rr);
+	}
+
+	/**
+	 * Prior to Aug 2008, POI would re-serialize spreadsheets with {@link ArrayRecord}s or
+	 * {@link TableRecord}s with those records out of order.  Similar to 
+	 * {@link SharedFormulaRecord}s, these records should appear immediately after the first
+	 * {@link FormulaRecord}s that they apply to (and only once).<br/>
+	 */
+	public void testArraysAndTables() {
+		HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testArraysAndTables.xls");
+		Record[] sheetRecs = RecordInspector.getRecords(wb.getSheetAt(0), 0);
+		
+		int countArrayFormulas = verifySharedValues(sheetRecs, ArrayRecord.class);
+		assertEquals(5, countArrayFormulas);
+		int countTableFormulas = verifySharedValues(sheetRecs, TableRecord.class);
+		assertEquals(3, countTableFormulas);
+
+		// Note - SharedFormulaRecords are currently not re-serialized by POI (each is extracted
+		// into many non-shared formulas), but if they ever were, the same rules would apply. 
+		int countSharedFormulas = verifySharedValues(sheetRecs, SharedFormulaRecord.class);
+		assertEquals(0, countSharedFormulas);
+		
+
+		if (false) { // set true to observe re-serialized file
+			File f = new File(System.getProperty("java.io.tmpdir") + "/testArraysAndTables-out.xls");
+			try {
+				OutputStream os = new FileOutputStream(f);
+				wb.write(os);
+				os.close();
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+			System.out.println("Output file to " + f.getAbsolutePath());
+		}
+	}
+
+	private static int verifySharedValues(Record[] recs, Class shfClass) {
+		
+		int result =0;
+		for(int i=0; i<recs.length; i++) {
+			Record rec = recs[i];
+			if (rec.getClass() == shfClass) {
+				result++;
+				Record prevRec = recs[i-1];
+				if (!(prevRec instanceof FormulaRecord)) {
+					throw new AssertionFailedError("Bad record order at index "
+							+ i + ": Formula record expected but got (" 
+							+ prevRec.getClass().getName() + ")");
+				}
+				verifySharedFormula((FormulaRecord) prevRec, rec);
+			}
+		}
+		return result;
+	}
+
+	private static void verifySharedFormula(FormulaRecord firstFormula, Record rec) {
+		CellRangeAddress8Bit range = ((SharedValueRecordBase)rec).getRange();
+		assertEquals(range.getFirstRow(), firstFormula.getRow());
+		assertEquals(range.getFirstColumn(), firstFormula.getColumn());
+	}
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java?rev=690636&r1=690635&r2=690636&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java Sat Aug 30 21:45:00 2008
@@ -28,10 +28,15 @@
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.RecordStream;
+import org.apache.poi.hssf.model.RowBlocksReader;
 import org.apache.poi.hssf.record.BlankRecord;
+import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RecordBase;
 import org.apache.poi.hssf.record.SharedFormulaRecord;
+import org.apache.poi.hssf.record.WindowTwoRecord;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 
@@ -47,6 +52,7 @@
         List records = new ArrayList();
         records.add( new FormulaRecord() );
         records.add( new SharedFormulaRecord() );
+        records.add(new WindowTwoRecord());
 
         constructValueRecord(records);
         Iterator iterator = valueRecord.getIterator();
@@ -59,8 +65,13 @@
     }
 
     private void constructValueRecord(List records) {
-        SharedFormulaHolder sfrh = SharedFormulaHolder.create(records, 0, records.size());
-        valueRecord.construct(records, 0, records.size(), sfrh );
+        RowBlocksReader rbr = new RowBlocksReader(records, 0);
+        SharedValueManager sfrh = rbr.getSharedFormulaManager();
+        RecordStream rs = rbr.getPlainRecordStream();
+        while(rs.hasNext()) {
+            Record rec = rs.getNext();
+            valueRecord.construct((CellValueRecordInterface)rec, rs, sfrh);
+        }
     }
 
     private static List testData() {
@@ -73,6 +84,7 @@
         blankRecord.setColumn( (short) 2 );
         records.add( formulaRecord );
         records.add( blankRecord );
+        records.add(new WindowTwoRecord());
         return records;
     }
 

Added: poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/RecordInspector.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/RecordInspector.java?rev=690636&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/RecordInspector.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/RecordInspector.java Sat Aug 30 21:45:00 2008
@@ -0,0 +1,67 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
+
+/**
+ * Test utility class to get {@link Record}s out HSSF objects
+ * 
+ * @author Josh Micich
+ */
+public final class RecordInspector {
+
+	private RecordInspector() {
+		// no instances of this class
+	}
+
+	private static final class RecordCollector implements RecordVisitor {
+
+		private List _list;
+
+		public RecordCollector() {
+			_list = new ArrayList(128);
+		}
+
+		public void visitRecord(Record r) {
+			_list.add(r);
+		}
+
+		public Record[] getRecords() {
+			Record[] result = new Record[_list.size()];
+			_list.toArray(result);
+			return result;
+		}
+	}
+
+	/**
+	 * @param streamOffset start position for serialization. This affects values in some
+	 *         records such as INDEX, but most callers will be OK to pass zero.
+	 * @return the {@link Record}s (in order) which will be output when the
+	 *         specified sheet is serialized
+	 */
+	public static Record[] getRecords(HSSFSheet hSheet, int streamOffset) {
+		RecordCollector rc = new RecordCollector();
+		hSheet.getSheet().visitContainedRecords(rc, streamOffset);
+		return rc.getRecords();
+	}
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org


Mime
View raw message