public void TestCreateBATBlocks() { // Test 0 Length array (basic sanity) BATBlock[] rvalue = BATBlock.CreateBATBlocks(CreateTestArray(0)); Assert.AreEqual(0, rvalue.Length); // Test array of Length 1 rvalue = BATBlock.CreateBATBlocks(CreateTestArray(1)); Assert.AreEqual(1, rvalue.Length); VerifyContents(rvalue, 1); // Test array of Length 127 rvalue = BATBlock.CreateBATBlocks(CreateTestArray(127)); Assert.AreEqual(1, rvalue.Length); VerifyContents(rvalue, 127); // Test array of Length 128 rvalue = BATBlock.CreateBATBlocks(CreateTestArray(128)); Assert.AreEqual(1, rvalue.Length); VerifyContents(rvalue, 128); // Test array of Length 129 rvalue = BATBlock.CreateBATBlocks(CreateTestArray(129)); Assert.AreEqual(2, rvalue.Length); VerifyContents(rvalue, 129); }
public void TestCreateXBATBlocks() { // Test 0 Length array (basic sanity) BATBlock[] rvalue = BATBlock.CreateXBATBlocks(CreateTestArray(0), 1); Assert.AreEqual(0, rvalue.Length); // Test array of Length 1 rvalue = BATBlock.CreateXBATBlocks(CreateTestArray(1), 1); Assert.AreEqual(1, rvalue.Length); verifyXBATContents(rvalue, 1, 1); // Test array of Length 127 rvalue = BATBlock.CreateXBATBlocks(CreateTestArray(127), 1); Assert.AreEqual(1, rvalue.Length); verifyXBATContents(rvalue, 127, 1); // Test array of Length 128 rvalue = BATBlock.CreateXBATBlocks(CreateTestArray(128), 1); Assert.AreEqual(2, rvalue.Length); verifyXBATContents(rvalue, 128, 1); // Test array of Length 254 rvalue = BATBlock.CreateXBATBlocks(CreateTestArray(254), 1); Assert.AreEqual(2, rvalue.Length); verifyXBATContents(rvalue, 254, 1); // Test array of Length 255 rvalue = BATBlock.CreateXBATBlocks(CreateTestArray(255), 1); Assert.AreEqual(3, rvalue.Length); verifyXBATContents(rvalue, 255, 1); }
/** * Create a POIFSFileSystem from an <tt>InputStream</tt>. Normally the stream is read until * EOF. The stream is always closed.<p/> * * Some streams are usable After reaching EOF (typically those that return <code>true</code> * for <tt>markSupported()</tt>). In the unlikely case that the caller has such a stream * <i>and</i> needs to use it After this constructor completes, a work around is to wrap the * stream in order to trap the <tt>close()</tt> call. A convenience method ( * <tt>CreateNonClosingInputStream()</tt>) has been provided for this purpose: * <pre> * InputStream wrappedStream = POIFSFileSystem.CreateNonClosingInputStream(is); * HSSFWorkbook wb = new HSSFWorkbook(wrappedStream); * is.Reset(); * doSomethingElse(is); * </pre> * Note also the special case of <tt>MemoryStream</tt> for which the <tt>close()</tt> * method does nothing. * <pre> * MemoryStream bais = ... * HSSFWorkbook wb = new HSSFWorkbook(bais); // calls bais.Close() ! * bais.Reset(); // no problem * doSomethingElse(bais); * </pre> * * @param stream the InputStream from which to read the data * * @exception IOException on errors Reading, or on invalid data */ public NPOIFSFileSystem(Stream stream) : this(false) { Stream channel = null; bool success = false; try { // Turn our InputStream into something NIO based channel = stream; // Get the header ByteBuffer headerBuffer = ByteBuffer.CreateBuffer(POIFSConstants.SMALLER_BIG_BLOCK_SIZE); IOUtils.ReadFully(channel, headerBuffer.Buffer); // Have the header Processed _header = new HeaderBlock(headerBuffer); // Sanity check the block count BlockAllocationTableReader.SanityCheckBlockCount(_header.BATCount); // We need to buffer the whole file into memory when // working with an InputStream. // The max possible size is when each BAT block entry is used int maxSize = BATBlock.CalculateMaximumSize(_header); //ByteBuffer data = ByteBuffer.allocate(maxSize); // byte[] data = new byte[maxSize]; //// Copy in the header //for(int i = 0; i < headerBuffer.Length; i++) //{ // data[i] = headerBuffer[i]; //} // byte[] temp = new byte[channel.Length]; // Now read the rest of the stream ByteBuffer data = ByteBuffer.CreateBuffer(maxSize); headerBuffer.Position = 0; data.Write(headerBuffer.Buffer); data.Position = headerBuffer.Length; //IOUtils.ReadFully(channel, data); data.Position += IOUtils.ReadFully(channel, data.Buffer, data.Position, (int)channel.Length); success = true; // Turn it into a DataSource _data = new ByteArrayBackedDataSource(data.Buffer, data.Position); } finally { // As per the constructor contract, always close the stream if (channel != null) { channel.Close(); } CloseInputStream(stream, success); } // Now process the various entries ReadCoreContents(); }
public void TestCreateBATBlocks() { // Test 0 Length array (basic sanity) BATBlock[] rvalue = BATBlock.CreateBATBlocks(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, CreateTestArray(0)); Assert.AreEqual(0, rvalue.Length); // Test array of Length 1 rvalue = BATBlock.CreateBATBlocks(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, CreateTestArray(1)); Assert.AreEqual(1, rvalue.Length); VerifyContents(rvalue, 1); // Test array of Length 127 rvalue = BATBlock.CreateBATBlocks(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, CreateTestArray(127)); Assert.AreEqual(1, rvalue.Length); VerifyContents(rvalue, 127); // Test array of Length 128 rvalue = BATBlock.CreateBATBlocks(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, CreateTestArray(128)); Assert.AreEqual(1, rvalue.Length); VerifyContents(rvalue, 128); // Test array of Length 129 rvalue = BATBlock.CreateBATBlocks(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, CreateTestArray(129)); Assert.AreEqual(2, rvalue.Length); VerifyContents(rvalue, 129); }
public void TestBATandXBAT() { byte[] hugeStream = new byte[8 * 1024 * 1024]; POIFSFileSystem fs = new POIFSFileSystem(); fs.Root.CreateDocument("BIG", new MemoryStream(hugeStream)); MemoryStream baos = new MemoryStream(); fs.WriteFileSystem(baos); byte[] fsData = baos.ToArray(); // Check the header was written properly Stream inp = new MemoryStream(fsData); HeaderBlock header = new HeaderBlock(inp); Assert.AreEqual(109 + 21, header.BATCount); Assert.AreEqual(1, header.XBATCount); ByteBuffer xbatData = ByteBuffer.CreateBuffer(512); xbatData.Write(fsData, (1 + header.XBATIndex) * 512, 512); xbatData.Position = 0; BATBlock xbat = BATBlock.CreateBATBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, xbatData); for (int i = 0; i < 21; i++) { Assert.IsTrue(xbat.GetValueAt(i) != POIFSConstants.UNUSED_BLOCK); } for (int i = 21; i < 127; i++) { Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, xbat.GetValueAt(i)); } Assert.AreEqual(POIFSConstants.END_OF_CHAIN, xbat.GetValueAt(127)); RawDataBlockList blockList = new RawDataBlockList(inp, POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); Assert.AreEqual(fsData.Length / 512, blockList.BlockCount() + 1); new BlockAllocationTableReader(header.BigBlockSize, header.BATCount, header.BATArray, header.XBATCount, header.XBATIndex, blockList); Assert.AreEqual(fsData.Length / 512, blockList.BlockCount() + 1); //fs = null; //fs = new POIFSFileSystem(new MemoryStream(fsData)); //DirectoryNode root = fs.Root; //Assert.AreEqual(1, root.EntryCount); //DocumentNode big = (DocumentNode)root.GetEntry("BIG"); //Assert.AreEqual(hugeStream.Length, big.Size); }
/** * 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); } }
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); }
/** * Create a POIFSFileSystem from an <tt>InputStream</tt>. Normally the stream is read until * EOF. The stream is always closed.<p/> * * Some streams are usable After reaching EOF (typically those that return <code>true</code> * for <tt>markSupported()</tt>). In the unlikely case that the caller has such a stream * <i>and</i> needs to use it After this constructor completes, a work around is to wrap the * stream in order to trap the <tt>close()</tt> call. A convenience method ( * <tt>CreateNonClosingInputStream()</tt>) has been provided for this purpose: * <pre> * InputStream wrappedStream = POIFSFileSystem.CreateNonClosingInputStream(is); * HSSFWorkbook wb = new HSSFWorkbook(wrappedStream); * is.Reset(); * doSomethingElse(is); * </pre> * Note also the special case of <tt>MemoryStream</tt> for which the <tt>close()</tt> * method does nothing. * <pre> * MemoryStream bais = ... * HSSFWorkbook wb = new HSSFWorkbook(bais); // calls bais.Close() ! * bais.Reset(); // no problem * doSomethingElse(bais); * </pre> * * @param stream the InputStream from which to read the data * * @exception IOException on errors Reading, or on invalid data */ public NPOIFSFileSystem(Stream stream) : this(false) { Stream channel = null; bool success = false; try { // Turn our InputStream into something NIO based channel = stream; // Get the header ByteBuffer headerBuffer = ByteBuffer.CreateBuffer(POIFSConstants.SMALLER_BIG_BLOCK_SIZE); IOUtils.ReadFully(channel, headerBuffer.Buffer); // Have the header Processed _header = new HeaderBlock(headerBuffer); // Sanity check the block count BlockAllocationTableReader.SanityCheckBlockCount(_header.BATCount); // We need to buffer the whole file into memory when // working with an InputStream. // The max possible size is when each BAT block entry is used long maxSize = BATBlock.CalculateMaximumSize(_header); if (maxSize > int.MaxValue) { throw new ArgumentException("Unable read a >2gb file via an InputStream"); } ByteBuffer data = ByteBuffer.CreateBuffer((int)maxSize); headerBuffer.Position = 0; data.Write(headerBuffer.Buffer); data.Position = headerBuffer.Length; //IOUtils.ReadFully(channel, data); data.Position += IOUtils.ReadFully(channel, data.Buffer, data.Position, (int)channel.Length); success = true; // Turn it into a DataSource _data = new ByteArrayBackedDataSource(data.Buffer, data.Position); } finally { // As per the constructor contract, always close the stream if (channel != null) { channel.Close(); channel.Dispose(); } CloseInputStream(stream, success); } // Now process the various entries ReadCoreContents(); }
public void TestUsedSectors() { POIFSBigBlockSize b512 = POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS; POIFSBigBlockSize b4096 = POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS; // Try first with 512 block sizes, which can hold 128 entries BATBlock block512 = BATBlock.CreateEmptyBATBlock(b512, false); Assert.AreEqual(true, block512.HasFreeSectors); Assert.AreEqual(0, block512.GetUsedSectors(false)); // Allocate a few block512.SetValueAt(0, 42); block512.SetValueAt(10, 42); block512.SetValueAt(20, 42); Assert.AreEqual(true, block512.HasFreeSectors); Assert.AreEqual(3, block512.GetUsedSectors(false)); // Allocate all for (int i = 0; i < b512.GetBATEntriesPerBlock(); i++) { block512.SetValueAt(i, 82); } // Check Assert.AreEqual(false, block512.HasFreeSectors); Assert.AreEqual(128, block512.GetUsedSectors(false)); Assert.AreEqual(127, block512.GetUsedSectors(true)); // Release one block512.SetValueAt(10, POIFSConstants.UNUSED_BLOCK); Assert.AreEqual(true, block512.HasFreeSectors); Assert.AreEqual(127, block512.GetUsedSectors(false)); Assert.AreEqual(126, block512.GetUsedSectors(true)); // Now repeat with 4096 block sizes BATBlock block4096 = BATBlock.CreateEmptyBATBlock(b4096, false); Assert.AreEqual(true, block4096.HasFreeSectors); Assert.AreEqual(0, block4096.GetUsedSectors(false)); block4096.SetValueAt(0, 42); block4096.SetValueAt(10, 42); block4096.SetValueAt(20, 42); Assert.AreEqual(true, block4096.HasFreeSectors); Assert.AreEqual(3, block4096.GetUsedSectors(false)); // Allocate all for (int i = 0; i < b4096.GetBATEntriesPerBlock(); i++) { block4096.SetValueAt(i, 82); } // Check Assert.AreEqual(false, block4096.HasFreeSectors); Assert.AreEqual(1024, block4096.GetUsedSectors(false)); Assert.AreEqual(1023, block4096.GetUsedSectors(true)); }
private BATBlock CreateBAT(int offset, bool isBAT) { // Create a new BATBlock BATBlock newBAT = BATBlock.CreateEmptyBATBlock(bigBlockSize, !isBAT); newBAT.OurBlockIndex = offset; // Ensure there's a spot in the file for it ByteBuffer buffer = ByteBuffer.CreateBuffer(bigBlockSize.GetBigBlockSize()); int WriteTo = (1 + offset) * bigBlockSize.GetBigBlockSize(); // Header isn't in BATs _data.Write(buffer, WriteTo); // All done return newBAT; }
/** * Constructor, intended for writing */ public NPOIFSFileSystem() : this(true) { // Mark us as having a single empty BAT at offset 0 _header.BATCount = 1; _header.BATArray = new int[] { 0 }; _bat_blocks.Add(BATBlock.CreateEmptyBATBlock(bigBlockSize, false)); SetNextBlock(0, POIFSConstants.FAT_SECTOR_BLOCK); // Now associate the properties with the empty block _property_table.StartBlock = 1; SetNextBlock(1, POIFSConstants.END_OF_CHAIN); }
/** * Constructor, intended for writing */ public NPOIFSFileSystem() : this(true) { // Mark us as having a single empty BAT at offset 0 _header.BATCount = 1; _header.BATArray = new int[] { 0 }; BATBlock bb = BATBlock.CreateEmptyBATBlock(bigBlockSize, false); bb.OurBlockIndex = 0; _bat_blocks.Add(bb); SetNextBlock(0, POIFSConstants.FAT_SECTOR_BLOCK); SetNextBlock(1, POIFSConstants.END_OF_CHAIN); _property_table.StartBlock = (POIFSConstants.END_OF_CHAIN); }
/** * Constructor, intended for writing */ public NPOIFSFileSystem() : this(true) { // Reserve block 0 for the start of the Properties Table // Create a single empty BAT, at pop that at offset 1 _header.BATCount = 1; _header.BATArray = new int[] { 1 }; BATBlock bb = BATBlock.CreateEmptyBATBlock(bigBlockSize, false); bb.OurBlockIndex = 1; _bat_blocks.Add(bb); SetNextBlock(0, POIFSConstants.END_OF_CHAIN); SetNextBlock(1, POIFSConstants.FAT_SECTOR_BLOCK); _property_table.StartBlock = 0; }
public void TestCalculateXBATStorageRequirements() { int[] blockCounts = { 0, 1, 127, 128 }; int[] requirements = { 0, 1, 1, 2 }; for (int j = 0; j < blockCounts.Length; j++) { Assert.AreEqual( requirements[j], BATBlock.CalculateXBATStorageRequirements(blockCounts[j]), "requirement for " + blockCounts[j]); } }
/** * 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); }
/** * 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 numSectors = bigBlockSize.GetBATEntriesPerBlock(); // First up, do we have any spare ones? int offset = 0; foreach (BATBlock temp in _bat_blocks) { if (temp.HasFreeSectors) { // Claim one of them and return it for (int j = 0; j < numSectors; j++) { int batValue = temp.GetValueAt(j); if (batValue == POIFSConstants.UNUSED_BLOCK) { // Bingo return(offset + j); } } } // Move onto the next BAT offset += numSectors; } // If we Get here, then there aren't any free sectors // in any of the BATs, so we need another BAT BATBlock bat = CreateBAT(offset, true); bat.SetValueAt(0, POIFSConstants.FAT_SECTOR_BLOCK); _bat_blocks.Add(bat); // Now store a reference to the BAT in the required place if (_header.BATCount >= 109) { // Needs to come from an XBAT BATBlock xbat = null; foreach (BATBlock x in _xbat_blocks) { if (x.HasFreeSectors) { xbat = x; break; } } if (xbat == null) { // Oh joy, we need a new XBAT too... xbat = CreateBAT(offset + 1, false); // Allocate our new BAT as the first block in the XBAT xbat.SetValueAt(0, offset); // And allocate the XBAT in the BAT bat.SetValueAt(1, POIFSConstants.DIFAT_SECTOR_BLOCK); // Will go one place higher as XBAT Added in offset++; // Chain it if (_xbat_blocks.Count == 0) { _header.XBATStart = offset; } else { _xbat_blocks[_xbat_blocks.Count - 1].SetValueAt( bigBlockSize.GetXBATEntriesPerBlock(), offset ); } _xbat_blocks.Add(xbat); _header.XBATCount = _xbat_blocks.Count; } else { // Allocate us in the XBAT for (int i = 0; i < bigBlockSize.GetXBATEntriesPerBlock(); i++) { if (xbat.GetValueAt(i) == POIFSConstants.UNUSED_BLOCK) { xbat.SetValueAt(i, offset); break; } } } } else { // Store us in the header int[] newBATs = new int[_header.BATCount + 1]; Array.Copy(_header.BATArray, 0, newBATs, 0, newBATs.Length - 1); newBATs[newBATs.Length - 1] = offset; _header.BATArray = newBATs; } _header.BATCount = _bat_blocks.Count; // The current offset stores us, but the next one is free return(offset + 1); }
/** * Returns the BATBlock that handles the specified offset, * and the relative index within it */ public override BATBlockAndIndex GetBATBlockAndIndex(int offset) { return(BATBlock.GetBATBlockAndIndex(offset, _header, _bat_blocks)); }
public void TestWriteThenReplace() { NPOIFSFileSystem fs = new NPOIFSFileSystem(); // Starts empty BATBlock bat = fs.GetBATBlockAndIndex(0).Block; Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(2)); // Write something that uses a main stream byte[] main4106 = new byte[4106]; main4106[0] = unchecked ((byte)-10); main4106[4105] = unchecked ((byte)-11); DocumentEntry normal = fs.Root.CreateDocument( "Normal", new MemoryStream(main4106)); // Should have used 9 blocks Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(3, bat.GetValueAt(2)); Assert.AreEqual(4, bat.GetValueAt(3)); Assert.AreEqual(5, bat.GetValueAt(4)); Assert.AreEqual(6, bat.GetValueAt(5)); Assert.AreEqual(7, bat.GetValueAt(6)); Assert.AreEqual(8, bat.GetValueAt(7)); Assert.AreEqual(9, bat.GetValueAt(8)); Assert.AreEqual(10, bat.GetValueAt(9)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(10)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(11)); normal = (DocumentEntry)fs.Root.GetEntry("Normal"); Assert.AreEqual(4106, normal.Size); Assert.AreEqual(4106, ((DocumentNode)normal).Property.Size); // Replace with one still big enough for a main stream, but one block smaller byte[] main4096 = new byte[4096]; main4096[0] = unchecked ((byte)-10); main4096[4095] = unchecked ((byte)-11); NDocumentOutputStream nout = new NDocumentOutputStream(normal); nout.Write(main4096); nout.Close(); // Will have dropped to 8 Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(3, bat.GetValueAt(2)); Assert.AreEqual(4, bat.GetValueAt(3)); Assert.AreEqual(5, bat.GetValueAt(4)); Assert.AreEqual(6, bat.GetValueAt(5)); Assert.AreEqual(7, bat.GetValueAt(6)); Assert.AreEqual(8, bat.GetValueAt(7)); Assert.AreEqual(9, bat.GetValueAt(8)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(9)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(10)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(11)); normal = (DocumentEntry)fs.Root.GetEntry("Normal"); Assert.AreEqual(4096, normal.Size); Assert.AreEqual(4096, ((DocumentNode)normal).Property.Size); // Write and check fs = TestNPOIFSFileSystem.WriteOutAndReadBack(fs); bat = fs.GetBATBlockAndIndex(0).Block; // Will have properties, but otherwise the same Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(3, bat.GetValueAt(2)); Assert.AreEqual(4, bat.GetValueAt(3)); Assert.AreEqual(5, bat.GetValueAt(4)); Assert.AreEqual(6, bat.GetValueAt(5)); Assert.AreEqual(7, bat.GetValueAt(6)); Assert.AreEqual(8, bat.GetValueAt(7)); Assert.AreEqual(9, bat.GetValueAt(8)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(9)); // End of Normal Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(10)); // Props Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(11)); normal = (DocumentEntry)fs.Root.GetEntry("Normal"); Assert.AreEqual(4096, normal.Size); Assert.AreEqual(4096, ((DocumentNode)normal).Property.Size); // Make longer, take 1 block After the properties too normal = (DocumentEntry)fs.Root.GetEntry("Normal"); nout = new NDocumentOutputStream(normal); nout.Write(main4106); nout.Close(); Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(3, bat.GetValueAt(2)); Assert.AreEqual(4, bat.GetValueAt(3)); Assert.AreEqual(5, bat.GetValueAt(4)); Assert.AreEqual(6, bat.GetValueAt(5)); Assert.AreEqual(7, bat.GetValueAt(6)); Assert.AreEqual(8, bat.GetValueAt(7)); Assert.AreEqual(9, bat.GetValueAt(8)); Assert.AreEqual(11, bat.GetValueAt(9)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(10)); // Props Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(11)); // Normal Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(12)); normal = (DocumentEntry)fs.Root.GetEntry("Normal"); Assert.AreEqual(4106, normal.Size); Assert.AreEqual(4106, ((DocumentNode)normal).Property.Size); // Make it small, will trigger the SBAT stream and free lots up byte[] mini = new byte[] { 42, 0, 1, 2, 3, 4, 42 }; normal = (DocumentEntry)fs.Root.GetEntry("Normal"); nout = new NDocumentOutputStream(normal); nout.Write(mini); nout.Close(); Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(2)); // SBAT Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(3)); // Mini Stream Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(4)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(5)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(6)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(7)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(8)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(9)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(10)); // Props Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(11)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(12)); normal = (DocumentEntry)fs.Root.GetEntry("Normal"); Assert.AreEqual(7, normal.Size); Assert.AreEqual(7, ((DocumentNode)normal).Property.Size); // Finally back to big again nout = new NDocumentOutputStream(normal); nout.Write(main4096); nout.Close(); // Will keep the mini stream, now empty Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(2)); // SBAT Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(3)); // Mini Stream Assert.AreEqual(5, bat.GetValueAt(4)); Assert.AreEqual(6, bat.GetValueAt(5)); Assert.AreEqual(7, bat.GetValueAt(6)); Assert.AreEqual(8, bat.GetValueAt(7)); Assert.AreEqual(9, bat.GetValueAt(8)); Assert.AreEqual(11, bat.GetValueAt(9)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(10)); // Props Assert.AreEqual(12, bat.GetValueAt(11)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(12)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(13)); normal = (DocumentEntry)fs.Root.GetEntry("Normal"); Assert.AreEqual(4096, normal.Size); Assert.AreEqual(4096, ((DocumentNode)normal).Property.Size); // Save, re-load, re-check fs = TestNPOIFSFileSystem.WriteOutAndReadBack(fs); bat = fs.GetBATBlockAndIndex(0).Block; Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(2)); // SBAT Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(3)); // Mini Stream Assert.AreEqual(5, bat.GetValueAt(4)); Assert.AreEqual(6, bat.GetValueAt(5)); Assert.AreEqual(7, bat.GetValueAt(6)); Assert.AreEqual(8, bat.GetValueAt(7)); Assert.AreEqual(9, bat.GetValueAt(8)); Assert.AreEqual(11, bat.GetValueAt(9)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(10)); // Props Assert.AreEqual(12, bat.GetValueAt(11)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(12)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(13)); normal = (DocumentEntry)fs.Root.GetEntry("Normal"); Assert.AreEqual(4096, normal.Size); Assert.AreEqual(4096, ((DocumentNode)normal).Property.Size); fs.Close(); }
public void TestReadWriteNewStream() { NPOIFSFileSystem fs = new NPOIFSFileSystem(); NPOIFSStream stream = new NPOIFSStream(fs); // Check our filesystem has a BAT and the Properties Assert.AreEqual(2, fs.GetFreeBlock()); BATBlock bat = fs.GetBATBlockAndIndex(0).Block; Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(2)); // Check the stream as-is Assert.AreEqual(POIFSConstants.END_OF_CHAIN, stream.GetStartBlock()); try { stream.GetBlockIterator(); Assert.Fail("Shouldn't be able to get an iterator before writing"); } catch (Exception) { } // Write in two blocks byte[] data = new byte[512 + 20]; for (int i = 0; i < 512; i++) { data[i] = (byte)(i % 256); } for (int i = 512; i < data.Length; i++) { data[i] = (byte)(i % 256 + 100); } stream.UpdateContents(data); // Check now Assert.AreEqual(4, fs.GetFreeBlock()); bat = fs.GetBATBlockAndIndex(0).Block; Assert.AreEqual(POIFSConstants.FAT_SECTOR_BLOCK, bat.GetValueAt(0)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(1)); Assert.AreEqual(3, bat.GetValueAt(2)); Assert.AreEqual(POIFSConstants.END_OF_CHAIN, bat.GetValueAt(3)); Assert.AreEqual(POIFSConstants.UNUSED_BLOCK, bat.GetValueAt(4)); IEnumerator <ByteBuffer> it = stream.GetBlockIterator(); Assert.AreEqual(true, it.MoveNext()); ByteBuffer b = it.Current; byte[] read = new byte[512]; //b.get(read); // Array.Copy(b, 0, read, 0, b.Length); b.Read(read); for (int i = 0; i < read.Length; i++) { //Assert.AreEqual("Wrong value at " + i, data[i], read[i]); Assert.AreEqual(data[i], read[i], "Wrong value at " + i); } Assert.AreEqual(true, it.MoveNext()); b = it.Current; read = new byte[512]; //b.get(read); //Array.Copy(b, 0, read, 0, b.Length); b.Read(read); for (int i = 0; i < 20; i++) { Assert.AreEqual(data[i + 512], read[i]); } for (int i = 20; i < read.Length; i++) { Assert.AreEqual(0, read[i]); } Assert.AreEqual(false, it.MoveNext()); fs.Close(); }
public void TestCalculateMaximumSize() { // Zero fat blocks isn't technically valid, but it'd be header only Assert.AreEqual( 512, BATBlock.CalculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 0) ); Assert.AreEqual( 4096, BATBlock.CalculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 0) ); // A single FAT block can address 128/1024 blocks Assert.AreEqual( 512 + 512 * 128, BATBlock.CalculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 1) ); Assert.AreEqual( 4096 + 4096 * 1024, BATBlock.CalculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 1) ); Assert.AreEqual( 512 + 4 * 512 * 128, BATBlock.CalculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 4) ); Assert.AreEqual( 4096 + 4 * 4096 * 1024, BATBlock.CalculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 4) ); // One XBAT block holds 127/1023 individual BAT blocks, so they can address // a fairly hefty amount of space themselves // However, the BATs continue as before Assert.AreEqual( 512 + 109 * 512 * 128, BATBlock.CalculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 109) ); Assert.AreEqual( 4096 + 109 * 4096 * 1024, BATBlock.CalculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 109) ); Assert.AreEqual( 512 + 110 * 512 * 128, BATBlock.CalculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 110) ); Assert.AreEqual( 4096 + 110 * 4096 * 1024, BATBlock.CalculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 110) ); Assert.AreEqual( 512 + 112 * 512 * 128, BATBlock.CalculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 112) ); Assert.AreEqual( 4096 + 112 * 4096 * 1024, BATBlock.CalculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 112) ); // Check for >2gb, which we only support via a File Assert.AreEqual( 512 + 8030L * 512 * 128, BATBlock.CalculateMaximumSize(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS, 8030) ); Assert.AreEqual( 4096 + 8030L * 4096 * 1024, BATBlock.CalculateMaximumSize(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS, 8030) ); }
public void TestGetBATBlockAndIndex() { HeaderBlock header = new HeaderBlock(POIFSConstants.SMALLER_BIG_BLOCK_SIZE_DETAILS); List <BATBlock> blocks = new List <BATBlock>(); int offset; // First, try a one BAT block file header.BATCount = (1); blocks.Add( BATBlock.CreateBATBlock(header.BigBlockSize, new ByteBuffer(512, 512)) ); offset = 0; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 1; Assert.AreEqual(1, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 127; Assert.AreEqual(127, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); // Now go for one with multiple BAT blocks header.BATCount = (2); blocks.Add( BATBlock.CreateBATBlock(header.BigBlockSize, new ByteBuffer(512, 512)) ); offset = 0; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 127; Assert.AreEqual(127, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 128; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(1, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 129; Assert.AreEqual(1, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(1, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); // The XBAT count makes no difference, as we flatten in memory header.BATCount = (1); header.XBATCount = (1); offset = 0; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 126; Assert.AreEqual(126, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 127; Assert.AreEqual(127, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 128; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(1, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 129; Assert.AreEqual(1, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(1, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); // Check with the bigger block size too header = new HeaderBlock(POIFSConstants.LARGER_BIG_BLOCK_SIZE_DETAILS); offset = 0; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 1022; Assert.AreEqual(1022, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 1023; Assert.AreEqual(1023, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 1024; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(1, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); // Biggr block size, back to real BATs header.BATCount = (2); offset = 0; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 1022; Assert.AreEqual(1022, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 1023; Assert.AreEqual(1023, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(0, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); offset = 1024; Assert.AreEqual(0, BATBlock.GetBATBlockAndIndex(offset, header, blocks).Index); Assert.AreEqual(1, blocks.IndexOf(BATBlock.GetBATBlockAndIndex(offset, header, blocks).Block)); }