-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathimg3file.rb
100 lines (89 loc) · 2.51 KB
/
img3file.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
require 'bit-struct'
require 'pp'
class Header < BitStruct
default_options :endian=>:native
unsigned :signature, 32, "signature"
unsigned :full_size, 32, "full_size"
unsigned :data_size, 32, "data_size"
unsigned :shsh_offset, 32, "shsh_offset"
unsigned :image_type, 32, "image_type"
end
class ElementHeader < BitStruct
default_options :endian=>:native
unsigned :signature, 32, "signature"
unsigned :full_size, 32, "full_size"
unsigned :data_size, 32, "data_size"
end
class Element < BitStruct
default_options :endian=>:native
nest :header, ElementHeader
rest :data, "data"
end
class Img3File
attr_accessor :header, :elements, :elementkeys
def parse(input)
data = input.read(Header.round_byte_length)
@header = Header.new data
@elements, @elementkeys = self.parse_elements(input, @header.full_size)
end
def parse_elements(input, total_len)
elements = []
elementkeys = []
#
pos = Header.round_byte_length
while pos < total_len do
#p "#{pos}/#{@header.full_size}"
data = input.read(ElementHeader.round_byte_length)
if data.nil?
break
end
h = ElementHeader.new data
elementkeys += [h.signature]
element = Element.new
element.header = h
element.data = input.read(h.full_size-ElementHeader.round_byte_length)
elements += [element]
pos += h.full_size
end
# self
[elements, elementkeys]
end
def update_elements(input, total_len)
# parse
elements, elementkeys = parse_elements(input, total_len)
pp elementkeys
# update keys
tmp = []
@elements.each do |e|
if not elementkeys.include?(e.header.signature)
tmp += [e]
end
end
# update
@elements = tmp + elements
@elementkeys = elementkeys
end
def to_s
tmp = StringIO.new
header = Header.new
pos = 0
@elements.each do |e|
#p "#{pos}/#{@header.full_size} #{e.header.signature}"
if e.header.signature == "SHSH".reverse.unpack("i*")[0] # 0x53485348, 1397248840
# 53485348
header.shsh_offset = pos
end
tmp << e.to_s
pos += e.header.full_size
end
header.signature = @header.signature
header.full_size = pos + Header.round_byte_length
header.data_size = pos
header.image_type = @header.image_type
output = StringIO.new
output << header.to_s
output << tmp.string
output.rewind
output.read
end
end