From: Nick Burch Date: Sun, 19 Dec 2010 05:54:11 +0000 (+0000) Subject: Start to merge the POIFS classes HeaderBlockReader and HeaderBlockWriter into a commo... X-Git-Tag: REL_3_8_BETA1~92 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=6703ad1c9367738d08e53a974a849c0a0a7479c6;p=poi.git Start to merge the POIFS classes HeaderBlockReader and HeaderBlockWriter into a common HeaderBlock class git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1050764 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java b/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java index 7a6b187fe0..cd183b3ba4 100644 --- a/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java +++ b/src/java/org/apache/poi/poifs/dev/POIFSHeaderDumper.java @@ -18,21 +18,16 @@ package org.apache.poi.poifs.dev; import java.io.FileInputStream; -import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.Iterator; import org.apache.poi.poifs.common.POIFSBigBlockSize; import org.apache.poi.poifs.common.POIFSConstants; -import org.apache.poi.poifs.filesystem.DirectoryNode; -import org.apache.poi.poifs.filesystem.DocumentNode; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; 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.HeaderBlockReader; +import org.apache.poi.poifs.storage.HeaderBlock; import org.apache.poi.poifs.storage.ListManagedBlock; import org.apache.poi.poifs.storage.RawDataBlockList; import org.apache.poi.poifs.storage.SmallBlockTableReader; @@ -67,51 +62,50 @@ public class POIFSHeaderDumper { InputStream inp = new FileInputStream(filename); // Header - HeaderBlockReader header_block_reader = - new HeaderBlockReader(inp); - displayHeader(header_block_reader); + HeaderBlock header_block = new HeaderBlock(inp); + displayHeader(header_block); // Raw blocks - POIFSBigBlockSize bigBlockSize = header_block_reader.getBigBlockSize(); + POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize(); RawDataBlockList data_blocks = new RawDataBlockList(inp, bigBlockSize); displayRawBlocksSummary(data_blocks); // Main FAT Table BlockAllocationTableReader batReader = new BlockAllocationTableReader( - header_block_reader.getBigBlockSize(), - header_block_reader.getBATCount(), - header_block_reader.getBATArray(), - header_block_reader.getXBATCount(), - header_block_reader.getXBATIndex(), + header_block.getBigBlockSize(), + header_block.getBATCount(), + header_block.getBATArray(), + header_block.getXBATCount(), + header_block.getXBATIndex(), data_blocks); displayBATReader(batReader); // Properties Table PropertyTable properties = new PropertyTable( - header_block_reader.getBigBlockSize(), - header_block_reader.getPropertyStart(), + header_block.getBigBlockSize(), + header_block.getPropertyStart(), data_blocks); // Mini Fat BlockList sbat = SmallBlockTableReader.getSmallDocumentBlocks( bigBlockSize, data_blocks, properties.getRoot(), - header_block_reader.getSBATStart() + header_block.getSBATStart() ); } - public static void displayHeader(HeaderBlockReader header_block_reader) throws Exception { + public static void displayHeader(HeaderBlock header_block) throws Exception { System.out.println("Header Details:"); - System.out.println(" Block size: " + header_block_reader.getBigBlockSize()); - System.out.println(" BAT (FAT) header blocks: " + header_block_reader.getBATArray().length); - System.out.println(" BAT (FAT) block count: " + header_block_reader.getBATCount()); - System.out.println(" XBAT (FAT) block count: " + header_block_reader.getXBATCount()); - System.out.println(" XBAT (FAT) block 1 at: " + header_block_reader.getXBATIndex()); - System.out.println(" SBAT (MiniFAT) block count: " + header_block_reader.getSBATCount()); - System.out.println(" SBAT (MiniFAT) block 1 at: " + header_block_reader.getSBATStart()); - System.out.println(" Property table at: " + header_block_reader.getPropertyStart()); + System.out.println(" Block size: " + header_block.getBigBlockSize()); + System.out.println(" BAT (FAT) header blocks: " + header_block.getBATArray().length); + System.out.println(" BAT (FAT) block count: " + header_block.getBATCount()); + 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()); + System.out.println(" SBAT (MiniFAT) block 1 at: " + header_block.getSBATStart()); + System.out.println(" Property table at: " + header_block.getPropertyStart()); System.out.println(""); } diff --git a/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java b/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java index bb83bf815f..4504226227 100644 --- a/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java +++ b/src/java/org/apache/poi/poifs/eventfilesystem/POIFSReader.java @@ -31,7 +31,7 @@ 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.HeaderBlockReader; +import org.apache.poi.poifs.storage.HeaderBlock; import org.apache.poi.poifs.storage.RawDataBlockList; import org.apache.poi.poifs.storage.SmallBlockTableReader; @@ -75,32 +75,32 @@ public class POIFSReader registryClosed = true; // read the header block from the stream - HeaderBlockReader header_block_reader = new HeaderBlockReader(stream); + HeaderBlock header_block = new HeaderBlock(stream); // read the rest of the stream into blocks - RawDataBlockList data_blocks = new RawDataBlockList(stream, header_block_reader.getBigBlockSize()); + RawDataBlockList data_blocks = new RawDataBlockList(stream, header_block.getBigBlockSize()); // set up the block allocation table (necessary for the // data_blocks to be manageable - new BlockAllocationTableReader(header_block_reader.getBigBlockSize(), - header_block_reader.getBATCount(), - header_block_reader.getBATArray(), - header_block_reader.getXBATCount(), - header_block_reader.getXBATIndex(), + new BlockAllocationTableReader(header_block.getBigBlockSize(), + header_block.getBATCount(), + header_block.getBATArray(), + header_block.getXBATCount(), + header_block.getXBATIndex(), data_blocks); // get property table from the document PropertyTable properties = - new PropertyTable(header_block_reader.getBigBlockSize(), - header_block_reader.getPropertyStart(), + new PropertyTable(header_block.getBigBlockSize(), + header_block.getPropertyStart(), data_blocks); // process documents processProperties(SmallBlockTableReader .getSmallDocumentBlocks( - header_block_reader.getBigBlockSize(), + header_block.getBigBlockSize(), data_blocks, properties.getRoot(), - header_block_reader.getSBATStart()), + header_block.getSBATStart()), data_blocks, properties.getRoot() .getChildren(), new POIFSDocumentPath()); } diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java index 0a5f97844a..bbc22515dd 100644 --- a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java +++ b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java @@ -43,7 +43,7 @@ import org.apache.poi.poifs.storage.BlockAllocationTableWriter; import org.apache.poi.poifs.storage.BlockList; import org.apache.poi.poifs.storage.BlockWritable; import org.apache.poi.poifs.storage.HeaderBlockConstants; -import org.apache.poi.poifs.storage.HeaderBlockReader; +import org.apache.poi.poifs.storage.HeaderBlock; import org.apache.poi.poifs.storage.HeaderBlockWriter; import org.apache.poi.poifs.storage.RawDataBlockList; import org.apache.poi.poifs.storage.SmallBlockTableReader; @@ -146,12 +146,12 @@ public class POIFSFileSystem this(); boolean success = false; - HeaderBlockReader header_block_reader; + HeaderBlock header_block; RawDataBlockList data_blocks; try { // read the header block from the stream - header_block_reader = new HeaderBlockReader(stream); - bigBlockSize = header_block_reader.getBigBlockSize(); + header_block = new HeaderBlock(stream); + bigBlockSize = header_block.getBigBlockSize(); // read the rest of the stream into blocks data_blocks = new RawDataBlockList(stream, bigBlockSize); @@ -163,29 +163,29 @@ public class POIFSFileSystem // set up the block allocation table (necessary for the // data_blocks to be manageable - new BlockAllocationTableReader(header_block_reader.getBigBlockSize(), - header_block_reader.getBATCount(), - header_block_reader.getBATArray(), - header_block_reader.getXBATCount(), - header_block_reader.getXBATIndex(), + new BlockAllocationTableReader(header_block.getBigBlockSize(), + header_block.getBATCount(), + header_block.getBATArray(), + header_block.getXBATCount(), + header_block.getXBATIndex(), data_blocks); // get property table from the document PropertyTable properties = new PropertyTable(bigBlockSize, - header_block_reader.getPropertyStart(), + header_block.getPropertyStart(), data_blocks); // init documents processProperties( SmallBlockTableReader.getSmallDocumentBlocks( bigBlockSize, data_blocks, properties.getRoot(), - header_block_reader.getSBATStart() + header_block.getSBATStart() ), data_blocks, properties.getRoot().getChildren(), null, - header_block_reader.getPropertyStart() + header_block.getPropertyStart() ); // For whatever reason CLSID of root is always 0. diff --git a/src/java/org/apache/poi/poifs/storage/HeaderBlock.java b/src/java/org/apache/poi/poifs/storage/HeaderBlock.java new file mode 100644 index 0000000000..e12ec447d5 --- /dev/null +++ b/src/java/org/apache/poi/poifs/storage/HeaderBlock.java @@ -0,0 +1,343 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.poifs.storage; + +import static org.apache.poi.poifs.storage.HeaderBlockConstants._bat_array_offset; +import static org.apache.poi.poifs.storage.HeaderBlockConstants._bat_count_offset; +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; +import static org.apache.poi.poifs.storage.HeaderBlockConstants._xbat_start_offset; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import org.apache.poi.poifs.common.POIFSBigBlockSize; +import org.apache.poi.poifs.common.POIFSConstants; +import org.apache.poi.poifs.filesystem.OfficeXmlFileException; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.IOUtils; +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.POILogFactory; +import org.apache.poi.util.POILogger; +import org.apache.poi.util.ShortField; + +/** + * The block containing the archive header + */ +public final class HeaderBlock { + private static final POILogger _logger = + POILogFactory.getLogger(HeaderBlock.class); + + /** + * What big block size the file uses. Most files + * use 512 bytes, but a few use 4096 + */ + private final POIFSBigBlockSize bigBlockSize; + + /** + * number of big block allocation table blocks (int). + * (Number of FAT Sectors in Microsoft parlance) + */ + private int _bat_count; + + /** + * Start of the property set block (int index of the property set + * chain's first big block). + */ + private int _property_start; + + /** + * start of the small block allocation table (int index of small + * block allocation table's first big block) + */ + private int _sbat_start; + /** + * Number of small block allocation table blocks (int) + * (Number of MiniFAT Sectors in Microsoft parlance) + */ + private int _sbat_count; + + /** + * Big block index for extension to the big block allocation table + */ + private int _xbat_start; + /** + * Number of big block allocation table blocks (int) + * (Number of DIFAT Sectors in Microsoft parlance) + */ + private int _xbat_count; + + /** + * The data. Only ever 512 bytes, because 4096 byte + * files use zeros for the extra header space. + */ + private final byte[] _data; + + private static final byte _default_value = ( byte ) 0xFF; + + /** + * create a new HeaderBlockReader from an InputStream + * + * @param stream the source InputStream + * + * @exception IOException on errors or bad data + */ + public HeaderBlock(InputStream stream) throws IOException { + // Grab the first 512 bytes + // (For 4096 sized blocks, the remaining 3584 bytes are zero) + // Then, process the contents + this(readFirst512(stream)); + + // Fetch the rest of the block if needed + if(bigBlockSize.getBigBlockSize() != 512) { + int rest = bigBlockSize.getBigBlockSize() - 512; + byte[] tmp = new byte[rest]; + IOUtils.readFully(stream, tmp); + } + } + + public HeaderBlock(ByteBuffer buffer) throws IOException { + this(buffer.array()); + } + + private HeaderBlock(byte[] data) throws IOException { + this._data = data; + + // verify signature + long signature = LittleEndian.getLong(_data, _signature_offset); + + if (signature != _signature) { + // Is it one of the usual suspects? + byte[] OOXML_FILE_HEADER = POIFSConstants.OOXML_FILE_HEADER; + if(_data[0] == OOXML_FILE_HEADER[0] && + _data[1] == OOXML_FILE_HEADER[1] && + _data[2] == OOXML_FILE_HEADER[2] && + _data[3] == OOXML_FILE_HEADER[3]) { + throw new OfficeXmlFileException("The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)"); + } + if ((signature & 0xFF8FFFFFFFFFFFFFL) == 0x0010000200040009L) { + // BIFF2 raw stream starts with BOF (sid=0x0009, size=0x0004, data=0x00t0) + throw new IllegalArgumentException("The supplied data appears to be in BIFF2 format. " + + "POI only supports BIFF8 format"); + } + + // Give a generic error + throw new IOException("Invalid header signature; read " + + longToHex(signature) + ", expected " + + longToHex(_signature)); + } + + + // Figure out our block size + if (_data[30] == 12) { + this.bigBlockSize = POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS; + } else if(_data[30] == 9) { + this.bigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; + } else { + throw new IOException("Unsupported blocksize (2^"+ _data[30] + "). Expected 2^9 or 2^12."); + } + + // Setup the fields to read and write the counts and starts + _bat_count = new IntegerField(_bat_count_offset, data).get(); + _property_start = new IntegerField(_property_start_offset,_data).get(); + _sbat_start = new IntegerField(_sbat_start_offset, _data).get(); + _sbat_count = new IntegerField(_sbat_block_count_offset, _data).get(); + _xbat_start = new IntegerField(_xbat_start_offset, _data).get(); + _xbat_count = new IntegerField(_xbat_count_offset, _data).get(); + + // Sanity check values + if(_bat_count > _max_bats_in_header) { + _logger.log(POILogger.WARN, "Too many BAT blocks listed in header, found " + + _bat_count + " but the maximum is " + _max_bats_in_header); + _bat_count = _max_bats_in_header; + } + } + + /** + * Create a single instance initialized with default values + */ + public HeaderBlock(POIFSBigBlockSize bigBlockSize) throws IOException + { + this.bigBlockSize = bigBlockSize; + + // Our data is always 512 big no matter what + _data = new byte[ POIFSConstants.SMALLER_BIG_BLOCK_SIZE ]; + Arrays.fill(_data, _default_value); + + // Set all the default values + new LongField(_signature_offset, _signature, _data); + new IntegerField(0x08, 0, _data); + new IntegerField(0x0c, 0, _data); + new IntegerField(0x10, 0, _data); + new IntegerField(0x14, 0, _data); + new ShortField(0x18, ( short ) 0x3b, _data); + new ShortField(0x1a, ( short ) 0x3, _data); + new ShortField(0x1c, ( short ) -2, _data); + + new ShortField(0x1e, bigBlockSize.getHeaderValue(), _data); + new IntegerField(0x20, 0x6, _data); + new IntegerField(0x24, 0, _data); + new IntegerField(0x28, 0, _data); + new IntegerField(0x34, 0, _data); + new IntegerField(0x38, 0x1000, _data); + + // Initialise the variables + _bat_count = 0; + _sbat_count = 0; + _xbat_count = 0; + _property_start = POIFSConstants.END_OF_CHAIN; + _sbat_start = POIFSConstants.END_OF_CHAIN; + _xbat_start = POIFSConstants.END_OF_CHAIN; + } + + private static byte[] readFirst512(InputStream stream) throws IOException { + // Grab the first 512 bytes + // (For 4096 sized blocks, the remaining 3584 bytes are zero) + byte[] data = new byte[512]; + int bsCount = IOUtils.readFully(stream, data); + if(bsCount != 512) { + throw alertShortRead(bsCount, 512); + } + return data; + } + + private static String longToHex(long value) { + return new String(HexDump.longToHex(value)); + } + + private static IOException alertShortRead(int pRead, int expectedReadSize) { + int read; + if (pRead < 0) { + //Can't have -1 bytes read in the error message! + read = 0; + } else { + read = pRead; + } + String type = " byte" + (read == 1 ? (""): ("s")); + + return new IOException("Unable to read entire header; " + + read + type + " read; expected " + + expectedReadSize + " bytes"); + } + + /** + * get start of Property Table + * + * @return the index of the first block of the Property Table + */ + public int getPropertyStart() { + return _property_start; + } + + /** + * @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 + */ + public int getBATCount() { + return _bat_count; + } + + /** + * Returns the offsets to the first (up to) 109 + * BAT sectors. + * Any additional BAT sectors are held in the XBAT (DIFAT) + * sectors in a chain. + * @return BAT offset array + */ + public int[] getBATArray() { + // Read them in + int[] result = new int[ _bat_count ]; + int offset = _bat_array_offset; + for (int j = 0; j < _bat_count; j++) { + result[ j ] = LittleEndian.getInt(_data, offset); + offset += LittleEndianConsts.INT_SIZE; + } + return result; + } + + /** + * @return XBAT (DIFAT) count + */ + public int getXBATCount() { + return _xbat_count; + } + + /** + * @return XBAT (DIFAT) index + */ + public int getXBATIndex() { + return _xbat_start; + } + + /** + * @return The Big Block size, normally 512 bytes, sometimes 4096 bytes + */ + public POIFSBigBlockSize getBigBlockSize() { + return bigBlockSize; + } + + /** + * Write the block's data to an OutputStream + * + * @param stream the OutputStream to which the stored data should + * be written + * + * @exception IOException on problems writing to the specified + * stream + */ + void writeData(final OutputStream stream) + throws IOException + { + // Update the counts and start positions + new IntegerField(_bat_count_offset, _bat_count, _data); + new IntegerField(_property_start_offset, _property_start, _data); + new IntegerField(_sbat_start_offset, _sbat_start, _data); + new IntegerField(_sbat_block_count_offset, _sbat_count, _data); + new IntegerField(_xbat_start_offset, _xbat_start, _data); + new IntegerField(_xbat_count_offset, _xbat_count, _data); + + // Write the main data out + stream.write(_data, 0, 512); + + // Now do the padding if needed + for(int i=POIFSConstants.SMALLER_BIG_BLOCK_SIZE; i 0); - assertEquals(0, header_block_reader.getXBATCount()); + assertEquals(1, header_block.getBATArray().length); + assertEquals(1, header_block.getBATCount()); + assertEquals(0, header_block.getXBATCount()); // Now check we can get the basic fat RawDataBlockList data_blocks = new RawDataBlockList(inp, bigBlockSize); diff --git a/src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java b/src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java index b589922587..46011916ee 100644 --- a/src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java +++ b/src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java @@ -33,8 +33,8 @@ public final class AllPOIFSStorageTests { result.addTestSuite(TestBlockAllocationTableWriter.class); result.addTestSuite(TestBlockListImpl.class); result.addTestSuite(TestDocumentBlock.class); - result.addTestSuite(TestHeaderBlockReader.class); - result.addTestSuite(TestHeaderBlockWriter.class); + result.addTestSuite(TestHeaderBlockReading.class); + result.addTestSuite(TestHeaderBlockWriting.class); result.addTestSuite(TestPropertyBlock.class); result.addTestSuite(TestRawDataBlock.class); result.addTestSuite(TestRawDataBlockList.class); diff --git a/src/testcases/org/apache/poi/poifs/storage/TestBlockAllocationTableReader.java b/src/testcases/org/apache/poi/poifs/storage/TestBlockAllocationTableReader.java index 45dd34c26e..79f7bd76de 100644 --- a/src/testcases/org/apache/poi/poifs/storage/TestBlockAllocationTableReader.java +++ b/src/testcases/org/apache/poi/poifs/storage/TestBlockAllocationTableReader.java @@ -405,10 +405,10 @@ public final class TestBlockAllocationTableReader extends TestCase { // similar code to POIFSFileSystem.: InputStream stream = new ByteArrayInputStream(data); - HeaderBlockReader hb; + HeaderBlock hb; RawDataBlockList dataBlocks; try { - hb = new HeaderBlockReader(stream); + hb = new HeaderBlock(stream); dataBlocks = new RawDataBlockList(stream, bigBlockSize); } catch (IOException e) { throw new RuntimeException(e); @@ -419,7 +419,11 @@ public final class TestBlockAllocationTableReader extends TestCase { hb.getXBATIndex(), dataBlocks); } catch (IOException e) { // expected during successful test - assertEquals("Block count 538976257 is too high. POI maximum is 65535.", e.getMessage()); + assertEquals( + "Your file contains 0 sectors, but the initial DIFAT array at index 0 referenced block # 538976288. This isn't allowed and your file is corrupt", + e.getMessage() + ); +// assertEquals("Block count 538976257 is too high. POI maximum is 65535.", e.getMessage()); } catch (OutOfMemoryError e) { if (e.getStackTrace()[1].getMethodName().equals("testBadSectorAllocationTableSize")) { throw new AssertionFailedError("Identified bug 48085"); diff --git a/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockReader.java b/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockReader.java deleted file mode 100644 index f49ef12322..0000000000 --- a/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockReader.java +++ /dev/null @@ -1,83 +0,0 @@ -/* ==================================================================== - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -==================================================================== */ - -package org.apache.poi.poifs.storage; - -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import junit.framework.TestCase; - -/** - * Class to test HeaderBlockReader functionality - * - * @author Marc Johnson - */ -public final class TestHeaderBlockReader extends TestCase { - - public void testConstructors() throws IOException { - String[] hexData = { - "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", - "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", - "01 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - }; - byte[] content = RawDataUtil.decode(hexData); - HeaderBlockReader block = new HeaderBlockReader(new ByteArrayInputStream(content)); - - assertEquals(-2, block.getPropertyStart()); - - // verify we can't read a short block - byte[] shortblock = new byte[511]; - - System.arraycopy(content, 0, shortblock, 0, 511); - try { - block = new HeaderBlockReader(new ByteArrayInputStream(shortblock)); - fail("Should have caught IOException reading a short block"); - } catch (IOException ignored) { - - // as expected - } - - // try various forms of corruption - for (int index = 0; index < 8; index++) { - content[index] = (byte) (content[index] - 1); - try { - block = new HeaderBlockReader(new ByteArrayInputStream(content)); - fail("Should have caught IOException corrupting byte " + index); - } catch (IOException ignored) { - - // as expected - } - - // restore byte value - content[index] = (byte) (content[index] + 1); - } - } -} diff --git a/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockReading.java b/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockReading.java new file mode 100644 index 0000000000..15077c4fba --- /dev/null +++ b/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockReading.java @@ -0,0 +1,83 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.poifs.storage; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import junit.framework.TestCase; + +/** + * Class to test HeaderBlockReader functionality + * + * @author Marc Johnson + */ +public final class TestHeaderBlockReading extends TestCase { + + public void testConstructors() throws IOException { + String[] hexData = { + "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", + "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", + "01 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + }; + byte[] content = RawDataUtil.decode(hexData); + HeaderBlock block = new HeaderBlock(new ByteArrayInputStream(content)); + + assertEquals(-2, block.getPropertyStart()); + + // verify we can't read a short block + byte[] shortblock = new byte[511]; + + System.arraycopy(content, 0, shortblock, 0, 511); + try { + block = new HeaderBlock(new ByteArrayInputStream(shortblock)); + fail("Should have caught IOException reading a short block"); + } catch (IOException ignored) { + + // as expected + } + + // try various forms of corruption + for (int index = 0; index < 8; index++) { + content[index] = (byte) (content[index] - 1); + try { + block = new HeaderBlock(new ByteArrayInputStream(content)); + fail("Should have caught IOException corrupting byte " + index); + } catch (IOException ignored) { + + // as expected + } + + // restore byte value + content[index] = (byte) (content[index] + 1); + } + } +} diff --git a/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriter.java b/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriter.java deleted file mode 100644 index 456d30c52e..0000000000 --- a/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriter.java +++ /dev/null @@ -1,270 +0,0 @@ -/* ==================================================================== - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -==================================================================== */ - -package org.apache.poi.poifs.storage; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import junit.framework.TestCase; - -import org.apache.poi.poifs.common.POIFSConstants; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.LittleEndianConsts; - -/** - * Class to test HeaderBlockWriter functionality - * - * @author Marc Johnson - */ -public final class TestHeaderBlockWriter extends TestCase { - - private static void confirmEqual(String[] expectedDataHexDumpLines, byte[] actual) { - byte[] expected = RawDataUtil.decode(expectedDataHexDumpLines); - - assertEquals(expected.length, actual.length); - for (int j = 0; j < expected.length; j++) { - assertEquals("testing byte " + j, expected[j], actual[j]); - } - } - - /** - * Test creating a HeaderBlockWriter - */ - public void testConstructors() throws IOException { - HeaderBlockWriter block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); - ByteArrayOutputStream output = new ByteArrayOutputStream(512); - - block.writeBlocks(output); - byte[] copy = output.toByteArray(); - String[] expected = { - "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", - "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", - "00 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - }; - - confirmEqual(expected, copy); - - // verify we can read a 'good' HeaderBlockWriter (also test - // getPropertyStart) - block.setPropertyStart(0x87654321); - output = new ByteArrayOutputStream(512); - block.writeBlocks(output); - assertEquals(0x87654321, new HeaderBlockReader(new ByteArrayInputStream(output - .toByteArray())).getPropertyStart()); - } - - /** - * Test setting the SBAT start block - */ - public void testSetSBATStart() throws IOException { - HeaderBlockWriter block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); - - block.setSBATStart(0x01234567); - ByteArrayOutputStream output = new ByteArrayOutputStream(512); - - block.writeBlocks(output); - byte[] copy = output.toByteArray(); - String[] expected = { - "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", - "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 67 45 23 01", - "00 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - }; - confirmEqual(expected, copy); - } - - /** - * test setPropertyStart and getPropertyStart - */ - public void testSetPropertyStart() throws IOException { - HeaderBlockWriter block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); - - block.setPropertyStart(0x01234567); - ByteArrayOutputStream output = new ByteArrayOutputStream(512); - - block.writeBlocks(output); - byte[] copy = output.toByteArray(); - String[] expected = { - "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", - "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 67 45 23 01 00 00 00 00 00 10 00 00 FE FF FF FF", - "00 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - }; - confirmEqual(expected, copy); - } - - /** - * test setting the BAT blocks; also tests getBATCount, getBATArray, - * getXBATCount - */ - public void testSetBATBlocks() throws IOException { - - // first, a small set of blocks - HeaderBlockWriter block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); - BATBlock[] xbats = block.setBATBlocks(5, 0x01234567); - - assertEquals(0, xbats.length); - assertEquals(0, HeaderBlockWriter.calculateXBATStorageRequirements(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,5)); - ByteArrayOutputStream output = new ByteArrayOutputStream(512); - - block.writeBlocks(output); - byte[] copy = output.toByteArray(); - String[] expected = { - "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", - "06 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", - "00 00 00 00 FE FF FF FF 00 00 00 00 67 45 23 01 68 45 23 01 69 45 23 01 6A 45 23 01 6B 45 23 01", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", - }; - - confirmEqual(expected, copy); - - // second, a full set of blocks (109 blocks) - block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); - xbats = block.setBATBlocks(109, 0x01234567); - assertEquals(0, xbats.length); - assertEquals(0, HeaderBlockWriter.calculateXBATStorageRequirements(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,109)); - output = new ByteArrayOutputStream(512); - block.writeBlocks(output); - copy = output.toByteArray(); - String[] expected2 = { - "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", - "06 00 00 00 00 00 00 00 00 00 00 00 6D 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", - "00 00 00 00 FE FF FF FF 00 00 00 00 67 45 23 01 68 45 23 01 69 45 23 01 6A 45 23 01 6B 45 23 01", - "6C 45 23 01 6D 45 23 01 6E 45 23 01 6F 45 23 01 70 45 23 01 71 45 23 01 72 45 23 01 73 45 23 01", - "74 45 23 01 75 45 23 01 76 45 23 01 77 45 23 01 78 45 23 01 79 45 23 01 7A 45 23 01 7B 45 23 01", - "7C 45 23 01 7D 45 23 01 7E 45 23 01 7F 45 23 01 80 45 23 01 81 45 23 01 82 45 23 01 83 45 23 01", - "84 45 23 01 85 45 23 01 86 45 23 01 87 45 23 01 88 45 23 01 89 45 23 01 8A 45 23 01 8B 45 23 01", - "8C 45 23 01 8D 45 23 01 8E 45 23 01 8F 45 23 01 90 45 23 01 91 45 23 01 92 45 23 01 93 45 23 01", - "94 45 23 01 95 45 23 01 96 45 23 01 97 45 23 01 98 45 23 01 99 45 23 01 9A 45 23 01 9B 45 23 01", - "9C 45 23 01 9D 45 23 01 9E 45 23 01 9F 45 23 01 A0 45 23 01 A1 45 23 01 A2 45 23 01 A3 45 23 01", - "A4 45 23 01 A5 45 23 01 A6 45 23 01 A7 45 23 01 A8 45 23 01 A9 45 23 01 AA 45 23 01 AB 45 23 01", - "AC 45 23 01 AD 45 23 01 AE 45 23 01 AF 45 23 01 B0 45 23 01 B1 45 23 01 B2 45 23 01 B3 45 23 01", - "B4 45 23 01 B5 45 23 01 B6 45 23 01 B7 45 23 01 B8 45 23 01 B9 45 23 01 BA 45 23 01 BB 45 23 01", - "BC 45 23 01 BD 45 23 01 BE 45 23 01 BF 45 23 01 C0 45 23 01 C1 45 23 01 C2 45 23 01 C3 45 23 01", - "C4 45 23 01 C5 45 23 01 C6 45 23 01 C7 45 23 01 C8 45 23 01 C9 45 23 01 CA 45 23 01 CB 45 23 01", - "CC 45 23 01 CD 45 23 01 CE 45 23 01 CF 45 23 01 D0 45 23 01 D1 45 23 01 D2 45 23 01 D3 45 23 01", - }; - confirmEqual(expected2, copy); - - // finally, a really large set of blocks (256 blocks) - block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); - xbats = block.setBATBlocks(256, 0x01234567); - assertEquals(2, xbats.length); - assertEquals(2, HeaderBlockWriter.calculateXBATStorageRequirements(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,256)); - output = new ByteArrayOutputStream(512); - block.writeBlocks(output); - copy = output.toByteArray(); - String[] expected3 = { - "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", - "06 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", - "00 00 00 00 67 46 23 01 02 00 00 00 67 45 23 01 68 45 23 01 69 45 23 01 6A 45 23 01 6B 45 23 01", - "6C 45 23 01 6D 45 23 01 6E 45 23 01 6F 45 23 01 70 45 23 01 71 45 23 01 72 45 23 01 73 45 23 01", - "74 45 23 01 75 45 23 01 76 45 23 01 77 45 23 01 78 45 23 01 79 45 23 01 7A 45 23 01 7B 45 23 01", - "7C 45 23 01 7D 45 23 01 7E 45 23 01 7F 45 23 01 80 45 23 01 81 45 23 01 82 45 23 01 83 45 23 01", - "84 45 23 01 85 45 23 01 86 45 23 01 87 45 23 01 88 45 23 01 89 45 23 01 8A 45 23 01 8B 45 23 01", - "8C 45 23 01 8D 45 23 01 8E 45 23 01 8F 45 23 01 90 45 23 01 91 45 23 01 92 45 23 01 93 45 23 01", - "94 45 23 01 95 45 23 01 96 45 23 01 97 45 23 01 98 45 23 01 99 45 23 01 9A 45 23 01 9B 45 23 01", - "9C 45 23 01 9D 45 23 01 9E 45 23 01 9F 45 23 01 A0 45 23 01 A1 45 23 01 A2 45 23 01 A3 45 23 01", - "A4 45 23 01 A5 45 23 01 A6 45 23 01 A7 45 23 01 A8 45 23 01 A9 45 23 01 AA 45 23 01 AB 45 23 01", - "AC 45 23 01 AD 45 23 01 AE 45 23 01 AF 45 23 01 B0 45 23 01 B1 45 23 01 B2 45 23 01 B3 45 23 01", - "B4 45 23 01 B5 45 23 01 B6 45 23 01 B7 45 23 01 B8 45 23 01 B9 45 23 01 BA 45 23 01 BB 45 23 01", - "BC 45 23 01 BD 45 23 01 BE 45 23 01 BF 45 23 01 C0 45 23 01 C1 45 23 01 C2 45 23 01 C3 45 23 01", - "C4 45 23 01 C5 45 23 01 C6 45 23 01 C7 45 23 01 C8 45 23 01 C9 45 23 01 CA 45 23 01 CB 45 23 01", - "CC 45 23 01 CD 45 23 01 CE 45 23 01 CF 45 23 01 D0 45 23 01 D1 45 23 01 D2 45 23 01 D3 45 23 01", - }; - - confirmEqual(expected3, copy); - - output = new ByteArrayOutputStream(1028); - xbats[0].writeBlocks(output); - xbats[1].writeBlocks(output); - copy = output.toByteArray(); - int correct = 0x012345D4; - int offset = 0; - int k = 0; - - for (; k < 127; k++) { - assertEquals("XBAT entry " + k, correct, LittleEndian.getInt(copy, offset)); - correct++; - offset += LittleEndianConsts.INT_SIZE; - } - assertEquals("XBAT Chain", 0x01234567 + 257, LittleEndian.getInt(copy, offset)); - offset += LittleEndianConsts.INT_SIZE; - k++; - for (; k < 148; k++) { - assertEquals("XBAT entry " + k, correct, LittleEndian.getInt(copy, offset)); - correct++; - offset += LittleEndianConsts.INT_SIZE; - } - for (; k < 255; k++) { - assertEquals("XBAT entry " + k, -1, LittleEndian.getInt(copy, offset)); - offset += LittleEndianConsts.INT_SIZE; - } - assertEquals("XBAT End of chain", -2, LittleEndian.getInt(copy, offset)); - } -} diff --git a/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriting.java b/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriting.java new file mode 100644 index 0000000000..e01c7885be --- /dev/null +++ b/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriting.java @@ -0,0 +1,270 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.poifs.storage; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.poi.poifs.common.POIFSConstants; +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianConsts; + +/** + * Class to test HeaderBlockWriter functionality + * + * @author Marc Johnson + */ +public final class TestHeaderBlockWriting extends TestCase { + + private static void confirmEqual(String[] expectedDataHexDumpLines, byte[] actual) { + byte[] expected = RawDataUtil.decode(expectedDataHexDumpLines); + + assertEquals(expected.length, actual.length); + for (int j = 0; j < expected.length; j++) { + assertEquals("testing byte " + j, expected[j], actual[j]); + } + } + + /** + * Test creating a HeaderBlockWriter + */ + public void testConstructors() throws IOException { + HeaderBlockWriter block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); + ByteArrayOutputStream output = new ByteArrayOutputStream(512); + + block.writeBlocks(output); + byte[] copy = output.toByteArray(); + String[] expected = { + "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", + "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", + "00 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + }; + + confirmEqual(expected, copy); + + // verify we can read a 'good' HeaderBlockWriter (also test + // getPropertyStart) + block.setPropertyStart(0x87654321); + output = new ByteArrayOutputStream(512); + block.writeBlocks(output); + assertEquals(0x87654321, new HeaderBlock( + new ByteArrayInputStream(output.toByteArray())).getPropertyStart()); + } + + /** + * Test setting the SBAT start block + */ + public void testSetSBATStart() throws IOException { + HeaderBlockWriter block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); + + block.setSBATStart(0x01234567); + ByteArrayOutputStream output = new ByteArrayOutputStream(512); + + block.writeBlocks(output); + byte[] copy = output.toByteArray(); + String[] expected = { + "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", + "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 67 45 23 01", + "00 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + }; + confirmEqual(expected, copy); + } + + /** + * test setPropertyStart and getPropertyStart + */ + public void testSetPropertyStart() throws IOException { + HeaderBlockWriter block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); + + block.setPropertyStart(0x01234567); + ByteArrayOutputStream output = new ByteArrayOutputStream(512); + + block.writeBlocks(output); + byte[] copy = output.toByteArray(); + String[] expected = { + "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", + "06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 67 45 23 01 00 00 00 00 00 10 00 00 FE FF FF FF", + "00 00 00 00 FE FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + }; + confirmEqual(expected, copy); + } + + /** + * test setting the BAT blocks; also tests getBATCount, getBATArray, + * getXBATCount + */ + public void testSetBATBlocks() throws IOException { + + // first, a small set of blocks + HeaderBlockWriter block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); + BATBlock[] xbats = block.setBATBlocks(5, 0x01234567); + + assertEquals(0, xbats.length); + assertEquals(0, HeaderBlockWriter.calculateXBATStorageRequirements(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,5)); + ByteArrayOutputStream output = new ByteArrayOutputStream(512); + + block.writeBlocks(output); + byte[] copy = output.toByteArray(); + String[] expected = { + "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", + "06 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", + "00 00 00 00 FE FF FF FF 00 00 00 00 67 45 23 01 68 45 23 01 69 45 23 01 6A 45 23 01 6B 45 23 01", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", + }; + + confirmEqual(expected, copy); + + // second, a full set of blocks (109 blocks) + block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); + xbats = block.setBATBlocks(109, 0x01234567); + assertEquals(0, xbats.length); + assertEquals(0, HeaderBlockWriter.calculateXBATStorageRequirements(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,109)); + output = new ByteArrayOutputStream(512); + block.writeBlocks(output); + copy = output.toByteArray(); + String[] expected2 = { + "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", + "06 00 00 00 00 00 00 00 00 00 00 00 6D 00 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", + "00 00 00 00 FE FF FF FF 00 00 00 00 67 45 23 01 68 45 23 01 69 45 23 01 6A 45 23 01 6B 45 23 01", + "6C 45 23 01 6D 45 23 01 6E 45 23 01 6F 45 23 01 70 45 23 01 71 45 23 01 72 45 23 01 73 45 23 01", + "74 45 23 01 75 45 23 01 76 45 23 01 77 45 23 01 78 45 23 01 79 45 23 01 7A 45 23 01 7B 45 23 01", + "7C 45 23 01 7D 45 23 01 7E 45 23 01 7F 45 23 01 80 45 23 01 81 45 23 01 82 45 23 01 83 45 23 01", + "84 45 23 01 85 45 23 01 86 45 23 01 87 45 23 01 88 45 23 01 89 45 23 01 8A 45 23 01 8B 45 23 01", + "8C 45 23 01 8D 45 23 01 8E 45 23 01 8F 45 23 01 90 45 23 01 91 45 23 01 92 45 23 01 93 45 23 01", + "94 45 23 01 95 45 23 01 96 45 23 01 97 45 23 01 98 45 23 01 99 45 23 01 9A 45 23 01 9B 45 23 01", + "9C 45 23 01 9D 45 23 01 9E 45 23 01 9F 45 23 01 A0 45 23 01 A1 45 23 01 A2 45 23 01 A3 45 23 01", + "A4 45 23 01 A5 45 23 01 A6 45 23 01 A7 45 23 01 A8 45 23 01 A9 45 23 01 AA 45 23 01 AB 45 23 01", + "AC 45 23 01 AD 45 23 01 AE 45 23 01 AF 45 23 01 B0 45 23 01 B1 45 23 01 B2 45 23 01 B3 45 23 01", + "B4 45 23 01 B5 45 23 01 B6 45 23 01 B7 45 23 01 B8 45 23 01 B9 45 23 01 BA 45 23 01 BB 45 23 01", + "BC 45 23 01 BD 45 23 01 BE 45 23 01 BF 45 23 01 C0 45 23 01 C1 45 23 01 C2 45 23 01 C3 45 23 01", + "C4 45 23 01 C5 45 23 01 C6 45 23 01 C7 45 23 01 C8 45 23 01 C9 45 23 01 CA 45 23 01 CB 45 23 01", + "CC 45 23 01 CD 45 23 01 CE 45 23 01 CF 45 23 01 D0 45 23 01 D1 45 23 01 D2 45 23 01 D3 45 23 01", + }; + confirmEqual(expected2, copy); + + // finally, a really large set of blocks (256 blocks) + block = new HeaderBlockWriter(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); + xbats = block.setBATBlocks(256, 0x01234567); + assertEquals(2, xbats.length); + assertEquals(2, HeaderBlockWriter.calculateXBATStorageRequirements(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS,256)); + output = new ByteArrayOutputStream(512); + block.writeBlocks(output); + copy = output.toByteArray(); + String[] expected3 = { + "D0 CF 11 E0 A1 B1 1A E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3B 00 03 00 FE FF 09 00", + "06 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 FE FF FF FF 00 00 00 00 00 10 00 00 FE FF FF FF", + "00 00 00 00 67 46 23 01 02 00 00 00 67 45 23 01 68 45 23 01 69 45 23 01 6A 45 23 01 6B 45 23 01", + "6C 45 23 01 6D 45 23 01 6E 45 23 01 6F 45 23 01 70 45 23 01 71 45 23 01 72 45 23 01 73 45 23 01", + "74 45 23 01 75 45 23 01 76 45 23 01 77 45 23 01 78 45 23 01 79 45 23 01 7A 45 23 01 7B 45 23 01", + "7C 45 23 01 7D 45 23 01 7E 45 23 01 7F 45 23 01 80 45 23 01 81 45 23 01 82 45 23 01 83 45 23 01", + "84 45 23 01 85 45 23 01 86 45 23 01 87 45 23 01 88 45 23 01 89 45 23 01 8A 45 23 01 8B 45 23 01", + "8C 45 23 01 8D 45 23 01 8E 45 23 01 8F 45 23 01 90 45 23 01 91 45 23 01 92 45 23 01 93 45 23 01", + "94 45 23 01 95 45 23 01 96 45 23 01 97 45 23 01 98 45 23 01 99 45 23 01 9A 45 23 01 9B 45 23 01", + "9C 45 23 01 9D 45 23 01 9E 45 23 01 9F 45 23 01 A0 45 23 01 A1 45 23 01 A2 45 23 01 A3 45 23 01", + "A4 45 23 01 A5 45 23 01 A6 45 23 01 A7 45 23 01 A8 45 23 01 A9 45 23 01 AA 45 23 01 AB 45 23 01", + "AC 45 23 01 AD 45 23 01 AE 45 23 01 AF 45 23 01 B0 45 23 01 B1 45 23 01 B2 45 23 01 B3 45 23 01", + "B4 45 23 01 B5 45 23 01 B6 45 23 01 B7 45 23 01 B8 45 23 01 B9 45 23 01 BA 45 23 01 BB 45 23 01", + "BC 45 23 01 BD 45 23 01 BE 45 23 01 BF 45 23 01 C0 45 23 01 C1 45 23 01 C2 45 23 01 C3 45 23 01", + "C4 45 23 01 C5 45 23 01 C6 45 23 01 C7 45 23 01 C8 45 23 01 C9 45 23 01 CA 45 23 01 CB 45 23 01", + "CC 45 23 01 CD 45 23 01 CE 45 23 01 CF 45 23 01 D0 45 23 01 D1 45 23 01 D2 45 23 01 D3 45 23 01", + }; + + confirmEqual(expected3, copy); + + output = new ByteArrayOutputStream(1028); + xbats[0].writeBlocks(output); + xbats[1].writeBlocks(output); + copy = output.toByteArray(); + int correct = 0x012345D4; + int offset = 0; + int k = 0; + + for (; k < 127; k++) { + assertEquals("XBAT entry " + k, correct, LittleEndian.getInt(copy, offset)); + correct++; + offset += LittleEndianConsts.INT_SIZE; + } + assertEquals("XBAT Chain", 0x01234567 + 257, LittleEndian.getInt(copy, offset)); + offset += LittleEndianConsts.INT_SIZE; + k++; + for (; k < 148; k++) { + assertEquals("XBAT entry " + k, correct, LittleEndian.getInt(copy, offset)); + correct++; + offset += LittleEndianConsts.INT_SIZE; + } + for (; k < 255; k++) { + assertEquals("XBAT entry " + k, -1, LittleEndian.getInt(copy, offset)); + offset += LittleEndianConsts.INT_SIZE; + } + assertEquals("XBAT End of chain", -2, LittleEndian.getInt(copy, offset)); + } +}