/** * 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) { _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); }