# -*- coding: binary -*-
##
# $Id$
# Version: $Revision$
##

##
# Rex::OLE - an OLE implementation
# written in 2010 by Joshua J. Drake <jduck [at] metasploit.com>
##

module Rex
module OLE

class FAT < DIFAT

	#
	# low-level functions
	#
	def read(difat)
		@entries = []
		cnt = left = @stg.header._csectFat
		difat.each { |fs|
			break if (left == 0)

			if (fs != SECT_FREE)
				buf = @stg.read_sector(fs, @stg.header.sector_size)
				arr = Util.get32array(buf)

				# hax!
				if (@entries[fs] == SECT_DIF)
					# chop the next ptr
					@entries += arr.slice!(0, arr.length - 1)
				else
					@entries += arr
				end
				left -= 1
			end
		}

		if (left != 0)
			raise RuntimeError, 'Only found %u of %u sectors' % [(cnt - left), cnt]
		end
	end

	def allocate_sector(type=nil)
		idx = @entries.index(SECT_FREE)
		if (not idx)
			# add a sector worth
			idx = @entries.length
			@stg.header.idx_per_sect.times {
				@entries << SECT_FREE
			}
		end

		# mark the sector as in use
		if (type)
			@entries[idx] = type
		else
			# default normal sectors to end of chain
			@entries[idx] = SECT_END
		end
		idx
	end

	def write(difat)
		# we build the difat as we write these..
		difat.reset

		# allocate the sectors
		fat_sects = []
		left = @entries.length
		while (left > 0)
			if (left > @stg.header.idx_per_sect)
				left -= @stg.header.idx_per_sect
			else
				left = 0
			end
			fat_sects << allocate_sector(SECT_FAT)
		end

		# write the fat into the difat/allocated sectors
		copy = @entries.dup
		fat_sects.each { |fs|
			part = copy.slice!(0, @stg.header.idx_per_sect)
			sbuf = Util.pack32array(part)

			if (sbuf.length != @stg.header.sector_size)
				raise RuntimeError, 'Unsupported number of fat sectors (not multiple of idx per sect)'
			end

			@stg.write_sector_raw(fs, sbuf)
			difat << fs
		}
	end

end

end
end
