Browse Source

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
tags/REL_3_7_BETA1
Nick Burch 14 years ago
parent
commit
350df80600

+ 12
- 1
src/java/org/apache/poi/poifs/common/POIFSConstants.java View File

/** Some use 4096 bytes */ /** Some use 4096 bytes */
public static final int LARGER_BIG_BLOCK_SIZE = 0x1000; 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 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; 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 = public static final byte[] OOXML_FILE_HEADER =
new byte[] { 0x50, 0x4b, 0x03, 0x04 }; new byte[] { 0x50, 0x4b, 0x03, 0x04 };
} // end public interface POIFSConstants; } // end public interface POIFSConstants;

+ 27
- 6
src/java/org/apache/poi/poifs/storage/BlockAllocationTableReader.java View File

+ " is too high. POI maximum is " + MAX_BLOCK_COUNT + "."); + " 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 limit = Math.min(block_count, block_array.length);
int block_index; 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++) 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 ] = 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) if (block_index < block_count)
{ {


int max_entries_per_block = BATBlock.entriesPerXBATBlock(); int max_entries_per_block = BATBlock.entriesPerXBATBlock();
int chain_index_offset = BATBlock.getXBATChainOffset(); 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++) for (int j = 0; j < xbat_count; j++)
{ {
limit = Math.min(block_count - block_index, limit = Math.min(block_count - block_index,
throw new IOException("Could not find all blocks"); 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); setEntries(blocks, raw_block_list);
} }



+ 2
- 0
src/java/org/apache/poi/poifs/storage/BlockList.java View File



public void setBAT(final BlockAllocationTableReader bat) public void setBAT(final BlockAllocationTableReader bat)
throws IOException; throws IOException;
public int blockCount();
} // end public interface BlockList } // end public interface BlockList



+ 17
- 0
src/java/org/apache/poi/poifs/storage/BlockListImpl.java View File

} }
_bat = bat; _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;
}
} }

+ 5
- 0
src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java View File

(POIFSConstants.BIG_BLOCK_SIZE - _bat_array_offset) (POIFSConstants.BIG_BLOCK_SIZE - _bat_array_offset)
/ LittleEndianConsts.INT_SIZE; / LittleEndianConsts.INT_SIZE;


// Note - in Microsoft terms:
// BAT ~= FAT
// SBAT ~= MiniFAT
// XBAT ~= DIFat
// useful offsets // useful offsets
public static final int _signature_offset = 0; public static final int _signature_offset = 0;
public static final int _bat_count_offset = 0x2C; public static final int _bat_count_offset = 0x2C;

+ 33
- 9
src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java View File

import static org.apache.poi.poifs.storage.HeaderBlockConstants._max_bats_in_header; 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._property_start_offset;
import static org.apache.poi.poifs.storage.HeaderBlockConstants._sbat_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;
import static org.apache.poi.poifs.storage.HeaderBlockConstants._signature_offset; import static org.apache.poi.poifs.storage.HeaderBlockConstants._signature_offset;
import static org.apache.poi.poifs.storage.HeaderBlockConstants._xbat_count_offset; import static org.apache.poi.poifs.storage.HeaderBlockConstants._xbat_count_offset;
*/ */
private final int bigBlockSize; 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; 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; 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) * block allocation table's first big block)
*/ */
private final int _sbat_start; 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; 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 int _xbat_count;
private final byte[] _data; private final byte[] _data;


_bat_count = getInt(_bat_count_offset, _data); _bat_count = getInt(_bat_count_offset, _data);
_property_start = getInt(_property_start_offset, _data); _property_start = getInt(_property_start_offset, _data);
_sbat_start = getInt(_sbat_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_start = getInt(_xbat_start_offset, _data);
_xbat_count = getInt(_xbat_count_offset, _data); _xbat_count = getInt(_xbat_count_offset, _data);
} }
} }


/** /**
* @return start of small block allocation table
* @return start of small block (MiniFAT) allocation table
*/ */
public int getSBATStart() { public int getSBATStart() {
return _sbat_start; return _sbat_start;
} }
public int getSBATCount() {
return _sbat_count;
}


/** /**
* @return number of BAT blocks * @return number of BAT blocks
} }


/** /**
* @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() { public int[] getBATArray() {
int[] result = new int[ _max_bats_in_header ]; int[] result = new int[ _max_bats_in_header ];
} }


/** /**
* @return XBAT count
* @return XBAT (DIFAT) count
*/ */
public int getXBATCount() { public int getXBATCount() {
return _xbat_count; return _xbat_count;
} }


/** /**
* @return XBAT index
* @return XBAT (DIFAT) index
*/ */
public int getXBATIndex() { public int getXBATIndex() {
return _xbat_start; return _xbat_start;

+ 4
- 0
src/java/org/apache/poi/poifs/storage/RawDataBlock.java View File

public boolean hasData() { public boolean hasData() {
return _hasData; return _hasData;
} }
public String toString() {
return "RawDataBlock of size " + _data.length;
}


/* ********** START implementation of ListManagedBlock ********** */ /* ********** START implementation of ListManagedBlock ********** */



+ 20
- 0
src/testcases/org/apache/poi/poifs/filesystem/TestPOIFSFileSystem.java View File

// Check sizes // 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) { private static InputStream openSampleStream(String sampleFileName) {
return HSSFTestDataSamples.openSampleFileStream(sampleFileName); return HSSFTestDataSamples.openSampleFileStream(sampleFileName);

+ 4
- 0
src/testcases/org/apache/poi/poifs/storage/LocalRawDataBlockList.java View File

_array = _list.toArray(new RawDataBlock[ 0 ]); _array = _list.toArray(new RawDataBlock[ 0 ]);
} }
} }
public int blockCount() {
return _list.size();
}
} }

BIN
test-data/poifs/ReferencesInvalidSectors.mpp View File


Loading…
Cancel
Save