public static Sheet createSheet(RecordStream rs) {
return new Sheet(rs);
}
private Sheet(RecordStream rs) {
_mergedCellsTable = new MergedCellsTable();
RowRecordsAggregate rra = null;
records = new ArrayList<RecordBase>(128);
// TODO - take chart streams off into separate java objects
int bofEofNestingLevel = 1; // nesting level can only get to 2 (when charts are present)
int dimsloc = -1;
if (rs.peekNextSid() == BOFRecord.sid) {
BOFRecord bof = (BOFRecord) rs.getNext();
if (bof.getType() != BOFRecord.TYPE_WORKSHEET) {
// TODO - fix junit tests throw new RuntimeException("Bad BOF record type");
}
records.add(bof);
} else {
throw new RuntimeException("BOF record expected");
}
while (rs.hasNext()) {
int recSid = rs.peekNextSid();
if ( recSid == CFHeaderRecord.sid ) {
condFormatting = new ConditionalFormattingTable(rs);
records.add(condFormatting);
continue;
}
if (recSid == ColumnInfoRecord.sid) {
_columnInfos = new ColumnInfoRecordsAggregate(rs);
records.add(_columnInfos);
continue;
}
if ( recSid == DVALRecord.sid) {
_dataValidityTable = new DataValidityTable(rs);
records.add(_dataValidityTable);
continue;
}
if (RecordOrderer.isRowBlockRecord(recSid) && bofEofNestingLevel == 1 ) {
//only add the aggregate once
if (rra != null) {
throw new RuntimeException("row/cell records found in the wrong place");
}
RowBlocksReader rbr = new RowBlocksReader(rs);
_mergedCellsTable.addRecords(rbr.getLooseMergedCells());
rra = new RowRecordsAggregate(rbr.getPlainRecordStream(), rbr.getSharedFormulaManager());
records.add(rra); //only add the aggregate once
continue;
}
if (PageSettingsBlock.isComponentRecord(recSid)) {
PageSettingsBlock psb = new PageSettingsBlock(rs);
if (_psBlock == null) {
_psBlock = psb;
} else {
if (bofEofNestingLevel == 2) {
// It's normal for a chart to have its own PageSettingsBlock
// Fall through and add psb here, because chart records
// are stored loose among the sheet records.
// this latest psb does not clash with _psBlock
} else if (windowTwo != null) {
// probably 'Custom View Settings' sub-stream which is found between
// USERSVIEWBEGIN(01AA) and USERSVIEWEND(01AB)
// This happens three times in test sample file "29982.xls"
if (rs.peekNextSid() != UnknownRecord.USERSVIEWEND_01AB) {
// not quite the expected situation
throw new RuntimeException("two Page Settings Blocks found in the same sheet");
}
} else {
// Some apps write PLS, WSBOOL, <psb> but PLS is part of <psb>
// This happens in the test sample file "NoGutsRecords.xls" and "WORKBOOK_in_capitals.xls"
// In this case the first PSB is two records back
int prevPsbIx = records.size()-2;
if (_psBlock != records.get(prevPsbIx) || !(records.get(prevPsbIx+1) instanceof WSBoolRecord)) {
// not quite the expected situation
throw new RuntimeException("two Page Settings Blocks found in the same sheet");
}
records.remove(prevPsbIx); // WSBOOL will drop down one position.
psb = mergePSBs(_psBlock, psb);
_psBlock = psb;
}
}
records.add(psb);
continue;
}
if (recSid == MergeCellsRecord.sid) {
// when the MergedCellsTable is found in the right place, we expect those records to be contiguous
_mergedCellsTable.read(rs);
continue;
}
Record rec = rs.getNext();
if ( recSid == IndexRecord.sid ) {
// ignore INDEX record because it is only needed by Excel,
// and POI always re-calculates its contents
continue;
}
if (recSid == UncalcedRecord.sid) {
// don't add UncalcedRecord to the list
_isUncalced = true; // this flag is enough
continue;
}
if (recSid == BOFRecord.sid)
{
bofEofNestingLevel++;
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel);
}
else if (recSid == EOFRecord.sid)
{
--bofEofNestingLevel;
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel);
if (bofEofNestingLevel == 0) {
records.add(rec);
break;
}
}
else if (recSid == DimensionsRecord.sid)
{
// Make a columns aggregate if one hasn't ready been created.
if (_columnInfos == null)
{
_columnInfos = new ColumnInfoRecordsAggregate();
records.add(_columnInfos);
}
_dimensions = ( DimensionsRecord ) rec;
dimsloc = records.size();
}
else if (recSid == DefaultColWidthRecord.sid)
{
defaultcolwidth = ( DefaultColWidthRecord ) rec;
}
else if (recSid == DefaultRowHeightRecord.sid)
{
defaultrowheight = ( DefaultRowHeightRecord ) rec;
}
else if ( recSid == PrintGridlinesRecord.sid )
{
printGridlines = (PrintGridlinesRecord) rec;
}
else if ( recSid == GridsetRecord.sid )
{
gridset = (GridsetRecord) rec;
}
else if ( recSid == SelectionRecord.sid )
{
selection = (SelectionRecord) rec;
}
else if ( recSid == WindowTwoRecord.sid )
{
windowTwo = (WindowTwoRecord) rec;
}
else if ( recSid == ProtectRecord.sid )
{
protect = (ProtectRecord) rec;
}
else if ( recSid == ObjectProtectRecord.sid )
{
objprotect = (ObjectProtectRecord) rec;
}
else if ( recSid == ScenarioProtectRecord.sid )
{
scenprotect = (ScenarioProtectRecord) rec;
}
else if ( recSid == PasswordRecord.sid )
{
password = (PasswordRecord) rec;
}
records.add(rec);
}
if (windowTwo == null) {
throw new RuntimeException("WINDOW2 was not found");
}
if (_dimensions == null) {
// Excel seems to always write the DIMENSION record, but tolerates when it is not present
// in all cases Excel (2007) adds the missing DIMENSION record
if (rra == null) {
// bug 46206 alludes to files which skip the DIMENSION record
// when there are no row/cell records.
// Not clear which application wrote these files.
rra = new RowRecordsAggregate();
} else {
log.log(POILogger.WARN, "DIMENSION record not found even though row/cells present");
// Not sure if any tools write files like this, but Excel reads them OK
}
dimsloc = findFirstRecordLocBySid(WindowTwoRecord.sid);
_dimensions = rra.createDimensions();
records.add(dimsloc, _dimensions);
}
if (rra == null) {
rra = new RowRecordsAggregate();
records.add(dimsloc + 1, rra);
}
_rowsAggregate = rra;
// put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */
RecordOrderer.addNewSheetRecord(records, _mergedCellsTable);