/// <summary> /// Create a single instance initialized with default values /// </summary> /// <param name="bigBlockSize"></param> /// <param name="properties">the properties to be inserted</param> /// <param name="offset">the offset into the properties array</param> protected PropertyBlock(POIFSBigBlockSize bigBlockSize, Property[] properties, int offset) : base(bigBlockSize) { _properties = new Property[bigBlockSize.GetPropertiesPerBlock()]; for (int j = 0; j < _properties.Length; j++) { _properties[j] = properties[j + offset]; } }
public SmallDocumentBlock(POIFSBigBlockSize bigBlockSize, byte[] data, int index) { _bigBlockSize = bigBlockSize; _blocks_per_big_block = GetBlocksPerBigBlock(bigBlockSize); _data = new byte[_block_size]; System.Array.Copy(data, index * _block_size, _data, 0, _block_size); }
internal BigBlockStore(POIFSBigBlockSize bigBlockSize, POIFSDocumentPath path, string name, int size, POIFSWriterListener writer) { this.bigBlockSize = bigBlockSize; this.bigBlocks = new DocumentBlock[0]; this.path = path; this.name = name; this.size = size; this.writer = writer; }
internal BigBlockStore(POIFSBigBlockSize bigBlockSize, DocumentBlock[] blocks) { this.bigBlockSize = bigBlockSize; bigBlocks = (DocumentBlock[])blocks.Clone(); path = null; name = null; size = -1; writer = null; }
internal SmallBlockStore(POIFSBigBlockSize bigBlockSize, SmallDocumentBlock[] blocks) { this.bigBlockSize = bigBlockSize; smallBlocks = (SmallDocumentBlock[])blocks.Clone(); this.path = null; this.name = null; this.size = -1; this.writer = null; }
public static BATBlockAndIndex GetSBATBlockAndIndex(int offset, HeaderBlock header, List <BATBlock> sbats) { POIFSBigBlockSize bigBlockSize = header.BigBlockSize; int whichSBAT = (int)Math.Floor(1.0 * offset / bigBlockSize.GetBATEntriesPerBlock()); int index = offset % bigBlockSize.GetBATEntriesPerBlock(); return(new BATBlockAndIndex(index, sbats[whichSBAT])); }
public void TestUsedSectors() { POIFSBigBlockSize b512 = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; POIFSBigBlockSize b4096 = POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS; // Try first with 512 block sizes, which can hold 128 entries BATBlock block512 = BATBlock.CreateEmptyBATBlock(b512, false); Assert.AreEqual(true, block512.HasFreeSectors); Assert.AreEqual(0, block512.GetUsedSectors(false)); // Allocate a few block512.SetValueAt(0, 42); block512.SetValueAt(10, 42); block512.SetValueAt(20, 42); Assert.AreEqual(true, block512.HasFreeSectors); Assert.AreEqual(3, block512.GetUsedSectors(false)); // Allocate all for (int i = 0; i < b512.GetBATEntriesPerBlock(); i++) { block512.SetValueAt(i, 82); } // Check Assert.AreEqual(false, block512.HasFreeSectors); Assert.AreEqual(128, block512.GetUsedSectors(false)); Assert.AreEqual(127, block512.GetUsedSectors(true)); // Release one block512.SetValueAt(10, POIFSConstants.UNUSED_BLOCK); Assert.AreEqual(true, block512.HasFreeSectors); Assert.AreEqual(127, block512.GetUsedSectors(false)); Assert.AreEqual(126, block512.GetUsedSectors(true)); // Now repeat with 4096 block sizes BATBlock block4096 = BATBlock.CreateEmptyBATBlock(b4096, false); Assert.AreEqual(true, block4096.HasFreeSectors); Assert.AreEqual(0, block4096.GetUsedSectors(false)); block4096.SetValueAt(0, 42); block4096.SetValueAt(10, 42); block4096.SetValueAt(20, 42); Assert.AreEqual(true, block4096.HasFreeSectors); Assert.AreEqual(3, block4096.GetUsedSectors(false)); // Allocate all for (int i = 0; i < b4096.GetBATEntriesPerBlock(); i++) { block4096.SetValueAt(i, 82); } // Check Assert.AreEqual(false, block4096.HasFreeSectors); Assert.AreEqual(1024, block4096.GetUsedSectors(false)); Assert.AreEqual(1023, block4096.GetUsedSectors(true)); }
/// <summary> /// Makes the empty small document block. /// </summary> /// <returns></returns> private static SmallDocumentBlock MakeEmptySmallDocumentBlock(POIFSBigBlockSize bigBlockSize) { SmallDocumentBlock block = new SmallDocumentBlock(bigBlockSize); for (int i = 0; i < block._data.Length; i++) { block._data[i] = _default_fill; } return(block); }
///** // * Creates a single BATBlock, with all the values set to empty. // */ public static BATBlock CreateEmptyBATBlock(POIFSBigBlockSize bigBlockSize, bool isXBAT) { BATBlock block = new BATBlock(bigBlockSize); if (isXBAT) { block.SetXBATChain(bigBlockSize, POIFSConstants.END_OF_CHAIN); } return(block); }
private static BlockAllocationTableReader prepareReader( POIFSBigBlockSize bigBlockSize, RawDataBlockList blockList, BlockList list, RootProperty root, int sbatStart) { // Process the SBAT and blocks return(new BlockAllocationTableReader(bigBlockSize, blockList.FetchBlocks(sbatStart, -1), list)); }
/** * Read and process the PropertiesTable and the * FAT / XFAT blocks, so that we're Ready to * work with the file */ private void ReadCoreContents() { // Grab the block size bigBlockSize = _header.BigBlockSize; // Each block should only ever be used by one of the // FAT, XFAT or Property Table. Ensure it does ChainLoopDetector loopDetector = GetChainLoopDetector(); // Read the FAT blocks foreach (int fatAt in _header.BATArray) { ReadBAT(fatAt, loopDetector); } // Now read the XFAT blocks, and the FATs within them BATBlock xfat; int nextAt = _header.XBATIndex; for (int i = 0; i < _header.XBATCount; i++) { loopDetector.Claim(nextAt); ByteBuffer fatData = GetBlockAt(nextAt); xfat = BATBlock.CreateBATBlock(bigBlockSize, fatData); xfat.OurBlockIndex = nextAt; nextAt = xfat.GetValueAt(bigBlockSize.GetXBATEntriesPerBlock()); _xbat_blocks.Add(xfat); for (int j = 0; j < bigBlockSize.GetXBATEntriesPerBlock(); j++) { int fatAt = xfat.GetValueAt(j); if (fatAt == POIFSConstants.UNUSED_BLOCK) break; ReadBAT(fatAt, loopDetector); } } // We're now able to load steams // Use this to read in the properties _property_table = new NPropertyTable(_header, this); // Finally read the Small Stream FAT (SBAT) blocks BATBlock sfat; List<BATBlock> sbats = new List<BATBlock>(); _mini_store = new NPOIFSMiniStore(this, _property_table.Root, sbats, _header); nextAt = _header.SBATStart; for (int i = 0; i < _header.SBATCount; i++) { loopDetector.Claim(nextAt); ByteBuffer fatData = GetBlockAt(nextAt); sfat = BATBlock.CreateBATBlock(bigBlockSize, fatData); sfat.OurBlockIndex = nextAt; sbats.Add(sfat); nextAt = GetNextBlock(nextAt); } }
/// <summary> /// fetch the small document block list from an existing file /// </summary> /// <param name="blockList">the raw data from which the small block table will be extracted</param> /// <param name="root">the root property (which contains the start block and small block table size)</param> /// <param name="sbatStart">the start block of the SBAT</param> /// <returns>the small document block list</returns> public static BlockList GetSmallDocumentBlocks(POIFSBigBlockSize bigBlockSize, RawDataBlockList blockList, RootProperty root, int sbatStart) { BlockList list = new SmallDocumentBlockList( SmallDocumentBlock.Extract(bigBlockSize, blockList.FetchBlocks(root.StartBlock, -1))); new BlockAllocationTableReader(bigBlockSize, blockList.FetchBlocks(sbatStart, -1), list); return(list); }
/// <summary> /// fetch the small document block list from an existing file, normally /// needed for debugging and low level dumping. You should typically call /// </summary> /// <param name="bigBlockSize">the poifs bigBlockSize</param> /// <param name="blockList">the raw data from which the small block table will be extracted</param> /// <param name="root">the root property (which contains the start block and small block table size)</param> /// <param name="sbatStart">the start block of the SBAT</param> /// <returns>the small document block reader</returns> public static BlockAllocationTableReader _getSmallDocumentBlockReader( POIFSBigBlockSize bigBlockSize, RawDataBlockList blockList, RootProperty root, int sbatStart) { BlockList list = prepareSmallDocumentBlocks( bigBlockSize, blockList, root, sbatStart); return(prepareReader( bigBlockSize, blockList, list, root, sbatStart)); }
/** * Calculates the maximum size of a file which is addressable given the * number of FAT (BAT) sectors specified. (We don't care if those BAT * blocks come from the 109 in the header, or from header + XBATS, it * won't affect the calculation) * * The actual file size will be between [size of fatCount-1 blocks] and * [size of fatCount blocks]. * For 512 byte block sizes, this means we may over-estimate by up to 65kb. * For 4096 byte block sizes, this means we may over-estimate by up to 4mb */ public static long CalculateMaximumSize(POIFSBigBlockSize bigBlockSize, int numBATs) { long size = 1; // Header isn't FAT addressed // The header has up to 109 BATs, and extra ones are referenced // from XBATs // However, all BATs can contain 128/1024 blocks size += (numBATs * bigBlockSize.GetBATEntriesPerBlock()); // So far we've been in sector counts, turn into bytes return(size * bigBlockSize.GetBigBlockSize()); }
/// <summary> /// fill out a List of SmallDocumentBlocks so that it fully occupies /// a Set of big blocks /// </summary> /// <param name="bigBlockSize"></param> /// <param name="blocks">the List to be filled out.</param> /// <returns>number of big blocks the list encompasses</returns> public static int Fill(POIFSBigBlockSize bigBlockSize, IList <SmallDocumentBlock> blocks) { int _blocks_per_big_block = GetBlocksPerBigBlock(bigBlockSize); int count = blocks.Count; int big_block_count = (count + _blocks_per_big_block - 1) / _blocks_per_big_block; int full_count = big_block_count * _blocks_per_big_block; for (; count < full_count; count++) { blocks.Add(MakeEmptySmallDocumentBlock(bigBlockSize)); } return(big_block_count); }
protected BATBlock(POIFSBigBlockSize bigBlockSize) : base(bigBlockSize) { int _entries_per_block = bigBlockSize.GetBATEntriesPerBlock(); _values = new int[_entries_per_block]; _has_free_sectors = true; for (int i = 0; i < _values.Length; i++) { _values[i] = POIFSConstants.UNUSED_BLOCK; } }
public void PrivateHeaderBlock(byte[] data) { _data = data; long signature = LittleEndian.GetLong(_data, _signature_offset); if (signature != _signature) { 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 & unchecked ((long)0xFF8FFFFFFFFFFFFFL)) == 0x0010000200040009L) { throw new ArgumentException("The supplied data appears to be in BIFF2 format. " + "POI only supports BIFF8 format"); } // Give a generic error if the OLE2 signature isn't found throw new IOException("Invalid header signature; read " + LongToHex(signature) + ", expected " + LongToHex(_signature) + " - Your file appears " + "not to be a valid OLE2 document"); } if (_data[30] == 12) { bigBlockSize = POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS; } else if (_data[30] == 9) { 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(HeaderBlockConstants._bat_count_offset, _data).Value; _property_start = new IntegerField(HeaderBlockConstants._property_start_offset, _data).Value; _sbat_start = new IntegerField(HeaderBlockConstants._sbat_start_offset, _data).Value; _sbat_count = new IntegerField(HeaderBlockConstants._sbat_block_count_offset, _data).Value; _xbat_start = new IntegerField(HeaderBlockConstants._xbat_start_offset, _data).Value; _xbat_count = new IntegerField(HeaderBlockConstants._xbat_count_offset, _data).Value; }
/** * Create a single instance initialized (perhaps partially) with entries * * @param entries the array of block allocation table entries * @param start_index the index of the first entry to be written * to the block * @param end_index the index, plus one, of the last entry to be * written to the block (writing is for all index * k, start_index <= k < end_index) */ protected BATBlock(POIFSBigBlockSize bigBlockSize, int[] entries, int start_index, int end_index) : this(bigBlockSize) { for (int k = start_index; k < end_index; k++) { _values[k - start_index] = entries[k]; } // Do we have any free sectors? if (end_index - start_index == _values.Length) { RecomputeFree(); } }
private static BlockList prepareSmallDocumentBlocks( POIFSBigBlockSize bigBlockSize, RawDataBlockList blockList, RootProperty root, int sbatStart) { // Fetch the blocks which hold the Small Blocks stream ListManagedBlock[] smallBlockBlocks = blockList.FetchBlocks(root.StartBlock, -1); // Turn that into a list BlockList list = new SmallDocumentBlockList( SmallDocumentBlock.Extract(bigBlockSize, smallBlockBlocks)); return(list); }
/// <summary> /// create a list of SmallDocumentBlock's from raw data /// </summary> /// <param name="bigBlockSize"></param> /// <param name="blocks">the raw data containing the SmallDocumentBlock</param> /// <returns>a List of SmallDocumentBlock's extracted from the input</returns> public static List <SmallDocumentBlock> Extract(POIFSBigBlockSize bigBlockSize, ListManagedBlock [] blocks) { int _blocks_per_big_block = GetBlocksPerBigBlock(bigBlockSize); List <SmallDocumentBlock> sdbs = new List <SmallDocumentBlock>(); for (int j = 0; j < blocks.Length; j++) { byte[] data = blocks[j].Data; for (int k = 0; k < _blocks_per_big_block; k++) { sdbs.Add(new SmallDocumentBlock(bigBlockSize, data, k)); } } return(sdbs); }
/** * Create a single BATBlock from the byte buffer, which must hold at least * one big block of data to be read. */ public static BATBlock CreateBATBlock(POIFSBigBlockSize bigBlockSize, BinaryReader data) { // Create an empty block BATBlock block = new BATBlock(bigBlockSize); // Fill it byte[] buffer = new byte[LittleEndianConsts.INT_SIZE]; for (int i = 0; i < block._values.Length; i++) { data.Read(buffer, 0, buffer.Length); block._values[i] = LittleEndian.GetInt(buffer); } block.RecomputeFree(); // All done return(block); }
public POIFSDocument(string name, int size, POIFSBigBlockSize bigBlockSize, POIFSDocumentPath path, POIFSWriterListener writer) { _size = size; _bigBigBlockSize = bigBlockSize; _property = new DocumentProperty(name, _size); _property.Document = this; if (_property.ShouldUseSmallBlocks) { _small_store = new SmallBlockStore(_bigBigBlockSize, path, name, size, writer); _big_store = new BigBlockStore(_bigBigBlockSize, EMPTY_BIG_BLOCK_ARRAY); } else { _small_store = new SmallBlockStore(_bigBigBlockSize, EMPTY_SMALL_BLOCK_ARRAY); _big_store = new BigBlockStore(_bigBigBlockSize, path, name, size, writer); } }
public static DataInputBlock GetDataInputBlock(DocumentBlock[] blocks, int offset) { if (blocks == null || blocks.Length == 0) { return(null); } POIFSBigBlockSize bigBlockSize = blocks[0].bigBlockSize; int BLOCK_SHIFT = bigBlockSize.GetHeaderValue(); int BLOCK_SIZE = bigBlockSize.GetBigBlockSize(); int BLOCK_MASK = BLOCK_SIZE - 1; int firstBlockIndex = offset >> BLOCK_SHIFT; int firstBlockOffset = offset & BLOCK_MASK; return(new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset)); }
public POIFSDocument(string name, SmallDocumentBlock[] blocks, int length) { _size = length; if (blocks.Length == 0) { _bigBigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; } else { _bigBigBlockSize = blocks[0].BigBlockSize; } _big_store = new BigBlockStore(_bigBigBlockSize, EMPTY_BIG_BLOCK_ARRAY); _property = new DocumentProperty(name, _size); _small_store = new SmallBlockStore(_bigBigBlockSize, blocks); _property.Document = this; }
/// <summary> /// Create an array of BATBlocks from an array of int block /// allocation table entries /// </summary> /// <param name="bigBlockSize">the poifs bigBlockSize</param> /// <param name="entries">the array of int entries</param> /// <returns>the newly created array of BATBlocks</returns> public static BATBlock[] CreateBATBlocks(POIFSBigBlockSize bigBlockSize, int[] entries) { int block_count = CalculateStorageRequirements(entries.Length); BATBlock[] blocks = new BATBlock[block_count]; int index = 0; int remaining = entries.Length; for (int j = 0; j < entries.Length; j += _entries_per_block) { blocks[index++] = new BATBlock(bigBlockSize, entries, j, (remaining > _entries_per_block) ? j + _entries_per_block : entries.Length); remaining -= _entries_per_block; } return(blocks); }
public POIFSDocument(string name, POIFSBigBlockSize bigBlockSize, ListManagedBlock[] blocks, int length) { _size = length; _bigBigBlockSize = bigBlockSize; _property = new DocumentProperty(name, _size); _property.Document = this; if (Property.IsSmall(_size)) { _big_store = new BigBlockStore(bigBlockSize, EMPTY_BIG_BLOCK_ARRAY); _small_store = new SmallBlockStore(bigBlockSize, ConvertRawBlocksToSmallBlocks(blocks)); } else { _big_store = new BigBlockStore(bigBlockSize, ConvertRawBlocksToBigBlocks(blocks)); _small_store = new SmallBlockStore(bigBlockSize, EMPTY_SMALL_BLOCK_ARRAY); } }
public POIFSDocument(string name, RawDataBlock[] blocks, int length) { _size = length; if (blocks.Length == 0) { _bigBigBlockSize = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; } else { _bigBigBlockSize = (blocks[0].BigBlockSize == POIFSConstants.SMALLER_BIG_BLOCK_SIZE ? POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS : POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS); } _big_store = new BigBlockStore(_bigBigBlockSize, ConvertRawBlocksToBigBlocks(blocks)); _property = new DocumentProperty(name, _size); _small_store = new SmallBlockStore(_bigBigBlockSize, EMPTY_SMALL_BLOCK_ARRAY); _property.Document = this; }
/// <summary> /// Create a OPOIFSFileSystem from an Stream. Normally the stream is Read until /// EOF. The stream is always Closed. In the unlikely case that the caller has such a stream and /// needs to use it after this constructor completes, a work around is to wrap the /// stream in order to trap the Close() call. /// </summary> /// <param name="stream">the Streamfrom which to Read the data</param> public OPOIFSFileSystem(Stream stream) : this() { bool success = false; HeaderBlock header_block_reader; RawDataBlockList data_blocks; try { // Read the header block from the stream header_block_reader = new HeaderBlock(stream); bigBlockSize = header_block_reader.BigBlockSize; // Read the rest of the stream into blocks data_blocks = new RawDataBlockList(stream, bigBlockSize); success = true; } finally { CloseInputStream(stream, success); } // Set up the block allocation table (necessary for the // data_blocks to be manageable new BlockAllocationTableReader(header_block_reader.BigBlockSize, header_block_reader.BATCount, header_block_reader.BATArray, header_block_reader.XBATCount, header_block_reader.XBATIndex, data_blocks); // Get property table from the document PropertyTable properties = new PropertyTable(header_block_reader, data_blocks); // init documents ProcessProperties(SmallBlockTableReader.GetSmallDocumentBlocks(bigBlockSize, data_blocks, properties.Root, header_block_reader.SBATStart), data_blocks, properties.Root.Children, null, header_block_reader.PropertyStart); // For whatever reason CLSID of root is always 0. Root.StorageClsid = (properties.Root.StorageClsid); }
public void Test4KBlocks() { Stream inp = _samples.OpenResourceAsStream("BlockSize4096.zvi"); try { // First up, check that we can process the header properly HeaderBlock header_block = new HeaderBlock(inp); POIFSBigBlockSize bigBlockSize = header_block.BigBlockSize; Assert.AreEqual(4096, bigBlockSize.GetBigBlockSize()); // Check the fat info looks sane Assert.AreEqual(1, header_block.BATArray.Length); Assert.AreEqual(1, header_block.BATCount); Assert.AreEqual(0, header_block.XBATCount); // Now check we can get the basic fat RawDataBlockList data_blocks = new RawDataBlockList(inp, bigBlockSize); Assert.AreEqual(15, data_blocks.BlockCount()); // Now try and open properly POIFSFileSystem fs = new POIFSFileSystem( _samples.OpenResourceAsStream("BlockSize4096.zvi") ); Assert.IsTrue(fs.Root.EntryCount > 3); // Check we can get at all the contents CheckAllDirectoryContents(fs.Root); // Finally, check we can do a similar 512byte one too fs = new POIFSFileSystem( _samples.OpenResourceAsStream("BlockSize512.zvi") ); Assert.IsTrue(fs.Root.EntryCount > 3); CheckAllDirectoryContents(fs.Root); } finally { inp.Close(); } }
/// <summary> /// Set BAT block parameters. Assumes that all BAT blocks are /// contiguous. Will construct XBAT blocks if necessary and return /// the array of newly constructed XBAT blocks. /// </summary> /// <param name="blockCount">count of BAT blocks</param> /// <param name="startBlock">index of first BAT block</param> /// <returns>array of XBAT blocks; may be zero Length, will not be /// null</returns> public BATBlock[] SetBATBlocks(int blockCount, int startBlock) { BATBlock[] rvalue; POIFSBigBlockSize bigBlockSize = _header_block.BigBlockSize; _header_block.BATCount = blockCount; int limit = Math.Min(blockCount, _max_bats_in_header); int[] bat_blocks = new int[limit]; for (int j = 0; j < limit; j++) { bat_blocks[j] = startBlock + j; } _header_block.BATArray = bat_blocks; if (blockCount > _max_bats_in_header) { int excess_blocks = blockCount - _max_bats_in_header; int[] excess_block_array = new int[excess_blocks]; for (int j = 0; j < excess_blocks; j++) { excess_block_array[j] = startBlock + j + _max_bats_in_header; } rvalue = BATBlock.CreateXBATBlocks(bigBlockSize, excess_block_array, startBlock + blockCount); _header_block.XBATStart = startBlock + blockCount; } else { rvalue = BATBlock.CreateXBATBlocks(bigBlockSize, new int[0], 0); _header_block.XBATStart = POIFSConstants.END_OF_CHAIN; } _header_block.XBATCount = rvalue.Length; return(rvalue); }