resedit 1.5.1 → 1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/resedit.rb +5 -1
- data/lib/resedit/app/app.rb +2 -3
- data/lib/resedit/app/app_command.rb +2 -2
- data/lib/resedit/app/mz_command.rb +2 -5
- data/lib/resedit/app/std_commands.rb +0 -1
- data/lib/resedit/classes/changeable.rb +299 -0
- data/lib/resedit/{app → classes}/colorizer.rb +6 -2
- data/lib/resedit/{mz → classes}/hexwriter.rb +2 -2
- data/lib/resedit/convert/codepatch.rb +66 -0
- data/lib/resedit/mz/mz.rb +8 -8
- data/lib/resedit/mz/mz_body.rb +38 -37
- data/lib/resedit/mz/mz_header.rb +32 -14
- data/lib/resedit/mz/mzenv.rb +1 -1
- data/lib/resedit/text/huffman.rb +1 -1
- data/lib/resedit/text/text.rb +1 -1
- metadata +8 -7
- data/lib/resedit/mz/changeable.rb +0 -248
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5b4e01f23eab7befb55f58374b179252e580ba27
|
|
4
|
+
data.tar.gz: c70bea5859d5fcdb2c62379956034d641336d320
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bec413733f867fe85b74bfbb07f99bcb4be3b161f3a3539cf50ed5312e03365accff257b81a107308c1ad205e0c8eb7779f330bb62414e3c508af802ce64edab
|
|
7
|
+
data.tar.gz: f6ef54cd8d085aaf2821f3b7821ccdbaa4c15ac26a4cf38b734091f0095b6626a7333f673a1ccaa72bc49075fbec2d57839dd9588391a46fc25ea7dc2744b9a0
|
data/lib/resedit.rb
CHANGED
|
@@ -9,9 +9,13 @@ require 'resedit/text/huffman'
|
|
|
9
9
|
require 'resedit/app/font_convert'
|
|
10
10
|
require 'resedit/app/text_convert'
|
|
11
11
|
require 'resedit/convert/bitconv'
|
|
12
|
+
require 'resedit/convert/codepatch'
|
|
12
13
|
require 'resedit/mz/mz'
|
|
14
|
+
require 'resedit/classes/colorizer'
|
|
15
|
+
require 'resedit/classes/hexwriter'
|
|
16
|
+
require 'resedit/classes/changeable'
|
|
13
17
|
|
|
14
18
|
|
|
15
19
|
module Resedit
|
|
16
|
-
VERSION = "1.
|
|
20
|
+
VERSION = "1.6"
|
|
17
21
|
end
|
data/lib/resedit/app/app.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'resedit/app/std_commands'
|
|
2
2
|
require 'resedit/app/mz_command'
|
|
3
|
-
require 'resedit/
|
|
3
|
+
require 'resedit/classes/colorizer'
|
|
4
4
|
require 'logger'
|
|
5
5
|
require 'readline'
|
|
6
6
|
|
|
@@ -34,7 +34,7 @@ module Resedit
|
|
|
34
34
|
@cmds[n] = c;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
@col = Colorizer.
|
|
37
|
+
@col = Colorizer.instance()
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
|
|
@@ -83,7 +83,6 @@ module Resedit
|
|
|
83
83
|
return nil if cmd.length()==0 || cmd[0][0]=='#'
|
|
84
84
|
c = @cmds[cmd[0]]
|
|
85
85
|
raise "Unknown command: #{cmd[0]}" if !c
|
|
86
|
-
res=[]
|
|
87
86
|
prms = c.parseParams(cmd[1..-1])
|
|
88
87
|
return c,prms
|
|
89
88
|
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require 'resedit/app/app'
|
|
2
1
|
require 'resedit/app/app_command'
|
|
3
2
|
require 'resedit/mz/mz'
|
|
4
3
|
require 'resedit/mz/mzenv'
|
|
@@ -15,14 +14,14 @@ module Resedit
|
|
|
15
14
|
addParam('p3', "mz command parameter","")
|
|
16
15
|
addParam('p4', "mz command parameter","")
|
|
17
16
|
addParam('p5', "mz command parameter","")
|
|
18
|
-
addOption('help', 'h',
|
|
17
|
+
addOption('help', 'h', false, 'help on mz commands')
|
|
19
18
|
@cmds = {
|
|
20
19
|
"help"=>[method(:help), "show help on mz commands", {"command" => "command to show help on"}],
|
|
21
20
|
"use"=>[method(:use), "select mz file", {"file" => "path to mz file"}],
|
|
22
21
|
"save"=>[method(:save), "save current file",{"filename" => "filename fir saving", "final"=>"don't save changes"}],
|
|
23
22
|
"close"=>[method(:close), "close file", {"file" => "path or id of file to close"}],
|
|
24
23
|
"print"=>[method(:info), "print info about mz objects", {"what" => "files/header/reloc/changes", "how" => "original/modified"}],
|
|
25
|
-
"append"=>[method(:append), "add bytes to current file", {"value" => "value", "type" => "value type", }],
|
|
24
|
+
"append"=>[method(:append), "add bytes to current file", {"value" => "value", "type" => "value type", "where" => "append offset. default: above ss:sp"}],
|
|
26
25
|
"replace"=>[method(:replace), "replace added bytes", {"value" => "value", "type"=>"value type"}],
|
|
27
26
|
"change"=>[method(:change), "change bytes at offset", {"ofs" => "data ofset", "value" => "value", "disp" => "code/file", "type"=>"value type"}],
|
|
28
27
|
"reloc"=>[method(:reloc), "add relocation", {"value" => "value"}],
|
|
@@ -94,7 +93,6 @@ module Resedit
|
|
|
94
93
|
|
|
95
94
|
|
|
96
95
|
def use(params)
|
|
97
|
-
App::get().col.on = true
|
|
98
96
|
mz = getfile(params['file'])
|
|
99
97
|
if mz==nil
|
|
100
98
|
mz = MZ.new(params['file'])
|
|
@@ -113,7 +111,6 @@ module Resedit
|
|
|
113
111
|
mz.close()
|
|
114
112
|
mz = nil
|
|
115
113
|
@cur = @files[0] if !@cur && @files.length > 0
|
|
116
|
-
App::get().col.on = false if @files.length == 0
|
|
117
114
|
info()
|
|
118
115
|
end
|
|
119
116
|
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
require 'resedit/classes/colorizer'
|
|
2
|
+
require 'resedit/classes/hexwriter'
|
|
3
|
+
require 'logger'
|
|
4
|
+
|
|
5
|
+
module Resedit
|
|
6
|
+
|
|
7
|
+
class Changeable
|
|
8
|
+
HOW_CHANGED = 0
|
|
9
|
+
HOW_ORIGINAL = 1
|
|
10
|
+
COL_CHANGED = Colorizer::YELLOW
|
|
11
|
+
COL_ORIGINAL = Colorizer::PURPLE
|
|
12
|
+
LOG = Logger.new(STDOUT)
|
|
13
|
+
|
|
14
|
+
class Change
|
|
15
|
+
|
|
16
|
+
attr_accessor :buf, :sz, :n, :obuf, :nbuf
|
|
17
|
+
|
|
18
|
+
def initialize(obuf=nil, nbuf=nil)
|
|
19
|
+
@n = nil
|
|
20
|
+
@mode = HOW_CHANGED
|
|
21
|
+
_updbufs(obuf, nbuf)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def _updbufs(obuf=nil, nbuf=nil)
|
|
25
|
+
@obuf = obuf ? obuf : ''
|
|
26
|
+
@nbuf = nbuf
|
|
27
|
+
mode()
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def mode(mode=nil)
|
|
31
|
+
@mode = mode if mode
|
|
32
|
+
@buf = (@mode == HOW_CHANGED && @nbuf) ? @nbuf : @obuf
|
|
33
|
+
@sz = @buf.length
|
|
34
|
+
@n.mode(mode) if @n && mode
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def data(ofs, size)
|
|
38
|
+
return @n.data(ofs - @sz, size) if ofs > @sz
|
|
39
|
+
return @buf[ofs .. -1] + @n.data(0, size - @sz + ofs) if @sz < ofs+size
|
|
40
|
+
return @buf[ofs, size]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def all; return @buf + (@n ? @n.all() : '') end
|
|
44
|
+
def size; return @sz + (@n ? @n.size() : 0) end
|
|
45
|
+
|
|
46
|
+
def split(ofs, data, nu=false)
|
|
47
|
+
if ofs+(nu ? 0 : data.length) == @sz
|
|
48
|
+
tail = @n
|
|
49
|
+
else
|
|
50
|
+
ntail = @nbuf ? @nbuf[ofs + (nu ? 0 : data.length) .. -1] : nil
|
|
51
|
+
tail = Change.new(@obuf[ofs + (nu ? 0 : data.length) .. -1], ntail)
|
|
52
|
+
tail.n = @n
|
|
53
|
+
end
|
|
54
|
+
if ofs != 0
|
|
55
|
+
body = Change.new(nu ? nil : @obuf[ofs, data.length], data)
|
|
56
|
+
body.n = tail
|
|
57
|
+
_updbufs(@buf[0, ofs], @nbuf ? @nbuf[0, ofs] : nil)
|
|
58
|
+
@n = body
|
|
59
|
+
else
|
|
60
|
+
_updbufs(nu ? nil : @obuf[0, data.length], data)
|
|
61
|
+
@n = tail
|
|
62
|
+
end
|
|
63
|
+
mode(@mode)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def insert(ofs, data)
|
|
67
|
+
return @sz + @n.insert(ofs - @sz, data) if ofs > @sz
|
|
68
|
+
LOG.debug("inserting #{data} @#{ofs} of #{@buf} #{@sz}")
|
|
69
|
+
if @nbuf
|
|
70
|
+
@nbuf = @nbuf[0, ofs] + data + @nbuf[ofs..-1]
|
|
71
|
+
mode()
|
|
72
|
+
return ofs
|
|
73
|
+
end
|
|
74
|
+
split(ofs, data, true)
|
|
75
|
+
mode()
|
|
76
|
+
return ofs
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def change(ofs, data)
|
|
80
|
+
return @sz + @n.change(ofs - @sz, data) if ofs > @sz
|
|
81
|
+
nxt = data.length - @sz + ofs
|
|
82
|
+
size = nxt>0 ? data.length-nxt : data.length
|
|
83
|
+
@n.change(0, data[size..-1]) if nxt > 0
|
|
84
|
+
if @nbuf
|
|
85
|
+
@nbuf = @nbuf[0,ofs] + data[0, size] + @nbuf[ofs+size..-1]
|
|
86
|
+
mode()
|
|
87
|
+
return ofs
|
|
88
|
+
end
|
|
89
|
+
split(ofs, data[0, size])
|
|
90
|
+
mode()
|
|
91
|
+
return ofs
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def undo(ofs)
|
|
95
|
+
LOG.debug("undo #{ofs} #{@buf}")
|
|
96
|
+
return @n.undo(ofs - @sz) if ofs >= @sz
|
|
97
|
+
raise "Change not found @#{ofs}" if ofs != 0 || !@nbuf
|
|
98
|
+
@nbuf = nil
|
|
99
|
+
mode()
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def revert
|
|
103
|
+
@nbuf = nil
|
|
104
|
+
mode()
|
|
105
|
+
@n.revert if @n
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def changed?(ofs, size)
|
|
109
|
+
return @n.changed?(ofs - @sz, size) if ofs >= @sz
|
|
110
|
+
return true if @nbuf
|
|
111
|
+
return @n.changed?(0, size - @sz + ofs) if @sz < ofs+size
|
|
112
|
+
return false
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def hex(writer, ofs, size, col)
|
|
116
|
+
if ofs > @sz
|
|
117
|
+
return size if !n
|
|
118
|
+
return n.hex(writer, ofs - @sz, size, col)
|
|
119
|
+
end
|
|
120
|
+
sz = @sz < ofs+size ? @sz-ofs : size
|
|
121
|
+
writer.addBytes(@buf[ofs, sz], @nbuf ? col : nil)
|
|
122
|
+
return 0 if sz==size
|
|
123
|
+
return n.hex(writer, 0, size-sz, col) if n
|
|
124
|
+
return size-sz
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def getChanges(ofs=0)
|
|
128
|
+
ch = {}
|
|
129
|
+
if @nbuf
|
|
130
|
+
ch[ofs] = [@obuf, @nbuf]
|
|
131
|
+
end
|
|
132
|
+
ch = ch.merge(@n.getChanges(ofs+@sz)) if @n
|
|
133
|
+
return ch
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def normalize()
|
|
137
|
+
while @n && !@nbuf && @obuf.length==0
|
|
138
|
+
@obuf = @n.obuf
|
|
139
|
+
@nbuf = @n.nbuf
|
|
140
|
+
@n = @n.n
|
|
141
|
+
end
|
|
142
|
+
@n=@n.n while @n && !@n.nbuf && @n.obuf.length==0
|
|
143
|
+
while @n &&
|
|
144
|
+
((@obuf.length>0 && @n.obuf.length>0) || (@obuf.length == 0 && @n.obuf.length==0)) &&
|
|
145
|
+
((@nbuf && @n.nbuf) || (!@nbuf && !@n.nbuf))
|
|
146
|
+
@obuf += @n.obuf
|
|
147
|
+
@nbuf = @nbuf ? @nbuf+@n.nbuf : nil
|
|
148
|
+
@n=@n.n
|
|
149
|
+
end
|
|
150
|
+
mode()
|
|
151
|
+
@n.normalize() if @n
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def dump()
|
|
155
|
+
printf("#{@sz}:O(#{@obuf.length})\t\t%s\n", @nbuf ? "N(#{@nbuf.length if @nbuf})" : "")
|
|
156
|
+
@n.dump() if @n
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def cload(ofs, bytes, len)
|
|
160
|
+
LOG.debug("load #{ofs} #{bytes} #{len}")
|
|
161
|
+
return @n.cload(ofs - @sz, bytes, len) if ofs > @sz
|
|
162
|
+
change(ofs, bytes.length>0 ? bytes : '*'*len)
|
|
163
|
+
nd = ofs==0 ? self : @n
|
|
164
|
+
nd.nbuf = nd.obuf
|
|
165
|
+
nd.obuf = bytes
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Changeable
|
|
170
|
+
|
|
171
|
+
def initialize(fileOrBytes, fileSize=nil)
|
|
172
|
+
LOG.level = Logger::INFO
|
|
173
|
+
@col = Colorizer.instance()
|
|
174
|
+
@mode = HOW_CHANGED
|
|
175
|
+
@root = nil
|
|
176
|
+
addData(fileOrBytes, fileSize)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def addData(fileOrBytes, size=nil)
|
|
180
|
+
if fileOrBytes.is_a?(IO)
|
|
181
|
+
data = fileOrBytes.read(size)
|
|
182
|
+
else
|
|
183
|
+
data = fileOrBytes
|
|
184
|
+
end
|
|
185
|
+
data = @root.buf + data if @root
|
|
186
|
+
@root = Change.new(data)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def mode(how)
|
|
191
|
+
@root.mode(how)
|
|
192
|
+
@mode = how
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def insert(offset, data)
|
|
196
|
+
return if !data || !data.length
|
|
197
|
+
@root.insert(offset, data)
|
|
198
|
+
@root.normalize()
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def undo(offset)
|
|
202
|
+
@root.undo(offset)
|
|
203
|
+
@root.normalize()
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def change(ofs, bytes)
|
|
207
|
+
@root.change(ofs, bytes)
|
|
208
|
+
@root.normalize()
|
|
209
|
+
return ofs
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def changed?(ofs, size=1); return @root.changed?(ofs, size) end
|
|
213
|
+
|
|
214
|
+
def debug(); LOG.level = Logger::DEBUG end
|
|
215
|
+
|
|
216
|
+
def dbgdump
|
|
217
|
+
LOG.debug("---#{@root.size()}---\n")
|
|
218
|
+
@root.dump()
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def getData(ofs, size); return @root.data(ofs, size) end
|
|
222
|
+
|
|
223
|
+
def bytes; return @root.all() end
|
|
224
|
+
|
|
225
|
+
def getChanges; @root.getChanges(); end
|
|
226
|
+
|
|
227
|
+
def revert(what)
|
|
228
|
+
if what=='all'
|
|
229
|
+
@root.revert()
|
|
230
|
+
@root.normalize()
|
|
231
|
+
return true
|
|
232
|
+
end
|
|
233
|
+
undo(what)
|
|
234
|
+
return true
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def curcol; @mode == HOW_ORIGINAL ? COL_ORIGINAL : COL_CHANGED end
|
|
239
|
+
|
|
240
|
+
def colVal(ofs, size)
|
|
241
|
+
fmt = "%#{size*2}.#{size*2}X"
|
|
242
|
+
u = size == 2 ? "v" : V
|
|
243
|
+
return colStr( sprintf(fmt, getData(ofs, size).unpack(u)[0]) , changed?(ofs,size))
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def colStr(str, cond=true)
|
|
247
|
+
str = sprintf("%04X", str) if !str.is_a?(String)
|
|
248
|
+
return str if !cond
|
|
249
|
+
return @col.color(curcol(), str)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def parseHow(how)
|
|
254
|
+
return HOW_CHANGED if !how || how == HOW_CHANGED
|
|
255
|
+
return HOW_ORIGINAL if how == HOW_ORIGINAL
|
|
256
|
+
return HOW_ORIGINAL if how[0] == 'o' || how[0] == 'O'
|
|
257
|
+
return HOW_CHANGED
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def hex(writer, ofs, size, how)
|
|
262
|
+
mode(parseHow(how))
|
|
263
|
+
col = curcol()
|
|
264
|
+
return @root.hex(writer, ofs, size, col)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def saveData(file)
|
|
269
|
+
mode(HOW_CHANGED)
|
|
270
|
+
file.write(bytes())
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def saveChanges(file)
|
|
274
|
+
mode(HOW_CHANGED)
|
|
275
|
+
chs = getChanges()
|
|
276
|
+
file.write([chs.length].pack('V'))
|
|
277
|
+
chs.each{|o,bts|
|
|
278
|
+
flg = bts[0].length==0 ? 0x80000000 : 0
|
|
279
|
+
file.write([o, bts[1].length | flg ].pack('VV'))
|
|
280
|
+
file.write(bts[0]) if flg==0
|
|
281
|
+
}
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def loadChanges(file)
|
|
285
|
+
mode(HOW_CHANGED)
|
|
286
|
+
@root.revert
|
|
287
|
+
clen = file.read(4).unpack('V')[0]
|
|
288
|
+
for _ in 0..clen-1
|
|
289
|
+
ofs, len = file.read(8).unpack('VV')
|
|
290
|
+
isNu = len & 0x80000000 !=0
|
|
291
|
+
len &= 0x7FFFFFFF
|
|
292
|
+
@root.cload(ofs, isNu ? "" : file.read(len), len)
|
|
293
|
+
end
|
|
294
|
+
mode(HOW_CHANGED)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
1
3
|
module Resedit
|
|
2
4
|
|
|
3
5
|
class Colorizer
|
|
@@ -12,8 +14,10 @@ module Resedit
|
|
|
12
14
|
|
|
13
15
|
attr_accessor :on
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
include Singleton
|
|
18
|
+
|
|
19
|
+
def initialize()
|
|
20
|
+
@on = true
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
def color(col, text)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require 'resedit/
|
|
1
|
+
require 'resedit/classes/colorizer'
|
|
2
2
|
|
|
3
3
|
module Resedit
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ module Resedit
|
|
|
10
10
|
@written = 0
|
|
11
11
|
@charsInLine = 0x10
|
|
12
12
|
@addr = addr
|
|
13
|
-
@col =
|
|
13
|
+
@col = Colorizer.instance()
|
|
14
14
|
@size = 0
|
|
15
15
|
@line = nil
|
|
16
16
|
@cline = ''
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Resedit
|
|
2
|
+
|
|
3
|
+
class CodePatch
|
|
4
|
+
FMT_BINARY = 0
|
|
5
|
+
FMT_HEXSTRING = 1
|
|
6
|
+
|
|
7
|
+
class Chunk
|
|
8
|
+
NOP = "\x90"
|
|
9
|
+
attr_reader :data, :ofs, :size, :format
|
|
10
|
+
|
|
11
|
+
def initialize(data, format, splitter=NOP)
|
|
12
|
+
splitter.force_encoding(Encoding::ASCII_8BIT)
|
|
13
|
+
@data, @format = data, format
|
|
14
|
+
@ofs, @size = [], []
|
|
15
|
+
ofs=0
|
|
16
|
+
data.split(splitter).each{ |part|
|
|
17
|
+
@ofs += [ofs]
|
|
18
|
+
@size += [part.length()]
|
|
19
|
+
ofs += part.length+1
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def addr(idx, adr)
|
|
24
|
+
adr[0] += @ofs[idx]
|
|
25
|
+
return adr
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def hexdata()
|
|
29
|
+
@data.each_byte.map { |b| sprintf("%02X",b) }.join
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def value(idx, size, adr = nil, rep = "\xFF\xFF\xFF\xFF")
|
|
33
|
+
NOP.force_encoding(Encoding::ASCII_8BIT)
|
|
34
|
+
rep.force_encoding(Encoding::ASCII_8BIT)
|
|
35
|
+
ret = data[@ofs[idx], @size[idx]]
|
|
36
|
+
if adr and rep
|
|
37
|
+
#replace with seg:ofs
|
|
38
|
+
ret.gsub!(rep, mkadr(adr))
|
|
39
|
+
end
|
|
40
|
+
raise "Code is bigger #{ret.length()} than expected #{size}" if ret.length>size
|
|
41
|
+
while ret.length()<size
|
|
42
|
+
ret += NOP
|
|
43
|
+
end
|
|
44
|
+
if @format == CodePatch::FMT_HEXSTRING
|
|
45
|
+
ret = ret.each_byte.map { |b| sprintf("%02X",b) }.join
|
|
46
|
+
end
|
|
47
|
+
return ret
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def mkadr(adr)
|
|
51
|
+
ret = (adr[0]&0xFF).chr + ((adr[0]>>8)&0xFF).chr
|
|
52
|
+
ret += (adr[1]&0xFF).chr + ((adr[1]>>8)&0xFF).chr
|
|
53
|
+
return ret
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.loadPatch(fname, format = FMT_HEXSTRING, chunksplit="\x90\x90\x90\x90\x90")
|
|
59
|
+
chunksplit.force_encoding(Encoding::ASCII_8BIT)
|
|
60
|
+
bytes = File.read(fname, encoding:Encoding::ASCII_8BIT)
|
|
61
|
+
return bytes.split(chunksplit).each.map{|data| CodePatch::Chunk.new(data, format)}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
data/lib/resedit/mz/mz.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'resedit/mz/mz_header'
|
|
2
2
|
require 'resedit/mz/mz_body'
|
|
3
|
-
require 'resedit/
|
|
3
|
+
require 'resedit/classes/hexwriter'
|
|
4
4
|
require 'resedit/mz/mzenv'
|
|
5
5
|
|
|
6
6
|
module Resedit
|
|
@@ -32,7 +32,7 @@ module Resedit
|
|
|
32
32
|
@name = File.basename(@path, ".*")
|
|
33
33
|
hi = @header.info()
|
|
34
34
|
env().set(:entry, hi[:CS].to_s+":"+hi[:IP].to_s)
|
|
35
|
-
env().set(:append, sprintf("
|
|
35
|
+
env().set(:append, sprintf("0:0"))
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
|
|
@@ -90,8 +90,9 @@ module Resedit
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
def append(value, type=nil)
|
|
94
|
-
|
|
93
|
+
def append(value, type=nil, where=nil)
|
|
94
|
+
where = s2i(where) if where
|
|
95
|
+
res = @body.append(getValue(value,type), where)
|
|
95
96
|
s = ""
|
|
96
97
|
res.each{|a|
|
|
97
98
|
if a.is_a?(Array)
|
|
@@ -105,9 +106,9 @@ module Resedit
|
|
|
105
106
|
end
|
|
106
107
|
|
|
107
108
|
|
|
108
|
-
def replace(value, type=nil)
|
|
109
|
+
def replace(value, type=nil, where=nil)
|
|
109
110
|
@body.removeAppend()
|
|
110
|
-
return append(value,type)
|
|
111
|
+
return append(value,type, where)
|
|
111
112
|
end
|
|
112
113
|
|
|
113
114
|
|
|
@@ -120,7 +121,7 @@ module Resedit
|
|
|
120
121
|
else
|
|
121
122
|
res = @body.change(ofs,value) + @header.headerSize()
|
|
122
123
|
end
|
|
123
|
-
log("Change added at %08X", res)
|
|
124
|
+
log("Change added at %08X", res) if res
|
|
124
125
|
end
|
|
125
126
|
|
|
126
127
|
def reloc(ofs)
|
|
@@ -167,7 +168,6 @@ module Resedit
|
|
|
167
168
|
}
|
|
168
169
|
end
|
|
169
170
|
|
|
170
|
-
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
end
|
data/lib/resedit/mz/mz_body.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require 'resedit/
|
|
1
|
+
require 'resedit/classes/changeable'
|
|
2
|
+
|
|
2
3
|
begin
|
|
3
4
|
require 'crabstone'
|
|
4
5
|
include Crabstone
|
|
@@ -12,10 +13,16 @@ module Resedit
|
|
|
12
13
|
|
|
13
14
|
class MZBody < Changeable
|
|
14
15
|
|
|
15
|
-
attr_reader :segments, :appSeg
|
|
16
|
+
attr_reader :segments, :appSeg, :mz
|
|
16
17
|
|
|
17
18
|
def initialize(mz, file, size)
|
|
18
|
-
|
|
19
|
+
@mz = mz
|
|
20
|
+
super(file, size)
|
|
21
|
+
@segments = nil
|
|
22
|
+
@addsz = 0
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def reloadSegments()
|
|
19
26
|
@segments = Set.new()
|
|
20
27
|
for i in 0..@mz.header.info[:NumberOfRelocations]-1
|
|
21
28
|
r = @mz.header.getRelocation(i)
|
|
@@ -23,22 +30,25 @@ module Resedit
|
|
|
23
30
|
val = segData(r, 2).unpack('v')[0]
|
|
24
31
|
@segments.add(val)
|
|
25
32
|
end
|
|
26
|
-
@appSeg = (@realSize >> 4) + 1
|
|
27
33
|
end
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
def patchRelocs(add)
|
|
36
|
+
@segments = Set.new()
|
|
37
|
+
for i in 0..@mz.header.info[:NumberOfRelocations]-1
|
|
38
|
+
r = @mz.header.getRelocation(i)
|
|
39
|
+
@segments.add(r[1])
|
|
40
|
+
ofs = seg2Linear(r[0], r[1])
|
|
41
|
+
val = getData(ofs, 2).unpack('v')[0] + add
|
|
42
|
+
change(ofs, [val].pack('v'))
|
|
43
|
+
@segments.add(val)
|
|
44
|
+
end
|
|
34
45
|
end
|
|
35
46
|
|
|
36
|
-
|
|
37
47
|
def seg2Linear(a,s) (s << 4) + a end
|
|
38
48
|
|
|
39
|
-
|
|
40
49
|
def seg4Linear(linear)
|
|
41
50
|
linear >>= 4
|
|
51
|
+
reloadSegments() if !@segments
|
|
42
52
|
min = @segments.sort.reverse.find{|e| e <= linear}
|
|
43
53
|
return min ? min : 0
|
|
44
54
|
end
|
|
@@ -58,51 +68,42 @@ module Resedit
|
|
|
58
68
|
|
|
59
69
|
def segData(reloc, size, isStr=false)
|
|
60
70
|
ofs = seg2Linear(reloc[0], reloc[1])
|
|
61
|
-
return "None" if ofs
|
|
71
|
+
#return "None" if ofs > @root.size()
|
|
62
72
|
return getData(ofs, size) if !isStr
|
|
63
73
|
return colVal(ofs, size)
|
|
64
74
|
end
|
|
65
75
|
|
|
66
76
|
|
|
67
77
|
def removeAppend()
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
super()
|
|
78
|
+
mode(HOW_CHANGED)
|
|
79
|
+
undo(0) if @root.obuf.length==0
|
|
80
|
+
@addsz = 0
|
|
72
81
|
end
|
|
73
82
|
|
|
74
|
-
|
|
75
83
|
def revert(what)
|
|
76
|
-
@realOfs = @mz.header.headerSize()
|
|
77
84
|
super(what)
|
|
85
|
+
@addsz = 0
|
|
78
86
|
end
|
|
79
87
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
bytes = ("\x90" * res).force_encoding(Encoding::ASCII_8BIT) + bytes if res > 0
|
|
90
|
-
end
|
|
91
|
-
res += super(bytes)
|
|
92
|
-
@mz.header.setCodeSize(@bytes.length + @add.length)
|
|
88
|
+
def append(bytes, where=nil)
|
|
89
|
+
mode(HOW_CHANGED)
|
|
90
|
+
res = @addsz
|
|
91
|
+
buf = @addsz>0 ? @root.nbuf[0, @addsz] : ''
|
|
92
|
+
buf += bytes
|
|
93
|
+
removeAppend()
|
|
94
|
+
@addsz = buf.length
|
|
95
|
+
sz = @mz.header.rebuildHeader(@addsz)
|
|
96
|
+
insert(0, bytes + "\x00"*(sz-@addsz))
|
|
93
97
|
seg = linear2seg(res)
|
|
94
|
-
res = [res, seg]
|
|
95
|
-
|
|
96
|
-
raise "Segs not match" if (@appSeg << 4) != res[0]
|
|
97
|
-
@segments.add(@appSeg)
|
|
98
|
-
res += [ [ 0, @appSeg] ]
|
|
99
|
-
end
|
|
98
|
+
res = [res, seg, sz/0x10]
|
|
99
|
+
patchRelocs(sz/0x10)
|
|
100
100
|
return res
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
def print(what, how)
|
|
105
105
|
if what=="header"
|
|
106
|
+
reloadSegments() if !@segments
|
|
106
107
|
puts "Known segments: " + @segments.sort.map{ |i| sprintf('%04X',i) }.join(", ")
|
|
107
108
|
return true
|
|
108
109
|
end
|
data/lib/resedit/mz/mz_header.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require 'resedit/
|
|
1
|
+
require 'resedit/classes/changeable'
|
|
2
2
|
|
|
3
3
|
module Resedit
|
|
4
4
|
|
|
@@ -8,17 +8,18 @@ module Resedit
|
|
|
8
8
|
PARA = 0x10
|
|
9
9
|
HSIZE = 0x1C
|
|
10
10
|
|
|
11
|
-
attr_reader :info
|
|
11
|
+
attr_reader :info, :mz
|
|
12
12
|
|
|
13
13
|
def initialize(mz, file, size)
|
|
14
14
|
raise "Not MZ file" if size < HSIZE
|
|
15
|
-
|
|
15
|
+
@mz = mz
|
|
16
|
+
super(file, HSIZE)
|
|
16
17
|
@fsize = size
|
|
17
18
|
@_infoOrig = loadInfo()
|
|
18
19
|
@_info = nil
|
|
19
20
|
@info = @_infoOrig
|
|
20
21
|
raise "Not MZ file" if MAGIC != @info[:Magic]
|
|
21
|
-
|
|
22
|
+
addData(file, headerSize() - HSIZE)
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
|
|
@@ -56,8 +57,22 @@ module Resedit
|
|
|
56
57
|
change(2, ch.pack('vv'))
|
|
57
58
|
end
|
|
58
59
|
|
|
59
|
-
def
|
|
60
|
-
|
|
60
|
+
def rebuildHeader(codesize)
|
|
61
|
+
mode(HOW_ORIGINAL)
|
|
62
|
+
ss = @info[:SS]
|
|
63
|
+
cs = @info[:CS]
|
|
64
|
+
sz = fileSize()-headerSize()
|
|
65
|
+
codesize += PARA - codesize % PARA if codesize % PARA!=0
|
|
66
|
+
changeSize(sz + codesize + headerSize())
|
|
67
|
+
paras = codesize / PARA
|
|
68
|
+
change(14, [ss+paras].pack('v'))
|
|
69
|
+
change(22, [cs+paras].pack('v'))
|
|
70
|
+
for i in 0..@mz.header.info[:NumberOfRelocations]-1
|
|
71
|
+
rel = getRelocation(i)
|
|
72
|
+
rel[1]+=paras
|
|
73
|
+
setRelocation(i, rel)
|
|
74
|
+
end
|
|
75
|
+
return codesize
|
|
61
76
|
end
|
|
62
77
|
|
|
63
78
|
def addHeaderSize(size)
|
|
@@ -88,6 +103,11 @@ module Resedit
|
|
|
88
103
|
return getData(@info[:RelocTableOffset] + idx * 4, 4).unpack('vv')
|
|
89
104
|
end
|
|
90
105
|
|
|
106
|
+
def setRelocation(idx, data)
|
|
107
|
+
raise "Wrong relocation index " if idx<0 || idx>@info[:NumberOfRelocations]
|
|
108
|
+
change(@info[:RelocTableOffset] + idx * 4, data.pack('vv'))
|
|
109
|
+
end
|
|
110
|
+
|
|
91
111
|
|
|
92
112
|
def freeSpace(middle = false)
|
|
93
113
|
return @info[:RelocTableOffset] - HSIZE if middle
|
|
@@ -109,14 +129,13 @@ module Resedit
|
|
|
109
129
|
mode(HOW_CHANGED)
|
|
110
130
|
end
|
|
111
131
|
val = @mz.body.linear2seg(ofs)
|
|
112
|
-
puts "VAL"+ val.to_s()
|
|
113
132
|
pos = @info[:RelocTableOffset]+@info[:NumberOfRelocations]*4
|
|
133
|
+
cnt = @info[:NumberOfRelocations]
|
|
114
134
|
change(pos, val.pack('vv'))
|
|
115
|
-
change(6, [
|
|
135
|
+
change(6, [cnt+1].pack('v'))
|
|
116
136
|
return true
|
|
117
137
|
end
|
|
118
138
|
|
|
119
|
-
|
|
120
139
|
def print(what, how)
|
|
121
140
|
mode(parseHow(how))
|
|
122
141
|
if what == "header"
|
|
@@ -128,11 +147,11 @@ module Resedit
|
|
|
128
147
|
puts
|
|
129
148
|
fsz = fileSize()
|
|
130
149
|
hsz = headerSize()
|
|
131
|
-
s = colStr(sprintf("%d (%X)", fsz,fsz), changed?(2,4))
|
|
150
|
+
s = colStr(sprintf("%d (%X)", fsz,fsz), changed?(2, 4))
|
|
132
151
|
printf("mz file size: %s\treal file size: %d (0x%X)\n", s, @fsize, @fsize)
|
|
133
|
-
printf("header size: %s\n", colStr(hsz, changed?(8)))
|
|
134
|
-
printf("code size: %s\n", colStr(fsz - hsz, @mz.body.
|
|
135
|
-
printf("reloc table size: %s\n", colStr(@info[:NumberOfRelocations] * 4, changed?(6)))
|
|
152
|
+
printf("header size: %s\n", colStr(hsz, changed?(8, 2)))
|
|
153
|
+
printf("code size: %s\n", colStr(fsz - hsz, @mz.body.changed?(0)))
|
|
154
|
+
printf("reloc table size: %s\n", colStr(@info[:NumberOfRelocations] * 4, changed?(6, 2)))
|
|
136
155
|
printf("free space in header: before relocs 0x%X, after relocs 0x%X\n", freeSpace(true), freeSpace())
|
|
137
156
|
return true
|
|
138
157
|
end
|
|
@@ -148,7 +167,6 @@ module Resedit
|
|
|
148
167
|
end
|
|
149
168
|
return true
|
|
150
169
|
end
|
|
151
|
-
return super(what, how)
|
|
152
170
|
end
|
|
153
171
|
|
|
154
172
|
|
data/lib/resedit/mz/mzenv.rb
CHANGED
data/lib/resedit/text/huffman.rb
CHANGED
data/lib/resedit/text/text.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: resedit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: '1.6'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- bjfn
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-
|
|
11
|
+
date: 2017-10-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: chunky_png
|
|
@@ -49,20 +49,21 @@ files:
|
|
|
49
49
|
- lib/resedit.rb
|
|
50
50
|
- lib/resedit/app/app.rb
|
|
51
51
|
- lib/resedit/app/app_command.rb
|
|
52
|
-
- lib/resedit/app/colorizer.rb
|
|
53
52
|
- lib/resedit/app/font_convert.rb
|
|
54
53
|
- lib/resedit/app/io_commands.rb
|
|
55
54
|
- lib/resedit/app/mz_command.rb
|
|
56
55
|
- lib/resedit/app/std_commands.rb
|
|
57
56
|
- lib/resedit/app/text_convert.rb
|
|
57
|
+
- lib/resedit/classes/changeable.rb
|
|
58
|
+
- lib/resedit/classes/colorizer.rb
|
|
59
|
+
- lib/resedit/classes/hexwriter.rb
|
|
58
60
|
- lib/resedit/convert/bitconv.rb
|
|
61
|
+
- lib/resedit/convert/codepatch.rb
|
|
59
62
|
- lib/resedit/font/font.rb
|
|
60
63
|
- lib/resedit/font/font_char.rb
|
|
61
64
|
- lib/resedit/image/image.rb
|
|
62
65
|
- lib/resedit/image/image_factory.rb
|
|
63
66
|
- lib/resedit/image/png_image.rb
|
|
64
|
-
- lib/resedit/mz/changeable.rb
|
|
65
|
-
- lib/resedit/mz/hexwriter.rb
|
|
66
67
|
- lib/resedit/mz/mz.rb
|
|
67
68
|
- lib/resedit/mz/mz_body.rb
|
|
68
69
|
- lib/resedit/mz/mz_header.rb
|
|
@@ -83,9 +84,9 @@ require_paths:
|
|
|
83
84
|
- lib
|
|
84
85
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
86
|
requirements:
|
|
86
|
-
- - "
|
|
87
|
+
- - "~>"
|
|
87
88
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: '0'
|
|
89
|
+
version: '2.0'
|
|
89
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
91
|
requirements:
|
|
91
92
|
- - ">="
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
require 'resedit/app/colorizer'
|
|
2
|
-
require 'resedit/mz/hexwriter'
|
|
3
|
-
require 'resedit/mz/mzenv'
|
|
4
|
-
|
|
5
|
-
module Resedit
|
|
6
|
-
|
|
7
|
-
class Changeable
|
|
8
|
-
HOW_CHANGED = 0
|
|
9
|
-
HOW_ORIGINAL = 1
|
|
10
|
-
COL_CHANGED = Colorizer::YELLOW
|
|
11
|
-
COL_ORIGINAL = Colorizer::PURPLE
|
|
12
|
-
|
|
13
|
-
attr_reader :mz, :bytes, :add, :changes, :realSize, :realOfs
|
|
14
|
-
|
|
15
|
-
def initialize(mz, file, size)
|
|
16
|
-
@mz = mz
|
|
17
|
-
@bytes = file.read(size)
|
|
18
|
-
@realOfs = 0
|
|
19
|
-
@realSize = @bytes.size
|
|
20
|
-
@add = nil
|
|
21
|
-
@changes = {}
|
|
22
|
-
@c2 = []
|
|
23
|
-
@col = App::get().col
|
|
24
|
-
@mode = HOW_ORIGINAL
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def readMore(file, size)
|
|
28
|
-
@bytes += file.read(size)
|
|
29
|
-
@realSize = @bytes.size
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def mode(how)
|
|
34
|
-
return if @mode == how
|
|
35
|
-
if how == HOW_CHANGED
|
|
36
|
-
@bytes += @add if @add
|
|
37
|
-
else
|
|
38
|
-
@add = @bytes[@realSize..-1] if @bytes.length > @realSize
|
|
39
|
-
@bytes = @bytes[0, @realSize]
|
|
40
|
-
end
|
|
41
|
-
@changes.each{|c,bts|
|
|
42
|
-
@changes[c] = @bytes[c, bts.length]
|
|
43
|
-
bts.each_byte{|b|
|
|
44
|
-
@bytes[c] = b.chr
|
|
45
|
-
c += 1
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
@mode = how
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def append(bytes)
|
|
52
|
-
mode(HOW_ORIGINAL)
|
|
53
|
-
pos = @bytes.length + (@add ? @add.length : 0)
|
|
54
|
-
@add = @add ? @add + bytes : bytes
|
|
55
|
-
return pos
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def removeAppend()
|
|
59
|
-
mode(HOW_ORIGINAL)
|
|
60
|
-
@add = nil
|
|
61
|
-
@bytes = @bytes[0,@realSize]
|
|
62
|
-
return true
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def changed?(ofs, size=2)
|
|
67
|
-
return true if ofs+size > @realSize
|
|
68
|
-
lower = @c2.find { |e| e < (ofs + size) }
|
|
69
|
-
return false if !lower
|
|
70
|
-
return lower + @changes[lower].length > ofs
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def nextChange(ofs)
|
|
74
|
-
return ofs if changed?(ofs,1)
|
|
75
|
-
return @c2.reverse.find { |e| e > ofs }
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def checkRange(ofs, size)
|
|
79
|
-
raise "Wrong offset: "+ofs.to_s if ofs < 0 || ofs >= @bytes.length
|
|
80
|
-
raise "Byte range overflow: " + ((ofs + size)-@bytes.length).to_s if ofs + size > @bytes.length
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def bufWrite(buf, str, index)
|
|
84
|
-
return buf[0, index] + str + buf[index+str.length .. -1]
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def change(ofs, bytes)
|
|
88
|
-
if ofs > @realSize
|
|
89
|
-
mode(HOW_CHANGED)
|
|
90
|
-
checkRange(ofs, bytes.length)
|
|
91
|
-
bytes.each_byte{|b|
|
|
92
|
-
@bytes[ofs] = b.chr
|
|
93
|
-
ofs += 1
|
|
94
|
-
}
|
|
95
|
-
return ofs
|
|
96
|
-
end
|
|
97
|
-
mode(HOW_ORIGINAL)
|
|
98
|
-
checkRange(ofs, bytes.length)
|
|
99
|
-
if changed?(ofs,bytes.length)
|
|
100
|
-
lower = @c2.find { |e| e < ofs + bytes.length }
|
|
101
|
-
strt = [lower, ofs].min()
|
|
102
|
-
en = [lower+@changes[lower].length, ofs+bytes.length].max()
|
|
103
|
-
buf = ("\0" * (en-strt)).force_encoding(Encoding::ASCII_8BIT)
|
|
104
|
-
buf = bufWrite(buf, @changes[lower], lower - strt)
|
|
105
|
-
buf = bufWrite(buf, bytes, ofs - strt)
|
|
106
|
-
@changes.delete(lower)
|
|
107
|
-
@c2.delete(lower)
|
|
108
|
-
change(strt, buf)
|
|
109
|
-
else
|
|
110
|
-
@changes[ofs] = bytes
|
|
111
|
-
@c2 = @changes.keys.reverse
|
|
112
|
-
end
|
|
113
|
-
return ofs
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def revertChange(ofs)
|
|
117
|
-
raise sprintf("Change not found at: ") if !@changes[ofs]
|
|
118
|
-
mode(HOW_ORIGINAL)
|
|
119
|
-
@changes.delete(ofs)
|
|
120
|
-
@c2 = @changes.keys.reverse
|
|
121
|
-
return ofs
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def revert(what)
|
|
125
|
-
mode(HOW_ORIGINAL)
|
|
126
|
-
if what=='all'
|
|
127
|
-
removeAppend()
|
|
128
|
-
@changes = {}
|
|
129
|
-
@c2=[]
|
|
130
|
-
return true
|
|
131
|
-
end
|
|
132
|
-
if what == 'append' || what==@realSize+@realOfs
|
|
133
|
-
removeAppend()
|
|
134
|
-
return true
|
|
135
|
-
end
|
|
136
|
-
return false if !@changes[what-@realOfs]
|
|
137
|
-
revertChange(what-@realOfs)
|
|
138
|
-
return true
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def curcol() return @mode == HOW_ORIGINAL ? COL_ORIGINAL : COL_CHANGED end
|
|
143
|
-
|
|
144
|
-
def colVal(ofs, size)
|
|
145
|
-
fmt = "%#{size*2}.#{size*2}X"
|
|
146
|
-
u = size == 2 ? "v" : V
|
|
147
|
-
return colStr( sprintf(fmt, getData(ofs, size).unpack(u)[0]) , changed?(ofs,size))
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def colStr(str, cond=true)
|
|
151
|
-
str = sprintf("%04X", str) if !str.is_a?(String)
|
|
152
|
-
return str if !cond
|
|
153
|
-
return @col.color(curcol(), str)
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def getData(ofs, size)
|
|
157
|
-
checkRange(ofs, size)
|
|
158
|
-
return @bytes[ofs,size]
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def parseHow(how)
|
|
163
|
-
return HOW_CHANGED if !how || how == HOW_CHANGED
|
|
164
|
-
return HOW_ORIGINAL if how == HOW_ORIGINAL
|
|
165
|
-
return HOW_ORIGINAL if how[0] == 'o' || how[0] == 'O'
|
|
166
|
-
return HOW_CHANGED
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def print(what, how)
|
|
170
|
-
mode(parseHow(how))
|
|
171
|
-
if what=="changes"
|
|
172
|
-
@changes.each{|ofs,bts|
|
|
173
|
-
bts = getData(ofs, bts.length)
|
|
174
|
-
printf("%08X: %s\n", ofs+@realOfs, colStr(bts.bytes.map { |b| sprintf("%02X",b) }.join))
|
|
175
|
-
}
|
|
176
|
-
if @add
|
|
177
|
-
printf("%08X: %s\n", @realSize+@realOfs, colStr(@add.bytes.map { |b| sprintf("%02X",b) }.join))
|
|
178
|
-
end
|
|
179
|
-
puts
|
|
180
|
-
return true
|
|
181
|
-
end
|
|
182
|
-
return false
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def hex(writer, ofs, size, how)
|
|
187
|
-
mode(parseHow(how))
|
|
188
|
-
col = curcol()
|
|
189
|
-
return size if ofs > @bytes.length
|
|
190
|
-
while size > 0
|
|
191
|
-
if ofs>=@realSize
|
|
192
|
-
sz = [size, @bytes.length - ofs].min
|
|
193
|
-
if sz
|
|
194
|
-
writer.addBytes(@bytes[ofs, sz], col)
|
|
195
|
-
size -= sz
|
|
196
|
-
end
|
|
197
|
-
return size
|
|
198
|
-
end
|
|
199
|
-
x = nextChange(ofs)
|
|
200
|
-
x = @realSize if !x
|
|
201
|
-
sz = [size, x-ofs].min
|
|
202
|
-
if sz
|
|
203
|
-
writer.addBytes(@bytes[ofs, sz], nil)
|
|
204
|
-
size -= sz
|
|
205
|
-
ofs += sz
|
|
206
|
-
end
|
|
207
|
-
return 0 if size == 0
|
|
208
|
-
if @changes[x]
|
|
209
|
-
sz = [size, @changes[x].length].min
|
|
210
|
-
if sz
|
|
211
|
-
writer.addBytes(@bytes[ofs, sz], col)
|
|
212
|
-
size -= sz
|
|
213
|
-
ofs += sz
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def saveData(file)
|
|
220
|
-
mode(HOW_CHANGED)
|
|
221
|
-
file.write(@bytes)
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def saveChanges(file)
|
|
225
|
-
mode(HOW_CHANGED)
|
|
226
|
-
file.write([@realSize, @changes.length].pack('VV'))
|
|
227
|
-
@changes.each{|c,bts|
|
|
228
|
-
file.write([c, bts.length].pack('VV'))
|
|
229
|
-
file.write(bts)
|
|
230
|
-
}
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def loadChanges(file)
|
|
234
|
-
mode(HOW_CHANGED)
|
|
235
|
-
@realSize,clen=file.read(8).unpack('VV')
|
|
236
|
-
@add = @bytes[@realSize..-1] if @bytes.length > @realSize
|
|
237
|
-
@bytes = @bytes[0, @realSize]
|
|
238
|
-
for i in 0..clen-1
|
|
239
|
-
ofs, bts = file.read(8).unpack('VV')
|
|
240
|
-
@changes[ofs] = file.read(bts)
|
|
241
|
-
end
|
|
242
|
-
@c2 = @changes.keys.reverse
|
|
243
|
-
mode(HOW_ORIGINAL)
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
end
|