]> source.dussan.org Git - poi.git/commitdiff
Begin to support and test in-place changes to documents within a NPOIFS stream
authorNick Burch <nick@apache.org>
Fri, 25 Apr 2014 23:07:00 +0000 (23:07 +0000)
committerNick Burch <nick@apache.org>
Fri, 25 Apr 2014 23:07:00 +0000 (23:07 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1590185 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/poifs/filesystem/NDocumentOutputStream.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java
src/java/org/apache/poi/poifs/property/DocumentProperty.java
src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java

diff --git a/src/java/org/apache/poi/poifs/filesystem/NDocumentOutputStream.java b/src/java/org/apache/poi/poifs/filesystem/NDocumentOutputStream.java
new file mode 100644 (file)
index 0000000..0215009
--- /dev/null
@@ -0,0 +1,88 @@
+/* ====================================================================
+   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.IOException;
+import java.io.OutputStream;
+
+/**
+ * This class provides methods to write a DocumentEntry managed by a
+ * {@link NPOIFSFileSystem} instance.
+ */
+public final class NDocumentOutputStream extends OutputStream {
+       /** the Document's size */
+       private int _document_size;
+
+       /** have we been closed? */
+       private boolean _closed;
+
+       /** the actual Document */
+       private NPOIFSDocument _document;
+       
+       /**
+        * Create an OutputStream from the specified DocumentEntry.
+        * The specified entry will be emptied.
+        * 
+        * @param document the DocumentEntry to be written
+        */
+       public NDocumentOutputStream(DocumentEntry document) throws IOException {
+               if (!(document instanceof DocumentNode)) {
+                       throw new IOException("Cannot open internal document storage, " + document + " not a Document Node");
+               }
+               _document_size = 0;
+               _closed = false;
+               
+               _document = new NPOIFSDocument((DocumentNode)document);
+               _document.free();
+       }
+       
+       /**
+        * Create an OutputStream to create the specified new Entry
+        * 
+        * @param parent Where to create the Entry
+        * @param name Name of the new entry
+        */
+       public NDocumentOutputStream(DirectoryEntry parent, String name) throws IOException {
+        if (!(parent instanceof DirectoryNode)) {
+            throw new IOException("Cannot open internal directory storage, " + parent + " not a Directory Node");
+        }
+        _document_size = 0;
+        _closed = false;
+
+        // Have an empty one created for now
+        DocumentEntry doc = parent.createDocument(name, new ByteArrayInputStream(new byte[0]));
+        _document = new NPOIFSDocument((DocumentNode)doc);
+       }
+
+    public void write(int b) throws IOException {
+        // TODO
+    }
+
+    public void write(byte[] b) throws IOException {
+        // TODO
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+        // TODO
+    }
+
+    public void close() throws IOException {
+        // TODO
+    }
+}
index 0da6de87fd89281af30f6f72a428b99ffdec445d..affaa161254413f6490f6760e097ba24d2244ffc 100644 (file)
@@ -176,7 +176,9 @@ public final class NPOIFSDocument implements POIFSViewable {
    
    public void replaceContents(InputStream stream) throws IOException {
        free();
-       store(stream);
+       int size = store(stream);
+       _property.setStartBlock(_stream.getStartBlock()); 
+       _property.updateSize(size);
    }
 
    /**
index 20ff232641e7369baa7e513db620484ee36db12c..67c8b03073dc117bd651109e259fa758d0d1734a 100644 (file)
@@ -120,6 +120,14 @@ public class DocumentProperty
 
         // do nothing
     }
+    
+    /**
+     * Update the size of the property's data
+     */
+    public void updateSize(int size)
+    {
+        setSize(size);
+    }
 
     /* **********  END  extension of Property ********** */
 }   // end public class DocumentProperty
index c7fafe30dd3e8555722a47b2adab6f045e08ed8a..8e228f68717b4f837ee2a3708e428917c2fcf0b3 100644 (file)
 
 package org.apache.poi.hpsf.basic;
 
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.util.Date;
 import java.util.HashMap;
@@ -26,14 +35,37 @@ import java.util.Map;
 import junit.framework.TestCase;
 
 import org.apache.poi.POIDataSamples;
-import org.apache.poi.hpsf.*;
+import org.apache.poi.hpsf.ClassID;
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.HPSFException;
+import org.apache.poi.hpsf.IllegalPropertySetDataException;
+import org.apache.poi.hpsf.MutableProperty;
+import org.apache.poi.hpsf.MutablePropertySet;
+import org.apache.poi.hpsf.MutableSection;
+import org.apache.poi.hpsf.NoFormatIDException;
+import org.apache.poi.hpsf.NoPropertySetStreamException;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.ReadingNotSupportedException;
+import org.apache.poi.hpsf.Section;
+import org.apache.poi.hpsf.SummaryInformation;
+import org.apache.poi.hpsf.UnsupportedVariantTypeException;
+import org.apache.poi.hpsf.Variant;
+import org.apache.poi.hpsf.VariantSupport;
+import org.apache.poi.hpsf.WritingNotSupportedException;
 import org.apache.poi.hpsf.wellknown.PropertyIDMap;
 import org.apache.poi.hpsf.wellknown.SectionIDMap;
 import org.apache.poi.poifs.eventfilesystem.POIFSReader;
 import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
 import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DocumentNode;
+import org.apache.poi.poifs.filesystem.NDocumentInputStream;
+import org.apache.poi.poifs.filesystem.NDocumentOutputStream;
+import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.CodePageUtil;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.TempFile;
 import org.junit.Assert;
@@ -764,6 +796,106 @@ public class TestWrite extends TestCase
         assertEquals(ps1, ps2);
     }
 
+    /**
+     * Tests that when using NPOIFS, we can do an in-place write
+     *  without needing to stream in + out the whole kitchen sink
+     * TODO Finish implementing the logic for this
+     */
+    public void DISBALEDtestInPlaceNPOIFSWrite() throws Exception {
+        NPOIFSFileSystem fs = null;
+        DirectoryEntry root = null;
+        DocumentNode sinfDoc = null;
+        DocumentNode dinfDoc = null;
+        SummaryInformation sinf = null;
+        DocumentSummaryInformation dinf = null;
+        
+        final File copy = TempFile.createTempFile("Test-HPSF", "ole2");
+        copy.deleteOnExit();
+        
+        // Copy a test file over to a temp location
+        InputStream inp = _samples.openResourceAsStream("TestShiftJIS.doc");
+        FileOutputStream out = new FileOutputStream(copy);
+        IOUtils.copy(inp, out);
+        inp.close();
+        out.close();
+        
+        // Open the copy in read/write mode
+        fs = new NPOIFSFileSystem(copy);
+        root = fs.getRoot();
+        
+        // Read the properties in there
+        sinfDoc = (DocumentNode)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
+        sinf = (SummaryInformation)PropertySetFactory.create(new NDocumentInputStream(sinfDoc));
+        assertEquals(131077, sinf.getOSVersion());
+        
+        dinfDoc = (DocumentNode)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
+        dinf = (DocumentSummaryInformation)PropertySetFactory.create(new NDocumentInputStream(dinfDoc));
+        assertEquals(131077, dinf.getOSVersion());
+        
+        // Check they start as we expect
+        assertEquals("Reiichiro Hori", sinf.getAuthor());
+        assertEquals("Microsoft Word 9.0", sinf.getApplicationName());
+        assertEquals("\u7b2c1\u7ae0", sinf.getTitle());
+        
+        assertEquals("", dinf.getCompany());
+        assertEquals(null, dinf.getManager());
+        
+        // Alter a few of them
+        sinf.setAuthor("Changed Author");
+        sinf.setTitle("Le titre \u00e9tait chang\u00e9");
+        dinf.setManager("Changed Manager");
+        
+        
+        // Save this into the filesystem
+        sinf.write(new NDocumentOutputStream(sinfDoc));
+        dinf.write(new NDocumentOutputStream(dinfDoc));
+        
+        
+        // Read as-is
+        sinfDoc = (DocumentNode)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
+        sinf = (SummaryInformation)PropertySetFactory.create(new NDocumentInputStream(sinfDoc));
+        assertEquals(131077, sinf.getOSVersion());
+        
+        dinfDoc = (DocumentNode)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
+        dinf = (DocumentSummaryInformation)PropertySetFactory.create(new NDocumentInputStream(dinfDoc));
+        assertEquals(131077, dinf.getOSVersion());
+
+        assertEquals("Changed Author", sinf.getAuthor());
+        assertEquals("Microsoft Word 9.0", sinf.getApplicationName());
+        assertEquals("Le titre \u00e9tait chang\u00e9", sinf.getTitle());
+        
+        assertEquals("", dinf.getCompany());
+        assertEquals("Changed Manager", dinf.getManager());
+
+        
+        // Close, re-load
+        fs.writeFilesystem();
+        fs.close();
+        
+        fs = new NPOIFSFileSystem(copy);
+        root = fs.getRoot();
+        
+        // Re-check on load
+        sinfDoc = (DocumentNode)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
+        sinf = (SummaryInformation)PropertySetFactory.create(new NDocumentInputStream(sinfDoc));
+        assertEquals(131077, sinf.getOSVersion());
+        
+        dinfDoc = (DocumentNode)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
+        dinf = (DocumentSummaryInformation)PropertySetFactory.create(new NDocumentInputStream(dinfDoc));
+        assertEquals(131077, dinf.getOSVersion());
+
+        assertEquals("Changed Author", sinf.getAuthor());
+        assertEquals("Microsoft Word 9.0", sinf.getApplicationName());
+        assertEquals("Le titre \u00e9tait chang\u00e9", sinf.getTitle());
+        
+        assertEquals("", dinf.getCompany());
+        assertEquals("Changed Manager", dinf.getManager());
+        
+        
+        // Tidy up
+        fs.close();
+        copy.delete();
+    }
 
 
     /**
index 3467877371bb85db2164f09f28a0463214730ea5..ea3df4cf2d11ac39c5e98153560b7818f37ec0fa 100644 (file)
@@ -862,6 +862,43 @@ public final class TestNPOIFSFileSystem {
            assertContentsMatches(mini3, (DocumentEntry)testDir.getEntry("Mini3"));
            assertContentsMatches(main4096, (DocumentEntry)testDir.getEntry("Normal4096"));
            
+           
+           // Change some existing streams
+           NPOIFSDocument mini2Doc = new NPOIFSDocument((DocumentNode)testDir.getEntry("Mini2"));
+           mini2Doc.replaceContents(new ByteArrayInputStream(mini));
+           
+           byte[] main4106 = new byte[4106];
+           main4106[0] = 41;
+           main4106[4105] = 42;
+           NPOIFSDocument mainDoc = new NPOIFSDocument((DocumentNode)testDir.getEntry("Normal4096"));
+           mainDoc.replaceContents(new ByteArrayInputStream(main4106));
+           
+           
+           // Re-check
+           fs = writeOutAndReadBack(fs);
+           
+           root = fs.getRoot();
+           testDir = (DirectoryEntry)root.getEntry("Testing 123");
+           
+           assertEquals(5, root.getEntryCount());
+           assertThat(root.getEntryNames(), hasItem("Thumbnail"));
+           assertThat(root.getEntryNames(), hasItem("Image"));
+           assertThat(root.getEntryNames(), hasItem("Testing 123"));
+           assertThat(root.getEntryNames(), hasItem("\u0005DocumentSummaryInformation"));
+           assertThat(root.getEntryNames(), hasItem("\u0005SummaryInformation"));
+           
+           assertEquals(5, testDir.getEntryCount());
+           assertThat(testDir.getEntryNames(), hasItem("Mini2"));
+           assertThat(testDir.getEntryNames(), hasItem("Mini3"));
+           assertThat(testDir.getEntryNames(), hasItem("Normal4096"));
+           assertThat(testDir.getEntryNames(), hasItem("Testing 789"));
+           assertThat(testDir.getEntryNames(), hasItem("Testing ABC"));
+
+           assertContentsMatches(mini, (DocumentEntry)testDir.getEntry("Mini2"));
+           assertContentsMatches(mini3, (DocumentEntry)testDir.getEntry("Mini3"));
+           assertContentsMatches(main4106, (DocumentEntry)testDir.getEntry("Normal4096"));
+           
+           
            // All done
            fs.close();
        }