--- /dev/null
+/* ====================================================================
+ 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 = "<NO DATA>";
+ }
+ } 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 <code>true</code> if a viewer should call getViewableArray,
+ * <code>false</code> 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();
+ }
+}