You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2008/05/23 05:56:34 UTC

svn commit: r659403 - in /poi/trunk/src: documentation/content/xdocs/ java/org/apache/poi/hssf/model/ java/org/apache/poi/hssf/record/ java/org/apache/poi/hssf/usermodel/ testcases/org/apache/poi/hssf/model/ testcases/org/apache/poi/hssf/usermodel/

Author: josh
Date: Thu May 22 20:56:31 2008
New Revision: 659403

URL: http://svn.apache.org/viewvc?rev=659403&view=rev
Log:
Fix for 45066 - sheet encoding size mismatch problems

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/DBCellRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
    poi/trunk/src/testcases/org/apache/poi/hssf/model/TestSheet.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.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=659403&r1=659402&r2=659403&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/changes.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/changes.xml Thu May 22 20:56:31 2008
@@ -37,6 +37,7 @@
 
 		<!-- Don't forget to update status.xml too! -->
         <release version="3.1-final" date="2008-06-??">
+           <action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
            <action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
            <action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action>
            <action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</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=659403&r1=659402&r2=659403&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Thu May 22 20:56:31 2008
@@ -34,6 +34,7 @@
 	<!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1-final" date="2008-06-??">
+           <action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
            <action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
            <action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action>
            <action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action>

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=659403&r1=659402&r2=659403&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 Thu May 22 20:56:31 2008
@@ -96,8 +96,8 @@
     protected List                       condFormatting    =     new ArrayList();
 
     /** Add an UncalcedRecord if not true indicating formulas have not been calculated */
-    protected boolean uncalced = false;
-	
+    protected boolean _isUncalced = false;
+    
     public static final byte PANE_LOWER_RIGHT = (byte)0;
     public static final byte PANE_UPPER_RIGHT = (byte)1;
     public static final byte PANE_LOWER_LEFT = (byte)2;
@@ -162,7 +162,7 @@
                 }
             }
             else if (rec.getSid() == UncalcedRecord.sid) {
-                retval.uncalced = true;
+                retval._isUncalced = true;
             }
             else if (rec.getSid() == DimensionsRecord.sid)
             {
@@ -329,16 +329,8 @@
             }
         }
         retval.records = records;
-//        if (retval.rows == null)
-//        {
-//            retval.rows = new RowRecordsAggregate();
-//        }
         retval.checkCells();
         retval.checkRows();
-//        if (retval.cells == null)
-//        {
-//            retval.cells = new ValueRecordsAggregate();
-//        }
         if (log.check( POILogger.DEBUG ))
             log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
         return retval;
@@ -816,17 +808,17 @@
             // Once the rows have been found in the list of records, start
             //  writing out the blocked row information. This includes the DBCell references
             if (record instanceof RowRecordsAggregate) {
-              pos += ((RowRecordsAggregate)record).serialize(pos, data, cells);   // rec.length;
+              pos += ((RowRecordsAggregate)record).serialize(pos, data, cells);
             } else if (record instanceof ValueRecordsAggregate) {
               //Do nothing here. The records were serialized during the RowRecordAggregate block serialization
             } else {
-              pos += record.serialize(pos, data );   // rec.length;
+              pos += record.serialize(pos, data );
             }
 
             // If the BOF record was just serialized then add the IndexRecord
             if (record.getSid() == BOFRecord.sid) {
               // Add an optional UncalcedRecord
-              if (uncalced) {
+              if (_isUncalced) {
                   UncalcedRecord rec = new UncalcedRecord();
                   pos += rec.serialize(pos, data);
               }
@@ -837,31 +829,10 @@
                 pos += serializeIndexRecord(k, pos, data);
               }
             }
-
-            //// uncomment to test record sizes ////
-//            System.out.println( record.getClass().getName() );
-//            byte[] data2 = new byte[record.getRecordSize()];
-//            record.serialize(0, data2 );   // rec.length;
-//            if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4
-//                    && record instanceof RowRecordsAggregate == false
-//                    && record instanceof ValueRecordsAggregate == false
-//                    && record instanceof EscherAggregate == false)
-//            {
-//                throw new RuntimeException("Blah!!!  Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records.");
-//            }
-
-//asd:            int len = record.serialize(pos + offset, data );
-
-            /////  DEBUG BEGIN /////
-//asd:            if (len != record.getRecordSize())
-//asd:                throw new IllegalStateException("Record size does not match serialized bytes.  Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize() + ". Record object is " + record.getClass());
-            /////  DEBUG END /////
-
-//asd:            pos += len;   // rec.length;
-
         }
-        if (log.check( POILogger.DEBUG ))
+        if (log.check( POILogger.DEBUG )) {
             log.log(POILogger.DEBUG, "Sheet.serialize returning ");
+        }
         return pos-offset;
     }
 
@@ -875,10 +846,17 @@
       for (int j = BOFRecordIndex+1; j < records.size(); j++)
       {
         Record tmpRec = (( Record ) records.get(j));
-        if (tmpRec instanceof RowRecordsAggregate)
-          break;
+        if (tmpRec instanceof UncalcedRecord) {
+            continue;
+        }
+        if (tmpRec instanceof RowRecordsAggregate) {
+            break;
+        }
         sheetRecSize+= tmpRec.getRecordSize();
       }
+      if (_isUncalced) {
+          sheetRecSize += UncalcedRecord.getStaticRecordSize();
+      }
       //Add the references to the DBCells in the IndexRecord (one for each block)
       int blockCount = rows.getRowBlockCount();
       //Calculate the size of this IndexRecord
@@ -2017,31 +1995,33 @@
     {
         int retval = 0;
 
-        for ( int k = 0; k < records.size(); k++ )
-        {
-            retval += ( (Record) records.get( k ) ).getRecordSize();
+        for ( int k = 0; k < records.size(); k++) {
+            Record record = (Record) records.get(k);
+            if (record instanceof UncalcedRecord) {
+                // skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set
+                continue;
+            }
+            retval += record.getRecordSize();
         }
-        //Add space for the IndexRecord
         if (rows != null) {
-            final int blocks = rows.getRowBlockCount();
-            retval += IndexRecord.getRecordSizeForBlockCount(blocks);
-
-            //Add space for the DBCell records
-            //Once DBCell per block.
-            //8 bytes per DBCell (non variable section)
-            //2 bytes per row reference
-            retval += (8 * blocks);
-            for (Iterator itr = rows.getIterator(); itr.hasNext();) {
-                RowRecord row = (RowRecord)itr.next();
-                if (cells != null && cells.rowHasCells(row.getRowNumber()))
-                    retval += 2;
+            // Add space for the IndexRecord and DBCell records
+            final int nBlocks = rows.getRowBlockCount();
+            int nRows = 0;
+            if (cells != null) {
+                for (Iterator itr = rows.getIterator(); itr.hasNext();) {
+                    RowRecord row = (RowRecord)itr.next();
+                    if (cells.rowHasCells(row.getRowNumber())) {
+                        nRows++;
+                    }
+                }
             }
+            retval += IndexRecord.getRecordSizeForBlockCount(nBlocks);
+            retval += DBCellRecord.calculateSizeOfRecords(nBlocks, nRows);
         }
         // Add space for UncalcedRecord
-        if (uncalced) {
+        if (_isUncalced) {
             retval += UncalcedRecord.getStaticRecordSize();
         }
-
         return retval;
     }
 
@@ -2518,13 +2498,13 @@
      * @return whether an uncalced record must be inserted or not at generation
      */
     public boolean getUncalced() {
-        return uncalced;
+        return _isUncalced;
     }
     /**
      * @param uncalced whether an uncalced record must be inserted or not at generation
      */
     public void setUncalced(boolean uncalced) {
-        this.uncalced = uncalced;
+        this._isUncalced = uncalced;
     }
 
     /**

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/DBCellRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/DBCellRecord.java?rev=659403&r1=659402&r2=659403&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/DBCellRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/DBCellRecord.java Thu May 22 20:56:31 2008
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -15,7 +14,6 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
@@ -29,10 +27,7 @@
  * @author Jason Height
  * @version 2.0-pre
  */
-
-public class DBCellRecord
-    extends Record
-{
+public final class DBCellRecord extends Record {
     public final static int BLOCK_SIZE = 32;
     public final static short sid = 0xd7;
     private int               field_1_row_offset;
@@ -46,7 +41,6 @@
      * Constructs a DBCellRecord and sets its fields appropriately
      * @param in the RecordInputstream to read the record from
      */
-
     public DBCellRecord(RecordInputStream in)
     {
         super(in);
@@ -78,7 +72,6 @@
      *
      * @param offset    offset to the start of the first cell in the next DBCell block
      */
-
     public void setRowOffset(int offset)
     {
         field_1_row_offset = offset;
@@ -108,7 +101,6 @@
      *
      * @return rowoffset to the start of the first cell in the next DBCell block
      */
-
     public int getRowOffset()
     {
         return field_1_row_offset;
@@ -120,7 +112,6 @@
      * @param index of the cell offset to retrieve
      * @return celloffset from the celloffset array
      */
-
     public short getCellOffsetAt(int index)
     {
         return field_2_cell_offsets[ index ];
@@ -131,7 +122,6 @@
      *
      * @return number of cell offsets
      */
-
     public int getNumCellOffsets()
     {
         return field_2_cell_offsets.length;
@@ -175,9 +165,15 @@
         return 8 + (getNumCellOffsets() * 2);
     }
     
-    /** Returns the size of a DBCellRecord when it needs to reference a certain number of rows*/
-    public static int getRecordSizeForRows(int rows) {
-      return 8 + (rows * 2);
+    /**
+     *  @returns the size of the group of <tt>DBCellRecord</tt>s needed to encode
+     *  the specified number of blocks and rows
+     */
+    public static int calculateSizeOfRecords(int nBlocks, int nRows) {
+        // One DBCell per block.
+        // 8 bytes per DBCell (non variable section)
+        // 2 bytes per row reference
+        return nBlocks * 8 + nRows * 2;
     }
 
     public short getSid()

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java?rev=659403&r1=659402&r2=659403&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java Thu May 22 20:56:31 2008
@@ -15,12 +15,6 @@
    limitations under the License.
 ==================================================================== */
 
-
-/*
- * HSSFWorkbook.java
- *
- * Created on September 30, 2001, 3:37 PM
- */
 package org.apache.poi.hssf.usermodel;
 
 import org.apache.poi.POIDocument;
@@ -64,7 +58,6 @@
  * @author  Shawn Laubach (slaubach at apache dot org)
  * @version 2.0-pre
  */
-
 public class HSSFWorkbook extends POIDocument
 {
     private static final int DEBUG = POILogger.DEBUG;
@@ -88,7 +81,7 @@
      * this holds the HSSFSheet objects attached to this workbook
      */
 
-    protected ArrayList sheets;
+    protected List _sheets;
 
     /**
      * this holds the HSSFName objects attached to this workbook
@@ -142,7 +135,7 @@
     {
         super(null, null);
         workbook = book;
-        sheets = new ArrayList( INITIAL_CAPACITY );
+        _sheets = new ArrayList( INITIAL_CAPACITY );
         names = new ArrayList( INITIAL_CAPACITY );
     }
 
@@ -233,7 +226,7 @@
            this.directory = null;
         }
 
-        sheets = new ArrayList(INITIAL_CAPACITY);
+        _sheets = new ArrayList(INITIAL_CAPACITY);
         names  = new ArrayList(INITIAL_CAPACITY);
 
         // Grab the data from the workbook stream, however
@@ -263,7 +256,7 @@
 
             HSSFSheet hsheet = new HSSFSheet(this, sheet);
 
-            sheets.add(hsheet);
+            _sheets.add(hsheet);
 
             // workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size());
         }
@@ -361,12 +354,12 @@
      */
 
     public void setSheetOrder(String sheetname, int pos ) {
-        sheets.add(pos,sheets.remove(getSheetIndex(sheetname)));
+        _sheets.add(pos,_sheets.remove(getSheetIndex(sheetname)));
         workbook.setSheetOrder(sheetname, pos);
     }
 
     private void validateSheetIndex(int index) {
-        int lastSheetIx = sheets.size() - 1;
+        int lastSheetIx = _sheets.size() - 1;
         if (index < 0 || index > lastSheetIx) {
             throw new IllegalArgumentException("Sheet index (" 
                     + index +") is out of range (0.." +    lastSheetIx + ")");
@@ -380,7 +373,7 @@
     public void setSelectedTab(int index) {
         
         validateSheetIndex(index);
-        int nSheets = sheets.size();
+        int nSheets = _sheets.size();
         for (int i=0; i<nSheets; i++) {
                getSheetAt(i).setSelected(i == index);
         }
@@ -398,7 +391,7 @@
         for (int i = 0; i < indexes.length; i++) {
             validateSheetIndex(indexes[i]);
         }
-        int nSheets = sheets.size();
+        int nSheets = _sheets.size();
         for (int i=0; i<nSheets; i++) {
             boolean bSelect = false;
             for (int j = 0; j < indexes.length; j++) {
@@ -420,7 +413,7 @@
     public void setActiveSheet(int index) {
         
         validateSheetIndex(index);
-        int nSheets = sheets.size();
+        int nSheets = _sheets.size();
         for (int i=0; i<nSheets; i++) {
              getSheetAt(i).setActive(i == index);
         }
@@ -492,19 +485,15 @@
      * set the sheet name.
      * Will throw IllegalArgumentException if the name is greater than 31 chars
      * or contains /\?*[]
-     * @param sheet number (0 based)
+     * @param sheetIx number (0 based)
      */
-    public void setSheetName(int sheet, String name)
+    public void setSheetName(int sheetIx, String name)
     {
-        if (workbook.doesContainsSheetName( name, sheet ))
+        if (workbook.doesContainsSheetName( name, sheetIx )) {
             throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
-
-        if (sheet > (sheets.size() - 1))
-        {
-            throw new RuntimeException("Sheet out of bounds");
         }
-
-        workbook.setSheetName( sheet, name);
+        validateSheetIndex(sheetIx);
+        workbook.setSheetName(sheetIx, name);
     }
 
 
@@ -516,15 +505,12 @@
      * or contains /\?*[]
      * @param sheet number (0 based)
      */
-    public void setSheetName( int sheet, String name, short encoding )
+    public void setSheetName(int sheetIx, String name, short encoding)
     {
-        if (workbook.doesContainsSheetName( name, sheet ))
+        if (workbook.doesContainsSheetName( name, sheetIx )) {
             throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
-
-        if (sheet > (sheets.size() - 1))
-        {
-            throw new RuntimeException("Sheet out of bounds");
         }
+        validateSheetIndex(sheetIx);
 
         switch ( encoding ) {
         case ENCODING_COMPRESSED_UNICODE:
@@ -536,51 +522,39 @@
             throw new RuntimeException( "Unsupported encoding" );
         }
 
-        workbook.setSheetName( sheet, name, encoding );
+        workbook.setSheetName( sheetIx, name, encoding );
     }
 
     /**
      * get the sheet name
-     * @param sheet Number
+     * @param sheetIx Number
      * @return Sheet name
      */
-
-    public String getSheetName(int sheet)
+    public String getSheetName(int sheetIx)
     {
-        if (sheet > (sheets.size() - 1))
-        {
-            throw new RuntimeException("Sheet out of bounds");
-        }
-        return workbook.getSheetName(sheet);
+        validateSheetIndex(sheetIx);
+        return workbook.getSheetName(sheetIx);
     }
 
     /**
      * check whether a sheet is hidden
-     * @param sheet Number
+     * @param sheetIx Number
      * @return True if sheet is hidden
      */
-
-    public boolean isSheetHidden(int sheet) {
-        if (sheet > (sheets.size() - 1))
-        {
-            throw new RuntimeException("Sheet out of bounds");
-        }
-        return workbook.isSheetHidden(sheet);
+    public boolean isSheetHidden(int sheetIx) {
+        validateSheetIndex(sheetIx);
+        return workbook.isSheetHidden(sheetIx);
     }
 
     /**
      * Hide or unhide a sheet
      *
-     * @param sheetnum The sheet number
+     * @param sheetIx The sheet index
      * @param hidden True to mark the sheet as hidden, false otherwise
      */
-
-    public void setSheetHidden(int sheet, boolean hidden) {
-        if (sheet > (sheets.size() - 1))
-        {
-            throw new RuntimeException("Sheet out of bounds");
-        }
-        workbook.setSheetHidden(sheet,hidden);
+    public void setSheetHidden(int sheetIx, boolean hidden) {
+        validateSheetIndex(sheetIx);
+        workbook.setSheetHidden(sheetIx, hidden);
     }
 
     /*
@@ -602,12 +576,12 @@
 
     /** Returns the index of the given sheet
      * @param sheet the sheet to look up
-     * @return index of the sheet (0 based)
+     * @return index of the sheet (0 based). <tt>-1</tt> if not found
      */
     public int getSheetIndex(HSSFSheet sheet)
     {
-        for(int i=0; i<sheets.size(); i++) {
-            if(sheets.get(i) == sheet) {
+        for(int i=0; i<_sheets.size(); i++) {
+            if(_sheets.get(i) == sheet) {
                 return i;
             }
         }
@@ -636,9 +610,9 @@
     {
         HSSFSheet sheet = new HSSFSheet(this);
 
-        sheets.add(sheet);
-        workbook.setSheetName(sheets.size() - 1, "Sheet" + (sheets.size() - 1));
-        boolean isOnlySheet = sheets.size() == 1;
+        _sheets.add(sheet);
+        workbook.setSheetName(_sheets.size() - 1, "Sheet" + (_sheets.size() - 1));
+        boolean isOnlySheet = _sheets.size() == 1;
         sheet.setSelected(isOnlySheet);
         sheet.setActive(isOnlySheet);
         return sheet;
@@ -652,13 +626,13 @@
 
     public HSSFSheet cloneSheet(int sheetNum) {
         validateSheetIndex(sheetNum);
-        HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum);
+        HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetNum);
         String srcName = workbook.getSheetName(sheetNum);
         HSSFSheet clonedSheet = srcSheet.cloneSheet(this);
         clonedSheet.setSelected(false);
         clonedSheet.setActive(false);
 
-        sheets.add(clonedSheet);
+        _sheets.add(clonedSheet);
         int i = 1;
         while (true) {
             // Try and find the next sheet name that is unique
@@ -672,7 +646,7 @@
 
             //If the sheet name is unique, then set it otherwise move on to the next number.
             if (workbook.getSheetIndex(name) == -1) {
-              workbook.setSheetName(sheets.size()-1, name);
+              workbook.setSheetName(_sheets.size()-1, name);
               break;
             }
         }
@@ -693,14 +667,14 @@
 
     public HSSFSheet createSheet(String sheetname)
     {
-        if (workbook.doesContainsSheetName( sheetname, sheets.size() ))
+        if (workbook.doesContainsSheetName( sheetname, _sheets.size() ))
             throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
 
         HSSFSheet sheet = new HSSFSheet(this);
 
-        sheets.add(sheet);
-        workbook.setSheetName(sheets.size() - 1, sheetname);
-        boolean isOnlySheet = sheets.size() == 1;
+        _sheets.add(sheet);
+        workbook.setSheetName(_sheets.size() - 1, sheetname);
+        boolean isOnlySheet = _sheets.size() == 1;
         sheet.setSelected(isOnlySheet);
         sheet.setActive(isOnlySheet);
         return sheet;
@@ -713,9 +687,14 @@
 
     public int getNumberOfSheets()
     {
-        return sheets.size();
+        return _sheets.size();
     }
 
+    private HSSFSheet[] getSheets() {
+        HSSFSheet[] result = new HSSFSheet[_sheets.size()];
+        _sheets.toArray(result);
+        return result;
+    }
     /**
      * Get the HSSFSheet object at the given index.
      * @param index of the sheet number (0-based physical & logical)
@@ -724,7 +703,7 @@
 
     public HSSFSheet getSheetAt(int index)
     {
-        return (HSSFSheet) sheets.get(index);
+        return (HSSFSheet) _sheets.get(index);
     }
 
     /**
@@ -737,13 +716,13 @@
     {
         HSSFSheet retval = null;
 
-        for (int k = 0; k < sheets.size(); k++)
+        for (int k = 0; k < _sheets.size(); k++)
         {
             String sheetname = workbook.getSheetName(k);
 
             if (sheetname.equalsIgnoreCase(name))
             {
-                retval = (HSSFSheet) sheets.get(k);
+                retval = (HSSFSheet) _sheets.get(k);
             }
         }
         return retval;
@@ -772,11 +751,11 @@
         boolean wasActive = getSheetAt(index).isActive();
         boolean wasSelected = getSheetAt(index).isSelected();
 
-        sheets.remove(index);
+        _sheets.remove(index);
         workbook.removeSheet(index);
 
         // set the remaining active/selected sheet
-        int nSheets = sheets.size();
+        int nSheets = _sheets.size();
         if (nSheets < 1) {
             // nothing more to do if there are no sheets left
             return;
@@ -1152,48 +1131,47 @@
 
     public byte[] getBytes()
     {
-        if (log.check( POILogger.DEBUG ))
+        if (log.check( POILogger.DEBUG )) {
             log.log(DEBUG, "HSSFWorkbook.getBytes()");
+        }
+        
+        HSSFSheet[] sheets = getSheets();
+        int nSheets = sheets.length;
 
         // before getting the workbook size we must tell the sheets that
         // serialization is about to occur.
-        for (int k = 0; k < sheets.size(); k++)
-            ((HSSFSheet) sheets.get(k)).getSheet().preSerialize();
-
-        int wbsize = workbook.getSize();
+        for (int i = 0; i < nSheets; i++) {
+            sheets[i].getSheet().preSerialize();
+        }
 
-        // log.debug("REMOVEME: old sizing method "+workbook.serialize().length);
-        // ArrayList sheetbytes = new ArrayList(sheets.size());
-        int totalsize = wbsize;
+        int totalsize = workbook.getSize();
 
-        for (int k = 0; k < sheets.size(); k++)
-        {
+        // pre-calculate all the sheet sizes and set BOF indexes
+        int[] estimatedSheetSizes = new int[nSheets];
+        for (int k = 0; k < nSheets; k++) {
             workbook.setSheetBof(k, totalsize);
-            totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize();
+            int sheetSize = sheets[k].getSheet().getSize();
+            estimatedSheetSizes[k] = sheetSize;
+            totalsize += sheetSize;
         }
 
 
-/*        if (totalsize < 4096)
-        {
-            totalsize = 4096;
-        }*/
         byte[] retval = new byte[totalsize];
         int pos = workbook.serialize(0, retval);
 
-        // System.arraycopy(wb, 0, retval, 0, wb.length);
-        for (int k = 0; k < sheets.size(); k++)
-        {
-
-            // byte[] sb = (byte[])sheetbytes.get(k);
-            // System.arraycopy(sb, 0, retval, pos, sb.length);
-            int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos,
-                                retval);
-            pos += len;   // sb.length;
+        for (int k = 0; k < nSheets; k++) {
+            int serializedSize = sheets[k].getSheet().serialize(pos, retval);
+            if (serializedSize != estimatedSheetSizes[k]) {
+                // Wrong offset values have been passed in the call to setSheetBof() above.
+                // For books with more than one sheet, this discrepancy would cause excel 
+                // to report errors and loose data while reading the workbook
+                throw new IllegalStateException("Actual serialized sheet size (" + serializedSize 
+                        + ") differs from pre-calculated size (" + estimatedSheetSizes[k] 
+                        + ") for sheet (" + k + ")");
+                // TODO - add similar sanity check to ensure that Sheet.serializeIndexRecord() does not write mis-aligned offsets either
+            }
+            pos += serializedSize;
         }
-/*        for (int k = pos; k < totalsize; k++)
-        {
-            retval[k] = 0;
-        }*/
         return retval;
     }
 

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/model/TestSheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/model/TestSheet.java?rev=659403&r1=659402&r2=659403&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/model/TestSheet.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/model/TestSheet.java Thu May 22 20:56:31 2008
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hssf.model;
 
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
@@ -351,5 +352,25 @@
         xfindex = sheet.getXFIndexForColAt((short) 10);
         assertEquals(DEFAULT_IDX, xfindex);
     }
+
+    /**
+     * Prior to bug 45066, POI would get the estimated sheet size wrong 
+     * when an <tt>UncalcedRecord</tt> was present.<p/>
+     */
+    public void testUncalcSize_bug45066() {
+
+        List records = new ArrayList();
+        records.add(new BOFRecord());
+        records.add(new UncalcedRecord());
+        records.add(new EOFRecord());
+        Sheet sheet = Sheet.createSheet( records, 0, 0 );
+
+        int estimatedSize = sheet.getSize();
+        int serializedSize = sheet.serialize(0, new byte[estimatedSize]);
+        if (serializedSize != estimatedSize) {
+            throw new AssertionFailedError("Identified bug 45066 b");
+        }
+        assertEquals(50, serializedSize);
+    }
 }
 

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java?rev=659403&r1=659402&r2=659403&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java Thu May 22 20:56:31 2008
@@ -20,12 +20,16 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.List;
 
 import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.Sheet;
 import org.apache.poi.hssf.record.NameRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.util.TempFile;
 /**
  *
@@ -376,4 +380,49 @@
         assertEquals("active", expectedActive, sheet.isActive());
         assertEquals("selected", expectedSelected, sheet.isSelected());
     }
-}
+    
+    /**
+     * If Sheet.getSize() returns a different result to Sheet.serialize(), this will cause the BOF
+     * records to be written with invalid offset indexes.  Excel does not like this, and such 
+     * errors are particularly hard to track down.  This test ensures that HSSFWorkbook throws
+     * a specific exception as soon as the situation is detected. See bugzilla 45066
+     */
+    public void testSheetSerializeSizeMismatch_bug45066() {
+        HSSFWorkbook wb = new HSSFWorkbook();
+        Sheet sheet = wb.createSheet("Sheet1").getSheet();
+        List sheetRecords = sheet.getRecords();
+        // one way (of many) to cause the discrepancy is with a badly behaved record:
+        sheetRecords.add(new BadlyBehavedRecord());
+        // There is also much logic inside Sheet that (if buggy) might also cause the discrepancy
+        try {
+            wb.getBytes();
+            throw new AssertionFailedError("Identified bug 45066 a");
+        } catch (IllegalStateException e) {
+            // Expected badly behaved sheet record to cause exception
+            assertTrue(e.getMessage().startsWith("Actual serialized sheet size"));
+        }
+    }
+    /**
+     * result returned by getRecordSize() differs from result returned by serialize()
+     */
+    private static final class BadlyBehavedRecord extends Record {
+        public BadlyBehavedRecord() {
+            // 
+        }
+        protected void fillFields(RecordInputStream in) {
+            throw new RuntimeException("Should not be called");
+        }
+        public short getSid() {
+            return 0x777;
+        }
+        public int serialize(int offset, byte[] data) {
+            return 4;
+        }
+        protected void validateSid(short id) {
+            throw new RuntimeException("Should not be called");
+        }
+        public int getRecordSize() {
+            return 8;
+        }
+    }
+ }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java?rev=659403&r1=659402&r2=659403&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java Thu May 22 20:56:31 2008
@@ -45,8 +45,8 @@
 	 */
 	public void testTextSheets() throws Exception {
 		// Both should have two sheets
-		assertEquals(2, wbH.sheets.size());
-		assertEquals(2, wbU.sheets.size());
+		assertEquals(2, wbH.getNumberOfSheets());
+		assertEquals(2, wbU.getNumberOfSheets());
 
 		// All sheets should have one row
 		assertEquals(0, wbH.getSheetAt(0).getLastRowNum());



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