Reapplied DBCell etc etc patch to head after it had been clobbered during the move from the rel_2_branch to head.
Refixes bug 9576 git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353605 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
49e1a3d294
commit
f5b0a702a7
@ -46,7 +46,7 @@ import java.util.List;
|
|||||||
* @author Andrew C. Oliver (acoliver at apache dot org)
|
* @author Andrew C. Oliver (acoliver at apache dot org)
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
* @author Shawn Laubach (slaubach at apache dot org) Gridlines, Headers, Footers, and PrintSetup
|
* @author Shawn Laubach (slaubach at apache dot org) Gridlines, Headers, Footers, and PrintSetup
|
||||||
* @author Jason Height (jheight at chariot dot net dot au) Clone support
|
* @author Jason Height (jheight at chariot dot net dot au) Clone support. DBCell & Index Record writing support
|
||||||
* @author Brian Sanders (kestrel at burdell dot org) Active Cell support
|
* @author Brian Sanders (kestrel at burdell dot org) Active Cell support
|
||||||
*
|
*
|
||||||
* @see org.apache.poi.hssf.model.Workbook
|
* @see org.apache.poi.hssf.model.Workbook
|
||||||
@ -272,6 +272,15 @@ public class Sheet implements Model
|
|||||||
{
|
{
|
||||||
retval.windowTwo = (WindowTwoRecord) rec;
|
retval.windowTwo = (WindowTwoRecord) rec;
|
||||||
}
|
}
|
||||||
|
else if ( rec.getSid() == DBCellRecord.sid )
|
||||||
|
{
|
||||||
|
rec = null;
|
||||||
|
}
|
||||||
|
else if ( rec.getSid() == IndexRecord.sid )
|
||||||
|
{
|
||||||
|
rec = null;
|
||||||
|
}
|
||||||
|
|
||||||
else if ( rec.getSid() == ProtectRecord.sid )
|
else if ( rec.getSid() == ProtectRecord.sid )
|
||||||
{
|
{
|
||||||
retval.protect = (ProtectRecord) rec;
|
retval.protect = (ProtectRecord) rec;
|
||||||
@ -719,51 +728,6 @@ public class Sheet implements Model
|
|||||||
return preoffset;
|
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()
|
|
||||||
{
|
|
||||||
if (log.check( POILogger.DEBUG ))
|
|
||||||
log.log(POILogger.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;
|
|
||||||
// POILogger.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;
|
|
||||||
}
|
|
||||||
if (log.check( POILogger.DEBUG ))
|
|
||||||
log.log(POILogger.DEBUG, "Sheet.serialize returning " + retval);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes all records in the sheet into one big byte array. Use this to write
|
* Serializes all records in the sheet into one big byte array. Use this to write
|
||||||
* the sheet out.
|
* the sheet out.
|
||||||
@ -778,47 +742,75 @@ public class Sheet implements Model
|
|||||||
if (log.check( POILogger.DEBUG ))
|
if (log.check( POILogger.DEBUG ))
|
||||||
log.log(POILogger.DEBUG, "Sheet.serialize using offsets");
|
log.log(POILogger.DEBUG, "Sheet.serialize using offsets");
|
||||||
|
|
||||||
// addDBCellRecords();
|
int pos = offset;
|
||||||
// ArrayList bytes = new ArrayList(4096);
|
boolean haveSerializedIndex = false;
|
||||||
// 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;
|
|
||||||
// POILogger.DEBUG((new StringBuffer("arraysize=")).append(arraysize)
|
|
||||||
// .toString());
|
|
||||||
// }
|
|
||||||
for (int k = 0; k < records.size(); k++)
|
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));
|
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;
|
||||||
|
}
|
||||||
|
//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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//// 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.");
|
|
||||||
// }
|
|
||||||
|
|
||||||
pos += record.serialize(pos + offset, data ); // rec.length;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if (log.check( POILogger.DEBUG ))
|
if (log.check( POILogger.DEBUG ))
|
||||||
log.log(POILogger.DEBUG, "Sheet.serialize returning ");
|
log.log(POILogger.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a row record. (does not add it to the records contained in this sheet)
|
* Create a row record. (does not add it to the records contained in this sheet)
|
||||||
@ -1378,118 +1370,6 @@ public class Sheet implements Model
|
|||||||
// return null;
|
// return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 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
|
* creates the BOF record
|
||||||
* @see org.apache.poi.hssf.record.BOFRecord
|
* @see org.apache.poi.hssf.record.BOFRecord
|
||||||
@ -2148,6 +2028,21 @@ public class Sheet implements Model
|
|||||||
{
|
{
|
||||||
retval += (( Record ) records.get(k)).getRecordSize();
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,16 +21,18 @@ package org.apache.poi.hssf.record;
|
|||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title: DBCell Record (Currently read only. Not required.)
|
* Title: DBCell Record
|
||||||
* Description: Used to find rows in blocks...TODO<P>
|
* 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>
|
* 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 Andrew C. Oliver (acoliver at apache dot org)
|
||||||
|
* @author Jason Height
|
||||||
* @version 2.0-pre
|
* @version 2.0-pre
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class DBCellRecord
|
public class DBCellRecord
|
||||||
extends Record
|
extends Record
|
||||||
{
|
{
|
||||||
|
public final static int BLOCK_SIZE = 32;
|
||||||
public final static short sid = 0xd7;
|
public final static short sid = 0xd7;
|
||||||
private int field_1_row_offset;
|
private int field_1_row_offset;
|
||||||
private short[] field_2_cell_offsets;
|
private short[] field_2_cell_offsets;
|
||||||
@ -180,7 +182,7 @@ public class DBCellRecord
|
|||||||
LittleEndian.putInt(data, 4 + offset, getRowOffset());
|
LittleEndian.putInt(data, 4 + offset, getRowOffset());
|
||||||
for (int k = 0; k < getNumCellOffsets(); k++)
|
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();
|
return getRecordSize();
|
||||||
}
|
}
|
||||||
@ -189,6 +191,11 @@ public class DBCellRecord
|
|||||||
{
|
{
|
||||||
return 8 + (getNumCellOffsets() * 2);
|
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()
|
public short getSid()
|
||||||
{
|
{
|
||||||
|
@ -184,6 +184,13 @@ public class IndexRecord
|
|||||||
{
|
{
|
||||||
return 20 + (getNumDbcells() * 4);
|
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()
|
public short getSid()
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.aggregates;
|
package org.apache.poi.hssf.record.aggregates;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.DBCellRecord;
|
||||||
import org.apache.poi.hssf.record.Record;
|
import org.apache.poi.hssf.record.Record;
|
||||||
import org.apache.poi.hssf.record.RowRecord;
|
import org.apache.poi.hssf.record.RowRecord;
|
||||||
|
|
||||||
@ -94,30 +95,90 @@ public class RowRecordsAggregate
|
|||||||
{
|
{
|
||||||
return lastrow;
|
return lastrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/** Returns the number of row blocks.
|
||||||
* No need to go through all the records as we're just collecting RowRecords
|
* <p/>The row blocks are goupings of rows that contain the DBCell record
|
||||||
|
* after them
|
||||||
public int construct(int offset, List records)
|
*/
|
||||||
{
|
public int getRowBlockCount() {
|
||||||
int k = 0;
|
int size = records.size()/DBCellRecord.BLOCK_SIZE;
|
||||||
|
if ((records.size() % DBCellRecord.BLOCK_SIZE) != 0)
|
||||||
for (k = offset; k < records.size(); k++)
|
size++;
|
||||||
{
|
return size;
|
||||||
Record rec = ( Record ) records.get(k);
|
|
||||||
|
|
||||||
if (!rec.isInValueSection() && !(rec instanceof UnknownRecord))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (rec.getSid() == RowRecord.sid)
|
|
||||||
{
|
|
||||||
insertRow(( RowRecord ) rec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return k;
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
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 Given that we basically iterate through the rows in order,
|
||||||
|
//For a performance improvement, it would be better to return an instance of
|
||||||
|
//an iterator and use that instance throughout, rather than recreating one and
|
||||||
|
//having to move it to the right position.
|
||||||
|
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) {
|
||||||
|
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 Given that we basically iterate through the rows in order,
|
||||||
|
//For a performance improvement, it would be better to return an instance of
|
||||||
|
//an iterator and use that instance throughout, rather than recreating one and
|
||||||
|
//having to move it to the right position.
|
||||||
|
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.
|
* called by the class that is responsible for writing this sucker.
|
||||||
@ -129,14 +190,38 @@ public class RowRecordsAggregate
|
|||||||
* @return number of bytes written
|
* @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;
|
||||||
int pos = offset;
|
|
||||||
|
//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);
|
||||||
|
|
||||||
while (itr.hasNext())
|
|
||||||
{
|
|
||||||
pos += (( Record ) itr.next()).serialize(pos, data);
|
|
||||||
}
|
}
|
||||||
return pos - offset;
|
return pos - offset;
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,10 @@ import org.apache.poi.hssf.record.*;
|
|||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.SortedMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Aggregate value records together. Things are easier to handle that way.
|
* Aggregate value records together. Things are easier to handle that way.
|
||||||
@ -40,8 +42,114 @@ public class ValueRecordsAggregate
|
|||||||
int firstcell = -1;
|
int firstcell = -1;
|
||||||
int lastcell = -1;
|
int lastcell = -1;
|
||||||
TreeMap records = null;
|
TreeMap records = null;
|
||||||
// int size = 0;
|
|
||||||
|
|
||||||
|
/** This class is used to find a row in the TreeMap.
|
||||||
|
*
|
||||||
|
* This instance of which is used by the rowHasCells method as the key.
|
||||||
|
*/
|
||||||
|
private class RowComparator implements CellValueRecordInterface, Comparable {
|
||||||
|
private int row;
|
||||||
|
|
||||||
|
public void setRow(int row) {
|
||||||
|
this.row = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(Object obj) {
|
||||||
|
CellValueRecordInterface cell = (CellValueRecordInterface) obj;
|
||||||
|
|
||||||
|
if (row == cell.getRow()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (row < cell.getRow()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (row > cell.getRow()){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
public int getRow() { return row;}
|
||||||
|
public short getColumn() { return 0;}
|
||||||
|
public void setColumn(short col){}
|
||||||
|
public void setXFIndex(short xf){}
|
||||||
|
public short getXFIndex(){return 0;}
|
||||||
|
public boolean isBefore(CellValueRecordInterface i){ return false; }
|
||||||
|
public boolean isAfter(CellValueRecordInterface i){ return false; }
|
||||||
|
public boolean isEqual(CellValueRecordInterface i){ return false; }
|
||||||
|
public Object clone(){ return null;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates the cell records that exist between the startRow and endRow (inclusive).
|
||||||
|
*
|
||||||
|
* User must ensure that hasNext & next are called insequence for correct
|
||||||
|
* operation. Could fix, but since this is only used internally to the
|
||||||
|
* ValueRecordsAggregate class there doesnt seem much point.
|
||||||
|
*/
|
||||||
|
private class RowCellIterator implements Iterator {
|
||||||
|
private int startRow;
|
||||||
|
private int endRow;
|
||||||
|
private Iterator internalIterator;
|
||||||
|
private CellValueRecordInterface atCell;
|
||||||
|
|
||||||
|
public class RowCellComparator extends RowComparator {
|
||||||
|
public int compareTo(Object obj) {
|
||||||
|
CellValueRecordInterface cell = (CellValueRecordInterface) obj;
|
||||||
|
|
||||||
|
if (getRow() == cell.getRow() && cell.getColumn() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (getRow() < cell.getRow()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (getRow() > cell.getRow()){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (cell.getColumn() > 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (cell.getColumn() < 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RowCellComparator rowCellCompare;
|
||||||
|
|
||||||
|
|
||||||
|
public RowCellIterator(int startRow, int endRow) {
|
||||||
|
this.startRow = startRow;
|
||||||
|
this.endRow = endRow;
|
||||||
|
rowCellCompare = new RowCellComparator();
|
||||||
|
rowCellCompare.setRow(startRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
if (internalIterator == null) {
|
||||||
|
internalIterator = records.tailMap(rowCellCompare).values().iterator();
|
||||||
|
}
|
||||||
|
if (internalIterator.hasNext()) {
|
||||||
|
atCell = (CellValueRecordInterface) internalIterator.next();
|
||||||
|
return (atCell.getRow() <= endRow);
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object next() {
|
||||||
|
return atCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
//Do Nothing (Not called)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Only need a single instance of this class, but the row fields
|
||||||
|
//will probably change each use. Instance is only used in the rowHasCells method.
|
||||||
|
public final RowComparator compareRow = new RowComparator();
|
||||||
|
|
||||||
/** Creates a new instance of ValueRecordsAggregate */
|
/** Creates a new instance of ValueRecordsAggregate */
|
||||||
|
|
||||||
public ValueRecordsAggregate()
|
public ValueRecordsAggregate()
|
||||||
@ -51,17 +159,6 @@ public class ValueRecordsAggregate
|
|||||||
|
|
||||||
public void insertCell(CellValueRecordInterface cell)
|
public void insertCell(CellValueRecordInterface cell)
|
||||||
{
|
{
|
||||||
/* if (records.get(cell) == null)
|
|
||||||
{
|
|
||||||
size += (( Record ) cell).getRecordSize();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size += (( Record ) cell).getRecordSize()
|
|
||||||
- (( Record ) records.get(cell)).getRecordSize();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// XYLocator xy = new XYLocator(cell.getRow(), cell.getColumn());
|
|
||||||
Object o = records.put(cell, cell);
|
Object o = records.put(cell, cell);
|
||||||
|
|
||||||
if ((cell.getColumn() < firstcell) || (firstcell == -1))
|
if ((cell.getColumn() < firstcell) || (firstcell == -1))
|
||||||
@ -76,9 +173,6 @@ public class ValueRecordsAggregate
|
|||||||
|
|
||||||
public void removeCell(CellValueRecordInterface cell)
|
public void removeCell(CellValueRecordInterface cell)
|
||||||
{
|
{
|
||||||
// size -= (( Record ) cell).getRecordSize();
|
|
||||||
|
|
||||||
// XYLocator xy = new XYLocator(cell.getRow(), cell.getColumn());
|
|
||||||
records.remove(cell);
|
records.remove(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,15 +239,49 @@ public class ValueRecordsAggregate
|
|||||||
|
|
||||||
public int serialize(int offset, byte [] data)
|
public int serialize(int offset, byte [] data)
|
||||||
{
|
{
|
||||||
Iterator itr = records.values().iterator();
|
throw new RuntimeException("This method shouldnt be called. ValueRecordsAggregate.serializeCellRow() should be called from RowRecordsAggregate.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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) {
|
||||||
|
RowCellIterator itr = new RowCellIterator(startRow, endRow);
|
||||||
|
int size = 0;
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
|
||||||
|
int row = cell.getRow();
|
||||||
|
if (row > endRow)
|
||||||
|
break;
|
||||||
|
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) {
|
||||||
|
compareRow.setRow(row);
|
||||||
|
return records.containsKey(compareRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Serializes the cells that are allocated to a certain row range*/
|
||||||
|
public int serializeCellRow(final int row, int offset, byte [] data)
|
||||||
|
{
|
||||||
|
RowCellIterator itr = new RowCellIterator(row, row);
|
||||||
int pos = offset;
|
int pos = offset;
|
||||||
|
|
||||||
while (itr.hasNext())
|
while (itr.hasNext())
|
||||||
{
|
{
|
||||||
pos += (( Record ) itr.next()).serialize(pos, data);
|
CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
|
||||||
|
if (cell.getRow() != row)
|
||||||
|
break;
|
||||||
|
pos += (( Record ) cell).serialize(pos, data);
|
||||||
}
|
}
|
||||||
return pos - offset;
|
return pos - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called by the constructor, should set class level fields. Should throw
|
* called by the constructor, should set class level fields. Should throw
|
||||||
* runtime exception for bad/icomplete data.
|
* runtime exception for bad/icomplete data.
|
||||||
@ -197,7 +325,6 @@ public class ValueRecordsAggregate
|
|||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
// return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator getIterator()
|
public Iterator getIterator()
|
||||||
@ -214,59 +341,4 @@ public class ValueRecordsAggregate
|
|||||||
}
|
}
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* class XYLocator implements Comparable {
|
|
||||||
* private int row = 0;
|
|
||||||
* private int col = 0;
|
|
||||||
* public XYLocator(int row, int col) {
|
|
||||||
* this.row = row;
|
|
||||||
* this.col = col;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public int getRow() {
|
|
||||||
* return row;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public int getCol() {
|
|
||||||
* return col;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public int compareTo(Object obj) {
|
|
||||||
* XYLocator loc = (XYLocator)obj;
|
|
||||||
*
|
|
||||||
* if (this.getRow() == loc.getRow() &&
|
|
||||||
* this.getCol() == loc.getCol() )
|
|
||||||
* return 0;
|
|
||||||
*
|
|
||||||
* if (this.getRow() < loc.getRow())
|
|
||||||
* return -1;
|
|
||||||
*
|
|
||||||
* if (this.getRow() > loc.getRow())
|
|
||||||
* return 1;
|
|
||||||
*
|
|
||||||
* if (this.getCol() < loc.getCol())
|
|
||||||
* return -1;
|
|
||||||
*
|
|
||||||
* if (this.getCol() > loc.getCol())
|
|
||||||
* return 1;
|
|
||||||
*
|
|
||||||
* return -1;
|
|
||||||
*
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public boolean equals(Object obj) {
|
|
||||||
* if (!(obj instanceof XYLocator)) return false;
|
|
||||||
*
|
|
||||||
* XYLocator loc = (XYLocator)obj;
|
|
||||||
* if (this.getRow() == loc.getRow()
|
|
||||||
* &&
|
|
||||||
* this.getCol() == loc.getCol()
|
|
||||||
* ) return true;
|
|
||||||
* return false;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* }
|
|
||||||
*/
|
|
Loading…
Reference in New Issue
Block a user