From 47be5cb1428c261b101fb31342513f8fdbaad559 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Mon, 28 Nov 2011 16:44:16 +0000 Subject: [PATCH] Add a POIFS Helper FilteringDirectoryNode, which wraps a DirectoryEntry and allows certain parts to be ignored git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1207412 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../filesystem/FilteringDirectoryNode.java | 211 ++++++++++++++++++ .../TestFilteringDirectoryNode.java | 172 ++++++++++++++ 3 files changed, 384 insertions(+) create mode 100644 src/java/org/apache/poi/poifs/filesystem/FilteringDirectoryNode.java create mode 100644 src/testcases/org/apache/poi/poifs/filesystem/TestFilteringDirectoryNode.java diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 4741a2e34..367548933 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + POIFS Helper FilteringDirectoryNode, which wraps a DirectoryEntry and allows certain parts to be ignored 52209 - fixed inserting multiple pictures in XSLF 51803 - fixed HSLF TextExtractor to extract content from master slide 52190 - null check on XWPF setFontFamily diff --git a/src/java/org/apache/poi/poifs/filesystem/FilteringDirectoryNode.java b/src/java/org/apache/poi/poifs/filesystem/FilteringDirectoryNode.java new file mode 100644 index 000000000..737f8d97c --- /dev/null +++ b/src/java/org/apache/poi/poifs/filesystem/FilteringDirectoryNode.java @@ -0,0 +1,211 @@ + +/* ==================================================================== + 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.poifs.filesystem; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.poi.hpsf.ClassID; + +/** + * A DirectoryEntry filter, which exposes another + * DirectoryEntry less certain parts. + * This is typically used when copying or comparing + * Filesystems. + */ +public class FilteringDirectoryNode implements DirectoryEntry +{ + /** + * The names of our entries to exclude + */ + private Set excludes; + /** + * Excludes of our child directories + */ + private Map> childExcludes; + + private DirectoryEntry directory; + + /** + * Creates a filter round the specified directory, which + * will exclude entries such as "MyNode" and "MyDir/IgnoreNode". + * The excludes can stretch into children, if they contain a /. + * + * @param entry The Directory to filter + * @param excludes The Entries to exclude + */ + public FilteringDirectoryNode(DirectoryEntry directory, Collection excludes) { + this.directory = directory; + + // Process the excludes + this.excludes = new HashSet(); + this.childExcludes = new HashMap>(); + for (String excl : excludes) { + int splitAt = excl.indexOf('/'); + if (splitAt == -1) { + // Applies to us + this.excludes.add(excl); + } else { + // Applies to a child + String child = excl.substring(0, splitAt); + String childExcl = excl.substring(splitAt+1); + if (! this.childExcludes.containsKey(child)) { + this.childExcludes.put(child, new ArrayList()); + } + this.childExcludes.get(child).add(childExcl); + } + } + } + + public DirectoryEntry createDirectory(String name) throws IOException { + return directory.createDirectory(name); + } + + public DocumentEntry createDocument(String name, InputStream stream) + throws IOException { + return directory.createDocument(name, stream); + } + + public DocumentEntry createDocument(String name, int size, + POIFSWriterListener writer) throws IOException { + return directory.createDocument(name, size, writer); + } + + public Iterator getEntries() { + return new FilteringIterator(); + } + + public Iterator iterator() { + return getEntries(); + } + + public int getEntryCount() { + int size = directory.getEntryCount(); + for (String excl : excludes) { + if (directory.hasEntry(excl)) { + size--; + } + } + return size; + } + + public boolean isEmpty() { + return (getEntryCount() == 0); + } + + public boolean hasEntry(String name) { + if (excludes.contains(name)) { + return false; + } + return directory.hasEntry(name); + } + + public Entry getEntry(String name) throws FileNotFoundException { + if (excludes.contains(name)) { + throw new FileNotFoundException(name); + } + + Entry entry = directory.getEntry(name); + return wrapEntry(entry); + } + private Entry wrapEntry(Entry entry) { + String name = entry.getName(); + if (childExcludes.containsKey(name) && entry instanceof DirectoryEntry) { + return new FilteringDirectoryNode( + (DirectoryEntry)entry, childExcludes.get(name)); + } + return entry; + } + + public ClassID getStorageClsid() { + return directory.getStorageClsid(); + } + + public void setStorageClsid(ClassID clsidStorage) { + directory.setStorageClsid(clsidStorage); + } + + public boolean delete() { + return directory.delete(); + } + + public boolean renameTo(String newName) { + return directory.renameTo(newName); + } + + public String getName() { + return directory.getName(); + } + + public DirectoryEntry getParent() { + return directory.getParent(); + } + + public boolean isDirectoryEntry() { + return true; + } + + public boolean isDocumentEntry() { + return false; + } + + private class FilteringIterator implements Iterator { + private Iterator parent; + private Entry next; + + private FilteringIterator() { + parent = directory.getEntries(); + locateNext(); + } + private void locateNext() { + next = null; + Entry e; + while (parent.hasNext() && next == null) { + e = parent.next(); + if (! excludes.contains(e.getName())) { + next = wrapEntry(e); + } + } + } + + public boolean hasNext() { + return (next != null); + } + + public Entry next() { + Entry e = next; + locateNext(); + return e; + } + + public void remove() { + throw new UnsupportedOperationException("Remove not supported"); + } + } +} \ No newline at end of file diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestFilteringDirectoryNode.java b/src/testcases/org/apache/poi/poifs/filesystem/TestFilteringDirectoryNode.java new file mode 100644 index 000000000..bef0281f2 --- /dev/null +++ b/src/testcases/org/apache/poi/poifs/filesystem/TestFilteringDirectoryNode.java @@ -0,0 +1,172 @@ + +/* ==================================================================== + 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.poifs.filesystem; + +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import junit.framework.TestCase; + +/** + * Class to test FilteringDirectoryNode functionality + */ +public final class TestFilteringDirectoryNode extends TestCase { + private POIFSFileSystem fs; + private DirectoryEntry dirA; + private DirectoryEntry dirAA; + private DirectoryEntry dirB; + private DocumentEntry eRoot; + private DocumentEntry eA; + private DocumentEntry eAA; + + @Override + protected void setUp() throws Exception { + fs = new POIFSFileSystem(); + dirA = fs.createDirectory("DirA"); + dirB = fs.createDirectory("DirB"); + dirAA = dirA.createDirectory("DirAA"); + eRoot = fs.getRoot().createDocument("Root", new ByteArrayInputStream(new byte[] {})); + eA = dirA.createDocument("NA", new ByteArrayInputStream(new byte[] {})); + eAA = dirAA.createDocument("NAA", new ByteArrayInputStream(new byte[] {})); + } + + public void testNoFiltering() throws Exception { + FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), new HashSet()); + assertEquals(3, d.getEntryCount()); + assertEquals(dirA.getName(), d.getEntry(dirA.getName()).getName()); + + assertEquals(true, d.getEntry(dirA.getName()).isDirectoryEntry()); + assertEquals(false, d.getEntry(dirA.getName()).isDocumentEntry()); + + assertEquals(true, d.getEntry(dirB.getName()).isDirectoryEntry()); + assertEquals(false, d.getEntry(dirB.getName()).isDocumentEntry()); + + assertEquals(false, d.getEntry(eRoot.getName()).isDirectoryEntry()); + assertEquals(true, d.getEntry(eRoot.getName()).isDocumentEntry()); + + Iterator i = d.getEntries(); + assertEquals(dirA, i.next()); + assertEquals(dirB, i.next()); + assertEquals(eRoot, i.next()); + assertEquals(null, i.next()); + } + + public void testChildFiltering() throws Exception { + List excl = Arrays.asList(new String[] {"NotThere","AlsoNotThere", eRoot.getName()}); + FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), excl); + + assertEquals(2, d.getEntryCount()); + assertEquals(true, d.hasEntry(dirA.getName())); + assertEquals(true, d.hasEntry(dirB.getName())); + assertEquals(false, d.hasEntry(eRoot.getName())); + + assertEquals(dirA, d.getEntry(dirA.getName())); + assertEquals(dirB, d.getEntry(dirB.getName())); + try { + d.getEntry(eRoot.getName()); + fail("Should be filtered"); + } catch(FileNotFoundException e) {} + + Iterator i = d.getEntries(); + assertEquals(dirA, i.next()); + assertEquals(dirB, i.next()); + assertEquals(null, i.next()); + + + // Filter more + excl = Arrays.asList(new String[] {"NotThere","AlsoNotThere", eRoot.getName(), dirA.getName()}); + d = new FilteringDirectoryNode(fs.getRoot(), excl); + + assertEquals(1, d.getEntryCount()); + assertEquals(false, d.hasEntry(dirA.getName())); + assertEquals(true, d.hasEntry(dirB.getName())); + assertEquals(false, d.hasEntry(eRoot.getName())); + + try { + d.getEntry(dirA.getName()); + fail("Should be filtered"); + } catch(FileNotFoundException e) {} + assertEquals(dirB, d.getEntry(dirB.getName())); + try { + d.getEntry(eRoot.getName()); + fail("Should be filtered"); + } catch(FileNotFoundException e) {} + + i = d.getEntries(); + assertEquals(dirB, i.next()); + assertEquals(null, i.next()); + + + // Filter everything + excl = Arrays.asList(new String[] {"NotThere", eRoot.getName(), dirA.getName(), dirB.getName()}); + d = new FilteringDirectoryNode(fs.getRoot(), excl); + + assertEquals(0, d.getEntryCount()); + assertEquals(false, d.hasEntry(dirA.getName())); + assertEquals(false, d.hasEntry(dirB.getName())); + assertEquals(false, d.hasEntry(eRoot.getName())); + + try { + d.getEntry(dirA.getName()); + fail("Should be filtered"); + } catch(FileNotFoundException e) {} + try { + d.getEntry(dirB.getName()); + fail("Should be filtered"); + } catch(FileNotFoundException e) {} + try { + d.getEntry(eRoot.getName()); + fail("Should be filtered"); + } catch(FileNotFoundException e) {} + + i = d.getEntries(); + assertEquals(null, i.next()); + } + + public void testNestedFiltering() throws Exception { + List excl = Arrays.asList(new String[] { + dirA.getName()+"/"+"MadeUp", + dirA.getName()+"/"+eA.getName(), + dirA.getName()+"/"+dirAA.getName()+"/Test", + eRoot.getName() + }); + FilteringDirectoryNode d = new FilteringDirectoryNode(fs.getRoot(), excl); + + // Check main + assertEquals(2, d.getEntryCount()); + assertEquals(true, d.hasEntry(dirA.getName())); + assertEquals(true, d.hasEntry(dirB.getName())); + assertEquals(false, d.hasEntry(eRoot.getName())); + + // Check filtering down + assertEquals(true, d.getEntry(dirA.getName()) instanceof FilteringDirectoryNode); + assertEquals(false, d.getEntry(dirB.getName()) instanceof FilteringDirectoryNode); + + DirectoryEntry fdA = (DirectoryEntry)d.getEntry(dirA.getName()); + assertEquals(false, fdA.hasEntry(eA.getName())); + assertEquals(true, fdA.hasEntry(dirAA.getName())); + + DirectoryEntry fdAA = (DirectoryEntry)fdA.getEntry(dirAA.getName()); + assertEquals(true, fdAA.hasEntry(eAA.getName())); + } +}