protected void CreateBlockIfNeeded() { if (buffer != null && buffer.HasRemaining()) { return; } int thisBlock = nextBlock; // Allocate a block if needed, otherwise figure // out what the next block will be if (thisBlock == POIFSConstants.END_OF_CHAIN) { thisBlock = pStream.blockStore.GetFreeBlock(); loopDetector.Claim(thisBlock); // We're on the end of the chain nextBlock = POIFSConstants.END_OF_CHAIN; // Mark the previous block as carrying on to us if needed if (prevBlock != POIFSConstants.END_OF_CHAIN) { pStream.blockStore.SetNextBlock(prevBlock, thisBlock); } pStream.blockStore.SetNextBlock(thisBlock, POIFSConstants.END_OF_CHAIN); // If we've just written the first block on a // new stream, save the start block offset if (pStream.startBlock == POIFSConstants.END_OF_CHAIN) { pStream.startBlock = thisBlock; } } else { loopDetector.Claim(thisBlock); nextBlock = pStream.blockStore.GetNextBlock(thisBlock); } buffer = pStream.blockStore.CreateBlockIfNeeded(thisBlock); // Update pointers prevBlock = thisBlock; }
/** * Load the block, extending the underlying stream if needed */ public override ByteBuffer CreateBlockIfNeeded(int offset) { bool firstInStore = false; // If we are the first block to be allocated, initialise the stream if (_mini_stream.GetStartBlock() == POIFSConstants.END_OF_CHAIN) { firstInStore = true; } // Try to Get it without extending the stream if (!firstInStore) { try { return(GetBlockAt(offset)); } catch (IndexOutOfRangeException) { } } // Need to extend the stream // TODO Replace this with proper append support // For now, do the extending by hand... // Ask for another block int newBigBlock = _filesystem.GetFreeBlock(); _filesystem.CreateBlockIfNeeded(newBigBlock); // If we are the first block to be allocated, initialise the stream if (firstInStore) { _filesystem.PropertyTable.Root.StartBlock = (newBigBlock); _mini_stream = new NPOIFSStream(_filesystem, newBigBlock); } else { // Tack it onto the end of our chain ChainLoopDetector loopDetector = _filesystem.GetChainLoopDetector(); int block = _mini_stream.GetStartBlock(); while (true) { loopDetector.Claim(block); int next = _filesystem.GetNextBlock(block); if (next == POIFSConstants.END_OF_CHAIN) { break; } block = next; } _filesystem.SetNextBlock(block, newBigBlock); } _filesystem.SetNextBlock(newBigBlock, POIFSConstants.END_OF_CHAIN); // Now try again, to get the real small block return(CreateBlockIfNeeded(offset)); }
private void ReadBAT(int batAt, ChainLoopDetector loopDetector) { loopDetector.Claim(batAt); ByteBuffer fatData = GetBlockAt(batAt); // byte[] fatData = GetBlockAt(batAt); BATBlock bat = BATBlock.CreateBATBlock(bigBlockSize, fatData); bat.OurBlockIndex = batAt; _bat_blocks.Add(bat); }
public ByteBuffer Next() { if (nextBlock == POIFSConstants.END_OF_CHAIN) { throw new IndexOutOfRangeException("Can't read past the end of the stream"); } try { loopDetector.Claim(nextBlock); //byte[] data = blockStore.GetBlockAt(nextBlock); ByteBuffer data = pStream.blockStore.GetBlockAt(nextBlock); nextBlock = pStream.blockStore.GetNextBlock(nextBlock); return(data); } catch (IOException e) { throw new RuntimeException(e.Message); } }
internal void Free(ChainLoopDetector loopDetector) { int nextBlock = startBlock; while (nextBlock != POIFSConstants.END_OF_CHAIN) { int thisBlock = nextBlock; loopDetector.Claim(thisBlock); nextBlock = blockStore.GetNextBlock(thisBlock); blockStore.SetNextBlock(thisBlock, POIFSConstants.UNUSED_BLOCK); } startBlock = POIFSConstants.END_OF_CHAIN; }
/** * 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); } // Work out how many FAT blocks remain in the XFATs int remainingFATs = _header.BATCount - _header.BATArray.Length; // 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); // Process all the (used) FATs from this XFAT int xbatFATs = Math.Min(remainingFATs, bigBlockSize.GetXBATEntriesPerBlock()); for (int j = 0; j < xbatFATs; j++) { int fatAt = xfat.GetValueAt(j); if (fatAt == POIFSConstants.UNUSED_BLOCK || fatAt == POIFSConstants.END_OF_CHAIN) { break; } ReadBAT(fatAt, loopDetector); } remainingFATs -= xbatFATs; } // 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); } }
/** * Finds a free block, and returns its offset. * This method will extend the file if needed, and if doing * so, allocate new FAT blocks to Address the extra space. */ public override int GetFreeBlock() { int sectorsPerSBAT = _filesystem.GetBigBlockSizeDetails().GetBATEntriesPerBlock(); // First up, do we have any spare ones? int offset = 0; for (int i = 0; i < _sbat_blocks.Count; i++) { // Check this one BATBlock sbat = _sbat_blocks[i]; if (sbat.HasFreeSectors) { // Claim one of them and return it for (int j = 0; j < sectorsPerSBAT; j++) { int sbatValue = sbat.GetValueAt(j); if (sbatValue == POIFSConstants.UNUSED_BLOCK) { // Bingo return(offset + j); } } } // Move onto the next SBAT offset += sectorsPerSBAT; } // If we Get here, then there aren't any // free sectors in any of the SBATs // So, we need to extend the chain and add another // Create a new BATBlock BATBlock newSBAT = BATBlock.CreateEmptyBATBlock(_filesystem.GetBigBlockSizeDetails(), false); int batForSBAT = _filesystem.GetFreeBlock(); newSBAT.OurBlockIndex = batForSBAT; // Are we the first SBAT? if (_header.SBATCount == 0) { // Tell the header that we've got our first SBAT there _header.SBATStart = batForSBAT; _header.SBATBlockCount = 1; } else { // Find the end of the SBAT stream, and add the sbat in there ChainLoopDetector loopDetector = _filesystem.GetChainLoopDetector(); int batOffset = _header.SBATStart; while (true) { loopDetector.Claim(batOffset); int nextBat = _filesystem.GetNextBlock(batOffset); if (nextBat == POIFSConstants.END_OF_CHAIN) { break; } batOffset = nextBat; } // Add it in at the end _filesystem.SetNextBlock(batOffset, batForSBAT); // And update the count _header.SBATBlockCount = _header.SBATCount + 1; } // Finish allocating _filesystem.SetNextBlock(batForSBAT, POIFSConstants.END_OF_CHAIN); _sbat_blocks.Add(newSBAT); // Return our first spot return(offset); }