resedit 1.5.1 → 1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|