From e4ff06ec794e82ac0e7c50d71e4fe7dabbfc2ece Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Tue, 2 Sep 2008 19:37:52 +0000 Subject: [PATCH] Initial ExtractorFactory support for building TextExtractors for embeded documents git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@691351 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/changes.xml | 1 + src/documentation/content/xdocs/status.xml | 1 + .../org/apache/poi/POIOLE2TextExtractor.java | 9 ++ .../poi/hssf/extractor/ExcelExtractor.java | 6 +- .../poi/extractor/ExtractorFactory.java | 85 ++++++++++++++++-- .../poi/extractor/TestExtractorFactory.java | 61 +++++++++++++ .../apache/poi/hdgf/chunks/ChunkFactory.java | 4 + .../hdgf/extractor/VisioTextExtractor.java | 6 +- .../hslf/extractor/PowerPointExtractor.java | 4 + .../poi/hwpf/extractor/WordExtractor.java | 5 ++ .../org/apache/poi/hssf/data/WithEmbeded.xlsx | Bin 0 -> 23668 bytes 11 files changed, 175 insertions(+), 7 deletions(-) create mode 100755 src/testcases/org/apache/poi/hssf/data/WithEmbeded.xlsx diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index fc7206925c..14dcd3b4fc 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -41,6 +41,7 @@ --> + Initial ExtractorFactory support for building TextExtractors for embeded documents Support stripping XSSF header and footer fields (eg page number) out of header and footer text if required Add POIXMLPropertiesTextExtractor, which provides to the OOXML file formats a similar function to HPSF's HPSFPropertiesExtractor 45539 - Improve XWPFWordExtractor to extract headers and footers diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 94d1a47207..e92ca9b704 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -38,6 +38,7 @@ --> + Initial ExtractorFactory support for building TextExtractors for embeded documents Support stripping XSSF header and footer fields (eg page number) out of header and footer text if required Add POIXMLPropertiesTextExtractor, which provides to the OOXML file formats a similar function to HPSF's HPSFPropertiesExtractor 45539 - Improve XWPFWordExtractor to extract headers and footers diff --git a/src/java/org/apache/poi/POIOLE2TextExtractor.java b/src/java/org/apache/poi/POIOLE2TextExtractor.java index d46c7e4aad..f198c19337 100644 --- a/src/java/org/apache/poi/POIOLE2TextExtractor.java +++ b/src/java/org/apache/poi/POIOLE2TextExtractor.java @@ -19,6 +19,7 @@ package org.apache.poi; import org.apache.poi.hpsf.DocumentSummaryInformation; import org.apache.poi.hpsf.SummaryInformation; import org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** * Common Parent for OLE2 based Text Extractors @@ -59,4 +60,12 @@ public abstract class POIOLE2TextExtractor extends POITextExtractor { public POITextExtractor getMetadataTextExtractor() { return new HPSFPropertiesExtractor(this); } + + /** + * Return the underlying POIFS FileSystem of + * this document. + */ + public POIFSFileSystem getFileSystem() { + return document.filesystem; + } } diff --git a/src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java b/src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java index 0381a04573..b9750fc58a 100644 --- a/src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java +++ b/src/java/org/apache/poi/hssf/extractor/ExcelExtractor.java @@ -26,6 +26,7 @@ import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** @@ -48,7 +49,10 @@ public class ExcelExtractor extends POIOLE2TextExtractor implements org.apache.p this.wb = wb; } public ExcelExtractor(POIFSFileSystem fs) throws IOException { - this(new HSSFWorkbook(fs)); + this(fs.getRoot(), fs); + } + public ExcelExtractor(DirectoryNode dir, POIFSFileSystem fs) throws IOException { + this(new HSSFWorkbook(dir, fs, true)); } diff --git a/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java b/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java index 55a47065b9..8e07afd1fd 100644 --- a/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java +++ b/src/ooxml/java/org/apache/poi/extractor/ExtractorFactory.java @@ -18,9 +18,11 @@ package org.apache.poi.extractor; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; +import java.util.ArrayList; import java.util.Iterator; import org.apache.poi.POIOLE2TextExtractor; @@ -31,6 +33,8 @@ import org.apache.poi.hdgf.extractor.VisioTextExtractor; import org.apache.poi.hslf.extractor.PowerPointExtractor; import org.apache.poi.hssf.extractor.ExcelExtractor; import org.apache.poi.hwpf.extractor.WordExtractor; +import org.apache.poi.poifs.filesystem.DirectoryEntry; +import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.xslf.XSLFSlideShow; @@ -105,24 +109,95 @@ public class ExtractorFactory { } public static POIOLE2TextExtractor createExtractor(POIFSFileSystem fs) throws IOException { + return createExtractor(fs.getRoot(), fs); + } + public static POIOLE2TextExtractor createExtractor(DirectoryNode poifsDir, POIFSFileSystem fs) throws IOException { // Look for certain entries in the stream, to figure it // out from - for(Iterator entries = fs.getRoot().getEntries(); entries.hasNext(); ) { + for(Iterator entries = poifsDir.getEntries(); entries.hasNext(); ) { Entry entry = (Entry)entries.next(); if(entry.getName().equals("Workbook")) { - return new ExcelExtractor(fs); + return new ExcelExtractor(poifsDir, fs); } if(entry.getName().equals("WordDocument")) { - return new WordExtractor(fs); + return new WordExtractor(poifsDir, fs); } if(entry.getName().equals("PowerPoint Document")) { - return new PowerPointExtractor(fs); + return new PowerPointExtractor(poifsDir, fs); } if(entry.getName().equals("VisioDocument")) { - return new VisioTextExtractor(fs); + return new VisioTextExtractor(poifsDir, fs); } } throw new IllegalArgumentException("No supported documents found in the OLE2 stream"); } + + + /** + * Returns an array of text extractors, one for each of + * the embeded documents in the file (if there are any). + * If there are no embeded documents, you'll get back an + * empty array. Otherwise, you'll get one open + * {@link POITextExtractor} for each embeded file. + */ + public static POITextExtractor[] getEmbededDocsTextExtractors(POIOLE2TextExtractor ext) throws IOException { + // Find all the embeded directories + ArrayList dirs = new ArrayList(); + POIFSFileSystem fs = ext.getFileSystem(); + if(fs == null) { + throw new IllegalStateException("The extractor didn't know which POIFS it came from!"); + } + + if(ext instanceof ExcelExtractor) { + // These are in MBD... under the root + Iterator it = fs.getRoot().getEntries(); + while(it.hasNext()) { + Entry entry = (Entry)it.next(); + if(entry.getName().startsWith("MBD")) { + dirs.add(entry); + } + } + } else if(ext instanceof WordExtractor) { + // These are in ObjectPool -> _... under the root + try { + DirectoryEntry op = (DirectoryEntry) + fs.getRoot().getEntry("ObjectPool"); + Iterator it = op.getEntries(); + while(it.hasNext()) { + Entry entry = (Entry)it.next(); + if(entry.getName().startsWith("_")) { + dirs.add(entry); + } + } + } catch(FileNotFoundException e) {} + } else if(ext instanceof PowerPointExtractor) { + // Tricky, not stored directly in poifs + // TODO + } + + // Create the extractors + if(dirs == null || dirs.size() == 0) { + return new POITextExtractor[0]; + } + + POITextExtractor[] te = new POITextExtractor[dirs.size()]; + for(int i=0; i 20); + } + + // Word + f = new File(poifs_dir, "word_with_embeded.doc"); + ext = (POIOLE2TextExtractor) + ExtractorFactory.createExtractor(f); + embeds = ExtractorFactory.getEmbededDocsTextExtractors(ext); + + assertEquals(4, embeds.length); + assertTrue(embeds[0] instanceof WordExtractor); + assertTrue(embeds[1] instanceof ExcelExtractor); + assertTrue(embeds[2] instanceof ExcelExtractor); + assertTrue(embeds[3] instanceof PowerPointExtractor); + for(int i=0; i 20); + } + + // TODO - PowerPoint + // TODO - Visio + } } diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java index bb58933de8..34a2f4f893 100644 --- a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java +++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java @@ -64,6 +64,10 @@ public class ChunkFactory { private void processChunkParseCommands() throws IOException { String line; InputStream cpd = ChunkFactory.class.getResourceAsStream(chunkTableName); + if(cpd == null) { + throw new IllegalStateException("Unable to find HDGF chunk definition on the classpath - " + chunkTableName); + } + BufferedReader inp = new BufferedReader(new InputStreamReader(cpd)); while( (line = inp.readLine()) != null ) { if(line.startsWith("#")) continue; diff --git a/src/scratchpad/src/org/apache/poi/hdgf/extractor/VisioTextExtractor.java b/src/scratchpad/src/org/apache/poi/hdgf/extractor/VisioTextExtractor.java index 9b1307cee3..9b861d6d62 100644 --- a/src/scratchpad/src/org/apache/poi/hdgf/extractor/VisioTextExtractor.java +++ b/src/scratchpad/src/org/apache/poi/hdgf/extractor/VisioTextExtractor.java @@ -28,6 +28,7 @@ import org.apache.poi.hdgf.chunks.Chunk.Command; import org.apache.poi.hdgf.streams.ChunkStream; import org.apache.poi.hdgf.streams.PointerContainingStream; import org.apache.poi.hdgf.streams.Stream; +import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** @@ -44,7 +45,10 @@ public class VisioTextExtractor extends POIOLE2TextExtractor { this.hdgf = hdgf; } public VisioTextExtractor(POIFSFileSystem fs) throws IOException { - this(new HDGFDiagram(fs)); + this(fs.getRoot(), fs); + } + public VisioTextExtractor(DirectoryNode dir, POIFSFileSystem fs) throws IOException { + this(new HDGFDiagram(dir, fs)); this.fs = fs; } public VisioTextExtractor(InputStream inp) throws IOException { diff --git a/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java b/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java index 841bd38f9c..cc0205647b 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java +++ b/src/scratchpad/src/org/apache/poi/hslf/extractor/PowerPointExtractor.java @@ -30,6 +30,7 @@ import org.apache.poi.hslf.model.Notes; import org.apache.poi.hslf.model.Slide; import org.apache.poi.hslf.model.TextRun; import org.apache.poi.hslf.usermodel.SlideShow; +import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** @@ -96,6 +97,9 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { public PowerPointExtractor(POIFSFileSystem fs) throws IOException { this(new HSLFSlideShow(fs)); } + public PowerPointExtractor(DirectoryNode dir, POIFSFileSystem fs) throws IOException { + this(new HSLFSlideShow(dir, fs)); + } /** * Creates a PowerPointExtractor, from a HSLFSlideShow diff --git a/src/scratchpad/src/org/apache/poi/hwpf/extractor/WordExtractor.java b/src/scratchpad/src/org/apache/poi/hwpf/extractor/WordExtractor.java index deaffc79af..816b2c1221 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/extractor/WordExtractor.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/extractor/WordExtractor.java @@ -28,6 +28,7 @@ import org.apache.poi.hwpf.model.TextPiece; import org.apache.poi.hwpf.usermodel.HeaderStories; import org.apache.poi.hwpf.usermodel.Paragraph; import org.apache.poi.hwpf.usermodel.Range; +import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.POIFSFileSystem; /** @@ -58,6 +59,10 @@ public class WordExtractor extends POIOLE2TextExtractor { this(new HWPFDocument(fs)); this.fs = fs; } + public WordExtractor(DirectoryNode dir, POIFSFileSystem fs) throws IOException { + this(new HWPFDocument(dir, fs)); + this.fs = fs; + } /** * Create a new Word Extractor diff --git a/src/testcases/org/apache/poi/hssf/data/WithEmbeded.xlsx b/src/testcases/org/apache/poi/hssf/data/WithEmbeded.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..411de4a08cad43030fd563e2abdd4fcb14f6a887 GIT binary patch literal 23668 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 literal 0 HcmV?d00001