/// <summary> /// Initializes a new instance of the <see cref="SmallBlockTableWriter"/> class. /// </summary> /// <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); }
public NPropertyTable(HeaderBlock headerBlock, NPOIFSFileSystem fileSystem) :base(headerBlock, BuildProperties( (new NPOIFSStream(fileSystem, headerBlock.PropertyStart)).GetEnumerator(),headerBlock.BigBlockSize) ) { _bigBigBlockSize = headerBlock.BigBlockSize; }
/// <summary> /// Create a single instance initialized with default values /// </summary> /// <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="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> /// 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()); }
// private static List<Property> BuildProperties(IEnumerator<byte[]> dataSource, POIFSBigBlockSize bigBlockSize) private static List<Property> BuildProperties(IEnumerator<ByteBuffer> dataSource, POIFSBigBlockSize bigBlockSize) { try { List<Property> properties = new List<Property>(); while(dataSource.MoveNext()) { ByteBuffer bb = dataSource.Current; //byte[] bb = (byte[])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()]; //bb.get(data, 0, data.length); bb.Read(data, 0, data.Length); } //} //data = new byte[bigBlockSize.GetBigBlockSize()]; //System.Array.Copy(bb, data, bb.Length); PropertyFactory.ConvertToProperties(data, properties); } return properties; } catch(System.IO.IOException ex) { throw ex; } }
/// <summary> /// Create an array of PropertyBlocks from an array of Property /// instances, creating empty Property instances to make up any /// shortfall /// </summary> /// <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; }
///** // * 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; }
/** * 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 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; }
/** * 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); } }
/** * 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 void SetXBATChain(POIFSBigBlockSize bigBlockSize, int chainIndex) { int _entries_per_xbat_block = bigBlockSize.GetXBATEntriesPerBlock(); _values[_entries_per_xbat_block] = chainIndex; }
public HeaderBlock(POIFSBigBlockSize bigBlockSize) { this.bigBlockSize = bigBlockSize; _data = new byte[POIFSConstants.SMALLER_BIG_BLOCK_SIZE]; //fill the array. for (int i = 0; i < _data.Length; i++) _data[i] = _default_value; 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((int)0x18, (short)0x3b, ref _data); new ShortField((int)0x1a, (short)0x3, ref _data); new ShortField((int)0x1c, (short)-2, ref _data); new ShortField(0x1e, bigBlockSize.GetHeaderValue(), ref _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); _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; }
/// <summary> /// Create an array of BATBlocks from an array of int block /// allocation table entries /// </summary> /// <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 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 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); }
public NPropertyTable(HeaderBlock headerBlock) : base(headerBlock) { _bigBigBlockSize = headerBlock.BigBlockSize; }
/// <summary> /// For a given number of BAT blocks, calculate how many XBAT /// blocks will be needed /// </summary> /// <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; }
/// <summary> /// create a new HeaderBlockReader from an Stream /// </summary> /// <param name="stream">the source Stream</param> public HeaderBlockReader(Stream stream) { stream.Position = 0; this._data = ReadFirst512(stream); // verify signature long signature = LittleEndian.GetLong(_data, HeaderBlockConstants._signature_offset); if (signature != HeaderBlockConstants._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. POI only supports OLE2 Office documents"); } if ((signature & unchecked((long)0xFF8FFFFFFFFFFFFFL)) == 0x0010000200040009L) { // BIFF2 raw stream starts with BOF (sid=0x0009, size=0x0004, data=0x00t0) throw new ArgumentException("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(HeaderBlockConstants._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(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; // 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 HeaderBlockWriter(POIFSBigBlockSize bigBlockSize) { _header_block = new HeaderBlock(bigBlockSize); }
/// <summary> /// Create an array of XBATBlocks from an array of int block /// allocation table entries /// </summary> /// <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; }
/** * Default constructor */ public PropertyTable(HeaderBlock headerBlock) : base(headerBlock) { _bigBigBlockSize = headerBlock.BigBlockSize; _blocks = null; }
/** * 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 int CalculateMaximumSize(POIFSBigBlockSize bigBlockSize, int numBATs) { int 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 DocumentBlock(POIFSBigBlockSize bigBlockSize) :base(bigBlockSize) { _data = new byte[POIFSConstants.BIG_BLOCK_SIZE]; Arrays.Fill(_data, _default_value); }
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"); } throw new IOException("Invalid header signature; read " + LongToHex(signature) + ", expected " + LongToHex(_signature)); } 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; }
protected BigBlock(POIFSBigBlockSize bigBlockSize) { this.bigBlockSize = bigBlockSize; }
/// <summary> /// Create a single instance initialized with data. /// </summary> /// <param name="stream">the InputStream delivering the data.</param> public DocumentBlock(Stream stream, POIFSBigBlockSize bigBlockSize) : this(bigBlockSize) { int count = IOUtils.ReadFully(stream, _data); _bytes_Read = (count == -1) ? 0: count; }