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;
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
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;
{
private static final Log _logger = LogFactory.getLog(POIFSFileSystem.class);
-
private static final class CloseIgnoringInputStream extends InputStream {
private final InputStream _is;
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();
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);
// 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);
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
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;
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
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;
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
_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();
{
return _xbat_start.get();
}
+
+ /**
+ * @return The Big Block size, normally 512 bytes, sometimes 4096 bytes
+ */
+ public int getBigBlockSize() {
+ return bigBlockSize;
+ }
} // end public class HeaderBlockReader
* 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())
{
import junit.framework.*;
+import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.storage.BlockAllocationTableReader;
import org.apache.poi.poifs.storage.RawDataBlockList;
( 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
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;
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;
}
import java.io.*;
+import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.util.DummyPOILogger;
import org.apache.poi.util.POILogFactory;
{
data[ j ] = ( byte ) j;
}
- new RawDataBlockList(new ByteArrayInputStream(data));
+ new RawDataBlockList(new ByteArrayInputStream(data), POIFSConstants.BIG_BLOCK_SIZE);
}
/**
public void testEmptyConstructor()
throws IOException
{
- new RawDataBlockList(new ByteArrayInputStream(new byte[ 0 ]));
+ new RawDataBlockList(new ByteArrayInputStream(new byte[ 0 ]), POIFSConstants.BIG_BLOCK_SIZE);
}
/**
// 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());
}
}
import junit.framework.*;
+import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.property.PropertyTable;
import org.apache.poi.poifs.property.RootProperty;
( 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