]> source.dussan.org Git - poi.git/commitdiff
Fix bug #45590: Header/footer extraction for .ppt files saved in Office 2007
authorYegor Kozlov <yegor@apache.org>
Tue, 12 Aug 2008 06:55:10 +0000 (06:55 +0000)
committerYegor Kozlov <yegor@apache.org>
Tue, 12 Aug 2008 06:55:10 +0000 (06:55 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@685054 13f79535-47bb-0310-9956-ffa450edef68

13 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java
src/scratchpad/src/org/apache/poi/hslf/model/MasterSheet.java
src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java
src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
src/scratchpad/src/org/apache/poi/hslf/record/OEPlaceholderAtom.java
src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
src/scratchpad/src/org/apache/poi/hslf/record/RoundTripHFPlaceholder12.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
src/scratchpad/testcases/org/apache/poi/hslf/data/headers_footers_2007.ppt [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hslf/model/TestHeadersFooters.java

index 62b53e54102eed45ab18cb4a5e0e4ab59cf0ff77..985db6ab9f255e841ae91c7c87a28fc7ba377df7 100644 (file)
@@ -37,6 +37,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45590 - Fix for Header/footer extraction for .ppt files saved in Office 2007</action>
            <action dev="POI-DEVELOPERS" type="fix">Big improvement in how HWPF handles unicode text, and more sanity checking of text ranges within HWPF</action>
            <action dev="POI-DEVELOPERS" type="add">Include headers and footers int he extracted text from HWPF's WordExtractor</action>
            <action dev="POI-DEVELOPERS" type="add">Added support to HWPF for headers and footers</action>
index a020a892a25750e008fddf8056eb2a66fe70f1e0..d762f1e5a5173d465e87151ca3c2a5ae1f023742 100644 (file)
@@ -34,6 +34,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45590 - Fix for Header/footer extraction for .ppt files saved in Office 2007</action>
            <action dev="POI-DEVELOPERS" type="fix">Big improvement in how HWPF handles unicode text, and more sanity checking of text ranges within HWPF</action>
            <action dev="POI-DEVELOPERS" type="add">Include headers and footers int he extracted text from HWPF's WordExtractor</action>
            <action dev="POI-DEVELOPERS" type="add">Added support to HWPF for headers and footers</action>
index 90aee3421d0e14b9ce890e2be52a04978bd93468..38b0dff9e20039238acda6769e1cb88f7238740a 100644 (file)
@@ -32,11 +32,22 @@ public class HeadersFooters {
     private HeadersFootersContainer _container;\r
     private boolean _newRecord;\r
     private SlideShow _ppt;\r
+    private Sheet _sheet;\r
+    private boolean _ppt2007;\r
 \r
-    public HeadersFooters(HeadersFootersContainer rec, SlideShow ppt, boolean newRecord){\r
+\r
+    public HeadersFooters(HeadersFootersContainer rec, SlideShow ppt, boolean newRecord, boolean isPpt2007){\r
         _container = rec;\r
         _newRecord = newRecord;\r
         _ppt = ppt;\r
+        _ppt2007 = isPpt2007;\r
+    }\r
+\r
+    public HeadersFooters(HeadersFootersContainer rec, Sheet sheet, boolean newRecord, boolean isPpt2007){\r
+        _container = rec;\r
+        _newRecord = newRecord;\r
+        _sheet = sheet;\r
+        _ppt2007 = isPpt2007;\r
     }\r
 \r
     /**\r
@@ -45,8 +56,8 @@ public class HeadersFooters {
      * @return Headers's text\r
      */\r
     public String getHeaderText(){\r
-       CString cs = _container.getHeaderAtom();\r
-       return cs == null ? null : cs.getText();\r
+        CString cs = _container == null ? null : _container.getHeaderAtom();\r
+        return getPlaceholderText(OEPlaceholderAtom.MasterHeader, cs);\r
     }\r
 \r
     /**\r
@@ -70,8 +81,8 @@ public class HeadersFooters {
      * @return Footer's text\r
      */\r
     public String getFooterText(){\r
-        CString cs = _container.getFooterAtom();\r
-        return cs == null ? null : cs.getText();\r
+        CString cs = _container == null ? null : _container.getFooterAtom();\r
+        return getPlaceholderText(OEPlaceholderAtom.MasterFooter, cs);\r
     }\r
 \r
     /**\r
@@ -95,8 +106,8 @@ public class HeadersFooters {
      * @return custom user date\r
      */\r
     public String getDateTimeText(){\r
-        CString cs = _container.getUserDateAtom();\r
-        return cs == null ? null : cs.getText();\r
+        CString cs = _container == null ? null : _container.getUserDateAtom();\r
+        return getPlaceholderText(OEPlaceholderAtom.MasterDate, cs);\r
     }\r
 \r
     /**\r
@@ -119,7 +130,7 @@ public class HeadersFooters {
      * whether the footer text is displayed.\r
      */\r
     public boolean isFooterVisible(){\r
-        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasFooter);\r
+        return isVisible(HeadersFootersAtom.fHasFooter, OEPlaceholderAtom.MasterFooter);\r
     }\r
 \r
     /**\r
@@ -134,7 +145,7 @@ public class HeadersFooters {
      * whether the header text is displayed.\r
      */\r
     public boolean isHeaderVisible(){\r
-        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasHeader);\r
+        return isVisible(HeadersFootersAtom.fHasHeader, OEPlaceholderAtom.MasterHeader);\r
     }\r
 \r
     /**\r
@@ -149,7 +160,7 @@ public class HeadersFooters {
      * whether the date is displayed in the footer.\r
      */\r
     public boolean isDateTimeVisible(){\r
-        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasDate);\r
+        return isVisible(HeadersFootersAtom.fHasDate, OEPlaceholderAtom.MasterDate);\r
     }\r
 \r
     /**\r
@@ -164,7 +175,7 @@ public class HeadersFooters {
      * whether the custom user date is used instead of today's date.\r
      */\r
     public boolean isUserDateVisible(){\r
-        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasUserDate);\r
+        return isVisible(HeadersFootersAtom.fHasUserDate, OEPlaceholderAtom.MasterDate);\r
     }\r
 \r
     /**\r
@@ -179,7 +190,7 @@ public class HeadersFooters {
      * whether the slide number is displayed in the footer.\r
      */\r
     public boolean isSlideNumberVisible(){\r
-        return _container.getHeadersFootersAtom().getFlag(HeadersFootersAtom.fHasSlideNumber);\r
+        return isVisible(HeadersFootersAtom.fHasSlideNumber, OEPlaceholderAtom.MasterSlideNumber);\r
     }\r
 \r
     /**\r
@@ -225,4 +236,32 @@ public class HeadersFooters {
         doc.addChildAfter(_container, lst);\r
         _newRecord = false;\r
     }\r
+\r
+    private boolean isVisible(int flag, int placeholderId){\r
+        boolean visible;\r
+        if(_ppt2007){\r
+            Sheet master = _sheet != null ? _sheet : _ppt.getSlidesMasters()[0];\r
+            TextShape placeholder = master.getPlaceholder(placeholderId);\r
+            visible = placeholder != null && placeholder.getText() != null;\r
+        } else {\r
+            visible = _container.getHeadersFootersAtom().getFlag(flag);\r
+        }\r
+        return visible;\r
+    }\r
+\r
+    private String getPlaceholderText(int placeholderId, CString cs){\r
+        String text = null;\r
+        if(_ppt2007){\r
+            Sheet master = _sheet != null ? _sheet : _ppt.getSlidesMasters()[0];\r
+            TextShape placeholder = master.getPlaceholder(placeholderId);\r
+            if(placeholder != null) text = placeholder.getText();\r
+\r
+            //default text in master placeholders is not visible\r
+            if("*".equals(text)) text = null;\r
+        } else {\r
+            text = cs == null ? null : cs.getText();\r
+        }\r
+        return text;\r
+    }\r
+\r
 }\r
index 17c1d1c23f49e6f622c8bdaecfd92870a364e7fc..501cf65bdf414b371f2c03be5bd0efce2b41a6f3 100644 (file)
@@ -19,6 +19,7 @@ package org.apache.poi.hslf.model;
 import org.apache.poi.hslf.record.SheetContainer;
 import org.apache.poi.hslf.record.Record;
 import org.apache.poi.hslf.record.RecordTypes;
+import org.apache.poi.hslf.record.OEPlaceholderAtom;
 import org.apache.poi.hslf.model.textproperties.TextProp;
 
 /**
@@ -54,20 +55,4 @@ public abstract class MasterSheet extends Sheet {
         return tx.getPlaceholderAtom() != null;
     }
 
-    /**
-     * Return placeholder by text type
-     */
-    public TextShape getPlaceholder(int type){
-        Shape[] shape = getShapes();
-        for (int i = 0; i < shape.length; i++) {
-            if(shape[i] instanceof TextShape){
-                TextShape tx = (TextShape)shape[i];
-                TextRun run = tx.getTextRun();
-                if(run != null && run.getRunType() == type){
-                    return tx;
-                }
-            }
-        }
-        return null;
-    }
 }
index 6eb84ca2e75f93a0984ee739550e2c4011230c6a..ccbc03829fae15b0a98725b78edc3f58f5ee2063 100644 (file)
@@ -362,4 +362,83 @@ public abstract class Sheet {
     public void draw(Graphics2D graphics){
 
     }
+
+    /**
+     * Return placeholder by text type
+     *
+     * @param type  type of text, See {@link org.apache.poi.hslf.record.TextHeaderAtom}
+     * @return  <code>TextShape</code> or <code>null</code>
+     */
+    public TextShape getPlaceholderByTextType(int type){
+        Shape[] shape = getShapes();
+        for (int i = 0; i < shape.length; i++) {
+            if(shape[i] instanceof TextShape){
+                TextShape tx = (TextShape)shape[i];
+                TextRun run = tx.getTextRun();
+                if(run != null && run.getRunType() == type){
+                    return tx;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Search text placeholer by its type
+     *
+     * @param type  type of placeholder to search. See {@link org.apache.poi.hslf.record.OEPlaceholderAtom}
+     * @return  <code>TextShape</code> or <code>null</code>
+     */
+    public TextShape getPlaceholder(int type){
+        Shape[] shape = getShapes();
+        for (int i = 0; i < shape.length; i++) {
+            if(shape[i] instanceof TextShape){
+                TextShape tx = (TextShape)shape[i];
+                int placeholderId = 0;
+                OEPlaceholderAtom oep = tx.getPlaceholderAtom();
+                if(oep != null) {
+                    placeholderId = oep.getPlaceholderId();
+                } else {
+                    //special case for files saved in Office 2007
+                    RoundTripHFPlaceholder12 hldr = (RoundTripHFPlaceholder12)tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID);
+                    if(hldr != null) placeholderId = hldr.getPlaceholderId();
+                }
+                if(placeholderId == type){
+                    return tx;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return programmable tag associated with this sheet, e.g. <code>___PPT12</code>.
+     *
+     * @return programmable tag associated with this sheet.
+     */
+    public String getProgrammableTag(){
+        String tag = null;
+        RecordContainer progTags = (RecordContainer)
+                getSheetContainer().findFirstOfType(
+                            RecordTypes.ProgTags.typeID
+        );
+        if(progTags != null) {
+            RecordContainer progBinaryTag = (RecordContainer)
+                progTags.findFirstOfType(
+                        RecordTypes.ProgBinaryTag.typeID
+            );
+            if(progBinaryTag != null) {
+                CString binaryTag = (CString)
+                    progBinaryTag.findFirstOfType(
+                            RecordTypes.CString.typeID
+                );
+                if(binaryTag != null) tag = binaryTag.getText();
+            }
+        }
+
+        return tag;
+
+    }
+
+
 }
index 48f2fdefccdf911a5e34d0ed041c53e525295d4e..c524f31f70a2811fd1d04827f5651b546a3fd7e2 100644 (file)
@@ -440,14 +440,24 @@ public class Slide extends Sheet
      public HeadersFooters getHeadersFooters(){
         HeadersFootersContainer hdd = null;
         Record[] ch = getSheetContainer().getChildRecords();
+        boolean ppt2007 = false;
         for (int i = 0; i < ch.length; i++) {
             if(ch[i] instanceof HeadersFootersContainer){
                 hdd = (HeadersFootersContainer)ch[i];
-                break;
+            } else if (ch[i].getRecordType() == RecordTypes.RoundTripContentMasterId.typeID){
+                ppt2007 = true;
             }
         }
         boolean newRecord = false;
-        if(hdd == null) return getSlideShow().getSlideHeadersFooters();
-        else return new HeadersFooters(hdd, getSlideShow(), newRecord);
+        if(hdd == null && !ppt2007) {
+            return getSlideShow().getSlideHeadersFooters();
+        }
+        else {
+            if(hdd == null) {
+                hdd = new HeadersFootersContainer(HeadersFootersContainer.SlideHeadersFootersContainer);
+                newRecord = true;
+            }
+            return new HeadersFooters(hdd, this, newRecord, ppt2007);
+        }
     }
 }
index 44cb2b2412124828b8618e19bf732606cc3fef8c..a9975ab370bd83c9c2b1c856f678d3c6637ce7f9 100755 (executable)
@@ -269,7 +269,7 @@ public abstract class TextShape extends SimpleShape {
             int type = getTextRun().getRunType();
             MasterSheet master = getSheet().getMasterSheet();
             if(master != null){
-                TextShape masterShape = master.getPlaceholder(type);
+                TextShape masterShape = master.getPlaceholderByTextType(type);
                 if(masterShape != null) valign = masterShape.getVerticalAlignment();
             } else {
                 //not found in the master sheet. Use the hardcoded defaults.
index 62a624af9d0af44c3bd826934e626c4875424c32..9bfae4fccb4d76f6fa946c6331b937765b0be5eb 100644 (file)
@@ -26,7 +26,7 @@ import java.io.OutputStream;
 /**
  * OEPlaceholderAtom (3011).
  * <p>
- *  Atom that describes the placeholder.
+ *  An atom record that specifies whether a shape is a placeholder shape.
  * </p>
  *
  * @author Yegor Kozlov
@@ -34,61 +34,169 @@ import java.io.OutputStream;
 
 public class OEPlaceholderAtom extends RecordAtom{
 
+    /**
+     * The full size of the master body text placeholder shape.
+     */
     public static final int PLACEHOLDER_FULLSIZE = 0;
+
+    /**
+     * Half of the size of the master body text placeholder shape.
+     */
     public static final int PLACEHOLDER_HALFSIZE = 1;
+
+    /**
+     * A quarter of the size of the master body text placeholder shape.
+     */
     public static final int PLACEHOLDER_QUARTSIZE = 2;
 
+    /**
+     * MUST NOT be used for this field.
+     */
     public static final byte None = 0;
 
+    /**
+     * The corresponding shape contains the master title text.
+     * The corresponding slide MUST be a main master slide.
+     */
     public static final byte MasterTitle = 1;
 
+    /**
+     * The corresponding shape contains the master body text.
+     * The corresponding slide MUST be a main master slide.
+     */
     public static final byte MasterBody = 2;
 
+    /**
+     * The corresponding shape contains the master center title text.
+     * The corresponding slide MUST be a title master slide.
+     */
     public static final byte MasterCenteredTitle = 3;
 
-    public static final byte MasterNotesSlideImage = 4;
+    /**
+     * The corresponding shape contains the master sub-title text.
+     * The corresponding slide MUST be a title master slide.
+     */
+    public static final byte MasterSubTitle = 4;
 
-    public static final byte MasterNotesBodyImage = 5;
+    /**
+     * The corresponding shape contains the shared properties for slide image shapes.
+     * The corresponding slide MUST be a notes master slide.
+     */
+    public static final byte MasterNotesSlideImage = 5;
 
-    public static final byte MasterDate = 6;
+    /**
+     * The corresponding shape contains the master body text.
+     * The corresponding slide MUST be a notes master slide.
+     */
+    public static final byte MasterNotesBody = 6;
 
-    public static final byte MasterSlideNumber = 7;
+    /**
+     * The corresponding shape contains the date text field.
+     * The corresponding slide MUST be a main master slide, title master slide, notes master slide, or handout master slide.
+     */
+    public static final byte MasterDate = 7;
 
-    public static final byte MasterFooter = 8;
+    /**
+     * The corresponding shape contains a slide number text field.
+     * The corresponding slide MUST be a main master slide, title master slide, notes master slide, or handout master slide.
+     */
+    public static final byte MasterSlideNumber = 8;
 
-    public static final byte MasterHeader = 9;
+    /**
+     * The corresponding shape contains a footer text field.
+     * The corresponding slide MUST be a main master slide, title master slide, notes master slide, or handout master slide.
+     */
+    public static final byte MasterFooter = 9;
 
-    public static final byte MasterSubtitle = 10;
+    /**
+     * The corresponding shape contains a header text field. 
+     * The corresponding slide must be a notes master slide or handout master slide.
+     */
+    public static final byte MasterHeader = 10;
 
-    public static final byte GenericTextObject = 11;
+    /**
+     * The corresponding shape contains a presentation slide image.
+     * The corresponding slide MUST be a notes slide.
+     */
+    public static final byte NotesSlideImage = 11;
 
-    public static final byte Title = 12;
+    /**
+     * The corresponding shape contains the notes text.
+     * The corresponding slide MUST be a notes slide.
+     */
+    public static final byte NotesBody = 12;
 
-    public static final byte Body = 13;
+    /**
+     *  The corresponding shape contains the title text.
+     *  The corresponding slide MUST be a presentation slide.
+     */
+    public static final byte Title = 13;
 
-    public static final byte NotesBody = 14;
+    /**
+     * The corresponding shape contains the body text.
+     * The corresponding slide MUST be a presentation slide.
+     */
+    public static final byte Body = 14;
 
+    /**
+     * The corresponding shape contains the title text.
+     * The corresponding slide MUST be a presentation slide.
+     */
     public static final byte CenteredTitle = 15;
 
+    /**
+     * The corresponding shape contains the sub-title text.
+     * The corresponding slide MUST be a presentation slide.
+     */
     public static final byte Subtitle = 16;
 
+    /**
+     * The corresponding shape contains the title text with vertical text flow.
+     * The corresponding slide MUST be a presentation slide.
+     */
     public static final byte VerticalTextTitle = 17;
 
+    /**
+     * The corresponding shape contains the body text with vertical text flow.
+     * The corresponding slide MUST be a presentation slide.
+     */
     public static final byte VerticalTextBody = 18;
 
-    public static final byte NotesSlideImage = 19;
-
-    public static final byte Object = 20;
+    /**
+     *  The corresponding shape contains a generic object.
+     *  The corresponding slide MUST be a presentation slide.
+     */
+    public static final byte Object = 19;
 
-    public static final byte Graph = 21;
+    /**
+     * The corresponding shape contains a chart object.
+     * The corresponding slide MUST be a presentation slide.
+     */
+    public static final byte Graph = 20;
 
-    public static final byte Table = 22;
+    /**
+     * The corresponding shape contains a table object.
+     * The corresponding slide MUST be a presentation slide.
+     */
+    public static final byte Table = 21;
 
-    public static final byte ClipArt = 23;
+    /**
+     * The corresponding shape contains a clipart object.
+     * The corresponding slide MUST be a presentation slide.
+     */
+    public static final byte ClipArt = 22;
 
-    public static final byte OrganizationChart = 24;
+    /**
+     * The corresponding shape contains an organization chart object.
+     * The corresponding slide MUST be a presentation slide.
+     */
+    public static final byte OrganizationChart = 23;
 
-    public static final byte MediaClip = 25;
+    /**
+     * The corresponding shape contains a media object.
+     * The corresponding slide MUST be a presentation slide.
+     */
+    public static final byte MediaClip = 24;
 
        private byte[] _header;
 
@@ -116,11 +224,13 @@ public class OEPlaceholderAtom extends RecordAtom{
      */
        protected OEPlaceholderAtom(byte[] source, int start, int len) {
                _header = new byte[8];
-               System.arraycopy(source,start,_header,0,8);
+        int offset = start;
+        System.arraycopy(source,start,_header,0,8);
+        offset += _header.length;
 
-        placementId = LittleEndian.getInt(source, start);
-        placeholderId = LittleEndian.getUnsignedByte(source, start+4);
-        placeholderSize = LittleEndian.getUnsignedByte(source, start+5);
+        placementId = LittleEndian.getInt(source, offset); offset += 4;
+        placeholderId = LittleEndian.getUnsignedByte(source, offset); offset++;
+        placeholderSize = LittleEndian.getUnsignedByte(source, offset); offset++;
        }
 
     /**
@@ -130,6 +240,11 @@ public class OEPlaceholderAtom extends RecordAtom{
 
     /**
      * Returns the placement Id.
+     * <p>
+     * The placement Id is a number assigned to the placeholder. It goes from -1 to the number of placeholders.
+     * It SHOULD be unique among all PlacholderAtom records contained in the corresponding slide.
+     * The value 0xFFFFFFFF specifies that the corresponding shape is not a placeholder shape.
+     * </p>
      *
      * @return the placement Id.
      */
@@ -139,6 +254,11 @@ public class OEPlaceholderAtom extends RecordAtom{
 
     /**
      * Sets the placement Id.
+     * <p>
+     * The placement Id is a number assigned to the placeholder. It goes from -1 to the number of placeholders.
+     * It SHOULD be unique among all PlacholderAtom records contained in the corresponding slide.
+     * The value 0xFFFFFFFF specifies that the corresponding shape is not a placeholder shape.
+     * </p>
      *
      * @param id the placement Id.
      */
@@ -149,6 +269,11 @@ public class OEPlaceholderAtom extends RecordAtom{
     /**
      * Returns the placeholder Id.
      *
+     * <p>
+     * placeholder Id specifies the type of the placeholder shape.
+     * The value MUST be one of the static constants defined in this class
+     * </p>
+     *
      * @return the placeholder Id.
      */
     public int getPlaceholderId(){
@@ -158,6 +283,10 @@ public class OEPlaceholderAtom extends RecordAtom{
     /**
      * Sets the placeholder Id.
      *
+     * <p>
+     * placeholder Id specifies the type of the placeholder shape.
+     * The value MUST be one of the static constants defined in this class
+     * </p>
      * @param id the placeholder Id.
      */
     public void setPlaceholderId(byte id){
index d7a664725e9e12097ecf52d45d212aec33ed8c38..9c867d5ab0fb07bf24297dd25d4c64c029bf5e0c 100644 (file)
@@ -162,6 +162,17 @@ public class RecordTypes {
     // Records ~12050 seem to be related to Document Encryption
     public static final Type DocumentEncryptionAtom = new Type(12052,DocumentEncryptionAtom.class);
 
+    public static final Type OriginalMainMasterId = new Type(1052,null);
+    public static final Type CompositeMasterId = new Type(1052,null);
+    public static final Type RoundTripContentMasterInfo12 = new Type(1054,null);
+    public static final Type RoundTripShapeId12 = new Type(1055,null);
+    public static final Type RoundTripHFPlaceholder12 = new Type(1056,RoundTripHFPlaceholder12.class);
+    public static final Type RoundTripContentMasterId = new Type(1058,null);
+    public static final Type RoundTripOArtTextStyles12 = new Type(1059,null);
+    public static final Type RoundTripShapeCheckSumForCustomLayouts12 = new Type(1062,null);
+    public static final Type RoundTripNotesMasterTextStyles12 = new Type(1063,null);
+    public static final Type RoundTripCustomTableStyles12 = new Type(1064,null);
+
     //records greater then 0xF000 belong to with Microsoft Office Drawing format also known as Escher
     public static final int EscherDggContainer = 0xf000;
     public static final int EscherDgg = 0xf006;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/RoundTripHFPlaceholder12.java b/src/scratchpad/src/org/apache/poi/hslf/record/RoundTripHFPlaceholder12.java
new file mode 100644 (file)
index 0000000..0f49b5b
--- /dev/null
@@ -0,0 +1,99 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+        \r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.util.Date;\r
+\r
+import org.apache.poi.hslf.util.SystemTimeUtils;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+/**\r
+ * An atom record that specifies that a shape is a header or footer placeholder shape\r
+ *\r
+ * @since  PowerPoint 2007\r
+ * @author Yegor Kozlov\r
+ */\r
+\r
+public class RoundTripHFPlaceholder12 extends RecordAtom\r
+{\r
+    /**\r
+     * Record header.\r
+     */\r
+    private byte[] _header;\r
+\r
+    /**\r
+     * Specifies the placeholder shape ID.\r
+     *\r
+     * MUST be {@link OEPlaceholderAtom#MasterDate},  {@link OEPlaceholderAtom#MasterSlideNumber}, \r
+     * {@link OEPlaceholderAtom#MasterFooter}, or {@link OEPlaceholderAtom#MasterHeader}\r
+     */\r
+    private byte _placeholderId;\r
+\r
+    /**\r
+     * Constructs the comment atom record from its source data.\r
+     *\r
+     * @param source the source data as a byte array.\r
+     * @param start the start offset into the byte array.\r
+     * @param len the length of the slice in the byte array.\r
+     */\r
+    protected RoundTripHFPlaceholder12(byte[] source, int start, int len) {\r
+        // Get the header.\r
+        _header = new byte[8];\r
+        System.arraycopy(source,start,_header,0,8);\r
+\r
+        // Get the record data.\r
+        _placeholderId = source[start+8];\r
+    }\r
+\r
+    /**\r
+     * Gets the comment number (note - each user normally has their own count).\r
+     * @return the comment number.\r
+     */\r
+    public int getPlaceholderId() {\r
+        return _placeholderId;\r
+    }\r
+\r
+    /**\r
+     * Sets the comment number (note - each user normally has their own count).\r
+     * @param number the comment number.\r
+     */\r
+    public void setPlaceholderId(int number) {\r
+        _placeholderId = (byte)number;\r
+    }\r
+\r
+    /**\r
+     * Gets the record type.\r
+     * @return the record type.\r
+     */\r
+    public long getRecordType() { return RecordTypes.RoundTripHFPlaceholder12.typeID; }\r
+\r
+    /**\r
+     * Write the contents of the record back, so it can be written\r
+     * to disk\r
+     *\r
+     * @param out the output stream to write to.\r
+     * @throws java.io.IOException if an error occurs.\r
+     */\r
+    public void writeOut(OutputStream out) throws IOException {\r
+        out.write(_header);\r
+        out.write(_placeholderId);\r
+    }\r
+}
\ No newline at end of file
index 1b2b9f5eeb6bab497519c70b78c3a8565c402334..a546d0444c1d26adb3027647a1dc4ca13a6099c6 100644 (file)
@@ -37,14 +37,7 @@ import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.hslf.HSLFSlideShow;
 import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
 import org.apache.poi.hslf.exceptions.HSLFException;
-import org.apache.poi.hslf.model.HeadersFooters;
-import org.apache.poi.hslf.model.Notes;
-import org.apache.poi.hslf.model.PPFont;
-import org.apache.poi.hslf.model.Picture;
-import org.apache.poi.hslf.model.Shape;
-import org.apache.poi.hslf.model.Slide;
-import org.apache.poi.hslf.model.SlideMaster;
-import org.apache.poi.hslf.model.TitleMaster;
+import org.apache.poi.hslf.model.*;
 import org.apache.poi.hslf.record.Document;
 import org.apache.poi.hslf.record.DocumentAtom;
 import org.apache.poi.hslf.record.FontCollection;
@@ -843,6 +836,10 @@ public final class SlideShow {
      * @return Header / Footer settings for slides
      */
     public HeadersFooters getSlideHeadersFooters(){
+        //detect if this ppt was saved in Office2007
+        String tag = getSlidesMasters()[0].getProgrammableTag();
+        boolean ppt2007 = "___PPT12".equals(tag);
+
         HeadersFootersContainer hdd = null;
         Record[] ch = _documentRecord.getChildRecords();
         for (int i = 0; i < ch.length; i++) {
@@ -857,7 +854,7 @@ public final class SlideShow {
             hdd = new HeadersFootersContainer(HeadersFootersContainer.SlideHeadersFootersContainer);
             newRecord = true;
         }
-        return new HeadersFooters(hdd, this, newRecord);
+        return new HeadersFooters(hdd, this, newRecord, ppt2007);
     }
 
     /**
@@ -866,6 +863,10 @@ public final class SlideShow {
      * @return Header / Footer settings for notes
      */
     public HeadersFooters getNotesHeadersFooters(){
+        //detect if this ppt was saved in Office2007
+        String tag = getSlidesMasters()[0].getProgrammableTag();
+        boolean ppt2007 = "___PPT12".equals(tag);
+
         HeadersFootersContainer hdd = null;
         Record[] ch = _documentRecord.getChildRecords();
         for (int i = 0; i < ch.length; i++) {
@@ -873,13 +874,18 @@ public final class SlideShow {
                     ((HeadersFootersContainer)ch[i]).getOptions() == HeadersFootersContainer.NotesHeadersFootersContainer){
                 hdd = (HeadersFootersContainer)ch[i];
                 break;
-            }
+           }
         }
         boolean newRecord = false;
         if(hdd == null) {
             hdd = new HeadersFootersContainer(HeadersFootersContainer.NotesHeadersFootersContainer);
             newRecord = true;
         }
-        return new HeadersFooters(hdd, this, newRecord);
+        if(ppt2007 && _notes.length > 0){
+            return new HeadersFooters(hdd, _notes[0], newRecord, ppt2007);
+        } else {
+            return new HeadersFooters(hdd, this, newRecord, ppt2007);
+        }
     }
+
 }
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/headers_footers_2007.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/headers_footers_2007.ppt
new file mode 100644 (file)
index 0000000..51b2c53
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/headers_footers_2007.ppt differ
index 8b1cdbe09e63193ce2cf369599032aa5244d6a3a..39255d3e8b03b52f2f34d42d4e79542a0b4e5568 100644 (file)
@@ -77,6 +77,112 @@ public class TestHeadersFooters extends TestCase
         assertEquals("custom date format", hd2.getDateTimeText());\r
     }\r
 \r
+    /**\r
+     * If Headers / Footers are not set, all the getters should return <code>false</code> or <code>null</code>\r
+     */\r
+    public void testReadNoHeadersFooters() throws Exception\r
+    {\r
+        File file = new File(cwd, "basic_test_ppt_file.ppt");\r
+        FileInputStream is = new FileInputStream(file);\r
+        SlideShow ppt = new SlideShow(is);\r
+        is.close();\r
+\r
+        HeadersFooters slideHdd = ppt.getSlideHeadersFooters();\r
+        assertFalse(slideHdd.isFooterVisible());\r
+        assertNull(slideHdd.getFooterText());\r
+        assertFalse(slideHdd.isSlideNumberVisible());\r
+        assertFalse(slideHdd.isHeaderVisible());\r
+        assertNull(slideHdd.getHeaderText());\r
+        assertFalse(slideHdd.isUserDateVisible());\r
+        assertNull(slideHdd.getDateTimeText());\r
+\r
+\r
+        HeadersFooters notesHdd = ppt.getNotesHeadersFooters();\r
+        assertFalse(notesHdd.isFooterVisible());\r
+        assertNull(notesHdd.getFooterText());\r
+        assertFalse(notesHdd.isHeaderVisible());\r
+        assertNull(notesHdd.getHeaderText());\r
+        assertFalse(notesHdd.isUserDateVisible());\r
+        assertNull(notesHdd.getDateTimeText());\r
+\r
+        Slide[] slide = ppt.getSlides();\r
+        for(int i=0 ; i < slide.length; i++){\r
+            HeadersFooters hd1 = slide[i].getHeadersFooters();\r
+            assertFalse(hd1.isFooterVisible());\r
+            assertNull(hd1.getFooterText());\r
+            assertFalse(hd1.isHeaderVisible());\r
+            assertNull(hd1.getHeaderText());\r
+            assertFalse(hd1.isUserDateVisible());\r
+            assertNull(hd1.getDateTimeText());\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Test extraction of headers / footers from PPTs saved in Office 2007\r
+     */\r
+    public void testRead2007() throws Exception\r
+    {\r
+        File file = new File(cwd, "headers_footers_2007.ppt");\r
+        FileInputStream is = new FileInputStream(file);\r
+        SlideShow ppt = new SlideShow(is);\r
+        is.close();\r
+\r
+        HeadersFooters slideHdd = ppt.getSlideHeadersFooters();\r
+        assertTrue(slideHdd.isFooterVisible());\r
+        assertEquals("THE FOOTER TEXT", slideHdd.getFooterText());\r
+        assertTrue(slideHdd.isSlideNumberVisible());\r
+        assertFalse(slideHdd.isHeaderVisible());\r
+        assertNull(slideHdd.getHeaderText());\r
+        assertTrue(slideHdd.isUserDateVisible());\r
+        assertEquals("Wednesday, August 06, 2008", slideHdd.getDateTimeText());\r
+\r
+\r
+        HeadersFooters notesHdd = ppt.getNotesHeadersFooters();\r
+        assertTrue(notesHdd.isFooterVisible());\r
+        assertEquals("THE NOTES FOOTER TEXT", notesHdd.getFooterText());\r
+        assertTrue(notesHdd.isHeaderVisible());\r
+        assertEquals("THE NOTES HEADER TEXT", notesHdd.getHeaderText());\r
+        assertTrue(notesHdd.isUserDateVisible());\r
+        assertTrue(notesHdd.isDateTimeVisible());\r
+        //TODO: depending on the formatId getDateTimeText() should return formatted date\r
+        //assertEquals("08/12/08", notesHdd.getDateTimeText());\r
+\r
+        //per-slide headers / footers\r
+        Slide[] slide = ppt.getSlides();\r
+        //the first slide uses presentation-scope headers / footers\r
+        HeadersFooters hd1 = slide[0].getHeadersFooters();\r
+        assertTrue(hd1.isFooterVisible());\r
+        assertEquals("THE FOOTER TEXT", hd1.getFooterText());\r
+        assertTrue(hd1.isSlideNumberVisible());\r
+        assertFalse(hd1.isHeaderVisible());\r
+        assertNull(hd1.getHeaderText());\r
+        assertTrue(hd1.isUserDateVisible());\r
+        assertTrue(hd1.isDateTimeVisible());\r
+        assertEquals("Wednesday, August 06, 2008", hd1.getDateTimeText());\r
+\r
+        //the second slide uses custom per-slide headers / footers\r
+        HeadersFooters hd2 = slide[1].getHeadersFooters();\r
+        assertTrue(hd2.isFooterVisible());\r
+        assertEquals("THE FOOTER TEXT FOR SLIDE 2", hd2.getFooterText());\r
+        assertTrue(hd2.isSlideNumberVisible());\r
+        assertFalse(hd2.isHeaderVisible());\r
+        assertNull(hd2.getHeaderText());\r
+        assertTrue(hd2.isUserDateVisible());\r
+        assertTrue(hd2.isDateTimeVisible());\r
+        assertEquals("August 06, 2008", hd2.getDateTimeText());\r
+\r
+        //the third slide uses per-slide headers / footers\r
+        HeadersFooters hd3 = slide[2].getHeadersFooters();\r
+        assertTrue(hd3.isFooterVisible());\r
+        assertEquals("THE FOOTER TEXT", hd3.getFooterText());\r
+        assertTrue(hd3.isSlideNumberVisible());\r
+        assertFalse(hd3.isHeaderVisible());\r
+        assertNull(hd3.getHeaderText());\r
+        assertTrue(hd3.isUserDateVisible());\r
+        assertTrue(hd3.isDateTimeVisible());\r
+        assertEquals("Wednesday, August 06, 2008", hd3.getDateTimeText());\r
+    }\r
+\r
     public void testCreateSlideFooters() throws Exception\r
     {\r
         SlideShow ppt = new SlideShow();\r