From 9a865f1a3023c19864f082c540e9316556494bfc Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Tue, 28 Dec 2010 07:15:38 +0000 Subject: [PATCH] Add NPOIFS high level Document implementation git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1053273 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/poifs/filesystem/DirectoryNode.java | 30 ++- .../poi/poifs/filesystem/NPOIFSDocument.java | 185 ++++++++++++++++++ .../poifs/filesystem/NPOIFSFileSystem.java | 4 +- .../apache/poi/poifs/storage/BATBlock.java | 6 + 4 files changed, 216 insertions(+), 9 deletions(-) create mode 100644 src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java diff --git a/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java b/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java index 5b0cfb660..92261929a 100644 --- a/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java +++ b/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java @@ -187,7 +187,6 @@ public class DirectoryNode * * @exception IOException */ - DocumentEntry createDocument(final POIFSDocument document) throws IOException { @@ -195,12 +194,30 @@ public class DirectoryNode DocumentNode rval = new DocumentNode(property, this); (( DirectoryProperty ) getProperty()).addChild(property); + _ofilesystem.addDocument(document); - if(_ofilesystem != null) { - _ofilesystem.addDocument(document); - } else { - _nfilesystem.addDocument(document); - } + _entries.add(rval); + _byname.put(property.getName(), rval); + return rval; + } + + /** + * create a new DocumentEntry + * + * @param document the new document + * + * @return the new DocumentEntry + * + * @exception IOException + */ + DocumentEntry createDocument(final NPOIFSDocument document) + throws IOException + { + DocumentProperty property = document.getDocumentProperty(); + DocumentNode rval = new DocumentNode(property, this); + + (( DirectoryProperty ) getProperty()).addChild(property); + _nfilesystem.addDocument(document); _entries.add(rval); _byname.put(property.getName(), rval); @@ -215,7 +232,6 @@ public class DirectoryNode * * @return true if the operation succeeded, else false */ - boolean changeName(final String oldName, final String newName) { boolean rval = false; diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java new file mode 100644 index 000000000..08c66b677 --- /dev/null +++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSDocument.java @@ -0,0 +1,185 @@ +/* ==================================================================== + 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.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.Iterator; + +import org.apache.poi.poifs.common.POIFSConstants; +import org.apache.poi.poifs.dev.POIFSViewable; +import org.apache.poi.poifs.property.DocumentProperty; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.IOUtils; + +/** + * This class manages a document in the NIO POIFS filesystem. + * This is the {@link NPOIFSFileSystem} version. + */ +public final class NPOIFSDocument implements POIFSViewable { + private DocumentProperty _property; + + private NPOIFSFileSystem _filesystem; + private NPOIFSStream _stream; + private int _block_size; + + /** + * Constructor for an existing Document + */ + public NPOIFSDocument(DocumentProperty property, NPOIFSFileSystem filesystem) + throws IOException + { + this._property = property; + this._filesystem = filesystem; + + if(property.getSize() <= POIFSConstants.BIG_BLOCK_MINIMUM_DOCUMENT_SIZE) { + _stream = new NPOIFSStream(_filesystem.getMiniStore(), property.getStartBlock()); + _block_size = _filesystem.getMiniStore().getBlockStoreBlockSize(); + } else { + _stream = new NPOIFSStream(_filesystem, property.getStartBlock()); + _block_size = _filesystem.getBlockStoreBlockSize(); + } + } + + /** + * Constructor for a new Document + * + * @param name the name of the POIFSDocument + * @param stream the InputStream we read data from + */ + public NPOIFSDocument(String name, NPOIFSFileSystem filesystem, InputStream stream) + throws IOException + { + this._filesystem = filesystem; + + // Buffer the contents into memory. This is a bit icky... + // TODO Replace with a buffer up to the mini stream size, then streaming write + byte[] contents; + if(stream instanceof ByteArrayInputStream) { + ByteArrayInputStream bais = (ByteArrayInputStream)stream; + contents = new byte[bais.available()]; + bais.read(contents); + } else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IOUtils.copy(stream, baos); + contents = baos.toByteArray(); + } + + // Do we need to store as a mini stream or a full one? + if(contents.length <= POIFSConstants.BIG_BLOCK_MINIMUM_DOCUMENT_SIZE) { + _stream = new NPOIFSStream(filesystem.getMiniStore()); + _block_size = _filesystem.getMiniStore().getBlockStoreBlockSize(); + } else { + _stream = new NPOIFSStream(filesystem); + _block_size = _filesystem.getBlockStoreBlockSize(); + } + + // Store it + _stream.updateContents(contents); + + // And build the property for it + this._property = new DocumentProperty(name, contents.length); + _property.setStartBlock(_stream.getStartBlock()); + } + + /** + * @return size of the document + */ + public int getSize() { + return _property.getSize(); + } + + /** + * @return the instance's DocumentProperty + */ + DocumentProperty getDocumentProperty() { + return _property; + } + + /** + * Get an array of objects, some of which may implement POIFSViewable + * + * @return an array of Object; may not be null, but may be empty + */ + public Object[] getViewableArray() { + Object[] results = new Object[1]; + String result; + + try { + if(getSize() > 0) { + // Get all the data into a single array + byte[] data = new byte[getSize()]; + int offset = 0; + for(ByteBuffer buffer : _stream) { + int length = Math.min(_block_size, data.length-offset); + buffer.get(data, offset, length); + offset += length; + } + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + HexDump.dump(data, 0, output, 0); + result = output.toString(); + } else { + result = ""; + } + } catch (IOException e) { + result = e.getMessage(); + } + results[0] = result; + return results; + } + + /** + * Get an Iterator of objects, some of which may implement POIFSViewable + * + * @return an Iterator; may not be null, but may have an empty back end + * store + */ + public Iterator getViewableIterator() { + return Collections.EMPTY_LIST.iterator(); + } + + /** + * Give viewers a hint as to whether to call getViewableArray or + * getViewableIterator + * + * @return true if a viewer should call getViewableArray, + * false if a viewer should call getViewableIterator + */ + public boolean preferArray() { + return true; + } + + /** + * Provides a short description of the object, to be used when a + * POIFSViewable object has not provided its contents. + * + * @return short description + */ + public String getShortDescription() { + StringBuffer buffer = new StringBuffer(); + + buffer.append("Document: \"").append(_property.getName()).append("\""); + buffer.append(" size = ").append(getSize()); + return buffer.toString(); + } +} diff --git a/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java index c292b0a92..a397136c2 100644 --- a/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java +++ b/src/java/org/apache/poi/poifs/filesystem/NPOIFSFileSystem.java @@ -279,7 +279,7 @@ public class NPOIFSFileSystem extends BlockStore ByteBuffer fatData = getBlockAt(nextAt); xfat = BATBlock.createBATBlock(bigBlockSize, fatData); xfat.setOurBlockIndex(nextAt); - nextAt = xfat.getValueAt(bigBlockSize.getNextXBATChainOffset()); + nextAt = xfat.getValueAt(bigBlockSize.getXBATEntriesPerBlock()); _bat_blocks.add(xfat); } @@ -464,7 +464,7 @@ public class NPOIFSFileSystem extends BlockStore * * @param document the POIFSDocument being added */ - void addDocument(final POIFSDocument document) + void addDocument(final NPOIFSDocument document) { _property_table.addProperty(document.getDocumentProperty()); } diff --git a/src/java/org/apache/poi/poifs/storage/BATBlock.java b/src/java/org/apache/poi/poifs/storage/BATBlock.java index 6f85c84c7..36da6dc38 100644 --- a/src/java/org/apache/poi/poifs/storage/BATBlock.java +++ b/src/java/org/apache/poi/poifs/storage/BATBlock.java @@ -310,6 +310,12 @@ public final class BATBlock extends BigBlock { } public int getValueAt(int relativeOffset) { + if(relativeOffset >= _values.length) { + throw new ArrayIndexOutOfBoundsException( + "Unable to fetch offset " + relativeOffset + " as the " + + "BAT only contains " + _values.length + " entries" + ); + } return _values[relativeOffset]; } public void setValueAt(int relativeOffset, int value) {