]> source.dussan.org Git - poi.git/commitdiff
Fix for bug 46840 - PageSettingsBlock should include HEADERFOOTER record
authorJosh Micich <josh@apache.org>
Mon, 23 Mar 2009 19:42:39 +0000 (19:42 +0000)
committerJosh Micich <josh@apache.org>
Mon, 23 Mar 2009 19:42:39 +0000 (19:42 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@757520 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/model/Sheet.java
src/java/org/apache/poi/hssf/record/UnknownRecord.java
src/java/org/apache/poi/hssf/record/aggregates/PageSettingsBlock.java
src/testcases/org/apache/poi/hssf/record/aggregates/TestPageSettingBlock.java

index fd101fb8f24992d6b846527a975801702d6153c8..0cb62592cb99b99c55e50e91ddede73f8d40fca6 100644 (file)
@@ -37,7 +37,8 @@
 
                <!-- 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>
index 3b3ba8e7ab6a29a72cd4862e1c081bfc4a417d21..bef81975faf37129ba4ab72feaa3982af04139f1 100644 (file)
@@ -34,7 +34,8 @@
        <!-- 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>
index 80adc84579387fae08090f8251ffbc6913fc090e..8256556420a786cc724f230ed0e8b3a0324a5325 100644 (file)
@@ -222,8 +222,12 @@ public final class Sheet implements Model {
                     } 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");
                         }
index e3cef59d9f65757e558f3e023cebbc002ce69cd8..0a7209332523d3da7c94b248e99c090122194e96 100644 (file)
@@ -48,6 +48,7 @@ public final class UnknownRecord extends StandardRecord {
        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;
@@ -181,7 +182,7 @@ public final class UnknownRecord extends StandardRecord {
                        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";
index 828c0e31f6a91b476beb9bce388236336a235482..1d818aa03859f71b3d0c8f4076dc91450f9bf1b6 100644 (file)
@@ -71,6 +71,7 @@ public final class PageSettingsBlock extends RecordAggregate {
        private List<ContinueRecord> _plsContinues;
        private PrintSetupRecord printSetup;
        private Record _bitmap;
+       private Record _headerFooter;
 
        public PageSettingsBlock(RecordStream rs) {
                while(true) {
@@ -112,6 +113,7 @@ public final class PageSettingsBlock extends RecordAggregate {
                        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;
@@ -164,6 +166,9 @@ public final class PageSettingsBlock extends RecordAggregate {
                        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;
@@ -224,6 +229,7 @@ public final class PageSettingsBlock extends RecordAggregate {
                }
                visitIfPresent(printSetup, rv);
                visitIfPresent(_bitmap, rv);
+               visitIfPresent(_headerFooter, rv);
        }
        private static void visitIfPresent(Record r, RecordVisitor rv) {
                if (r != null) {
@@ -523,4 +529,16 @@ public final class PageSettingsBlock extends RecordAggregate {
        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;
+       }
 }
index 518ed5f308e5535682b7caa66605babe626da93b..07a49fd1e6d0669c433c306d099919a538b29773 100644 (file)
 
 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}
@@ -47,4 +62,54 @@ public final class TestPageSettingBlock extends TestCase {
                        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));
+       }
 }