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
This commit is contained in:
Nick Burch 2014-04-25 23:07:00 +00:00
parent 868a108fe3
commit c3769b5da0
5 changed files with 270 additions and 3 deletions

View File

@ -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
}
}

View 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);
}
/**

View 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

View File

@ -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();
}
/**

View 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();
}