mirror of https://github.com/apache/poi.git
Change how the NIO block read works, to re-use the byte array for the from-InputStream case. Also start on reading the FAT blocks for NPOIFSFileSystem
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1050775 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
302df8aa4c
commit
aaddcfc655
|
@ -184,12 +184,18 @@ public class NPOIFSFileSystem
|
||||||
_header = new HeaderBlock(headerBuffer);
|
_header = new HeaderBlock(headerBuffer);
|
||||||
|
|
||||||
// We need to buffer the whole file into memory when
|
// We need to buffer the whole file into memory when
|
||||||
// working with an InputStream. Do so now
|
// working with an InputStream.
|
||||||
int maxSize = _header.getBATCount() *
|
// The max possible size is when each BAT block entry is used
|
||||||
|
int maxSize =
|
||||||
|
_header.getBATCount() *
|
||||||
_header.getBigBlockSize().getBATEntriesPerBlock() *
|
_header.getBigBlockSize().getBATEntriesPerBlock() *
|
||||||
_header.getBigBlockSize().getBigBlockSize();
|
_header.getBigBlockSize().getBigBlockSize()
|
||||||
|
;
|
||||||
ByteBuffer data = ByteBuffer.allocate(maxSize);
|
ByteBuffer data = ByteBuffer.allocate(maxSize);
|
||||||
|
// Copy in the header
|
||||||
data.put(headerBuffer);
|
data.put(headerBuffer);
|
||||||
|
data.position(_header.getBigBlockSize().getBigBlockSize());
|
||||||
|
// Now read the rest of the stream
|
||||||
IOUtils.readFully(channel, data);
|
IOUtils.readFully(channel, data);
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
|
@ -260,14 +266,46 @@ public class NPOIFSFileSystem
|
||||||
// Grab the block size
|
// Grab the block size
|
||||||
bigBlockSize = _header.getBigBlockSize();
|
bigBlockSize = _header.getBigBlockSize();
|
||||||
|
|
||||||
// Read the properties
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
// Read the FAT blocks
|
// Read the FAT blocks
|
||||||
// TODO
|
for(int fatAT : _header.getBATArray()) {
|
||||||
|
ByteBuffer fatData = getBlockAt(fatAT);
|
||||||
|
_blocks.add(BATBlock.createBATBlock(bigBlockSize, fatData));
|
||||||
|
}
|
||||||
|
|
||||||
// Now read the XFAT blocks
|
// Now read the XFAT blocks
|
||||||
|
// TODO Corrupt / Loop checking
|
||||||
|
BATBlock xfat;
|
||||||
|
int nextAt = _header.getXBATIndex();
|
||||||
|
for(int i=0; i<_header.getXBATCount(); i++) {
|
||||||
|
ByteBuffer fatData = getBlockAt(nextAt);
|
||||||
|
xfat = BATBlock.createBATBlock(bigBlockSize, fatData);
|
||||||
|
nextAt = xfat.getValueAt(bigBlockSize.getNextXBATChainOffset());
|
||||||
|
|
||||||
|
_blocks.add(xfat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're now able to load steams
|
||||||
|
// Use this to read in the properties
|
||||||
// TODO
|
// TODO
|
||||||
|
// TODO With loop checking
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the block at the given offset.
|
||||||
|
*/
|
||||||
|
protected ByteBuffer getBlockAt(final int offset) throws IOException {
|
||||||
|
ByteBuffer data = ByteBuffer.allocate(bigBlockSize.getBigBlockSize());
|
||||||
|
|
||||||
|
// The header block doesn't count, so add one
|
||||||
|
long startAt = (offset+1) * bigBlockSize.getBigBlockSize();
|
||||||
|
return _data.read(bigBlockSize.getBigBlockSize(), startAt);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Works out what block follows the specified one.
|
||||||
|
*/
|
||||||
|
protected int getNextBlock(final int offset) {
|
||||||
|
// TODO
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -34,16 +34,16 @@ public class ByteArrayBackedDataSource extends DataSource {
|
||||||
this(data, data.length);
|
this(data, data.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void read(ByteBuffer dst, long position) {
|
public ByteBuffer read(int length, long position) {
|
||||||
if(position >= size) {
|
if(position >= size) {
|
||||||
throw new IndexOutOfBoundsException(
|
throw new IndexOutOfBoundsException(
|
||||||
"Unable to read " + dst.capacity() + " bytes from " +
|
"Unable to read " + length + " bytes from " +
|
||||||
position + " in stream of length " + size
|
position + " in stream of length " + size
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int toRead = (int)Math.min(dst.capacity(), size - position);
|
int toRead = (int)Math.min(length, size - position);
|
||||||
dst.put(buffer, (int)position, toRead);
|
return ByteBuffer.wrap(buffer, (int)position, toRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(ByteBuffer src, long position) {
|
public void write(ByteBuffer src, long position) {
|
||||||
|
|
|
@ -24,8 +24,8 @@ import java.nio.ByteBuffer;
|
||||||
* Common definition of how we read and write bytes
|
* Common definition of how we read and write bytes
|
||||||
*/
|
*/
|
||||||
public abstract class DataSource {
|
public abstract class DataSource {
|
||||||
abstract void read(ByteBuffer dst, long position) throws IOException;
|
public abstract ByteBuffer read(int length, long position) throws IOException;
|
||||||
abstract void write(ByteBuffer src, long position) throws IOException;
|
public abstract void write(ByteBuffer src, long position) throws IOException;
|
||||||
abstract long size() throws IOException;
|
public abstract long size() throws IOException;
|
||||||
abstract void close() throws IOException;
|
public abstract void close() throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,17 +42,26 @@ public class FileBackedDataSource extends DataSource {
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void read(ByteBuffer dst, long position) throws IOException {
|
public ByteBuffer read(int length, long position) throws IOException {
|
||||||
if(position >= size()) {
|
if(position >= size()) {
|
||||||
throw new IllegalArgumentException("Position " + position + " past the end of the file");
|
throw new IllegalArgumentException("Position " + position + " past the end of the file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read
|
||||||
channel.position(position);
|
channel.position(position);
|
||||||
|
ByteBuffer dst = ByteBuffer.allocate(length);
|
||||||
int worked = IOUtils.readFully(channel, dst);
|
int worked = IOUtils.readFully(channel, dst);
|
||||||
|
|
||||||
|
// Check
|
||||||
if(worked == -1) {
|
if(worked == -1) {
|
||||||
throw new IllegalArgumentException("Position " + position + " past the end of the file");
|
throw new IllegalArgumentException("Position " + position + " past the end of the file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ready it for reading
|
||||||
|
dst.position(0);
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(ByteBuffer src, long position) throws IOException {
|
public void write(ByteBuffer src, long position) throws IOException {
|
||||||
|
|
|
@ -56,4 +56,29 @@ public final class TestNPOIFSFileSystem extends TestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testPropertiesAndFatOnRead() throws Exception {
|
||||||
|
NPOIFSFileSystem fsA, fsB;
|
||||||
|
|
||||||
|
// With a simple 512 block file
|
||||||
|
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 properties
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now with a simple 4096 block file
|
||||||
|
fsA = new NPOIFSFileSystem(_inst.getFile("BlockSize4096.zvi"));
|
||||||
|
fsB = new NPOIFSFileSystem(_inst.openResourceAsStream("BlockSize4096.zvi"));
|
||||||
|
for(NPOIFSFileSystem fs : new NPOIFSFileSystem[] {fsA,fsB}) {
|
||||||
|
// Check the FAT was properly processed
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// Check the properties
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.apache.poi.poifs.nio;
|
package org.apache.poi.poifs.nio;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.apache.poi.POIDataSamples;
|
import org.apache.poi.POIDataSamples;
|
||||||
|
@ -40,20 +41,23 @@ public class TestDataSource extends TestCase
|
||||||
assertEquals(8192, ds.size());
|
assertEquals(8192, ds.size());
|
||||||
|
|
||||||
// Start of file
|
// Start of file
|
||||||
ByteBuffer bs = ByteBuffer.allocate(4);
|
ByteBuffer bs;
|
||||||
ds.read(bs, 0);
|
bs = ds.read(4, 0);
|
||||||
assertEquals(4, bs.capacity());
|
assertEquals(4, bs.capacity());
|
||||||
assertEquals(4, bs.position());
|
assertEquals(0, bs.position());
|
||||||
assertEquals(0xd0-256, bs.get(0));
|
assertEquals(0xd0-256, bs.get(0));
|
||||||
assertEquals(0xcf-256, bs.get(1));
|
assertEquals(0xcf-256, bs.get(1));
|
||||||
assertEquals(0x11-000, bs.get(2));
|
assertEquals(0x11-000, bs.get(2));
|
||||||
assertEquals(0xe0-256, bs.get(3));
|
assertEquals(0xe0-256, bs.get(3));
|
||||||
|
assertEquals(0xd0-256, bs.get());
|
||||||
|
assertEquals(0xcf-256, bs.get());
|
||||||
|
assertEquals(0x11-000, bs.get());
|
||||||
|
assertEquals(0xe0-256, bs.get());
|
||||||
|
|
||||||
// Mid way through
|
// Mid way through
|
||||||
bs = ByteBuffer.allocate(8);
|
bs = ds.read(8, 0x400);
|
||||||
ds.read(bs, 0x400);
|
|
||||||
assertEquals(8, bs.capacity());
|
assertEquals(8, bs.capacity());
|
||||||
assertEquals(8, bs.position());
|
assertEquals(0, bs.position());
|
||||||
assertEquals((byte)'R', bs.get(0));
|
assertEquals((byte)'R', bs.get(0));
|
||||||
assertEquals(0, bs.get(1));
|
assertEquals(0, bs.get(1));
|
||||||
assertEquals((byte)'o', bs.get(2));
|
assertEquals((byte)'o', bs.get(2));
|
||||||
|
@ -64,14 +68,12 @@ public class TestDataSource extends TestCase
|
||||||
assertEquals(0, bs.get(7));
|
assertEquals(0, bs.get(7));
|
||||||
|
|
||||||
// Can go to the end, but not past it
|
// Can go to the end, but not past it
|
||||||
bs.clear();
|
bs = ds.read(8, 8190);
|
||||||
ds.read(bs, 8190);
|
assertEquals(0, bs.position()); // TODO How best to warn of a short read?
|
||||||
assertEquals(2, bs.position());
|
|
||||||
|
|
||||||
// Can't go off the end
|
// Can't go off the end
|
||||||
try {
|
try {
|
||||||
bs.clear();
|
bs = ds.read(4, 8192);
|
||||||
ds.read(bs, 8192);
|
|
||||||
fail("Shouldn't be able to read off the end of the file");
|
fail("Shouldn't be able to read off the end of the file");
|
||||||
} catch(IllegalArgumentException e) {}
|
} catch(IllegalArgumentException e) {}
|
||||||
}
|
}
|
||||||
|
@ -87,70 +89,64 @@ public class TestDataSource extends TestCase
|
||||||
ByteArrayBackedDataSource ds = new ByteArrayBackedDataSource(data);
|
ByteArrayBackedDataSource ds = new ByteArrayBackedDataSource(data);
|
||||||
|
|
||||||
// Start
|
// Start
|
||||||
ByteBuffer bs = ByteBuffer.allocate(4);
|
ByteBuffer bs;
|
||||||
ds.read(bs, 0);
|
bs = ds.read(4, 0);
|
||||||
assertEquals(4, bs.capacity());
|
assertEquals(0, bs.position());
|
||||||
assertEquals(4, bs.position());
|
assertEquals(0x00, bs.get());
|
||||||
assertEquals(0x00, bs.get(0));
|
assertEquals(0x01, bs.get());
|
||||||
assertEquals(0x01, bs.get(1));
|
assertEquals(0x02, bs.get());
|
||||||
assertEquals(0x02, bs.get(2));
|
assertEquals(0x03, bs.get());
|
||||||
assertEquals(0x03, bs.get(3));
|
|
||||||
|
|
||||||
// Middle
|
// Middle
|
||||||
bs.clear();
|
bs = ds.read(4, 100);
|
||||||
ds.read(bs, 100);
|
assertEquals(100, bs.position());
|
||||||
assertEquals(4, bs.capacity());
|
assertEquals(100, bs.get());
|
||||||
assertEquals(4, bs.position());
|
assertEquals(101, bs.get());
|
||||||
assertEquals(100, bs.get(0));
|
assertEquals(102, bs.get());
|
||||||
assertEquals(101, bs.get(1));
|
assertEquals(103, bs.get());
|
||||||
assertEquals(102, bs.get(2));
|
|
||||||
assertEquals(103, bs.get(3));
|
|
||||||
|
|
||||||
// End
|
// End
|
||||||
bs.clear();
|
bs = ds.read(4, 252);
|
||||||
ds.read(bs, 252);
|
assertEquals(-4, bs.get());
|
||||||
assertEquals(4, bs.capacity());
|
assertEquals(-3, bs.get());
|
||||||
assertEquals(4, bs.position());
|
assertEquals(-2, bs.get());
|
||||||
assertEquals(-4, bs.get(0));
|
assertEquals(-1, bs.get());
|
||||||
assertEquals(-3, bs.get(1));
|
|
||||||
assertEquals(-2, bs.get(2));
|
|
||||||
assertEquals(-1, bs.get(3));
|
|
||||||
|
|
||||||
// Off the end
|
// Off the end
|
||||||
bs.clear();
|
bs = ds.read(4, 254);
|
||||||
ds.read(bs, 254);
|
assertEquals(-2, bs.get());
|
||||||
assertEquals(4, bs.capacity());
|
assertEquals(-1, bs.get());
|
||||||
assertEquals(2, bs.position());
|
try {
|
||||||
assertEquals(-2, bs.get(0));
|
bs.get();
|
||||||
assertEquals(-1, bs.get(1));
|
fail("Shouldn't be able to read off the end");
|
||||||
|
} catch(BufferUnderflowException e) {}
|
||||||
|
|
||||||
// Past the end
|
// Past the end
|
||||||
bs.clear();
|
|
||||||
try {
|
try {
|
||||||
ds.read(bs, 256);
|
bs = ds.read(4, 256);
|
||||||
fail("Shouldn't be able to read off the end");
|
fail("Shouldn't be able to read off the end");
|
||||||
} catch(IndexOutOfBoundsException e) {}
|
} catch(IndexOutOfBoundsException e) {}
|
||||||
|
|
||||||
|
|
||||||
// Overwrite
|
// Overwrite
|
||||||
bs.clear();
|
bs = ByteBuffer.allocate(4);
|
||||||
bs.put(0, (byte)-55);
|
bs.put(0, (byte)-55);
|
||||||
bs.put(1, (byte)-54);
|
bs.put(1, (byte)-54);
|
||||||
bs.put(2, (byte)-53);
|
bs.put(2, (byte)-53);
|
||||||
bs.put(3, (byte)-52);
|
bs.put(3, (byte)-52);
|
||||||
|
|
||||||
|
assertEquals(256, ds.size());
|
||||||
ds.write(bs, 40);
|
ds.write(bs, 40);
|
||||||
bs.clear();
|
assertEquals(256, ds.size());
|
||||||
ds.read(bs, 40);
|
bs = ds.read(4, 40);
|
||||||
|
|
||||||
assertEquals(4, bs.position());
|
assertEquals(-55, bs.get());
|
||||||
assertEquals(-55, bs.get(0));
|
assertEquals(-54, bs.get());
|
||||||
assertEquals(-54, bs.get(1));
|
assertEquals(-53, bs.get());
|
||||||
assertEquals(-53, bs.get(2));
|
assertEquals(-52, bs.get());
|
||||||
assertEquals(-52, bs.get(3));
|
|
||||||
|
|
||||||
// Append
|
// Append
|
||||||
bs.clear();
|
bs = ByteBuffer.allocate(4);
|
||||||
bs.put(0, (byte)-55);
|
bs.put(0, (byte)-55);
|
||||||
bs.put(1, (byte)-54);
|
bs.put(1, (byte)-54);
|
||||||
bs.put(2, (byte)-53);
|
bs.put(2, (byte)-53);
|
||||||
|
@ -160,12 +156,11 @@ public class TestDataSource extends TestCase
|
||||||
ds.write(bs, 256);
|
ds.write(bs, 256);
|
||||||
assertEquals(260, ds.size());
|
assertEquals(260, ds.size());
|
||||||
|
|
||||||
bs.clear();
|
bs = ds.read(4, 256);
|
||||||
ds.read(bs, 256);
|
assertEquals(256, bs.position());
|
||||||
assertEquals(4, bs.position());
|
assertEquals(-55, bs.get());
|
||||||
assertEquals(-55, bs.get(0));
|
assertEquals(-54, bs.get());
|
||||||
assertEquals(-54, bs.get(1));
|
assertEquals(-53, bs.get());
|
||||||
assertEquals(-53, bs.get(2));
|
assertEquals(-52, bs.get());
|
||||||
assertEquals(-52, bs.get(3));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue