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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c544c164c27a245f45cebe0ede011c1a8ebd19d2
4
- data.tar.gz: a212b23cc05f16ec779469aecc74601b046ae468
3
+ metadata.gz: 5b4e01f23eab7befb55f58374b179252e580ba27
4
+ data.tar.gz: c70bea5859d5fcdb2c62379956034d641336d320
5
5
  SHA512:
6
- metadata.gz: 85deaaad0d6928ceafda0bb8a6642b8af902f061870c1e8a0fc2ba33bf3e3c25c97c83ac38c2858534214f058f713b3e955bba3fa995eacf77abb4b9ea47ea42
7
- data.tar.gz: a8c03dcca383eb79c3215009e4c3563e73cce82e05bd590946926b70ef3a56d57433e57ca51dbb4ea2fbf07596cad6106ccf6fadc66ed6fbd9cd2510db6815de
6
+ metadata.gz: bec413733f867fe85b74bfbb07f99bcb4be3b161f3a3539cf50ed5312e03365accff257b81a107308c1ad205e0c8eb7779f330bb62414e3c508af802ce64edab
7
+ data.tar.gz: f6ef54cd8d085aaf2821f3b7821ccdbaa4c15ac26a4cf38b734091f0095b6626a7333f673a1ccaa72bc49075fbec2d57839dd9588391a46fc25ea7dc2744b9a0
@@ -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.5.1"
20
+ VERSION = "1.6"
17
21
  end
@@ -1,6 +1,6 @@
1
1
  require 'resedit/app/std_commands'
2
2
  require 'resedit/app/mz_command'
3
- require 'resedit/app/colorizer'
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.new(false)
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
@@ -67,8 +67,8 @@ module Resedit
67
67
  pidx+=1
68
68
  end
69
69
  end
70
- @params.each{|p|
71
- raise "Expected parameter #{p[:name]}" if res[p[:name]]==nil
70
+ @params.each{|pp|
71
+ raise "Expected parameter #{pp[:name]}" if res[pp[:name]]==nil
72
72
  }
73
73
  return res
74
74
  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', nil, 'help on mz commands')
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
 
@@ -1,5 +1,4 @@
1
1
  require 'resedit/app/app_command'
2
- require 'resedit'
3
2
 
4
3
  module Resedit
5
4
 
@@ -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
- def initialize(on=true)
16
- @on = on;
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/app/app'
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 = App::get().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
@@ -1,6 +1,6 @@
1
1
  require 'resedit/mz/mz_header'
2
2
  require 'resedit/mz/mz_body'
3
- require 'resedit/mz/hexwriter'
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("%04X:0",@body.appSeg))
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
- res = @body.append(getValue(value,type))
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
@@ -1,4 +1,5 @@
1
- require 'resedit/mz/changeable'
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
- super(mz, file, size)
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
- def loadChanges(f)
31
- super(f)
32
- @appSeg = (@realSize >> 4) + 1
33
- @segments.add(@appSeg)
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>@bytes.length
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
- @segments.each{|s|
69
- @segments.delete(s) if (s << 4) > @realSize
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
- def append(bytes)
82
- mode(HOW_ORIGINAL)
83
- res = 0
84
- addseg = false
85
- if !@add
86
- addseg = true
87
- res = 0x10 - (@realSize % 0x10)
88
- res = 0 if res == 0x10
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
- if addseg
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
@@ -1,4 +1,4 @@
1
- require 'resedit/mz/changeable'
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
- super(mz, file, HSIZE)
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
- readMore(file, headerSize() - HSIZE)
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 setCodeSize(size)
60
- changeSize(size + headerSize())
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, [@info[:NumberOfRelocations]+1].pack('v'))
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.add != nil))
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
 
@@ -37,7 +37,7 @@ module Resedit
37
37
  sz = s.length / 2 + s.length % 2 if !sz || sz==0
38
38
  hx = eval('0x'+s, binding())
39
39
  s=""
40
- for i in 0..sz-1
40
+ for _ in 0..sz-1
41
41
  s += sprintf("%02X", hx & 0xFF)
42
42
  hx >>= 8
43
43
  end
@@ -170,7 +170,7 @@ module Resedit
170
170
  bytes.each_byte{|b|
171
171
  raise sprintf("No byte in encode table: %02X", b) if !tbl[b]
172
172
  val = tbl[b][0]
173
- for i in 0..tbl[b][1]-1
173
+ for _ in 0..tbl[b][1]-1
174
174
  byte |= ((val & 1) << bytelen)
175
175
  val >>= 1
176
176
  bytelen += 1
@@ -32,7 +32,7 @@ module Resedit
32
32
  end
33
33
  end
34
34
 
35
- def addLine(line, meta)
35
+ def addLine(line, meta = nil)
36
36
  line.encode!("utf-8",@encoding) if @encoding
37
37
  line.force_encoding('utf-8')
38
38
  @lines += [line]
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.5.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-09-02 00:00:00.000000000 Z
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