diff --git a/src/java/org/apache/poi/hssf/model/InternalSheet.java b/src/java/org/apache/poi/hssf/model/InternalSheet.java index 277fdbd72..183ca2c41 100644 --- a/src/java/org/apache/poi/hssf/model/InternalSheet.java +++ b/src/java/org/apache/poi/hssf/model/InternalSheet.java @@ -21,7 +21,42 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import org.apache.poi.hssf.record.*; +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.CFHeaderRecord; +import org.apache.poi.hssf.record.CalcCountRecord; +import org.apache.poi.hssf.record.CalcModeRecord; +import org.apache.poi.hssf.record.CellValueRecordInterface; +import org.apache.poi.hssf.record.ColumnInfoRecord; +import org.apache.poi.hssf.record.DVALRecord; +import org.apache.poi.hssf.record.DefaultColWidthRecord; +import org.apache.poi.hssf.record.DefaultRowHeightRecord; +import org.apache.poi.hssf.record.DeltaRecord; +import org.apache.poi.hssf.record.DimensionsRecord; +import org.apache.poi.hssf.record.DrawingRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.EscherAggregate; +import org.apache.poi.hssf.record.FeatHdrRecord; +import org.apache.poi.hssf.record.FeatRecord; +import org.apache.poi.hssf.record.GridsetRecord; +import org.apache.poi.hssf.record.GutsRecord; +import org.apache.poi.hssf.record.IndexRecord; +import org.apache.poi.hssf.record.IterationRecord; +import org.apache.poi.hssf.record.MergeCellsRecord; +import org.apache.poi.hssf.record.NoteRecord; +import org.apache.poi.hssf.record.PaneRecord; +import org.apache.poi.hssf.record.PrintGridlinesRecord; +import org.apache.poi.hssf.record.PrintHeadersRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordBase; +import org.apache.poi.hssf.record.RecordFormatException; +import org.apache.poi.hssf.record.RefModeRecord; +import org.apache.poi.hssf.record.RowRecord; +import org.apache.poi.hssf.record.SCLRecord; +import org.apache.poi.hssf.record.SaveRecalcRecord; +import org.apache.poi.hssf.record.SelectionRecord; +import org.apache.poi.hssf.record.UncalcedRecord; +import org.apache.poi.hssf.record.WSBoolRecord; +import org.apache.poi.hssf.record.WindowTwoRecord; import org.apache.poi.hssf.record.aggregates.ChartSubstreamRecordAggregate; import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable; @@ -131,11 +166,27 @@ public final class InternalSheet { if (rs.peekNextSid() != BOFRecord.sid) { throw new RuntimeException("BOF record expected"); } + BOFRecord bof = (BOFRecord) rs.getNext(); - if (bof.getType() != BOFRecord.TYPE_WORKSHEET) { - // TODO - fix junit tests throw new RuntimeException("Bad BOF record type"); + if (bof.getType() == BOFRecord.TYPE_WORKSHEET) { + // Good, well supported + } else if (bof.getType() == BOFRecord.TYPE_CHART || + bof.getType() == BOFRecord.TYPE_EXCEL_4_MACRO) { + // These aren't really typical sheets... Let it go though, + // we can handle them roughly well enough as a "normal" one + } else { + // Not a supported type + // Skip onto the EOF, then complain + while (rs.hasNext()) { + Record rec = rs.getNext(); + if (rec instanceof EOFRecord) { + break; + } + } + throw new UnsupportedBOFType(bof.getType()); } records.add(bof); + while (rs.hasNext()) { int recSid = rs.peekNextSid(); @@ -318,6 +369,18 @@ public final class InternalSheet { recs.add(r); }}); } + + public static class UnsupportedBOFType extends RecordFormatException { + private final int type; + protected UnsupportedBOFType(int type) { + super("BOF not of a supported type, found " + type); + this.type = type; + } + + public int getType() { + return type; + } + } private static final class RecordCloner implements RecordVisitor { diff --git a/src/java/org/apache/poi/hssf/model/RecordOrderer.java b/src/java/org/apache/poi/hssf/model/RecordOrderer.java index 69e9971fa..9f1871cad 100644 --- a/src/java/org/apache/poi/hssf/model/RecordOrderer.java +++ b/src/java/org/apache/poi/hssf/model/RecordOrderer.java @@ -25,6 +25,7 @@ import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.CalcCountRecord; import org.apache.poi.hssf.record.CalcModeRecord; +import org.apache.poi.hssf.record.ColumnInfoRecord; import org.apache.poi.hssf.record.DVALRecord; import org.apache.poi.hssf.record.DateWindow1904Record; import org.apache.poi.hssf.record.DefaultColWidthRecord; @@ -415,7 +416,7 @@ final class RecordOrderer { case DrawingSelectionRecord.sid: case ObjRecord.sid: case TextObjectRecord.sid: - + case ColumnInfoRecord.sid: // See Bugzilla 53984 case GutsRecord.sid: // see Bugzilla 50426 case WindowOneRecord.sid: // should really be part of workbook stream, but some apps seem to put this before WINDOW2 diff --git a/src/java/org/apache/poi/hssf/record/EscherAggregate.java b/src/java/org/apache/poi/hssf/record/EscherAggregate.java index 9ca4fefc0..21c4db454 100644 --- a/src/java/org/apache/poi/hssf/record/EscherAggregate.java +++ b/src/java/org/apache/poi/hssf/record/EscherAggregate.java @@ -19,7 +19,12 @@ package org.apache.poi.hssf.record; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import org.apache.poi.ddf.DefaultEscherRecordFactory; import org.apache.poi.ddf.EscherClientDataRecord; @@ -754,8 +759,15 @@ public final class EscherAggregate extends AbstractEscherHolderRecord { * @param loc - location of the record which sid must be returned * @return sid of the record with selected location */ - private static short sid(List records, int loc) { - return ((Record) records.get(loc)).getSid(); + private static short sid(List records, int loc) { + RecordBase record = records.get(loc); + if (record instanceof Record) { + return ((Record)record).getSid(); + } else { + // Aggregates don't have a sid + // We could step into them, but for these needs we don't care + return -1; + } } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 7a1479fdd..51d4b48ba 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -46,6 +46,7 @@ import org.apache.poi.hssf.OldExcelFormatException; import org.apache.poi.hssf.model.DrawingManager2; import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.model.InternalSheet; +import org.apache.poi.hssf.model.InternalSheet.UnsupportedBOFType; import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.record.AbstractEscherHolderRecord; @@ -321,8 +322,13 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss convertLabelRecords(records, recOffset); RecordStream rs = new RecordStream(records, recOffset); while (rs.hasNext()) { - InternalSheet sheet = InternalSheet.createSheet(rs); - _sheets.add(new HSSFSheet(this, sheet)); + try { + InternalSheet sheet = InternalSheet.createSheet(rs); + _sheets.add(new HSSFSheet(this, sheet)); + } catch (UnsupportedBOFType eb) { + // Hopefully there's a supported one after this! + log.log(POILogger.WARN, "Unsupported BOF found of type " + eb.getType()); + } } for (int i = 0 ; i < workbook.getNumNames() ; ++i){ diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index 543ec99eb..f0cc68101 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -2731,4 +2731,15 @@ public final class TestBugs extends BaseTestBugzillaIssues { assertEquals("A$1+B$1", s.getRow(row).getCell(2).getCellFormula()); } } + + /** + * Unexpected record type (org.apache.poi.hssf.record.ColumnInfoRecord) + */ + @Test + public void bug53984() { + Workbook wb = openSample("53984.xls"); + Sheet s = wb.getSheetAt(0); + assertEquals("International Communication Services SA", s.getRow(2).getCell(0).getStringCellValue()); + assertEquals("Saudi Arabia-Riyadh", s.getRow(210).getCell(0).getStringCellValue()); + } } diff --git a/test-data/spreadsheet/53984.xls b/test-data/spreadsheet/53984.xls new file mode 100644 index 000000000..07d3e8337 Binary files /dev/null and b/test-data/spreadsheet/53984.xls differ