Class: Ole::Storage::MetaData

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/ole/storage/meta_data.rb

Overview

The MetaData class is designed to be high level interface to all the underlying meta data stored within different sections, themselves within different property set streams.

With this class, you can simply get properties using their names, without needing to know about the underlying guids, property ids etc.

Example:

Ole::Storage.open('test.doc') { |ole| p ole..doc_author }

TODO:

  • add write support

  • fix some of the missing type coercion (eg FileTime)

  • maybe add back the ability to access individual property sets as a unit directly. ie ole.summary_information. Is this useful?

  • full key support, for unknown keys, like ole.meta_data[myguid, myid]. probably needed for user-defined properties too.

Constant Summary collapse

FILE_MAP =
{
	Types::PropertySet::FMTID_SummaryInformation => "\005SummaryInformation",
	Types::PropertySet::FMTID_DocSummaryInfo => "\005DocumentSummaryInformation"
}
FORMAT_MAP =
{
	'MSWordDoc' => :doc
}
CLSID_EXCEL97 =
Types::Clsid.parse "{00020820-0000-0000-c000-000000000046}"
CLSID_EXCEL95 =
Types::Clsid.parse "{00020810-0000-0000-c000-000000000046}"
CLSID_WORD97 =
Types::Clsid.parse "{00020906-0000-0000-c000-000000000046}"
CLSID_WORD95 =
Types::Clsid.parse "{00020900-0000-0000-c000-000000000046}"
CLSID_MAP =
{
	CLSID_EXCEL97 => :xls,
	CLSID_EXCEL95 => :xls,
	CLSID_WORD97  => :doc,
	CLSID_WORD95  => :doc
}
MIME_TYPES =
{
	:xls => 'application/vnd.ms-excel',
	:doc => 'application/msword',
	:ppt => 'application/vnd.ms-powerpoint',
	# not registered at IANA, but seems most common usage
	:msg => 'application/vnd.ms-outlook',
	# this is my default fallback option. also not registered at IANA.
	# file(1)'s default is application/msword, which is useless...
	nil  => 'application/x-ole-storage'
}

Instance Method Summary collapse

Methods included from Enumerable

#group_by, #sum

Constructor Details

#initialize(ole) ⇒ MetaData

Returns a new instance of MetaData.



62
63
64
# File 'lib/ole/storage/meta_data.rb', line 62

def initialize ole
	@ole = ole
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



136
137
138
139
140
# File 'lib/ole/storage/meta_data.rb', line 136

def method_missing name, *args, &block
	return super unless args.empty?
	pair = Types::PropertySet::PROPERTY_MAP[name.to_s] or return super
	self[name]
end

Instance Method Details

#[](key) ⇒ Object



114
115
116
117
118
119
# File 'lib/ole/storage/meta_data.rb', line 114

def [] key
	pair = Types::PropertySet::PROPERTY_MAP[key.to_s] or return nil
	file = FILE_MAP[pair.first] or return nil
	dirent = @ole.root[file] or return nil
	dirent.open { |io| return Types::PropertySet.new(io)[key] }
end

#[]=(key, value) ⇒ Object

Raises:

  • (NotImplementedError)


121
122
123
# File 'lib/ole/storage/meta_data.rb', line 121

def []= key, value
	raise NotImplementedError, 'meta data writes not implemented'
end

#each(&block) ⇒ Object



125
126
127
128
129
130
# File 'lib/ole/storage/meta_data.rb', line 125

def each(&block)
	FILE_MAP.values.each do |file|
		dirent = @ole.root[file] or next
		dirent.open { |io| Types::PropertySet.new(io).each(&block) }
	end
end

#file_formatObject



92
93
94
# File 'lib/ole/storage/meta_data.rb', line 92

def file_format
	comp_obj[:file_format]
end

#mime_typeObject



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/ole/storage/meta_data.rb', line 96

def mime_type
	# based on the CompObj stream contents
	type = FORMAT_MAP[file_format]
	return MIME_TYPES[type] if type

	# based on the root clsid
	type = CLSID_MAP[Types::Clsid.load(@ole.root.clsid)]
	return MIME_TYPES[type] if type

	# fallback to heuristics
	has_file = Hash[*@ole.root.children.map { |d| [d.name.downcase, true] }.flatten]
	return MIME_TYPES[:msg] if has_file['__nameid_version1.0'] or has_file['__properties_version1.0']
	return MIME_TYPES[:doc] if has_file['worddocument'] or has_file['document']
	return MIME_TYPES[:xls] if has_file['workbook'] or has_file['book']

	MIME_TYPES[nil]
end

#to_hObject



132
133
134
# File 'lib/ole/storage/meta_data.rb', line 132

def to_h
	inject({}) { |hash, (name, value)| hash.update name.to_sym => value }
end