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.



64
65
66
# File 'lib/ole/storage/meta_data.rb', line 64

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



138
139
140
141
142
# File 'lib/ole/storage/meta_data.rb', line 138

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

Instance Method Details

#[](key) ⇒ Object



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

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)


123
124
125
# File 'lib/ole/storage/meta_data.rb', line 123

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

#each(&block) ⇒ Object



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

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



94
95
96
# File 'lib/ole/storage/meta_data.rb', line 94

def file_format
	comp_obj[:file_format]
end

#mime_typeObject



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

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



134
135
136
# File 'lib/ole/storage/meta_data.rb', line 134

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