Class: Ole::Storage::Dirent
- Inherits:
-
Struct
- Object
- Struct
- Ole::Storage::Dirent
- Includes:
- RecursivelyEnumerable
- Defined in:
- lib/ole/storage/base.rb
Overview
A class which wraps an ole directory entry. Can be either a directory (Dirent#dir?
) or a file (Dirent#file?
)
Most interaction with Ole::Storage
is through this class. The 2 most important functions are Dirent#children
, and Dirent#data
.
was considering separate classes for dirs and files. some methods/attrs only applicable to one or the other.
As with the other classes, #to_s performs the serialization.
Constant Summary collapse
- PACK =
'a64 v C C V3 a16 V a8 a8 V2 a4'
- SIZE =
128
- TYPE_MAP =
{ # this is temporary 0 => :empty, 1 => :dir, 2 => :file, 5 => :root }
- COLOUR_MAP =
something to do with the fact that the tree is supposed to be red-black
{ 0 => :red, 1 => :black }
- EOT =
used in the next / prev / child stuff to show that the tree ends here. also used for first_block for directory.
0xffffffff
- DEFAULT =
[ 0.chr * 2, 2, 0, # will get overwritten 1, EOT, EOT, EOT, 0.chr * 16, 0, nil, nil, AllocationTable::EOC, 0, 0.chr * 4 ]
Instance Attribute Summary collapse
-
#child ⇒ Object
Returns the value of attribute child.
-
#children ⇒ Object
readonly
This returns all the children of this
Dirent
. -
#clsid ⇒ Object
Returns the value of attribute clsid.
-
#colour ⇒ Object
Returns the value of attribute colour.
-
#create_time ⇒ Object
readonly
Returns the value of attribute create_time.
-
#create_time_str ⇒ Object
Returns the value of attribute create_time_str.
-
#first_block ⇒ Object
Returns the value of attribute first_block.
-
#flags ⇒ Object
Returns the value of attribute flags.
-
#idx ⇒ Object
i think its just used by the tree building.
-
#modify_time ⇒ Object
readonly
Returns the value of attribute modify_time.
-
#modify_time_str ⇒ Object
Returns the value of attribute modify_time_str.
-
#name ⇒ Object
Returns the value of attribute name.
-
#name_len ⇒ Object
Returns the value of attribute name_len.
-
#name_utf16 ⇒ Object
Returns the value of attribute name_utf16.
-
#next ⇒ Object
Returns the value of attribute next.
-
#ole ⇒ Object
readonly
Returns the value of attribute ole.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#prev ⇒ Object
Returns the value of attribute prev.
-
#reserved ⇒ Object
Returns the value of attribute reserved.
-
#size ⇒ Object
Returns the value of attribute size.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
-
#type_id ⇒ Object
Returns the value of attribute type_id.
Class Method Summary collapse
- .copy(src, dst) ⇒ Object
-
.flatten_helper(children) ⇒ Object
i think making the tree structure optimized is actually more complex than this, and requires some intelligent ordering of the children based on names, but as long as it is valid its ok.
Instance Method Summary collapse
-
#/(name) ⇒ Object
maybe need some options regarding case sensitivity.
- #<<(child) ⇒ Object
- #[](idx) ⇒ Object
-
#delete(child, truncate = true) ⇒ Object
remove the Dirent
child
from the children array, truncating the data by default. - #dir? ⇒ Boolean
- #each_child(&block) ⇒ Object
- #file? ⇒ Boolean
-
#flatten(dirents = []) ⇒ Object
flattens the tree starting from here into
dirents
. -
#initialize(ole, values = DEFAULT, params = {}) ⇒ Dirent
constructor
A new instance of Dirent.
- #inspect ⇒ Object
- #open(mode = 'r') ⇒ Object
- #read(limit = nil) ⇒ Object
-
#time ⇒ Object
move to ruby-msg.
- #to_s ⇒ Object
Methods included from RecursivelyEnumerable
#each_recursive, #each_recursive_breadth_first, #each_recursive_depth_first, #recursive, #to_tree
Constructor Details
#initialize(ole, values = DEFAULT, params = {}) ⇒ Dirent
Returns a new instance of Dirent.
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 |
# File 'lib/ole/storage/base.rb', line 740 def initialize ole, values=DEFAULT, params={} @ole = ole values, params = DEFAULT, values if Hash === values values = values.unpack(PACK) if String === values super(*values) # extra parsing from the actual struct values @name = params[:name] || Types::Variant.load(Types::VT_LPWSTR, name_utf16[0...name_len]) @type = if params[:type] unless TYPE_MAP.values.include?(params[:type]) raise ArgumentError, "unknown type #{params[:type].inspect}" end params[:type] else TYPE_MAP[type_id] or raise FormatError, "unknown type_id #{type_id.inspect}" end # further extra type specific stuff if file? default_time = @ole.params[:update_timestamps] ? Types::FileTime.now : nil @create_time ||= default_time @modify_time ||= default_time @create_time = Types::Variant.load(Types::VT_FILETIME, create_time_str) if create_time_str @modify_time = Types::Variant.load(Types::VT_FILETIME, create_time_str) if modify_time_str @children = nil @name_lookup = nil else @create_time = nil @modify_time = nil self.size = 0 unless @type == :root @children = [] @name_lookup = {} end @parent = nil # to silence warnings. used for tree building at load time # only. @idx = nil end |
Instance Attribute Details
#child ⇒ Object
Returns the value of attribute child
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def child @child end |
#children ⇒ Object (readonly)
This returns all the children of this Dirent
. It is filled in when the tree structure is recreated.
727 728 729 |
# File 'lib/ole/storage/base.rb', line 727 def children @children end |
#clsid ⇒ Object
Returns the value of attribute clsid
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def clsid @clsid end |
#colour ⇒ Object
Returns the value of attribute colour
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def colour @colour end |
#create_time ⇒ Object (readonly)
Returns the value of attribute create_time.
729 730 731 |
# File 'lib/ole/storage/base.rb', line 729 def create_time @create_time end |
#create_time_str ⇒ Object
Returns the value of attribute create_time_str
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def create_time_str @create_time_str end |
#first_block ⇒ Object
Returns the value of attribute first_block
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def first_block @first_block end |
#flags ⇒ Object
Returns the value of attribute flags
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def flags @flags end |
#idx ⇒ Object
i think its just used by the tree building
733 734 735 |
# File 'lib/ole/storage/base.rb', line 733 def idx @idx end |
#modify_time ⇒ Object (readonly)
Returns the value of attribute modify_time.
729 730 731 |
# File 'lib/ole/storage/base.rb', line 729 def modify_time @modify_time end |
#modify_time_str ⇒ Object
Returns the value of attribute modify_time_str
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def modify_time_str @modify_time_str end |
#name ⇒ Object
Returns the value of attribute name.
728 729 730 |
# File 'lib/ole/storage/base.rb', line 728 def name @name end |
#name_len ⇒ Object
Returns the value of attribute name_len
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def name_len @name_len end |
#name_utf16 ⇒ Object
Returns the value of attribute name_utf16
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def name_utf16 @name_utf16 end |
#next ⇒ Object
Returns the value of attribute next
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def next @next end |
#ole ⇒ Object (readonly)
Returns the value of attribute ole.
729 730 731 |
# File 'lib/ole/storage/base.rb', line 729 def ole @ole end |
#parent ⇒ Object
Returns the value of attribute parent.
730 731 732 |
# File 'lib/ole/storage/base.rb', line 730 def parent @parent end |
#prev ⇒ Object
Returns the value of attribute prev
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def prev @prev end |
#reserved ⇒ Object
Returns the value of attribute reserved
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def reserved @reserved end |
#size ⇒ Object
Returns the value of attribute size
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def size @size end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
729 730 731 |
# File 'lib/ole/storage/base.rb', line 729 def type @type end |
#type_id ⇒ Object
Returns the value of attribute type_id
693 694 695 |
# File 'lib/ole/storage/base.rb', line 693 def type_id @type_id end |
Class Method Details
.copy(src, dst) ⇒ Object
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 |
# File 'lib/ole/storage/base.rb', line 925 def self.copy src, dst # copies the contents of src to dst. must be the same type. this will throw an # error on copying to root. maybe this will recurse too much for big documents?? raise ArgumentError, 'differing types' if src.file? and !dst.file? dst.name = src.name if src.dir? src.children.each do |src_child| dst_child = Dirent.new dst.ole, :type => src_child.type dst << dst_child Dirent.copy src_child, dst_child end else src.open do |src_io| dst.open { |dst_io| IO.copy src_io, dst_io } end end end |
.flatten_helper(children) ⇒ Object
i think making the tree structure optimized is actually more complex than this, and requires some intelligent ordering of the children based on names, but as long as it is valid its ok. actually, i think its ok. gsf for example only outputs a singly-linked-list, where prev is always EOT.
857 858 859 860 861 862 863 |
# File 'lib/ole/storage/base.rb', line 857 def self.flatten_helper children return EOT if children.empty? i = children.length / 2 this = children[i] this.prev, this.next = [(0...i), (i+1..-1)].map { |r| flatten_helper children[r] } this.idx end |
Instance Method Details
#/(name) ⇒ Object
maybe need some options regarding case sensitivity.
816 817 818 |
# File 'lib/ole/storage/base.rb', line 816 def / name @name_lookup[name] end |
#<<(child) ⇒ Object
906 907 908 909 910 |
# File 'lib/ole/storage/base.rb', line 906 def << child child.parent = self @name_lookup[child.name] = child @children << child end |
#[](idx) ⇒ Object
820 821 822 823 824 825 826 827 |
# File 'lib/ole/storage/base.rb', line 820 def [] idx if String === idx #warn 'String form of Dirent#[] is deprecated' self / idx else super end end |
#delete(child, truncate = true) ⇒ Object
remove the Dirent child
from the children array, truncating the data by default.
914 915 916 917 918 919 920 921 922 923 |
# File 'lib/ole/storage/base.rb', line 914 def delete child, truncate=true # remove from our child array, so that on reflatten and re-creation of @dirents, it will be gone unless @children.delete(child) raise ArgumentError, "#{child.inspect} not a child of #{self.inspect}" end @name_lookup.delete(child.name) child.parent = nil # free our blocks child.open { |io| io.truncate 0 } if child.file? end |
#dir? ⇒ Boolean
810 811 812 813 |
# File 'lib/ole/storage/base.rb', line 810 def dir? # to count root as a dir. !file? end |
#each_child(&block) ⇒ Object
835 836 837 |
# File 'lib/ole/storage/base.rb', line 835 def each_child(&block) @children.each(&block) if dir? end |
#file? ⇒ Boolean
806 807 808 |
# File 'lib/ole/storage/base.rb', line 806 def file? type == :file end |
#flatten(dirents = []) ⇒ Object
flattens the tree starting from here into dirents
. note it modifies its argument.
840 841 842 843 844 845 846 847 848 849 850 |
# File 'lib/ole/storage/base.rb', line 840 def flatten dirents=[] @idx = dirents.length dirents << self if file? self.prev = self.next = self.child = EOT else children.each { |child| child.flatten dirents } self.child = Dirent.flatten_helper children end dirents end |
#inspect ⇒ Object
891 892 893 894 895 896 897 898 899 900 901 902 903 904 |
# File 'lib/ole/storage/base.rb', line 891 def inspect str = "#<Dirent:#{name.inspect}" # perhaps i should remove the data snippet. its not that useful anymore. # there is also some dir specific stuff. like clsid, flags, that i should # probably include if file? tmp = read 9 data = tmp.length == 9 ? tmp[0, 5] + '...' : tmp str << " size=#{size}" + "#{modify_time ? ' modify_time=' + modify_time.to_s.inspect : nil}" + " data=#{data.inspect}" end str + '>' end |
#open(mode = 'r') ⇒ Object
790 791 792 793 794 795 796 797 798 799 800 |
# File 'lib/ole/storage/base.rb', line 790 def open mode='r' raise Errno::EISDIR unless file? io = RangesIOMigrateable.new self, mode @modify_time = Types::FileTime.now if io.mode.writeable? if block_given? begin yield io ensure; io.close end else io end end |
#read(limit = nil) ⇒ Object
802 803 804 |
# File 'lib/ole/storage/base.rb', line 802 def read limit=nil open { |io| io.read limit } end |
#time ⇒ Object
move to ruby-msg. and remove from here
830 831 832 833 |
# File 'lib/ole/storage/base.rb', line 830 def time #warn 'Dirent#time is deprecated' create_time || modify_time end |
#to_s ⇒ Object
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 |
# File 'lib/ole/storage/base.rb', line 865 def to_s tmp = Types::Variant.dump(Types::VT_LPWSTR, name) tmp = tmp[0, 62] if tmp.length > 62 tmp += 0.chr * 2 self.name_len = tmp.length self.name_utf16 = tmp + 0.chr * (64 - tmp.length) # type_id can perhaps be set in the initializer, as its read only now. self.type_id = TYPE_MAP.to_a.find { |id, name| @type == name }.first # for the case of files, it is assumed that that was handled already # note not dir?, so as not to override root's first_block self.first_block = Dirent::EOT if type == :dir if file? # this is messed up. it changes the time stamps regardless of whether the file # was actually touched. instead, any open call with a writeable mode, should update # the modify time. create time would be set in new. if @ole.params[:update_timestamps] self.create_time_str = Types::Variant.dump Types::VT_FILETIME, @create_time self.modify_time_str = Types::Variant.dump Types::VT_FILETIME, @modify_time end else self.create_time_str = 0.chr * 8 self.modify_time_str = 0.chr * 8 end to_a.pack PACK end |