예제 #1
0
        /**
         * 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);
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        private 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);
            }
            this.startBlock = POIFSConstants.END_OF_CHAIN;
        }
예제 #4
0
 public StreamBlockByteBufferIterator(BlockStore blockStore, int firstBlock)
 {
     this.blockStore = blockStore;
     this.nextBlock  = firstBlock;
     try
     {
         this.loopDetector = blockStore.GetChainLoopDetector();
     }
     catch (IOException e)
     {
         //throw new System.RuntimeException(e);
         throw new Exception(e.Message);
     }
 }
예제 #5
0
        /**
         * Load the block, extending the underlying stream if needed
         */
        public override ByteBuffer CreateBlockIfNeeded(int offset)
        {
            // Try to Get it without extending the stream
            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);

                // 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 it
                return(CreateBlockIfNeeded(offset));
            }
        }
예제 #6
0
        // TODO Streaming write support
        // TODO  then convert fixed sized write to use streaming internally
        // TODO Append write support (probably streaming)

        /**
         * Frees all blocks in the stream
         */
        public void free()
        {
            ChainLoopDetector loopDetector = blockStore.GetChainLoopDetector();

            free(loopDetector);
        }
예제 #7
0
        /**
         * Updates the contents of the stream to the new
         *  Set of bytes.
         * Note - if this is property based, you'll still
         *  need to update the size in the property yourself
         */
        public void UpdateContents(byte[] contents)
        {
            // How many blocks are we going to need?
            int blockSize = blockStore.GetBlockStoreBlockSize();
            int blocks    = (int)Math.Ceiling(((double)contents.Length) / blockSize);

            // Make sure we don't encounter a loop whilst overwriting
            //  the existing blocks
            ChainLoopDetector loopDetector = blockStore.GetChainLoopDetector();

            // Start writing
            int prevBlock = POIFSConstants.END_OF_CHAIN;
            int nextBlock = startBlock;

            for (int i = 0; i < blocks; i++)
            {
                int thisBlock = nextBlock;

                // Allocate a block if needed, otherwise figure
                //  out what the next block will be
                if (thisBlock == POIFSConstants.END_OF_CHAIN)
                {
                    thisBlock = 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)
                    {
                        blockStore.SetNextBlock(prevBlock, thisBlock);
                    }
                    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 (this.startBlock == POIFSConstants.END_OF_CHAIN)
                    {
                        this.startBlock = thisBlock;
                    }
                }
                else
                {
                    loopDetector.Claim(thisBlock);
                    nextBlock = blockStore.GetNextBlock(thisBlock);
                }

                // Write it
                //byte[] buffer = blockStore.CreateBlockIfNeeded(thisBlock);
                ByteBuffer buffer  = blockStore.CreateBlockIfNeeded(thisBlock);
                int        startAt = i * blockSize;
                int        endAt   = Math.Min(contents.Length - startAt, blockSize);
                buffer.Write(contents, startAt, endAt);
                //for (int index = startAt, j = 0; index < endAt; index++, j++)
                //    buffer[j] = contents[index];

                // Update pointers
                prevBlock = thisBlock;
            }
            int lastBlock = prevBlock;

            // If we're overwriting, free any remaining blocks
            NPOIFSStream toFree = new NPOIFSStream(blockStore, nextBlock);

            toFree.free(loopDetector);

            // Mark the end of the stream
            blockStore.SetNextBlock(lastBlock, POIFSConstants.END_OF_CHAIN);
        }
예제 #8
0
        /**
         * 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);
        }