]> source.dussan.org Git - poi.git/commitdiff
Fixed ExtSST serialization (length not calculated correctly)
authorJason Height <jheight@apache.org>
Thu, 18 Sep 2003 02:10:50 +0000 (02:10 +0000)
committerJason Height <jheight@apache.org>
Thu, 18 Sep 2003 02:10:50 +0000 (02:10 +0000)
Implemented DBCellRecord and IndexRecord serialization

Can now import into MS Access. Cool! Both of the above fixes were required to make this work.

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353356 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/model/Sheet.java
src/java/org/apache/poi/hssf/record/DBCellRecord.java
src/java/org/apache/poi/hssf/record/ExtSSTInfoSubRecord.java
src/java/org/apache/poi/hssf/record/ExtSSTRecord.java
src/java/org/apache/poi/hssf/record/IndexRecord.java
src/java/org/apache/poi/hssf/record/SSTDeserializer.java
src/java/org/apache/poi/hssf/record/SSTRecord.java
src/java/org/apache/poi/hssf/record/SSTSerializer.java
src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java

index d596cc9ac37774eee0d7f41ae21af9c2dec4603d..456606bc2d382cb5bb5c331d62a2a7ee50022c0e 100644 (file)
@@ -288,6 +288,15 @@ public class Sheet implements Model
            {
                retval.windowTwo = (WindowTwoRecord) rec;
            }
+            else if ( rec.getSid() == DBCellRecord.sid )
+            {
+                rec = null;
+            }
+            else if ( rec.getSid() == IndexRecord.sid )
+            {
+                rec = null;
+            }
+
            
             if (rec != null)
             {
@@ -700,49 +709,6 @@ public class Sheet implements Model
         return preoffset;
     }
 
-    /**
-     * Serializes all records in the sheet into one big byte array.  Use this to write
-     * the sheet out.
-     *
-     * @return byte[] array containing the binary representation of the records in this sheet
-     *
-     */
-
-    public byte [] serialize()
-    {
-        log.log(log.DEBUG, "Sheet.serialize");
-
-        // addDBCellRecords();
-        byte[] retval    = null;
-
-        // ArrayList bytes     = new ArrayList(4096);
-        int    arraysize = getSize();
-        int    pos       = 0;
-
-        // for (int k = 0; k < records.size(); k++)
-        // {
-        // bytes.add((( Record ) records.get(k)).serialize());
-        //
-        // }
-        // for (int k = 0; k < bytes.size(); k++)
-        // {
-        // arraysize += (( byte [] ) bytes.get(k)).length;
-        // log.debug((new StringBuffer("arraysize=")).append(arraysize)
-        // .toString());
-        // }
-        retval = new byte[ arraysize ];
-        for (int k = 0; k < records.size(); k++)
-        {
-
-            // byte[] rec = (( byte [] ) bytes.get(k));
-            // System.arraycopy(rec, 0, retval, pos, rec.length);
-            pos += (( Record ) records.get(k)).serialize(pos,
-                    retval);   // rec.length;
-        }
-        log.log(log.DEBUG, "Sheet.serialize returning " + retval);
-        return retval;
-    }
-
     /**
      * Serializes all records in the sheet into one big byte array.  Use this to write
      * the sheet out.
@@ -756,40 +722,69 @@ public class Sheet implements Model
     {
         log.log(log.DEBUG, "Sheet.serialize using offsets");
 
-        // addDBCellRecords();
-        // ArrayList bytes     = new ArrayList(4096);
-        // int arraysize = getSize();   // 0;
-        int pos       = 0;
-
-        // for (int k = 0; k < records.size(); k++)
-        // {
-        // bytes.add((( Record ) records.get(k)).serialize());
-        //
-        // }
-        // for (int k = 0; k < bytes.size(); k++)
-        // {
-        // arraysize += (( byte [] ) bytes.get(k)).length;
-        // log.debug((new StringBuffer("arraysize=")).append(arraysize)
-        // .toString());
-        // }
+        int pos = offset;
+        boolean haveSerializedIndex = false;
         for (int k = 0; k < records.size(); k++)
         {
-//             byte[] rec = (( byte [] ) bytes.get(k));
-            // System.arraycopy(rec, 0, data, offset + pos, rec.length);
             Record record = (( Record ) records.get(k));
+            int startPos = pos;
+            //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;
+            } 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;
+            }
 
-            //uncomment to test record sizes
-//            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)
-//                throw new RuntimeException("Blah!!!");
-
-            pos += record.serialize(pos + offset, data );   // rec.length;
-
+            //If the BOF record was just serialized then add the IndexRecord
+            if (record.getSid() == BOFRecord.sid) {
+              //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 (!haveSerializedIndex) {
+                haveSerializedIndex = true;
+                pos += serializeIndexRecord(k, pos, data);
+              }
+            }
         }
         log.log(log.DEBUG, "Sheet.serialize returning ");
-        return pos;
+        return pos-offset;
+    }
+
+    private int serializeIndexRecord(final int BOFRecordIndex, final int offset, byte[] data) {
+      IndexRecord index = new IndexRecord();
+      index.setFirstRow(rows.getFirstRowNum());
+      index.setLastRowAdd1(rows.getLastRowNum()+1);
+      //Calculate the size of the records from the end of the BOF
+      //and up to the RowRecordsAggregate...
+      int sheetRecSize = 0;
+      for (int j = BOFRecordIndex+1; j < records.size(); j++)
+      {
+        Record tmpRec = (( Record ) records.get(j));
+        if (tmpRec instanceof RowRecordsAggregate)
+          break;
+        sheetRecSize+= tmpRec.getRecordSize();
+      }
+      //Add the references to the DBCells in the IndexRecord (one for each block)
+      int blockCount = rows.getRowBlockCount();
+      //Calculate the size of this IndexRecord
+      int indexRecSize = index.getRecordSizeForBlockCount(blockCount);
+
+      int rowBlockOffset = 0;
+      int cellBlockOffset = 0;
+      int dbCellOffset = 0;
+      for (int block=0;block<blockCount;block++) {
+        rowBlockOffset += rows.getRowBlockSize(block);
+        cellBlockOffset += cells.getRowCellBlockSize(rows.getStartRowNumberForBlock(block),
+                                                     rows.getEndRowNumberForBlock(block));
+        //Note: The offsets are relative to the Workbook BOF. Assume that this is
+        //0 for now.....
+        index.addDbcell(offset + indexRecSize + sheetRecSize + dbCellOffset + rowBlockOffset + cellBlockOffset);
+        //Add space required to write the dbcell record(s) (whose references were just added).
+        dbCellOffset += (8 + (rows.getRowCountForBlock(block) * 2));
+      }
+      return index.serialize(offset, data);
     }
 
     /**
@@ -1369,84 +1364,6 @@ public class Sheet implements Model
         return this.cells.getRowCellIterator(row);
     }
 
-    /**
-     * Not currently used method to calculate and add dbcell records
-     *
-     */
-
-    public void addDBCellRecords()
-    {
-        int         offset        = 0;
-        int         recnum        = 0;
-        int         rownum        = 0;
-        //int         lastrow       = 0;
-        //long        lastrowoffset = 0;
-        IndexRecord index         = null;
-
-        // ArrayList rowOffsets = new ArrayList();
-        IntList     rowOffsets    = new IntList();
-
-        for (recnum = 0; recnum < records.size(); recnum++)
-        {
-            Record rec = ( Record ) records.get(recnum);
-
-            if (rec.getSid() == IndexRecord.sid)
-            {
-                index = ( IndexRecord ) rec;
-            }
-            if (rec.getSid() != RowRecord.sid)
-            {
-                offset += rec.serialize().length;
-            }
-            else
-            {
-                break;
-            }
-        }
-
-        // First Row Record
-        for (; recnum < records.size(); recnum++)
-        {
-            Record rec = ( Record ) records.get(recnum);
-
-            if (rec.getSid() == RowRecord.sid)
-            {
-                rownum++;
-                rowOffsets.add(offset);
-                if ((rownum % 32) == 0)
-                {
-
-                    // if this is the last rec in a  dbcell block
-                    // find the next row or last value record
-                    for (int rn = recnum; rn < records.size(); rn++)
-                    {
-                        rec = ( Record ) records.get(rn);
-                        if ((!rec.isInValueSection())
-                                || (rec.getSid() == RowRecord.sid))
-                        {
-
-                            // here is the next row or last value record
-                            records.add(rn,
-                                        createDBCell(offset, rowOffsets,
-                                                     index));
-                            recnum = rn;
-                            break;
-                        }
-                    }
-                }
-                else
-                {
-                }
-            }
-            if (!rec.isInValueSection())
-            {
-                records.add(recnum, createDBCell(offset, rowOffsets, index));
-                break;
-            }
-            offset += rec.serialize().length;
-        }
-    }
-
     public int getFirstRow() {
         return rows.getFirstRowNum();
     }
@@ -1455,41 +1372,6 @@ public class Sheet implements Model
         return rows.getLastRowNum();
     }
 
-
-    /** not currently used */
-
-    private DBCellRecord createDBCell(int offset, IntList rowoffsets,
-                                      IndexRecord index)
-    {
-        DBCellRecord rec = new DBCellRecord();
-
-        rec.setRowOffset(offset - rowoffsets.get(0));
-
-        // test hack
-        rec.addCellOffset(( short ) 0x0);
-
-        // end test hack
-        addDbCellToIndex(offset, index);
-        return rec;
-    }
-
-    /** not currently used */
-
-    private void addDbCellToIndex(int offset, IndexRecord index)
-    {
-        int numdbcells = index.getNumDbcells() + 1;
-
-        index.addDbcell(offset + preoffset);
-
-        // stupid but whenever we add an offset that causes everything to be shifted down 4
-        for (int k = 0; k < numdbcells; k++)
-        {
-            int dbval = index.getDbcellAt(k);
-
-            index.setDbcell(k, dbval + 4);
-        }
-    }
-
     /**
      * creates the BOF record
      * @see org.apache.poi.hssf.record.BOFRecord
@@ -2238,6 +2120,21 @@ public class Sheet implements Model
         {
             retval += (( Record ) records.get(k)).getRecordSize();
         }
+        //Add space for the IndexRecord
+        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
+        int startRetVal = retval;
+        retval += (8 * blocks);
+        for (Iterator itr = rows.getIterator(); itr.hasNext();) {
+          RowRecord row = (RowRecord)itr.next();
+          if (cells.rowHasCells(row.getRowNumber()))
+            retval += 2;
+        }
 
         return retval;
     }
index 6dd3679beac8e3da4d49c8c94ab8a112916b94bd..7d556231fdff5af93cc719157ad35d2fc791e424 100644 (file)
@@ -58,16 +58,18 @@ package org.apache.poi.hssf.record;
 import org.apache.poi.util.LittleEndian;
 
 /**
- * Title:        DBCell Record (Currently read only.  Not required.)
- * Description:  Used to find rows in blocks...TODO<P>
+ * Title:        DBCell Record
+ * Description:  Used by Excel and other MS apps to quickly find rows in the sheets.<P>
  * REFERENCE:  PG 299/440 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
  * @author Andrew C. Oliver (acoliver at apache dot org)
+ * @author Jason Height
  * @version 2.0-pre
  */
 
 public class DBCellRecord
     extends Record
 {
+    public final static int BLOCK_SIZE = 32;
     public final static short sid = 0xd7;
     private int               field_1_row_offset;
     private short[]           field_2_cell_offsets;
@@ -217,7 +219,7 @@ public class DBCellRecord
         LittleEndian.putInt(data, 4 + offset, getRowOffset());
         for (int k = 0; k < getNumCellOffsets(); k++)
         {
-            LittleEndian.putShort(data, 8 + k + offset, getCellOffsetAt(k));
+            LittleEndian.putShort(data, 8 + 2*k + offset, getCellOffsetAt(k));
         }
         return getRecordSize();
     }
@@ -227,6 +229,11 @@ public class DBCellRecord
         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);
+    }
+
     public short getSid()
     {
         return this.sid;
index 6af6ec3b912094d30dc6e604afe065c4f3098161..da1d2178d748bf8af1add41fdf4bbf2ae4e7f53b 100644 (file)
@@ -65,8 +65,8 @@ import org.apache.poi.util.LittleEndian;
 /**
  * Extended SST table info subrecord<P>
  * contains the elements of "info" in the SST's array field<P>
- * WE HAVE VERY LITTLE INFORMATION ON HOW TO IMPLEMENT THIS RECORD! (EXTSSST)<P>
  * @author Andrew C. Oliver (acoliver at apache dot org)
+ * @author Jason Height
  * @version 2.0-pre
  * @see org.apache.poi.hssf.record.ExtSSTRecord
  */
index e825987c3f67248502e3b69d2e0c60d0a7206e38..51ce742e242715cf35b1ca5fdfcae42863542a22 100644 (file)
@@ -61,13 +61,13 @@ import java.util.ArrayList;
 
 /**
  * Title:        Extended Static String Table<P>
- * Description:  I really don't understand this thing... its supposed to be "a hash
- *               table for optimizing external copy operations"  --
- *<P>
- *               This sounds like a job for Marc "BitMaster" Johnson aka the
- *               "Hawaiian Master Chef".<P>
+ * Description: This record is used for a quick lookup into the SST record. This
+ *              record breaks the SST table into a set of buckets. The offsets
+ *              to these buckets within the SST record are kept as well as the
+ *              position relative to the start of the SST record.
  * REFERENCE:  PG 313 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
  * @author Andrew C. Oliver (acoliver at apache dot org)
+ * @author Jason Height
  * @version 2.0-pre
  * @see org.apache.poi.hssf.record.ExtSSTInfoSubRecord
  */
@@ -75,8 +75,9 @@ import java.util.ArrayList;
 public class ExtSSTRecord
     extends Record
 {
+    private static final int DEFAULT_BUCKET_SIZE = 8;
     public final static short sid = 0xff;
-    private short             field_1_strings_per_bucket;
+    private short             field_1_strings_per_bucket = DEFAULT_BUCKET_SIZE;
     private ArrayList         field_2_sst_info;
 
 
@@ -120,12 +121,11 @@ public class ExtSSTRecord
         }
     }
 
-    // this probably doesn't work but we don't really care at this point
     protected void fillFields(byte [] data, short size, int offset)
     {
         field_2_sst_info           = new ArrayList();
         field_1_strings_per_bucket = LittleEndian.getShort(data, 0 + offset);
-        for (int k = 2; k < ((data.length - offset) - size); k += 8)
+        for (int k = 2; k < (size-offset); k += 8)
         {
             byte[] tempdata = new byte[ 8 + offset ];
 
@@ -196,16 +196,16 @@ public class ExtSSTRecord
 
         for (int k = 0; k < getNumInfoRecords(); k++)
         {
-            System.arraycopy(getInfoRecordAt(k).serialize(), 0, data,
-                             pos + offset, 8);
-            pos += getInfoRecordAt(k).getRecordSize();
+          ExtSSTInfoSubRecord rec = getInfoRecordAt(k);
+          pos += rec.serialize(pos + offset, data);
         }
-        return getRecordSize();
+
+        return pos;
     }
 
     public int getRecordSize()
     {
-        return 4 + 2 + field_2_sst_info.size() * 8;
+        return 6+8*getNumInfoRecords();
     }
 
     public short getSid()
index 836e07e09234f85fe863881c79e5f8e74c9eac2c..e38382249f73d7626e3194f741f37cd5afeb9d31 100644 (file)
@@ -222,6 +222,13 @@ public class IndexRecord
         return 20 + (getNumDbcells() * 4);
     }
 
+    /** Returns the size of an INdexRecord when it needs to index the specified number of blocks
+     *
+     */
+    public static int getRecordSizeForBlockCount(int blockCount) {
+      return 20 + (4 * blockCount);
+    }
+
     public short getSid()
     {
         return this.sid;
index dcf4e50b931b64044e68c247a7d418d75b2ad72a..9d140c516431d0ddace9873047558af9643984ec 100644 (file)
@@ -249,7 +249,6 @@ class SSTDeserializer
      */
     static public void addToStringTable( BinaryTree strings, Integer integer, UnicodeString string )
     {
-
         if ( string.isRichText() )
             string.setOptionFlags( (byte) ( string.getOptionFlags() & ( ~8 ) ) );
         if ( string.isExtendedText() )
index 9cd941121d934546b52d9204f9eaacc9ee21f4c1..32c3842abd41eed8740b8928a2d9edfd587487c2 100644 (file)
@@ -586,7 +586,10 @@ public class SSTRecord
      */
     public int calcExtSSTRecordSize()
     {
-        return 4 + 2 + ((field_3_strings.size() / SSTSerializer.DEFAULT_BUCKET_SIZE) + 1) * 8;
+        int infoRecs = (field_3_strings.size() / SSTSerializer.DEFAULT_BUCKET_SIZE);
+        if ((field_3_strings.size() % SSTSerializer.DEFAULT_BUCKET_SIZE) != 0)
+          infoRecs ++;
+        return 4 + 2 + (infoRecs * 8);
     }
 }
 
index 69e7af87d573b379b2ecf0c5d5e190decf33d880..905770b2ce509506f6912315d28aa830c5130b3f 100644 (file)
@@ -93,8 +93,11 @@ class SSTSerializer
         this.numUniqueStrings = numUniqueStrings;
         this.sstRecordHeader = new SSTRecordHeader( numStrings, numUniqueStrings );
 
-        this.bucketAbsoluteOffsets = new int[strings.size()/DEFAULT_BUCKET_SIZE+1];
-        this.bucketRelativeOffsets = new int[strings.size()/DEFAULT_BUCKET_SIZE+1];
+        int infoRecs = (strings.size() / SSTSerializer.DEFAULT_BUCKET_SIZE);
+        if ((strings.size() % SSTSerializer.DEFAULT_BUCKET_SIZE) != 0)
+          infoRecs ++;
+        this.bucketAbsoluteOffsets = new int[infoRecs];
+        this.bucketRelativeOffsets = new int[infoRecs];
     }
 
     /**
index 09587af8112b3ff6adf646f7109e33b0c6a0a168..1bd27c941d5a61c3143cd05cee863d2f688199ec 100644 (file)
@@ -57,6 +57,7 @@ package org.apache.poi.hssf.record.aggregates;
 
 import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RowRecord;
+import org.apache.poi.hssf.record.DBCellRecord;
 import org.apache.poi.hssf.record.UnknownRecord;
 
 import java.util.Map;
@@ -169,6 +170,86 @@ public class RowRecordsAggregate
         return k;
     }
 
+    /** Returns the number of row blocks.
+     * <p/>The row blocks are goupings of rows that contain the DBCell record
+     * after them
+     */
+    public int getRowBlockCount() {
+      int size = records.size()/DBCellRecord.BLOCK_SIZE;
+      if ((records.size() % DBCellRecord.BLOCK_SIZE) != 0)
+          size++;
+      return size;
+    }
+
+    public int getRowBlockSize(int block) {
+      return 20 * getRowCountForBlock(block);
+    }
+
+    /** Returns the number of physical rows within a block*/
+    public int getRowCountForBlock(int block) {
+      int startIndex = block * DBCellRecord.BLOCK_SIZE;
+      int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1;
+      if (endIndex >= records.size())
+        endIndex = records.size()-1;
+
+      return endIndex-startIndex+1;
+    }
+
+    /** Returns the physical row number of the first row in a block*/
+    public int getStartRowNumberForBlock(int block) {
+      //JMH Damn! I would like to directly index a record in the map rather than
+      //iterating through it.
+      int startIndex = block * DBCellRecord.BLOCK_SIZE;
+      Iterator rowIter = records.values().iterator();
+      RowRecord row = null;
+      //Position the iterator at the start of the block
+      for (int i=0; i<=startIndex;i++) {
+        row = (RowRecord)rowIter.next();
+      }
+
+      return row.getRowNumber();
+    }
+
+    /** Returns the physical row number of the end row in a block*/
+    public int getEndRowNumberForBlock(int block) {
+      //JMH Damn! I would like to directly index a record in the map rather than
+      //iterating through it.
+      int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1;
+      if (endIndex >= records.size())
+        endIndex = records.size()-1;
+
+      Iterator rowIter = records.values().iterator();
+      RowRecord row = null;
+      for (int i=0; i<=endIndex;i++) {
+        row = (RowRecord)rowIter.next();
+      }
+      return row.getRowNumber();
+    }
+
+
+    /** Serializes a block of the rows */
+    private int serializeRowBlock(final int block, final int offset, byte[] data) {
+      final int startIndex = block*DBCellRecord.BLOCK_SIZE;
+      final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
+
+      Iterator rowIterator = records.values().iterator();
+      int pos = offset;
+
+      //JMH TBD create an iterator that can start at a specific index.
+      int i=0;
+      for (;i<startIndex;i++)
+        rowIterator.next();
+      while(rowIterator.hasNext() && (i++ < endIndex)) {
+        RowRecord row = (RowRecord)rowIterator.next();
+        pos += row.serialize(pos, data);
+      }
+      return pos - offset;
+    }
+
+    public int serialize(int offset, byte [] data) {
+      throw new RuntimeException("The serialize method that passes in cells should be used");
+    }
+
     /**
      * called by the class that is responsible for writing this sucker.
      * Subclasses should implement this so that their data is passed back in a
@@ -179,14 +260,38 @@ public class RowRecordsAggregate
      * @return number of bytes written
      */
 
-    public int serialize(int offset, byte [] data)
+    public int serialize(int offset, byte [] data, ValueRecordsAggregate cells)
     {
         Iterator itr = records.values().iterator();
         int      pos = offset;
 
-        while (itr.hasNext())
-        {
-            pos += (( Record ) itr.next()).serialize(pos, data);
+        //DBCells are serialized before row records.
+        final int blockCount = getRowBlockCount();
+        for (int block=0;block<blockCount;block++) {
+          //Serialize a block of rows.
+          //Hold onto the position of the first row in the block
+          final int rowStartPos = pos;
+          //Hold onto the size of this block that was serialized
+          final int rowBlockSize = serializeRowBlock(block, pos, data);
+          pos += rowBlockSize;
+          //Serialize a block of cells for those rows
+          final int startRowNumber = getStartRowNumberForBlock(block);
+          final int endRowNumber = getEndRowNumberForBlock(block);
+          DBCellRecord cellRecord = new DBCellRecord();
+          //Note: Cell references start from the second row...
+          int cellRefOffset = (rowBlockSize-20);
+          for (int row=startRowNumber;row<=endRowNumber;row++) {
+            if (cells.rowHasCells(row)) {
+              final int rowCellSize = cells.serializeCellRow(row, pos, data);
+              pos += rowCellSize;
+              //Add the offset to the first cell for the row into the DBCellRecord.
+              cellRecord.addCellOffset((short)cellRefOffset);
+              cellRefOffset = rowCellSize;
+            }
+          }
+          //Calculate Offset from the start of a DBCellRecord to the first Row
+          cellRecord.setRowOffset(pos - rowStartPos);
+          pos += cellRecord.serialize(pos, data);
         }
         return pos - offset;
     }
index 7a3601c00aa110a0cee1120aa7938357eed08842..e16d3951068635c626c5ad0f3e3d9233f188a8dc 100644 (file)
@@ -115,22 +115,7 @@ public class ValueRecordsAggregate
 
     public int serialize(int offset, byte [] data)
     {
-        //throw new RuntimeException("Not Implemented serialize");
-        int      pos = offset;
-        Iterator irecs = getIterator();
-
-        while (irecs.hasNext()) {
-                pos += (( Record ) irecs.next()).serialize(pos,data);
-        }
-
-/*        Iterator itr = records.values().iterator();
-        int      pos = offset;
-
-        while (itr.hasNext())
-        {
-            pos += (( Record ) itr.next()).serialize(pos, data);
-        }*/
-        return pos - offset;
+        throw new RuntimeException("This method shouldnt be called. ValueRecordsAggregate.serializeCellRow() should be called from RowRecordsAggregate.");
     }
 
     public ValueRecordsAggregate() {
@@ -147,6 +132,42 @@ public class ValueRecordsAggregate
       return new VRAIterator(this);
     }
 
+    /** Tallies a count of the size of the cell records
+     *  that are attached to the rows in the range specified.
+     */
+    public int getRowCellBlockSize(int startRow, int endRow) {
+      Iterator cellRec = new VRAIterator(this, startRow, endRow);;
+      int size = 0;
+      while (cellRec.hasNext()) {
+        CellValueRecordInterface cell = (CellValueRecordInterface)cellRec.next();
+        int row = cell.getRow();
+        if ((row >=startRow) && (row <= endRow))
+          size += ((Record)cell).getRecordSize();
+      }
+      return size;
+    }
+
+    /** Returns true if the row has cells attached to it */
+    public boolean rowHasCells(int row) {
+      IntList ctRow = (IntList) celltype.get(row);
+      return ((ctRow != null) && (ctRow.size() > 0));
+    }
+
+    /** Serializes the cells that are allocated to a certain row range*/
+    public int serializeCellRow(final int row, int offset, byte [] data)
+    {
+        Iterator itr = new VRAIterator(this, row);
+        int      pos = offset;
+
+        while (itr.hasNext())
+        {
+            CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
+            pos += (( Record ) cell).serialize(pos, data);
+        }
+        return pos - offset;
+    }
+
+
 
     public int construct(int offset, List records)
     {
@@ -512,29 +533,32 @@ public class ValueRecordsAggregate
 class VRAIterator implements Iterator {
     private boolean hasNext;
     private ValueRecordsAggregate vra;
-    int popindex;
-    int row;
-    int rowlimit;
-    int col;
+    private int popindex;
+    private int row;
+    private int rowlimit;
+    private int col;
     CellValueRecordInterface current = null;
     CellValueRecordInterface next    = null;
 
     public VRAIterator(ValueRecordsAggregate vra) {
+      this(vra, 0, -1);
+    }
+
+    public VRAIterator(ValueRecordsAggregate vra, int row) {
+        this(vra, row, row);
+    }
+
+    public VRAIterator(ValueRecordsAggregate vra, int startRow, int endRow) {
         this.vra = vra;
-        this.rowlimit = -1;
-        popindex = 0;
+        this.row = startRow;
+        this.rowlimit = endRow;
+        this.popindex = vra.populatedRows.indexOf(row);
         if (vra.getPhysicalNumberOfCells() > 0) {
-            hasNext = true;
             next = findNextCell(null);
+            hasNext = (next != null);
         }
     }
 
-    public VRAIterator(ValueRecordsAggregate vra, int row) {
-        this(vra);
-        rowlimit = row;
-        this.row = row;
-        this.popindex = vra.populatedRows.indexOf(row);
-    }
 
     public boolean hasNext() {
         return hasNext;
@@ -575,7 +599,7 @@ class VRAIterator implements Iterator {
             rowNum = vra.populatedRows.get(popindex);
             ctRow = (IntList)vra.celltype.get(rowNum);
             if (ctRow.size() == 0) {
-                if (rowlimit == -1) {
+                if ((rowlimit == -1)||(rowNum<=rowlimit)) {
                     popindex++;
                 } else {
                     this.hasNext = false;
@@ -592,8 +616,11 @@ class VRAIterator implements Iterator {
             colNum = newCol;
             if (colNum == -1) {                          //end of row, forward one row
                 popindex++;
-                if (popindex < vra.populatedRows.size() && rowlimit == -1) {
+                if (popindex < vra.populatedRows.size() && ((rowlimit == -1)||(rowNum<=rowlimit))) {
                     rowNum = vra.populatedRows.get(popindex);
+                    //Return null if the row is out of range
+                    if ((rowlimit != -1) &&( rowNum > rowlimit))
+                      return null;
                 } else {
                     return null;
                 }