<!-- Don't forget to update status.xml too! -->
<release version="3.5-beta6" date="2009-??-??">
- <action dev="POI-DEVELOPERS" type="fix">update cell type when setting cached formula result in XSSFCell</action>
+ <action dev="POI-DEVELOPERS" type="fix">46840 - PageSettingsBlock should include HEADERFOOTER record</action>
+ <action dev="POI-DEVELOPERS" type="fix">46885 - update cell type when setting cached formula result in XSSFCell</action>
<action dev="POI-DEVELOPERS" type="add">added modifiers for anchor type to XSSFClientAnchor</action>
<action dev="POI-DEVELOPERS" type="add">46772 - support built-in data formats in XSSFDataFormat</action>
<action dev="POI-DEVELOPERS" type="fix">46719 - fixed XSSFSheet.shiftRows to correctly preserve row heights</action>
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.5-beta6" date="2009-??-??">
- <action dev="POI-DEVELOPERS" type="fix">update cell type when setting cached formula result in XSSFCell</action>
+ <action dev="POI-DEVELOPERS" type="fix">46840 - PageSettingsBlock should include HEADERFOOTER record</action>
+ <action dev="POI-DEVELOPERS" type="fix">46885 - update cell type when setting cached formula result in XSSFCell</action>
<action dev="POI-DEVELOPERS" type="add">added modifiers for anchor type to XSSFClientAnchor</action>
<action dev="POI-DEVELOPERS" type="add">46772 - support built-in data formats in XSSFDataFormat</action>
<action dev="POI-DEVELOPERS" type="fix">46719 - fixed XSSFSheet.shiftRows to correctly preserve row heights</action>
} else if (windowTwo != null) {
// probably 'Custom View Settings' sub-stream which is found between
// USERSVIEWBEGIN(01AA) and USERSVIEWEND(01AB)
+ // TODO - create UsersViewAggregate to hold these sub-streams, and simplify this code a bit
// This happens three times in test sample file "29982.xls"
- if (rs.peekNextSid() != UnknownRecord.USERSVIEWEND_01AB) {
+ // Also several times in bugzilla samples 46840-23373 and 46840-23374
+ if (recSid == UnknownRecord.HEADER_FOOTER_089C) {
+ _psBlock.addLateHeaderFooter(rs.getNext());
+ } else if (rs.peekNextSid() != UnknownRecord.USERSVIEWEND_01AB) {
// not quite the expected situation
throw new RuntimeException("two Page Settings Blocks found in the same sheet");
}
public static final int SHEETEXT_0862 = 0x0862; // OOO calls this SHEETLAYOUT
public static final int SHEETPROTECTION_0867 = 0x0867;
public static final int RANGEPROTECTION_0868 = 0x0868;
+ public static final int HEADER_FOOTER_089C = 0x089C;
private int _sid;
private byte[] _rawData;
case 0x0897: return "GUIDTYPELIB";
case 0x089A: return "MTRSETTINGS";
case 0x089B: return "COMPRESSPICTURES";
- case 0x089C: return "HEADERFOOTER";
+ case HEADER_FOOTER_089C: return "HEADERFOOTER";
case 0x08A1: return "SHAPEPROPSSTREAM";
case 0x08A3: return "FORCEFULLCALCULATION";
case 0x08A4: return "SHAPEPROPSSTREAM";
private List<ContinueRecord> _plsContinues;
private PrintSetupRecord printSetup;
private Record _bitmap;
+ private Record _headerFooter;
public PageSettingsBlock(RecordStream rs) {
while(true) {
case UnknownRecord.PLS_004D:
case PrintSetupRecord.sid:
case UnknownRecord.BITMAP_00E9:
+ case UnknownRecord.HEADER_FOOTER_089C: // extra header/footer settings supported by Excel 2007
return true;
}
return false;
case UnknownRecord.BITMAP_00E9:
_bitmap = rs.getNext();
break;
+ case UnknownRecord.HEADER_FOOTER_089C:
+ _headerFooter = rs.getNext();
+ break;
default:
// all other record types are not part of the PageSettingsBlock
return false;
}
visitIfPresent(printSetup, rv);
visitIfPresent(_bitmap, rv);
+ visitIfPresent(_headerFooter, rv);
}
private static void visitIfPresent(Record r, RecordVisitor rv) {
if (r != null) {
public HCenterRecord getHCenter() {
return _hCenter;
}
+
+ /**
+ * HEADERFOOTER is new in 2007. Some apps seem to have scattered this record long after
+ * the {@link PageSettingsBlock} where it belongs.
+ *
+ */
+ public void addLateHeaderFooter(Record rec) {
+ if (_headerFooter != null) {
+ throw new IllegalStateException("This page settings block already has a header/footer record");
+ }
+ _headerFooter = rec;
+ }
}
package org.apache.poi.hssf.record.aggregates;
+import java.util.Arrays;
+
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.RecordStream;
+import org.apache.poi.hssf.model.Sheet;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.DimensionsRecord;
+import org.apache.poi.hssf.record.EOFRecord;
+import org.apache.poi.hssf.record.FooterRecord;
+import org.apache.poi.hssf.record.HeaderRecord;
+import org.apache.poi.hssf.record.NumberRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.UnknownRecord;
+import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector;
+import org.apache.poi.util.HexRead;
/**
* Tess for {@link PageSettingsBlock}
throw new AssertionFailedError("Identified bug 46548: PageSettingBlock missing PrintSetupRecord record");
}
}
+
+ /**
+ * Bug 46840 occurred because POI failed to recognise HEADERFOOTER as part of the
+ * {@link PageSettingsBlock}.
+ *
+ */
+ public void testHeaderFooter_bug46840() {
+
+ int rowIx = 5;
+ int colIx = 6;
+ NumberRecord nr = new NumberRecord();
+ nr.setRow(rowIx);
+ nr.setColumn((short) colIx);
+ nr.setValue(3.0);
+
+ Record[] recs = {
+ BOFRecord.createSheetBOF(),
+ new HeaderRecord("&LSales Figures"),
+ new FooterRecord("&LJanuary"),
+ ur(UnknownRecord.HEADER_FOOTER_089C, "9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 60 00 00 00 00 00 00 00 00"),
+ new DimensionsRecord(),
+ new WindowTwoRecord(),
+ ur(UnknownRecord.USERSVIEWBEGIN_01AA, "ED 77 3B 86 BC 3F 37 4C A9 58 60 23 43 68 54 4B 01 00 00 00 64 00 00 00 40 00 00 00 02 00 00 00 3D 80 04 00 00 00 00 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 3F FF FF 01 00"),
+ new HeaderRecord("&LSales Figures"),
+ new FooterRecord("&LJanuary"),
+ ur(UnknownRecord.HEADER_FOOTER_089C, "9C 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C4 60 00 00 00 00 00 00 00 00"),
+ ur(UnknownRecord.USERSVIEWEND_01AB, "01, 00"),
+
+ EOFRecord.instance,
+ };
+ RecordStream rs = new RecordStream(Arrays.asList(recs), 0);
+ Sheet sheet;
+ try {
+ sheet = Sheet.createSheet(rs);
+ } catch (RuntimeException e) {
+ if (e.getMessage().equals("two Page Settings Blocks found in the same sheet")) {
+ throw new AssertionFailedError("Identified bug 46480");
+ }
+ throw e;
+ }
+
+ RecordCollector rv = new RecordCollector();
+ sheet.visitContainedRecords(rv, rowIx);
+ Record[] outRecs = rv.getRecords();
+ assertEquals(13, outRecs.length);
+ }
+
+ private static UnknownRecord ur(int sid, String hexData) {
+ return new UnknownRecord(sid, HexRead.readFromString(hexData));
+ }
}