/** * 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)); }
public void TestGetFreeBlockWithNoneSpare() { NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.OpenResourceAsStream("BlockSize512.zvi")); int free; Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, fs.GetNextBlock(99)); assertBATCount(fs, 1, 0); for (int i = 100; i < 128; i++) Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(i)); Assert.AreEqual(true, fs.GetBATBlockAndIndex(0).Block.HasFreeSectors); for (int i = 100; i < 128; i++) fs.SetNextBlock(i, POIFSConstants.END_OF_CHAIN); Assert.AreEqual(false, fs.GetBATBlockAndIndex(0).Block.HasFreeSectors); try { Assert.AreEqual(false, fs.GetBATBlockAndIndex(128).Block.HasFreeSectors); Assert.Fail("Should only be one BAT"); } //catch (IndexOutOfRangeException) catch (ArgumentOutOfRangeException) { } assertBATCount(fs, 1, 0); // Now ask for a free one, will need to extend the file Assert.AreEqual(129, fs.GetFreeBlock()); Assert.AreEqual(false, fs.GetBATBlockAndIndex(0).Block.HasFreeSectors); Assert.AreEqual(true, fs.GetBATBlockAndIndex(128).Block.HasFreeSectors); Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, fs.GetNextBlock(128)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(129)); // We now have 2 BATs, but no XBATs assertBATCount(fs, 2, 0); // Fill up to hold 109 BAT blocks for (int i = 0; i < 109; i++) { fs.GetFreeBlock(); int startOffset = i * 128; while (fs.GetBATBlockAndIndex(startOffset).Block.HasFreeSectors) { free = fs.GetFreeBlock(); fs.SetNextBlock(free, POIFSConstants.END_OF_CHAIN); } } Assert.AreEqual(false, fs.GetBATBlockAndIndex(109 * 128 - 1).Block.HasFreeSectors); try { Assert.AreEqual(false, fs.GetBATBlockAndIndex(109 * 128).Block.HasFreeSectors); Assert.Fail("Should only be 109 BATs"); } // catch (IndexOutOfRangeException) catch (ArgumentOutOfRangeException) { } // We now have 109 BATs, but no XBATs assertBATCount(fs, 109, 0); // Ask for it to be written out, and check the header HeaderBlock header = WriteOutAndReadHeader(fs); Assert.AreEqual(109, header.BATCount); Assert.AreEqual(0, header.XBATCount); free = fs.GetFreeBlock(); Assert.AreEqual(false, fs.GetBATBlockAndIndex(109 * 128 - 1).Block.HasFreeSectors); Assert.AreEqual(true, fs.GetBATBlockAndIndex(110 * 128 - 1).Block.HasFreeSectors); try { Assert.AreEqual(false, fs.GetBATBlockAndIndex(110 * 128).Block.HasFreeSectors); Assert.Fail("Should only be 110 BATs"); } //catch (IndexOutOfRangeException) catch (ArgumentOutOfRangeException) { } assertBATCount(fs, 110, 1); header = WriteOutAndReadHeader(fs); Assert.AreEqual(110, header.BATCount); Assert.AreEqual(1, header.XBATCount); for (int i = 109; i < 109 + 127; i++) { fs.GetFreeBlock(); int startOffset = i * 128; while (fs.GetBATBlockAndIndex(startOffset).Block.HasFreeSectors) { free = fs.GetFreeBlock(); fs.SetNextBlock(free, POIFSConstants.END_OF_CHAIN); } assertBATCount(fs, i + 1, 1); } // Should now have 109+127 = 236 BATs Assert.AreEqual(false, fs.GetBATBlockAndIndex(236 * 128 - 1).Block.HasFreeSectors); try { Assert.AreEqual(false, fs.GetBATBlockAndIndex(236 * 128).Block.HasFreeSectors); Assert.Fail("Should only be 236 BATs"); } catch (ArgumentOutOfRangeException) { } assertBATCount(fs, 236, 1); // Ask for another, will get our 2nd XBAT free = fs.GetFreeBlock(); Assert.AreEqual(false, fs.GetBATBlockAndIndex(236 * 128 - 1).Block.HasFreeSectors); Assert.AreEqual(true, fs.GetBATBlockAndIndex(237 * 128 - 1).Block.HasFreeSectors); try { Assert.AreEqual(false, fs.GetBATBlockAndIndex(237 * 128).Block.HasFreeSectors); Assert.Fail("Should only be 237 BATs"); } // catch (IndexOutOfRangeException) { } catch (ArgumentOutOfRangeException) { } // Check the counts now assertBATCount(fs, 237, 2); // Check the header header = WriteOutAndReadHeader(fs); // Now, write it out, and read it back in again fully fs = WriteOutAndReadBack(fs); // Check that it is seen correctly assertBATCount(fs, 237, 2); Assert.AreEqual(false, fs.GetBATBlockAndIndex(236 * 128 - 1).Block.HasFreeSectors); Assert.AreEqual(true, fs.GetBATBlockAndIndex(237 * 128 - 1).Block.HasFreeSectors); try { Assert.AreEqual(false, fs.GetBATBlockAndIndex(237 * 128).Block.HasFreeSectors); Assert.Fail("Should only be 237 BATs"); } catch (ArgumentOutOfRangeException) { } fs.Close(); }
public void TestGetFreeBlockWithSpare() { NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.GetFile("BlockSize512.zvi")); Assert.AreEqual(true, fs.GetBATBlockAndIndex(0).Block.HasFreeSectors); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(100)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(101)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(102)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(103)); Assert.AreEqual(100, fs.GetFreeBlock()); Assert.AreEqual(100, fs.GetFreeBlock()); fs.SetNextBlock(100, POIFSConstants.END_OF_CHAIN); Assert.AreEqual(101, fs.GetFreeBlock()); fs.Close(); }
public void TestWriteFailsOnLoop() { NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.GetFile("BlockSize512.zvi")); // Hack the FAT so that it goes 0->1->2->0 fs.SetNextBlock(0, 1); fs.SetNextBlock(1, 2); fs.SetNextBlock(2, 0); // Try to write a large amount, should fail on the write byte[] data = new byte[512 * 4]; NPOIFSStream stream = new NPOIFSStream(fs, 0); try { stream.UpdateContents(data); Assert.Fail("Loop should have been detected but wasn't!"); } catch (Exception) { } // Now reset, and try on a small bit // Should fail during the freeing set fs.SetNextBlock(0, 1); fs.SetNextBlock(1, 2); fs.SetNextBlock(2, 0); data = new byte[512]; stream = new NPOIFSStream(fs, 0); try { stream.UpdateContents(data); Assert.Fail("Loop should have been detected but wasn't!"); } catch (Exception) { } fs.Close(); }
public void TestWriteNewStreamExtraFATs() { NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.OpenResourceAsStream("BlockSize512.zvi")); // Allocate almost all the blocks Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, fs.GetNextBlock(99)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(100)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(127)); for (int i = 100; i < 127; i++) { fs.SetNextBlock(i, POIFSConstants.END_OF_CHAIN); } Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(127)); Assert.AreEqual(true, fs.GetBATBlockAndIndex(0).Block.HasFreeSectors); // Write a 3 block stream byte[] data = new byte[512 * 3]; for (int i = 0; i < data.Length; i++) { data[i] = (byte)(i % 256); } NPOIFSStream stream = new NPOIFSStream(fs); stream.UpdateContents(data); // Check we got another BAT Assert.AreEqual(false, fs.GetBATBlockAndIndex(0).Block.HasFreeSectors); Assert.AreEqual(true, fs.GetBATBlockAndIndex(128).Block.HasFreeSectors); // the BAT will be in the first spot of the new block Assert.AreEqual(POIFSConstants.END_OF_CHAIN, fs.GetNextBlock(126)); Assert.AreEqual(129, fs.GetNextBlock(127)); Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, fs.GetNextBlock(128)); Assert.AreEqual(130, fs.GetNextBlock(129)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, fs.GetNextBlock(130)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, fs.GetNextBlock(131)); fs.Close(); }
public void TestReadFailsOnLoop() { NPOIFSFileSystem fs = new NPOIFSFileSystem(_inst.GetFile("BlockSize512.zvi")); // Hack the FAT so that it goes 0->1->2->0 fs.SetNextBlock(0, 1); fs.SetNextBlock(1, 2); fs.SetNextBlock(2, 0); // Now try to read NPOIFSStream stream = new NPOIFSStream(fs, 0); IEnumerator<ByteBuffer> i = stream.GetBlockIterator(); //1st read works Assert.AreEqual(true, i.MoveNext()); // 1st read works // i.MoveNext(); // 2nd read works Assert.AreEqual(true, i.MoveNext()); // i.MoveNext(); // Assert.AreEqual(true, i.MoveNext()); // 3rd read works //i.MoveNext(); Assert.AreEqual(true, i.MoveNext()); // 4th read blows up as it loops back to 0 try { i.MoveNext(); Assert.Fail("Loop should have been detected but wasn't!"); } catch (Exception) { // Good, it was detected } //Assert.AreEqual(true, i.MoveNext()); fs.Close(); }