Class: Omnizip::Formats::Ole::Header

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/omnizip/formats/ole/header.rb

Overview

OLE header parser

Parses the 512-byte header block from OLE compound documents. The first 76 bytes contain the header structure, followed by up to 109 BAT block indices.

Constant Summary collapse

PACK =

Pack format for header structure

"a8 a16 v2 a2 v2 a6 V3 a4 V5"

Constants included from Constants

Constants::AVAIL, Constants::BAT, Constants::BYTE_ORDER_LE, Constants::DEFAULT_BIG_BLOCK_SHIFT, Constants::DEFAULT_SMALL_BLOCK_SHIFT, Constants::DEFAULT_THRESHOLD, Constants::DIRENT_COLORS, Constants::DIRENT_SIZE, Constants::DIRENT_TYPES, Constants::EOC, Constants::EOT, Constants::HEADER_BLOCK_SIZE, Constants::HEADER_SIZE, Constants::MAGIC, Constants::MAX_NAME_LENGTH, Constants::META_BAT

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeHeader

Initialize header



95
96
97
# File 'lib/omnizip/formats/ole/header.rb', line 95

def initialize
  apply_defaults
end

Instance Attribute Details

#b_shiftInteger

Returns Big block shift (9 = 512 bytes).

Returns:

  • (Integer)

    Big block shift (9 = 512 bytes)



33
34
35
# File 'lib/omnizip/formats/ole/header.rb', line 33

def b_shift
  @b_shift
end

#byte_orderString

Returns 2-byte byte order marker.

Returns:

  • (String)

    2-byte byte order marker



30
31
32
# File 'lib/omnizip/formats/ole/header.rb', line 30

def byte_order
  @byte_order
end

#clsidString

Returns 16-byte CLSID (usually zeros).

Returns:

  • (String)

    16-byte CLSID (usually zeros)



21
22
23
# File 'lib/omnizip/formats/ole/header.rb', line 21

def clsid
  @clsid
end

#csectdirInteger

Returns Number of SECTs in directory (0 for v3).

Returns:

  • (Integer)

    Number of SECTs in directory (0 for v3)



42
43
44
# File 'lib/omnizip/formats/ole/header.rb', line 42

def csectdir
  @csectdir
end

#dirent_startInteger

Returns First block of directory entries.

Returns:

  • (Integer)

    First block of directory entries



48
49
50
# File 'lib/omnizip/formats/ole/header.rb', line 48

def dirent_start
  @dirent_start
end

#magicString

Returns 8-byte OLE magic signature.

Returns:

  • (String)

    8-byte OLE magic signature



18
19
20
# File 'lib/omnizip/formats/ole/header.rb', line 18

def magic
  @magic
end

#major_verInteger

Returns Major version (3 or 4).

Returns:

  • (Integer)

    Major version (3 or 4)



27
28
29
# File 'lib/omnizip/formats/ole/header.rb', line 27

def major_ver
  @major_ver
end

#mbat_startInteger

Returns First block of Meta BAT.

Returns:

  • (Integer)

    First block of Meta BAT



63
64
65
# File 'lib/omnizip/formats/ole/header.rb', line 63

def mbat_start
  @mbat_start
end

#minor_verInteger

Returns Minor version (usually 59).

Returns:

  • (Integer)

    Minor version (usually 59)



24
25
26
# File 'lib/omnizip/formats/ole/header.rb', line 24

def minor_ver
  @minor_ver
end

#num_batInteger

Returns Number of BAT blocks.

Returns:

  • (Integer)

    Number of BAT blocks



45
46
47
# File 'lib/omnizip/formats/ole/header.rb', line 45

def num_bat
  @num_bat
end

#num_mbatInteger

Returns Number of Meta BAT blocks.

Returns:

  • (Integer)

    Number of Meta BAT blocks



66
67
68
# File 'lib/omnizip/formats/ole/header.rb', line 66

def num_mbat
  @num_mbat
end

#num_sbatInteger

Returns Number of SBAT blocks.

Returns:

  • (Integer)

    Number of SBAT blocks



60
61
62
# File 'lib/omnizip/formats/ole/header.rb', line 60

def num_sbat
  @num_sbat
end

#reservedString

Returns 6-byte reserved field.

Returns:

  • (String)

    6-byte reserved field



39
40
41
# File 'lib/omnizip/formats/ole/header.rb', line 39

def reserved
  @reserved
end

#s_shiftInteger

Returns Small block shift (6 = 64 bytes).

Returns:

  • (Integer)

    Small block shift (6 = 64 bytes)



36
37
38
# File 'lib/omnizip/formats/ole/header.rb', line 36

def s_shift
  @s_shift
end

#sbat_startInteger

Returns First block of SBAT.

Returns:

  • (Integer)

    First block of SBAT



57
58
59
# File 'lib/omnizip/formats/ole/header.rb', line 57

def sbat_start
  @sbat_start
end

#thresholdInteger

Returns Small block threshold (4096).

Returns:

  • (Integer)

    Small block threshold (4096)



54
55
56
# File 'lib/omnizip/formats/ole/header.rb', line 54

def threshold
  @threshold
end

#transacting_signatureString

Returns 4-byte transaction signature.

Returns:

  • (String)

    4-byte transaction signature



51
52
53
# File 'lib/omnizip/formats/ole/header.rb', line 51

def transacting_signature
  @transacting_signature
end

Class Method Details

.createHeader

Create default header for new documents

Returns:

  • (Header)

    New header with default values



88
89
90
91
92
# File 'lib/omnizip/formats/ole/header.rb', line 88

def self.create
  header = new
  header.apply_defaults
  header
end

.parse(data) ⇒ Header

Parse header from binary data

Parameters:

  • data (String)

    512-byte header block

Returns:

  • (Header)

    Parsed header object

Raises:

  • (ArgumentError)

    If data is invalid



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/omnizip/formats/ole/header.rb', line 73

def self.parse(data)
  if data.nil? || data.bytesize < HEADER_SIZE
    raise ArgumentError,
          "Header data too short"
  end

  header = new
  header.unpack(data)
  header.validate!
  header
end

Instance Method Details

#apply_defaultsObject

Apply default values



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/omnizip/formats/ole/header.rb', line 100

def apply_defaults
  @magic = MAGIC.dup
  @clsid = "\x00".b * 16
  @minor_ver = 59
  @major_ver = 3
  @byte_order = BYTE_ORDER_LE.dup
  @b_shift = DEFAULT_BIG_BLOCK_SHIFT
  @s_shift = DEFAULT_SMALL_BLOCK_SHIFT
  @reserved = "\x00".b * 6
  @csectdir = 0
  @num_bat = 1
  @dirent_start = EOC
  @transacting_signature = "\x00".b * 4
  @threshold = DEFAULT_THRESHOLD
  @sbat_start = EOC
  @num_sbat = 0
  @mbat_start = EOC
  @num_mbat = 0
end

#big_block_sizeInteger

Get big block size

Returns:

  • (Integer)

    Block size in bytes



123
124
125
# File 'lib/omnizip/formats/ole/header.rb', line 123

def big_block_size
  1 << @b_shift
end

#packString

Pack header to binary data

Returns:

  • (String)

    76-byte header binary data



161
162
163
164
165
166
167
168
# File 'lib/omnizip/formats/ole/header.rb', line 161

def pack
  [
    @magic, @clsid, @minor_ver, @major_ver, @byte_order,
    @b_shift, @s_shift, @reserved, @csectdir, @num_bat,
    @dirent_start, @transacting_signature, @threshold,
    @sbat_start, @num_sbat, @mbat_start, @num_mbat
  ].pack(PACK)
end

#small_block_sizeInteger

Get small block size

Returns:

  • (Integer)

    Block size in bytes



130
131
132
# File 'lib/omnizip/formats/ole/header.rb', line 130

def small_block_size
  1 << @s_shift
end

#unpack(data) ⇒ Object

Unpack header from binary data

Parameters:

  • data (String)

    Binary data



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/omnizip/formats/ole/header.rb', line 137

def unpack(data)
  values = data[0, HEADER_SIZE].unpack(PACK)
  @magic = values[0]
  @clsid = values[1]
  @minor_ver = values[2]
  @major_ver = values[3]
  @byte_order = values[4]
  @b_shift = values[5]
  @s_shift = values[6]
  @reserved = values[7]
  @csectdir = values[8]
  @num_bat = values[9]
  @dirent_start = values[10]
  @transacting_signature = values[11]
  @threshold = values[12]
  @sbat_start = values[13]
  @num_sbat = values[14]
  @mbat_start = values[15]
  @num_mbat = values[16]
end

#validate!Object

Validate header structure

Raises:

  • (ArgumentError)

    If header is invalid



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/omnizip/formats/ole/header.rb', line 173

def validate!
  unless @magic == MAGIC
    raise ArgumentError, "Invalid OLE magic signature"
  end

  if @num_bat.zero?
    raise ArgumentError, "Invalid OLE: no BAT blocks"
  end

  if @s_shift > @b_shift || @b_shift <= 6 || @b_shift >= 31
    raise ArgumentError, "Invalid block shift values"
  end

  unless @byte_order == BYTE_ORDER_LE
    raise ArgumentError, "Only little-endian OLE files are supported"
  end

  if @threshold != DEFAULT_THRESHOLD
    # Warning, not error
  end

  true
end