Class: Ole::Storage::AllocationTable

### Home Classes Methods

### In Files

- lib/ole/storage/base.rb

### Parent

Array

### Namespace

- CLASS Ole::Storage::AllocationTable::Big
- CLASS Ole::Storage::AllocationTable::Small

### Methods

- ::new
- #[]=
- #blocks_to_ranges
- #chain
- #free_block
- #load
- #open
- #ranges
- #read
- #resize_chain
- #to_s
- #truncate
- #truncate!

### Files

- ChangeLog
- README

### Class/Module Index

Quicksearch

- Ole
- Ole::IOMode
- Ole::IOMode::Constants
- Ole::Storage
- Ole::Storage::AllocationTable
- Ole::Storage::AllocationTable::Big
- Ole::Storage::AllocationTable::Small
- Ole::Storage::DirClass
- Ole::Storage::DirClass::Dir
- Ole::Storage::Dirent
- Ole::Storage::FileClass
- Ole::Storage::FileClass::Stat
- Ole::Storage::Header
- Ole::Storage::MetaData
- Ole::Storage::RangesIOMigrateable
- Ole::Storage::RangesIOResizeable
- Ole::Types
- Ole::Types::Clsid
- Ole::Types::Data
- Ole::Types::FileTime
- Ole::Types::Lpstr
- Ole::Types::Lpwstr
- Ole::Types::PropertySet
- Ole::Types::PropertySet::Constants
- Ole::Types::PropertySet::Section
- Ole::Types::Variant
- Ole::Types::Variant::Constants
- RangesIO

No matching classes.

# Ole::Storage::AllocationTable

`AllocationTable`'s hold the chains corresponding to files. Given an initial index, `AllocationTable#chain` follows the chain, returning the blocks that make up that file.

There are 2 allocation tables, the bbat, and sbat, for big and small blocks respectively. The block chain should be loaded using either `Storage#read_big_blocks` or `Storage#read_small_blocks` as appropriate.

Whether or not big or small blocks are used for a file depends on whether its size is over the `Header#threshold` level.

An `Ole::Storage` document is serialized as a series of directory objects, which are stored in blocks throughout the file. The blocks are either big or small, and are accessed using the `AllocationTable`.

The bbat allocation table's data is stored in the spare room in the header block, and in extra blocks throughout the file as referenced by the meta bat. That chain is linear, as there is no higher level table.

AllocationTable.new is used to create an empty table. It can parse a string with the load method. Serialization is accomplished with the to_s method.

### Constants

AVAIL

  a free block (I don't currently leave any blocks free), although I do pad out the allocation table with AVAIL to the block size.

BAT

  these blocks are used for storing the allocation table chains

EOC
META_BAT

### Attributes

block_size[R]
io[R]
ole[R]

### Public Class Methods

new(ole) click to toggle source

    # File lib/ole/storage/base.rb, line 435
    def initialize ole
      @ole = ole
      @sparse = true
      super()
    end

### Public Instance Methods

[]=(idx, val) click to toggle source

    # File lib/ole/storage/base.rb, line 525
    def []= idx, val
      @sparse = true if val == AVAIL
      super
    end

blocks_to_ranges(chain, size=nil) click to toggle source

Turn a chain (an array given by `chain`) of blocks (optionally truncated to `size`) into an array of arrays describing the stretches of bytes in the file that it belongs to.

The blocks are Big or Small blocks depending on the table type.

    # File lib/ole/storage/base.rb, line 487
    def blocks_to_ranges chain, size=nil
      # truncate the chain if required
      chain = chain[0, (size.to_f / block_size).ceil] if size
      # convert chain to ranges of the block size
      ranges = chain.map { |i| [block_size * i, block_size] }
      # truncate final range if required
      ranges.last[1] -= (ranges.length * block_size - size) if ranges.last and size
      ranges
    end

chain(idx) click to toggle source

rewrote this to be non-recursive as it broke on a large attachment chain with a stack error

    # File lib/ole/storage/base.rb, line 471
    def chain idx
      a = []
      until idx >= META_BAT
        raise FormatError, "broken allocationtable chain" if idx < 0 || idx > length
        a << idx
        idx = self[idx]
      end
      Log.warn "invalid chain terminator #{idx}" unless idx == EOC
      a
    end

free_block() click to toggle source

    # File lib/ole/storage/base.rb, line 530
    def free_block
      if @sparse
        i = index(AVAIL) and return i
        @sparse = false
      end
      push AVAIL
      length - 1
    end

load(data) click to toggle source

    # File lib/ole/storage/base.rb, line 441
    def load data
      replace data.unpack('V*')
    end

open(chain, size=nil, &block) click to toggle source

quick shortcut. chain can be either a head (in which case the table is used to turn it into a chain), or a chain. it is converted to ranges, then to rangesio.

    # File lib/ole/storage/base.rb, line 504
    def open chain, size=nil, &block
      RangesIO.open @io, :ranges => ranges(chain, size), &block
    end

ranges(chain, size=nil) click to toggle source

    # File lib/ole/storage/base.rb, line 497
    def ranges chain, size=nil
      chain = self.chain(chain) unless Array === chain
      blocks_to_ranges chain, size
    end

read(chain, size=nil) click to toggle source

    # File lib/ole/storage/base.rb, line 508
    def read chain, size=nil
      open chain, size, &:read
    end

resize_chain(blocks, size) click to toggle source

must return first_block. modifies `blocks` in place

    # File lib/ole/storage/base.rb, line 540
    def resize_chain blocks, size
      new_num_blocks = (size / block_size.to_f).ceil
      old_num_blocks = blocks.length
      if new_num_blocks < old_num_blocks
        # de-allocate some of our old blocks. TODO maybe zero them out in the file???
        (new_num_blocks...old_num_blocks).each { |i| self[blocks[i]] = AVAIL }
        self[blocks[new_num_blocks-1]] = EOC if new_num_blocks > 0
        blocks.slice! new_num_blocks..-1
      elsif new_num_blocks > old_num_blocks
        # need some more blocks.
        last_block = blocks.last
        (new_num_blocks - old_num_blocks).times do
          block = free_block
          # connect the chain. handle corner case of blocks being [] initially
          self[last_block] = block if last_block
          blocks << block
          last_block = block
          self[last_block] = EOC
        end
      end
      # update ranges, and return that also now
      blocks
    end

to_s() click to toggle source

    # File lib/ole/storage/base.rb, line 459
    def to_s
      table = truncate
      # pad it out some
      num = @ole.bbat.block_size / 4
      # do you really use AVAIL? they probably extend past end of file, and may shortly
      # be used for the bat. not really good.
      table += [AVAIL] * (num - (table.length % num)) if (table.length % num) != 0
      table.pack 'V*'
    end

truncate() click to toggle source

    # File lib/ole/storage/base.rb, line 445
    def truncate
      # this strips trailing AVAILs. come to think of it, this has the potential to break
      # bogus ole. if you terminate using AVAIL instead of EOC, like I did before. but that is
      # very broken. however, if a chain ends with AVAIL, it should probably be fixed to EOC
      # at load time.
      temp = reverse
      not_avail = temp.find { |b| b != AVAIL } and temp = temp[temp.index(not_avail)..-1]
      temp.reverse
    end

truncate!() click to toggle source

    # File lib/ole/storage/base.rb, line 455
    def truncate!
      replace truncate
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.