Make a start on handling different big block sizes in POIFS, but work isn't complete. See bug #35928 for part of what we're after

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@636786 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-03-13 15:38:28 +00:00
parent 709c487a42
commit 86565db81c
9 changed files with 84 additions and 33 deletions

View File

@ -27,7 +27,11 @@ package org.apache.poi.poifs.common;
public interface POIFSConstants public interface POIFSConstants
{ {
/** Most files use 512 bytes as their big block size */
public static final int BIG_BLOCK_SIZE = 0x0200; public static final int BIG_BLOCK_SIZE = 0x0200;
/** Some use 4096 bytes */
public static final int LARGER_BIG_BLOCK_SIZE = 0x1000;
public static final int END_OF_CHAIN = -2; public static final int END_OF_CHAIN = -2;
public static final int PROPERTY_SIZE = 0x0080; public static final int PROPERTY_SIZE = 0x0080;
public static final int UNUSED_BLOCK = -1; public static final int UNUSED_BLOCK = -1;

View File

@ -78,7 +78,7 @@ public class POIFSReader
HeaderBlockReader header_block_reader = new HeaderBlockReader(stream); HeaderBlockReader header_block_reader = new HeaderBlockReader(stream);
// read the rest of the stream into blocks // read the rest of the stream into blocks
RawDataBlockList data_blocks = new RawDataBlockList(stream); RawDataBlockList data_blocks = new RawDataBlockList(stream, header_block_reader.getBigBlockSize());
// set up the block allocation table (necessary for the // set up the block allocation table (necessary for the
// data_blocks to be manageable // data_blocks to be manageable

View File

@ -33,6 +33,7 @@ import java.util.List;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable; import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DirectoryProperty; import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.property.Property; import org.apache.poi.poifs.property.Property;
@ -63,7 +64,6 @@ public class POIFSFileSystem
{ {
private static final Log _logger = LogFactory.getLog(POIFSFileSystem.class); private static final Log _logger = LogFactory.getLog(POIFSFileSystem.class);
private static final class CloseIgnoringInputStream extends InputStream { private static final class CloseIgnoringInputStream extends InputStream {
private final InputStream _is; private final InputStream _is;
@ -92,10 +92,15 @@ public class POIFSFileSystem
private List _documents; private List _documents;
private DirectoryNode _root; private DirectoryNode _root;
/**
* What big block size the file uses. Most files
* use 512 bytes, but a few use 4096
*/
private int bigBlockSize = POIFSConstants.BIG_BLOCK_SIZE;
/** /**
* Constructor, intended for writing * Constructor, intended for writing
*/ */
public POIFSFileSystem() public POIFSFileSystem()
{ {
_property_table = new PropertyTable(); _property_table = new PropertyTable();
@ -138,13 +143,15 @@ public class POIFSFileSystem
this(); this();
boolean success = false; boolean success = false;
// read the header block from the stream
HeaderBlockReader header_block_reader; HeaderBlockReader header_block_reader;
// read the rest of the stream into blocks
RawDataBlockList data_blocks; RawDataBlockList data_blocks;
try { try {
// read the header block from the stream
header_block_reader = new HeaderBlockReader(stream); header_block_reader = new HeaderBlockReader(stream);
data_blocks = new RawDataBlockList(stream); bigBlockSize = header_block_reader.getBigBlockSize();
// read the rest of the stream into blocks
data_blocks = new RawDataBlockList(stream, bigBlockSize);
success = true; success = true;
} finally { } finally {
closeInputStream(stream, success); closeInputStream(stream, success);
@ -602,6 +609,13 @@ public class POIFSFileSystem
return "POIFS FileSystem"; return "POIFS FileSystem";
} }
/**
* @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
*/
public int getBigBlockSize() {
return bigBlockSize;
}
/* ********** END begin implementation of POIFSViewable ********** */ /* ********** END begin implementation of POIFSViewable ********** */
} // end public class POIFSFileSystem } // end public class POIFSFileSystem

View File

@ -21,8 +21,6 @@ package org.apache.poi.poifs.storage;
import java.io.*; import java.io.*;
import java.util.*;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException; import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
@ -30,7 +28,6 @@ import org.apache.poi.util.IntegerField;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LongField; import org.apache.poi.util.LongField;
import org.apache.poi.util.ShortField;
/** /**
* The block containing the archive header * The block containing the archive header
@ -41,6 +38,11 @@ import org.apache.poi.util.ShortField;
public class HeaderBlockReader public class HeaderBlockReader
implements HeaderBlockConstants implements HeaderBlockConstants
{ {
/**
* What big block size the file uses. Most files
* use 512 bytes, but a few use 4096
*/
private int bigBlockSize = POIFSConstants.BIG_BLOCK_SIZE;
// number of big block allocation table blocks (int) // number of big block allocation table blocks (int)
private IntegerField _bat_count; private IntegerField _bat_count;
@ -69,20 +71,27 @@ public class HeaderBlockReader
public HeaderBlockReader(final InputStream stream) public HeaderBlockReader(final InputStream stream)
throws IOException throws IOException
{ {
_data = new byte[ POIFSConstants.BIG_BLOCK_SIZE ]; // At this point, we don't know how big our
int byte_count = IOUtils.readFully(stream, _data); // block sizes are
// So, read the first 32 bytes to check, then
// read the rest of the block
byte[] blockStart = new byte[32];
int bsCount = IOUtils.readFully(stream, blockStart);
if(bsCount != 32) {
alertShortRead(bsCount);
}
if (byte_count != POIFSConstants.BIG_BLOCK_SIZE) // Figure out our block size
{ if(blockStart[30] == 12) {
if (byte_count == -1) bigBlockSize = POIFSConstants.LARGER_BIG_BLOCK_SIZE;
//Cant have -1 bytes read in the error message! }
byte_count = 0; _data = new byte[ bigBlockSize ];
String type = " byte" + ((byte_count == 1) ? ("") System.arraycopy(blockStart, 0, _data, 0, blockStart.length);
: ("s"));
throw new IOException("Unable to read entire header; " // Now we can read the rest of our header
+ byte_count + type + " read; expected " int byte_count = IOUtils.readFully(stream, _data, blockStart.length, _data.length - blockStart.length);
+ POIFSConstants.BIG_BLOCK_SIZE + " bytes"); if (byte_count+bsCount != bigBlockSize) {
alertShortRead(byte_count);
} }
// verify signature // verify signature
@ -111,12 +120,23 @@ public class HeaderBlockReader
_xbat_count = new IntegerField(_xbat_count_offset, _data); _xbat_count = new IntegerField(_xbat_count_offset, _data);
} }
private void alertShortRead(int read) throws IOException {
if (read == -1)
//Cant have -1 bytes read in the error message!
read = 0;
String type = " byte" + ((read == 1) ? ("")
: ("s"));
throw new IOException("Unable to read entire header; "
+ read + type + " read; expected "
+ bigBlockSize + " bytes");
}
/** /**
* get start of Property Table * get start of Property Table
* *
* @return the index of the first block of the Property Table * @return the index of the first block of the Property Table
*/ */
public int getPropertyStart() public int getPropertyStart()
{ {
return _property_start.get(); return _property_start.get();
@ -174,5 +194,12 @@ public class HeaderBlockReader
{ {
return _xbat_start.get(); return _xbat_start.get();
} }
/**
* @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
*/
public int getBigBlockSize() {
return bigBlockSize;
}
} // end public class HeaderBlockReader } // end public class HeaderBlockReader

View File

@ -37,19 +37,20 @@ public class RawDataBlockList
* Constructor RawDataBlockList * Constructor RawDataBlockList
* *
* @param stream the InputStream from which the data will be read * @param stream the InputStream from which the data will be read
* @param bigBlockSize The big block size, either 512 bytes or 4096 bytes
* *
* @exception IOException on I/O errors, and if an incomplete * @exception IOException on I/O errors, and if an incomplete
* block is read * block is read
*/ */
public RawDataBlockList(final InputStream stream) public RawDataBlockList(final InputStream stream, int bigBlockSize)
throws IOException throws IOException
{ {
List blocks = new ArrayList(); List blocks = new ArrayList();
while (true) while (true)
{ {
RawDataBlock block = new RawDataBlock(stream); RawDataBlock block = new RawDataBlock(stream, bigBlockSize);
if (block.eof()) if (block.eof())
{ {

View File

@ -25,6 +25,7 @@ import java.util.*;
import junit.framework.*; import junit.framework.*;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.storage.BlockAllocationTableReader; import org.apache.poi.poifs.storage.BlockAllocationTableReader;
import org.apache.poi.poifs.storage.RawDataBlockList; import org.apache.poi.poifs.storage.RawDataBlockList;
@ -2598,7 +2599,7 @@ public class TestPropertyTable
( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF
}; };
RawDataBlockList data_blocks = RawDataBlockList data_blocks =
new RawDataBlockList(new ByteArrayInputStream(raw_data_array)); new RawDataBlockList(new ByteArrayInputStream(raw_data_array), POIFSConstants.BIG_BLOCK_SIZE);
int[] bat_array = int[] bat_array =
{ {
15 15

View File

@ -19,6 +19,8 @@
package org.apache.poi.poifs.storage; package org.apache.poi.poifs.storage;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
@ -47,7 +49,7 @@ public class LocalRawDataBlockList
public LocalRawDataBlockList() public LocalRawDataBlockList()
throws IOException throws IOException
{ {
super(new ByteArrayInputStream(new byte[ 0 ])); super(new ByteArrayInputStream(new byte[ 0 ]), POIFSConstants.BIG_BLOCK_SIZE);
_list = new ArrayList(); _list = new ArrayList();
_array = null; _array = null;
} }

View File

@ -21,6 +21,7 @@ package org.apache.poi.poifs.storage;
import java.io.*; import java.io.*;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.util.DummyPOILogger; import org.apache.poi.util.DummyPOILogger;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -69,7 +70,7 @@ public class TestRawDataBlockList
{ {
data[ j ] = ( byte ) j; data[ j ] = ( byte ) j;
} }
new RawDataBlockList(new ByteArrayInputStream(data)); new RawDataBlockList(new ByteArrayInputStream(data), POIFSConstants.BIG_BLOCK_SIZE);
} }
/** /**
@ -81,7 +82,7 @@ public class TestRawDataBlockList
public void testEmptyConstructor() public void testEmptyConstructor()
throws IOException throws IOException
{ {
new RawDataBlockList(new ByteArrayInputStream(new byte[ 0 ])); new RawDataBlockList(new ByteArrayInputStream(new byte[ 0 ]), POIFSConstants.BIG_BLOCK_SIZE);
} }
/** /**
@ -108,7 +109,7 @@ public class TestRawDataBlockList
// Check we logged the error // Check we logged the error
logger.reset(); logger.reset();
new RawDataBlockList(new ByteArrayInputStream(data)); new RawDataBlockList(new ByteArrayInputStream(data), POIFSConstants.BIG_BLOCK_SIZE);
assertEquals(1, logger.logged.size()); assertEquals(1, logger.logged.size());
} }
} }

View File

@ -25,6 +25,7 @@ import java.util.*;
import junit.framework.*; import junit.framework.*;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.property.PropertyTable; import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.property.RootProperty; import org.apache.poi.poifs.property.RootProperty;
@ -2112,7 +2113,7 @@ public class TestSmallBlockTableReader
( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF
}; };
RawDataBlockList data_blocks = RawDataBlockList data_blocks =
new RawDataBlockList(new ByteArrayInputStream(raw_data_array)); new RawDataBlockList(new ByteArrayInputStream(raw_data_array), POIFSConstants.BIG_BLOCK_SIZE);
int[] bat_array = int[] bat_array =
{ {
15 15