diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 0cd747f15..2d9fe5a3d 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 45672 - improve handling by MissingRecordAwareHSSFListener of records that cover multiple cells (MulBlankRecord and MulRKRecord) 48096 - relaxed validation check in RecalcIdRecord 48085 - improved error checking in BlockAllocationTableReader to trap unreasonable field values 47924 - fixed logic for matching cells and comments in HSSFCell.getCellComment() diff --git a/src/java/org/apache/poi/hssf/eventusermodel/MissingRecordAwareHSSFListener.java b/src/java/org/apache/poi/hssf/eventusermodel/MissingRecordAwareHSSFListener.java index e41b0b92a..7da8ee5e2 100644 --- a/src/java/org/apache/poi/hssf/eventusermodel/MissingRecordAwareHSSFListener.java +++ b/src/java/org/apache/poi/hssf/eventusermodel/MissingRecordAwareHSSFListener.java @@ -21,9 +21,14 @@ import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingRowDummyRecord; import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.CellValueRecordInterface; +import org.apache.poi.hssf.record.MulBlankRecord; +import org.apache.poi.hssf.record.MulRKRecord; import org.apache.poi.hssf.record.NoteRecord; +import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordFactory; import org.apache.poi.hssf.record.RowRecord; import org.apache.poi.hssf.record.SharedFormulaRecord; @@ -62,7 +67,7 @@ public final class MissingRecordAwareHSSFListener implements HSSFListener { public void processRecord(Record record) { int thisRow; int thisColumn; - + CellValueRecordInterface[] expandedRecords = null; if (record instanceof CellValueRecordInterface) { CellValueRecordInterface valueRec = (CellValueRecordInterface) record; @@ -105,6 +110,19 @@ public final class MissingRecordAwareHSSFListener implements HSSFListener { // - so don't fire off the LastCellOfRowDummyRecord yet childListener.processRecord(record); return; + case MulBlankRecord.sid: + // These appear in the middle of the cell records, to + // specify that the next bunch are empty but styled + // Expand this out into multiple blank cells + MulBlankRecord mbr = (MulBlankRecord)record; + expandedRecords = RecordFactory.convertBlankRecords(mbr); + break; + case MulRKRecord.sid: + // This is multiple consecutive number cells in one record + // Exand this out into multiple regular number cells + MulRKRecord mrk = (MulRKRecord)record; + expandedRecords = RecordFactory.convertRKRecords(mrk); + break; case NoteRecord.sid: NoteRecord nrec = (NoteRecord) record; thisRow = nrec.getRow(); @@ -112,6 +130,13 @@ public final class MissingRecordAwareHSSFListener implements HSSFListener { break; } } + + // First part of expanded record handling + if(expandedRecords != null && expandedRecords.length > 0) { + thisRow = expandedRecords[0].getRow(); + thisColumn = expandedRecords[0].getColumn(); + } + // If we're on cells, and this cell isn't in the same // row as the last one, then fire the // dummy end-of-row records @@ -148,13 +173,26 @@ public final class MissingRecordAwareHSSFListener implements HSSFListener { } } + // Next part of expanded record handling + if(expandedRecords != null && expandedRecords.length > 0) { + thisColumn = expandedRecords[expandedRecords.length-1].getColumn(); + } + + // Update cell and row counts as needed if(thisColumn != -1) { lastCellColumn = thisColumn; lastCellRow = thisRow; } - childListener.processRecord(record); + // Pass along the record(s) + if(expandedRecords != null && expandedRecords.length > 0) { + for(CellValueRecordInterface r : expandedRecords) { + childListener.processRecord((Record)r); + } + } else { + childListener.processRecord(record); + } } private void resetCounts() { diff --git a/src/java/org/apache/poi/hssf/record/MulBlankRecord.java b/src/java/org/apache/poi/hssf/record/MulBlankRecord.java index 87d4eafea..695c55c87 100644 --- a/src/java/org/apache/poi/hssf/record/MulBlankRecord.java +++ b/src/java/org/apache/poi/hssf/record/MulBlankRecord.java @@ -56,6 +56,13 @@ public final class MulBlankRecord extends StandardRecord { public int getFirstColumn() { return _firstCol; } + + /** + * @return ending column (last cell this holds in the row). Zero based + */ + public int getLastColumn() { + return _lastCol; + } /** * get the number of columns this contains (last-first +1) diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index 3d200e7ef..85f3a082e 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -281,7 +281,6 @@ public final class RecordFactory { * Converts a {@link MulRKRecord} into an equivalent array of {@link NumberRecord}s */ public static NumberRecord[] convertRKRecords(MulRKRecord mrk) { - NumberRecord[] mulRecs = new NumberRecord[mrk.getNumColumns()]; for (int k = 0; k < mrk.getNumColumns(); k++) { NumberRecord nr = new NumberRecord(); @@ -295,6 +294,22 @@ public final class RecordFactory { return mulRecs; } + /** + * Converts a {@link MulBlankRecord} into an equivalent array of {@link BlankRecord}s + */ + public static BlankRecord[] convertBlankRecords(MulBlankRecord mbk) { + BlankRecord[] mulRecs = new BlankRecord[mbk.getNumColumns()]; + for (int k = 0; k < mbk.getNumColumns(); k++) { + BlankRecord br = new BlankRecord(); + + br.setColumn((short) (k + mbk.getFirstColumn())); + br.setRow(mbk.getRow()); + br.setXFIndex(mbk.getXFAt(k)); + mulRecs[k] = br; + } + return mulRecs; + } + /** * @return an array of all the SIDS for all known records */ diff --git a/src/testcases/org/apache/poi/hssf/eventusermodel/TestMissingRecordAwareHSSFListener.java b/src/testcases/org/apache/poi/hssf/eventusermodel/TestMissingRecordAwareHSSFListener.java index aa4bbcc6f..e632cbbbb 100644 --- a/src/testcases/org/apache/poi/hssf/eventusermodel/TestMissingRecordAwareHSSFListener.java +++ b/src/testcases/org/apache/poi/hssf/eventusermodel/TestMissingRecordAwareHSSFListener.java @@ -29,7 +29,9 @@ import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingRowDummyRecord; import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.MulBlankRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.RowRecord; import org.apache.poi.hssf.record.SharedFormulaRecord; @@ -422,4 +424,41 @@ public final class TestMissingRecordAwareHSSFListener extends TestCase { assertEquals(1, eorCount); assertEquals(1, sfrCount); } + + /** + * MulBlank records hold multiple blank cells. Check we + * can handle them correctly. + */ + public void testMulBlankHandling() { + readRecords("45672.xls"); + + // Check that we don't have any MulBlankRecords, but do + // have lots of BlankRecords + Record[] rr = r; + int eorCount=0; + int mbrCount=0; + int brCount=0; + for (int i = 0; i < rr.length; i++) { + Record record = rr[i]; + if (record instanceof MulBlankRecord) { + mbrCount++; + } + if (record instanceof BlankRecord) { + brCount++; + } + if (record instanceof LastCellOfRowDummyRecord) { + eorCount++; + } + } + if (mbrCount > 0) { + throw new AssertionFailedError("Identified bug 45672"); + } + if (brCount < 20) { + throw new AssertionFailedError("Identified bug 45672"); + } + if (eorCount != 2) { + throw new AssertionFailedError("Identified bug 45672"); + } + assertEquals(2, eorCount); + } } diff --git a/test-data/spreadsheet/45672.xls b/test-data/spreadsheet/45672.xls new file mode 100644 index 000000000..752ce5da0 Binary files /dev/null and b/test-data/spreadsheet/45672.xls differ