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;
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("");
}
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;
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());
}
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;
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);
// 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.
--- /dev/null
+/* ====================================================================
+ 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<POIFSConstants.LARGER_BIG_BLOCK_SIZE; i++) {
+ stream.write(0);
+ }
+ }
+}
+++ /dev/null
-/* ====================================================================
- 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.nio.ByteBuffer;
-
-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.util.HexDump;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.LittleEndianConsts;
-
-/**
- * The block containing the archive header
- *
- * @author Marc Johnson (mjohnson at apache dot org)
- */
-public final class HeaderBlockReader {
- /**
- * 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 final int _bat_count;
-
- /**
- * 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
- * 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
- */
- 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;
-
- /**
- * The data
- */
- private final byte[] _data;
-
- /**
- * create a new HeaderBlockReader from an InputStream
- *
- * @param stream the source InputStream
- *
- * @exception IOException on errors or bad data
- */
- public HeaderBlockReader(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 HeaderBlockReader(ByteBuffer buffer) throws IOException {
- this(buffer.array());
- }
-
- private HeaderBlockReader(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
- switch (_data[30]) {
- case 12:
- bigBlockSize = POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS; break;
- case 9:
- bigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; break;
- default:
- throw new IOException("Unsupported blocksize (2^"
- + _data[30] + "). Expected 2^9 or 2^12.");
- }
-
- _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);
- }
-
- 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 int getInt(int offset, byte[] data) {
- return LittleEndian.getInt(data, offset);
- }
-
- 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
- * @return BAT offset array
- */
- public int[] getBATArray() {
- int[] result = new int[ _max_bats_in_header ];
- int offset = _bat_array_offset;
-
- for (int j = 0; j < _max_bats_in_header; 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;
- }
-}
import org.apache.poi.POIDataSamples;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.poifs.common.POIFSBigBlockSize;
-import org.apache.poi.poifs.storage.HeaderBlockReader;
+import org.apache.poi.poifs.storage.HeaderBlock;
import org.apache.poi.poifs.storage.RawDataBlockList;
/**
InputStream inp = _samples.openResourceAsStream("BlockSize4096.zvi");
// First up, check that we can process the header properly
- HeaderBlockReader header_block_reader = new HeaderBlockReader(inp);
- POIFSBigBlockSize bigBlockSize = header_block_reader.getBigBlockSize();
+ HeaderBlock header_block = new HeaderBlock(inp);
+ POIFSBigBlockSize bigBlockSize = header_block.getBigBlockSize();
assertEquals(4096, bigBlockSize.getBigBlockSize());
// Check the fat info looks sane
- assertEquals(109, header_block_reader.getBATArray().length);
- assertTrue(header_block_reader.getBATCount() > 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);
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);
// similar code to POIFSFileSystem.<init>:
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);
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");
+++ /dev/null
-/* ====================================================================
- 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);
- }
- }
-}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+ }
+}
+++ /dev/null
-/* ====================================================================
- 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));
- }
-}
--- /dev/null
+/* ====================================================================
+ 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));
+ }
+}