From 2362cacb3e2e2f55e35fd53f9dfd54613da073f1 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Sun, 28 Jun 2015 17:53:24 +0000 Subject: [PATCH] Refactor the small block reader creation, so that POIFSHeaderDumper can dump the sbat structure too git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1688030 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/poifs/dev/POIFSHeaderDumper.java | 40 ++++++++-- .../poifs/storage/SmallBlockTableReader.java | 74 ++++++++++++++---- test-data/openxml4j/sample.xlsx | Bin 12050 -> 10059 bytes 3 files changed, 93 insertions(+), 21 deletions(-) diff --git a/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java b/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java index 78ed986a40..7856015e7f 100644 --- a/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java +++ b/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java @@ -24,9 +24,10 @@ import java.lang.reflect.Method; import org.apache.poi.poifs.common.POIFSBigBlockSize; import org.apache.poi.poifs.common.POIFSConstants; +import org.apache.poi.poifs.property.DirectoryProperty; +import org.apache.poi.poifs.property.Property; import org.apache.poi.poifs.property.PropertyTable; import org.apache.poi.poifs.storage.BlockAllocationTableReader; -import org.apache.poi.poifs.storage.BlockList; import org.apache.poi.poifs.storage.HeaderBlock; import org.apache.poi.poifs.storage.ListManagedBlock; import org.apache.poi.poifs.storage.RawDataBlockList; @@ -59,6 +60,7 @@ public class POIFSHeaderDumper { } public static void viewFile(final String filename) throws Exception { + System.out.println("Dumping headers from: " + filename); InputStream inp = new FileInputStream(filename); // Header @@ -79,18 +81,22 @@ public class POIFSHeaderDumper { header_block.getXBATCount(), header_block.getXBATIndex(), data_blocks); - displayBATReader(batReader); + displayBATReader("Big Blocks", batReader); // Properties Table PropertyTable properties = new PropertyTable(header_block, data_blocks); // Mini Fat - BlockList sbat = - SmallBlockTableReader.getSmallDocumentBlocks( + BlockAllocationTableReader sbatReader = + SmallBlockTableReader._getSmallDocumentBlockReader( bigBlockSize, data_blocks, properties.getRoot(), header_block.getSBATStart() ); + displayBATReader("Small Blocks", sbatReader); + + // Summary of the properties + displayPropertiesSummary(properties); } public static void displayHeader(HeaderBlock header_block) throws Exception { @@ -98,6 +104,8 @@ public class POIFSHeaderDumper { System.out.println(" Block size: " + header_block.getBigBlockSize().getBigBlockSize()); System.out.println(" BAT (FAT) header blocks: " + header_block.getBATArray().length); System.out.println(" BAT (FAT) block count: " + header_block.getBATCount()); + if (header_block.getBATCount() > 0) + System.out.println(" BAT (FAT) block 1 at: " + header_block.getBATArray()[0]); System.out.println(" XBAT (FAT) block count: " + header_block.getXBATCount()); System.out.println(" XBAT (FAT) block 1 at: " + header_block.getXBATIndex()); System.out.println(" SBAT (MiniFAT) block count: " + header_block.getSBATCount()); @@ -125,8 +133,8 @@ public class POIFSHeaderDumper { System.out.println(""); } - public static void displayBATReader(BlockAllocationTableReader batReader) throws Exception { - System.out.println("Sectors, as referenced from the FAT:"); + public static void displayBATReader(String type, BlockAllocationTableReader batReader) throws Exception { + System.out.println("Sectors, as referenced from the "+type+" FAT:"); Field entriesF = batReader.getClass().getDeclaredField("_entries"); entriesF.setAccessible(true); IntList entries = (IntList)entriesF.get(batReader); @@ -149,4 +157,24 @@ public class POIFSHeaderDumper { System.out.println(""); } + + public static void displayPropertiesSummary(PropertyTable properties) { + System.out.println("Properties and their block start:"); + displayProperties(properties.getRoot(), ""); + System.out.println(""); + } + public static void displayProperties(DirectoryProperty prop, String indent) { + indent = indent + " "; + System.out.println(prop.getName()); + for (Property cp : prop) { + if (cp instanceof DirectoryProperty) { + displayProperties((DirectoryProperty)cp, indent); + } else { + // TODO + if (cp.shouldUseSmallBlocks()) { + + } + } + } + } } diff --git a/src/java/org/apache/poi/poifs/storage/SmallBlockTableReader.java b/src/java/org/apache/poi/poifs/storage/SmallBlockTableReader.java index 8b6efd36e8..2f9528318d 100644 --- a/src/java/org/apache/poi/poifs/storage/SmallBlockTableReader.java +++ b/src/java/org/apache/poi/poifs/storage/SmallBlockTableReader.java @@ -25,13 +25,66 @@ import org.apache.poi.poifs.property.RootProperty; /** * This class implements reading the small document block list from an * existing file - * - * @author Marc Johnson (mjohnson at apache dot org) */ public final class SmallBlockTableReader { + private static BlockList prepareSmallDocumentBlocks( + final POIFSBigBlockSize bigBlockSize, + final RawDataBlockList blockList, final RootProperty root, + final int sbatStart) + throws IOException + { + // Fetch the blocks which hold the Small Blocks stream + ListManagedBlock [] smallBlockBlocks = + blockList.fetchBlocks(root.getStartBlock(), -1); + + // Turn that into a list + BlockList list =new SmallDocumentBlockList( + SmallDocumentBlock.extract(bigBlockSize, smallBlockBlocks)); + + return list; + } + private static BlockAllocationTableReader prepareReader( + final POIFSBigBlockSize bigBlockSize, + final RawDataBlockList blockList, final BlockList list, + final RootProperty root, final int sbatStart) + throws IOException + { + // Process the SBAT and blocks + return new BlockAllocationTableReader(bigBlockSize, + blockList.fetchBlocks(sbatStart, -1), + list); + } + + /** + * Fetch the small document block reader from an existing file, normally + * needed for debugging and low level dumping. You should typically call + * {@link #getSmallDocumentBlocks(POIFSBigBlockSize, RawDataBlockList, RootProperty, int)} + * instead. + * + * @param blockList the raw data from which the small block table + * will be extracted + * @param root the root property (which contains the start block + * and small block table size) + * @param sbatStart the start block of the SBAT + * + * @return the small document block reader + * + * @exception IOException + */ + public static BlockAllocationTableReader _getSmallDocumentBlockReader( + final POIFSBigBlockSize bigBlockSize, + final RawDataBlockList blockList, final RootProperty root, + final int sbatStart) + throws IOException + { + BlockList list = prepareSmallDocumentBlocks( + bigBlockSize, blockList, root, sbatStart); + return prepareReader( + bigBlockSize, blockList, list, root, sbatStart); + } /** - * fetch the small document block list from an existing file + * Fetch the small document block list from an existing file * * @param blockList the raw data from which the small block table * will be extracted @@ -49,18 +102,9 @@ public final class SmallBlockTableReader { final int sbatStart) throws IOException { - // Fetch the blocks which hold the Small Blocks stream - ListManagedBlock [] smallBlockBlocks = - blockList.fetchBlocks(root.getStartBlock(), -1); - - // Turn that into a list - BlockList list =new SmallDocumentBlockList( - SmallDocumentBlock.extract(bigBlockSize, smallBlockBlocks)); - - // Process - new BlockAllocationTableReader(bigBlockSize, - blockList.fetchBlocks(sbatStart, -1), - list); + BlockList list = prepareSmallDocumentBlocks( + bigBlockSize, blockList, root, sbatStart); + prepareReader(bigBlockSize, blockList, list, root, sbatStart); return list; } } diff --git a/test-data/openxml4j/sample.xlsx b/test-data/openxml4j/sample.xlsx index a275cf417e01a78f9562b1b13725a404f234d5d1..328a9e39230a26623197aaf37b96a4f435933a07 100644 GIT binary patch literal 10059 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 literal 12050 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 I{_*Mm0DX*4GXMYp -- 2.39.5