/// <summary> /// convert a single long array into an array of SmallDocumentBlock /// instances /// </summary> /// <param name="bigBlockSize">the poifs bigBlockSize</param> /// <param name="array">the byte array to be converted</param> /// <param name="size">the intended size of the array (which may be smaller)</param> /// <returns>an array of SmallDocumentBlock instances, filled from /// the array</returns> public static SmallDocumentBlock [] Convert(POIFSBigBlockSize bigBlockSize, byte [] array, int size) { SmallDocumentBlock[] rval = new SmallDocumentBlock[ (size + _block_size - 1) / _block_size ]; int offset = 0; for (int k = 0; k < rval.Length; k++) { rval[ k ] = new SmallDocumentBlock(bigBlockSize); if (offset < array.Length) { int length = Math.Min(_block_size, array.Length - offset); Array.Copy(array, offset, rval[ k ]._data, 0, length); if (length != _block_size) { for (int i = length; i < _block_size; i++) rval[k]._data[i] = _default_fill; } } else { for (int j = 0; j < rval[k]._data.Length; j++) { rval[k]._data[j] = _default_fill; } } offset += _block_size; } return rval; }
private static List<Property> BuildProperties(IEnumerator<ByteBuffer> dataSource, POIFSBigBlockSize bigBlockSize) { List<Property> properties = new List<Property>(); while(dataSource.MoveNext()) { ByteBuffer bb = dataSource.Current; // Turn it into an array byte[] data; if (bb.HasBuffer && bb.Offset == 0 && bb.Buffer.Length == bigBlockSize.GetBigBlockSize()) { data = bb.Buffer; } else { data = new byte[bigBlockSize.GetBigBlockSize()]; int toRead = data.Length; if (bb.Remaining() < bigBlockSize.GetBigBlockSize()) { // Looks to be a truncated block // This isn't allowed, but some third party created files // sometimes do this, and we can normally read anyway toRead = bb.Remaining(); } bb.Read(data, 0, toRead); } PropertyFactory.ConvertToProperties(data, properties); } return properties; }
/// <summary> /// Initializes a new instance of the <see cref="SmallBlockTableWriter"/> class. /// </summary> /// <param name="bigBlockSize">the poifs bigBlockSize</param> /// <param name="documents">a IList of POIFSDocument instances</param> /// <param name="root">the Filesystem's root property</param> public SmallBlockTableWriter(POIFSBigBlockSize bigBlockSize, IList documents, RootProperty root) { _sbat = new BlockAllocationTableWriter(bigBlockSize); _small_blocks = new ArrayList(); _root = root; IEnumerator iter = documents.GetEnumerator(); while (iter.MoveNext()) { POIFSDocument doc = ( POIFSDocument ) iter.Current; BlockWritable[] blocks = doc.SmallBlocks; if (blocks.Length != 0) { doc.StartBlock=_sbat.AllocateSpace(blocks.Length); for (int j = 0; j < blocks.Length; j++) { _small_blocks.Add(blocks[ j ]); } } else { doc.StartBlock=POIFSConstants.END_OF_CHAIN; } } _sbat.SimpleCreateBlocks(); _root.Size=_small_blocks.Count; _big_block_count = SmallDocumentBlock.Fill(bigBlockSize, _small_blocks); }
/// <summary> /// Initializes a new instance of the <see cref="BlockAllocationTableWriter"/> class. /// </summary> public BlockAllocationTableWriter(POIFSBigBlockSize bigBlockSize) { _start_block = POIFSConstants.END_OF_CHAIN; _entries = new List<int>(_default_size); _blocks = new BATBlock[ 0 ]; _bigBlockSize = bigBlockSize; }
public NPropertyTable(HeaderBlock headerBlock, NPOIFSFileSystem fileSystem) :base(headerBlock, BuildProperties( (new NPOIFSStream(fileSystem, headerBlock.PropertyStart)).GetEnumerator(),headerBlock.BigBlockSize) ) { _bigBigBlockSize = headerBlock.BigBlockSize; }
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); }
/// <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 ]; } }
/** * reading constructor (used when we've read in a file and we want * to extract the property table from it). Populates the * properties thoroughly * * @param startBlock the first block of the property table * @param blockList the list of blocks * * @exception IOException if anything goes wrong (which should be * a result of the input being NFG) */ public PropertyTable(HeaderBlock headerBlock, RawDataBlockList blockList) : base(headerBlock, PropertyFactory.ConvertToProperties( blockList.FetchBlocks(headerBlock.PropertyStart, -1) ) ) { _bigBigBlockSize = headerBlock.BigBlockSize; _blocks = null; }
/// <summary> /// fetch the small document block list from an existing file /// </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 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; }
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> /// Initializes a new instance of the <see cref="RawDataBlockList"/> class. /// </summary> /// <param name="stream">the InputStream from which the data will be read</param> /// <param name="bigBlockSize">The big block size, either 512 bytes or 4096 bytes</param> public RawDataBlockList(Stream stream, POIFSBigBlockSize bigBlockSize) { List<RawDataBlock> blocks = new List<RawDataBlock>(); while (true) { RawDataBlock block = new RawDataBlock(stream, bigBlockSize.GetBigBlockSize()); // If there was data, add the block to the list if(block.HasData) { blocks.Add(block); } // If the stream is now at the End Of File, we're done if (block.EOF) { break; } } SetBlocks((ListManagedBlock[])blocks.ToArray()); }
/// <summary> /// Create an array of PropertyBlocks from an array of Property /// instances, creating empty Property instances to make up any /// shortfall /// </summary> /// <param name="bigBlockSize"></param> /// <param name="properties">the Property instances to be converted into PropertyBlocks, in a java List</param> /// <returns>the array of newly created PropertyBlock instances</returns> public static BlockWritable [] CreatePropertyBlockArray( POIFSBigBlockSize bigBlockSize, List<Property> properties) { int _properties_per_block = bigBlockSize.GetPropertiesPerBlock(); int blockCount = (properties.Count + _properties_per_block - 1) / _properties_per_block; Property[] toBeWritten = new Property[blockCount * _properties_per_block]; System.Array.Copy(properties.ToArray(), 0, toBeWritten, 0, properties.Count); for (int i = properties.Count; i < toBeWritten.Length; i++) { toBeWritten[i] = new AnonymousProperty(); } BlockWritable[] rvalue = new BlockWritable[blockCount]; for (int i = 0; i < blockCount; i++) rvalue[i] = new PropertyBlock(bigBlockSize, toBeWritten, i * _properties_per_block); return rvalue; }
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; }
private void SetXBATChain(POIFSBigBlockSize bigBlockSize, int chainIndex) { int _entries_per_xbat_block = bigBlockSize.GetXBATEntriesPerBlock(); _values[_entries_per_xbat_block] = chainIndex; }
/** * 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(); }
public static int CalculateXBATStorageRequirements(POIFSBigBlockSize bigBlockSize, int entryCount) { int _entries_per_xbat_block = bigBlockSize.GetXBATEntriesPerBlock(); return (entryCount + _entries_per_xbat_block - 1) / _entries_per_xbat_block; }
/// <summary> /// Create an array of XBATBlocks from an array of int block /// allocation table entries /// </summary> /// <param name="bigBlockSize"></param> /// <param name="entries">the array of int entries</param> /// <param name="startBlock">the start block of the array of XBAT blocks</param> /// <returns>the newly created array of BATBlocks</returns> public static BATBlock[] CreateXBATBlocks(POIFSBigBlockSize bigBlockSize, int[] entries, int startBlock) { int block_count = CalculateXBATStorageRequirements(entries.Length); BATBlock[] blocks = new BATBlock[block_count]; int index = 0; int remaining = entries.Length; if (block_count != 0) { for (int j = 0; j < entries.Length; j += _entries_per_xbat_block) { blocks[index++] = new BATBlock(bigBlockSize, entries, j, (remaining > _entries_per_xbat_block) ? j + _entries_per_xbat_block : entries.Length); remaining -= _entries_per_xbat_block; } for (index = 0; index < blocks.Length - 1; index++) { blocks[index].SetXBATChain(bigBlockSize, startBlock + index + 1); } blocks[index].SetXBATChain(bigBlockSize, POIFSConstants.END_OF_CHAIN); } return blocks; }
/// <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; }
private static int GetBlocksPerBigBlock(POIFSBigBlockSize bigBlockSize) { return bigBlockSize.GetBigBlockSize()/_block_size; }
/// <summary> /// Initializes a new instance of the <see cref="BlockAllocationTableReader"/> class. /// </summary> public BlockAllocationTableReader(POIFSBigBlockSize bigBlockSize) { this.bigBlockSize = bigBlockSize; _entries = new List<int>(); }
public HeaderBlockWriter(POIFSBigBlockSize bigBlockSize) { _header_block = new HeaderBlock(bigBlockSize); }
/// <summary> /// Create a POIFSFileSystem 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 POIFSFileSystem(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); }
/** * 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(); } }
public SmallDocumentBlock(POIFSBigBlockSize bigBlockSize) { _bigBlockSize = bigBlockSize; _blocks_per_big_block = GetBlocksPerBigBlock(bigBlockSize); _data = new byte[_block_size]; }
/// <summary> /// For a given number of BAT blocks, calculate how many XBAT /// blocks will be needed /// </summary> /// <param name="bigBlockSize"></param> /// <param name="blockCount">number of BAT blocks</param> /// <returns>number of XBAT blocks needed</returns> public static int CalculateXBATStorageRequirements(POIFSBigBlockSize bigBlockSize, int blockCount) { return (blockCount > _max_bats_in_header) ? BATBlock.CalculateXBATStorageRequirements(bigBlockSize, blockCount - _max_bats_in_header) : 0; }
/** * 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; }
/// <summary> /// create a BlockAllocationTableReader from an array of raw data blocks /// </summary> /// <param name="bigBlockSize"></param> /// <param name="blocks">the raw data</param> /// <param name="raw_block_list">the list holding the managed blocks</param> public BlockAllocationTableReader(POIFSBigBlockSize bigBlockSize, ListManagedBlock[] blocks, BlockList raw_block_list) : this(bigBlockSize) { SetEntries(blocks, raw_block_list); }
//public static BATBlock CreateBATBlock(POIFSBigBlockSize bigBlockSize, byte[] data) public static BATBlock CreateBATBlock(POIFSBigBlockSize bigBlockSize, ByteBuffer data) { // Create an empty block BATBlock block = new BATBlock(bigBlockSize); // Fill it byte[] buffer = new byte[LittleEndianConsts.INT_SIZE]; //int index = 0; for (int i = 0; i < block._values.Length; i++) { //data.Read(buffer, 0, buffer.Length); //for (int j = 0; j < buffer.Length; j++, index++) // buffer[j] = data[index]; data.Read(buffer); block._values[i] = LittleEndian.GetInt(buffer); } block.RecomputeFree(); // All done return block; }
/// <summary> /// create a BlockAllocationTableReader for an existing filesystem. Side /// effect: when this method finishes, the BAT blocks will have /// been Removed from the raw block list, and any blocks labeled as /// 'unused' in the block allocation table will also have been /// Removed from the raw block list. </summary> /// <param name="bigBlockSizse">the poifs bigBlockSize</param> /// <param name="block_count">the number of BAT blocks making up the block allocation table</param> /// <param name="block_array">the array of BAT block indices from the /// filesystem's header</param> /// <param name="xbat_count">the number of XBAT blocks</param> /// <param name="xbat_index">the index of the first XBAT block</param> /// <param name="raw_block_list">the list of RawDataBlocks</param> public BlockAllocationTableReader(POIFSBigBlockSize bigBlockSizse, int block_count, int[] block_array, int xbat_count, int xbat_index, BlockList raw_block_list) : this(bigBlockSizse) { SanityCheckBlockCount(block_count); RawDataBlock[] blocks = new RawDataBlock[block_count]; int limit = Math.Min(block_count, block_array.Length); int block_index; for (block_index = 0; block_index < limit; block_index++) { int nextOffset = block_array[block_index]; if (nextOffset > raw_block_list.BlockCount()) { throw new IOException("Your file contains " + raw_block_list.BlockCount() + " sectors, but the initial DIFAT array at index " + block_index + " referenced block # " + nextOffset + ". This isn't allowed and " + " your file is corrupt"); } blocks[block_index] = (RawDataBlock)raw_block_list.Remove(nextOffset); } if (block_index < block_count) { // must have extended blocks if (xbat_index < 0) { throw new IOException( "BAT count exceeds limit, yet XBAT index indicates no valid entries"); } int chain_index = xbat_index; int max_entries_per_block = BATBlock.EntriesPerXBATBlock; int chain_index_offset = BATBlock.XBATChainOffset; // Each XBAT block contains either: // (maximum number of sector indexes) + index of next XBAT // some sector indexes + FREE sectors to max # + EndOfChain for (int j = 0; j < xbat_count; j++) { limit = Math.Min(block_count - block_index, max_entries_per_block); byte[] data = raw_block_list.Remove(chain_index).Data; int offset = 0; for (int k = 0; k < limit; k++) { blocks[block_index++] = (RawDataBlock)raw_block_list.Remove(LittleEndian.GetInt(data, offset)); offset += LittleEndianConsts.INT_SIZE; } chain_index = LittleEndian.GetInt(data, chain_index_offset); if (chain_index == POIFSConstants.END_OF_CHAIN) { break; } } } if (block_index != block_count) { throw new IOException("Could not find all blocks"); } // now that we have all of the raw data blocks, go through and // create the indices SetEntries((ListManagedBlock[])blocks, raw_block_list); }
///** // * 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; }