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
{
/** Most files use 512 bytes as their big block size */
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 PROPERTY_SIZE = 0x0080;
public static final int UNUSED_BLOCK = -1;

View File

@ -78,7 +78,7 @@ public class POIFSReader
HeaderBlockReader header_block_reader = new HeaderBlockReader(stream);
// 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
// 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.LogFactory;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DirectoryProperty;
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 class CloseIgnoringInputStream extends InputStream {
private final InputStream _is;
@ -91,11 +91,16 @@ public class POIFSFileSystem
private PropertyTable _property_table;
private List _documents;
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
*/
public POIFSFileSystem()
{
_property_table = new PropertyTable();
@ -138,13 +143,15 @@ public class POIFSFileSystem
this();
boolean success = false;
// read the header block from the stream
HeaderBlockReader header_block_reader;
// read the rest of the stream into blocks
RawDataBlockList data_blocks;
try {
// read the header block from the 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;
} finally {
closeInputStream(stream, success);
@ -307,7 +314,7 @@ public class POIFSFileSystem
// create a list of BATManaged objects: the documents plus the
// property table and the small block table
List bm_objects = new ArrayList();
List bm_objects = new ArrayList();
bm_objects.addAll(_documents);
bm_objects.add(_property_table);
@ -602,6 +609,13 @@ public class POIFSFileSystem
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 public class POIFSFileSystem

View File

@ -21,8 +21,6 @@ package org.apache.poi.poifs.storage;
import java.io.*;
import java.util.*;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
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.LittleEndianConsts;
import org.apache.poi.util.LongField;
import org.apache.poi.util.ShortField;
/**
* The block containing the archive header
@ -41,6 +38,11 @@ import org.apache.poi.util.ShortField;
public class HeaderBlockReader
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)
private IntegerField _bat_count;
@ -69,20 +71,27 @@ public class HeaderBlockReader
public HeaderBlockReader(final InputStream stream)
throws IOException
{
_data = new byte[ POIFSConstants.BIG_BLOCK_SIZE ];
int byte_count = IOUtils.readFully(stream, _data);
if (byte_count != POIFSConstants.BIG_BLOCK_SIZE)
{
if (byte_count == -1)
//Cant have -1 bytes read in the error message!
byte_count = 0;
String type = " byte" + ((byte_count == 1) ? ("")
: ("s"));
throw new IOException("Unable to read entire header; "
+ byte_count + type + " read; expected "
+ POIFSConstants.BIG_BLOCK_SIZE + " bytes");
// At this point, we don't know how big our
// 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);
}
// Figure out our block size
if(blockStart[30] == 12) {
bigBlockSize = POIFSConstants.LARGER_BIG_BLOCK_SIZE;
}
_data = new byte[ bigBlockSize ];
System.arraycopy(blockStart, 0, _data, 0, blockStart.length);
// Now we can read the rest of our header
int byte_count = IOUtils.readFully(stream, _data, blockStart.length, _data.length - blockStart.length);
if (byte_count+bsCount != bigBlockSize) {
alertShortRead(byte_count);
}
// verify signature
@ -110,13 +119,24 @@ public class HeaderBlockReader
_xbat_start = new IntegerField(_xbat_start_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
*
* @return the index of the first block of the Property Table
*/
public int getPropertyStart()
{
return _property_start.get();
@ -174,5 +194,12 @@ public class HeaderBlockReader
{
return _xbat_start.get();
}
/**
* @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
*/
public int getBigBlockSize() {
return bigBlockSize;
}
} // end public class HeaderBlockReader

View File

@ -37,19 +37,20 @@ public class RawDataBlockList
* Constructor RawDataBlockList
*
* @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
* block is read
*/
public RawDataBlockList(final InputStream stream)
public RawDataBlockList(final InputStream stream, int bigBlockSize)
throws IOException
{
List blocks = new ArrayList();
while (true)
{
RawDataBlock block = new RawDataBlock(stream);
RawDataBlock block = new RawDataBlock(stream, bigBlockSize);
if (block.eof())
{

View File

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

View File

@ -19,6 +19,8 @@
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.LittleEndianConsts;
@ -47,7 +49,7 @@ public class LocalRawDataBlockList
public LocalRawDataBlockList()
throws IOException
{
super(new ByteArrayInputStream(new byte[ 0 ]));
super(new ByteArrayInputStream(new byte[ 0 ]), POIFSConstants.BIG_BLOCK_SIZE);
_list = new ArrayList();
_array = null;
}

View File

@ -21,6 +21,7 @@ package org.apache.poi.poifs.storage;
import java.io.*;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.util.DummyPOILogger;
import org.apache.poi.util.POILogFactory;
@ -69,7 +70,7 @@ public class TestRawDataBlockList
{
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()
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
logger.reset();
new RawDataBlockList(new ByteArrayInputStream(data));
new RawDataBlockList(new ByteArrayInputStream(data), POIFSConstants.BIG_BLOCK_SIZE);
assertEquals(1, logger.logged.size());
}
}

View File

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