More NPOIFSFileSystem and NPOIFSStream read unit tests, along with details of a few more tests still to be written

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1052186 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2010-12-23 07:08:50 +00:00
parent 39f533b4d0
commit e911c35421
4 changed files with 343 additions and 6 deletions

View File

@ -653,12 +653,21 @@ public class NPOIFSFileSystem
* we can bail out with an error rather than
* spinning away for ever...
*/
private class ChainLoopDetector {
protected class ChainLoopDetector {
private boolean[] used_blocks;
private ChainLoopDetector() throws IOException {
used_blocks = new boolean[(int)(_data.size()/bigBlockSize.getBigBlockSize())];
protected ChainLoopDetector() throws IOException {
int numBlocks = (int)Math.ceil(_data.size()/bigBlockSize.getBigBlockSize());
used_blocks = new boolean[numBlocks];
}
private void claim(int offset) {
protected void claim(int offset) {
if(offset >= used_blocks.length) {
// They're writing, and have had new blocks requested
// for the write to proceed. That means they're into
// blocks we've allocated for them, so are safe
return;
}
// Claiming an existing block, ensure there's no loop
if(used_blocks[offset]) {
throw new IllegalStateException(
"Potential loop detected - Block " + offset +

View File

@ -24,6 +24,7 @@ import java.nio.ByteBuffer;
import java.util.Iterator;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem.ChainLoopDetector;
import org.apache.poi.poifs.property.Property;
import org.apache.poi.poifs.storage.HeaderBlock;
@ -38,6 +39,8 @@ import org.apache.poi.poifs.storage.HeaderBlock;
* This only works on big block streams, it doesn't
* handle small block ones.
* This uses the new NIO code
*
* TODO Add loop checking on read and on write
*/
public class NPOIFSStream implements Iterable<ByteBuffer>
@ -100,11 +103,16 @@ public class NPOIFSStream implements Iterable<ByteBuffer>
// How many blocks are we going to need?
int blocks = (int)Math.ceil(contents.length / filesystem.getBigBlockSize());
// Make sure we don't encounter a loop whilst overwriting
// the existing blocks
ChainLoopDetector loopDetector = filesystem.new ChainLoopDetector();
// Start writing
int prevBlock = POIFSConstants.END_OF_CHAIN;
int nextBlock = startBlock;
for(int i=0; i<blocks; i++) {
int thisBlock = nextBlock;
loopDetector.claim(thisBlock);
// Allocate a block if needed, otherwise figure
// out what the next block will be
@ -128,6 +136,9 @@ public class NPOIFSStream implements Iterable<ByteBuffer>
prevBlock = thisBlock;
}
// If we're overwriting, free any remaining blocks
// TODO
// Mark the end of the stream
filesystem.setNextBlock(nextBlock, POIFSConstants.END_OF_CHAIN);
}
@ -138,9 +149,16 @@ public class NPOIFSStream implements Iterable<ByteBuffer>
* Class that handles a streaming read of one stream
*/
protected class StreamBlockByteBufferIterator implements Iterator<ByteBuffer> {
private ChainLoopDetector loopDetector;
private int nextBlock;
protected StreamBlockByteBufferIterator(int firstBlock) {
nextBlock = firstBlock;
this.nextBlock = firstBlock;
try {
this.loopDetector = filesystem.new ChainLoopDetector();
} catch(IOException e) {
throw new RuntimeException(e);
}
}
public boolean hasNext() {
@ -156,6 +174,7 @@ public class NPOIFSStream implements Iterable<ByteBuffer>
}
try {
loopDetector.claim(nextBlock);
ByteBuffer data = filesystem.getBlockAt(nextBlock);
nextBlock = filesystem.getNextBlock(nextBlock);
return data;

View File

@ -17,6 +17,8 @@
package org.apache.poi.poifs.filesystem;
import java.nio.ByteBuffer;
import junit.framework.TestCase;
import org.apache.poi.POIDataSamples;
@ -116,6 +118,32 @@ public final class TestNPOIFSFileSystem extends TestCase {
* Check we get the right data back for each block
*/
public void testGetBlock() throws Exception {
// TODO
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
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());
}
}

View File

@ -0,0 +1,281 @@
/* ====================================================================
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.nio.ByteBuffer;
import java.util.Iterator;
import junit.framework.TestCase;
import org.apache.poi.POIDataSamples;
/**
* Tests {@link NPOIFSStream}
*/
public final class TestNPOIFSStream extends TestCase {
private static final POIDataSamples _inst = POIDataSamples.getPOIFSInstance();
/**
* Read a single block stream
*/
public void testReadTinyStream() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
// 98 is actually the last block in a two block stream...
NPOIFSStream stream = new NPOIFSStream(fs, 98);
Iterator<ByteBuffer> i = stream.getBlockIterator();
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
ByteBuffer b = i.next();
assertEquals(false, i.hasNext());
assertEquals(false, i.hasNext());
assertEquals(false, i.hasNext());
// Check the contents
assertEquals((byte)0x81, b.get());
assertEquals((byte)0x00, b.get());
assertEquals((byte)0x00, b.get());
assertEquals((byte)0x00, b.get());
assertEquals((byte)0x82, b.get());
assertEquals((byte)0x00, b.get());
assertEquals((byte)0x00, b.get());
assertEquals((byte)0x00, b.get());
}
/**
* Read a stream with only two blocks in it
*/
public void testReadShortStream() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
// 97 -> 98 -> end
NPOIFSStream stream = new NPOIFSStream(fs, 97);
Iterator<ByteBuffer> i = stream.getBlockIterator();
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
ByteBuffer b97 = i.next();
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
ByteBuffer b98 = i.next();
assertEquals(false, i.hasNext());
assertEquals(false, i.hasNext());
assertEquals(false, i.hasNext());
// Check the contents of the 1st block
assertEquals((byte)0x01, b97.get());
assertEquals((byte)0x00, b97.get());
assertEquals((byte)0x00, b97.get());
assertEquals((byte)0x00, b97.get());
assertEquals((byte)0x02, b97.get());
assertEquals((byte)0x00, b97.get());
assertEquals((byte)0x00, b97.get());
assertEquals((byte)0x00, b97.get());
// Check the contents of the 2nd block
assertEquals((byte)0x81, b98.get());
assertEquals((byte)0x00, b98.get());
assertEquals((byte)0x00, b98.get());
assertEquals((byte)0x00, b98.get());
assertEquals((byte)0x82, b98.get());
assertEquals((byte)0x00, b98.get());
assertEquals((byte)0x00, b98.get());
assertEquals((byte)0x00, b98.get());
}
/**
* Read a stream with many blocks
*/
public void testReadLongerStream() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
ByteBuffer b0 = null;
ByteBuffer b1 = null;
ByteBuffer b22 = null;
// The stream at 0 has 23 blocks in it
NPOIFSStream stream = new NPOIFSStream(fs, 0);
Iterator<ByteBuffer> i = stream.getBlockIterator();
int count = 0;
while(i.hasNext()) {
ByteBuffer b = i.next();
if(count == 0) {
b0 = b;
}
if(count == 1) {
b1 = b;
}
if(count == 22) {
b22 = b;
}
count++;
}
assertEquals(23, count);
// Check the contents
// 1st block is at 0
assertEquals((byte)0x9e, b0.get());
assertEquals((byte)0x75, b0.get());
assertEquals((byte)0x97, b0.get());
assertEquals((byte)0xf6, b0.get());
// 2nd block is at 1
assertEquals((byte)0x86, b1.get());
assertEquals((byte)0x09, b1.get());
assertEquals((byte)0x22, b1.get());
assertEquals((byte)0xfb, b1.get());
// last block is at 89
assertEquals((byte)0xfe, b22.get());
assertEquals((byte)0xff, b22.get());
assertEquals((byte)0x00, b22.get());
assertEquals((byte)0x00, b22.get());
assertEquals((byte)0x05, b22.get());
assertEquals((byte)0x01, b22.get());
assertEquals((byte)0x02, b22.get());
assertEquals((byte)0x00, b22.get());
}
/**
* Read a stream with several blocks in a 4096 byte block file
*/
public void testReadStream4096() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
// 0 -> 1 -> 2 -> end
NPOIFSStream stream = new NPOIFSStream(fs, 0);
Iterator<ByteBuffer> i = stream.getBlockIterator();
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
ByteBuffer b0 = i.next();
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
ByteBuffer b1 = i.next();
assertEquals(true, i.hasNext());
assertEquals(true, i.hasNext());
ByteBuffer b2 = i.next();
assertEquals(false, i.hasNext());
assertEquals(false, i.hasNext());
assertEquals(false, i.hasNext());
// Check the contents of the 1st block
assertEquals((byte)0x9E, b0.get());
assertEquals((byte)0x75, b0.get());
assertEquals((byte)0x97, b0.get());
assertEquals((byte)0xF6, b0.get());
assertEquals((byte)0xFF, b0.get());
assertEquals((byte)0x21, b0.get());
assertEquals((byte)0xD2, b0.get());
assertEquals((byte)0x11, b0.get());
// Check the contents of the 2nd block
assertEquals((byte)0x00, b1.get());
assertEquals((byte)0x00, b1.get());
assertEquals((byte)0x03, b1.get());
assertEquals((byte)0x00, b1.get());
assertEquals((byte)0x00, b1.get());
assertEquals((byte)0x00, b1.get());
assertEquals((byte)0x00, b1.get());
assertEquals((byte)0x00, b1.get());
// Check the contents of the 3rd block
assertEquals((byte)0x6D, b2.get());
assertEquals((byte)0x00, b2.get());
assertEquals((byte)0x00, b2.get());
assertEquals((byte)0x00, b2.get());
assertEquals((byte)0x03, b2.get());
assertEquals((byte)0x00, b2.get());
assertEquals((byte)0x46, b2.get());
assertEquals((byte)0x00, b2.get());
}
/**
* Craft a nasty file with a loop, and ensure we don't get stuck
*/
public void testReadFailsOnLoop() throws Exception {
// TODO
}
/**
* Writing the same amount of data as before
*/
public void testReplaceStream() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
// TODO
}
/**
* Writes less data than before, some blocks will need
* to be freed
*/
public void testReplaceStreamWithLess() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
// TODO
}
/**
* Writes more data than before, new blocks will be needed
*/
public void testReplaceStreamWithMore() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
// TODO
}
/**
* Writes to a new stream in the file
*/
public void testWriteNewStream() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
// TODO
}
/**
* Writes to a new stream in the file, where we've not enough
* free blocks so new FAT segments will need to be allocated
* to support this
*/
public void testWriteNewStreamExtraFATs() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize512.zvi"));
// TODO
}
/**
* Replaces data in an existing stream, with a bit
* more data than before, in a 4096 byte block file
*/
public void testWriteStream4096() throws Exception {
NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
// TODO
}
/**
* Craft a nasty file with a loop, and ensure we don't get stuck
*/
public void testWriteFailsOnLoop() throws Exception {
// TODO
}
}