aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2014-04-25 23:07:00 +0000
committerNick Burch <nick@apache.org>2014-04-25 23:07:00 +0000
commit6bf09f5b16d8e5d9b0dd81aced437d012759a7a9 (patch)
tree768d095592c6176d543ad64df6744072b50b5931
parent9d2023f2ace81bb70b101772206d351d818d8263 (diff)
downloadpoi-6bf09f5b16d8e5d9b0dd81aced437d012759a7a9.tar.gz
poi-6bf09f5b16d8e5d9b0dd81aced437d012759a7a9.zip
Begin to support and test in-place changes to documents within a NPOIFS stream
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1590185 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/java/org/apache/poi/poifs/filesystem/NDocumentOutputStream.java88
-rw-r--r--src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java4
-rw-r--r--src/java/org/apache/poi/poifs/property/DocumentProperty.java8
-rw-r--r--src/testcases/org/apache/poi/hpsf/basic/TestWrite.java136
-rw-r--r--src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java37
5 files changed, 270 insertions, 3 deletions
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
index 0000000000..0215009475
--- /dev/null
+++ b/src/java/org/apache/poi/poifs/filesystem/NDocumentOutputStream.java
@@ -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
+ }
+}
diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java
index 0da6de87fd..affaa16125 100644
--- a/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java
+++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java
@@ -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);
}
/**
diff --git a/src/java/org/apache/poi/poifs/property/DocumentProperty.java b/src/java/org/apache/poi/poifs/property/DocumentProperty.java
index 20ff232641..67c8b03073 100644
--- a/src/java/org/apache/poi/poifs/property/DocumentProperty.java
+++ b/src/java/org/apache/poi/poifs/property/DocumentProperty.java
@@ -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
diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
index c7fafe30dd..8e228f6871 100644
--- a/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
+++ b/src/testcases/org/apache/poi/hpsf/basic/TestWrite.java
@@ -17,7 +17,16 @@
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();
+ }
/**
diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java
index 3467877371..ea3df4cf2d 100644
--- a/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java
+++ b/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java
@@ -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();
}