Class: Mapi::Pst::Header

Inherits:
Object
  • Object
show all
Defined in:
lib/mapi/pst.rb

Overview

class which encapsulates the pst header

Constant Summary collapse

SIZE =
512
MAGIC =
0x2142444e
INDEX_TYPE_OFFSET =

these are the constants defined in libpst.c, that are referenced in pst_open()

0x0A
FILE_SIZE_POINTER =
0xA8
FILE_SIZE_POINTER_64 =
0xB8
SECOND_POINTER =
0xBC
INDEX_POINTER =
0xC4
SECOND_POINTER_64 =
0xE0
INDEX_POINTER_64 =
0xF0
ENC_OFFSET =
0x1CD

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Header

Returns a new instance of Header.



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/mapi/pst.rb', line 163

def initialize data
	@magic = data.unpack('N')[0]
	@index_type = data[INDEX_TYPE_OFFSET].ord
	@version = {0x0e => 1997, 0x17 => 2003, 0x24 => 2003}[@index_type]

	if version_2003?
		# don't know?
		# >> data1.unpack('V*').zip(data2.unpack('V*')).enum_with_index.select { |(c, d), i| c != d and not [46, 56, 60].include?(i) }.select { |(a, b), i| b == 0 }.map { |(a, b), i| [a / 256, i] }
		#   [8, 76], [32768, 84], [128, 89]
		# >> data1.unpack('C*').zip(data2.unpack('C*')).enum_with_index.select { |(c, d), i| c != d and not [184..187, 224..227, 240..243].any? { |r| r === i } }.select { |(a, b), i| b == 0 and ((Math.log(a) / Math.log(2)) % 1) < 0.0001 }
		#   [[[2, 0], 61], [[2, 0], 76], [[2, 0], 195], [[2, 0], 257], [[8, 0], 305], [[128, 0], 338], [[128, 0], 357]]
		# i have only 2 psts to base this guess on, so i can't really come up with anything that looks reasonable yet. not sure what the offset is. unfortunately there is so much in the header
		# that isn't understood...
		@encrypt_type = 1

		@node_btree_count, @node_btree = Pst.unpack(data[SECOND_POINTER_64 - 8, 16], "T2")
		@block_btree_count, @block_btree = Pst.unpack(data[INDEX_POINTER_64  - 8, 16], "T2")

		@size = data[FILE_SIZE_POINTER_64, 4].unpack('V')[0]
	else
		@encrypt_type = data[ENC_OFFSET].ord

		@node_btree_count, @node_btree = data[SECOND_POINTER - 4, 8].unpack('V2')
		@block_btree_count, @block_btree = data[INDEX_POINTER  - 4, 8].unpack('V2')

		@size = data[FILE_SIZE_POINTER, 4].unpack('V')[0]
	end

	validate!
end

Instance Attribute Details

#block_btreeInteger (readonly)

Returns:

  • (Integer)


155
156
157
# File 'lib/mapi/pst.rb', line 155

def block_btree
  @block_btree
end

#block_btree_countInteger (readonly)

Returns:

  • (Integer)


153
154
155
# File 'lib/mapi/pst.rb', line 153

def block_btree_count
  @block_btree_count
end

#encrypt_typeInteger (readonly)

Returns:

  • (Integer)


149
150
151
# File 'lib/mapi/pst.rb', line 149

def encrypt_type
  @encrypt_type
end

#index_typeInteger (readonly)

Returns:

  • (Integer)


147
148
149
# File 'lib/mapi/pst.rb', line 147

def index_type
  @index_type
end

#magicInteger (readonly)

Returns:

  • (Integer)


145
146
147
# File 'lib/mapi/pst.rb', line 145

def magic
  @magic
end

#node_btreeInteger (readonly)

Returns:

  • (Integer)


159
160
161
# File 'lib/mapi/pst.rb', line 159

def node_btree
  @node_btree
end

#node_btree_countInteger (readonly)

Returns:

  • (Integer)


157
158
159
# File 'lib/mapi/pst.rb', line 157

def node_btree_count
  @node_btree_count
end

#sizeInteger (readonly)

Returns:

  • (Integer)


151
152
153
# File 'lib/mapi/pst.rb', line 151

def size
  @size
end

#versionInteger (readonly)

Returns:

  • (Integer)


161
162
163
# File 'lib/mapi/pst.rb', line 161

def version
  @version
end

Instance Method Details

#encrypted?Boolean

Returns:

  • (Boolean)


202
203
204
# File 'lib/mapi/pst.rb', line 202

def encrypted?
	encrypt_type != 0
end

#validate!Object

Raises:



206
207
208
209
210
# File 'lib/mapi/pst.rb', line 206

def validate!
	raise FormatError, "bad signature on pst file (#{'0x%x' % magic})" unless magic == MAGIC
	raise FormatError, "only index types 0x0e, 0x17 and 0x24 are handled (#{'0x%x' % index_type})" unless [0x0e, 0x17, 0x24].include?(index_type)
	raise FormatError, "only encrytion types 0 and 1 are handled (#{encrypt_type.inspect})" unless [0, 1].include?(encrypt_type)
end

#version_2003?Boolean

return ‘true` if pst is an Unicode version. Unicode version also uses 64-bit file pointer. otherwise return `false` where pst is an ANSI version. ANSI version uses 32-bit file pointer.

Returns:

  • (Boolean)


198
199
200
# File 'lib/mapi/pst.rb', line 198

def version_2003?
	version == 2003
end