You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ni...@apache.org on 2010/12/28 09:52:51 UTC
svn commit: r1053279 - in /poi/trunk/src:
java/org/apache/poi/poifs/filesystem/
testcases/org/apache/poi/poifs/filesystem/
Author: nick
Date: Tue Dec 28 08:52:50 2010
New Revision: 1053279
URL: http://svn.apache.org/viewvc?rev=1053279&view=rev
Log:
Implement a NPOIFS document reader, and add tests which use it
Added:
poi/trunk/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java
Modified:
poi/trunk/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java
poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java
poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java
poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java
Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java?rev=1053279&r1=1053278&r2=1053279&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java Tue Dec 28 08:52:50 2010
@@ -120,8 +120,7 @@ public class DirectoryNode
}
else
{
- childNode = new DocumentNode(( DocumentProperty ) child,
- this);
+ childNode = new DocumentNode((DocumentProperty) child, this);
}
_entries.add(childNode);
_byname.put(childNode.getName(), childNode);
Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java?rev=1053279&r1=1053278&r2=1053279&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java Tue Dec 28 08:52:50 2010
@@ -67,11 +67,16 @@ public final class DocumentInputStream e
if (!(document instanceof DocumentNode)) {
throw new IOException("Cannot open internal document storage");
}
+ DocumentNode documentNode = (DocumentNode)document;
+ if(documentNode.getDocument() == null) {
+ throw new IOException("Cannot open internal document storage");
+ }
+
_current_offset = 0;
_marked_offset = 0;
_document_size = document.getSize();
_closed = false;
- _document = ((DocumentNode) document).getDocument();
+ _document = documentNode.getDocument();
_currentBlock = getDataInputBlock(0);
}
Added: poi/trunk/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java?rev=1053279&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java (added)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/NDocumentInputStream.java Tue Dec 28 08:52:50 2010
@@ -0,0 +1,316 @@
+/* ====================================================================
+ 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.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+
+import org.apache.poi.poifs.property.DocumentProperty;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+
+/**
+ * This class provides methods to read a DocumentEntry managed by a
+ * {@link POIFSFileSystem} instance.
+ *
+ * @author Marc Johnson (mjohnson at apache dot org)
+ */
+public final class NDocumentInputStream extends InputStream implements LittleEndianInput {
+ /** returned by read operations if we're at end of document */
+ private static final int EOF = -1;
+
+ private static final int SIZE_SHORT = 2;
+ private static final int SIZE_INT = 4;
+ private static final int SIZE_LONG = 8;
+
+ /** current offset into the Document */
+ private int _current_offset;
+ /** current block count */
+ private int _current_block_count;
+
+ /** current marked offset into the Document (used by mark and reset) */
+ private int _marked_offset;
+ /** and the block count for it */
+ private int _marked_offset_count;
+
+ /** the Document's size */
+ private int _document_size;
+
+ /** have we been closed? */
+ private boolean _closed;
+
+ /** the actual Document */
+ private NPOIFSDocument _document;
+
+ private Iterator<ByteBuffer> _data;
+ private ByteBuffer _buffer;
+
+ /**
+ * Create an InputStream from the specified DocumentEntry
+ *
+ * @param document the DocumentEntry to be read
+ *
+ * @exception IOException if the DocumentEntry cannot be opened (like, maybe it has
+ * been deleted?)
+ */
+ public NDocumentInputStream(DocumentEntry document) throws IOException {
+ if (!(document instanceof DocumentNode)) {
+ throw new IOException("Cannot open internal document storage");
+ }
+ _current_offset = 0;
+ _current_block_count = 0;
+ _marked_offset = 0;
+ _marked_offset_count = 0;
+ _document_size = document.getSize();
+ _closed = false;
+
+ DocumentNode doc = (DocumentNode)document;
+ DocumentProperty property = (DocumentProperty)doc.getProperty();
+ _document = new NPOIFSDocument(
+ property,
+ ((DirectoryNode)doc.getParent()).getNFileSystem()
+ );
+ _data = _document.getBlockIterator();
+ }
+
+ /**
+ * Create an InputStream from the specified Document
+ *
+ * @param document the Document to be read
+ */
+ public NDocumentInputStream(NPOIFSDocument document) {
+ _current_offset = 0;
+ _current_block_count = 0;
+ _marked_offset = 0;
+ _marked_offset_count = 0;
+ _document_size = document.getSize();
+ _closed = false;
+ _document = document;
+ _data = _document.getBlockIterator();
+ }
+
+ public int available() {
+ if (_closed) {
+ throw new IllegalStateException("cannot perform requested operation on a closed stream");
+ }
+ return _document_size - _current_offset;
+ }
+
+ public void close() {
+ _closed = true;
+ }
+
+ public void mark(int ignoredReadlimit) {
+ _marked_offset = _current_offset;
+ _marked_offset_count = _current_block_count;
+ }
+
+ /**
+ * Tests if this input stream supports the mark and reset methods.
+ *
+ * @return <code>true</code> always
+ */
+ public boolean markSupported() {
+ return true;
+ }
+
+ public int read() throws IOException {
+ dieIfClosed();
+ if (atEOD()) {
+ return EOF;
+ }
+ byte[] b = new byte[1];
+ int result = read(b, 0, 1);
+ if(result >= 0) {
+ if(b[0] < 0) {
+ return b[0]+256;
+ }
+ return b[0];
+ }
+ return result;
+ }
+
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ dieIfClosed();
+ if (b == null) {
+ throw new IllegalArgumentException("buffer must not be null");
+ }
+ if (off < 0 || len < 0 || b.length < off + len) {
+ throw new IndexOutOfBoundsException("can't read past buffer boundaries");
+ }
+ if (len == 0) {
+ return 0;
+ }
+ if (atEOD()) {
+ return EOF;
+ }
+ int limit = Math.min(available(), len);
+ readFully(b, off, limit);
+ return limit;
+ }
+
+ /**
+ * Repositions this stream to the position at the time the mark() method was
+ * last called on this input stream. If mark() has not been called this
+ * method repositions the stream to its beginning.
+ */
+ public void reset() {
+ // Special case for reset to the start
+ if(_marked_offset == 0 && _marked_offset_count == 0) {
+ _current_block_count = _marked_offset_count;
+ _current_offset = _marked_offset;
+ _data = _document.getBlockIterator();
+ _buffer = null;
+ return;
+ }
+
+ // Start again, then wind on to the required block
+ _data = _document.getBlockIterator();
+ _current_offset = 0;
+ for(int i=0; i<_marked_offset_count; i++) {
+ _buffer = _data.next();
+ _current_offset += _buffer.remaining();
+ }
+
+ _current_block_count = _marked_offset_count;
+
+ // Do we need to position within it?
+ if(_current_offset != _marked_offset) {
+ // Grab the right block
+ _buffer = _data.next();
+ _current_block_count++;
+
+ // Skip to the right place in it
+ _buffer.position(_marked_offset - _current_offset);
+ }
+
+ // All done
+ _current_offset = _marked_offset;
+ }
+
+ public long skip(long n) throws IOException {
+ dieIfClosed();
+ if (n < 0) {
+ return 0;
+ }
+ int new_offset = _current_offset + (int) n;
+
+ if (new_offset < _current_offset) {
+ // wrap around in converting a VERY large long to an int
+ new_offset = _document_size;
+ } else if (new_offset > _document_size) {
+ new_offset = _document_size;
+ }
+
+ long rval = new_offset - _current_offset;
+
+ // TODO Do this better
+ byte[] skip = new byte[(int)rval];
+ readFully(skip);
+ return rval;
+ }
+
+ private void dieIfClosed() throws IOException {
+ if (_closed) {
+ throw new IOException("cannot perform requested operation on a closed stream");
+ }
+ }
+
+ private boolean atEOD() {
+ return _current_offset == _document_size;
+ }
+
+ private void checkAvaliable(int requestedSize) {
+ if (_closed) {
+ throw new IllegalStateException("cannot perform requested operation on a closed stream");
+ }
+ if (requestedSize > _document_size - _current_offset) {
+ throw new RuntimeException("Buffer underrun - requested " + requestedSize
+ + " bytes but " + (_document_size - _current_offset) + " was available");
+ }
+ }
+
+ public byte readByte() {
+ return (byte) readUByte();
+ }
+
+ public double readDouble() {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ public void readFully(byte[] buf) {
+ readFully(buf, 0, buf.length);
+ }
+
+ public short readShort() {
+ return (short) readUShort();
+ }
+
+ public void readFully(byte[] buf, int off, int len) {
+ checkAvaliable(len);
+
+ int read = 0;
+ while(read < len) {
+ if(_buffer == null || _buffer.remaining() == 0) {
+ _current_block_count++;
+ _buffer = _data.next();
+ }
+
+ int limit = Math.min(len-read, _buffer.remaining());
+ _buffer.get(buf, off+read, limit);
+ _current_offset += limit;
+ read += limit;
+ }
+ }
+
+ public long readLong() {
+ checkAvaliable(SIZE_LONG);
+ byte[] data = new byte[SIZE_LONG];
+ readFully(data, 0, SIZE_LONG);
+ return LittleEndian.getLong(data, 0);
+ }
+
+ public int readInt() {
+ checkAvaliable(SIZE_INT);
+ byte[] data = new byte[SIZE_INT];
+ readFully(data, 0, SIZE_INT);
+ return LittleEndian.getInt(data);
+ }
+
+ public int readUShort() {
+ checkAvaliable(SIZE_SHORT);
+ byte[] data = new byte[SIZE_SHORT];
+ readFully(data, 0, SIZE_SHORT);
+ return LittleEndian.getShort(data);
+ }
+
+ public int readUByte() {
+ checkAvaliable(1);
+ byte[] data = new byte[1];
+ readFully(data, 0, 1);
+ if(data[0] >= 0)
+ return data[0];
+ return data[0] + 256;
+ }
+}
Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java?rev=1053279&r1=1053278&r2=1053279&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java Tue Dec 28 08:52:50 2010
@@ -100,6 +100,14 @@ public final class NPOIFSDocument implem
this._property = new DocumentProperty(name, contents.length);
_property.setStartBlock(_stream.getStartBlock());
}
+
+ int getDocumentBlockSize() {
+ return _block_size;
+ }
+
+ Iterator<ByteBuffer> getBlockIterator() {
+ return _stream.getBlockIterator();
+ }
/**
* @return size of the document
Modified: poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java?rev=1053279&r1=1053278&r2=1053279&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java (original)
+++ poi/trunk/src/java/org/apache/poi/poifs/filesystem/NPOIFSMiniStore.java Tue Dec 28 08:52:50 2010
@@ -70,13 +70,16 @@ public class NPOIFSMiniStore extends Blo
}
ByteBuffer dataBlock = it.next();
- // Skip forward to the right place
+ // Our blocks are small, so duplicating it is fine
+ byte[] data = new byte[POIFSConstants.SMALL_BLOCK_SIZE];
dataBlock.position(
dataBlock.position() + bigBlockOffset
);
+ dataBlock.get(data, 0, data.length);
- // All done
- return dataBlock;
+ // Return a ByteBuffer on this
+ ByteBuffer miniBuffer = ByteBuffer.wrap(data);
+ return miniBuffer;
}
/**
Modified: poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java?rev=1053279&r1=1053278&r2=1053279&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/poifs/filesystem/TestNPOIFSFileSystem.java Tue Dec 28 08:52:50 2010
@@ -23,6 +23,10 @@ import java.util.Iterator;
import junit.framework.TestCase;
import org.apache.poi.POIDataSamples;
+import org.apache.poi.hpsf.DocumentSummaryInformation;
+import org.apache.poi.hpsf.PropertySet;
+import org.apache.poi.hpsf.PropertySetFactory;
+import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.property.NPropertyTable;
import org.apache.poi.poifs.property.Property;
@@ -446,12 +450,25 @@ public final class TestNPOIFSFileSystem
NPOIFSFileSystem fsD = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB,fsC,fsD}) {
DirectoryEntry root = fs.getRoot();
- Entry dsi = root.getEntry("\u0005DocumentSummaryInformation");
-
- assertEquals(true, dsi.isDocumentEntry());
- DocumentEntry doc = (DocumentEntry)dsi;
+ Entry si = root.getEntry("\u0005SummaryInformation");
+ assertEquals(true, si.isDocumentEntry());
+ DocumentNode doc = (DocumentNode)si;
+ // Check we can read it
+ NDocumentInputStream inp = new NDocumentInputStream(doc);
+ byte[] contents = new byte[doc.getSize()];
+ assertEquals(doc.getSize(), inp.read(contents));
+
+ // Now try to build the property set
+ inp = new NDocumentInputStream(doc);
+ PropertySet ps = PropertySetFactory.create(inp);
+ SummaryInformation inf = (SummaryInformation)ps;
+
+ // Check some bits in it
+ assertEquals(null, inf.getApplicationName());
+ assertEquals(null, inf.getAuthor());
+ assertEquals(null, inf.getSubject());
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org