aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2010-04-13 15:04:45 +0000
committerNick Burch <nick@apache.org>2010-04-13 15:04:45 +0000
commit350df806005ce582d50594364bb32e02a19c9b15 (patch)
tree44f37422d67dcda282a8580264849ca165633349 /src
parente53e3a376e2ef40140ff80ba00c1af14f2acc84d (diff)
downloadpoi-350df806005ce582d50594364bb32e02a19c9b15.tar.gz
poi-350df806005ce582d50594364bb32e02a19c9b15.zip
Lots more documentation on how we read in POIFS files and process the sectors/blocks and FATs. Also add a test that shows that bug #46391 is invalid
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@933663 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/java/org/apache/poi/poifs/common/POIFSConstants.java13
-rw-r--r--src/java/org/apache/poi/poifs/storage/BlockAllocationTableReader.java33
-rw-r--r--src/java/org/apache/poi/poifs/storage/BlockList.java2
-rw-r--r--src/java/org/apache/poi/poifs/storage/BlockListImpl.java17
-rw-r--r--src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java5
-rw-r--r--src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java42
-rw-r--r--src/java/org/apache/poi/poifs/storage/RawDataBlock.java4
-rw-r--r--src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java20
-rw-r--r--src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java4
9 files changed, 124 insertions, 16 deletions
diff --git a/src/java/org/apache/poi/poifs/common/POIFSConstants.java b/src/java/org/apache/poi/poifs/common/POIFSConstants.java
index ff2050274d..6630c25314 100644
--- a/src/java/org/apache/poi/poifs/common/POIFSConstants.java
+++ b/src/java/org/apache/poi/poifs/common/POIFSConstants.java
@@ -32,10 +32,21 @@ public interface POIFSConstants
/** 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;
+
+ /** The highest sector number you're allowed, 0xFFFFFFFA */
+ public static final int LARGEST_REGULAR_SECTOR_NUMBER = -5;
+
+ /** Indicates the sector holds a DIFAT block (0xFFFFFFFC) */
+ public static final int DIFAT_SECTOR_BLOCK = -4;
+ /** Indicates the sector holds a FAT block (0xFFFFFFFD) */
+ public static final int FAT_SECTOR_BLOCK = -3;
+ /** Indicates the sector is the end of a chain (0xFFFFFFFE) */
+ public static final int END_OF_CHAIN = -2;
+ /** Indicates the sector is not used (0xFFFFFFFF) */
public static final int UNUSED_BLOCK = -1;
+ /** The first 4 bytes of an OOXML file, used in detection */
public static final byte[] OOXML_FILE_HEADER =
new byte[] { 0x50, 0x4b, 0x03, 0x04 };
} // end public interface POIFSConstants;
diff --git a/src/java/org/apache/poi/poifs/storage/BlockAllocationTableReader.java b/src/java/org/apache/poi/poifs/storage/BlockAllocationTableReader.java
index 31a2609394..ae5efe3122 100644
--- a/src/java/org/apache/poi/poifs/storage/BlockAllocationTableReader.java
+++ b/src/java/org/apache/poi/poifs/storage/BlockAllocationTableReader.java
@@ -89,17 +89,35 @@ public final class BlockAllocationTableReader {
+ " is too high. POI maximum is " + MAX_BLOCK_COUNT + ".");
}
- // acquire raw data blocks containing the BAT block data
- RawDataBlock blocks[] = new RawDataBlock[ block_count ];
+ // We want to get the whole of the FAT table
+ // To do this:
+ // * Work through raw_block_list, which points to the
+ // first (up to) 109 BAT blocks
+ // * Jump to the XBAT offset, and read in XBATs which
+ // point to more BAT blocks
int limit = Math.min(block_count, block_array.length);
int block_index;
+
+ // This will hold all of the BAT blocks in order
+ RawDataBlock blocks[] = new RawDataBlock[ block_count ];
+ // Process the first (up to) 109 BAT blocks
for (block_index = 0; block_index < limit; block_index++)
{
+ // Check that the sector number of the BAT block is a valid one
+ int nextOffset = block_array[ block_index ];
+ if(nextOffset > raw_block_list.blockCount()) {
+ throw new IOException("Your file contains " + raw_block_list.blockCount() +
+ " sectors, but the initial DIFAT array at index " + block_index +
+ " referenced block # " + nextOffset + ". This isn't allowed and " +
+ " your file is corrupt");
+ }
+ // Record the sector number of this BAT block
blocks[ block_index ] =
- ( RawDataBlock ) raw_block_list
- .remove(block_array[ block_index ]);
+ ( RawDataBlock ) raw_block_list.remove(nextOffset);
}
+
+ // Process additional BAT blocks via the XBATs
if (block_index < block_count)
{
@@ -113,6 +131,9 @@ public final class BlockAllocationTableReader {
int max_entries_per_block = BATBlock.entriesPerXBATBlock();
int chain_index_offset = BATBlock.getXBATChainOffset();
+ // Each XBAT block contains either:
+ // (maximum number of sector indexes) + index of next XBAT
+ // some sector indexes + FREE sectors to max # + EndOfChain
for (int j = 0; j < xbat_count; j++)
{
limit = Math.min(block_count - block_index,
@@ -139,8 +160,8 @@ public final class BlockAllocationTableReader {
throw new IOException("Could not find all blocks");
}
- // now that we have all of the raw data blocks, go through and
- // create the indices
+ // Now that we have all of the raw data blocks which make
+ // up the FAT, go through and create the indices
setEntries(blocks, raw_block_list);
}
diff --git a/src/java/org/apache/poi/poifs/storage/BlockList.java b/src/java/org/apache/poi/poifs/storage/BlockList.java
index a5eb7df217..d7e23cfb9c 100644
--- a/src/java/org/apache/poi/poifs/storage/BlockList.java
+++ b/src/java/org/apache/poi/poifs/storage/BlockList.java
@@ -79,5 +79,7 @@ public interface BlockList
public void setBAT(final BlockAllocationTableReader bat)
throws IOException;
+
+ public int blockCount();
} // end public interface BlockList
diff --git a/src/java/org/apache/poi/poifs/storage/BlockListImpl.java b/src/java/org/apache/poi/poifs/storage/BlockListImpl.java
index df7de493a5..b7c6a0ccff 100644
--- a/src/java/org/apache/poi/poifs/storage/BlockListImpl.java
+++ b/src/java/org/apache/poi/poifs/storage/BlockListImpl.java
@@ -138,4 +138,21 @@ abstract class BlockListImpl implements BlockList {
}
_bat = bat;
}
+
+ /**
+ * Returns the count of the number of blocks
+ */
+ public int blockCount() {
+ return _blocks.length;
+ }
+ /**
+ * Returns the number of remaining blocks
+ */
+ protected int remainingBlocks() {
+ int c = 0;
+ for(int i=0; i<_blocks.length; i++) {
+ if(_blocks[i] != null) c++;
+ }
+ return c;
+ }
}
diff --git a/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java b/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java
index eebb504b45..d5f327a529 100644
--- a/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java
+++ b/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java
@@ -33,6 +33,11 @@ public interface HeaderBlockConstants
(POIFSConstants.BIG_BLOCK_SIZE - _bat_array_offset)
/ LittleEndianConsts.INT_SIZE;
+ // Note - in Microsoft terms:
+ // BAT ~= FAT
+ // SBAT ~= MiniFAT
+ // XBAT ~= DIFat
+
// useful offsets
public static final int _signature_offset = 0;
public static final int _bat_count_offset = 0x2C;
diff --git a/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java b/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
index 1cd5dd690e..a6961a27dd 100644
--- a/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
+++ b/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
@@ -22,6 +22,7 @@ import static org.apache.poi.poifs.storage.HeaderBlockConstants._bat_count_offse
import static org.apache.poi.poifs.storage.HeaderBlockConstants._max_bats_in_header;
import static org.apache.poi.poifs.storage.HeaderBlockConstants._property_start_offset;
import static org.apache.poi.poifs.storage.HeaderBlockConstants._sbat_start_offset;
+import static org.apache.poi.poifs.storage.HeaderBlockConstants._sbat_block_count_offset;
import static org.apache.poi.poifs.storage.HeaderBlockConstants._signature;
import static org.apache.poi.poifs.storage.HeaderBlockConstants._signature_offset;
import static org.apache.poi.poifs.storage.HeaderBlockConstants._xbat_count_offset;
@@ -49,21 +50,37 @@ public final class HeaderBlockReader {
*/
private final int bigBlockSize;
- /** number of big block allocation table blocks (int) */
+ /**
+ * number of big block allocation table blocks (int).
+ * (Number of FAT Sectors in Microsoft parlance)
+ */
private final int _bat_count;
- /** start of the property set block (int index of the property set
- * chain's first big block)
+ /**
+ * Start of the property set block (int index of the property set
+ * chain's first big block).
*/
private final int _property_start;
- /** start of the small block allocation table (int index of small
+ /**
+ * start of the small block allocation table (int index of small
* block allocation table's first big block)
*/
private final int _sbat_start;
+ /**
+ * Number of small block allocation table blocks (int)
+ * (Number of MiniFAT Sectors in Microsoft parlance)
+ */
+ private final int _sbat_count;
- /** big block index for extension to the big block allocation table */
+ /**
+ * Big block index for extension to the big block allocation table
+ */
private final int _xbat_start;
+ /**
+ * Number of big block allocation table blocks (int)
+ * (Number of DIFAT Sectors in Microsoft parlance)
+ */
private final int _xbat_count;
private final byte[] _data;
@@ -132,6 +149,7 @@ public final class HeaderBlockReader {
_bat_count = getInt(_bat_count_offset, _data);
_property_start = getInt(_property_start_offset, _data);
_sbat_start = getInt(_sbat_start_offset, _data);
+ _sbat_count = getInt(_sbat_block_count_offset, _data);
_xbat_start = getInt(_xbat_start_offset, _data);
_xbat_count = getInt(_xbat_count_offset, _data);
}
@@ -169,11 +187,14 @@ public final class HeaderBlockReader {
}
/**
- * @return start of small block allocation table
+ * @return start of small block (MiniFAT) allocation table
*/
public int getSBATStart() {
return _sbat_start;
}
+ public int getSBATCount() {
+ return _sbat_count;
+ }
/**
* @return number of BAT blocks
@@ -183,7 +204,10 @@ public final class HeaderBlockReader {
}
/**
- * @return BAT array
+ * Returns the offsets to the first (up to) 109
+ * BAT sectors.
+ * Any additional BAT sectors
+ * @return BAT offset array
*/
public int[] getBATArray() {
int[] result = new int[ _max_bats_in_header ];
@@ -197,14 +221,14 @@ public final class HeaderBlockReader {
}
/**
- * @return XBAT count
+ * @return XBAT (DIFAT) count
*/
public int getXBATCount() {
return _xbat_count;
}
/**
- * @return XBAT index
+ * @return XBAT (DIFAT) index
*/
public int getXBATIndex() {
return _xbat_start;
diff --git a/src/java/org/apache/poi/poifs/storage/RawDataBlock.java b/src/java/org/apache/poi/poifs/storage/RawDataBlock.java
index 5ca1781d07..a375885f92 100644
--- a/src/java/org/apache/poi/poifs/storage/RawDataBlock.java
+++ b/src/java/org/apache/poi/poifs/storage/RawDataBlock.java
@@ -111,6 +111,10 @@ public class RawDataBlock
public boolean hasData() {
return _hasData;
}
+
+ public String toString() {
+ return "RawDataBlock of size " + _data.length;
+ }
/* ********** START implementation of ListManagedBlock ********** */
diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java b/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java
index 3fd4f461de..033ef7a029 100644
--- a/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java
+++ b/src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java
@@ -148,6 +148,26 @@ public final class TestPOIFSFileSystem extends TestCase {
// Check sizes
}
}
+
+ /**
+ * Check that we do the right thing when the list of which
+ * sectors are BAT blocks points off the list of
+ * sectors that exist in the file.
+ */
+ public void testFATandDIFATsectors() throws Exception {
+ POIDataSamples _samples = POIDataSamples.getPOIFSInstance();
+
+ // Open the file up
+ try {
+ POIFSFileSystem fs = new POIFSFileSystem(
+ _samples.openResourceAsStream("ReferencesInvalidSectors.mpp")
+ );
+ fail("File is corrupt and shouldn't have been opened");
+ } catch(IOException e) {
+ String msg = e.getMessage();
+ assertTrue(msg.startsWith("Your file contains 695 sectors"));
+ }
+ }
private static InputStream openSampleStream(String sampleFileName) {
return HSSFTestDataSamples.openSampleFileStream(sampleFileName);
diff --git a/src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java b/src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java
index 61bc943f58..a0f1ec3475 100644
--- a/src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java
+++ b/src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java
@@ -181,4 +181,8 @@ public final class LocalRawDataBlockList extends RawDataBlockList {
_array = _list.toArray(new RawDataBlock[ 0 ]);
}
}
+
+ public int blockCount() {
+ return _list.size();
+ }
}