Bugzilla 47415 - Fixed PageSettingsBlock to allow multiple PLS records

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@788157 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2009-06-24 19:45:44 +00:00
parent c71e498a11
commit af131d4cee
4 changed files with 118 additions and 51 deletions

View File

@ -33,6 +33,7 @@
<changes> <changes>
<release version="3.5-beta7" date="2009-??-??"> <release version="3.5-beta7" date="2009-??-??">
<action dev="POI-DEVELOPERS" type="fix">47415 - Fixed PageSettingsBlock to allow multiple PLS records</action>
<action dev="POI-DEVELOPERS" type="fix">47412 - Fixed concurrency issue with EscherProperties.initProps()</action> <action dev="POI-DEVELOPERS" type="fix">47412 - Fixed concurrency issue with EscherProperties.initProps()</action>
<action dev="POI-DEVELOPERS" type="fix">47143 - Fixed OOM in HSSFWorkbook#getAllPictures when reading .xls files containing metafiles</action> <action dev="POI-DEVELOPERS" type="fix">47143 - Fixed OOM in HSSFWorkbook#getAllPictures when reading .xls files containing metafiles</action>
<action dev="POI-DEVELOPERS" type="add">Added implementation for ISNA()</action> <action dev="POI-DEVELOPERS" type="add">Added implementation for ISNA()</action>

View File

@ -42,6 +42,9 @@ public final class UnknownRecord extends StandardRecord {
* The few POI test samples with this record have data { 0x03, 0x00 }. * The few POI test samples with this record have data { 0x03, 0x00 }.
*/ */
public static final int PRINTSIZE_0033 = 0x0033; public static final int PRINTSIZE_0033 = 0x0033;
/**
* Environment-Specific Print Record
*/
public static final int PLS_004D = 0x004D; public static final int PLS_004D = 0x004D;
public static final int SHEETPR_0081 = 0x0081; public static final int SHEETPR_0081 = 0x0081;
public static final int SORT_0090 = 0x0090; public static final int SORT_0090 = 0x0090;

View File

@ -6,7 +6,7 @@
(the "License"); you may not use this file except in compliance with (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
@ -19,7 +19,6 @@ package org.apache.poi.hssf.record.aggregates;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
@ -50,6 +49,44 @@ import org.apache.poi.hssf.record.VerticalPageBreakRecord;
* @author Josh Micich * @author Josh Micich
*/ */
public final class PageSettingsBlock extends RecordAggregate { public final class PageSettingsBlock extends RecordAggregate {
/**
* PLS is potentially a <i>continued</i> record, but is currently uninterpreted by POI
*/
private static final class PLSAggregate extends RecordAggregate {
private static final ContinueRecord[] EMPTY_CONTINUE_RECORD_ARRAY = { };
private final Record _pls;
/**
* holds any continue records found after the PLS record.<br/>
* This would not be required if PLS was properly interpreted.
* Currently, PLS is an {@link UnknownRecord} and does not automatically
* include any trailing {@link ContinueRecord}s.
*/
private ContinueRecord[] _plsContinues;
public PLSAggregate(RecordStream rs) {
_pls = rs.getNext();
if (rs.peekNextSid()==ContinueRecord.sid) {
List<ContinueRecord> temp = new ArrayList<ContinueRecord>();
while (rs.peekNextSid()==ContinueRecord.sid) {
temp.add((ContinueRecord)rs.getNext());
}
_plsContinues = new ContinueRecord[temp.size()];
temp.toArray(_plsContinues);
} else {
_plsContinues = EMPTY_CONTINUE_RECORD_ARRAY;
}
}
@Override
public void visitContainedRecords(RecordVisitor rv) {
rv.visitRecord(_pls);
for (int i = 0; i < _plsContinues.length; i++) {
rv.visitRecord(_plsContinues[i]);
}
}
}
// Every one of these component records is optional // Every one of these component records is optional
// (The whole PageSettingsBlock may not be present) // (The whole PageSettingsBlock may not be present)
private PageBreakRecord _rowBreaksRecord; private PageBreakRecord _rowBreaksRecord;
@ -62,20 +99,14 @@ public final class PageSettingsBlock extends RecordAggregate {
private RightMarginRecord _rightMargin; private RightMarginRecord _rightMargin;
private TopMarginRecord _topMargin; private TopMarginRecord _topMargin;
private BottomMarginRecord _bottomMargin; private BottomMarginRecord _bottomMargin;
private Record _pls; private final List<PLSAggregate> _plsRecords;
/**
* holds any continue records found after the PLS record.<br/>
* This would not be required if PLS was properly interpreted.
* Currently, PLS is an {@link UnknownRecord} and does not automatically
* include any trailing {@link ContinueRecord}s.
*/
private List<ContinueRecord> _plsContinues;
private PrintSetupRecord _printSetup; private PrintSetupRecord _printSetup;
private Record _bitmap; private Record _bitmap;
private Record _headerFooter; private Record _headerFooter;
private Record _printSize; private Record _printSize;
public PageSettingsBlock(RecordStream rs) { public PageSettingsBlock(RecordStream rs) {
_plsRecords = new ArrayList<PLSAggregate>();
while(true) { while(true) {
if (!readARecord(rs)) { if (!readARecord(rs)) {
break; break;
@ -87,6 +118,7 @@ public final class PageSettingsBlock extends RecordAggregate {
* Creates a PageSettingsBlock with default settings * Creates a PageSettingsBlock with default settings
*/ */
public PageSettingsBlock() { public PageSettingsBlock() {
_plsRecords = new ArrayList<PLSAggregate>();
_rowBreaksRecord = new HorizontalPageBreakRecord(); _rowBreaksRecord = new HorizontalPageBreakRecord();
_columnBreaksRecord = new VerticalPageBreakRecord(); _columnBreaksRecord = new VerticalPageBreakRecord();
_header = new HeaderRecord(""); _header = new HeaderRecord("");
@ -165,14 +197,7 @@ public final class PageSettingsBlock extends RecordAggregate {
_bottomMargin = (BottomMarginRecord) rs.getNext(); _bottomMargin = (BottomMarginRecord) rs.getNext();
break; break;
case UnknownRecord.PLS_004D: case UnknownRecord.PLS_004D:
checkNotPresent(_pls); _plsRecords.add(new PLSAggregate(rs));
_pls = rs.getNext();
while (rs.peekNextSid()==ContinueRecord.sid) {
if (_plsContinues==null) {
_plsContinues = new LinkedList<ContinueRecord>();
}
_plsContinues.add((ContinueRecord)rs.getNext());
}
break; break;
case PrintSetupRecord.sid: case PrintSetupRecord.sid:
checkNotPresent(_printSetup); checkNotPresent(_printSetup);
@ -260,11 +285,8 @@ public final class PageSettingsBlock extends RecordAggregate {
visitIfPresent(_rightMargin, rv); visitIfPresent(_rightMargin, rv);
visitIfPresent(_topMargin, rv); visitIfPresent(_topMargin, rv);
visitIfPresent(_bottomMargin, rv); visitIfPresent(_bottomMargin, rv);
visitIfPresent(_pls, rv); for (RecordAggregate pls : _plsRecords) {
if (_plsContinues != null) { pls.visitContainedRecords(rv);
for (ContinueRecord cr : _plsContinues) {
visitIfPresent(cr, rv);
}
} }
visitIfPresent(_printSetup, rv); visitIfPresent(_printSetup, rv);
visitIfPresent(_bitmap, rv); visitIfPresent(_bitmap, rv);
@ -573,7 +595,6 @@ public final class PageSettingsBlock extends RecordAggregate {
/** /**
* HEADERFOOTER is new in 2007. Some apps seem to have scattered this record long after * HEADERFOOTER is new in 2007. Some apps seem to have scattered this record long after
* the {@link PageSettingsBlock} where it belongs. * the {@link PageSettingsBlock} where it belongs.
*
*/ */
public void addLateHeaderFooter(Record rec) { public void addLateHeaderFooter(Record rec) {
if (_headerFooter != null) { if (_headerFooter != null) {

View File

@ -27,6 +27,7 @@ import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.BOFRecord; import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BottomMarginRecord; import org.apache.poi.hssf.record.BottomMarginRecord;
import org.apache.poi.hssf.record.ContinueRecord;
import org.apache.poi.hssf.record.DimensionsRecord; import org.apache.poi.hssf.record.DimensionsRecord;
import org.apache.poi.hssf.record.EOFRecord; import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.FooterRecord; import org.apache.poi.hssf.record.FooterRecord;
@ -71,7 +72,6 @@ public final class TestPageSettingsBlock extends TestCase {
/** /**
* Bug 46840 occurred because POI failed to recognise HEADERFOOTER as part of the * Bug 46840 occurred because POI failed to recognise HEADERFOOTER as part of the
* {@link PageSettingsBlock}. * {@link PageSettingsBlock}.
*
*/ */
public void testHeaderFooter_bug46840() { public void testHeaderFooter_bug46840() {
@ -273,4 +273,46 @@ public final class TestPageSettingsBlock extends TestCase {
FooterRecord fr = (FooterRecord) outRecs[1]; FooterRecord fr = (FooterRecord) outRecs[1];
assertEquals("", fr.getText()); assertEquals("", fr.getText());
} }
/**
* Apparently it's OK to have more than one PLS record.
* Attachment 23866 from bug 47415 had a PageSettingsBlock with two PLS records. This file
* seems to open OK in Excel(2007) but both PLS records are removed (perhaps because the
* specified printers were not available on the testing machine). Since the example file does
* not upset Excel, POI will preserve multiple PLS records.</p>
*
* As of June 2009, PLS is still uninterpreted by POI
*/
public void testDuplicatePLS_bug47415() {
Record plsA = ur(UnknownRecord.PLS_004D, "BA AD F0 0D");
Record plsB = ur(UnknownRecord.PLS_004D, "DE AD BE EF");
Record contB1 = new ContinueRecord(HexRead.readFromString("FE ED"));
Record contB2 = new ContinueRecord(HexRead.readFromString("FA CE"));
Record[] recs = {
new HeaderRecord("&LSales Figures"),
new FooterRecord("&LInventory"),
new HCenterRecord(),
new VCenterRecord(),
plsA,
plsB, contB1, contB2, // make sure continuing PLS is still OK
};
RecordStream rs = new RecordStream(Arrays.asList(recs), 0);
PageSettingsBlock psb;
try {
psb = new PageSettingsBlock(rs);
} catch (RecordFormatException e) {
if ("Duplicate PageSettingsBlock record (sid=0x4d)".equals(e.getMessage())) {
throw new AssertionFailedError("Identified bug 47415");
}
throw e;
}
// serialize the PSB to see what records come out
RecordCollector rc = new RecordCollector();
psb.visitContainedRecords(rc);
Record[] outRecs = rc.getRecords();
// records were assembled in standard order, so this simple check is OK
assertTrue(Arrays.equals(recs, outRecs));
}
} }