mirror of https://github.com/apache/poi.git
changed serialize method on Sheet to visitContainedRecords to simplify serialization logic and also allow test code to inspect generated sheet records more directly
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@690626 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7039455b72
commit
e4787b1a21
|
@ -68,6 +68,7 @@ import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
|
||||||
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
||||||
import org.apache.poi.hssf.record.aggregates.RecordAggregate;
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate;
|
||||||
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate.PositionTrackingVisitor;
|
||||||
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
||||||
import org.apache.poi.hssf.util.CellRangeAddress;
|
import org.apache.poi.hssf.util.CellRangeAddress;
|
||||||
import org.apache.poi.hssf.util.PaneInformation;
|
import org.apache.poi.hssf.util.PaneInformation;
|
||||||
|
@ -105,7 +106,6 @@ public final class Sheet implements Model {
|
||||||
private static POILogger log = POILogFactory.getLogger(Sheet.class);
|
private static POILogger log = POILogFactory.getLogger(Sheet.class);
|
||||||
|
|
||||||
protected ArrayList records = null;
|
protected ArrayList records = null;
|
||||||
int preoffset = 0; // offset of the sheet in a new file
|
|
||||||
protected int dimsloc = -1; // TODO - remove dimsloc
|
protected int dimsloc = -1; // TODO - remove dimsloc
|
||||||
protected PrintGridlinesRecord printGridlines = null;
|
protected PrintGridlinesRecord printGridlines = null;
|
||||||
protected GridsetRecord gridset = null;
|
protected GridsetRecord gridset = null;
|
||||||
|
@ -148,7 +148,7 @@ public final class Sheet implements Model {
|
||||||
* @see #createSheet(List,int,int)
|
* @see #createSheet(List,int,int)
|
||||||
*/
|
*/
|
||||||
public Sheet() {
|
public Sheet() {
|
||||||
_mergedCellsTable = new MergedCellsTable();
|
_mergedCellsTable = new MergedCellsTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -245,12 +245,17 @@ public final class Sheet implements Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec.getSid() == MergeCellsRecord.sid) {
|
if (rec.getSid() == MergeCellsRecord.sid) {
|
||||||
// when the MergedCellsTable is found in the right place, we expect those records to be contiguous
|
// when the MergedCellsTable is found in the right place, we expect those records to be contiguous
|
||||||
RecordStream rs = new RecordStream(inRecs, k);
|
RecordStream rs = new RecordStream(inRecs, k);
|
||||||
retval._mergedCellsTable.read(rs);
|
retval._mergedCellsTable.read(rs);
|
||||||
k += rs.getCountRead()-1;
|
k += rs.getCountRead()-1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (rec.getSid() == UncalcedRecord.sid) {
|
||||||
|
// don't add UncalcedRecord to the list
|
||||||
|
retval._isUncalced = true; // this flag is enough
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (rec.getSid() == BOFRecord.sid)
|
if (rec.getSid() == BOFRecord.sid)
|
||||||
{
|
{
|
||||||
|
@ -269,9 +274,6 @@ public final class Sheet implements Model {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rec.getSid() == UncalcedRecord.sid) {
|
|
||||||
retval._isUncalced = true;
|
|
||||||
}
|
|
||||||
else if (rec.getSid() == DimensionsRecord.sid)
|
else if (rec.getSid() == DimensionsRecord.sid)
|
||||||
{
|
{
|
||||||
// Make a columns aggregate if one hasn't ready been created.
|
// Make a columns aggregate if one hasn't ready been created.
|
||||||
|
@ -585,61 +587,23 @@ public final class Sheet implements Model {
|
||||||
log.log(POILogger.DEBUG, "Sheet.setDimensions exiting");
|
log.log(POILogger.DEBUG, "Sheet.setDimensions exiting");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void visitContainedRecords(RecordVisitor rv, int offset) {
|
||||||
* Set the preoffset when using DBCELL records (currently unused) - this is
|
|
||||||
* the position of this sheet within the whole file.
|
|
||||||
*
|
|
||||||
* @param offset the offset of the sheet's BOF within the file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void setPreOffset(int offset)
|
PositionTrackingVisitor ptv = new PositionTrackingVisitor(rv, offset);
|
||||||
{
|
|
||||||
this.preoffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the preoffset when using DBCELL records (currently unused) - this is
|
|
||||||
* the position of this sheet within the whole file.
|
|
||||||
*
|
|
||||||
* @return offset the offset of the sheet's BOF within the file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int getPreOffset()
|
|
||||||
{
|
|
||||||
return preoffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes all records in the sheet into one big byte array. Use this to write
|
|
||||||
* the sheet out.
|
|
||||||
*
|
|
||||||
* @param offset to begin write at
|
|
||||||
* @param data array containing the binary representation of the records in this sheet
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int serialize(int offset, byte [] data)
|
|
||||||
{
|
|
||||||
if (log.check( POILogger.DEBUG ))
|
|
||||||
log.log(POILogger.DEBUG, "Sheet.serialize using offsets");
|
|
||||||
|
|
||||||
int pos = offset;
|
|
||||||
boolean haveSerializedIndex = false;
|
boolean haveSerializedIndex = false;
|
||||||
|
|
||||||
for (int k = 0; k < records.size(); k++)
|
for (int k = 0; k < records.size(); k++)
|
||||||
{
|
{
|
||||||
RecordBase record = (RecordBase) records.get(k);
|
RecordBase record = (RecordBase) records.get(k);
|
||||||
|
|
||||||
// Don't write out UncalcedRecord entries, as
|
if (record instanceof RecordAggregate) {
|
||||||
// we handle those specially just below
|
RecordAggregate agg = (RecordAggregate) record;
|
||||||
if (record instanceof UncalcedRecord) {
|
agg.visitContainedRecords(ptv);
|
||||||
continue;
|
} else {
|
||||||
|
ptv.visitRecord((Record) record);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once the rows have been found in the list of records, start
|
|
||||||
// writing out the blocked row information. This includes the DBCell references
|
|
||||||
pos += record.serialize(pos, data);
|
|
||||||
|
|
||||||
// If the BOF record was just serialized then add the IndexRecord
|
// If the BOF record was just serialized then add the IndexRecord
|
||||||
if (record instanceof BOFRecord) {
|
if (record instanceof BOFRecord) {
|
||||||
if (!haveSerializedIndex) {
|
if (!haveSerializedIndex) {
|
||||||
|
@ -649,50 +613,42 @@ public final class Sheet implements Model {
|
||||||
// If there are diagrams, they have their own BOFRecords,
|
// If there are diagrams, they have their own BOFRecords,
|
||||||
// and one shouldn't go in after that!
|
// and one shouldn't go in after that!
|
||||||
if (_isUncalced) {
|
if (_isUncalced) {
|
||||||
UncalcedRecord rec = new UncalcedRecord();
|
ptv.visitRecord(new UncalcedRecord());
|
||||||
pos += rec.serialize(pos, data);
|
|
||||||
}
|
}
|
||||||
//Can there be more than one BOF for a sheet? If not then we can
|
//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.
|
//remove this guard. So be safe it is left here.
|
||||||
if (_rowsAggregate != null) {
|
if (_rowsAggregate != null) {
|
||||||
pos += serializeIndexRecord(k, pos, data);
|
// find forward distance to first RowRecord
|
||||||
|
int initRecsSize = getSizeOfInitialSheetRecords(k);
|
||||||
|
int currentPos = ptv.getPosition();
|
||||||
|
ptv.visitRecord(_rowsAggregate.createIndexRecord(currentPos, initRecsSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (log.check( POILogger.DEBUG )) {
|
|
||||||
log.log(POILogger.DEBUG, "Sheet.serialize returning ");
|
|
||||||
}
|
|
||||||
return pos-offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param indexRecordOffset also happens to be the end of the BOF record
|
* 'initial sheet records' are between INDEX and the 'Row Blocks'
|
||||||
* @return the size of the serialized INDEX record
|
* @param bofRecordIndex index of record after which INDEX record is to be placed
|
||||||
|
* @return count of bytes from end of INDEX record to first ROW record.
|
||||||
*/
|
*/
|
||||||
private int serializeIndexRecord(int bofRecordIndex, int indexRecordOffset, byte[] data) {
|
private int getSizeOfInitialSheetRecords(int bofRecordIndex) {
|
||||||
|
|
||||||
// 'initial sheet records' are between INDEX and first ROW record.
|
int result = 0;
|
||||||
int sizeOfInitialSheetRecords = 0;
|
|
||||||
// start just after BOF record (INDEX is not present in this list)
|
// start just after BOF record (INDEX is not present in this list)
|
||||||
for (int j = bofRecordIndex + 1; j < records.size(); j++) {
|
for (int j = bofRecordIndex + 1; j < records.size(); j++) {
|
||||||
RecordBase tmpRec = ((RecordBase) records.get(j));
|
RecordBase tmpRec = (RecordBase) records.get(j);
|
||||||
if (tmpRec instanceof UncalcedRecord) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (tmpRec instanceof RowRecordsAggregate) {
|
if (tmpRec instanceof RowRecordsAggregate) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sizeOfInitialSheetRecords += tmpRec.getRecordSize();
|
result += tmpRec.getRecordSize();
|
||||||
}
|
}
|
||||||
if (_isUncalced) {
|
if (_isUncalced) {
|
||||||
sizeOfInitialSheetRecords += UncalcedRecord.getStaticRecordSize();
|
result += UncalcedRecord.getStaticRecordSize();
|
||||||
}
|
}
|
||||||
IndexRecord index = _rowsAggregate.createIndexRecord(indexRecordOffset, sizeOfInitialSheetRecords);
|
return result;
|
||||||
return index.serialize(indexRecordOffset, 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)
|
||||||
*/
|
*/
|
||||||
|
@ -1351,32 +1307,6 @@ public final class Sheet implements Model {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the serialized size of this sheet
|
|
||||||
*/
|
|
||||||
public int getSize() {
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
for ( int k = 0; k < records.size(); k++) {
|
|
||||||
RecordBase record = (RecordBase) 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 IndexRecord if needed
|
|
||||||
if (_rowsAggregate != null) {
|
|
||||||
// rowsAggregate knows how to make the index record
|
|
||||||
retval += IndexRecord.getRecordSizeForBlockCount(_rowsAggregate.getRowBlockCount());
|
|
||||||
}
|
|
||||||
// Add space for UncalcedRecord
|
|
||||||
if (_isUncalced) {
|
|
||||||
retval += UncalcedRecord.getStaticRecordSize();
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List getRecords()
|
public List getRecords()
|
||||||
{
|
{
|
||||||
return records;
|
return records;
|
||||||
|
|
|
@ -36,10 +36,16 @@ public abstract class RecordAggregate extends RecordBase {
|
||||||
protected final void fillFields(RecordInputStream in) {
|
protected final void fillFields(RecordInputStream in) {
|
||||||
throw new RuntimeException("Should not be called");
|
throw new RuntimeException("Should not be called");
|
||||||
}
|
}
|
||||||
public final short getSid() {
|
public final short getSid() {
|
||||||
throw new RuntimeException("Should not be called");
|
throw new RuntimeException("Should not be called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit each of the atomic BIFF records contained in this {@link RecordAggregate} in the order
|
||||||
|
* that they should be written to file. Implementors may or may not return the actual
|
||||||
|
* {@link Record}s being used to manage POI's internal implementation. Callers should not
|
||||||
|
* assume either way, and therefore only attempt to modify those {@link Record}s after cloning
|
||||||
|
*/
|
||||||
public abstract void visitContainedRecords(RecordVisitor rv);
|
public abstract void visitContainedRecords(RecordVisitor rv);
|
||||||
|
|
||||||
public final int serialize(int offset, byte[] data) {
|
public final int serialize(int offset, byte[] data) {
|
||||||
|
@ -94,4 +100,27 @@ public abstract class RecordAggregate extends RecordBase {
|
||||||
_totalSize += r.getRecordSize();
|
_totalSize += r.getRecordSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* A wrapper for {@link RecordVisitor} which accumulates the sizes of all
|
||||||
|
* records visited.
|
||||||
|
*/
|
||||||
|
public static final class PositionTrackingVisitor implements RecordVisitor {
|
||||||
|
private final RecordVisitor _rv;
|
||||||
|
private int _position;
|
||||||
|
|
||||||
|
public PositionTrackingVisitor(RecordVisitor rv, int initialPosition) {
|
||||||
|
_rv = rv;
|
||||||
|
_position = initialPosition;
|
||||||
|
}
|
||||||
|
public void visitRecord(Record r) {
|
||||||
|
_position += r.getRecordSize();
|
||||||
|
_rv.visitRecord(r);
|
||||||
|
}
|
||||||
|
public void setPosition(int position) {
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
public int getPosition() {
|
||||||
|
return _position;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ import org.apache.poi.hssf.record.RecordFactory;
|
||||||
import org.apache.poi.hssf.record.SSTRecord;
|
import org.apache.poi.hssf.record.SSTRecord;
|
||||||
import org.apache.poi.hssf.record.UnicodeString;
|
import org.apache.poi.hssf.record.UnicodeString;
|
||||||
import org.apache.poi.hssf.record.UnknownRecord;
|
import org.apache.poi.hssf.record.UnknownRecord;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
||||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||||
import org.apache.poi.hssf.record.formula.MemFuncPtg;
|
import org.apache.poi.hssf.record.formula.MemFuncPtg;
|
||||||
import org.apache.poi.hssf.record.formula.NameXPtg;
|
import org.apache.poi.hssf.record.formula.NameXPtg;
|
||||||
|
@ -1173,6 +1174,37 @@ public class HSSFWorkbook extends POIDocument
|
||||||
//poifs.writeFilesystem(stream);
|
//poifs.writeFilesystem(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Totals the sizes of all sheet records and eventually serializes them
|
||||||
|
*/
|
||||||
|
private static final class SheetRecordCollector implements RecordVisitor {
|
||||||
|
|
||||||
|
private List _list;
|
||||||
|
private int _totalSize;
|
||||||
|
|
||||||
|
public SheetRecordCollector() {
|
||||||
|
_totalSize = 0;
|
||||||
|
_list = new ArrayList(128);
|
||||||
|
}
|
||||||
|
public int getTotalSize() {
|
||||||
|
return _totalSize;
|
||||||
|
}
|
||||||
|
public void visitRecord(Record r) {
|
||||||
|
_list.add(r);
|
||||||
|
_totalSize+=r.getRecordSize();
|
||||||
|
}
|
||||||
|
public int serialize(int offset, byte[] data) {
|
||||||
|
int result = 0;
|
||||||
|
int nRecs = _list.size();
|
||||||
|
for(int i=0; i<nRecs; i++) {
|
||||||
|
Record rec = (Record)_list.get(i);
|
||||||
|
result += rec.serialize(offset + result, data);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method getBytes - get the bytes of just the HSSF portions of the XLS file.
|
* Method getBytes - get the bytes of just the HSSF portions of the XLS file.
|
||||||
* Use this to construct a POI POIFSFileSystem yourself.
|
* Use this to construct a POI POIFSFileSystem yourself.
|
||||||
|
@ -1184,9 +1216,7 @@ public class HSSFWorkbook extends POIDocument
|
||||||
* @see org.apache.poi.hssf.model.Workbook
|
* @see org.apache.poi.hssf.model.Workbook
|
||||||
* @see org.apache.poi.hssf.model.Sheet
|
* @see org.apache.poi.hssf.model.Sheet
|
||||||
*/
|
*/
|
||||||
|
public byte[] getBytes() {
|
||||||
public byte[] getBytes()
|
|
||||||
{
|
|
||||||
if (log.check( POILogger.DEBUG )) {
|
if (log.check( POILogger.DEBUG )) {
|
||||||
log.log(DEBUG, "HSSFWorkbook.getBytes()");
|
log.log(DEBUG, "HSSFWorkbook.getBytes()");
|
||||||
}
|
}
|
||||||
|
@ -1203,26 +1233,27 @@ public class HSSFWorkbook extends POIDocument
|
||||||
int totalsize = workbook.getSize();
|
int totalsize = workbook.getSize();
|
||||||
|
|
||||||
// pre-calculate all the sheet sizes and set BOF indexes
|
// pre-calculate all the sheet sizes and set BOF indexes
|
||||||
int[] estimatedSheetSizes = new int[nSheets];
|
SheetRecordCollector[] srCollectors = new SheetRecordCollector[nSheets];
|
||||||
for (int k = 0; k < nSheets; k++) {
|
for (int k = 0; k < nSheets; k++) {
|
||||||
workbook.setSheetBof(k, totalsize);
|
workbook.setSheetBof(k, totalsize);
|
||||||
int sheetSize = sheets[k].getSheet().getSize();
|
SheetRecordCollector src = new SheetRecordCollector();
|
||||||
estimatedSheetSizes[k] = sheetSize;
|
sheets[k].getSheet().visitContainedRecords(src, totalsize);
|
||||||
totalsize += sheetSize;
|
totalsize += src.getTotalSize();
|
||||||
|
srCollectors[k] = src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
byte[] retval = new byte[totalsize];
|
byte[] retval = new byte[totalsize];
|
||||||
int pos = workbook.serialize(0, retval);
|
int pos = workbook.serialize(0, retval);
|
||||||
|
|
||||||
for (int k = 0; k < nSheets; k++) {
|
for (int k = 0; k < nSheets; k++) {
|
||||||
int serializedSize = sheets[k].getSheet().serialize(pos, retval);
|
SheetRecordCollector src = srCollectors[k];
|
||||||
if (serializedSize != estimatedSheetSizes[k]) {
|
int serializedSize = src.serialize(pos, retval);
|
||||||
|
if (serializedSize != src.getTotalSize()) {
|
||||||
// Wrong offset values have been passed in the call to setSheetBof() above.
|
// Wrong offset values have been passed in the call to setSheetBof() above.
|
||||||
// For books with more than one sheet, this discrepancy would cause excel
|
// For books with more than one sheet, this discrepancy would cause excel
|
||||||
// to report errors and loose data while reading the workbook
|
// to report errors and loose data while reading the workbook
|
||||||
throw new IllegalStateException("Actual serialized sheet size (" + serializedSize
|
throw new IllegalStateException("Actual serialized sheet size (" + serializedSize
|
||||||
+ ") differs from pre-calculated size (" + estimatedSheetSizes[k]
|
+ ") differs from pre-calculated size (" + src.getTotalSize()
|
||||||
+ ") for sheet (" + k + ")");
|
+ ") for sheet (" + k + ")");
|
||||||
// TODO - add similar sanity check to ensure that Sheet.serializeIndexRecord() does not write mis-aligned offsets either
|
// TODO - add similar sanity check to ensure that Sheet.serializeIndexRecord() does not write mis-aligned offsets either
|
||||||
}
|
}
|
||||||
|
@ -1664,8 +1695,8 @@ public class HSSFWorkbook extends POIDocument
|
||||||
* Note - This method should only used by POI internally.
|
* Note - This method should only used by POI internally.
|
||||||
* It may get deleted or change definition in future POI versions
|
* It may get deleted or change definition in future POI versions
|
||||||
*/
|
*/
|
||||||
public NameXPtg getNameXPtg(String name) {
|
public NameXPtg getNameXPtg(String name) {
|
||||||
return workbook.getNameXPtg(name);
|
return workbook.getNameXPtg(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package org.apache.poi.hssf.model;
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -25,8 +24,6 @@ import junit.framework.AssertionFailedError;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
import org.apache.poi.hssf.eventmodel.ERFListener;
|
|
||||||
import org.apache.poi.hssf.eventmodel.EventRecordFactory;
|
|
||||||
import org.apache.poi.hssf.record.BOFRecord;
|
import org.apache.poi.hssf.record.BOFRecord;
|
||||||
import org.apache.poi.hssf.record.BlankRecord;
|
import org.apache.poi.hssf.record.BlankRecord;
|
||||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||||
|
@ -46,6 +43,7 @@ import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
|
||||||
import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
|
import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
|
||||||
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
||||||
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
|
@ -88,15 +86,16 @@ public final class TestSheet extends TestCase {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class MergedCellListener implements ERFListener {
|
private static final class MergedCellListener implements RecordVisitor {
|
||||||
|
|
||||||
private int _count;
|
private int _count;
|
||||||
public MergedCellListener() {
|
public MergedCellListener() {
|
||||||
_count = 0;
|
_count = 0;
|
||||||
}
|
}
|
||||||
public boolean processRecord(Record rec) {
|
public void visitRecord(Record r) {
|
||||||
_count++;
|
if (r instanceof MergeCellsRecord) {
|
||||||
return true;
|
_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return _count;
|
return _count;
|
||||||
|
@ -118,12 +117,8 @@ public final class TestSheet extends TestCase {
|
||||||
assertTrue(sheet.getNumMergedRegions() == regionsToAdd);
|
assertTrue(sheet.getNumMergedRegions() == regionsToAdd);
|
||||||
|
|
||||||
//test that the regions were spread out over the appropriate number of records
|
//test that the regions were spread out over the appropriate number of records
|
||||||
byte[] sheetData = new byte[sheet.getSize()];
|
|
||||||
sheet.serialize(0, sheetData);
|
|
||||||
MergedCellListener mcListener = new MergedCellListener();
|
MergedCellListener mcListener = new MergedCellListener();
|
||||||
EventRecordFactory erf = new EventRecordFactory(mcListener, new short[] { MergeCellsRecord.sid, });
|
sheet.visitContainedRecords(mcListener, 0);
|
||||||
// POIFSFileSystem poifs = new POIFSFileSystem(new ByteArrayInputStream(sheetData));
|
|
||||||
erf.processRecords(new ByteArrayInputStream(sheetData));
|
|
||||||
int recordsAdded = mcListener.getCount();
|
int recordsAdded = mcListener.getCount();
|
||||||
int recordsExpected = regionsToAdd/1027;
|
int recordsExpected = regionsToAdd/1027;
|
||||||
if ((regionsToAdd % 1027) != 0)
|
if ((regionsToAdd % 1027) != 0)
|
||||||
|
@ -416,6 +411,27 @@ public final class TestSheet extends TestCase {
|
||||||
assertEquals(DEFAULT_IDX, xfindex);
|
assertEquals(DEFAULT_IDX, xfindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class SizeCheckingRecordVisitor implements RecordVisitor {
|
||||||
|
|
||||||
|
private int _totalSize;
|
||||||
|
public SizeCheckingRecordVisitor() {
|
||||||
|
_totalSize = 0;
|
||||||
|
}
|
||||||
|
public void visitRecord(Record r) {
|
||||||
|
|
||||||
|
int estimatedSize=r.getRecordSize();
|
||||||
|
byte[] buf = new byte[estimatedSize];
|
||||||
|
int serializedSize = r.serialize(0, buf);
|
||||||
|
if (estimatedSize != serializedSize) {
|
||||||
|
throw new AssertionFailedError("serialized size mismatch for record ("
|
||||||
|
+ r.getClass().getName() + ")");
|
||||||
|
}
|
||||||
|
_totalSize += estimatedSize;
|
||||||
|
}
|
||||||
|
public int getTotalSize() {
|
||||||
|
return _totalSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Prior to bug 45066, POI would get the estimated sheet size wrong
|
* Prior to bug 45066, POI would get the estimated sheet size wrong
|
||||||
* when an <tt>UncalcedRecord</tt> was present.<p/>
|
* when an <tt>UncalcedRecord</tt> was present.<p/>
|
||||||
|
@ -430,12 +446,12 @@ public final class TestSheet extends TestCase {
|
||||||
records.add(EOFRecord.instance);
|
records.add(EOFRecord.instance);
|
||||||
Sheet sheet = Sheet.createSheet(records, 0, 0);
|
Sheet sheet = Sheet.createSheet(records, 0, 0);
|
||||||
|
|
||||||
int estimatedSize = sheet.getSize();
|
// The original bug was due to different logic for collecting records for sizing and
|
||||||
int serializedSize = sheet.serialize(0, new byte[estimatedSize]);
|
// serialization. The code has since been refactored into a single method for visiting
|
||||||
if (serializedSize != estimatedSize) {
|
// all contained records. Now this test is much less interesting
|
||||||
throw new AssertionFailedError("Identified bug 45066 b");
|
SizeCheckingRecordVisitor scrv = new SizeCheckingRecordVisitor();
|
||||||
}
|
sheet.visitContainedRecords(scrv, 0);
|
||||||
assertEquals(90, serializedSize);
|
assertEquals(90, scrv.getTotalSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -479,31 +495,31 @@ public final class TestSheet extends TestCase {
|
||||||
* That value is found on the IndexRecord.
|
* That value is found on the IndexRecord.
|
||||||
*/
|
*/
|
||||||
private static int getDbCellRecordPos(Sheet sheet) {
|
private static int getDbCellRecordPos(Sheet sheet) {
|
||||||
int size = sheet.getSize();
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
sheet.serialize(0, data);
|
|
||||||
|
|
||||||
MyIndexRecordListener myIndexListener = new MyIndexRecordListener();
|
MyIndexRecordListener myIndexListener = new MyIndexRecordListener();
|
||||||
EventRecordFactory erf = new EventRecordFactory(myIndexListener, new short[] { IndexRecord.sid, });
|
sheet.visitContainedRecords(myIndexListener, 0);
|
||||||
erf.processRecords(new ByteArrayInputStream(data));
|
|
||||||
IndexRecord indexRecord = myIndexListener.getIndexRecord();
|
IndexRecord indexRecord = myIndexListener.getIndexRecord();
|
||||||
int dbCellRecordPos = indexRecord.getDbcellAt(0);
|
int dbCellRecordPos = indexRecord.getDbcellAt(0);
|
||||||
return dbCellRecordPos;
|
return dbCellRecordPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class MyIndexRecordListener implements ERFListener {
|
private static final class MyIndexRecordListener implements RecordVisitor {
|
||||||
|
|
||||||
private IndexRecord _indexRecord;
|
private IndexRecord _indexRecord;
|
||||||
public MyIndexRecordListener() {
|
public MyIndexRecordListener() {
|
||||||
// no-arg constructor
|
// no-arg constructor
|
||||||
}
|
}
|
||||||
public boolean processRecord(Record rec) {
|
|
||||||
_indexRecord = (IndexRecord)rec;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public IndexRecord getIndexRecord() {
|
public IndexRecord getIndexRecord() {
|
||||||
return _indexRecord;
|
return _indexRecord;
|
||||||
}
|
}
|
||||||
|
public void visitRecord(Record r) {
|
||||||
|
if (r instanceof IndexRecord) {
|
||||||
|
if (_indexRecord != null) {
|
||||||
|
throw new RuntimeException("too many index records");
|
||||||
|
}
|
||||||
|
_indexRecord = (IndexRecord)r;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,23 +17,19 @@
|
||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
import org.apache.poi.hssf.eventmodel.ERFListener;
|
|
||||||
import org.apache.poi.hssf.eventmodel.EventRecordFactory;
|
|
||||||
import org.apache.poi.hssf.model.Workbook;
|
import org.apache.poi.hssf.model.Workbook;
|
||||||
import org.apache.poi.hssf.record.BackupRecord;
|
import org.apache.poi.hssf.record.BackupRecord;
|
||||||
import org.apache.poi.hssf.record.LabelSSTRecord;
|
import org.apache.poi.hssf.record.LabelSSTRecord;
|
||||||
import org.apache.poi.hssf.record.Record;
|
import org.apache.poi.hssf.record.Record;
|
||||||
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
||||||
import org.apache.poi.hssf.util.CellRangeAddress;
|
import org.apache.poi.hssf.util.CellRangeAddress;
|
||||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
import org.apache.poi.util.TempFile;
|
import org.apache.poi.util.TempFile;
|
||||||
|
@ -72,10 +68,7 @@ public final class TestWorkbook extends TestCase {
|
||||||
* HSSFSheet last row or first row is incorrect. <P>
|
* HSSFSheet last row or first row is incorrect. <P>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
public void testWriteSheetSimple() throws IOException {
|
||||||
public void testWriteSheetSimple()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
File file = TempFile.createTempFile("testWriteSheetSimple",
|
File file = TempFile.createTempFile("testWriteSheetSimple",
|
||||||
".xls");
|
".xls");
|
||||||
FileOutputStream out = new FileOutputStream(file);
|
FileOutputStream out = new FileOutputStream(file);
|
||||||
|
@ -84,13 +77,10 @@ public final class TestWorkbook extends TestCase {
|
||||||
HSSFRow r = null;
|
HSSFRow r = null;
|
||||||
HSSFCell c = null;
|
HSSFCell c = null;
|
||||||
|
|
||||||
for (short rownum = ( short ) 0; rownum < 100; rownum++)
|
for (int rownum = 0; rownum < 100; rownum++) {
|
||||||
{
|
|
||||||
r = s.createRow(rownum);
|
r = s.createRow(rownum);
|
||||||
|
|
||||||
// r.setRowNum(( short ) rownum);
|
for (int cellnum = 0; cellnum < 50; cellnum += 2) {
|
||||||
for (short cellnum = ( short ) 0; cellnum < 50; cellnum += 2)
|
|
||||||
{
|
|
||||||
c = r.createCell(cellnum);
|
c = r.createCell(cellnum);
|
||||||
c.setCellValue(rownum * 10000 + cellnum
|
c.setCellValue(rownum * 10000 + cellnum
|
||||||
+ ((( double ) rownum / 1000)
|
+ ((( double ) rownum / 1000)
|
||||||
|
@ -104,8 +94,6 @@ public final class TestWorkbook extends TestCase {
|
||||||
sanityChecker.checkHSSFWorkbook(wb);
|
sanityChecker.checkHSSFWorkbook(wb);
|
||||||
assertEquals("LAST ROW == 99", 99, s.getLastRowNum());
|
assertEquals("LAST ROW == 99", 99, s.getLastRowNum());
|
||||||
assertEquals("FIRST ROW == 0", 0, s.getFirstRowNum());
|
assertEquals("FIRST ROW == 0", 0, s.getFirstRowNum());
|
||||||
|
|
||||||
// assert((s.getLastRowNum() == 99));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,13 +118,10 @@ public final class TestWorkbook extends TestCase {
|
||||||
HSSFRow r = null;
|
HSSFRow r = null;
|
||||||
HSSFCell c = null;
|
HSSFCell c = null;
|
||||||
|
|
||||||
for (short rownum = ( short ) 0; rownum < 100; rownum++)
|
for (int rownum = 0; rownum < 100; rownum++) {
|
||||||
{
|
|
||||||
r = s.createRow(rownum);
|
r = s.createRow(rownum);
|
||||||
|
|
||||||
// r.setRowNum(( short ) rownum);
|
for (int cellnum = 0; cellnum < 50; cellnum += 2) {
|
||||||
for (short cellnum = ( short ) 0; cellnum < 50; cellnum += 2)
|
|
||||||
{
|
|
||||||
c = r.createCell(cellnum);
|
c = r.createCell(cellnum);
|
||||||
c.setCellValue(rownum * 10000 + cellnum
|
c.setCellValue(rownum * 10000 + cellnum
|
||||||
+ ((( double ) rownum / 1000)
|
+ ((( double ) rownum / 1000)
|
||||||
|
@ -145,13 +130,11 @@ public final class TestWorkbook extends TestCase {
|
||||||
c.setCellValue(new HSSFRichTextString("TEST"));
|
c.setCellValue(new HSSFRichTextString("TEST"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (short rownum = ( short ) 0; rownum < 25; rownum++)
|
for (int rownum = 0; rownum < 25; rownum++) {
|
||||||
{
|
|
||||||
r = s.getRow(rownum);
|
r = s.getRow(rownum);
|
||||||
s.removeRow(r);
|
s.removeRow(r);
|
||||||
}
|
}
|
||||||
for (short rownum = ( short ) 75; rownum < 100; rownum++)
|
for (int rownum = 75; rownum < 100; rownum++) {
|
||||||
{
|
|
||||||
r = s.getRow(rownum);
|
r = s.getRow(rownum);
|
||||||
s.removeRow(r);
|
s.removeRow(r);
|
||||||
}
|
}
|
||||||
|
@ -428,12 +411,10 @@ public final class TestWorkbook extends TestCase {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
HSSFSheet s = wb.createSheet();
|
HSSFSheet s = wb.createSheet();
|
||||||
|
|
||||||
for (short rownum = ( short ) 0; rownum < 100; rownum++)
|
for (int rownum = 0; rownum < 100; rownum++) {
|
||||||
{
|
|
||||||
HSSFRow r = s.createRow(rownum);
|
HSSFRow r = s.createRow(rownum);
|
||||||
|
|
||||||
for (short cellnum = ( short ) 0; cellnum < 50; cellnum += 2)
|
for (int cellnum = 0; cellnum < 50; cellnum += 2) {
|
||||||
{
|
|
||||||
HSSFCell c = r.createCell(cellnum);
|
HSSFCell c = r.createCell(cellnum);
|
||||||
c.setCellValue(rownum * 10000 + cellnum
|
c.setCellValue(rownum * 10000 + cellnum
|
||||||
+ ((( double ) rownum / 1000)
|
+ ((( double ) rownum / 1000)
|
||||||
|
@ -465,13 +446,10 @@ public final class TestWorkbook extends TestCase {
|
||||||
/**
|
/**
|
||||||
* Test the backup field gets set as expected.
|
* Test the backup field gets set as expected.
|
||||||
*/
|
*/
|
||||||
|
public void testBackupRecord() {
|
||||||
public void testBackupRecord()
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
throws Exception
|
wb.createSheet();
|
||||||
{
|
Workbook workbook = wb.getWorkbook();
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
|
||||||
wb.createSheet();
|
|
||||||
Workbook workbook = wb.getWorkbook();
|
|
||||||
BackupRecord record = workbook.getBackupRecord();
|
BackupRecord record = workbook.getBackupRecord();
|
||||||
|
|
||||||
assertEquals(0, record.getBackup());
|
assertEquals(0, record.getBackup());
|
||||||
|
@ -479,7 +457,7 @@ public final class TestWorkbook extends TestCase {
|
||||||
assertEquals(1, record.getBackup());
|
assertEquals(1, record.getBackup());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class RecordCounter implements ERFListener {
|
private static final class RecordCounter implements RecordVisitor {
|
||||||
private int _count;
|
private int _count;
|
||||||
|
|
||||||
public RecordCounter() {
|
public RecordCounter() {
|
||||||
|
@ -488,9 +466,10 @@ public final class TestWorkbook extends TestCase {
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return _count;
|
return _count;
|
||||||
}
|
}
|
||||||
public boolean processRecord(Record rec) {
|
public void visitRecord(Record r) {
|
||||||
_count++;
|
if (r instanceof LabelSSTRecord) {
|
||||||
return true;
|
_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,9 +478,7 @@ public final class TestWorkbook extends TestCase {
|
||||||
*
|
*
|
||||||
* We need to make sure only one LabelSSTRecord is produced.
|
* We need to make sure only one LabelSSTRecord is produced.
|
||||||
*/
|
*/
|
||||||
public void testRepeatingBug()
|
public void testRepeatingBug() {
|
||||||
throws Exception
|
|
||||||
{
|
|
||||||
HSSFWorkbook workbook = new HSSFWorkbook();
|
HSSFWorkbook workbook = new HSSFWorkbook();
|
||||||
HSSFSheet sheet = workbook.createSheet("Design Variants");
|
HSSFSheet sheet = workbook.createSheet("Design Variants");
|
||||||
HSSFRow row = sheet.createRow(2);
|
HSSFRow row = sheet.createRow(2);
|
||||||
|
@ -510,12 +487,8 @@ public final class TestWorkbook extends TestCase {
|
||||||
cell.setCellValue(new HSSFRichTextString("Class"));
|
cell.setCellValue(new HSSFRichTextString("Class"));
|
||||||
cell = row.createCell(2);
|
cell = row.createCell(2);
|
||||||
|
|
||||||
byte[] data = new byte[sheet.getSheet().getSize()];
|
|
||||||
sheet.getSheet().serialize(0, data);
|
|
||||||
RecordCounter rc = new RecordCounter();
|
RecordCounter rc = new RecordCounter();
|
||||||
EventRecordFactory erf = new EventRecordFactory(rc, new short[] { LabelSSTRecord.sid, });
|
sheet.getSheet().visitContainedRecords(rc, 0);
|
||||||
erf.processRecords(new ByteArrayInputStream(data));
|
|
||||||
|
|
||||||
assertEquals(1, rc.getCount());
|
assertEquals(1, rc.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue