From e00116900df9ad4961388aa181509e416dd8d40a Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Sat, 9 Aug 2008 21:31:28 +0000 Subject: [PATCH] Start on headers/footers support git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@684349 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/org/apache/poi/hwpf/HWPFDocument.java | 4 + .../poi/hwpf/model/FileInformationBlock.java | 23 ++- .../org/apache/poi/hwpf/model/PlexOfCps.java | 2 + .../poi/hwpf/usermodel/HeaderStories.java | 143 +++++++++++++++++- .../poi/hwpf/usermodel/TestHeaderStories.java | 108 +++++++++++++ 5 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHeaderStories.java diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java index b0f7af334a..f06786b1fc 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java @@ -562,6 +562,10 @@ public class HWPFDocument extends POIDocument { return _dataStream; } + public byte[] getTableStream() + { + return _tableStream; + } public int registerList(HWPFList list) { diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java index 087a2d8633..22952735e4 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java @@ -261,6 +261,27 @@ public class FileInformationBlock extends FIBAbstractType _fieldHandler.setFieldSize(FIBFieldHandler.STTBFFFN, lcbSttbFffn); } + /** + * Return the offset to the PlcfHdd, in the table stream, + * i.e. fcPlcfHdd + */ + public int getPlcfHddOffset() { + return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFHDD); + } + /** + * Return the size of the PlcfHdd, in the table stream, + * i.e. lcbPlcfHdd + */ + public int getPlcfHddSize() { + return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFHDD); + } + public void setPlcfHddOffset(int fcPlcfHdd) { + _fieldHandler.setFieldOffset(FIBFieldHandler.PLCFHDD, fcPlcfHdd); + } + public void setPlcfHddSize(int lcbPlcfHdd) { + _fieldHandler.setFieldSize(FIBFieldHandler.PLCFHDD, lcbPlcfHdd); + } + public int getFcSttbSavedBy() { return _fieldHandler.getFieldOffset(FIBFieldHandler.STTBSAVEDBY); @@ -300,7 +321,7 @@ public class FileInformationBlock extends FIBAbstractType { _fieldHandler.setFieldSize(FIBFieldHandler.PLFLFO, modifiedHigh); } - + /** * How many bytes of the main stream contain real data. diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PlexOfCps.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PlexOfCps.java index a2b9cf43da..c0df0e8f8f 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/PlexOfCps.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PlexOfCps.java @@ -54,7 +54,9 @@ public class PlexOfCps */ public PlexOfCps(byte[] buf, int start, int size, int sizeOfStruct) { + // Figure out the number we hold _count = (size - 4)/(4 + sizeOfStruct); + _sizeOfStruct = sizeOfStruct; _props = new ArrayList(_count); diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/HeaderStories.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/HeaderStories.java index 65924d3e61..95cee57d1b 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/HeaderStories.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/HeaderStories.java @@ -16,16 +16,155 @@ ==================================================================== */ package org.apache.poi.hwpf.usermodel; +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.hwpf.model.FileInformationBlock; +import org.apache.poi.hwpf.model.GenericPropertyNode; +import org.apache.poi.hwpf.model.PlexOfCps; + /** * A HeaderStory is a Header, a Footer, or footnote/endnote * separator. * All the Header Stories get stored in the same Range in the * document, and this handles getting out all the individual * parts. + * + * WARNING - you shouldn't change the headers or footers, + * as offsets are not yet updated! */ public class HeaderStories { private Range headerStories; - public HeaderStories(Range headerStories) { - this.headerStories = headerStories; + private PlexOfCps plcfHdd; + + public HeaderStories(HWPFDocument doc) { + this.headerStories = doc.getHeaderStoryRange(); + FileInformationBlock fib = doc.getFileInformationBlock(); + + // If there's no PlcfHdd, nothing to do + if(fib.getCcpHdd() == 0) { + return; + } + if(fib.getPlcfHddSize() == 0) { + return; + } + + // Handle the PlcfHdd + plcfHdd = new PlexOfCps( + doc.getTableStream(), fib.getPlcfHddOffset(), + fib.getPlcfHddSize(), 0 + ); + } + + public String getFootnoteSeparator() { + return getAt(0); + } + public String getFootnoteContSeparator() { + return getAt(1); + } + public String getFootnoteContNote() { + return getAt(2); + } + public String getEndnoteSeparator() { + return getAt(3); + } + public String getEndnoteContSeparator() { + return getAt(4); + } + public String getEndnoteContNote() { + return getAt(5); + } + + + public String getEvenHeader() { + return getAt(6+0); + } + public String getOddHeader() { + return getAt(6+1); + } + public String getFirstHeader() { + return getAt(6+4); + } + /** + * Returns the correct, defined header for the given + * one based page + * @param pageNumber The one based page number + * @return + */ + public String getHeader(int pageNumber) { + // First page header is optional, only return + // if it's set + if(pageNumber == 1) { + if(getFirstHeader().length() > 0) { + return getFirstHeader(); + } + } + // Even page header is optional, only return + // if it's set + if(pageNumber % 2 == 0) { + if(getEvenHeader().length() > 0) { + return getEvenHeader(); + } + } + // Odd is the default + return getOddHeader(); + } + + + public String getEvenFooter() { + return getAt(6+2); + } + public String getOddFooter() { + return getAt(6+3); + } + public String getFirstFooter() { + return getAt(6+5); + } + /** + * Returns the correct, defined footer for the given + * one based page + * @param pageNumber The one based page number + * @return + */ + public String getFooter(int pageNumber) { + // First page footer is optional, only return + // if it's set + if(pageNumber == 1) { + if(getFirstFooter().length() > 0) { + return getFirstFooter(); + } + } + // Even page footer is optional, only return + // if it's set + if(pageNumber % 2 == 0) { + if(getEvenFooter().length() > 0) { + return getEvenFooter(); + } + } + // Odd is the default + return getOddFooter(); + } + + + /** + * Get the string that's pointed to by the + * given plcfHdd index + */ + private String getAt(int plcfHddIndex) { + if(plcfHdd == null) return null; + + GenericPropertyNode prop = plcfHdd.getProperty(plcfHddIndex); + if(prop.getStart() == prop.getEnd()) { + // Empty story + return ""; + } + + // Return the contents + return headerStories.text().substring(prop.getStart(), prop.getEnd()); + } + + public Range getRange() { + return headerStories; + } + protected PlexOfCps getPlcfHdd() { + return plcfHdd; } } diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHeaderStories.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHeaderStories.java new file mode 100644 index 0000000000..03256fba42 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHeaderStories.java @@ -0,0 +1,108 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ +package org.apache.poi.hwpf.usermodel; + +import java.io.File; +import java.io.FileInputStream; + +import junit.framework.TestCase; + +import org.apache.poi.hwpf.HWPFDocument; + +/** + * Tests for the handling of header stories into + * headers, footers etc + */ +public class TestHeaderStories extends TestCase { + private HWPFDocument none; + private HWPFDocument header; + private HWPFDocument footer; + private HWPFDocument headerFooter; + private HWPFDocument oddEven; + private HWPFDocument diffFirst; + private HWPFDocument unicode; + + protected void setUp() throws Exception { + String dirname = System.getProperty("HWPF.testdata.path"); + + none = new HWPFDocument( + new FileInputStream(new File(dirname, "NoHeadFoot.doc")) + ); + header = new HWPFDocument( + new FileInputStream(new File(dirname, "ThreeColHead.doc")) + ); + footer = new HWPFDocument( + new FileInputStream(new File(dirname, "ThreeColFoot.doc")) + ); + headerFooter = new HWPFDocument( + new FileInputStream(new File(dirname, "SimpleHeadThreeColFoot.doc")) + ); + oddEven = new HWPFDocument( + new FileInputStream(new File(dirname, "PageSpecificHeadFoot.doc")) + ); + diffFirst = new HWPFDocument( + new FileInputStream(new File(dirname, "DiffFirstPageHeadFoot.doc")) + ); + unicode = new HWPFDocument( + new FileInputStream(new File(dirname, "HeaderFooterUnicode.doc")) + ); + } + + public void testNone() throws Exception { + HeaderStories hs = new HeaderStories(none); + + assertNull(hs.getPlcfHdd()); + assertEquals(0, hs.getRange().text().length()); + } + + public void testHeader() throws Exception { + HeaderStories hs = new HeaderStories(header); + + assertEquals(60, hs.getRange().text().length()); + + // Should have the usual 6 separaters + // Then all 6 of the different header/footer kinds + // Finally a terminater + assertEquals(13, hs.getPlcfHdd().length()); + + assertEquals(215, hs.getRange().getStartOffset()); + + assertEquals(0, hs.getPlcfHdd().getProperty(0).getStart()); + assertEquals(3, hs.getPlcfHdd().getProperty(1).getStart()); + assertEquals(6, hs.getPlcfHdd().getProperty(2).getStart()); + assertEquals(6, hs.getPlcfHdd().getProperty(3).getStart()); + assertEquals(9, hs.getPlcfHdd().getProperty(4).getStart()); + assertEquals(12, hs.getPlcfHdd().getProperty(5).getStart()); + + assertEquals(12, hs.getPlcfHdd().getProperty(6).getStart()); + assertEquals(12, hs.getPlcfHdd().getProperty(7).getStart()); + assertEquals(59, hs.getPlcfHdd().getProperty(8).getStart()); + assertEquals(59, hs.getPlcfHdd().getProperty(9).getStart()); + assertEquals(59, hs.getPlcfHdd().getProperty(10).getStart()); + assertEquals(59, hs.getPlcfHdd().getProperty(11).getStart()); + + assertEquals(59, hs.getPlcfHdd().getProperty(12).getStart()); + + assertEquals("\u0003\r\r", hs.getFootnoteSeparator()); + assertEquals("\u0004\r\r", hs.getFootnoteContSeparator()); + assertEquals("", hs.getFootnoteContNote()); + assertEquals("\u0003\r\r", hs.getEndnoteSeparator()); + assertEquals("\u0004\r\r", hs.getEndnoteContSeparator()); + assertEquals("", hs.getEndnoteContNote()); + + } +} -- 2.39.5