Start on PropertyTable support for NPOIFS, and more NPOIFS tests
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1052205 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4d3ddefa5b
commit
574e993120
@ -43,6 +43,7 @@ import org.apache.poi.poifs.nio.ByteArrayBackedDataSource;
|
||||
import org.apache.poi.poifs.nio.DataSource;
|
||||
import org.apache.poi.poifs.nio.FileBackedDataSource;
|
||||
import org.apache.poi.poifs.property.DirectoryProperty;
|
||||
import org.apache.poi.poifs.property.NPropertyTable;
|
||||
import org.apache.poi.poifs.property.Property;
|
||||
import org.apache.poi.poifs.property.PropertyTable;
|
||||
import org.apache.poi.poifs.storage.BATBlock;
|
||||
@ -82,8 +83,8 @@ public class NPOIFSFileSystem
|
||||
return new CloseIgnoringInputStream(is);
|
||||
}
|
||||
|
||||
private PropertyTable _property_table;
|
||||
private List<BATBlock> _bat_blocks;
|
||||
private NPropertyTable _property_table;
|
||||
private List<BATBlock> _bat_blocks;
|
||||
private HeaderBlock _header;
|
||||
private DirectoryNode _root;
|
||||
|
||||
@ -104,7 +105,7 @@ public class NPOIFSFileSystem
|
||||
public NPOIFSFileSystem()
|
||||
{
|
||||
_header = new HeaderBlock(bigBlockSize);
|
||||
_property_table = new PropertyTable(_header);// TODO Needs correct type
|
||||
_property_table = new NPropertyTable(_header);
|
||||
_bat_blocks = new ArrayList<BATBlock>();
|
||||
_root = null;
|
||||
}
|
||||
@ -191,8 +192,9 @@ public class NPOIFSFileSystem
|
||||
int maxSize = BATBlock.calculateMaximumSize(_header);
|
||||
ByteBuffer data = ByteBuffer.allocate(maxSize);
|
||||
// Copy in the header
|
||||
headerBuffer.position(0);
|
||||
data.put(headerBuffer);
|
||||
data.position(_header.getBigBlockSize().getBigBlockSize());
|
||||
data.position(headerBuffer.capacity());
|
||||
// Now read the rest of the stream
|
||||
IOUtils.readFully(channel, data);
|
||||
success = true;
|
||||
@ -292,7 +294,7 @@ public class NPOIFSFileSystem
|
||||
|
||||
// We're now able to load steams
|
||||
// Use this to read in the properties
|
||||
// TODO
|
||||
_property_table = new NPropertyTable(_header, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,10 +481,6 @@ public class NPOIFSFileSystem
|
||||
public void writeFilesystem(final OutputStream stream)
|
||||
throws IOException
|
||||
{
|
||||
|
||||
// get the property table ready
|
||||
_property_table.preWrite();
|
||||
|
||||
// create the small block store, and the SBAT
|
||||
SmallBlockTableWriter sbtw =
|
||||
new SmallBlockTableWriter(bigBlockSize, _documents, _property_table.getRoot());
|
||||
@ -550,7 +548,6 @@ public class NPOIFSFileSystem
|
||||
|
||||
writers.add(header_block_writer);
|
||||
writers.addAll(_documents);
|
||||
writers.add(_property_table);
|
||||
writers.add(sbtw);
|
||||
writers.add(sbtw.getSBAT());
|
||||
writers.add(bat);
|
||||
@ -567,6 +564,11 @@ public class NPOIFSFileSystem
|
||||
|
||||
writer.writeBlocks(stream);
|
||||
}
|
||||
|
||||
// Finally have the property table serialise itself
|
||||
_property_table.write(
|
||||
new NPOIFSStream(this, _header.getPropertyStart())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
128
src/java/org/apache/poi/poifs/property/NPropertyTable.java
Normal file
128
src/java/org/apache/poi/poifs/property/NPropertyTable.java
Normal file
@ -0,0 +1,128 @@
|
||||
/* ====================================================================
|
||||
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.property;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.poifs.common.POIFSBigBlockSize;
|
||||
import org.apache.poi.poifs.common.POIFSConstants;
|
||||
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
|
||||
import org.apache.poi.poifs.filesystem.NPOIFSStream;
|
||||
import org.apache.poi.poifs.storage.HeaderBlock;
|
||||
|
||||
/**
|
||||
* This class embodies the Property Table for a {@link NPOIFSFileSystem};
|
||||
* this is basically the directory for all of the documents in the
|
||||
* filesystem.
|
||||
*/
|
||||
public final class NPropertyTable extends PropertyTableBase {
|
||||
private POIFSBigBlockSize _bigBigBlockSize;
|
||||
|
||||
public NPropertyTable(HeaderBlock headerBlock)
|
||||
{
|
||||
super(headerBlock);
|
||||
_bigBigBlockSize = headerBlock.getBigBlockSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* reading constructor (used when we've read in a file and we want
|
||||
* to extract the property table from it). Populates the
|
||||
* properties thoroughly
|
||||
*
|
||||
* @param headerBlock the header block of the file
|
||||
* @param filesystem the filesystem to read from
|
||||
*
|
||||
* @exception IOException if anything goes wrong (which should be
|
||||
* a result of the input being NFG)
|
||||
*/
|
||||
public NPropertyTable(final HeaderBlock headerBlock,
|
||||
final NPOIFSFileSystem filesystem)
|
||||
throws IOException
|
||||
{
|
||||
super(
|
||||
headerBlock,
|
||||
buildProperties(
|
||||
(new NPOIFSStream(filesystem, headerBlock.getPropertyStart())).iterator(),
|
||||
headerBlock.getBigBlockSize()
|
||||
)
|
||||
);
|
||||
_bigBigBlockSize = headerBlock.getBigBlockSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds
|
||||
* @param startAt
|
||||
* @param filesystem
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private static List<Property> buildProperties(final Iterator<ByteBuffer> dataSource,
|
||||
final POIFSBigBlockSize bigBlockSize) throws IOException
|
||||
{
|
||||
List<Property> properties = new ArrayList<Property>();
|
||||
while(dataSource.hasNext()) {
|
||||
ByteBuffer bb = dataSource.next();
|
||||
|
||||
// Turn it into an array
|
||||
byte[] data;
|
||||
if(bb.hasArray() && bb.arrayOffset() == 0 &&
|
||||
bb.array().length == bigBlockSize.getBigBlockSize()) {
|
||||
data = bb.array();
|
||||
} else {
|
||||
data = new byte[bigBlockSize.getBigBlockSize()];
|
||||
bb.get(data, 0, data.length);
|
||||
}
|
||||
|
||||
PropertyFactory.convertToProperties(data, properties);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of BigBlock's this instance uses
|
||||
*
|
||||
* @return count of BigBlock instances
|
||||
*/
|
||||
public int countBlocks()
|
||||
{
|
||||
int size = _properties.size() * POIFSConstants.PROPERTY_SIZE;
|
||||
return (int)Math.ceil(size / _bigBigBlockSize.getBigBlockSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the properties out into the given low-level stream
|
||||
*/
|
||||
public void write(NPOIFSStream stream) throws IOException {
|
||||
// TODO - Use a streaming write
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for(Property property : _properties) {
|
||||
property.writeData(baos);
|
||||
}
|
||||
stream.updateContents(baos.toByteArray());
|
||||
|
||||
// Update the start position if needed
|
||||
if(getStartBlock() != stream.getStartBlock()) {
|
||||
setStartBlock(stream.getStartBlock());
|
||||
}
|
||||
}
|
||||
}
|
@ -55,8 +55,19 @@ public final class TestNPOIFSFileSystem extends TestCase {
|
||||
fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
|
||||
fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
|
||||
for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
|
||||
// Check the FAT was properly processed
|
||||
// TODO
|
||||
// Check the FAT was properly processed:
|
||||
// Verify we only got one block
|
||||
fs.getBATBlockAndIndex(0);
|
||||
fs.getBATBlockAndIndex(1);
|
||||
try {
|
||||
fs.getBATBlockAndIndex(140);
|
||||
fail("Should only be one BAT, but a 2nd was found");
|
||||
} catch(IndexOutOfBoundsException e) {}
|
||||
|
||||
// Verify a few next offsets
|
||||
// 97 -> 98 -> END
|
||||
assertEquals(98, fs.getNextBlock(97));
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
|
||||
|
||||
// Check the properties
|
||||
// TODO
|
||||
@ -67,7 +78,19 @@ public final class TestNPOIFSFileSystem extends TestCase {
|
||||
fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
|
||||
for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
|
||||
// Check the FAT was properly processed
|
||||
// TODO
|
||||
// Verify we only got one block
|
||||
fs.getBATBlockAndIndex(0);
|
||||
fs.getBATBlockAndIndex(1);
|
||||
try {
|
||||
fs.getBATBlockAndIndex(1040);
|
||||
fail("Should only be one BAT, but a 2nd was found");
|
||||
} catch(IndexOutOfBoundsException e) {}
|
||||
|
||||
// Verify a few next offsets
|
||||
// 0 -> 1 -> 2 -> END
|
||||
assertEquals(1, fs.getNextBlock(0));
|
||||
assertEquals(2, fs.getNextBlock(1));
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(2));
|
||||
|
||||
// Check the properties
|
||||
// TODO
|
||||
@ -79,72 +102,81 @@ public final class TestNPOIFSFileSystem extends TestCase {
|
||||
* out what the next one is
|
||||
*/
|
||||
public void testNextBlock() throws Exception {
|
||||
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
|
||||
|
||||
// 0 -> 21 are simple
|
||||
for(int i=0; i<21; i++) {
|
||||
assertEquals(i+1, fs.getNextBlock(i));
|
||||
NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
|
||||
NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
|
||||
for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
|
||||
// 0 -> 21 are simple
|
||||
for(int i=0; i<21; i++) {
|
||||
assertEquals(i+1, fs.getNextBlock(i));
|
||||
}
|
||||
// 21 jumps to 89, then ends
|
||||
assertEquals(89, fs.getNextBlock(21));
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(89));
|
||||
|
||||
// 22 -> 88 simple sequential stream
|
||||
for(int i=22; i<88; i++) {
|
||||
assertEquals(i+1, fs.getNextBlock(i));
|
||||
}
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(88));
|
||||
|
||||
// 90 -> 96 is another stream
|
||||
for(int i=90; i<96; i++) {
|
||||
assertEquals(i+1, fs.getNextBlock(i));
|
||||
}
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(96));
|
||||
|
||||
// 97+98 is another
|
||||
assertEquals(98, fs.getNextBlock(97));
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
|
||||
|
||||
// 99 is our FAT block
|
||||
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
|
||||
|
||||
// 100 onwards is free
|
||||
for(int i=100; i<fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) {
|
||||
assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(i));
|
||||
}
|
||||
}
|
||||
// 21 jumps to 89, then ends
|
||||
assertEquals(89, fs.getNextBlock(21));
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(89));
|
||||
|
||||
// 22 -> 88 simple sequential stream
|
||||
for(int i=22; i<88; i++) {
|
||||
assertEquals(i+1, fs.getNextBlock(i));
|
||||
}
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(88));
|
||||
|
||||
// 90 -> 96 is another stream
|
||||
for(int i=90; i<96; i++) {
|
||||
assertEquals(i+1, fs.getNextBlock(i));
|
||||
}
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(96));
|
||||
|
||||
// 97+98 is another
|
||||
assertEquals(98, fs.getNextBlock(97));
|
||||
assertEquals(POIFSConstants.END_OF_CHAIN, fs.getNextBlock(98));
|
||||
|
||||
// 99 is our FAT block
|
||||
assertEquals(POIFSConstants.FAT_SECTOR_BLOCK, fs.getNextBlock(99));
|
||||
|
||||
// 100 onwards is free
|
||||
for(int i=100; i<fs.getBigBlockSizeDetails().getBATEntriesPerBlock(); i++) {
|
||||
assertEquals(POIFSConstants.UNUSED_BLOCK, fs.getNextBlock(i));
|
||||
}
|
||||
// TODO Check a few bits of a 4096 byte file
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we get the right data back for each block
|
||||
*/
|
||||
public void testGetBlock() throws Exception {
|
||||
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
|
||||
ByteBuffer b;
|
||||
NPOIFSFileSystem fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
|
||||
NPOIFSFileSystem fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize512.zvi"));
|
||||
for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
|
||||
ByteBuffer b;
|
||||
|
||||
// The 0th block is the first data block
|
||||
b = fs.getBlockAt(0);
|
||||
assertEquals((byte)0x9e, b.get());
|
||||
assertEquals((byte)0x75, b.get());
|
||||
assertEquals((byte)0x97, b.get());
|
||||
assertEquals((byte)0xf6, b.get());
|
||||
|
||||
// And the next block
|
||||
b = fs.getBlockAt(1);
|
||||
assertEquals((byte)0x86, b.get());
|
||||
assertEquals((byte)0x09, b.get());
|
||||
assertEquals((byte)0x22, b.get());
|
||||
assertEquals((byte)0xfb, b.get());
|
||||
|
||||
// Check the final block too
|
||||
b = fs.getBlockAt(99);
|
||||
assertEquals((byte)0x01, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x02, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
}
|
||||
|
||||
// The 0th block is the first data block
|
||||
b = fs.getBlockAt(0);
|
||||
assertEquals((byte)0x9e, b.get());
|
||||
assertEquals((byte)0x75, b.get());
|
||||
assertEquals((byte)0x97, b.get());
|
||||
assertEquals((byte)0xf6, b.get());
|
||||
|
||||
// And the next block
|
||||
b = fs.getBlockAt(1);
|
||||
assertEquals((byte)0x86, b.get());
|
||||
assertEquals((byte)0x09, b.get());
|
||||
assertEquals((byte)0x22, b.get());
|
||||
assertEquals((byte)0xfb, b.get());
|
||||
|
||||
// Check the final block too
|
||||
b = fs.getBlockAt(99);
|
||||
assertEquals((byte)0x01, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x02, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
assertEquals((byte)0x00, b.get());
|
||||
// TODO Check a few bits of a 4096 byte file
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user